Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Migrator #410

Merged
merged 14 commits into from
Apr 26, 2024
Merged

Add Migrator #410

merged 14 commits into from
Apr 26, 2024

Conversation

shahthepro
Copy link
Collaborator

If you made a contract change, make sure to complete the checklist below before merging it in master.

Contract change checklist:

  • Code reviewed by 2 reviewers.
  • Copy & paste code review security checklist below this checklist.
  • Unit tests pass
  • Slither tests pass with no warning
  • Echidna tests pass if PR includes changes to OUSD contract (not automated, run manually on local)

@shahthepro shahthepro changed the base branch from DanielVF/xogn2 to shah/ogn-rewards-source April 21, 2024 15:56
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/OgvStaking.sol Outdated Show resolved Hide resolved
contracts/OgvStaking.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
contracts/Migrator.sol Outdated Show resolved Hide resolved
@shahthepro shahthepro marked this pull request as ready for review April 26, 2024 09:28
@DanielVF
Copy link
Contributor

Code Review - Migrator

Requirements

We wish to provide one transaction + approval of OGV and veOGV stakes to OGN and xOGN stakes.

This contract collects ogv to the user's address, and then burns it there using an approval. OGN is then sent to a new stake for the user's address and/or sent directly to the user.

A simple migrate method can just burn and transfers without touching the staking system.

Authentication

  • Never use tx.origin
  • Every external/public function is supposed to be externally accessible
  • Every external/public function has the correct authentication

Ethereum

  • Contract does not send or receive Ethereum.
  • Contract has no payable methods.

Cryptographic code

No crypto

Gas problems

  • Contracts with for loops must have either:
    • A way to remove items
    • Can be upgraded to get unstuck
    • Size can only controlled by admins
  • Contracts with for loops must not allow end users to add unlimited items to a loop that is used by others or admins.

Black magic

  • Does not contain selfdestruct
  • Does not use delegatecall outside of proxying. If an implementation contract were to call delegatecall under attacker control, it could call selfdestruct the implementation contract, leading to calls through the proxy silently succeeding, even though they were failing.
  • Address.isContract should be treated as if could return anything at any time, because that's reality.

Overflow

  • Code is solidity version >= 0.8.0
  • All for loops use uint256

Proxy

  • No storage variable initialized at definition when contract used as a proxy implementation.

Events

  • All state changing functions emit events

Medium Checks

Rounding

  • Contract rounds in the protocols favor
  • Contract does not have bugs from loosing rounding precision
  • Code correctly multiplies before division
  • Contract does not have bugs from zero or near zero amounts

Dependencies

  • Review any new contract dependencies thoroughly (e.g. OpenZeppelin imports) when new dependencies are added or version of dependencies changes.
  • If OpenZeppelin ACL roles are use review & enumerate all of them.
  • Check OpenZeppelin security vulnerabilities and see if any apply to current PR considering the version of OpenZeppelin contract used.

External calls

  • Contract addresses passed in are validated
  • No unsafe external calls
  • Reentrancy Guards
    - [ ] guards on all state changing functions
    • Still doesn't protect against external contracts changing the state of the world if they are called.
    • All external contracts used are hardcoded and safe.
  • No malicious behaviors
  • Low level call() must require success.
  • No slippage attacks (we need to validate expected tokens received)
  • Oracles, one of:
    • No oracles
    • Oracles can't be bent
    • If oracle can be bent, it won't hurt us.
  • Do not call balanceOf for external contracts to determine what they will do when they use internal accounting

Tests

  • Each publicly callable method has a test
  • Each logical branch has a test
  • Each require() has a test
  • Edge conditions are tested
  • If tests interact with AMM make sure enough edge cases (pool tilts) are tested. Ideally with fuzzing.

Deploy

Deploy file not yet written

Logic

  • Public methods only send funds to msg.sender
  • Contract only pulls funds from msg.sender
  • Contract does not hold any veOGV
  • All converted OGN is distributed to the user

Logic looks correct.

Deployment Considerations

No deploy yet

Internal State

  • End time can only be written once
  • End time is after start time
  • Once started, OGN balance will always be sufficient to migrate everyone, until migration over.

Attack

This code will hold and then distribute 40%ish of the circulating supply of OGN. An exploit could have major financial consequences for token holders.

Although OGV is the current governance token and xOGN will be the future governance token, this migration contract should not be able to directly cause a loss of governance, since during the migration period, a multisig will temporary control governance.

We will be topping off the code with excess OGN tokens, since we don't know precisely when the migration will start. If the deployer still had governance, they could skim off excess tokens. We plan to move tokens to this contract and start() it from the same governance transaction, which means the governance action would fail if the migration contract was not owned by governance.

A concern would be if a user could take OGV tokens from someone else. This does not appear to be possible since all funds pulls are from msg.sender.

Another concern would be getting too many tokens for a conversion. The conversion rate matches the governance proposal. We will have another sanity check in that the amount of OGN initially transferred to the contract will be checked. Finally, the isSolvent modifier should revert if we give out too many tokens.

Flavor

Flavor is good.

@DanielVF
Copy link
Contributor

Code Review - veOGV

Requirements

  • Instant unstakes
  • Migrator controlled unstakes to the user
  • All staking disabled

