ZestyToken/GovernorAlpha/Timelock
Forked from Compound's Governance module
ZestyTokens adopts the Governor Alpha version of Compound's COMP token specification, Compound's implementation was chosen as it was simple and reliable. The protocol may adopt the Governor Bravo specification by Compound at a later date. Zesty Market is grateful for the contributions of Compound in the Ethereum ecosystem.
Likewise with Compound protocol, Zesty Market will be governed and upgraded by ZESTY token holders. The components are; ZestyToken, GovernorAlpha, and Timelock. Proposals are much more general on Zesty Market as compared to Compound. The Timelock contract can be treated as the decentralized owner of ZestyMarket.
ZestyTokens has a fixed supply of 100,000,000 ZESTY. Any address with more than 1,000,000 ZESTY (1% of ZESTY) delegated to it may propose governance actions, which are executable code. When a proposal is created, the community can submit their votes during a 3 day voting period. If a majority, and at least 7,000,000 (7% of ZESTY) votes are cast for the proposal, it is queued in the Timelock, and can be implemented after a minimum of 2 days.
Flow of Compound's Governor Alpha

ZestyToken

ZestyToken is an ERC-20 token that allows the owner to delegate voting rights to any address, including their own address. Changes to the owner’s token balance automatically adjust the voting rights of the delegate.

Delegate

Delegate votes from the sender to the delegatee. Users can delegate to 1 address at a time, and the number of votes added to the delegatee’s vote count is equivalent to the balance of COMP in the user’s account. Votes are delegated from the current block and onward, until the sender delegates again, or transfers their ZESTY.
ZestyToken
1
function delegate(address delegatee)
Copied!
    delegatee: The address in which the sender wishes to delegate their votes to.
    msg.sender: The address of the ZESTY token holder that is attempting to delegate their votes.
    RETURN: No return, reverts on error.
Solidity
1
ZestyToken zesty = ZestyToken(0x123...); // contract address
2
zesty.delegate(delegateeAddress);
Copied!
Web3 1.2.6
1
const tx = await zesty.methods.delegate(delegateeAddress).send({ from: sender });
Copied!

Delegate By Signature

Delegate votes from the signatory to the delegatee. This method has the same purpose as Delegate but it instead enables offline signatures to participate in Zesty Market's governance vote delegation. For more details on how to create an offline signature, review EIP-712.
ZestyToken
1
function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s)
Copied!
    delegatee: The address in which the sender wishes to delegate their votes to.
    nonce: The contract state required to match the signature. This can be retrieved from the contract’s public nonces mapping.
    expiry: The time at which to expire the signature. A block timestamp as seconds since the unix epoch (uint).
    v: The recovery byte of the signature.
    r: Half of the ECDSA signature pair.
    s: Half of the ECDSA signature pair.
    RETURN: No return, reverts on error.
Solidity
1
ZestyToken zesty = ZestyToken(0x123...); // contract address
2
zesty.delegateBySig(delegateeAddress, nonce, expiry, v, r, s);
Copied!
Web3 1.2.6
1
const tx = await zesty.methods.delegateBySig(delegateeAddress, nonce, expiry, v, r, s).send({});
Copied!

Get Current Votes

Gets the balance of votes for an account as of the current block.
ZestyToken
1
function getCurrentVotes(address account) returns (uint96)
Copied!
    account: Address of the account in which to retrieve the number of votes.
    RETURN: The number of votes (integer).
Solidity
1
ZestyMarket zesty = ZestyToken(0x123...); // contract address
2
uint votes = zesty.getCurrentVotes(0xabc...);
Copied!
Web3 1.2.6
1
const account = '0x123...'; // contract address
2
const votes = await zesty.methods.getCurrentVotes(account).call();
Copied!

Get Prior Votes

Gets the prior number of votes for an account at a specific block number. The block number passed must be a finalized block or the function will revert.
ZestyMarket
1
function getPriorVotes(address account, uint blockNumber) returns (uint96)
Copied!
    account: Address of the account in which to retrieve the prior number of votes.
    blockNumber: The block number at which to retrieve the prior number of votes.
    RETURN: The number of prior votes.
Solidity
1
ZestyMarket zesty = ZestyMarket(0x123...); // contract address
2
uint priorVotes = zesty.getPriorVotes(account, blockNumber);
Copied!
Web3 1.2.6
1
const priorVotes = await zesty.methods.getPriorVotes(account, blockNumber).call();
Copied!

Key Events

Event
Description
DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate)
An event thats emitted when an account changes its delegate.
DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance)
An event thats emitted when a delegate account's vote balance changes.
ProposalCreated(uint id, address proposer, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, uint startBlock, uint endBlock, string description)
An event emitted when a new proposal is created.
VoteCast(address voter, uint proposalId, bool support, uint votes)
An event emitted when a vote has been cast on a proposal.
ProposalCanceled(uint id)
An event emitted when a proposal has been canceled.
ProposalQueued(uint id, uint eta)
An event emitted when a proposal has been queued in the Timelock.
ProposalExecuted(uint id)
An event emitted when a proposal has been executed in the Timelock.

