diff --git a/.gitignore b/.gitignore index 463e6cc..2ed0d31 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,6 @@ docs/ broadcast/* # Bun -node_modules/ \ No newline at end of file +node_modules/ + +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..935477e --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +include .env + +checkL1: + @echo "Setting environment variable LIVE_DEPLOY_READ_FILE_NAME to $(file)" + @export LIVE_DEPLOY_READ_FILE_NAME=$(file) && forge test --mp test/LiveDeploy.t.sol --fork-url=${L1_RPC_URL} + +checkL2: + @echo "Setting environment variable LIVE_DEPLOY_READ_FILE_NAME to $(file)" + @export LIVE_DEPLOY_READ_FILE_NAME=$(file) && forge test --mp test/LiveDeploy.t.sol --fork-url=${L2_RPC_URL} + +deployL1: + @echo "Setting environment variable LIVE_DEPLOY_READ_FILE_NAME to $(file)" + @export LIVE_DEPLOY_READ_FILE_NAME=$(file) && forge script script/deploy/deployAll.s.sol --sig "run(string)" $(file) --fork-url=${L1_RPC_URL} + +deployL2: + @echo "Setting environment variable LIVE_DEPLOY_READ_FILE_NAME to $(file)" + @export LIVE_DEPLOY_READ_FILE_NAME=$(file) && forge script script/deploy/deployAll.s.sol --sig "run(string)" $(file) --fork-url=${L1_RPC_URL} + +live-deployL1: + @echo "Setting environment variable LIVE_DEPLOY_READ_FILE_NAME to $(file)" + @export LIVE_DEPLOY_READ_FILE_NAME=$(file) && forge script script/deploy/deployAll.s.sol --sig "run(string)" $(file) --fork-url=${L1_RPC_URL} --private-key=$(PRIVATE_KEY) --broadcast --slow --verify + +live-deployL2: + @echo "Setting environment variable LIVE_DEPLOY_READ_FILE_NAME to $(file)" + @export LIVE_DEPLOY_READ_FILE_NAME=$(file) && forge script script/deploy/deployAll.s.sol --sig "run(string)" $(file) --fork-url=${L1_RPC_URL} --private-key=$(PRIVATE_KEY) --broadcast --slow --verify + +prettier: + prettier --write '**/*.{md,yml,yaml,ts,js}' + +solhint: + solhint -w 0 'src/**/*.sol' + +slither: + slither src + +prepare: + husky + +deploy-createx-l1: + forge script script/DeployCustomCreatex.s.sol --rpc-url $L1_RPC_URL --private-key $PRIVATE_KEY --slow --no-metadata + +deploy-createx-l2: + forge script script/DeployCustomCreatex.s.sol --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --slow --no-metadata + +check-configs: + bun lzConfigCheck.cjs \ No newline at end of file diff --git a/deployment-config/boba-eth-l1-08-09-24.json b/deployment-config/boba-eth-l1-08-09-24.json index ad107ea..33eda44 100644 --- a/deployment-config/boba-eth-l1-08-09-24.json +++ b/deployment-config/boba-eth-l1-08-09-24.json @@ -1,7 +1,7 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "baseDecimals": "18", + "boringVaultAndBaseDecimals": "18", "boringVault": { "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000001", "boringVaultName": "Boba Native Yield Nucleus Token", diff --git a/deployment-config/boba-eth-l2-08-09-24.json b/deployment-config/boba-eth-l2-08-09-24.json index 547df94..9aa29f4 100644 --- a/deployment-config/boba-eth-l2-08-09-24.json +++ b/deployment-config/boba-eth-l2-08-09-24.json @@ -1,7 +1,7 @@ { "protocolAdmin": "0x0888c3D797E13892C5e67cD802F93Ffe55Ea2826", "base": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000", - "baseDecimals": "18", + "boringVaultAndBaseDecimals": "18", "boringVault": { "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000001", "boringVaultName": "Boba Native Yield Nucleus Token", diff --git a/deployment-config/chains/1.json b/deployment-config/chains/1.json index fc8de28..c9c214a 100644 --- a/deployment-config/chains/1.json +++ b/deployment-config/chains/1.json @@ -1,4 +1,5 @@ { + "name": "Ethereum", "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", "opMessenger": "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", "lzEndpoint": "0x1a44076050125825900e736c501f859c50fE728c", @@ -40,15 +41,24 @@ "priceFeedType": 1 }, "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0": { - "priceFeed": "", + "priceFeed": "0x86392dC19c0b719886221c78AB11eb8Cf5c52812", "rateProvider": "0xa360Df495d0560bDDc5d681B54991629965ae170", "decimals": 18, - "description": "", + "description": "STETH / ETH", "priceFeedType": 0 }, "0x8db2350d78abc13f5673a411d4700bcf87864dde": { "rateProvider": "0x318Da095d602C08eF41319f4c4bA0646d318C906", "decimals": 8 + }, + "0x9ba021b0a9b958b5e75ce9f6dff97c7ee52cb3e6":{ + "priceFeed": "0x19219bc90f48dee4d5cf202e09c438faacfd8bea", + "rateProvider": "0x0000000000000000000000000000000000000000", + "decimals": 18, + "description": "apxETH/ETH", + "priceFeedType": 1 + } + } } \ No newline at end of file diff --git a/deployment-config/chains/11155111.json b/deployment-config/chains/11155111.json new file mode 100644 index 0000000..e900a9a --- /dev/null +++ b/deployment-config/chains/11155111.json @@ -0,0 +1,5 @@ +{ + "name": "Ethereum Sepolia", + "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "lzEndpoint": "0x6EDCE65403992e310A62460808c4b910D972f10f" + } \ No newline at end of file diff --git a/deployment-config/chains/1329.json b/deployment-config/chains/1329.json index 67171d8..4596379 100644 --- a/deployment-config/chains/1329.json +++ b/deployment-config/chains/1329.json @@ -1,4 +1,5 @@ { + "name": "Sei", "balancerVault": "0x0000000000000000000000000000000000000000", "lzEndpoint": "0x1a44076050125825900e736c501f859c50fE728c" } \ No newline at end of file diff --git a/deployment-config/chains/252.json b/deployment-config/chains/252.json index 68c5b63..b7c0c39 100644 --- a/deployment-config/chains/252.json +++ b/deployment-config/chains/252.json @@ -1,4 +1,5 @@ { + "name": "Fraxtal", "balancerVault": "0x0000000000000000000000000000000000000000", "lzEndpoint": "0x1a44076050125825900e736c501f859c50fE728c" } \ No newline at end of file diff --git a/deployment-config/chains/288.json b/deployment-config/chains/288.json index 1d0cca9..21e0d49 100644 --- a/deployment-config/chains/288.json +++ b/deployment-config/chains/288.json @@ -1,4 +1,5 @@ { + "name": "Boba", "balancerVault": "0x0000000000000000000000000000000000000000", "lzEndpoint": "0x0000000000000000000000000000000000000000" } \ No newline at end of file diff --git a/deployment-config/exampleL1.json b/deployment-config/exampleL1.json new file mode 100644 index 0000000..72e92b3 --- /dev/null +++ b/deployment-config/exampleL1.json @@ -0,0 +1,57 @@ +{ + "base": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "18", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000001c", + "boringVaultName": "Nucleus Vault", + "boringVaultSymbol": "NV", + "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000001c", + "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000001c", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "2000", + "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000001c", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 30280, + "tellerContractName": "TellerWithMultiAssetSupport", + "assets": [ + ], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" + ], + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000001c", + "strategist": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", + "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", + "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000001c", + "address": "0x00000000004F96C07B83e86600D86F0000000000" + } +} \ No newline at end of file diff --git a/deployment-config/exampleL2.json b/deployment-config/exampleL2.json new file mode 100644 index 0000000..166ff3a --- /dev/null +++ b/deployment-config/exampleL2.json @@ -0,0 +1,56 @@ +{ + "base":"0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8", + "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", + "boringVaultAndBaseDecimals": "18", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000e", + "boringVaultName": "Nucleus Vault", + "boringVaultSymbol": "NV", + "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000e", + "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000e", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "2000", + "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000e", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 30280, + "tellerContractName": "TellerWithMultiAssetSupport", + "assets": [], + "dvnIfNoDefault": { + "required": [ + "0x6788f52439aca6bff597d3eec2dc9a44b8fee842" + ], + "optional": [ + "0x1feb08b1a53a9710afce82d380b8c2833c69a37e", + "0x87048402c32632b7c4d0a892d82bc1160e8b2393", + "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "0xbd00c87850416db0995ef8030b104f875e1bdd15" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000e", + "strategist": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", + "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", + "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", + "address": "0x00000000004F96C07B83e86600D86F0000000000" + } +} \ No newline at end of file diff --git a/deployment-config/form-btc-testnet-l1-08-30-24.json b/deployment-config/form-btc-testnet-l1-08-30-24.json new file mode 100644 index 0000000..5805959 --- /dev/null +++ b/deployment-config/form-btc-testnet-l1-08-30-24.json @@ -0,0 +1,57 @@ +{ + "base": "0x0893A950E8f80B21658ba35D39d9AB00cCa95589", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "8", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff000000000000000000000000000000000000000011", + "boringVaultName": "Form BTC", + "boringVaultSymbol": "FBTC", + "address": "0x0000000000000000000000000000000000000000" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a250000000000000000000000000000000000000000011", + "address": "0x0000000000000000000000000000000000000000" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f000000000000000000000000000000000000000011", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "0", + "address": "0x0000000000000000000000000000000000000000" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c91000000000000000000000000000000000000000011", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 40270, + "tellerContractName": "TellerWithMultiAssetSupport", + "opMessenger": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + "assets": [], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" + ], + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + "address": "0x0000000000000000000000000000000000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a000000000000000000000000000000000000000011", + "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "address": "0x0000000000000000000000000000000000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c000000000000000000000000000000000000000011", + "address": "0x0000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/deployment-config/form-eth-testnet-l1-08-30-24.json b/deployment-config/form-eth-testnet-l1-08-30-24.json new file mode 100644 index 0000000..bcb0cb6 --- /dev/null +++ b/deployment-config/form-eth-testnet-l1-08-30-24.json @@ -0,0 +1,59 @@ +{ + "base": "0xee44150250AfF3E6aC25539765F056EDb7F85D7B", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "18", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000e", + "boringVaultName": "Form ETH", + "boringVaultSymbol": "FETH", + "address": "0x0000000000000000000000000000000000000000" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000e", + "address": "0x0000000000000000000000000000000000000000" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000e", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "0", + "address": "0x0000000000000000000000000000000000000000" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000e", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 40270, + "tellerContractName": "TellerWithMultiAssetSupport", + "opMessenger": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + "assets": [ + + ], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" + ], + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + "address": "0x0000000000000000000000000000000000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000e", + "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "address": "0x0000000000000000000000000000000000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", + "address": "0x0000000000000000000000000000000000000000" + } + } \ No newline at end of file diff --git a/deployment-config/form-lst-testnet-l1-08-30-24.json b/deployment-config/form-lst-testnet-l1-08-30-24.json new file mode 100644 index 0000000..ae8ec95 --- /dev/null +++ b/deployment-config/form-lst-testnet-l1-08-30-24.json @@ -0,0 +1,57 @@ +{ + "base": "0xee44150250AfF3E6aC25539765F056EDb7F85D7B", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "18", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff000000000000000000000000000000000000000013", + "boringVaultName": "Form LST", + "boringVaultSymbol": "FLST", + "address": "0x0000000000000000000000000000000000000000" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a250000000000000000000000000000000000000000013", + "address": "0x0000000000000000000000000000000000000000" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f000000000000000000000000000000000000000013", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "0", + "address": "0x0000000000000000000000000000000000000000" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c91000000000000000000000000000000000000000013", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 40270, + "tellerContractName": "TellerWithMultiAssetSupport", + "opMessenger": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + "assets": [], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" + ], + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + "address": "0x0000000000000000000000000000000000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a000000000000000000000000000000000000000013", + "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "address": "0x0000000000000000000000000000000000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c000000000000000000000000000000000000000013", + "address": "0x0000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/deployment-config/form-usd-testnet-l1-08-30-24.json b/deployment-config/form-usd-testnet-l1-08-30-24.json new file mode 100644 index 0000000..6206524 --- /dev/null +++ b/deployment-config/form-usd-testnet-l1-08-30-24.json @@ -0,0 +1,57 @@ +{ + "base": "0x66248001cdB1B26B66a89aA7227424Bb14937eCD", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "6", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff000000000000000000000000000000000000000012", + "boringVaultName": "Form USDC", + "boringVaultSymbol": "FUSDC", + "address": "0x0000000000000000000000000000000000000000" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a250000000000000000000000000000000000000000012", + "address": "0x0000000000000000000000000000000000000000" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f000000000000000000000000000000000000000012", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "0", + "address": "0x0000000000000000000000000000000000000000" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c91000000000000000000000000000000000000000012", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 40270, + "tellerContractName": "TellerWithMultiAssetSupport", + "opMessenger": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + "assets": [], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" + ], + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + "address": "0x0000000000000000000000000000000000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a000000000000000000000000000000000000000012", + "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "address": "0x0000000000000000000000000000000000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c000000000000000000000000000000000000000012", + "address": "0x0000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/deployment-config/fraxtal-eth-l1-08-13-24.json b/deployment-config/fraxtal-eth-l1-08-13-24.json index a688703..b57624c 100644 --- a/deployment-config/fraxtal-eth-l1-08-13-24.json +++ b/deployment-config/fraxtal-eth-l1-08-13-24.json @@ -1,7 +1,7 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "baseDecimals": "18", + "boringVaultAndBaseDecimals": "18", "boringVault": { "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000002", "boringVaultName": "Fraxtal Native Yield Nucleus Token", diff --git a/deployment-config/fraxtal-eth-l2-08-13-24.json b/deployment-config/fraxtal-eth-l2-08-13-24.json index d618a44..29fd832 100644 --- a/deployment-config/fraxtal-eth-l2-08-13-24.json +++ b/deployment-config/fraxtal-eth-l2-08-13-24.json @@ -1,7 +1,7 @@ { "protocolAdmin": "0x0888c3D797E13892C5e67cD802F93Ffe55Ea2826", "base": "0xFC00000000000000000000000000000000000006", - "baseDecimals": "18", + "boringVaultAndBaseDecimals": "18", "boringVault": { "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000002", "boringVaultName": "Fraxtal Native Yield Nucleus Token", diff --git a/deployment-config/layerzero/dvn-deployments.json b/deployment-config/layerzero/dvn-deployments.json new file mode 100644 index 0000000..66ce343 --- /dev/null +++ b/deployment-config/layerzero/dvn-deployments.json @@ -0,0 +1,725 @@ +{ + "01node": { + "arbitrum": "0x7a205ed4e3d7f9d0777594501705d8cd405c3b05", + "avalanche": "0xa80aa110f05c9c6140018aae0c4e08a70f43350d", + "bsc": "0x8fc629aa400d4d9c0b118f2685a49316552abf27", + "ethereum": "0x58dff8622759ea75910a08dba5d060579271dcd7", + "fantom": "0x8fc629aa400d4d9c0b118f2685a49316552abf27", + "optimism": "0x969a0bdd86a230345ad87a6a381de5ed9e6cda85", + "polygon": "0xf0809f6e760a5452ee567975eda7a28da4a83d38" + }, + "Animoca-Blockdaemon": { + "arbitrum": "0xddaa92ce2d2fac3f7c5eae19136e438902ab46cc", + "avalanche": "0xffe42dc3927a240f3459e5ec27eaabd88727173e", + "bsc": "0x313328609a9c38459cae56625fff7f2ad6dcde3b", + "ethereum": "0x7e65bdd15c8db8995f80abf0d6593b57dc8be437", + "fantom": "0x313328609a9c38459cae56625fff7f2ad6dcde3b", + "optimism": "0x7b8a0fd9d6ae5011d5cbd3e85ed6d5510f98c9bf", + "polygon": "0xa6f5ddbf0bd4d03334523465439d301080574742" + }, + "Axelar": { + "arbitrum": "0x9d3979c7e3dd26653c52256307709c09f47741e0", + "avalanche": "0xc390fd7ca590a505655eb6c454ed0783c99a2ea9", + "bsc": "0x878c20d3685cdbc5e2680a8a0e7fb97389344fe1", + "blast": "0xb830a5afcbebb936c30c607a18bbba9f5b0a592f", + "ethereum": "0xce5b47fa5139fc5f3c8c5f4c278ad5f56a7b2016", + "fraxtal": "0x025bab5b7271790f9cf188fdce2c4214857f48d3", + "kava": "0x80c4c3768dd5a3dd105cf2bd868fdc50280e398b", + "mantle": "0x6e6359a9abe2e235ef2b82e48f0f93d1ec16afbb", + "optimism": "0x218b462e19d00c8fed4adbce78f33aef88d2ccfc", + "scroll": "0x70cedf51c199fad12c6c0a71cd876af948059540" + }, + "BCW_Group": { + "arbitrum": "0x78203678d264063815dac114ea810e9837cd80f7", + "nova": "0x34730f2570e6cff8b1c91faabf37d0dd917c4367", + "astar": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "avalanche": "0x7b8a0fd9d6ae5011d5cbd3e85ed6d5510f98c9bf", + "base": "0xb3ce0a5d132cd9bf965aba435e650c55edce0062", + "bsc": "0xd36246c322ee102a2203bca9cafb84c179d306f6", + "canto": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "conflux": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "coredao": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "dfk": "0x6a110d94e1baa6984a3d904bab37ae49b90e6b4f", + "dexalot": "0x58dff8622759ea75910a08dba5d060579271dcd7", + "dos": "0x2ac038606fff3fb00317b8f0ccfb4081694acdd0", + "ethereum": "0xe552485d02edd3067fe7fcbd4dd56bb1d3a998d2", + "fuse": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "eon": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "kava": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "klaytn": "0x28af4dadbc5066e994986e8bb105240023dc44b6", + "loot": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "manta": "0x809cde2afcf8627312e87a6a7bbffab3f8f347c7", + "mantle": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "beam": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "meter": "0xc4e1b199c3b24954022fce7ba85419b3f0669142", + "metis": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "moonriver": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "aurora": "0x70bf42c69173d6e33b834f59630dac592c70b369", + "opbnb": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "optimism": "0x73ddc92e39aeda95feb8d3e0008016d9f1268c76", + "orderly": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "polygon": "0xd410ddb726991f372b69a05b006d2ae5a8cedbd6", + "scroll": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "sei": "0x1feb08b1a53a9710afce82d380b8c2833c69a37e", + "shimmer": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "telos": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "tenet": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "tomo": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "xai": "0x34730f2570e6cff8b1c91faabf37d0dd917c4367", + "xpla": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "zksync": "0x0d1bc4efd08940eb109ef3040c1386d09b6334e0", + "zora": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5" + }, + "BWare": { + "arbitrum": "0x9bcd17a654bffaa6f8fea38d19661a7210e22196", + "nova": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "arbitrum-sepolia": "0x9f529527a6810f1b661fb2aeea19378ce5a2c23e", + "astar": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "astar-testnet": "0x44f29fa5237e6ba7bc6dd2fbe758e11ddc5e67a6", + "fuji": "0x0d88ab4c8e8f89d8d758cbd5a6373f86f7bd737b", + "avalanche": "0xcff5b0608fa638333f66e0da9d4f1eb906ac18e3", + "base": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "bsc": "0xfe1cd27827e16b07e61a4ac96b521bdb35e00328", + "bsc-testnet": "0x35fa068ec18631719a7f6253710ba29ab5c5f3b7", + "blast": "0xabc9b1819cc4d9846550f928b985993cf6240439", + "bob": "0x58dff8622759ea75910a08dba5d060579271dcd7", + "holesky-testnet": "0xd0d47c34937ddbebbe698267a6bbb1dace51198d", + "ethereum": "0x7a23612f07d81f16b26cf0b5a4c3eca0e8668df2", + "sepolia": "0xac294c43d44d4131db389256959f33e713851e31", + "fantom": "0x247624e2143504730aec22912ed41f092498bef2", + "fantom-testnet": "0x312f5c396cf78a80f6fac979b55a4ddde44031f0", + "chiado": "0x1c4fc6f1e44eaaef53ac701b7cc4c280f536fa75", + "gnosis": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "gravity": "0xcced05c3667877b545285b25f19f794436a1c481", + "iota": "0xd7bb44516b476ca805fb9d6fc5b508ef3ee9448d", + "linea": "0xf45742bbfabcee739ea2a2d0ba2dd140f1f2c6a3", + "manta": "0xabc9b1819cc4d9846550f928b985993cf6240439", + "mantle": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "metis": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "mode": "0x10901f74cae315f674d3f6fc0645217fe4fad77c", + "moonbase": "0xcc9a31f253970ad46cb45e6db19513e2248ed1fe", + "moonbeam": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "moonriver": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "okx": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "opbnb": "0x2ac038606fff3fb00317b8f0ccfb4081694acdd0", + "optimism": "0x19670df5e16bea2ba9b9e68b48c054c5baea06b8", + "optimism-sepolia": "0x3e9d8fa8067938f2a62baa7114eed183040824ab", + "peaq": "0x790d7b1e97a086eb0012393b65a5b32ce58a04dc", + "polygon": "0x247624e2143504730aec22912ed41f092498bef2", + "zkevm": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "scroll": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "scroll-testnet": "0xca01daa8e559cb6a810ce7906ec2aea39bdecce4", + "zklink": "0x1253e268bc04bb43cb96d2f7ee858b8a1433cf6d", + "zksync": "0x3a5a74f863ec48c1769c4ee85f6c3d70f5655e2a" + }, + "Blockhunters": { + "arbitrum": "0xd074b6bbcbec2f2b4c4265de3d95e521f82bf669", + "avalanche": "0xd074b6bbcbec2f2b4c4265de3d95e521f82bf669", + "bsc": "0x547bf6889b1095b7cc6e525a1f8e8fdb26134a38", + "ethereum": "0x6e70fcdc42d3d63748b7d8883399dcb16bbb5c8c", + "fantom": "0x547bf6889b1095b7cc6e525a1f8e8fdb26134a38", + "optimism": "0xb3ce0a5d132cd9bf965aba435e650c55edce0062", + "polygon": "0xbd40c9047980500c46b8aed4462e2f889299febe" + }, + "Chainlink_CCIP": { + "avalanche": "0xd46270746acbca85dab8de1ce1d71c46c2f2994c", + "bsc": "0x53561bcfe6b3f23bc72e5b9919c12322729942e8", + "ethereum": "0x771d10d0c86e26ea8d3b778ad4d31b30533b9cbf" + }, + "Delegate": { + "arbitrum": "0xdf30c9f6a70ce65a152c5bd09826525d7e97ba49", + "fuji": "0xe0f3389bf8a8aa1576b420d888cd462483fdc2a0", + "avalanche": "0x83d06212b6647b0d0865e730270751e3fdf5036e", + "bsc": "0x9eeee79f5dbc4d99354b5cb547c138af432f937b", + "bsc-testnet": "0xcd02c60d6a23966bd74d435df235a941b35f4f5f", + "ethereum": "0x87048402c32632b7c4d0a892d82bc1160e8b2393", + "sepolia": "0x942afc25b43d6ffe6d990af37737841f580638d7", + "fantom": "0x9eeee79f5dbc4d99354b5cb547c138af432f937b", + "fantom-testnet": "0x427859dcf157e29fda324c2cd90b17fa33d0e300", + "optimism": "0x7a205ed4e3d7f9d0777594501705d8cd405c3b05", + "polygon": "0x4d52f5bc932cf1a854381a85ad9ed79b8497c153" + }, + "Gitcoin": { + "arbitrum": "0x313328609a9c38459cae56625fff7f2ad6dcde3b", + "fuji": "0x071fbf35b35d48afc3edf84f0397980c25531560", + "avalanche": "0xcced05c3667877b545285b25f19f794436a1c481", + "bsc": "0x2afa3787cd95fee5d5753cd717ef228eb259f4ea", + "bsc-testnet": "0x6f978ee5bfd7b1a8085a3ea9e54eb76e668e195a", + "ethereum": "0x38179d3bfa6ef1d69a8a7b0b671ba3d8836b2ae8", + "sepolia": "0x28b92d35407caa791531cd7f7d215044f4c0cbdd", + "fantom": "0x2afa3787cd95fee5d5753cd717ef228eb259f4ea", + "fantom-testnet": "0x97f671e60196ff62279dd06c393948f5b0b90c05", + "optimism": "0xb4fa7f1c67e5ec99b556ec92cbddbcdd384106f2", + "polygon": "0x047d9dbe4fc6b5c916f37237f547f9f42809935a" + }, + "Google_Cloud": { + "arbitrum": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "nova": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "fuji": "0xa4652582077afc447ea7c9e984d656ee4963fe95", + "avalanche": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "base": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "bsc": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "bsc-testnet": "0x6f99ea3fc9206e2779249e15512d7248dab0b52e", + "celo": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "ethereum": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "sepolia": "0x96746917b256bdb8424496ff6bbcaf8216708a6a", + "fantom": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "fantom-testnet": "0xbdb61339dc1cd02982ab459fa46f858decf3cec6", + "gnosis": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "harmony": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "linea": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "moonbeam": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "optimism": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "polygon": "0xd56e4eab23cb81f43168f9f45211eb027b9ac7cc", + "solana": "F7gu9kLcpn4bSTZn183mhn2RXUuMy7zckdxJZdUjuALw" + }, + "Horizen": { + "arbitrum": "0x19670df5e16bea2ba9b9e68b48c054c5baea06b8", + "nova": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "astar": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "zkatana": "0x0131a4ce592e5f5eabb08e62b1ceeb9bafeba036", + "avalanche": "0x07c05eab7716acb6f83ebf6268f8eecda8892ba1", + "base": "0xa7b5189bca84cd304d8553977c7c614329750d99", + "bsc": "0x247624e2143504730aec22912ed41f092498bef2", + "blast": "0x70bf42c69173d6e33b834f59630dac592c70b369", + "bob": "0xf2067660520f79eb7a8326dc1266dce0167d64e7", + "canto": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "celo": "0x31f748a368a893bdb5abb67ec95f232507601a73", + "conflux": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "coredao": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "dfk": "0xa9ff468ad000a4d5729826459197a0db843f433e", + "degen": "0x01a998260da061efb9a85b26d42f8f8662bf3d5f", + "dexalot": "0xd42306df1a805d8053bc652ce0cd9f62bde80146", + "dos": "0x33e5fcc13d7439cc62d54c41aa966197145b3cd7", + "ebi": "0x3a2d3a2249691809c34fb9733fd0d826d1aee028", + "ethereum": "0x380275805876ff19055ea900cdb2b46a94ecf20d", + "fantom": "0x25e0e650a78e6304a3983fc4b7ffc6544b1beea6", + "flare": "0xeaa5a170d2588f84773f965281f8611d61312832", + "fraxtal": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "fuse": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "gnosis": "0x6abdb569dc985504cccb541ade8445e5266e7388", + "gravity": "0xe95b63c4da1d94fa5022e7c23c984f278b416ca7", + "harmony": "0x462a63dbe8ca43a57d379c88a382c02862b9a2ce", + "homeverse": "0x97841d4ab18e9a923322a002d5b8eb42b31ccdb5", + "eon": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "bb1": "0xc9c1b26505bf3f4d6562159a119f6ede1e245deb", + "iota": "0xdfc9455f8f86b45fa3b1116967f740905de6fe51", + "joc": "0xfb02364e3f5e97d8327dc6e4326e93828a28657d", + "kava": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "klaytn": "0xacde1f22eeab249d3ca6ba8805c8fee9f52a16e7", + "linea": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "loot": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "manta": "0x31f748a368a893bdb5abb67ec95f232507601a73", + "mantle": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "beam": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "meter": "0x3f10b9b75b05f103995ee8b8e2803aa6c7a9dcdf", + "metis": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "mode": "0xacde1f22eeab249d3ca6ba8805c8fee9f52a16e7", + "moonbeam": "0x34730f2570e6cff8b1c91faabf37d0dd917c4367", + "moonriver": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "aurora": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "okx": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "opbnb": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "optimism": "0x9e930731cb4a6bf7ecc11f695a295c60bdd212eb", + "orderly": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "polygon": "0x25e0e650a78e6304a3983fc4b7ffc6544b1beea6", + "zkevm": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "rarible": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "scroll": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "sei": "0x87048402c32632b7c4d0a892d82bc1160e8b2393", + "shimmer": "0xa59ba433ac34d2927232918ef5b2eaafcf130ba5", + "solana": "HR9NQKK1ynW9NzgdM37dU5CBtqRHTukmbMKS7qkwSkHX", + "taiko": "0xbd237ef21319e2200487bdf30c188c6c34b16d3b", + "telos": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "tenet": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "tiltyard": "0x0165c910ea47964a23dc4fb7c7483f6f3ad462ae", + "tron": "0xfee824cc7ced4f2ba7a0e72e5cfe20fd2197cd53", + "tomo": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "xchain": "0x0e5c792ec122cbe89ce0085d7efcdb151eae3376", + "xlayer": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "xpla": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "zircuit": "0xdcdd4628f858b45260c31d6ad076bd2c3d3c2f73", + "zklink": "0x27bb790440376db53c840326263801fafd9f0ee6", + "zksync": "0x1253e268bc04bb43cb96d2f7ee858b8a1433cf6d", + "zora": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b" + }, + "Lagrange": { + "arbitrum": "0x021e401c2a1a60618c5e6353a40524971eba1e8d", + "base": "0xc50a49186aa80427aa3b0d3c2cec19ba64222a29", + "ethereum": "0x95729ea44326f8add8a9b1d987279dbdc1dd3dff", + "optimism": "0xa4281c1c88f0278ff696edeb517052153190fc9e" + }, + "LayerZero_Labs": { + "abstract-testnet": "0x5dfcab27c1eec1eb07ff987846013f19355a04cb", + "arbitrum": "0x2f55c492897526677c5b68fb199ea31e2c126416", + "nova": "0xb7e97ad5661134185fe608b2a31fe8cef2147ba9", + "arbitrum-sepolia": "0x53f488e93b4f1b60e8e83aa374dbe1780a1ee8a8", + "astar": "0xe1975c47779edaaaba31f64934a33affd3ce15c2", + "astar-testnet": "0x190deb4f8555872b454920d6047a04006eee4ca9", + "zkatana": "0xce8358bc28dd8296ce8caf1cd2b44787abd65887", + "zkastar-testnet": "0x12523de19dc41c91f7d2093e0cfbb76b17012c8d", + "fuji": "0x9f0e79aeb198750f963b6f30b99d87c6ee5a0467", + "avalanche": "0x962f502a63f5fbeb44dc9ab932122648e8352959", + "bahamut-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "base": "0x9e059a54699a285714207b43b055483e78faac25", + "base-sepolia": "0xe1a12515f9ab2764b887bf60b923ca494ebbb2d6", + "bartio": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "besu1-testnet": "0xb0487596a0b62d1a71d0c33294bd6eb635fc6b09", + "bsc": "0xfd6865c841c2d64565562fcc7e05e619a30615f0", + "bsc-testnet": "0x0ee552262f7b562efced6dd4a7e2878ab897d405", + "blast": "0xc097ab8cd7b053326dfe9fb3e3a31a0cce3b526f", + "blast-testnet": "0x939afd54a8547078dbea02b683a7f1fdc929f853", + "bob": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "bob-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "botanix-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "bouncebit-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "camp-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "canto": "0x1bacc2205312534375c8d1801c27d28370656cff", + "canto-testnet": "0x032457e2c87376ad1d0ae8bbada45d178c9968b3", + "celo": "0x75b073994560a5c03cd970414d9170be0c6e5c36", + "codex-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "conflux": "0x8d183a062e99cad6f3723e6d836f9ea13886b173", + "conflux-testnet": "0x62a731f0840d23970d5ec36fb7a586e1d61db9b6", + "coredao": "0x3c5575898f59c097681d1fc239c2c6ad36b7b41c", + "coredao-testnet": "0xae9bbf877bf1bd41edd5dfc3473d263171cf3b9e", + "curtis-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "cyber": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "cyber-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "dfk": "0x1f7e674143031e74bc48a0c570c174a07aa9c5d0", + "dfk-testnet": "0x685e66cb79b4864ce0a01173f2c5efbf103715ad", + "degen": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "dexalot": "0xb98d764d25d53f803f05d451225612e4a9a3b712", + "dexalot-testnet": "0x433daf5e5fba834de2c3d06a82403c9e96df6b42", + "dos": "0x203dfa8cbcbe234821da01a6e95fcbf92da065ea", + "dos-testnet": "0x9e35059b08dca75f0f3c3940e4217b8dc73f4fda", + "ebi": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "ebi-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "holesky-testnet": "0x3e43f8ff0175580f7644da043071c289ddf98118", + "ethereum": "0x589dedbd617e0cbcb916a9223f4d1300c294236b", + "sepolia": "0x8eebf8b423b73bfca51a1db4b7354aa0bfca9193", + "etherlink": "0xc097ab8cd7b053326dfe9fb3e3a31a0cce3b526f", + "etherlink-testnet": "0x4d97186cd94047e285b7cb78fa63c93e69e7aad0", + "fantom": "0xe60a3959ca23a92bf5aaf992ef837ca7f828628a", + "fantom-testnet": "0xfffc92a6abe6480adc574901ebfde108a7077eb8", + "fi-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "flare": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "flare-testnet": "0x12523de19dc41c91f7d2093e0cfbb76b17012c8d", + "form-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "fraxtal": "0xcce466a522984415bc91338c232d98869193d46e", + "fraxtal-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "fuse": "0x795f8325af292ff6e58249361d1954893be15aff", + "fusespark": "0x955412c07d9bc1027eb4d481621ee063bfd9f4c6", + "glue-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "chiado": "0xabfa1f7c3586eaff6958dc85baebbab7d3908fd2", + "gnosis": "0x11bb2991882a86dc3e38858d922559a385d506ba", + "gravity": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "gunzilla-testnet": "0x8f337d230a5088e2a448515eab263735181a9039", + "harmony": "0x8363302080e711e0cab978c081b9e69308d49808", + "hedera-testnet": "0xec7ee1f9e9060e08df969dc08ee72674afd5e14d", + "homeverse": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "homeverse-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "eon": "0xe9ae261d3aff7d3fccf38fa2d612dd3897e07b2d", + "hubble": "0xe9ba4c1e76d874a43942718dafc96009ec9d9917", + "bb1": "0xb21f945e8917c6cd69fcfe66ac6703b90f7fe004", + "iota": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "iota-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "joc": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "joc-testnet": "0x9db9ca3305b48f196d18082e91cb64663b13d014", + "kava": "0x2d40a7b66f776345cf763c8ebb83199cd285e7a3", + "kava-testnet": "0x433daf5e5fba834de2c3d06a82403c9e96df6b42", + "klaytn": "0xc80233ad8251e668becbc3b0415707fc7075501e", + "klaytn-baobab": "0xe4fe9782b809b7d66f0dcd10157275d2c4e4898d", + "lif3-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "lightlink": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "lightlink-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "linea": "0x129ee430cb2ff2708ccaddbdb408a88fe4ffd480", + "lineasep-testnet": "0x701f3927871efcea1235db722f9e608ae120d243", + "loot": "0x4f8b7a7a346da5c467085377796e91220d904c15", + "loot-testnet": "0x09c3ff7df4f480f329cbee2df6f66c9a2e7f5a63", + "lyra-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "manta": "0xa09db5142654e3eb5cf547d66833fae7097b21c3", + "mantasep-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "mantle": "0x28b6140ead70cb2fb669705b3598ffb4beaa060b", + "mantle-sepolia": "0x9454f0eabc7c4ea9ebf89190b8bf9051a0468e03", + "masa": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "masa-testnet": "0xc1868e054425d378095a003ecba3823a5d0135c9", + "beam-testnet": "0x51b5ba90288c2253cfa03ca71bd1f04b53c423dd", + "beam": "0x5e38c31c28d0f485d6dc3ffabf8980bbcd882294", + "merlin": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "merlin-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "meter": "0xb792afc44214b5f910216bc904633dbd15b31680", + "meter-testnet": "0xe3a4539200e8906c957cd85b3e7a515c9883fd81", + "metis": "0x32d4f92437454829b3fe7bebfece5d0523deb475", + "metissep-testnet": "0x12523de19dc41c91f7d2093e0cfbb76b17012c8d", + "mode": "0xce8358bc28dd8296ce8caf1cd2b44787abd65887", + "mode-testnet": "0x12523de19dc41c91f7d2093e0cfbb76b17012c8d", + "moonbase": "0x90ccfdcd75a66dac697ab9c49f9ee0e32fd77e9f", + "moonbeam": "0x8b9b67b22ab2ed6ee324c2fd43734dbd2dddd045", + "moonriver": "0x2b3ebe6662ad402317ee7ef4e6b25c79a0f91015", + "morph-testnet": "0x55c175dd5b039331db251424538169d8495c18d1", + "aurora": "0xd4a903930f2c9085586cda0b11d9681eecb20d2f", + "okx-testnet": "0xdbdc042321a87dff222c6bf26be68ad7b3d7543f", + "okx": "0x52eea5c490fb89c7a0084b32feab854eeff07c82", + "olive-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "opbnb": "0x3ebb618b5c9d09de770979d552b27d6357aff73b", + "opbnb-testnet": "0x15e62434aadd26acc8a045e89404eceb4f6d2a52", + "opencampus-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "optimism": "0x6a02d83e8d433304bba74ef1c427913958187142", + "optimism-sepolia": "0xd680ec569f269aa7015f7979b4f1239b5aa4582c", + "orderly": "0xf53857dbc0d2c59d5666006ec200cba2936b8c35", + "orderly-testnet": "0x175d2b829604b82270d384393d25c666a822ab60", + "otherworld-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "peaq": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "peaq-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "plume-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "amoy-testnet": "0x55c175dd5b039331db251424538169d8495c18d1", + "polygon": "0x23de2fe932d9043291f870324b74f820e11dc81a", + "zkevm": "0x488863d609f3a673875a914fbee7508a1de45ec6", + "zkpolygon-sepolia": "0x55c175dd5b039331db251424538169d8495c18d1", + "rarible": "0x0b5e5452d0c9da1bb5fb0664f48313e9667d7820", + "real": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "root-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "sanko": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "sanko-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "scroll": "0xbe0d08a85eebfcc6eda0a843521f7cbb1180d2e2", + "scroll-testnet": "0xb186f85d0604fe58af2ea33fe40244f5eef7351b", + "sei": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "sei-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "shimmer": "0x9bdf3ae7e2e3d211811e5e782a808ca0a75bf1fc", + "skale": "0xce8358bc28dd8296ce8caf1cd2b44787abd65887", + "skale-testnet": "0x955412c07d9bc1027eb4d481621ee063bfd9f4c6", + "solana": "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb", + "solana-testnet": "4VDjp6XQaxoZf5RGwiPU9NR1EXSZn2TP4ATMmiSzLfhb", + "taiko": "0xc097ab8cd7b053326dfe9fb3e3a31a0cce3b526f", + "taiko-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "tangible-testnet": "0x25d5882bd4b6d4aa72a877eb62c7096364ae210a", + "telos-testnet": "0x5b11f3833393e9be06fa702c68453ad31976866e", + "telos": "0x3c5575898f59c097681d1fc239c2c6ad36b7b41c", + "tenet": "0x28a5536ca9f36c45a9d2ac8d2b62fc46fde024b6", + "tenet-testnet": "0x74582424b8b92be2ec17c192f6976b2effefab7c", + "tiltyard": "0xcfc3f9dd0205b76ff04e20243f106465dd829656", + "treasure-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "tron": "0x8bc1d368036ee5e726d230beb685294be191a24e", + "tron-testnet": "0xfb74015093331adb622ca9c0540bedf3de54e8ca", + "unreal-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "vanguard-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "tomo": "0x1ace9dd1bc743ad036ef2d92af42ca70a1159df5", + "xai": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "xai-testnet": "0xf49d162484290eaead7bb8c2c7e3a6f8f52e32d6", + "xchain": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "xchain-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "xlayer": "0x9c061c9a4782294eef65ef28cb88233a987f4bdd", + "xlayer-testnet": "0x55c175dd5b039331db251424538169d8495c18d1", + "xpla": "0x2d24207f9c1f77b2e08f2c3ad430da18e355cf66", + "xpla-testnet": "0x0747d0dabb284e5fbaeeea427bba7b2fba507120", + "zircuit": "0x6788f52439aca6bff597d3eec2dc9a44b8fee842", + "zircuit-testnet": "0x88b27057a9e00c5f05dda29241027aff63f9e6e0", + "zklink": "0x04830f6decf08dec9ed6c3fcad215245b78a59e1", + "zklink-testnet": "0x6869b4348fae6a911fdb5bae5e0d153b2aa261f6", + "zksync": "0x620a9df73d2f1015ea75aea1067227f9013f5c51", + "zksync-sepolia": "0xf52d98b18451eb5501d9929ec40a4caccd2e7e38", + "zora": "0xc1ec25a9e8a8de5aa346f635b33e5b74c4c081af", + "zora-sepolia": "0x701f3927871efcea1235db722f9e608ae120d243" + }, + "Luganodes": { + "arbitrum": "0x54dd79f5ce72b51fcbbcb170dd01e32034323565", + "avalanche": "0xe4193136b92ba91402313e95347c8e9fad8d27d0", + "bsc": "0x2c7185f5b0976397d9eb5c19d639d4005e6708f0", + "ethereum": "0x58249a2ec05c1978bf21df1f5ec1847e42455cf4", + "fantom": "0xa6f5ddbf0bd4d03334523465439d301080574742", + "optimism": "0xd841a741addcb6dea735d3b8c9faf96ba3f3d30d", + "polygon": "0xd1b5493e712081a6fbab73116405590046668f6b" + }, + "MIM": { + "arbitrum": "0x9e930731cb4a6bf7ecc11f695a295c60bdd212eb", + "avalanche": "0xf45742bbfabcee739ea2a2d0ba2dd140f1f2c6a3", + "bsc": "0x25e0e650a78e6304a3983fc4b7ffc6544b1beea6", + "ethereum": "0x0ae4e6a9a8b01ee22c6a49af22b674a4e033a23d", + "fantom": "0x1bab20e7fdc79257729cb596bef85db76c44915e", + "optimism": "0xd954bf7968ef68875c9100c9ec890f969504d120", + "polygon": "0x1bab20e7fdc79257729cb596bef85db76c44915e" + }, + "Nethermind": { + "arbitrum": "0xa7b5189bca84cd304d8553977c7c614329750d99", + "astar": "0xb19a9370d404308040a9760678c8ca28affbbb76", + "fuji": "0x7883f83ea40a56137a63baf93bfee5b9b8c1c447", + "avalanche": "0xa59ba433ac34d2927232918ef5b2eaafcf130ba5", + "base": "0xcd37ca043f8479064e10635020c65ffc005d36f6", + "bsc": "0x31f748a368a893bdb5abb67ec95f232507601a73", + "bsc-testnet": "0x6334290b7b4a365f3c0e79c85b1b42f078db78e4", + "blast": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "bob": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "canto": "0x809cde2afcf8627312e87a6a7bbffab3f8f347c7", + "alfajores": "0x449391d6812bce0b0b86d32d752035ff5be3f159", + "celo": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "conflux": "0x809cde2afcf8627312e87a6a7bbffab3f8f347c7", + "coredao": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "coredao-testnet": "0x4bb65bdb2c5d9bbaf25574a882c12fd98f5f994a", + "cyber": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "dfk": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "degen": "0x8d77d35604a9f37f488e41d1d916b2a0088f82dd", + "dexalot": "0x70bf42c69173d6e33b834f59630dac592c70b369", + "dos": "0xacde1f22eeab249d3ca6ba8805c8fee9f52a16e7", + "ebi": "0x261150ab73528dbd51573a52917eab243be9729a", + "ethereum": "0xa59ba433ac34d2927232918ef5b2eaafcf130ba5", + "sepolia": "0x715a4451be19106bb7cefd81e507813e23c30768", + "etherlink": "0x7a23612f07d81f16b26cf0b5a4c3eca0e8668df2", + "fantom": "0x31f748a368a893bdb5abb67ec95f232507601a73", + "fantom-testnet": "0x39ed64e4e063d22f69fb09d5a84ed6582aff120f", + "flare": "0x9bcd17a654bffaa6f8fea38d19661a7210e22196", + "fraxtal": "0xa7b5189bca84cd304d8553977c7c614329750d99", + "fuse": "0x809cde2afcf8627312e87a6a7bbffab3f8f347c7", + "chiado": "0xb186f85d0604fe58af2ea33fe40244f5eef7351b", + "gnosis": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "gravity": "0x4b92bc2a7d681bf5230472c80d92acfe9a6b9435", + "harmony": "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "iota": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "kava": "0x6a4c9096f162f0ab3c0517b0a40dc1ce44785e16", + "klaytn": "0x6a4c9096f162f0ab3c0517b0a40dc1ce44785e16", + "linea": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "manta": "0x247624e2143504730aec22912ed41f092498bef2", + "mantle": "0xb19a9370d404308040a9760678c8ca28affbbb76", + "meter": "0x08095eced6c0b46d50ee45a6a59c0fd3de0b0855", + "metis": "0x6abdb569dc985504cccb541ade8445e5266e7388", + "mode": "0xcd37ca043f8479064e10635020c65ffc005d36f6", + "moonbeam": "0x790d7b1e97a086eb0012393b65a5b32ce58a04dc", + "moonriver": "0xfe1cd27827e16b07e61a4ac96b521bdb35e00328", + "aurora": "0x34730f2570e6cff8b1c91faabf37d0dd917c4367", + "opbnb": "0x6a4c9096f162f0ab3c0517b0a40dc1ce44785e16", + "optimism": "0xa7b5189bca84cd304d8553977c7c614329750d99", + "orderly": "0x6a4c9096f162f0ab3c0517b0a40dc1ce44785e16", + "polygon": "0x31f748a368a893bdb5abb67ec95f232507601a73", + "zkevm": "0x7a7ddc46882220a075934f40380d3a7e1e87d409", + "rarible": "0xb53648ca1aa054a80159c1175c03679fdc76bf88", + "scroll": "0x446755349101cb20c582c224462c3912d3584dce", + "sei": "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "shimmer": "0x5fddd320a1e29bb466fa635661b125d51d976f92", + "solana": "GPjyWr8vCotGuFubDpTxDxy9Vj1ZeEN4F2dwRmFiaGab", + "taiko": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "telos": "0x809cde2afcf8627312e87a6a7bbffab3f8f347c7", + "tron": "0xfd952ea14b87fb18d4a1119be0be45064e448f45", + "tomo": "0x790d7b1e97a086eb0012393b65a5b32ce58a04dc", + "xai": "0xacde1f22eeab249d3ca6ba8805c8fee9f52a16e7", + "xchain": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "xlayer": "0x28af4dadbc5066e994986e8bb105240023dc44b6", + "xpla": "0x809cde2afcf8627312e87a6a7bbffab3f8f347c7", + "zksync": "0xb183c2b91cf76cad13602b32ada2fd273f19009c", + "zora": "0xa7b5189bca84cd304d8553977c7c614329750d99" + }, + "Nocturnal_Labs": { + "avalanche": "0x0ae4e6a9a8b01ee22c6a49af22b674a4e033a23d", + "ethereum": "0x04584d612802a3a26b160e3f90341e6443ddb76a", + "polygon": "0x05aaefdf9db6e0f7d27fa3b6ee099edb33da029e" + }, + "Nodes.Guru": { + "arbitrum": "0xd954bf7968ef68875c9100c9ec890f969504d120", + "avalanche": "0xd251d8a85cdfc84518b9454ee6a8d017e503f56c", + "bsc": "0x1bab20e7fdc79257729cb596bef85db76c44915e", + "ethereum": "0x9f45834f0c8042e36935781b944443e906886a87", + "fantom": "0x05aaefdf9db6e0f7d27fa3b6ee099edb33da029e", + "gravity": "0x4d52f5bc932cf1a854381a85ad9ed79b8497c153", + "optimism": "0xe6cd8c2e46ef396df88048449e5b1c75172b40c3", + "peaq": "0xdd7b5e1db4aafd5c8ec3b764efb8ed265aa5445b", + "polygon": "0xf7ddee427507cdb6885e53caaaa1973b1fe29357", + "zklink": "0x3a5a74f863ec48c1769c4ee85f6c3d70f5655e2a" + }, + "Omni_X": { + "arbitrum": "0xabea0b6b9237b589e676dc16f6d74bf7612591f4", + "avalanche": "0x21caf0bce846aaa78c9f23c5a4ec5988ecbf9988", + "base": "0xeede111103535e473451311e26c3e6660b0f77e1", + "bsc": "0x5a4c666e9c7aa86fd4fbfdfbfd04646dcc45c6c5", + "ethereum": "0xaf75bfd402f3d4ee84978179a6c87d16c4bd1724", + "fantom": "0xe0f0fbbdbf9d398eca0dd8c86d1f308d895b9eb7", + "optimism": "0x03d2414476a742aba715bcc337583c820525e22a", + "polygon": "0x06b85533967179ed5bc9c754b84ae7d02f7ed830" + }, + "Omnicat": { + "arbitrum": "0xd1c70192cc0eb9a89e3d9032b9facab259a0a1e9", + "base": "0xe6cd8c2e46ef396df88048449e5b1c75172b40c3", + "bsc": "0xdff3f73c260b3361d4f006b02972c6af6c5c5417", + "blast": "0x25e0e650a78e6304a3983fc4b7ffc6544b1beea6", + "canto": "0x25e0e650a78e6304a3983fc4b7ffc6544b1beea6", + "ethereum": "0xf10ea2c0d43bc4973cfbcc94ebafc39d1d4af118", + "polygon": "0xa2d10677441230c4aed58030e4ea6ba7bfd80393" + }, + "P-OPS": { + "arbitrum": "0x8fa9eef18c2a1459024f0b44714e5acc1ce7f5e8", + "avalanche": "0x2b8cbea81315130a4c422e875063362640ddfeb0", + "bsc": "0x33e5fcc13d7439cc62d54c41aa966197145b3cd7", + "ethereum": "0x94aafe0a92a8300f0a2100a7f3de47d6845747a9", + "fantom": "0x78203678d264063815dac114ea810e9837cd80f7", + "gnosis": "0x790d7b1e97a086eb0012393b65a5b32ce58a04dc", + "moonbeam": "0x7fe673201724925b5c477d4e1a4bd3e954688cf5", + "optimism": "0xe552485d02edd3067fe7fcbd4dd56bb1d3a998d2", + "polygon": "0xa75abcc0fab6ae09c8fd808bec7be7e88fe31d6b", + "scroll": "0x34730f2570e6cff8b1c91faabf37d0dd917c4367" + }, + "P2P": { + "arbitrum": "0xb3ce0a5d132cd9bf965aba435e650c55edce0062", + "fuji": "0xdbec329a5e6d7fb0113eb0a098750d2afd61e9ae", + "avalanche": "0xe94ae34dfcc87a61836938641444080b98402c75", + "bsc": "0x439264fb87581a70bb6d7befd16b636521b0ad2d", + "bsc-testnet": "0xd0a6fd2e542945d81d4ed82d8f4d25cc09c65f7f", + "ethereum": "0x06559ee34d85a88317bf0bfe307444116c631b67", + "sepolia": "0xe7b65ec1ae41186ef626a3a3cbf79d0c0426a911", + "fantom": "0x439264fb87581a70bb6d7befd16b636521b0ad2d", + "fantom-testnet": "0xf10955530720932660589259dabc44c964d88869", + "optimism": "0x539008c98b17803a273edf98aba2d4414ee3f4d7", + "polygon": "0x9eeee79f5dbc4d99354b5cb547c138af432f937b" + }, + "Pearlnet": { + "arbitrum": "0xabc9b1819cc4d9846550f928b985993cf6240439", + "avalanche": "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "ethereum": "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "optimism": "0xabc9b1819cc4d9846550f928b985993cf6240439" + }, + "Planetarium_Labs": { + "arbitrum": "0xe6cd8c2e46ef396df88048449e5b1c75172b40c3", + "avalanche": "0x2ac038606fff3fb00317b8f0ccfb4081694acdd0", + "bsc": "0x05aaefdf9db6e0f7d27fa3b6ee099edb33da029e", + "ethereum": "0x972ed7bd3d42d9c0bea3632992ebf7e97186ea4a", + "fantom": "0xf7ddee427507cdb6885e53caaaa1973b1fe29357", + "optimism": "0x021e401c2a1a60618c5e6353a40524971eba1e8d", + "polygon": "0x2ac038606fff3fb00317b8f0ccfb4081694acdd0" + }, + "Polyhedra": { + "arbitrum": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "nova": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "avalanche": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "base": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "bsc": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "bsc-testnet": "0x2ddf08e397541721acd82e5b8a1d0775454a180b", + "blast": "0x0ff4cc28826356503bb79c00637bec0ee006f237", + "celo": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "coredao": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "ethereum": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "fantom": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "gnosis": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "klaytn": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "linea": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "manta": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "mantle": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "metis": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "mode": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "moonbeam": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "opbnb": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "optimism": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "polygon": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "scroll": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24", + "xlayer": "0x8ddf05f9a5c488b4973897e278b58895bf87cb24" + }, + "Portal": { + "arbitrum": "0x539008c98b17803a273edf98aba2d4414ee3f4d7", + "avalanche": "0x0e95cf21ad9376a26997c97f326c5a0a267bb8ff", + "bsc": "0xbd40c9047980500c46b8aed4462e2f889299febe", + "ethereum": "0x92ef4381a03372985985e70fb15e9f081e2e8d14", + "fantom": "0xbd40c9047980500c46b8aed4462e2f889299febe", + "optimism": "0xdf30c9f6a70ce65a152c5bd09826525d7e97ba49", + "polygon": "0x8fc629aa400d4d9c0b118f2685a49316552abf27" + }, + "Republic": { + "fuji": "0xefdd92121acb3acd6e2f09dd810752d8da3dfdaf", + "avalanche": "0x1feb08b1a53a9710afce82d380b8c2833c69a37e", + "bsc": "0xf7ddee427507cdb6885e53caaaa1973b1fe29357", + "bsc-testnet": "0x33ba0e70d74c72d3633870904244b57edfb35df7", + "ethereum": "0xa1bc1b9af01a0ec78883aa5dc7decdce897e1e76", + "amoy-testnet": "0x35cea726508192472919c51951042dd140794b01", + "polygon": "0x547bf6889b1095b7cc6e525a1f8e8fdb26134a38" + }, + "Restake": { + "arbitrum": "0x969a0bdd86a230345ad87a6a381de5ed9e6cda85", + "avalanche": "0x377b51593a03b82543c1508fe7e75aba6acde008", + "bsc": "0x4d52f5bc932cf1a854381a85ad9ed79b8497c153", + "ethereum": "0xe4193136b92ba91402313e95347c8e9fad8d27d0", + "fantom": "0x4d52f5bc932cf1a854381a85ad9ed79b8497c153", + "optimism": "0xcced05c3667877b545285b25f19f794436a1c481", + "polygon": "0x2afa3787cd95fee5d5753cd717ef228eb259f4ea" + }, + "Shrapnel": { + "arbitrum": "0x7b8a0fd9d6ae5011d5cbd3e85ed6d5510f98c9bf", + "avalanche": "0x6a110d94e1baa6984a3d904bab37ae49b90e6b4f", + "bsc": "0xb4fa7f1c67e5ec99b556ec92cbddbcdd384106f2", + "ethereum": "0xce97511db880571a7c31821eb026ef12fcac892e", + "fantom": "0xb4fa7f1c67e5ec99b556ec92cbddbcdd384106f2", + "optimism": "0xd36246c322ee102a2203bca9cafb84c179d306f6", + "polygon": "0x54dd79f5ce72b51fcbbcb170dd01e32034323565" + }, + "StableLab": { + "arbitrum": "0xcd37ca043f8479064e10635020c65ffc005d36f6", + "fuji": "0xfde647565009b33b1df02689d5873bffff15d907", + "avalanche": "0x5fddd320a1e29bb466fa635661b125d51d976f92", + "bsc": "0xabc9b1819cc4d9846550f928b985993cf6240439", + "bsc-testnet": "0xd05c27f2e47fbba82adaac2a5adb71ba57a5b933", + "ethereum": "0x5fddd320a1e29bb466fa635661b125d51d976f92", + "sepolia": "0xf21f0282b55b4143251d8e39d3d93e78a78389ab", + "fantom": "0xabc9b1819cc4d9846550f928b985993cf6240439", + "fantom-testnet": "0x134dc38ae8c853d1aa2103d5047591acdaa16682", + "optimism": "0xcd37ca043f8479064e10635020c65ffc005d36f6", + "polygon": "0xabc9b1819cc4d9846550f928b985993cf6240439" + }, + "StakingCabin": { + "arbitrum": "0x6268950b2d11aa0516007b6361f6ee3facb3cb14", + "avalanche": "0x54dd79f5ce72b51fcbbcb170dd01e32034323565", + "bsc": "0xd841a741addcb6dea735d3b8c9faf96ba3f3d30d", + "ethereum": "0xdeb742e71d57603d8f769ce36f4353468007fc02", + "fantom": "0x2b8cbea81315130a4c422e875063362640ddfeb0", + "optimism": "0xea0c32623d19d888e926e68667a5e42853fa91b4", + "polygon": "0x53bdce6dccf7505a55813022f53c43fabfef7b3a" + }, + "Stargate": { + "arbitrum": "0x5756a74e8e18d8392605ba667171962b2b2826b5", + "avalanche": "0x252b234545e154543ad2784c7111eb90406be836", + "base": "0xcdf31d62140204c08853b547e64707110fbc6680", + "bsc": "0xac8de74ce0a44a5e73bbc709fe800406f58431e0", + "coredao": "0xe6cd8c2e46ef396df88048449e5b1c75172b40c3", + "ebi": "0x97841d4ab18e9a923322a002d5b8eb42b31ccdb5", + "ethereum": "0x8fafae7dd957044088b3d0f67359c327c6200d18", + "etherlink": "0x31f748a368a893bdb5abb67ec95f232507601a73", + "flare": "0x8d77d35604a9f37f488e41d1d916b2a0088f82dd", + "gravity": "0x70bf42c69173d6e33b834f59630dac592c70b369", + "iota": "0xf18a7d86917653725afb7c215e47a24f9d784718", + "kava": "0x9cbaf815ed62ef45c59e9f2cb05106babb4d31d3", + "klaytn": "0x17720e3f361dcc2f70871a2ce3ac51b0eaa5c2e4", + "linea": "0xef269bbadb81de86e4b3278fa1dae1723545268b", + "mantle": "0xfe809470016196573d64a8d17a745bebea4ecc41", + "metis": "0x61a1b61a1087be03abedc04900cfcc1c14187237", + "aurora": "0xe11c808bc6099abc9be566c9017aa2ab0f131d35", + "optimism": "0xfe6507f094155cabb4784403cd784c2df04122dd", + "polygon": "0xc79f0b1bcb7cdae9f9ba547dcfc57cbfcd2993a5", + "rarible": "0x2fa870cee4da57de84d1db36759d4716ad7e5038", + "scroll": "0xb87591d8b0b93fae8b631a073577c40e8dd46a62", + "sei": "0xbd00c87850416db0995ef8030b104f875e1bdd15", + "taiko": "0x37473676ff697f2eba29c8a3105309abf00ba013", + "xchain": "0x56053a8f4db677e5774f8ee5bdd9d2dc270075f3", + "zksync": "0x62aa89bad332788021f6f4f4fb196d5fe59c27a6" + }, + "Switchboard": { + "arbitrum": "0xcced05c3667877b545285b25f19f794436a1c481", + "fuji": "0xca5ab7adcd3ea879f1a1c4eee81eaccd250173e4", + "avalanche": "0x92ef4381a03372985985e70fb15e9f081e2e8d14", + "bsc": "0xf0809f6e760a5452ee567975eda7a28da4a83d38", + "bsc-testnet": "0x4ecbb26142a1f2233aeee417fd2f4fb0ec6e0d78", + "ethereum": "0x276e6b1138d2d49c0cda86658765d12ef84550c1", + "sepolia": "0x51e8907d6f3606587ba9f0aba4ece4c28ac31ec6", + "fantom": "0xf0809f6e760a5452ee567975eda7a28da4a83d38", + "fantom-testnet": "0xfd53de8f107538c28148f0bcdf1fb1f1dfd5461b", + "optimism": "0x313328609a9c38459cae56625fff7f2ad6dcde3b", + "polygon": "0xc6d46f63578635e4a7140cdf4d0eea0fd7bb50ec" + }, + "Zenrock": { + "arbitrum": "0x3b65e87e2a4690f14cae0483014259ded8215adc", + "avalanche": "0xe552485d02edd3067fe7fcbd4dd56bb1d3a998d2", + "base": "0x9e930731cb4a6bf7ecc11f695a295c60bdd212eb", + "bsc": "0xe5491fac6965aa664efd6d1ae5e7d1d56da4fdda", + "blast": "0x1383981c78393b36f59c4f8f4f12f1b4eb249ebf", + "celo": "0x1383981c78393b36f59c4f8f4f12f1b4eb249ebf", + "ethereum": "0xd42306df1a805d8053bc652ce0cd9f62bde80146", + "fantom": "0xae675d8a97a06dea4e74253d429bd324606ded24", + "gnosis": "0x07c05eab7716acb6f83ebf6268f8eecda8892ba1", + "optimism": "0xaf75bfd402f3d4ee84978179a6c87d16c4bd1724", + "polygon": "0xcd8ea69bbca0a2bb221aed59fa2704f01fc76a9f", + "scroll": "0x05aaefdf9db6e0f7d27fa3b6ee099edb33da029e", + "tron": "0x1de9dec8465638b07c198f53f1d4cb2a92be729c", + "zksync": "0xc4a1f52fda034a9a5e1b3b27d14451d15776fef6" + } +} \ No newline at end of file diff --git a/deployment-config/sei-eth-l1-08-08-24.json b/deployment-config/sei-eth-l1-08-08-24.json index 588851f..97b662e 100644 --- a/deployment-config/sei-eth-l1-08-08-24.json +++ b/deployment-config/sei-eth-l1-08-08-24.json @@ -1,7 +1,7 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "baseDecimals": "18", + "boringVaultAndBaseDecimals": "18", "boringVault":{ "boringVaultSalt": "0x100000000000000000000000000000000000000000000000000000000000000a", "boringVaultName": "Sei Native Yield Nucleus Token", diff --git a/deployment-config/sei-eth-l2-08-08-24.json b/deployment-config/sei-eth-l2-08-08-24.json index 852d858..93766a6 100644 --- a/deployment-config/sei-eth-l2-08-08-24.json +++ b/deployment-config/sei-eth-l2-08-08-24.json @@ -1,7 +1,7 @@ { "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", "base": "0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8", - "baseDecimals": "18", + "boringVaultAndBaseDecimals": "18", "boringVault":{ "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000000", "boringVaultName": "Sei Native Yield Nucleus Token", diff --git a/deployment-config/rswBTC-l1.json b/deployment-config/swell-btc-l1-08-22-24.json similarity index 87% rename from deployment-config/rswBTC-l1.json rename to deployment-config/swell-btc-l1-08-22-24.json index ce53341..c84c007 100644 --- a/deployment-config/rswBTC-l1.json +++ b/deployment-config/swell-btc-l1-08-22-24.json @@ -1,24 +1,24 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", "base": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", - "baseDecimals": "8", + "boringVaultAndBaseDecimals": "8", "boringVault":{ - "boringVaultSalt": "0x100000000000000000000000000000000000000000000000000000000000000b", - "boringVaultName": "Swell Native Yield Nucleus Token", + "boringVaultSalt": "0x100000000000000000000000000000000000000000000000000000000000000c", + "boringVaultName": "Swell BTC Native Yield Nucleus Token", "boringVaultSymbol": "rswBTC", "address": "0x0000000000000000000000000000000000000000" }, "manager":{ - "managerSalt": "0x200000000000000000000000000000000000000000000000000000000000000b", + "managerSalt": "0x200000000000000000000000000000000000000000000000000000000000000c", "address": "0x0000000000000000000000000000000000000000" }, "accountant":{ - "accountantSalt": "0x300000000000000000000000000000000000000000000000000000000000000b", + "accountantSalt": "0x300000000000000000000000000000000000000000000000000000000000000c", "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", "allowedExchangeRateChangeUpper": "10030", "allowedExchangeRateChangeLower": "9980", @@ -29,7 +29,7 @@ }, "teller": { - "tellerSalt": "0x400000000000000000000000000000000000000000000000000000000000000a", + "tellerSalt": "0x400000000000000000000000000000000000000000000000000000000000000c", "maxGasForPeer": 200000, "minGasForPeer": 60000, "peerEid": 0, @@ -41,7 +41,7 @@ "address": "0x0000000000000000000000000000000000000000" }, "rolesAuthority": { - "rolesAuthoritySalt": "0x500000000000000000000000000000000000000000000000000000000000000b", + "rolesAuthoritySalt": "0x500000000000000000000000000000000000000000000000000000000000000c", "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", diff --git a/incrementSalt.cjs b/incrementSalt.cjs new file mode 100644 index 0000000..ae277bf --- /dev/null +++ b/incrementSalt.cjs @@ -0,0 +1,46 @@ +const fs = require('fs'); + + +const args = process.argv.slice(2); +if (args.length < 1) { + console.error("Usage: node incrementSalt.cjs "); + process.exit(1); +} + +const [fileName] = args; +const filePath = 'deployment-config/'+fileName; + +fs.readFile(filePath, 'utf8', (err, data) => { + if (err) { + console.error('Error reading file:', err); + return; + } + + let jsonData = JSON.parse(data); + + const incrementHex = (hex) => { + let num = BigInt(hex); + num += 1n; + return '0x' + num.toString(16); + }; + + const incrementSalts = (obj) => { + for (let key in obj) { + if (typeof obj[key] === 'string' && obj[key].startsWith('0x') && key.toLowerCase().includes('salt')) { + obj[key] = incrementHex(obj[key]); + } else if (typeof obj[key] === 'object') { + incrementSalts(obj[key]); + } + } + }; + + incrementSalts(jsonData); + + fs.writeFile(filePath, JSON.stringify(jsonData, null, 2), 'utf8', (err) => { + if (err) { + console.error('Error writing file:', err); + return; + } + console.log('File successfully updated'); + }); +}); \ No newline at end of file diff --git a/lzConfigCheck.cjs b/lzConfigCheck.cjs new file mode 100644 index 0000000..ded3c98 --- /dev/null +++ b/lzConfigCheck.cjs @@ -0,0 +1,126 @@ +const fs = require('fs'); +const readline = require('readline'); + +// Function to load the DVN JSON data +function loadDvns() { + const data = fs.readFileSync('./deployment-config/layerzero/dvn-deployments.json', 'utf8'); + return JSON.parse(data); +} + +// Function to find an address in the JSON data +function findAddressInJson(addresses, jsonData, searchKey = "") { + const results = []; + const lowerCaseAddresses = addresses.map(a => a.toLowerCase()); + + for (const [parentKey, parentValue] of Object.entries(jsonData)) { + for (const [key, value] of Object.entries(parentValue)) { + if (lowerCaseAddresses.includes(value.toLowerCase())) { + results.push([parentKey, key, value]); + } + } + } + + if (searchKey === "") { + if (results.length === 1) { + const [parentKey, key, value] = results[0]; + return [true, key, parentKey]; + } else { + return [false, null, null]; + } + } else { + for (const [parentKey, key, value] of results) { + if (key === searchKey) { + return [true, key, parentKey]; + } + } + return [false, null, null]; + } +} + +// Function to get findings from a config file +function getFindingsInConfig(configName) { + const dvnJsonData = loadDvns(); + const data = fs.readFileSync(`./deployment-config/${configName}`, 'utf8'); + const configJsonData = JSON.parse(data); + + const required = configJsonData.teller.dvnIfNoDefault.required; + const optional = configJsonData.teller.dvnIfNoDefault.optional; + const addresses = [...required, ...optional]; + + let chain = ""; + for (const address of addresses) { + const [found, key, parentKey] = findAddressInJson([address], dvnJsonData); + if (found) { + chain = key; + break; + } + } + + if (chain === "") { + throw new Error("❌ All provided configs have duplicates or are not found in the DVN registry"); + } + + const findings = []; + for (const address of addresses) { + const [found, key, parentKey] = findAddressInJson([address], dvnJsonData, chain); + if (found) { + findings.push({ address, chain: key, provider: parentKey }); + } else { + console.log("Not Found ", address); + } + } + + return { + findings, + requiredCount: required.length, + optionalCount: optional.length, + confirmations: configJsonData.teller.dvnIfNoDefault.blockConfirmationsRequiredIfNoDefault, + threshold: configJsonData.teller.dvnIfNoDefault.optionalThreshold + }; +} + +function assert(statement, message){ + if(!statement){ + throw new Error("❌ "+message) + } +} + +// Main function +async function main() { + const args = process.argv.slice(2); + + if (args.length != 2) { + console.error("Usage: node script.js "); + process.exit(1); + } + + const [file1Name, file2Name] = args; + + try { + const findings1 = getFindingsInConfig(file1Name); + const findings2 = getFindingsInConfig(file2Name); + + assert(findings1.confirmations == findings2.confirmations, "Confirmations do not match"); + assert(findings1.threshold == findings2.threshold, "thresholds do not match"); + assert(findings1.requiredCount == findings2.requiredCount, "required DVNs count does not match"); + assert(findings1.optionalCount == findings2.optionalCount, "optional DVNs count does not match"); + + const chain1 = findings1.findings[0].chain; + const providers1 = findings1.findings.map(finding => finding.provider); + for (const finding of findings1.findings) { + assert(finding.chain == chain1, "Networks do not match for "+finding) + } + + const chain2 = findings2.findings[0].chain; + for (const finding of findings2.findings) { + assert(providers1.includes(finding.provider), "Provider: "+finding.provider+" does not have a matching provider in the first config"); + assert(finding.chain == chain2, "Networks do not match for: "+finding); + } + + console.log("✅ Config check passed"); + } catch (error) { + console.error(error.message); + } +} + +main(); diff --git a/package.json b/package.json index 9668c7b..7342fd3 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,7 @@ "coverage": "./coverage.sh", "solhint": "solhint -w 0 'src/**/*.sol'", "slither": "slither src", - "prepare": "husky", - "deploy-createx-l1": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L1_RPC_URL --private-key $PRIVATE_KEY --slow --no-metadata", - "deploy-createx-l2": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --slow --no-metadata", - "deploy-l1": "forge script script/deploy/deployAll.s.sol -f $L1_RPC_URL --private-key=$PRIVATE_KEY --slow", - "deploy-l2": "forge script script/deploy/deployAll.s.sol -f $L2_RPC_URL --private-key=$PRIVATE_KEY --slow" + "prepare": "husky" }, "devDependencies": { "@layerzerolabs/lz-definitions": "^2.3.25", diff --git a/script/Base.s.sol b/script/Base.s.sol index 2c915cd..19426e9 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -17,7 +17,7 @@ abstract contract BaseScript is Script { string constant CONFIG_CHAIN_ROOT = "./deployment-config/chains/"; /// Custom base params - ICreateX CREATEX = ICreateX(0x1077f8ea07EA34D9F23BC39256BF234665FB391f); + ICreateX immutable CREATEX; /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -43,6 +43,7 @@ abstract contract BaseScript is Script { /// /// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line. constructor() { + CREATEX = ICreateX(vm.envAddress("CREATEX")); deployCreate2 = vm.envOr({ name: "CREATE2", defaultValue: true }); address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); if (from != address(0)) { @@ -86,4 +87,8 @@ abstract contract BaseScript is Script { path = string.concat(CONFIG_PATH_ROOT, vm.prompt("Please Enter The Deployments Configuration File Name: ")); return vm.readFile(path); } + + function compareStrings(string memory a, string memory b) internal returns (bool) { + return (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))); + } } diff --git a/script/ConfigReader.s.sol b/script/ConfigReader.s.sol index 2cdb0e7..9e8a74c 100644 --- a/script/ConfigReader.s.sol +++ b/script/ConfigReader.s.sol @@ -15,7 +15,7 @@ library ConfigReader { struct Config { address protocolAdmin; address base; - uint8 baseDecimals; + uint8 boringVaultAndBaseDecimals; bytes32 accountantSalt; address boringVault; address payoutAddress; @@ -30,8 +30,10 @@ library ConfigReader { address balancerVault; bytes32 tellerSalt; uint32 peerEid; - address dvnIfNoDefault; - uint64 dvnBlockConfirmationsRequiredIfNoDefault; + address[] requiredDvns; + address[] optionalDvns; + uint64 dvnBlockConfirmationsRequired; + uint8 optionalDvnThreshold; address accountant; address opMessenger; uint64 maxGasForPeer; @@ -46,7 +48,6 @@ library ConfigReader { address rolesAuthority; bytes32 decoderSalt; address decoder; - address rateProvider; bytes32 rateProviderSalt; uint256 maxTimeFromLastUpdate; address[] assets; @@ -58,7 +59,7 @@ library ConfigReader { // Reading the 'protocolAdmin' config.protocolAdmin = _config.readAddress(".protocolAdmin"); config.base = _config.readAddress(".base"); - config.baseDecimals = uint8(_config.readUint(".baseDecimals")); + config.boringVaultAndBaseDecimals = uint8(_config.readUint(".boringVaultAndBaseDecimals")); // Reading from the 'accountant' section config.accountant = _config.readAddress(".accountant.address"); @@ -87,7 +88,12 @@ library ConfigReader { config.tellerContractName = _config.readString(".teller.tellerContractName"); config.assets = _config.readAddressArray(".teller.assets"); config.peerEid = uint32(_config.readUint(".teller.peerEid")); - config.opMessenger = _config.readAddress(".teller.opMessenger"); + + config.requiredDvns = _config.readAddressArray(".teller.dvnIfNoDefault.required"); + config.optionalDvns = _config.readAddressArray(".teller.dvnIfNoDefault.optional"); + config.dvnBlockConfirmationsRequired = + uint64(_config.readUint(".teller.dvnIfNoDefault.blockConfirmationsRequiredIfNoDefault")); + config.optionalDvnThreshold = uint8(_config.readUint(".teller.dvnIfNoDefault.optionalThreshold")); // Reading from the 'rolesAuthority' section config.rolesAuthority = _config.readAddress(".rolesAuthority.address"); diff --git a/script/DeployCustomCreatex.s.sol b/script/DeployCustomCreatex.s.sol index e2be751..cec0599 100644 --- a/script/DeployCustomCreatex.s.sol +++ b/script/DeployCustomCreatex.s.sol @@ -10,10 +10,11 @@ contract DeployCustomCreateX is Script { string internal mnemonic; string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; - address constant EXPECTED = 0x1077f8ea07EA34D9F23BC39256BF234665FB391f; + address immutable EXPECTED; bytes32 constant SALT = 0x8888888833388888888000000000000000000000000000000000000000000000; constructor() { + EXPECTED = vm.envAddress("CREATEX"); address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); if (from != address(0)) { broadcaster = from; diff --git a/script/deploy/01_DeployRateProviders.s.sol b/script/deploy/01_DeployRateProviders.s.sol index 987c1f3..363a7cb 100644 --- a/script/deploy/01_DeployRateProviders.s.sol +++ b/script/deploy/01_DeployRateProviders.s.sol @@ -16,8 +16,18 @@ contract DeployRateProviders is BaseScript { using StdJson for string; using Strings for address; + function run(string memory fileName, string memory configFileName) public { + string memory path = string.concat(CONFIG_PATH_ROOT, configFileName); + string memory config = vm.readFile(path); + _run(fileName, config); + } + function run() public { string memory config = requestConfigFileFromUser(); + _run(Strings.toString(block.chainid), config); + } + + function _run(string memory fileName, string memory config) internal { string memory chainConfig = getChainConfigFile(); address[] memory assets = config.readAddressArray(".teller.assets"); @@ -52,8 +62,7 @@ contract DeployRateProviders is BaseScript { ); rateProvider = deployRateProvider(description, priceFeed, maxTimeFromLastUpdate, decimals, priceFeedType); - string memory chainConfigFilePath = - string.concat(CONFIG_CHAIN_ROOT, Strings.toString(block.chainid), ".json"); + string memory chainConfigFilePath = string.concat(CONFIG_CHAIN_ROOT, fileName, ".json"); rateProvider.toHexString().write(chainConfigFilePath, rateProviderKey); } } diff --git a/script/deploy/deployAll.s.sol b/script/deploy/deployAll.s.sol index a9a72fd..1db7134 100644 --- a/script/deploy/deployAll.s.sol +++ b/script/deploy/deployAll.s.sol @@ -50,10 +50,8 @@ contract DeployAll is BaseScript { ConfigReader.Config mainConfig; - function run() public { - mainConfig = getConfig(); - - deploy(mainConfig); + function run(string memory deployFile) public { + deploy(ConfigReader.toConfig(vm.readFile(string.concat(CONFIG_PATH_ROOT, deployFile)), getChainConfigFile())); } function deploy(ConfigReader.Config memory config) public override returns (address) { @@ -83,6 +81,8 @@ contract DeployAll is BaseScript { new SetAuthorityAndTransferOwnerships().deploy(config); console.log("Set Authority And Transfer Ownerships Complete"); + + mainConfig = config; } function _deployTeller(ConfigReader.Config memory config) public returns (address teller) { @@ -96,8 +96,4 @@ contract DeployAll is BaseScript { revert INVALID_TELLER_CONTRACT_NAME(); } } - - function compareStrings(string memory a, string memory b) private returns (bool) { - return (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))); - } } diff --git a/script/deploy/single/02_DeployBoringVault.s.sol b/script/deploy/single/02_DeployBoringVault.s.sol index ea4ddea..263eefe 100644 --- a/script/deploy/single/02_DeployBoringVault.s.sol +++ b/script/deploy/single/02_DeployBoringVault.s.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.21; import { BoringVault } from "./../../../src/base/BoringVault.sol"; import { BaseScript } from "./../../Base.s.sol"; import { ConfigReader } from "../../ConfigReader.s.sol"; +import { ERC20 } from "@solmate/tokens/ERC20.sol"; import { stdJson as StdJson } from "@forge-std/StdJson.sol"; contract DeployIonBoringVaultScript is BaseScript { @@ -31,7 +32,7 @@ contract DeployIonBoringVaultScript is BaseScript { broadcaster, config.boringVaultName, config.boringVaultSymbol, - 18 // decimals + config.boringVaultAndBaseDecimals // decimals ) ) ) @@ -41,7 +42,9 @@ contract DeployIonBoringVaultScript is BaseScript { // Post Deploy Checks require(boringVault.owner() == broadcaster, "owner should be the deployer"); require(address(boringVault.hook()) == address(0), "before transfer hook should be zero"); - + require( + boringVault.decimals() == ERC20(config.base).decimals(), "boringVault decimals should be the same as base" + ); return address(boringVault); } } diff --git a/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol b/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol index 4782180..90ae876 100644 --- a/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol +++ b/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol @@ -31,8 +31,8 @@ contract DeployAccountantWithRateProviders is BaseScript { require(config.minimumUpdateDelayInSeconds >= 3600, "minimumUpdateDelayInSeconds"); require(config.managementFee < 1e4, "managementFee"); require( - startingExchangeRate == 10 ** config.baseDecimals, - "starting exchange rate must be equal to base decimals" + startingExchangeRate == 10 ** config.boringVaultAndBaseDecimals, + "starting exchange rate must be equal to the boringVault and base decimals" ); } // Create Contract diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index bbbc83c..2f94c31 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -9,11 +9,12 @@ import { stdJson as StdJson } from "@forge-std/StdJson.sol"; import { ConfigReader } from "../../ConfigReader.s.sol"; import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol"; +import { console2 } from "@forge-std/console2.sol"; contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { using StdJson for string; - address dead = 0x000000000000000000000000000000000000dEaD; + address constant DEAD = 0x000000000000000000000000000000000000dEaD; struct UlnConfig { uint64 confirmations; @@ -51,8 +52,19 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { ); // configure the crosschain functionality, assume same address - teller.setPeer(config.peerEid, bytes32(bytes20(address(teller)))); + bytes32 leftPaddedBytes32Peer = addressToBytes32LeftPad(address(teller)); + + // this number = 1 << (8*20) + // an address cannot take up more than 20 bytes and thus 1 shifted 20 bytes right should be larger than any + // number address can be if padded correctly + require( + leftPaddedBytes32Peer < 0x0000000000000000000000010000000000000000000000000000000000000000, + "Address not left padded correctly" + ); + + teller.setPeer(config.peerEid, leftPaddedBytes32Peer); teller.addChain(config.peerEid, true, true, address(teller), config.maxGasForPeer, config.minGasForPeer); + ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(config.lzEndpoint); // Post Deploy Checks require(teller.shareLockPeriod() == 0, "share lock period must be zero"); @@ -61,49 +73,120 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { AccountantWithRateProviders(teller.accountant()).vault() == teller.vault(), "the accountant vault must be the teller vault" ); - require(address(teller.endpoint()) == config.lzEndpoint, "OP Teller must have messenger set"); + require(address(endpoint) == config.lzEndpoint, "LZ Teller must have endpoint set"); + + // get the default libraries for the peer + address sendLib = endpoint.defaultSendLibrary(config.peerEid); + address receiveLib = endpoint.defaultReceiveLibrary(config.peerEid); + require(sendLib != address(0), "sendLib = 0, check peerEid"); + require(receiveLib != address(0), "receiveLib = 0, check peerEid"); + + // check if a default config exists for these libraries and if not set the config + _checkUlnConfig(address(teller), config, sendLib); + _checkUlnConfig(address(teller), config, receiveLib); + + // confirm the library is set + sendLib = endpoint.getSendLibrary(config.teller, config.peerEid); + (receiveLib,) = endpoint.getReceiveLibrary(config.teller, config.peerEid); + require(sendLib != address(0), "No sendLib"); + require(receiveLib != address(0), "no receiveLib"); + + // transfer delegate to the multisig + teller.setDelegate(config.protocolAdmin); - // check if the DVN is configured and print a message to the screen to inform the deployer if not. return address(teller); } - function _checkUlnConfig(ConfigReader.Config memory config) internal { + function _checkUlnConfig(address newTeller, ConfigReader.Config memory config, address lib) internal { ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(config.lzEndpoint); - address lib = endpoint.defaultSendLibrary(config.peerEid); - bytes memory configBytes = endpoint.getConfig(config.teller, lib, config.peerEid, 2); + + bytes memory configBytes = endpoint.getConfig(newTeller, lib, config.peerEid, 2); UlnConfig memory ulnConfig = abi.decode(configBytes, (UlnConfig)); - if (ulnConfig.confirmations == 0) { - _setConfig(endpoint, lib, config); - return; - } uint8 numRequiredDVN = ulnConfig.requiredDVNCount; uint8 numOptionalDVN = ulnConfig.optionalDVNCount; + bool isDead; + for (uint256 i; i < numRequiredDVN; ++i) { - if (ulnConfig.requiredDVNs[i] == dead) { - _setConfig(endpoint, lib, config); - return; + if (ulnConfig.requiredDVNs[i] == DEAD) { + isDead = true; } } - for (uint256 i; i < numRequiredDVN; ++i) { - if (ulnConfig.optionalDVNs[i] == dead) { - _setConfig(endpoint, lib, config); - return; + + for (uint256 i; i < numOptionalDVN; ++i) { + if (ulnConfig.optionalDVNs[i] == DEAD) { + isDead = true; } } - } - - function _setConfig(ILayerZeroEndpointV2 endpoint, address lib, ConfigReader.Config memory config) internal { - address[] memory requiredDVNs = new address[](1); - address[] memory optionalDVNs = new address[](0); - requiredDVNs[0] = config.dvnIfNoDefault; + // if no dead address in the ulnConfig, prompt for use of default onchain config, otherwise just use what's in + // config file + if (!isDead) { + string memory a = vm.prompt( + "There is a default onchain configuration for this chain/peerEid combination. Would you like to use it? (y/n)" + ); + if (compareStrings(a, "y")) { + console2.log("using default onchain config"); + } else { + console2.log("setting LayerZero ULN config using params provided in config file"); + _setConfig(newTeller, endpoint, lib, config); + } + } else { + console2.log( + "No default configuration for this chain/peerEid combination. Using params provided in config file" + ); + _setConfig(newTeller, endpoint, lib, config); + } + } - bytes memory ulnConfigBytes = - abi.encode(UlnConfig(config.dvnBlockConfirmationsRequiredIfNoDefault, 1, 0, 0, requiredDVNs, optionalDVNs)); + function _setConfig( + address newTeller, + ILayerZeroEndpointV2 endpoint, + address lib, + ConfigReader.Config memory config + ) + internal + { + require(config.dvnBlockConfirmationsRequired != 0, "dvn block confirmations 0"); + require(config.requiredDvns.length != 0, "no required dvns"); + + // sort the dvns + config.requiredDvns = sortAddresses(config.requiredDvns); + config.optionalDvns = sortAddresses(config.optionalDvns); + + bytes memory ulnConfigBytes = abi.encode( + UlnConfig( + config.dvnBlockConfirmationsRequired, + uint8(config.requiredDvns.length), + uint8(config.optionalDvns.length), + config.optionalDvnThreshold, + config.requiredDvns, + config.optionalDvns + ) + ); SetConfigParam[] memory setConfigParams = new SetConfigParam[](1); setConfigParams[0] = SetConfigParam(config.peerEid, 2, ulnConfigBytes); - endpoint.setConfig(config.teller, lib, setConfigParams); + endpoint.setConfig(newTeller, lib, setConfigParams); + } + + function sortAddresses(address[] memory addresses) internal pure returns (address[] memory) { + uint256 length = addresses.length; + if (length < 2) return addresses; + + for (uint256 i; i < length - 1; ++i) { + for (uint256 j; j < length - i - 1; ++j) { + if (addresses[j] > addresses[j + 1]) { + address temp = addresses[j]; + addresses[j] = addresses[j + 1]; + addresses[j + 1] = temp; + } + } + } + return addresses; + } + + function addressToBytes32LeftPad(address addr) internal returns (bytes32 leftPadBytes32) { + leftPadBytes32 = bytes32(bytes20(addr)) >> 0x60; } } diff --git a/src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol index a34cdb8..b496764 100644 --- a/src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol @@ -77,9 +77,7 @@ contract EtherFiLiquidDecoderAndSanitizer is * @notice BalancerV2, NativeWrapper, Curve, and Gearbox all specify a `withdraw(uint256)`, * all cases are handled the same way. */ - function withdraw( - uint256 - ) + function withdraw(uint256) external pure override( diff --git a/src/base/DecodersAndSanitizers/EtherFiLiquidEthDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/EtherFiLiquidEthDecoderAndSanitizer.sol index 18e52ca..5fe07a7 100644 --- a/src/base/DecodersAndSanitizers/EtherFiLiquidEthDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/EtherFiLiquidEthDecoderAndSanitizer.sol @@ -86,9 +86,7 @@ contract EtherFiLiquidEthDecoderAndSanitizer is * @notice BalancerV2, NativeWrapper, Curve, and Gearbox all specify a `withdraw(uint256)`, * all cases are handled the same way. */ - function withdraw( - uint256 - ) + function withdraw(uint256) external pure override( diff --git a/src/base/DecodersAndSanitizers/EtherFiLiquidUsdDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/EtherFiLiquidUsdDecoderAndSanitizer.sol index cbbdcef..675aa2e 100644 --- a/src/base/DecodersAndSanitizers/EtherFiLiquidUsdDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/EtherFiLiquidUsdDecoderAndSanitizer.sol @@ -79,9 +79,7 @@ contract EtherFiLiquidUsdDecoderAndSanitizer is * @notice BalancerV2, NativeWrapper, Curve, and Gearbox all specify a `withdraw(uint256)`, * all cases are handled the same way. */ - function withdraw( - uint256 - ) + function withdraw(uint256) external pure override( @@ -116,9 +114,7 @@ contract EtherFiLiquidUsdDecoderAndSanitizer is * @notice EtherFi, and Lido all specify a `wrap(uint256)`, * all cases are handled the same way. */ - function wrap( - uint256 - ) + function wrap(uint256) external pure override(EtherFiDecoderAndSanitizer, LidoDecoderAndSanitizer) @@ -132,9 +128,7 @@ contract EtherFiLiquidUsdDecoderAndSanitizer is * @notice EtherFi, and Lido all specify a `unwrap(uint256)`, * all cases are handled the same way. */ - function unwrap( - uint256 - ) + function unwrap(uint256) external pure override(EtherFiDecoderAndSanitizer, LidoDecoderAndSanitizer) diff --git a/src/base/DecodersAndSanitizers/LidoLiquidDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/LidoLiquidDecoderAndSanitizer.sol index 0be64ca..3efcb16 100644 --- a/src/base/DecodersAndSanitizers/LidoLiquidDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/LidoLiquidDecoderAndSanitizer.sol @@ -64,9 +64,7 @@ contract LidoLiquidDecoderAndSanitizer is * @notice BalancerV2, NativeWrapper, Curve, and Gearbox all specify a `withdraw(uint256)`, * all cases are handled the same way. */ - function withdraw( - uint256 - ) + function withdraw(uint256) external pure override( diff --git a/src/base/DecodersAndSanitizers/Protocols/EigenLayerLSTStakingDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/Protocols/EigenLayerLSTStakingDecoderAndSanitizer.sol index 31ea765..c345bac 100644 --- a/src/base/DecodersAndSanitizers/Protocols/EigenLayerLSTStakingDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/Protocols/EigenLayerLSTStakingDecoderAndSanitizer.sol @@ -23,9 +23,7 @@ abstract contract EigenLayerLSTStakingDecoderAndSanitizer is BaseDecoderAndSanit addressesFound = abi.encodePacked(strategy, token); } - function queueWithdrawals( - DecoderCustomTypes.QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) + function queueWithdrawals(DecoderCustomTypes.QueuedWithdrawalParams[] calldata queuedWithdrawalParams) external pure virtual diff --git a/src/base/DecodersAndSanitizers/Protocols/UniswapV3DecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/Protocols/UniswapV3DecoderAndSanitizer.sol index 3fce397..41bf656 100644 --- a/src/base/DecodersAndSanitizers/Protocols/UniswapV3DecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/Protocols/UniswapV3DecoderAndSanitizer.sol @@ -23,9 +23,7 @@ abstract contract UniswapV3DecoderAndSanitizer is BaseDecoderAndSanitizer { //============================== UNISWAP V3 =============================== - function exactInput( - DecoderCustomTypes.ExactInputParams calldata params - ) + function exactInput(DecoderCustomTypes.ExactInputParams calldata params) external pure virtual @@ -46,9 +44,7 @@ abstract contract UniswapV3DecoderAndSanitizer is BaseDecoderAndSanitizer { addressesFound = abi.encodePacked(addressesFound, params.recipient); } - function mint( - DecoderCustomTypes.MintParams calldata params - ) + function mint(DecoderCustomTypes.MintParams calldata params) external pure virtual @@ -59,9 +55,7 @@ abstract contract UniswapV3DecoderAndSanitizer is BaseDecoderAndSanitizer { addressesFound = abi.encodePacked(params.token0, params.token1, params.recipient); } - function increaseLiquidity( - DecoderCustomTypes.IncreaseLiquidityParams calldata params - ) + function increaseLiquidity(DecoderCustomTypes.IncreaseLiquidityParams calldata params) external view virtual @@ -77,9 +71,7 @@ abstract contract UniswapV3DecoderAndSanitizer is BaseDecoderAndSanitizer { addressesFound = abi.encodePacked(operator, token0, token1); } - function decreaseLiquidity( - DecoderCustomTypes.DecreaseLiquidityParams calldata params - ) + function decreaseLiquidity(DecoderCustomTypes.DecreaseLiquidityParams calldata params) external view virtual @@ -96,9 +88,7 @@ abstract contract UniswapV3DecoderAndSanitizer is BaseDecoderAndSanitizer { return addressesFound; } - function collect( - DecoderCustomTypes.CollectParams calldata params - ) + function collect(DecoderCustomTypes.CollectParams calldata params) external view virtual diff --git a/src/helper/Constants.sol b/src/helper/Constants.sol index 17cc9cc..5664215 100644 --- a/src/helper/Constants.sol +++ b/src/helper/Constants.sol @@ -8,6 +8,7 @@ IPriceFeed constant ETH_PER_EZETH_CHAINLINK = IPriceFeed(0x636A000262F6aA9e1F094 IPriceFeed constant ETH_PER_RSETH_CHAINLINK = IPriceFeed(0x03c68933f7a3F76875C0bc670a58e69294cDFD01); IPriceFeed constant ETH_PER_RSWETH_CHAINLINK = IPriceFeed(0xb613CfebD0b6e95abDDe02677d6bC42394FdB857); IPriceFeed constant ETH_PER_PUFETH_REDSTONE = IPriceFeed(0x76A495b0bFfb53ef3F0E94ef0763e03cE410835C); +IPriceFeed constant ETH_PER_APXETH_REDSTONE = IPriceFeed(0x19219BC90F48DeE4d5cF202E09c438FAacFd8Bea); address constant SWBTC = 0x8DB2350D78aBc13f5673A411D4700BCF87864dDE; address constant WBTC_ETHEREUM = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; diff --git a/src/interfaces/EtherFiLiquid1.sol b/src/interfaces/EtherFiLiquid1.sol index 080242e..14d5ffc 100644 --- a/src/interfaces/EtherFiLiquid1.sol +++ b/src/interfaces/EtherFiLiquid1.sol @@ -72,9 +72,7 @@ interface EtherFiLiquid1 { function addPosition(uint32 index, uint32 positionId, bytes memory configurationData, bool inDebtArray) external; function addPositionToCatalogue(uint32 positionId) external; function allowance(address, address) external view returns (uint256); - function alternativeAssetData( - address - ) + function alternativeAssetData(address) external view returns (bool isSupported, uint32 holdingPosition, uint32 depositFee); diff --git a/src/interfaces/IStaking.sol b/src/interfaces/IStaking.sol index f1d953a..5abf6ee 100644 --- a/src/interfaces/IStaking.sol +++ b/src/interfaces/IStaking.sol @@ -84,9 +84,7 @@ interface IUNSTETH { bool isClaimed; } - function getWithdrawalStatus( - uint256[] calldata _requestIds - ) + function getWithdrawalStatus(uint256[] calldata _requestIds) external view returns (WithdrawalRequestStatus[] memory statuses); diff --git a/src/interfaces/RawDataDecoderAndSanitizerInterfaces.sol b/src/interfaces/RawDataDecoderAndSanitizerInterfaces.sol index 6cb7bfb..0e5705b 100644 --- a/src/interfaces/RawDataDecoderAndSanitizerInterfaces.sol +++ b/src/interfaces/RawDataDecoderAndSanitizerInterfaces.sol @@ -24,9 +24,7 @@ interface INonFungiblePositionManager { } function ownerOf(uint256 tokenId) external view returns (address); - function positions( - uint256 tokenId - ) + function positions(uint256 tokenId) external view returns ( diff --git a/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/OptionsHelper.sol b/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/OptionsHelper.sol index f0f2cb4..0bd63c0 100644 --- a/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/OptionsHelper.sol +++ b/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/OptionsHelper.sol @@ -8,9 +8,7 @@ import { UlnOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/li contract UlnOptionsMock { using UlnOptions for bytes; - function decode( - bytes calldata _options - ) + function decode(bytes calldata _options) public pure returns (bytes memory executorOptions, bytes memory dvnOptions) @@ -33,9 +31,7 @@ contract OptionsHelper { (gas, value) = this.decodeLzReceiveOption(option); } - function _parseExecutorNativeDropOption( - bytes memory _options - ) + function _parseExecutorNativeDropOption(bytes memory _options) internal view returns (uint256 amount, bytes32 receiver) @@ -46,9 +42,7 @@ contract OptionsHelper { (amount, receiver) = this.decodeNativeDropOption(option); } - function _parseExecutorLzComposeOption( - bytes memory _options - ) + function _parseExecutorLzComposeOption(bytes memory _options) internal view returns (uint16 index, uint256 gas, uint256 value) @@ -109,9 +103,7 @@ contract OptionsHelper { return ExecutorOptions.decodeNativeDropOption(_option); } - function decodeLzComposeOption( - bytes calldata _option - ) + function decodeLzComposeOption(bytes calldata _option) external pure returns (uint16 index, uint128 gas, uint128 value) diff --git a/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/SendUln302Mock.sol b/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/SendUln302Mock.sol index 7ac7df9..78ab9b0 100644 --- a/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/SendUln302Mock.sol +++ b/test/CrossChain/@layerzerolabs-custom/test-evm-foundry-custom/SendUln302Mock.sol @@ -101,9 +101,7 @@ contract SendUln302Mock is SendUlnBase, SendLibBaseE2 { (otherWorkerFees, encodedPacket) = _payDVNs(fees, _packet, _options); } - function _splitOptions( - bytes calldata _options - ) + function _splitOptions(bytes calldata _options) internal pure override diff --git a/test/CrossChain/live/LIVECrossChainOPTellerWithMultiAssetSupport.t.sol b/test/CrossChain/live/LIVECrossChainOPTellerWithMultiAssetSupport.t.sol deleted file mode 100644 index f976407..0000000 --- a/test/CrossChain/live/LIVECrossChainOPTellerWithMultiAssetSupport.t.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.21; - -import { - CrossChainOPTellerWithMultiAssetSupportTest, - CrossChainOPTellerWithMultiAssetSupport -} from "../CrossChainOPTellerWithMultiAssetSupport.t.sol"; - -/** - * @notice live test for OP Teller, since OP doesn't use any sort of mock handlers or testing contracts, it is able to - * be almost entirely inherited from it's local test parent, with just adjusting the deployment with the existing - * addresses. - */ -contract LIVECrossChainOPTTellerWithMultiAssetSupportTest is CrossChainOPTellerWithMultiAssetSupportTest { - address constant SOURCE_TELLER = 0x8D9d36a33DAD6fb622180b549aB05B6ED71350F7; - address constant DESTINATION_TELLER = 0x8D9d36a33DAD6fb622180b549aB05B6ED71350F7; - string constant RPC_KEY = "SEPOLIA_RPC_URL"; - address from; - - function setUp() public virtual override { - uint256 forkId = vm.createFork(vm.envString(RPC_KEY)); - vm.selectFork(forkId); - from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); - vm.startPrank(from); - - sourceTellerAddr = SOURCE_TELLER; - destinationTellerAddr = DESTINATION_TELLER; - boringVault = CrossChainOPTellerWithMultiAssetSupport(sourceTellerAddr).vault(); - accountant = CrossChainOPTellerWithMultiAssetSupport(sourceTellerAddr).accountant(); - - CrossChainOPTellerWithMultiAssetSupport(sourceTellerAddr).setGasBounds(0, uint32(CHAIN_MESSAGE_GAS_LIMIT)); - - // deal(address(WETH), address(boringVault), 1_000e18); - deal(address(boringVault), from, 1000e18, true); - // deal(address(LINK), address(this), 1_000e18); - } - - function testBridgingShares(uint256 sharesToBridge) public virtual override { - vm.startPrank(from); - super.testBridgingShares(sharesToBridge); - } - - function _startFork(string memory rpcKey, uint256 blockNumber) internal virtual override returns (uint256 forkId) { } - - function _deploySourceAndDestinationTeller() internal virtual override { } - - function testReverts() public virtual override { - vm.startPrank(from); - super.testReverts(); - } -} diff --git a/test/CrossChain/live/LIVEMultiChainLayerZeroTellerWithMultiAssetSupport.t.sol b/test/CrossChain/live/LIVEMultiChainLayerZeroTellerWithMultiAssetSupport.t.sol deleted file mode 100644 index 95d6d73..0000000 --- a/test/CrossChain/live/LIVEMultiChainLayerZeroTellerWithMultiAssetSupport.t.sol +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.21; - -import { - MultiChainLayerZeroTellerWithMultiAssetSupport, - BridgeData, - ERC20, - TellerWithMultiAssetSupport, - MultiChainLayerZeroTellerWithMultiAssetSupportTest -} from "../MultiChainLayerZeroTellerWithMultiAssetSupport.t.sol"; -import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol"; - -/** - * @notice LayerZero normally is tested with a foundry testing framework that includes mocks for the crosschain ability, - * Testing this live is not an option so most functions must be overridden and simplified to test only on the local - * chain - */ -contract LIVEMultiChainLayerZeroTellerWithMultiAssetSupportTest is - MultiChainLayerZeroTellerWithMultiAssetSupportTest -{ - using FixedPointMathLib for uint256; - - address constant SOURCE_TELLER = 0xfFEa4FB47AC7FA102648770304605920CE35660c; - address constant DESTINATION_TELLER = 0xfFEa4FB47AC7FA102648770304605920CE35660c; - - string constant RPC_KEY = "SEPOLIA_RPC_URL"; - - function setUp() public virtual override { - uint256 forkId = vm.createFork(vm.envString(RPC_KEY)); - vm.selectFork(forkId); - address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); - vm.startPrank(from); - - sourceTellerAddr = SOURCE_TELLER; - destinationTellerAddr = DESTINATION_TELLER; - boringVault = MultiChainLayerZeroTellerWithMultiAssetSupport(sourceTellerAddr).vault(); - - // deal(address(WETH), address(boringVault), 1_000e18); - deal(address(boringVault), from, 1000e18, true); - } - - // function adjusted to only have source chain calls - function testBridgingShares(uint256 sharesToBridge) external virtual override { - MultiChainLayerZeroTellerWithMultiAssetSupport sourceTeller = - MultiChainLayerZeroTellerWithMultiAssetSupport(sourceTellerAddr); - - sharesToBridge = uint96(bound(sharesToBridge, 1, 1000e18)); - uint256 startingShareBalance = boringVault.balanceOf(address(this)); - // Setup chains on bridge. - sourceTeller.addChain(DESTINATION_SELECTOR, true, true, destinationTellerAddr, CHAIN_MESSAGE_GAS_LIMIT, 0); - - // Bridge shares. - address to = vm.addr(1); - - BridgeData memory data = BridgeData({ - chainSelector: DESTINATION_SELECTOR, - destinationChainReceiver: to, - bridgeFeeToken: ERC20(NATIVE), - messageGas: 80_000, - data: "" - }); - - uint256 quote = sourceTeller.previewFee(sharesToBridge, data); - bytes32 id = sourceTeller.bridge{ value: quote }(sharesToBridge, data); - - assertEq( - boringVault.balanceOf(address(this)), startingShareBalance - sharesToBridge, "Should have burned shares." - ); - } - - // function adjusted to only have source chain calls - function testDepositAndBridgeFailsWithShareLockTime(uint256 amount) external virtual override { - MultiChainLayerZeroTellerWithMultiAssetSupport sourceTeller = - MultiChainLayerZeroTellerWithMultiAssetSupport(sourceTellerAddr); - - sourceTeller.addChain(DESTINATION_SELECTOR, true, true, destinationTellerAddr, CHAIN_MESSAGE_GAS_LIMIT, 0); - sourceTeller.setShareLockPeriod(60); - - amount = bound(amount, 0.0001e18, 10_000e18); - // make a user and give them WETH - address user = makeAddr("A user"); - address userChain2 = makeAddr("A user on chain 2"); - deal(address(WETH), user, amount); - - // approve teller to spend WETH - vm.startPrank(user); - vm.deal(user, 10e18); - WETH.approve(address(boringVault), amount); - - // perform depositAndBridge - BridgeData memory data = BridgeData({ - chainSelector: DESTINATION_SELECTOR, - destinationChainReceiver: userChain2, - bridgeFeeToken: ERC20(NATIVE), - messageGas: 80_000, - data: "" - }); - - uint256 ONE_SHARE = 10 ** boringVault.decimals(); - - // so you don't really need to know exact shares in reality - // just need to pass in a number roughly the same size to get quote - // I still get the real number here for testing - uint256 shares = amount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(WETH)); - uint256 quote = sourceTeller.previewFee(shares, data); - - vm.expectRevert( - bytes( - abi.encodeWithSelector( - TellerWithMultiAssetSupport.TellerWithMultiAssetSupport__SharesAreLocked.selector - ) - ) - ); - sourceTeller.depositAndBridge{ value: quote }(WETH, amount, shares, data); - } - - // function adjusted to only have source chain calls - function testDepositAndBridge(uint256 amount) external virtual override { - MultiChainLayerZeroTellerWithMultiAssetSupport sourceTeller = - MultiChainLayerZeroTellerWithMultiAssetSupport(sourceTellerAddr); - - sourceTeller.addChain(DESTINATION_SELECTOR, true, true, destinationTellerAddr, CHAIN_MESSAGE_GAS_LIMIT, 0); - - amount = bound(amount, 0.0001e18, 10_000e18); - // make a user and give them WETH - address user = makeAddr("A user"); - address userChain2 = makeAddr("A user on chain 2"); - deal(address(WETH), user, amount); - - // approve teller to spend WETH - vm.startPrank(user); - vm.deal(user, 10e18); - WETH.approve(address(boringVault), amount); - - // perform depositAndBridge - BridgeData memory data = BridgeData({ - chainSelector: DESTINATION_SELECTOR, - destinationChainReceiver: userChain2, - bridgeFeeToken: ERC20(NATIVE), - messageGas: 80_000, - data: "" - }); - - uint256 ONE_SHARE = 10 ** boringVault.decimals(); - - // so you don't really need to know exact shares in reality - // just need to pass in a number roughly the same size to get quote - // I still get the real number here for testing - uint256 shares = amount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(WETH)); - uint256 quote = sourceTeller.previewFee(shares, data); - sourceTeller.depositAndBridge{ value: quote }(WETH, amount, shares, data); - - assertEq(boringVault.balanceOf(user), 0, "Should have burned shares."); - - vm.stopPrank(); - } - - function testReverts() public virtual override { - MultiChainLayerZeroTellerWithMultiAssetSupport sourceTeller = - MultiChainLayerZeroTellerWithMultiAssetSupport(sourceTellerAddr); - - super.testReverts(); - - // if the token is not NATIVE, should revert - address NOT_NATIVE = 0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3; - BridgeData memory data = - BridgeData(DESTINATION_SELECTOR, address(this), ERC20(NOT_NATIVE), 80_000, abi.encode(DESTINATION_SELECTOR)); - sourceTeller.addChain(DESTINATION_SELECTOR, true, true, destinationTellerAddr, CHAIN_MESSAGE_GAS_LIMIT, 0); - - vm.expectRevert( - abi.encodeWithSelector( - MultiChainLayerZeroTellerWithMultiAssetSupport - .MultiChainLayerZeroTellerWithMultiAssetSupport_InvalidToken - .selector - ) - ); - sourceTeller.bridge(1e18, data); - - // Call now succeeds. - data = BridgeData(DESTINATION_SELECTOR, address(this), ERC20(NATIVE), 80_000, abi.encode(DESTINATION_SELECTOR)); - uint256 quote = sourceTeller.previewFee(1e18, data); - - sourceTeller.bridge{ value: quote }(1e18, data); - } -} diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol new file mode 100644 index 0000000..1027477 --- /dev/null +++ b/test/LiveDeploy.t.sol @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.21; + +import { Test, stdStorage, StdStorage, stdError, console } from "@forge-std/Test.sol"; +import { DeployAll } from "script/deploy/deployAll.s.sol"; +import { ConfigReader } from "script/ConfigReader.s.sol"; +import { ERC20 } from "@solmate/tokens/ERC20.sol"; +import { BoringVault } from "src/base/BoringVault.sol"; +import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol"; + +import { TellerWithMultiAssetSupport } from "src/base/Roles/TellerWithMultiAssetSupport.sol"; +import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRateProviders.sol"; +import { RolesAuthority } from "@solmate/auth/authorities/RolesAuthority.sol"; +import { DeployRateProviders } from "script/deploy/01_DeployRateProviders.s.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { stdJson as StdJson } from "@forge-std/StdJson.sol"; + +import { CrossChainOPTellerWithMultiAssetSupportTest } from + "test/CrossChain/CrossChainOPTellerWithMultiAssetSupport.t.sol"; +import { CrossChainTellerBase, BridgeData, ERC20 } from "src/base/Roles/CrossChain/CrossChainTellerBase.sol"; +import { CrossChainOPTellerWithMultiAssetSupport } from + "src/base/Roles/CrossChain/CrossChainOPTellerWithMultiAssetSupport.sol"; +import { MultiChainLayerZeroTellerWithMultiAssetSupport } from + "src/base/Roles/CrossChain/MultiChainLayerZeroTellerWithMultiAssetSupport.sol"; + +string constant DEFAULT_RPC_URL = "L1_RPC_URL"; +uint256 constant DELTA = 10_000; + +// We use this so that we can use the inheritance linearization to start the fork before other constructors +abstract contract ForkTest is Test { + constructor() { + // the start fork must be done before the constructor in the Base.s.sol, as it attempts to access an onchain + // asset, CREATEX + _startFork(DEFAULT_RPC_URL); + } + + function _startFork(string memory rpcKey) internal virtual returns (uint256 forkId) { + if (block.chainid == 31_337) { + forkId = vm.createFork(vm.envString(rpcKey)); + vm.selectFork(forkId); + } + } +} + +contract LiveDeploy is ForkTest, DeployAll { + using Strings for address; + using StdJson for string; + using FixedPointMathLib for uint256; + + ERC20 constant NATIVE_ERC20 = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + uint256 ONE_SHARE; + uint8 constant SOLVER_ROLE = 42; + + function setUp() public virtual { + string memory FILE_NAME; + + // 31_337 is default if this script is ran with no --fork-url= CLI flag + // when using the Makefile we use this flag to simplify use of the makefile + // however, the script should still have a default configuration for fork and FILE_NAME + if (block.chainid == 31_337) { + // default file is exampleL1 + FILE_NAME = "exampleL1.json"; + + // we have to start the fork again... I don't exactly know why. But it's a known issue with foundry re: + // https://github.com/foundry-rs/foundry/issues/5471 + _startFork(DEFAULT_RPC_URL); + } else { + // Otherwise we use the makefile provided deployment file ENV name + FILE_NAME = vm.envString("LIVE_DEPLOY_READ_FILE_NAME"); + } + + // Run the deployment scripts + + run(FILE_NAME); + + // check for if all rate providers are deployed, if not error + for (uint256 i; i < mainConfig.assets.length; ++i) { + // set the corresponding rate provider + string memory key = string( + abi.encodePacked( + ".assetToRateProviderAndPriceFeed.", mainConfig.assets[i].toHexString(), ".rateProvider" + ) + ); + + address rateProvider = getChainConfigFile().readAddress(key); + assertNotEq(rateProvider, address(0), "Rate provider address is 0"); + assertNotEq(rateProvider.code.length, 0, "No code at rate provider address"); + } + + // warp forward the minimumUpdateDelay for the accountant to prevent it from pausing on update test + vm.warp(block.timestamp + mainConfig.minimumUpdateDelayInSeconds); + + // define one share based off of vault decimals + ONE_SHARE = 10 ** BoringVault(payable(mainConfig.boringVault)).decimals(); + + // give this the SOLVER_ROLE to call bulkWithdraw + RolesAuthority rolesAuthority = RolesAuthority(mainConfig.rolesAuthority); + vm.startPrank(mainConfig.protocolAdmin); + rolesAuthority.setUserRole(address(this), SOLVER_ROLE, true); + rolesAuthority.setRoleCapability( + SOLVER_ROLE, mainConfig.teller, TellerWithMultiAssetSupport.bulkWithdraw.selector, true + ); + vm.stopPrank(); + } + + function testDepositAndBridge(uint256 amount) public { + string memory tellerName = mainConfig.tellerContractName; + if (compareStrings(tellerName, "CrossChainOPTellerWithMultiAssetSupport")) { + _testOPDepositAndBridge(ERC20(mainConfig.base), amount); + } else if (compareStrings(tellerName, "MultiChainLayerZeroTellerWithMultiAssetSupport")) { + _testLZDepositAndBridge(ERC20(mainConfig.base), amount); + } else { } + } + + function testDepositBaseAssetAndUpdateRate(uint256 depositAmount, uint256 rateChange256) public { + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + // bound and cast since bound does not support uint96 + uint96 rateChange = uint96( + bound(rateChange256, mainConfig.allowedExchangeRateChangeLower, mainConfig.allowedExchangeRateChangeUpper) + ); + + depositAmount = bound(depositAmount, 1, 10_000e18); + + // mint a bunch of extra tokens to the vault for if rate increased + deal(mainConfig.base, mainConfig.boringVault, depositAmount); + + _depositAssetWithApprove(ERC20(mainConfig.base), depositAmount); + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + uint256 expected_shares = depositAmount; + + assertEq( + boringVault.balanceOf(address(this)), + expected_shares, + "Should have received expected shares 1:1 for base asset" + ); + + // update the rate + _updateRate(rateChange, accountant); + + uint256 expectedAssetsBack = depositAmount * rateChange / 10_000; + + // attempt a withdrawal after + TellerWithMultiAssetSupport(mainConfig.teller).bulkWithdraw( + ERC20(mainConfig.base), expected_shares, expectedAssetsBack, address(this) + ); + assertEq( + ERC20(mainConfig.base).balanceOf(address(this)), + expectedAssetsBack, + "Should have been able to withdraw back the depositAmount with rate factored" + ); + } + + function testDepositBaseAssetOnStartingRate(uint256 depositAmount, uint256 rateChange256) public { + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + + // bound and cast since bound does not support uint96 + uint96 rateChange = uint96( + bound(rateChange256, mainConfig.allowedExchangeRateChangeLower, mainConfig.allowedExchangeRateChangeUpper) + ); + depositAmount = bound(depositAmount, 2, 10_000e18); + + // update the rate + _updateRate(rateChange, accountant); + _depositAssetWithApprove(ERC20(mainConfig.base), depositAmount); + + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + uint256 sharesOut = boringVault.balanceOf(address(this)); + + // attempt a withdrawal after + TellerWithMultiAssetSupport(mainConfig.teller).bulkWithdraw( + ERC20(mainConfig.base), sharesOut, depositAmount - 2, address(this) + ); + + assertApproxEqAbs( + ERC20(mainConfig.base).balanceOf(address(this)), + depositAmount, + 2, + "Should have been able to withdraw back the depositAmount" + ); + } + + function testDepositBaseAsset(uint256 depositAmount) public { + depositAmount = bound(depositAmount, 1, 10_000e18); + _depositAssetWithApprove(ERC20(mainConfig.base), depositAmount); + + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + uint256 expected_shares = depositAmount; + assertEq( + boringVault.balanceOf(address(this)), + expected_shares, + "Should have received expected shares 1:1 for base asset" + ); + + // attempt a withdrawal after + TellerWithMultiAssetSupport(mainConfig.teller).bulkWithdraw( + ERC20(mainConfig.base), expected_shares, depositAmount, address(this) + ); + assertEq( + ERC20(mainConfig.base).balanceOf(address(this)), + depositAmount, + "Should have been able to withdraw back the depositAmount" + ); + } + + function testDepositASupportedAssetAndUpdateRate(uint256 depositAmount, uint96 rateChange) public { + uint256 assetsCount = mainConfig.assets.length; + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + // manual bounding done because bound() doesn't exist for uint96 + rateChange = rateChange % uint96(mainConfig.allowedExchangeRateChangeUpper - 1); + rateChange = (rateChange < mainConfig.allowedExchangeRateChangeLower + 1) + ? mainConfig.allowedExchangeRateChangeLower + 1 + : rateChange; + + depositAmount = bound(depositAmount, 1, 10_000e18); + + // mint a bunch of extra tokens to the vault for if rate increased + deal(mainConfig.base, mainConfig.boringVault, depositAmount); + uint256 expecteShares; + uint256[] memory expectedSharesByAsset = new uint256[](assetsCount); + uint256[] memory rateInQuoteBefore = new uint256[](assetsCount); + for (uint256 i; i < assetsCount; ++i) { + rateInQuoteBefore[i] = accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i])); + expectedSharesByAsset[i] = + depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i]))); + expecteShares += expectedSharesByAsset[i]; + + _depositAssetWithApprove(ERC20(mainConfig.assets[i]), depositAmount); + } + + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + assertEq(boringVault.balanceOf(address(this)), expecteShares, "Should have received expected shares"); + + // update the rate + _updateRate(rateChange, accountant); + + // withdrawal the assets for the same amount back + for (uint256 i; i < assetsCount; ++i) { + assertApproxEqAbs( + accountant.getRateInQuote(ERC20(mainConfig.assets[i])), + rateInQuoteBefore[i] * rateChange / 10_000, + 1, + "Rate change did not apply to asset" + ); + + // mint extra assets for vault to give out + deal(mainConfig.assets[i], mainConfig.boringVault, depositAmount); + + uint256 expectedAssetsBack = ((depositAmount) * rateChange / 10_000); + + uint256 assetsOut = expectedSharesByAsset[i].mulDivDown( + accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i])), ONE_SHARE + ); + + // Delta must be set very high to pass + assertApproxEqAbs(assetsOut, expectedAssetsBack, DELTA, "assets out not equal to expected assets back"); + + TellerWithMultiAssetSupport(mainConfig.teller).bulkWithdraw( + ERC20(mainConfig.assets[i]), expectedSharesByAsset[i], expectedAssetsBack * 99 / 100, address(this) + ); + + assertApproxEqAbs( + ERC20(mainConfig.assets[i]).balanceOf(address(this)), + expectedAssetsBack, + DELTA, + "Should have been able to withdraw back the depositAmounts" + ); + } + } + + function testDepositASupportedAsset(uint256 depositAmount, uint256 indexOfSupported) public { + uint256 assetsCount = mainConfig.assets.length; + indexOfSupported = bound(indexOfSupported, 0, assetsCount); + depositAmount = bound(depositAmount, 1, 10_000e18); + + uint256 expecteShares; + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + uint256[] memory expectedSharesByAsset = new uint256[](assetsCount); + for (uint256 i; i < assetsCount; ++i) { + expectedSharesByAsset[i] = + depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i]))); + expecteShares += expectedSharesByAsset[i]; + + _depositAssetWithApprove(ERC20(mainConfig.assets[i]), depositAmount); + } + + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + assertEq(boringVault.balanceOf(address(this)), expecteShares, "Should have received expected shares"); + + // withdrawal the assets for the same amount back + for (uint256 i; i < assetsCount; ++i) { + TellerWithMultiAssetSupport(mainConfig.teller).bulkWithdraw( + ERC20(mainConfig.assets[i]), expectedSharesByAsset[i], depositAmount - 1, address(this) + ); + assertApproxEqAbs( + ERC20(mainConfig.assets[i]).balanceOf(address(this)), + depositAmount, + 1, + "Should have been able to withdraw back the depositAmounts" + ); + } + } + + function testAssetsAreAllNormalERC20(uint256 mintAmount, uint256 transferAmount) public { + mintAmount = bound(mintAmount, 1, type(uint256).max); + transferAmount = bound(transferAmount, 1, mintAmount); + address user1 = makeAddr("user1"); + address user2 = makeAddr("user2"); + + for (uint256 i; i < mainConfig.assets.length; ++i) { + ERC20 asset = ERC20(mainConfig.assets[i]); + deal(address(asset), user1, mintAmount); + assertEq(asset.balanceOf(user1), mintAmount, "asset did not deal to user1 correctly"); + uint256 totalSupplyStart = asset.totalSupply(); + vm.prank(user1); + asset.transfer(user2, transferAmount); + assertEq(asset.balanceOf(user1), mintAmount - transferAmount, "user1 balance not removed after transfer"); + assertEq(asset.balanceOf(user2), transferAmount, "user2 balance not incremented after transfer"); + } + } + + function _depositAssetWithApprove(ERC20 asset, uint256 depositAmount) internal { + deal(address(asset), address(this), depositAmount); + asset.approve(mainConfig.boringVault, depositAmount); + TellerWithMultiAssetSupport(mainConfig.teller).deposit(asset, depositAmount, 0); + } + + function _testLZDepositAndBridge(ERC20 asset, uint256 amount) internal { + MultiChainLayerZeroTellerWithMultiAssetSupport sourceTeller = + MultiChainLayerZeroTellerWithMultiAssetSupport(mainConfig.teller); + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + + amount = bound(amount, 0.0001e18, 10_000e18); + // make a user and give them BASE + address user = makeAddr("A user"); + address userChain2 = makeAddr("A user on chain 2"); + deal(address(asset), user, amount); + + // approve teller to spend BASE + vm.startPrank(user); + vm.deal(user, 10e18); + asset.approve(address(boringVault), amount); + + // perform depositAndBridge + BridgeData memory data = BridgeData({ + chainSelector: mainConfig.peerEid, + destinationChainReceiver: userChain2, + bridgeFeeToken: NATIVE_ERC20, + messageGas: 100_000, + data: "" + }); + + uint256 ONE_SHARE = 10 ** boringVault.decimals(); + + // so you don't really need to know exact shares in reality + // just need to pass in a number roughly the same size to get quote + // I still get the real number here for testing + uint256 shares = amount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(asset)); + uint256 quote = sourceTeller.previewFee(shares, data); + uint256 assetBefore = asset.balanceOf(address(boringVault)); + + sourceTeller.depositAndBridge{ value: quote }(asset, amount, shares, data); + // verifyPackets(uint32(mainConfig.peerEid), addressToBytes32(address(mainConfig.teller))); + + assertEq(boringVault.balanceOf(user), 0, "Should have burned shares."); + + // assertEq(boringVault.balanceOf(userChain2), shares), ; + + assertEq(asset.balanceOf(address(boringVault)), assetBefore + shares, "boring vault should have shares"); + vm.stopPrank(); + } + + function _testOPDepositAndBridge(ERC20 asset, uint256 amount) internal { + CrossChainOPTellerWithMultiAssetSupport sourceTeller = + CrossChainOPTellerWithMultiAssetSupport(mainConfig.teller); + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + + amount = bound(amount, 0.0001e18, 10_000e18); + // make a user and give them BASE + + address user = makeAddr("A user"); + address userChain2 = makeAddr("A user on chain 2"); + deal(address(asset), user, amount); + + // approve teller to spend BASE + vm.startPrank(user); + vm.deal(user, 10e18); + asset.approve(mainConfig.boringVault, amount); + + // perform depositAndBridge + BridgeData memory data = BridgeData({ + chainSelector: 0, + destinationChainReceiver: userChain2, + bridgeFeeToken: NATIVE_ERC20, + messageGas: 100_000, + data: "" + }); + + uint256 ONE_SHARE = 10 ** boringVault.decimals(); + + uint256 shares = amount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(asset)); + uint256 quote = 0; + + uint256 wethBefore = asset.balanceOf(address(boringVault)); + + sourceTeller.depositAndBridge{ value: quote }(asset, amount, shares, data); + + assertEq(boringVault.balanceOf(user), 0, "Should have burned shares."); + + assertEq(asset.balanceOf(address(boringVault)), wethBefore + shares, "boring vault should have shares"); + } + + function addressToBytes32(address _addr) internal pure returns (bytes32) { + return bytes32(uint256(uint160(_addr))); + } + + function _updateRate(uint96 rateChange, AccountantWithRateProviders accountant) internal { + // update the rate + vm.startPrank(mainConfig.exchangeRateBot); + uint96 newRate = uint96(accountant.getRate()) * rateChange / 10_000; + accountant.updateExchangeRate(newRate); + vm.stopPrank(); + } +} diff --git a/test/RateMath.t.sol b/test/RateMath.t.sol new file mode 100644 index 0000000..4dca134 --- /dev/null +++ b/test/RateMath.t.sol @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.21; + +import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol"; +import { ERC20 } from "@solmate/tokens/ERC20.sol"; +import { Test, stdStorage, StdStorage, stdError, console } from "@forge-std/Test.sol"; + +contract RateMath is Test { + using FixedPointMathLib for uint256; + + uint256 constant ACCEPTED_DELTA_PERCENT_OUT_OF_FAVOR = 0.000015e18; + uint256 constant ACCEPTED_DELTA_PERCENT_IN_FAVOR = 0.01e18; + + // keep some state variables that each test can change according to the scenario it's testing + uint256 ONE_SHARE; + + // exchange rate as reported in base decimals + uint256 exchangeRateInBase; + // base asset decimals, ALSO the exchange rate decimals + uint256 baseDecimals; + // the quote asset decimals + uint256 quoteDecimals; + // decimals returned by rate provider in base per quote + uint256 quoteRateDecimals; + // quote rate returned by rate provider + uint256 quoteRate; + + function boundValues( + uint256 depositAmount, + uint256 startQuoteRate, + uint256 startExchangeRate + ) + internal + returns (uint256 _depositAmount, uint256 _quoteRate, uint256 _exchangeRate) + { + // Bound Deposit 1 - 100,000,000 QuoteDecimals + _depositAmount = bound(depositAmount, 1 * e(quoteDecimals), 100_000_000 * e(quoteDecimals)); + // Bound quote rate to 0.01 - 10 QuoteRateDecimals + _quoteRate = bound(startQuoteRate, 1 * e(quoteRateDecimals - 2), 10 * e(quoteRateDecimals)); + // bound exchange rate to 0.8 - 2 baseDecimals + _exchangeRate = bound(startExchangeRate, 8 * e(baseDecimals - 1), 2 * e(baseDecimals)); + } + + function testAtomicDepositAndWithdraw_18Decimals( + uint256 depositAmount, + uint256 startQuoteRate, + uint256 startExchangeRate + ) + external + { + // set decimals + baseDecimals = 18; + quoteDecimals = 18; + quoteRateDecimals = 18; + ONE_SHARE = 10 ** baseDecimals; + + // bound values with helper function + (depositAmount, quoteRate, exchangeRateInBase) = boundValues(depositAmount, startQuoteRate, startExchangeRate); + + // get shares out if deposit done + uint256 shares = depositAssetForShares(depositAmount); + + // get assets back if all shares are withdrawn immediately + uint256 assetsBack = withdrawSharesForAssets(shares); + assertTrue(assetsBack <= depositAmount, "Users should never get back more assets than they deposited"); + assertApproxEqAbs( + assetsBack, + depositAmount, + depositAmount.mulDivDown(ACCEPTED_DELTA_PERCENT_IN_FAVOR, 1e18), + "assetsBack != depositAmount when atomic | In Favor" + ); + } + + function testDepositAndWithdrawWithExchangeRateChange_18_6_Decimals( + uint256 depositAmount, + uint256 startQuoteRate, + uint256 startExchangeRate, + uint256 rateChange + ) + external + { + // set decimals + baseDecimals = 18; + quoteDecimals = 6; + quoteRateDecimals = 6; + ONE_SHARE = 10 ** baseDecimals; + + // bound values + (depositAmount, startQuoteRate, startExchangeRate) = + boundValues(depositAmount, startQuoteRate, startExchangeRate); + exchangeRateInBase = startExchangeRate; + quoteRate = startQuoteRate; + rateChange = bound(rateChange, 9980, 10_020); + + // get shares out if deposit done + uint256 shares = depositAssetForShares(depositAmount); + + // update the rate according to rate change + exchangeRateInBase = exchangeRateInBase.mulDivDown(rateChange, 10_000); + + uint256 assetsBack = withdrawSharesForAssets(shares); + // get expected amount out + uint256 expected = (depositAmount * exchangeRateInBase * startQuoteRate) / (quoteRate * startExchangeRate); + + if (assetsBack > expected) { + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_OUT_OF_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | Out Of Favor" + ); + } + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_IN_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | In Favor" + ); + } + + function testDepositAndWithdrawWithQuoteRateChange_18_6_Decimals( + uint256 depositAmount, + uint256 startQuoteRate, + uint256 startExchangeRate, + uint256 rateChange + ) + external + { + // set decimals + baseDecimals = 18; + quoteDecimals = 6; + quoteRateDecimals = 6; + ONE_SHARE = 10 ** baseDecimals; + + // bound values + (depositAmount, startQuoteRate, startExchangeRate) = + boundValues(depositAmount, startQuoteRate, startExchangeRate); + exchangeRateInBase = startExchangeRate; + quoteRate = startQuoteRate; + rateChange = bound(rateChange, 9980, 10_020); + + // get shares out if deposit done + uint256 shares = depositAssetForShares(depositAmount); + + // update the rate according to rate change + quoteRate = quoteRate.mulDivDown(rateChange, 10_000); + + uint256 assetsBack = withdrawSharesForAssets(shares); + + // get expected amount out + uint256 expected = (depositAmount * exchangeRateInBase * startQuoteRate) / (quoteRate * startExchangeRate); + + if (assetsBack > expected) { + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_OUT_OF_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | Out Of Favor" + ); + } + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_IN_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | In Favor" + ); + } + + function testDepositAndWithdrawWithAllFuzzed_18_decimals( + uint256 depositAmount, + uint256 startQuoteRate, + uint256 startExchangeRate, + uint256 exchangeRateChange, + uint256 quoteRateChange + ) + external + { + // set decimals + baseDecimals = 18; + quoteDecimals = 18; + quoteRateDecimals = quoteDecimals; + ONE_SHARE = 10 ** baseDecimals; + + // bound values + (depositAmount, startQuoteRate, startExchangeRate) = + boundValues(depositAmount, startQuoteRate, startExchangeRate); + exchangeRateInBase = startExchangeRate; + quoteRate = startQuoteRate; + exchangeRateChange = bound(exchangeRateChange, 5980, 20_020); + quoteRateChange = bound(quoteRateChange, 5980, 20_020); + + // get shares out if deposit done + uint256 shares = depositAssetForShares(depositAmount); + + // update the rate according to rate change + exchangeRateInBase = exchangeRateInBase.mulDivDown(exchangeRateChange, 10_000); + quoteRate = quoteRate.mulDivDown(quoteRateChange, 10_000); + + uint256 expected = (depositAmount * exchangeRateInBase * startQuoteRate) / (quoteRate * startExchangeRate); + + uint256 assetsBack = withdrawSharesForAssets(shares); + + if (assetsBack > expected) { + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_OUT_OF_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | Out Of Favor" + ); + } + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_IN_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | In Favor" + ); + } + + function testDepositAndWithdrawWithAllFuzzed_18_6_decimals( + uint256 depositAmount, + uint256 startQuoteRate, + uint256 startExchangeRate, + uint256 exchangeRateChange, + uint256 quoteRateChange + ) + external + { + // set decimals + baseDecimals = 18; + quoteDecimals = 6; + quoteRateDecimals = quoteDecimals; + ONE_SHARE = 10 ** baseDecimals; + + // bound values + (depositAmount, startQuoteRate, startExchangeRate) = + boundValues(depositAmount, startQuoteRate, startExchangeRate); + exchangeRateInBase = startExchangeRate; + quoteRate = startQuoteRate; + exchangeRateChange = bound(exchangeRateChange, 5980, 20_020); + quoteRateChange = bound(quoteRateChange, 5980, 20_020); + + // get shares out if deposit done + uint256 shares = depositAssetForShares(depositAmount); + + // update the rate according to rate change + exchangeRateInBase = exchangeRateInBase.mulDivDown(exchangeRateChange, 10_000); + quoteRate = quoteRate.mulDivDown(quoteRateChange, 10_000); + + uint256 expected = (depositAmount * exchangeRateInBase * startQuoteRate) / (quoteRate * startExchangeRate); + + uint256 assetsBack = withdrawSharesForAssets(shares); + + if (assetsBack > expected) { + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_OUT_OF_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | Out Of Favor" + ); + } + assertApproxEqAbs( + assetsBack, + expected, + expected.mulDivDown(ACCEPTED_DELTA_PERCENT_IN_FAVOR, 1e18), + "assetsBack != depositAmount with rate change | In Favor" + ); + } + + function withdrawSharesForAssets(uint256 shareAmount) public view returns (uint256 assetsOut) { + assetsOut = shareAmount.mulDivDown(getRateInQuote(), ONE_SHARE); + } + + function depositAssetForShares(uint256 depositAmount) public view returns (uint256 shares) { + if (depositAmount == 0) revert("depositAssetForShares amount = 0"); + shares = depositAmount.mulDivDown(ONE_SHARE, getRateInQuote()); + } + + function getRateInQuote() public view returns (uint256 rateInQuote) { + uint256 exchangeRateInQuoteDecimals = changeDecimals(exchangeRateInBase, baseDecimals, quoteDecimals); + uint256 oneQuote = 10 ** quoteDecimals; + rateInQuote = oneQuote.mulDivDown((exchangeRateInQuoteDecimals), quoteRate); + } + + function changeDecimals(uint256 amount, uint256 fromDecimals, uint256 toDecimals) internal pure returns (uint256) { + if (fromDecimals == toDecimals) { + return amount; + } else if (fromDecimals < toDecimals) { + return amount * 10 ** (toDecimals - fromDecimals); + } else { + return amount / 10 ** (fromDecimals - toDecimals); + } + } + + /// @dev Helper function to perform 10**x + function e(uint256 decimals) internal pure returns (uint256) { + return (10 ** decimals); + } +} diff --git a/test/TellerWithMultiAssetSupport.t.sol b/test/TellerWithMultiAssetSupport.t.sol index 6de8c91..5ee783e 100644 --- a/test/TellerWithMultiAssetSupport.t.sol +++ b/test/TellerWithMultiAssetSupport.t.sol @@ -39,6 +39,7 @@ contract TellerWithMultiAssetSupportTest is Test, MainnetAddresses { AtomicSolverV3 public atomicSolverV3; address public solver = vm.addr(54); + uint256 ONE_SHARE; function setUp() external { // Setup forked environment. @@ -47,6 +48,7 @@ contract TellerWithMultiAssetSupportTest is Test, MainnetAddresses { _startFork(rpcKey, blockNumber); boringVault = new BoringVault(address(this), "Boring Vault", "BV", 18); + ONE_SHARE = 10 ** boringVault.decimals(); accountant = new AccountantWithRateProviders( address(this), address(boringVault), payout_address, 1e18, address(WETH), 1.001e4, 0.999e4, 1, 0 diff --git a/test/ion/oracles/EthPerTokenRateProvider.t.sol b/test/ion/oracles/EthPerTokenRateProvider.t.sol index aaf6c71..3a0140d 100644 --- a/test/ion/oracles/EthPerTokenRateProvider.t.sol +++ b/test/ion/oracles/EthPerTokenRateProvider.t.sol @@ -8,7 +8,8 @@ import { ETH_PER_EZETH_CHAINLINK, ETH_PER_RSETH_CHAINLINK, ETH_PER_RSWETH_CHAINLINK, - ETH_PER_PUFETH_REDSTONE + ETH_PER_PUFETH_REDSTONE, + ETH_PER_APXETH_REDSTONE } from "./../../../src/helper/Constants.sol"; import { Test } from "@forge-std/Test.sol"; @@ -194,3 +195,30 @@ contract PufEthRateProviderTest is EthPerTokenRateProviderTest { ); } } + +contract ApxEthRateProviderTest is EthPerTokenRateProviderTest { + function setUp() public override { + super.setUp(); + + _setExpectedPriceRange(0.99e18, 1.2e18); + + ethPerTokenRateProvider = new EthPerTokenRateProvider( + "apxETH/ETH", + ETH_PER_APXETH_REDSTONE, + MAX_TIME_FROM_LAST_UPDATE, + 18, + EthPerTokenRateProvider.PriceFeedType.REDSTONE + ); + } + + function test_Revert_IncorrectDescription() public override { + vm.expectRevert(EthPerTokenRateProvider.InvalidDescription.selector); + ethPerTokenRateProvider = new EthPerTokenRateProvider( + incorrectDescription, + ETH_PER_APXETH_REDSTONE, + MAX_TIME_FROM_LAST_UPDATE, + 18, + EthPerTokenRateProvider.PriceFeedType.REDSTONE + ); + } +} diff --git a/test/ion/oracles/GenericRateProvider.t.sol b/test/ion/oracles/GenericRateProvider.t.sol index d40c3e1..0ddb4a0 100644 --- a/test/ion/oracles/GenericRateProvider.t.sol +++ b/test/ion/oracles/GenericRateProvider.t.sol @@ -22,18 +22,18 @@ abstract contract GenericRateProviderTest is Test { _initialize(); - require(address(rateProvider) != address(0), "rate provider not set"); - require(decimals > 0, "decimals not set"); - require(target != address(0), "target not set"); - require(bytes4(selector).length > 0, "selector not set"); + assertNotEq(address(rateProvider), address(0), "rate provider not set"); + assertGt(decimals, 0, "decimals not set"); + assertNotEq(target, address(0), "target not set"); + assertGt(bytes4(selector).length, 0, "selector not set"); } function test_GetRateWithinExpectedBounds() public { uint256 rate = rateProvider.getRate(); (uint256 min, uint256 max) = _expectedRateMinMax(); - require(rate >= min, "rate must be greater than or equal to min"); - require(rate <= max, "rate must be less than or equal to max"); + assertGe(rate, min, "rate must be greater than or equal to min"); + assertLe(rate, max, "rate must be less than or equal to max"); } function _initialize() public virtual;