/qoda-dao

Qoda DAO smart contracts.

Primary LanguageSolidityOtherNOASSERTION

Qoda DAO

Build Instructions

  1. Install npm dependencies: npm install
  2. Install foundry according to Foundry Book Installation Page
  3. Compile smart contracts: forge build
  4. Format code: forge fmt
  5. Run test: forge test
  6. Run single test with prefix testTotal: forge test -vvv --match-test testTotal
  7. Run test in forked network: forge test --fork-url https://[NODE_PROVIDER]

Mechanism

User can stake in pre-defined ERC20 token and earn

veQoda balance will be computed , so no claiming is needed to

There is no lock-up period in place, but to encourage continuous staking, unstaking for any method at any point of time will reset all veQoda balance to 0.

Total Ve Calculation

For reward distribution, reward at each epoch will be distributed according to account ve / total ve. Ve balance will be calculated automatically without user explicitly claiming token. To avoid iterating all user accounts to deduce total ve at the end of each epoch, total ve will be calculated as follow:

Terminology:

  1. Staked token amount of Account A = S(A) = StakingInfo.amount
  2. Last ve balance of Account A = LS(A) = StakingInfo.amountVe
  3. Last ve claim time of Account A = T(A) = StakingInfo.lastUpdateSec
  4. Reward distribution rate = R = MethodInfo.vePerDay

$Total\ Ve\ at\ time\ T$
$= LS(A) + S(A) \cdot [T - T(A)] \cdot R + LS(B) + S(B) \cdot [T - T(B)] \cdot R + ...$
$= [LS(A) + LS(B) + ...] + S(A) \cdot T \cdot R - S(A) \cdot T(A) \cdot R + S(B) \cdot T \cdot R - S(B) \cdot T(B) \cdot R + ...$
$= [LS(A) + LS(B) + ...] + [S(A) + S(B) + ...] \cdot T \cdot R - [S(A) \cdot T(A) + S(B) \cdot T(B) + ...] \cdot R$
$= [LS(A) + LS(B) + ...] + { [S(A) + S(B) + ...] \cdot T - [S(A) \cdot T(A) + S(B) \cdot T(B) + ...] } \cdot R $

So by keeping track of following upon balance update:

  1. [LS(A) + LS(B) + ...] = MethodInfo.totalVe
  2. [S(A) + S(B) + ...] = MethodInfo.tokenAmount
  3. [S(A) T(A) + S(B) T(B) + ...] = MethodInfo.tokenAmountTime

Total ve at any given time can be calculated as totalVe + (tokenAmount * time - tokenAmountTime) * vePerDay, as shown in totalVe() of VeQoda contract To support multiple ve per day distribution, tokenAmount, tokenAmountTime and vePerDay should be stored separately

Development Guide:

  1. All contract implementations should be made upgradable (except QodaToken) so DAO can propose upgrade to it.
  2. If for-loop is used, make sure looping condition is exposed as parameter to avoid breaching gas limit upon iteration, unless number of entries is guaranteed to be small.
  3. Any account can act on behalf on another account to facilitate support, unless the operation will damage benefit of target account (e.g. unstake).
  4. Coding style should follow Solidity Style Guide and NatSpec Comment Format