Governor Alpha

Governor Alpha is the governance module of the protocol; it allows addresses with more than 1,000,000 ZESTY to propose changes to the protocol. Addresses that held voting weight, at the start of the proposal, invoked through the getpriorvotes function, can submit their votes during a 3 day voting period. If a majority, and at least 7,000,000 votes are cast for the proposal, it is queued in the Timelock, and can be implemented after 2 days.

Quorum Votes

The required minimum number of votes in support of a proposal for it to succeed.
Governor Alpha
1
function quorumVotes() public pure returns (uint)
Copied!
    RETURN: The minimum number of votes required for a proposal to succeed.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint quorum = gov.quorumVotes();
Copied!
Web3 1.2.6
1
const quorum = await gov.methods.quorumVotes().call();
Copied!

Proposal Threshold

The minimum number of votes required for an account to create a proposal.
Governor Alpha
1
function proposalThreshold() returns (uint)
Copied!
    RETURN: The minimum number of votes required for an account to create a proposal.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint threshold = gov.proposalThreshold();
Copied!
Web3 1.2.6
1
const threshold = await gov.methods.proposalThreshold().call();
Copied!

Proposal Max Operations

The maximum number of actions that can be included in a proposal. Actions are functions calls that will be made when a proposal succeeds and executes.
Governor Alpha
1
function proposalMaxOperations() returns (uint)
Copied!
    RETURN: The maximum number of actions that can be included in a proposal.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint operations = gov.proposalMaxOperations();
Copied!
Web3 1.2.6
1
const operations = await gov.methods.proposalMaxOperations().call();
Copied!

Voting Delay

The number of Ethereum blocks to wait before voting on a proposal may begin. This value is added to the current block number when a proposal is created.
Governor Alpha
1
function votingDelay() returns (uint)
Copied!
    RETURN: Number of blocks to wait before voting on a proposal may begin.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint blocks = gov.votingDelay();
Copied!
Web3 1.2.6
1
const blocks = await gov.methods.votingDelay().call();
Copied!

Voting Period

The duration of voting on a proposal, in Ethereum blocks.
Governor Alpha
1
function votingPeriod() returns (uint)
Copied!
    RETURN: The duration of voting on a proposal, in Ethereum blocks.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint blocks = gov.votingPeriod();
Copied!
Web3 1.2.6
1
const blocks = await gov.methods.votingPeriod().call();
Copied!

Propose

Create a Proposal to call any function that would be executed by Timelock.
Proposals will be voted on by delegated voters. If there is sufficient support before the voting period ends, the proposal shall be automatically enacted. Enacted proposals are queued and executed in the ZestyMarket Timelock contract.
The sender must hold more ZESTY than the current proposal threshold (proposalThreshold()) as of the immediately previous block. If the threshold is 1,000,000 ZESTY, the sender must have been delegated more than 1% of all ZESTY in order to create a proposal. The proposal can have up to 10 actions (based on proposalMaxOperations()).
The proposer cannot create another proposal if they currently have a pending or active proposal. It is not possible to queue two identical actions in the same block (due to a restriction in the Timelock), therefore actions in a single proposal must be unique, and unique proposals that share an identical action must be queued in different blocks.
Governor Alpha
1
function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) returns (uint)
Copied!
    targets: The ordered list of target addresses for calls to be made during proposal execution. This array must be the same length as all other array parameters in this function.
    values: The ordered list of values (i.e. msg.value) to be passed to the calls made during proposal execution. This array must be the same length as all other array parameters in this function.
    signatures: The ordered list of function signatures to be passed during execution. This array must be the same length as all other array parameters in this function.
    calldatas: The ordered list of data to be passed to each individual function call during proposal execution. This array must be the same length as all other array parameters in this function.
    description: A human readable description of the proposal and the changes it will enact.
    RETURN: The ID of the newly created proposal.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint proposalId = gov.propose(targets, values, signatures, calldatas, description);
Copied!
Web3 1.2.6
1
const tx = gov.methods.propose(targets, values, signatures, calldatas, description).send({ from: sender });
Copied!

Queue

After a proposal has succeeded, any address can call the queue method to move the proposal into the Timelock queue. A proposal can only be queued if it has succeeded.
Governor Alpha
1
function queue(uint proposalId)
Copied!
    proposalId: ID of a proposal that has succeeded.
    RETURN: No return, reverts on error.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
gov.queue(proposalId);
Copied!
Web3 1.2.6
1
const tx = gov.methods.queue(proposalId).send({ from: sender });
Copied!

Execute

After the Timelock delay period, any account may invoke the execute method to apply the changes from the proposal to the target contracts. This will invoke each of the actions described in the proposal.
This function is payable so the Timelock contract can invoke payable functions that were selected in the proposal.
Governor Alpha
1
function execute(uint proposalId) payable returns (uint)
Copied!
    proposalId: ID of a succeeded proposal to execute.
    RETURN: No return, reverts on error.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
gov.execute(proposalId).value(999).gas(999)();
Copied!
Web3 1.2.6
1
const tx = gov.methods.execute(proposalId).send({ from: sender, value: 1 });
Copied!