Authentication

  • Never use tx.origin
  • Every external/public function is supposed to be externally accessible
  • Every external/public function has the correct authentication

Ethereum

  • Contract does not send or receive Ethereum.
  • Contract has no payable methods.

Cryptographic code

no crypto

Gas problems

  • Contracts with for loops must have either:
    • A way to remove items
    • Size can be changed by user
    • Can be upgraded to get unstuck
    • Size can only controlled by admins
  • Contracts with for loops must not allow end users to add unlimited items to a loop that is used by others or admins.

Black magic

  • Does not contain selfdestruct
  • Does not use delegatecall outside of proxying. If an implementation contract were to call delegatecall under attacker control, it could call selfdestruct the implementation contract, leading to calls through the proxy silently succeeding, even though they were failing.
  • Address.isContract should be treated as if could return anything at any time, because that's reality.

Overflow

  • Code is solidity version >= 0.8.0
  • All for loops use uint256

Proxy

  • No storage variable initialized at definition when contract used as a proxy implementation.

Events

  • All state changing functions emit events

Rounding

  • Contract rounds in the protocols favor
  • Contract does not have bugs from loosing rounding precision
  • Code correctly multiplies before division
  • Contract does not have bugs from zero or near zero amounts

Dependencies

  • Review any new contract dependencies thoroughly (e.g. OpenZeppelin imports) when new dependencies are added or version of dependencies changes.
  • If OpenZeppelin ACL roles are use review & enumerate all of them.
  • Check OpenZeppelin security vulnerabilities and see if any apply to current PR considering the version of OpenZeppelin contract used.

External calls

  • Contract addresses passed in are validated
  • No unsafe external calls
  • Reentrancy
    - [ ] guards on all state changing functions
    - [x] Only interact with trusted contracts
  • No malicious behaviors
  • Low level call() must require success.
  • No slippage attacks (we need to validate expected tokens received)
  • Oracles, one of:
    • No oracles
    • Oracles can't be bent
    • If oracle can be bent, it won't hurt us.
  • Do not call balanceOf for external contracts to determine what they will do when they use internal accounting

Deploy

No deploy code written

When deploy code is written, a collect call should be made just before this upgrade.

Logic

Logic appears correct.

Internal State

  • accRewardsPerShare no longer changes
  • No new lockups can be pushed

Attack

This contract holds 3.7 billion OGV, which will soon be convertible to OGN - 40 something million at today's prices.

An attack would attempt to gain access to another user's tokens, get more tokens than owed, or double withdraw.

  • All unstakes transfer OGV to the stake owner
  • The amount calculations to send to the user are a simple sum of staked amounts being cleared
  • Stakes are disabled in storage as soon as amounts are added to total
  • Duplicate stake ids in a removal should fail

Flavor

The code is slightly awkward because of the tension between keeping backwards compatibility versus most functionality no longer being needed. However there is not any anticipated future work on this contract, and it's okay as is.

@DanielVF
Copy link
Contributor

Noting that we should do some fork testing of this during the audit.

@DanielVF DanielVF merged commit 3c3b799 into shah/ogn-rewards-source Apr 26, 2024
3 checks passed
@DanielVF DanielVF deleted the shah/migrator-rebased branch April 26, 2024 20:08
DanielVF added a commit that referenced this pull request May 16, 2024
* Add OGNRewardsSource contract

* Make collectRewards only callable by RewardsTarget

* Draft xOGN staking contract

* Correct maxStakeDuration

* Add penalty event

* Change names

* Fix lockup ID

* Revert change and cast properly

* Gas opts

* Remove casting

* Add `getLockupsCount` method (#411)

* Allow non-duration change amount increase staking extends

* Add tests, add move lockupid code

* Add Migrator (#410)

* Add Migrator contract

* Fix some tests

* Code review changes

* Update OgvStaking tests

* Disable delegation tests

* Allow just unstakes

* Fix comment

* More cleanup

* Fix brownie tests

* Return 0 if uninitialized (#415)

* Check available balance in `previewRewards` (#413)

* Check available balance in `previewRewards`

* Chore: forge fmt

---------

Co-authored-by: Daniel Von Fange <[email protected]>

---------

Co-authored-by: Daniel Von Fange <[email protected]>
shahthepro added a commit that referenced this pull request May 22, 2024
* Add OGNRewardsSource contract

* Make collectRewards only callable by RewardsTarget

* Draft xOGN staking contract

* Correct maxStakeDuration

* Add penalty event

* Change names

* Fix lockup ID

* Revert change and cast properly

* Gas opts

* Remove casting

* Add `getLockupsCount` method (#411)

* Allow non-duration change amount increase staking extends

* Add tests, add move lockupid code

* Add Migrator (#410)

* Add Migrator contract

* Fix some tests

* Code review changes

* Update OgvStaking tests

* Disable delegation tests

* Allow just unstakes

* Fix comment

* More cleanup

* Fix brownie tests

* Return excess OGN rather than burn

* Simplify calculation

* Return 0 if uninitialized (#415)

* Check available balance in `previewRewards` (#413)

* Check available balance in `previewRewards`

* Chore: forge fmt

---------

Co-authored-by: Daniel Von Fange <[email protected]>

* Fix: Remove unused errors (#416)

* First draft of deploy file

* Add fork test tooling (#419)

---------

Co-authored-by: Shahul Hameed <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants