Skip to content

Commit

Permalink
fixed sync validator issue
Browse files Browse the repository at this point in the history
  • Loading branch information
0xbeny committed Sep 13, 2024
1 parent 048caad commit 0480454
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 2 deletions.
2 changes: 1 addition & 1 deletion packages/contracts/src/DaofinPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ contract DaofinPlugin is BaseDaofinPlugin {
_masterNodeDelegatee.numberOfJointMasterNodes--;
}

mnToWeights[masterNode_] = getMnWeight(masterNode_);
mnToWeights[delegatee] = getMnWeight(masterNode_);

emit MnSynced(masterNode_);
return true;
Expand Down
59 changes: 59 additions & 0 deletions packages/contracts/src/test/mock/XDCValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,65 @@ contract XDCValidator {
_candidateCount++;
}

function removeCandidate(address candidate) external {
// Check if the candidate exists and belongs to the sender
require(validatorsState[candidate].isCandidate, "Address is not a candidate");
require(validatorsState[candidate].owner == msg.sender, "Not the owner of this candidate");

// Remove candidate from the ownerToCandidate array
address[] storage ownerCandidates = ownerToCandidate[msg.sender];
for (uint256 i = 0; i < ownerCandidates.length; i++) {
if (ownerCandidates[i] == candidate) {
ownerCandidates[i] = ownerCandidates[ownerCandidates.length - 1]; // Move the last element into the place of the removed element
ownerCandidates.pop(); // Remove the last element
break;
}
}

// If the owner has no more candidates, remove them from _owners
if (ownerToCandidate[msg.sender].length == 0) {
for (uint256 i = 0; i < _owners.length; i++) {
if (_owners[i] == msg.sender) {
_owners[i] = _owners[_owners.length - 1]; // Move the last element into the place of the removed element
_owners.pop(); // Remove the last element
break;
}
}
}

// Remove candidate from candidates array
for (uint256 i = 0; i < candidates.length; i++) {
if (candidates[i] == candidate) {
candidates[i] = candidates[candidates.length - 1]; // Move the last element into the place of the removed element
candidates.pop(); // Remove the last element
break;
}
}

// Update candidate state
validatorsState[candidate].isCandidate = false;
validatorsState[candidate].owner = address(0); // Reset owner information

// Decrease the candidate count
_candidateCount--;
}

function remove(address candidate) external {
if (validatorsState[candidate].isCandidate) {
revert();
}
if (ownerToCandidate[msg.sender].length == 0) {
_owners.push(msg.sender);
}
validatorsState[candidate].isCandidate = true;
validatorsState[candidate].owner = msg.sender;

ownerToCandidate[msg.sender].push(candidate);

candidates.push(candidate);
_candidateCount++;
}