Cancel

Cancel a proposal that has not yet been executed. The Guardian is the only one who may execute this unless the proposer does not maintain the delegates required to create a proposal. If the proposer does not have more delegates than the proposal threshold, anyone can cancel the proposal.
Governor Alpha
1
function cancel(uint proposalId)
Copied!
    proposalId: ID of a proposal to cancel. The proposal cannot have already been executed.
    RETURN: No return, reverts on error.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
gov.cancel(proposalId);
Copied!
Web3 1.2.6
1
const tx = gov.methods.cancel(proposalId).send({ from: sender });
Copied!

Get Actions

Gets the actions of a selected proposal. Pass a proposal ID and get the targets, values, signatures and calldatas of that proposal.
Governor Alpha
1
function getActions(uint proposalId) returns (uint proposalId) public view returns (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas)
Copied!
    proposalId: ID of a proposal in which to get its actions.
    RETURN: Reverts if the proposal ID is invalid. If successful, the following 4 references are returned.
    1.
    Array of addresses of contracts the proposal calls.
    2.
    Array of unsigned integers the proposal uses as values.
    3.
    Array of strings of the proposal’s signatures.
    4.
    Array of calldata bytes of the proposal.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
uint proposalId = 123;
3
(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) = gov.getActions(proposalId);
Copied!
Web3 1.2.6
1
const {0: targets, 1: values, 2: signatures, 3: calldatas} = gov.methods.getActions(proposalId).call();
Copied!

Get Receipt

Gets a proposal ballot receipt of the indicated voter.
Governor Alpha
1
function getReceipt(uint proposalId, address voter) returns (Receipt memory)
Copied!
    proposalId: ID of the proposal in which to get a voter’s ballot receipt.
    voter: Address of the account of a proposal voter.
    RETURN: Reverts on error. If successful, returns a Receipt struct for the ballot of the voter address.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
Receipt ballot = gov.getReceipt(proposalId, voterAddress);
Copied!
Web3 1.2.6
1
const proposalId = 11;
2
const voterAddress = '0x123...';
3
const result = await gov.methods.getReceipt(proposalId, voterAddress).call();
4
const { hasVoted, support, votes } = result;
Copied!

State

Gets the proposal state for the specified proposal. The return value, ProposalState is an enumerated type defined in the Governor Alpha contract.
Governor Alpha
1
function state(uint proposalId) returns (ProposalState)
Copied!
    proposalId: ID of a proposal in which to get its state.
    RETURN: Enumerated type ProposalState. The types are Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, andExecuted.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
GovernorAlpha.ProposalState state = gov.state(123);
Copied!
Web3 1.2.6
1
const proposalStates = ['Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'];
2
const proposalId = 123;
3
result = await gov.methods.state(proposalId).call();
4
const proposalState = proposalStates[result];
Copied!

Cast Vote

Cast a vote on a proposal. The account's voting weight is determined by the number of votes the account had delegated to it at the time the proposal state became active.
Governor Alpha
1
function castVote(uint proposalId, bool support)
Copied!
    proposalId: ID of a proposal in which to cast a vote.
    support: A boolean of true for 'yes' or false for 'no' on the proposal vote.
    RETURN: No return, reverts on error.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
gov.castVote(proposalId, true);
Copied!
Web3 1.2.6
1
const tx = gov.methods.castVote(proposalId, false).send({ from: sender });
Copied!

Cast Vote By Signature

Cast a vote on a proposal. The account's voting weight is determined by the number of votes the account had delegated at the time that proposal state became active. This method has the same purpose as Cast Vote but it instead enables offline signatures to participate in Compound governance voting. For more details on how to create an offline signature, review EIP-712.
Governor Alpha
1
function castVoteBySig(uint proposalId, bool support, uint8 v, bytes32 r, bytes32 s)
Copied!
    proposalId: ID of a proposal in which to cast a vote.
    support: A boolean of true for 'yes' or false for 'no' on the proposal vote.
    v: The recovery byte of the signature.
    r: Half of the ECDSA signature pair.
    s: Half of the ECDSA signature pair.
    RETURN: No return, reverts on error.
Solidity
1
GovernorAlpha gov = GovernorAlpha(0x123...); // contract address
2
gov.castVoteBySig(proposalId, true, v, r, s);
Copied!
Web3 1.2.6
1
const tx = await gov.methods.castVoteBySig(proposalId, false, v, r, s).send({});
Copied!

Timelock

The Timelock is a decentralized owner of ZestyMarket and can execute any functions and store token like a treasury. We will refer to the Timelock contract and Zesty DAO interchangeably.
The Timelock has a hard-coded minimum delay of 2 days, which is the least amount of notice possible for a governance action. Each proposed action will be published at a minimum of 2 days in the future from the time of announcement. Major upgrades, such as changing the risk system, may have a 14 day delay.
The Timelock is controlled by the governance module; pending and completed governance actions can be monitored on the Timelock Dashboard.

Pause Guardian

The Pause Guardian address is assigned to the Timelock contract.
Last modified 3mo ago