celo-org / celo-monorepo

Official repository for core projects comprising the Celo platform
https://celo.org
Apache License 2.0
687 stars 362 forks source link

Add FeeCurrencyDirectory to Anvil migrations #10992

Closed arthurgousset closed 2 months ago

arthurgousset commented 2 months ago

Description

Adds the new FeeCurrencyDirectory contract to the Anvil migration script.

Changes

  1. deploys and proxies the FeeCurrencyDirectory contract
  2. registers FeeCurrencyDirectory in the Registry
  3. adds three existing cStables (cUSD, cEUR, and cREAL) to the FeeCurrencyDirectory

Other changes

  1. adds is IOracle to the class definition in SortedOracles
  2. removes a duplicate import in Migrations.s.sol

Tested

Yes, tested locally:

Steps to reproduce tests locally Requirement: 1. Have foundry installed 2. Be in the `packages/protocol` directory Tests: 1. Run migration script (in a different Terminal) ```sh $ ./migrations_sol/create_and_migrate_anvil_devchain.sh ``` 1. Check that Anvil is running ```sh $ nc -z localhost 8546 Connection to localhost port 8546 [tcp/*] succeeded! ``` Source: [start_anvil.sh](https://github.com/celo-org/celo-monorepo/blob/a36eae5bc2c9c2071fb942199b1ba265f3937c17/packages/protocol/migrations_sol/start_anvil.sh#L7) Anvil is running ✅ 1. get the `FeeCurrencyDirectory` address from the `Registry`: ```sh export REGISTRY_ADDRESS="0x000000000000000000000000000000000000ce10" export ANVIL_PORT=8546 cast call \ $REGISTRY_ADDRESS \ "getAddressForStringOrDie(string calldata identifier)" \ "FeeCurrencyDirectory" \ --rpc-url=http://127.0.0.1:$ANVIL_PORT 0x00000000000000000000000042fe5a2a61ed9705eb2f08a04a58ceb606d22f6a ``` ```sh cast abi-decode \ "getAddressForStringOrDie(string calldata identifier)(address)" \ "0x00000000000000000000000042fe5a2a61ed9705eb2f08a04a58ceb606d22f6a" 0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a ``` `FeeCurrencyDirectory` is registered in the `Registry` ✅ 1. get registered currencies from the `FeeCurrencyDirectory` contract ```sh export FEECURRENCYDIRECTORY_PROXY_ADDRESS=0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a export ANVIL_PORT=8546 cast call \ $FEECURRENCYDIRECTORY_PROXY_ADDRESS \ "getCurrencies()" \ --rpc-url=http://127.0.0.1:$ANVIL_PORT 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000e6774be4e5f97db10cafb4c00c74cfbdcdc434d9000000000000000000000000b7a33b4ad2b1f6b0a944232f5c71798d27ad92720000000000000000000000002a3733dbc31980f02b12135c809b5da33bf3a1e9 ``` ```sh cast abi-decode \ "getCurrencies()(address[] memory)" \ "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000e6774be4e5f97db10cafb4c00c74cfbdcdc434d9000000000000000000000000b7a33b4ad2b1f6b0a944232f5c71798d27ad92720000000000000000000000002a3733dbc31980f02b12135c809b5da33bf3a1e9" [0xe6774BE4E5f97dB10cAFB4c00C74cFbdCDc434D9, 0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272, 0x2A3733dBc31980f02b12135C809b5da33BF3a1e9] ``` 3 currencies are registered in the `FeeCurrencyDirectory` ✅ As expected, the registered currencies are: cUSD ✅ ```sh cast call \ 0xe6774BE4E5f97dB10cAFB4c00C74cFbdCDc434D9 \ "name()" \ --rpc-url=http://127.0.0.1:8546 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b43656c6f20446f6c6c6172000000000000000000000000000000000000000000 ``` ```sh cast abi-decode \ "name()(string memory)" \ "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b43656c6f20446f6c6c6172000000000000000000000000000000000000000000" "Celo Dollar" ``` cEUR ✅ ```sh cast call \ 0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272 \ "name()" \ --rpc-url=http://127.0.0.1:8546 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000943656c6f204575726f0000000000000000000000000000000000000000000000 ``` ```sh cast abi-decode \ "name()(string memory)" \ "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000943656c6f204575726f0000000000000000000000000000000000000000000000" "Celo Euro" ``` cREAL ✅ ```sh cast call \ 0x2A3733dBc31980f02b12135C809b5da33BF3a1e9 \ "name()" \ --rpc-url=http://127.0.0.1:8546 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001343656c6f204272617a696c69616e205265616c00000000000000000000000000 ``` ```sh cast abi-decode \ "name()(string memory)" \ "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001343656c6f204272617a696c69616e205265616c00000000000000000000000000" "Celo Brazilian Real" ``` 1. Get exchange rate for a currency: ```sh $ cast call \ 0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a \ "getExchangeRate(address)(uint256, uint256)" \ 0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272 \ --rpc-url=http://127.0.0.1:8546 1000000000000000000000000 [1e24] 1000000000000000000000000 [1e24] ``` Calling the `getExchangeRate` function on a registered currency returns an exchange rate ✅ 1. Terminate Anvil: ```sh $ kill $(lsof -i tcp:8546 | tail -n 1 | awk '{print $2}') ``` Source: [start_anvil.sh](https://github.com/celo-org/celo-monorepo/blob/a36eae5bc2c9c2071fb942199b1ba265f3937c17/packages/protocol/migrations_sol/start_anvil.sh#L9)

Related issues

Backwards compatibility

Yes, only adds to the migration script, doesn't alter existing expectations and behaviour.

Documentation

No docs changes

arthurgousset commented 2 months ago

Notes-to-self

create_and_migrate_anvil_devchain.sh Source: packages/protocol/migrations_sol/create_and_migrate_anvil_devchain.sh

  1. Entry point of workflow
  2. Starts anvil with start_anvil.sh script
  3. Deploys precompiles with deploy_precompiles.sh script
  4. Sets registry contract at specified addresses using registry bytecode

start_anvil.sh Source: packages/protocol/migrations_sol/start_anvil.sh

  1. Start anvil instance at specified port and console logs when anvil is running

deploy_precompiles.sh Source: packages/protocol/migrations_sol/deploy_precompiles.sh

  1. Gets bytecodes from build artifacts, chooses precompile addresses, and sets bytecode at specified addresses on anvil

Migration.s.sol Source: packages/protocol/migrations_sol/Migration.s.sol

  1. run() function is the main entry point of the script

migrationsConfig.json Source: packages/protocol/migrations_sol/migrationsConfig.json

  1. Contains contract initialisation data and configs

FeeCurrencyDirectory.sol Source: packages/protocol/contracts-0.8/common/FeeCurrencyDirectory.sol

  1. Set a currency config
/**
   * @notice Sets the currency configuration for a token.
   * @dev This action can only be performed by the contract owner.
   * @param token The token address.
   * @param oracle The oracle address for price fetching.
   * @param intrinsicGas The intrinsic gas value for transactions.
   */
  function setCurrencyConfig(
    address token,
    address oracle,
    uint256 intrinsicGas
  )

IFeeCurrencyDirectory.sol Source: packages/protocol/contracts-0.8/common/interfaces/IFeeCurrencyDirectory.sol

  1. Specifies interface including CurrencyConfig struct

run_integration_tests_in_anvil.sh Source: packages/protocol/migrations_sol/run_integration_tests_in_anvil.sh

  1. Generates devchain and runs simple integration test defined in Integration.t.sol

integration_tests.sh Source: packages/protocol/migrations_sol/integration_tests.sh

  1. Uses forge to run test defined in Integration.t.sol script

Integration.t.sol Source: packages/protocol/test-sol/integration/Integration.t.sol

  1. High-level test file that defines account1, account2, and registry address
  2. Currently doesn't test anything specific to other contracts as far as I can tell

FeeCurrencyDirectory.t.sol Source: packages/protocol/test-sol/common/FeeCurrencyDirectory.t.sol

  1. Foundry tests for FeeCurrencyDirectory

protocol_tests.yml Source: .github/workflows/protocol_tests.yml

  1. Workflow that runs Foundry-based tests
  2. Runs migration test defined in run_integration_tests_in_anvil.sh script

celo-monorepo.yml Source: .github/workflows/celo-monorepo.yml

  1. Not relevant to this PR, because it uses the devchain, which is currently Ganache-based.
arthurgousset commented 2 months ago

Test migration locally

Requirement:

  1. Have foundry installed
  2. Be in the packages/protocol directory

Steps to reproduce:

  1. Compile contracts
    $ forge --version && forge compile
  2. Run migration test
    $ ./migrations_sol/run_integration_tests_in_anvil.sh

Test FeeCurrencyDirectory migration locally

Possible (short-term) solutions:

  1. Manually run migration and run the devchain locally
  2. Manually call getCurrencyConfig(stabletoken) on the local devchain

Possible (longer-term) solutions:

  1. Add FeeCurrencyDirectory-related test to IntegrationTest (in Integration.t.sol), run integration test
  2. Run FeeCurrencyDirectory tests (in FeeCurrencyDirectory.t.sol) using forge, if they run against the devchain. I don’t think that’s the case, but let’s see.
arthurgousset commented 2 months ago

(note-to-self) Useful related PRs:

arthurgousset commented 2 months ago

At this point the compilation succeeds as expected, and the migration transactions are successful.

Next, I'll run a local Anvil instance (with all the migrations), and I'll interact with the deployed FeeCurrencyDirectory via cast to assert the FeeCurrencyDirectory contract works as expected:

  1. get FeeCurrencyDirectory contract from the Registry
  2. get the CurrencyConfig for the registered mock token
arthurgousset commented 2 months ago

(note-to-self)

  1. Check that Anvil is running

    $ export ANVIL_PORT=8546
    $ nc -z localhost $ANVIL_PORT
    Connection to localhost port 8546 [tcp/*] succeeded!

    Source: start_anvil.sh

  2. Terminate Anvil:

    $ export ANVIL_PORT=8546
    $ kill $(lsof -i tcp:$ANVIL_PORT | tail -n 1 | awk '{print $2}')

    Source: start_anvil.sh

arthurgousset commented 2 months ago

At this point (https://github.com/celo-org/celo-monorepo/pull/10992/commits/a36eae5bc2c9c2071fb942199b1ba265f3937c17), the local tests pass.

Local test

We can:

  1. get the FeeCurrencyDirectory address from the Registry:

    export REGISTRY_ADDRESS="0x000000000000000000000000000000000000ce10"
    export ANVIL_PORT=8546

    cast call \
    $REGISTRY_ADDRESS \
    "getAddressForStringOrDie(string calldata identifier)" \
    "FeeCurrencyDirectory" \
    --rpc-url=http://127.0.0.1:$ANVIL_PORT
    
    0x00000000000000000000000042fe5a2a61ed9705eb2f08a04a58ceb606d22f6a
    cast abi-decode \
    "getAddressForStringOrDie(string calldata identifier)(address)" \
    "0x00000000000000000000000042fe5a2a61ed9705eb2f08a04a58ceb606d22f6a"
    
    0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a
  2. get registered currencies from the FeeCurrencyDirectory contract

    export FEECURRENCYDIRECTORY_PROXY_ADDRESS=0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a
    export ANVIL_PORT=8546
    export MOCKTOKEN_ADDRESS=0xefB84935239dAcdecF7c5bA76d8dE40b077B7b33
    
    cast call \
    $FEECURRENCYDIRECTORY_PROXY_ADDRESS \
    "getCurrencies()" \
    --rpc-url=http://127.0.0.1:$ANVIL_PORT
    
    0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000e6774be4e5f97db10cafb4c00c74cfbdcdc434d9000000000000000000000000b7a33b4ad2b1f6b0a944232f5c71798d27ad92720000000000000000000000002a3733dbc31980f02b12135c809b5da33bf3a1e9
    cast abi-decode \
    "getCurrencies()(address[] memory)" \
    "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000e6774be4e5f97db10cafb4c00c74cfbdcdc434d9000000000000000000000000b7a33b4ad2b1f6b0a944232f5c71798d27ad92720000000000000000000000002a3733dbc31980f02b12135c809b5da33bf3a1e9"
    
    [0xe6774BE4E5f97dB10cAFB4c00C74cFbdCDc434D9, 0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272, 0x2A3733dBc31980f02b12135C809b5da33BF3a1e9]

    As expected, the registered currencies are

    cUSD:

    cast call \
    0xe6774BE4E5f97dB10cAFB4c00C74cFbdCDc434D9 \
    "name()" \
    --rpc-url=http://127.0.0.1:8546
    0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b43656c6f20446f6c6c6172000000000000000000000000000000000000000000
    cast abi-decode \
    "name()(string memory)" \
    "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b43656c6f20446f6c6c6172000000000000000000000000000000000000000000"
    "Celo Dollar"

    cEUR:

    cast call \
    0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272 \
    "name()" \
    --rpc-url=http://127.0.0.1:8546
    0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000943656c6f204575726f0000000000000000000000000000000000000000000000
    cast abi-decode \
    "name()(string memory)" \
    "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000943656c6f204575726f0000000000000000000000000000000000000000000000"
    "Celo Euro"

    cREAL:

    cast call \
    0x2A3733dBc31980f02b12135C809b5da33BF3a1e9 \
    "name()" \
    --rpc-url=http://127.0.0.1:8546
    0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001343656c6f204272617a696c69616e205265616c00000000000000000000000000
    cast abi-decode \
    "name()(string memory)" \
    "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001343656c6f204272617a696c69616e205265616c00000000000000000000000000"
    "Celo Brazilian Real"
arthurgousset commented 2 months ago

As of 8b910b7b3d9b988f6f20b02d5f5959c618682cc1, the migration script sets the oracle in CurrencyConfig to a MockOracle.sol contract (which implements IOracle.sol), and sets an arbitrary exchange rate of $\frac{10}{5}$.

This works as expected :white_check_mark:

Calling the getExchangeRate function on a registered currency returns the arbitrary exchange rate

$ cast call \
0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a \
"getExchangeRate(address)(uint256, uint256)" \
0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272 \
--rpc-url=http://127.0.0.1:8546/
10
5
arthurgousset commented 2 months ago

As of https://github.com/celo-org/celo-monorepo/pull/10992/commits/1c04e8ba7ea1c632754709bd560f7b9c58f0aa90, the migration script sets the oracle in CurrencyConfig to the SortedOracles.sol contract (which implements IOracle.sol).

This works as expected ✅

Calling the getExchangeRate function on a registered currency returns an exchange rate:

$ cast call \
0x42Fe5a2A61ed9705eb2F08a04A58CEB606D22f6a \
"getExchangeRate(address)(uint256, uint256)" \
0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272 \
--rpc-url=http://127.0.0.1:8546
1000000000000000000000000 [1e24]
1000000000000000000000000 [1e24]