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 FeeCurrencyDirectory to Anvil migrations #10992

Conversation

arthurgousset
Copy link
Member

@arthurgousset arthurgousset commented May 13, 2024

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:

  • get the FeeCurrencyDirectory address from the Registry
  • get registered currencies from the FeeCurrencyDirectory contract
  • get the exchange rate for a currency from the FeeCurrencyDirectory contract
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)

    $ ./migrations_sol/create_and_migrate_anvil_devchain.sh
  2. Check that Anvil is running

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

    Source: start_anvil.sh

    Anvil is running ✅

  3. 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

    FeeCurrencyDirectory is registered in the Registry

  4. get registered currencies from the FeeCurrencyDirectory contract

    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
    cast abi-decode \
    "getCurrencies()(address[] memory)" \
    "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000e6774be4e5f97db10cafb4c00c74cfbdcdc434d9000000000000000000000000b7a33b4ad2b1f6b0a944232f5c71798d27ad92720000000000000000000000002a3733dbc31980f02b12135c809b5da33bf3a1e9"
    
    [0xe6774BE4E5f97dB10cAFB4c00C74cFbdCDc434D9, 0xb7a33b4ad2B1f6b0a944232F5c71798d27Ad9272, 0x2A3733dBc31980f02b12135C809b5da33BF3a1e9]

    3 currencies are registered in the FeeCurrencyDirectory ✅ 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"
  5. Get exchange rate for a currency:

    $ 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 ✅

  6. Terminate Anvil:

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

    Source: start_anvil.sh

Related issues

Backwards compatibility

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

Documentation

No docs changes

@arthurgousset
Copy link
Member Author

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
Copy link
Member Author

arthurgousset commented May 13, 2024

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
Copy link
Member Author

…interface

I was calling `initialize()`, but that function is defined in `FeeCurrencyDirectory` not `IFeeCurrencyDirectory`.

Also updates string length, which was previously forgotten.

At this point the compilation succeeds as expected, and the migration transactions are successful.
@arthurgousset
Copy link
Member Author

arthurgousset commented May 17, 2024

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
Copy link
Member Author

arthurgousset commented May 17, 2024

(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
Copy link
Member Author

arthurgousset commented May 17, 2024

At this point (a36eae5), 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"

This means, all currencies registered in the `FeeCurrencyDirectory` now support the `getExchangeRate` function, which uses the MockOracle contract under the hood.
@arthurgousset
Copy link
Member Author

arthurgousset commented May 20, 2024

As of 8b910b7, 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 ✅

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 arthurgousset marked this pull request as ready for review May 20, 2024 11:10
@arthurgousset arthurgousset requested a review from a team as a code owner May 20, 2024 11:10
…grations' of github.com:celo-org/celo-monorepo into arthurgousset/feat/add-FeeCurrencyDirectory-to-Anvil-migrations
The `SortedOracles.sol` contract already implements the `IOracle.sol` interface. This commit only adds it to the contract definition for ease of reference.
…cles`

The latest `SortedOracles.sol` implementation implements the `IOracle.sol` interface. That means it implements the required `getExchangeRate()` function.

That means the `MockOracle.sol` contract is not required in the migrations.
@arthurgousset
Copy link
Member Author

As of 1c04e8b, 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]

@arthurgousset arthurgousset merged commit eded310 into master May 20, 2024
24 checks passed
@arthurgousset arthurgousset deleted the arthurgousset/feat/add-FeeCurrencyDirectory-to-Anvil-migrations branch May 20, 2024 16:19
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.

Add FeeCurrencyDirectory to Anvil migrations
2 participants