Skip to content

Commit

Permalink
add delegateBySig test and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
thurendous committed Sep 13, 2024
1 parent c139016 commit 347d1da
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,53 @@ And the URI of the NFT can be set by the URI setter role after the deployment of

This is the smart contract for the ERC20 token that is used to represent the utility token of the community. This utility token is transferable.

#### Possible use cases and functions explanation
#### Use cases and functions explanation

This token is used as the utility token for the community, which can be earned by doing missions or other activities for the community. The users can use utility token to exchange the governance token.

The default admin role has the right to set the minter and the burner role. The minter role is the role that can mint new tokens. The burner role is the role that can burn the tokens from the specified account.

The contract itself is pausable. The pauser role is the role that can pause and unpause the contract. When the contract is paused, the minting and transferring of the token are disabled.

#### Notes

- The contract is upgradable.
- The contract is pausable.
- The contract is ERC20Permit compliant.

### GovToken.sol

This is the smart contract for the governance token of the community. The contract is based on the ERC20Votes contract of the OpenZeppelin.

#### Use cases and functions explanation

The token is used to represent the voting power of the holder. The token is not transferable. At the same time, it is also used to represent the level of the holder, e.g. the higher the level, the more voting power the holder has.
For example, holding 1 token means the holder is level 2. Holding 0 token means the holder is level 1.

The token is not transferable. It means the token holder cannot transfer the token to any other address.

ERC20Permit is inherited here because OpenZeppelin's wizard is doing so and we followed its code, which is a relatively secure way in our opinion.

#### Notes

There are 2 phases when we want to utilize this token. After kicking off as Phase 1, the community governance will be under observation. When phase 1 is stable and mature, we will transition into phase 2 gradually.

- Phase 1:
We use the token to represent the voting power of the holder. And manage governance off-chain using the token balance of the governance participants.
- Phase 2:
We use the token to represent the level of the holder. And manage governance on-chain using the token balance of the governance participants.

The GovToken is in a sense an achievement recorder. We want to make sure the achievement system is transparent and verifiable for all participants. That is why we did not make this token upgradable.

### VotingPowerExchange.sol

#### Use cases and functions explanation

#### Notes

- The contract is created from scratch.
- `SafeERC20` is not used because the token contract we are using is known to be safe.

### MyGovernor.sol

### Timelock.sol
Expand Down
1 change: 1 addition & 0 deletions test/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ This is the token contract for the governance system.
- testTheRolesOfTheGovToken
- testTheTokenInfos
- testNonces
- testDelegateBySig
- testClock

## Integration Tests
Expand Down
35 changes: 35 additions & 0 deletions test/unit/GovToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,41 @@ contract GovTokenTest is Test {
assertEq(govToken.nonces(user), 0, "Other user's nonce should still be 0");
}

function testDelegateBySig() public {
uint256 privateKey = DEFAULT_ANVIL_KEY2;
address owner = vm.addr(privateKey);
// Initial delegate should be address(0)
assertEq(govToken.delegates(owner), address(0), "Initial delegate should be address(0)");
assertEq(govToken.nonces(owner), 0, "Initial nonce should be 0");

// Simulate a delegateBySig to change the delegate
uint256 nonce = govToken.nonces(owner);
uint256 expiry = block.timestamp + 1 hours;
bytes32 DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
// sign the delegateBySig by owner
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
privateKey,
keccak256(
abi.encodePacked(
"\x19\x01",
govToken.DOMAIN_SEPARATOR(),
keccak256(abi.encode(DELEGATION_TYPEHASH, address(this), nonce, expiry))
)
)
);

govToken.delegateBySig(address(this), nonce, expiry, v, r, s);

// Check if delegate is changed after delegateBySig
assertEq(govToken.delegates(owner), address(this), "Delegate should be changed after delegateBySig");

// Check if nonce is incremented after delegateBySig
assertEq(govToken.nonces(owner), 1, "Nonce should be incremented after delegateBySig");

// Other user's delegate should still be address(0)
assertEq(govToken.delegates(user), address(0), "Other user's delegate should still be address(0)");
}

function testClock() public {
// set up a timestamp
uint256 currentTimestamp = 1678901234; // 2023-03-15 12:33:54 UTC
Expand Down

0 comments on commit 347d1da

Please sign in to comment.