function getRealCandidates() external pure returns (uint256) {
return 420;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ describe(PLUGIN_CONTRACT_NAME, function () {

await advanceTime(ethers, convertDaysToSeconds(8));

await expect(daofinPlugin.execute(proposalId)).not.be.reverted;
await expect(daofinPlugin.execute(proposalId)).not.reverted;
});
it('must not be able to execute due to lack of YES votes', async () => {
await dao.grant(dao.address, daofinPlugin.address, EXECUTE_PERMISSION_ID);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import {DaofinPluginSetupParams} from '../../../plugin-settings';
import {
DaofinPlugin,
DaofinPlugin__factory,
MockTimestampOracle,
MockTimestampOracle__factory,
XDCValidator,
} from '../../../typechain';
import {deployWithProxy} from '../../../utils/helpers';
import {deployTestDao} from '../../helpers/test-dao';
import {deployXDCValidator} from '../../helpers/test-xdc-validator';
import {
advanceTime,
convertDaysToSeconds,
createCommitteeVotingSettings,
createProposalParams,
} from '../../helpers/utils';
import {
ADDRESS_ONE,
ADDRESS_TWO,
ADDRESS_ZERO,
JudiciaryCommittee,
MasterNodeCommittee,
PeoplesHouseCommittee,
UPDATE_JUDICIARY_MAPPING_PERMISSION_ID,
UPDATE_PROPOSAL_COSTS_PERMISSION_ID,
XdcValidator,
} from '../daofin-common';
import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers';
import {DAO, RatioTest, RatioTest__factory} from '@xinfin/osx-ethers';
import {expect} from 'chai';
import {BigNumber} from 'ethers';
import {parseEther} from 'ethers/lib/utils';
import {ethers, network} from 'hardhat';

const {PLUGIN_CONTRACT_NAME} = DaofinPluginSetupParams;

describe(PLUGIN_CONTRACT_NAME, function () {
let signers: SignerWithAddress[];
let dao: DAO;
let DaofinPlugin: DaofinPlugin__factory;
let daofinPlugin: DaofinPlugin;
let initializeParams: Parameters<DaofinPlugin['initialize']>;
let createPropsalParams: Parameters<DaofinPlugin['createProposal']>;
let Alice: SignerWithAddress;
let Bob: SignerWithAddress;
let Mike: SignerWithAddress;
let John: SignerWithAddress;
let Beny: SignerWithAddress;
let xdcValidatorMock: XDCValidator;
let ratio: RatioTest;
let MockTimestampOracle: MockTimestampOracle__factory;
let mockTimestampOracle: MockTimestampOracle;
before(async () => {
signers = await ethers.getSigners();
Alice = signers[0];
Bob = signers[1];
Mike = signers[2];
John = signers[3];
Beny = signers[4];

dao = await deployTestDao(Alice);

DaofinPlugin = new DaofinPlugin__factory(Alice);

const RatioTest = new RatioTest__factory(Alice);
ratio = await RatioTest.deploy();

MockTimestampOracle = new MockTimestampOracle__factory(Alice);
mockTimestampOracle = await MockTimestampOracle.deploy();
});

beforeEach(async () => {
xdcValidatorMock = await deployXDCValidator(Alice);

daofinPlugin = await deployWithProxy<DaofinPlugin>(DaofinPlugin);
const now = (await mockTimestampOracle.getUint64Timestamp()).toNumber();

initializeParams = [
dao.address,
parseEther('1'),
xdcValidatorMock.address,
[
createCommitteeVotingSettings(
MasterNodeCommittee,
'100000',
'100000',
parseEther('1')
),
createCommitteeVotingSettings(
PeoplesHouseCommittee,
'100000',
'100000',
parseEther('1')
),
createCommitteeVotingSettings(
JudiciaryCommittee,
'100000',
'100000',
parseEther('1')
),
],
[
createCommitteeVotingSettings(
MasterNodeCommittee,
'100000',
'100000',
parseEther('1')
),
createCommitteeVotingSettings(
PeoplesHouseCommittee,
'100000',
'100000',
parseEther('1')
),
createCommitteeVotingSettings(
JudiciaryCommittee,
'100000',
'100000',
parseEther('1')
),
],
[
BigNumber.from(now + 60 * 60 * 24 * 3),
BigNumber.from(now + 60 * 60 * 24 * 12),
],
[],
'1',
];
await daofinPlugin.initialize(...initializeParams);

await daofinPlugin.joinHouse({value: parseEther('1')});
});
describe('Sync validator snapshot count', async () => {
it('snapshot must be updated', async () => {
const snapshotBefore = await daofinPlugin.masternodeCountSnapshot();

await xdcValidatorMock.connect(John).addCandidate(ADDRESS_ONE);
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_TWO);
await xdcValidatorMock.connect(John).addCandidate(Bob.address);
await xdcValidatorMock.connect(Mike).addCandidate(Alice.address);

const syncStaticCall =
await daofinPlugin.callStatic.syncXdcValidatorSnapshot();
expect(syncStaticCall).be.true;
await daofinPlugin.syncXdcValidatorSnapshot();

const snapshotAfter = await daofinPlugin.masternodeCountSnapshot();
expect(snapshotAfter).be.eq(BigNumber.from('4'));
});
});

describe('Validator getWeight()', async () => {
it('must return the exact size of candidates number of an owner', async () => {
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_ONE);
expect(await daofinPlugin.getMnWeight(John.address)).be.eq(1);

await xdcValidatorMock.connect(John).addCandidate(ADDRESS_TWO);
await xdcValidatorMock.connect(John).addCandidate(Bob.address);
expect(await daofinPlugin.getMnWeight(John.address)).be.eq(3);

expect(await daofinPlugin.getMnWeight(Mike.address)).be.eq(0);
await xdcValidatorMock.connect(Mike).addCandidate(Alice.address);
expect(await daofinPlugin.getMnWeight(Mike.address)).be.eq(1);
});
});

describe('SyncXDCValidator', async () => {
it('must delete the existing master node delegate', async () => {
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_ONE);

await daofinPlugin
.connect(John)
.updateOrJoinMasterNodeDelegatee(Bob.address);

await xdcValidatorMock.connect(John).removeCandidate(ADDRESS_ONE);

expect(await daofinPlugin.isMasterNodeDelegatee(Bob.address)).be.true;
await daofinPlugin.syncWithXdcValidator(John.address);
expect(await daofinPlugin.isMasterNodeDelegatee(Bob.address)).be.false;
});
it('must adjust voting power', async () => {
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_ONE);

await daofinPlugin
.connect(John)
.updateOrJoinMasterNodeDelegatee(Bob.address);

const weightBefore = await daofinPlugin.mnToWeights(Bob.address);
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_TWO);

await daofinPlugin.syncWithXdcValidator(John.address);

expect(await daofinPlugin.isMasterNodeDelegatee(Bob.address)).be.true;

const weightAfter = await daofinPlugin.mnToWeights(Bob.address);

expect(weightAfter).be.eq(2);
});
it('must decrease voting power', async () => {
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_ONE);

await xdcValidatorMock.connect(John).addCandidate(ADDRESS_TWO);
await daofinPlugin
.connect(John)
.updateOrJoinMasterNodeDelegatee(Bob.address);

const weightBefore = await daofinPlugin.mnToWeights(Bob.address);
expect(weightBefore).be.eq(2);
await xdcValidatorMock.connect(John).removeCandidate(ADDRESS_TWO);
await daofinPlugin.syncWithXdcValidator(John.address);

expect(await daofinPlugin.isMasterNodeDelegatee(Bob.address)).be.true;

const weightAfter = await daofinPlugin.mnToWeights(Bob.address);

expect(weightAfter).be.eq(1);
});
it('no changes :)', async () => {
await xdcValidatorMock.connect(John).addCandidate(ADDRESS_ONE);

await xdcValidatorMock.connect(John).addCandidate(ADDRESS_TWO);
await daofinPlugin
.connect(John)
.updateOrJoinMasterNodeDelegatee(Bob.address);

const weightBefore = await daofinPlugin.mnToWeights(Bob.address);
expect(weightBefore).be.eq(2);
await daofinPlugin.syncWithXdcValidator(John.address);

expect(await daofinPlugin.isMasterNodeDelegatee(Bob.address)).be.true;

const weightAfter = await daofinPlugin.mnToWeights(Bob.address);

expect(weightAfter).be.eq(2);
});
});
});

0 comments on commit 0480454

Please sign in to comment.