From b4189236b71e7122b551bba6cdce71105b626dfb Mon Sep 17 00:00:00 2001 From: Carson Date: Mon, 19 Aug 2024 16:15:11 -0400 Subject: [PATCH 01/29] feat: added helper script for send1weicrosschain --- script/ConfigReader.s.sol | 3 +- script/Send1WeiAccrossChain.s.sol | 79 +++++++++++++++++++ ...LayerZeroTellerWithMultiAssetSupport.s.sol | 3 +- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 script/Send1WeiAccrossChain.s.sol diff --git a/script/ConfigReader.s.sol b/script/ConfigReader.s.sol index d8fda41..f86f4d0 100644 --- a/script/ConfigReader.s.sol +++ b/script/ConfigReader.s.sol @@ -85,7 +85,8 @@ library ConfigReader { config.assets = _config.readAddressArray(".teller.assets"); config.peerEid = uint32(_config.readUint(".teller.peerEid")); config.dvnIfNoDefault = _config.readAddress(".teller.dvnIfNoDefault"); - config.dvnBlockConfirmationsRequiredIfNoDefault = uint64(_config.readUint(".teller.dvnBlockConfirmationsRequiredIfNoDefault")); + config.dvnBlockConfirmationsRequiredIfNoDefault = + uint64(_config.readUint(".teller.dvnBlockConfirmationsRequiredIfNoDefault")); // Reading from the 'rolesAuthority' section config.rolesAuthority = _config.readAddress(".rolesAuthority.address"); diff --git a/script/Send1WeiAccrossChain.s.sol b/script/Send1WeiAccrossChain.s.sol new file mode 100644 index 0000000..82a1e26 --- /dev/null +++ b/script/Send1WeiAccrossChain.s.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.21; + +import { MainnetAddresses } from "test/resources/MainnetAddresses.sol"; +import { BoringVault } from "src/base/BoringVault.sol"; +import { ManagerWithMerkleVerification } from "src/base/Roles/ManagerWithMerkleVerification.sol"; +import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol"; +import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol"; +import { ERC20 } from "@solmate/tokens/ERC20.sol"; +import { BalancerVault } from "src/interfaces/BalancerVault.sol"; +import { EtherFiLiquidDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol"; +import { RolesAuthority, Authority } from "@solmate/auth/authorities/RolesAuthority.sol"; +import { TellerWithMultiAssetSupport } from "src/base/Roles/TellerWithMultiAssetSupport.sol"; +import { MultiChainLayerZeroTellerWithMultiAssetSupport } from "src/base/Roles/CrossChain/MultiChainLayerZeroTellerWithMultiAssetSupport.sol"; +import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRateProviders.sol"; +import { CrossChainTellerBase } from "src/base/Roles/CrossChain/CrossChainTellerBase.sol"; +import { BridgeData } from "src/base/Roles/CrossChain/CrossChainTellerBase.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 "@forge-std/Script.sol"; +import "@forge-std/StdJson.sol"; +import { console2 } from "forge-std/console2.sol"; +import { Test, stdStorage, StdStorage, stdError, console } from "@forge-std/Test.sol"; + +interface IWETH { + function deposit(uint256) external payable; + function approve(address, uint256) external; +} + +/** + * source .env && forge script script/DeployTestBoringVault.s.sol:DeployTestBoringVaultScript --with-gas-price + * 30000000000 --slow --broadcast --etherscan-api-key $ETHERSCAN_KEY --verify + * @dev Optionally can change --with-gas-price to something more reasonable + */ +contract TestScript is Script { + uint256 public privateKey; + address broadcaster; + + CrossChainTellerBase teller; + + function setUp() external { + privateKey = vm.envUint("PRIVATE_KEY"); + broadcaster = vm.addr(privateKey); + } + + function run() external { + vm.startBroadcast(privateKey); + + ERC20 NATIVE = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); + ERC20 WETH = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); + // ERC20 WETH = ERC20(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000); + address BORING_VAULT = 0x52E4d8989fa8b3E1C06696e7b16DEf5d7707A0d1; + address TELLER = 0xB52C7d88F0514796877B04cF945E56cC4C66CD05; + + teller = CrossChainTellerBase(TELLER); + + require(teller.isSupported(WETH), "asset not supported"); + + // WETH.approve(BORING_VAULT, 1 ether); + // IWETH(address(WETH)).deposit{value: 0.0001 ether}(0.0001 ether); + + // teller.deposit(WETH, 1000000000, 1000000000); + BridgeData memory data = BridgeData({ + chainSelector: 30280, + destinationChainReceiver: broadcaster, + bridgeFeeToken: NATIVE, + messageGas: 100_000, + data: "" + }); + + uint256 fee = teller.previewFee(1000000000, data); + + teller.depositAndBridge{value:fee}(WETH, 1, 1, data); + + // boring_vault = new BoringVault(owner, "Test Boring Vault", "BV", 18); + + // manager = new ManagerWithMerkleVerification(owner, address(boring_vault), balancerVault); + } +} \ No newline at end of file diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index 519b25f..bbbc83c 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -99,7 +99,8 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { requiredDVNs[0] = config.dvnIfNoDefault; - bytes memory ulnConfigBytes = abi.encode(UlnConfig(config.dvnBlockConfirmationsRequiredIfNoDefault, 1, 0, 0, requiredDVNs, optionalDVNs)); + bytes memory ulnConfigBytes = + abi.encode(UlnConfig(config.dvnBlockConfirmationsRequiredIfNoDefault, 1, 0, 0, requiredDVNs, optionalDVNs)); SetConfigParam[] memory setConfigParams = new SetConfigParam[](1); setConfigParams[0] = SetConfigParam(config.peerEid, 2, ulnConfigBytes); From ec3859159639140d0da01dc5a56c42d08da7162c Mon Sep 17 00:00:00 2001 From: Carson Date: Mon, 19 Aug 2024 16:51:53 -0400 Subject: [PATCH 02/29] fix: proompt for use of default --- deployment-config/mydeploy.json | 8 +++-- script/Base.s.sol | 4 +++ script/ConfigReader.s.sol | 14 +++++--- script/Send1WeiAccrossChain.s.sol | 13 +++---- script/deploy/deployAll.s.sol | 4 --- ...LayerZeroTellerWithMultiAssetSupport.s.sol | 35 +++++++++++-------- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/deployment-config/mydeploy.json b/deployment-config/mydeploy.json index febcc01..8b31319 100644 --- a/deployment-config/mydeploy.json +++ b/deployment-config/mydeploy.json @@ -32,13 +32,17 @@ "maxGasForPeer": 100000, "minGasForPeer": 0, "peerEid": 0, - "dvnIfNoDefault": "0x589dEDbD617e0CBcB916A9223F4d1300c294236b", - "dvnBlockConfirmationsRequiredIfNoDefault": 15, "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", "assets": [ "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110" ], + "dvnIfNoDefault":{ + "required":["0x589dEDbD617e0CBcB916A9223F4d1300c294236b"], + "optional":[], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, "address": "0x00000000004F96C07B83e86600D86F0000000000" }, diff --git a/script/Base.s.sol b/script/Base.s.sol index aab67ba..6470942 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -86,4 +86,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 f86f4d0..b8018e0 100644 --- a/script/ConfigReader.s.sol +++ b/script/ConfigReader.s.sol @@ -28,8 +28,10 @@ library ConfigReader { address balancerVault; bytes32 tellerSalt; uint32 peerEid; - address dvnIfNoDefault; - uint64 dvnBlockConfirmationsRequiredIfNoDefault; + address[] requiredDnvs; + address[] optionalDvns; + uint64 dvnBlockConfirmationsRequired; + uint8 optionalDvnThreshold; address accountant; address opMessenger; uint64 maxGasForPeer; @@ -84,9 +86,11 @@ library ConfigReader { config.tellerContractName = _config.readString(".teller.tellerContractName"); config.assets = _config.readAddressArray(".teller.assets"); config.peerEid = uint32(_config.readUint(".teller.peerEid")); - config.dvnIfNoDefault = _config.readAddress(".teller.dvnIfNoDefault"); - config.dvnBlockConfirmationsRequiredIfNoDefault = - uint64(_config.readUint(".teller.dvnBlockConfirmationsRequiredIfNoDefault")); + + config.requiredDnvs = _config.readAddressArray(".teller.dvnIfNoDefault.requiredDvns"); + config.optionalDvns = _config.readAddressArray(".teller.dvnIfNoDefault.optionalDvns"); + config.dvnBlockConfirmationsRequired = uint64(_config.readUint(".teller.dvnIfNoDefault.blockConfirmationsRequiredIfNoDefault")); + config.optionalDvnThreshold = uint8(_config.readUint(".teller.dvnIfNoDefault.optionalDvnThreshold")); // Reading from the 'rolesAuthority' section config.rolesAuthority = _config.readAddress(".rolesAuthority.address"); diff --git a/script/Send1WeiAccrossChain.s.sol b/script/Send1WeiAccrossChain.s.sol index 82a1e26..2248a2d 100644 --- a/script/Send1WeiAccrossChain.s.sol +++ b/script/Send1WeiAccrossChain.s.sol @@ -11,7 +11,8 @@ import { BalancerVault } from "src/interfaces/BalancerVault.sol"; import { EtherFiLiquidDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol"; import { RolesAuthority, Authority } from "@solmate/auth/authorities/RolesAuthority.sol"; import { TellerWithMultiAssetSupport } from "src/base/Roles/TellerWithMultiAssetSupport.sol"; -import { MultiChainLayerZeroTellerWithMultiAssetSupport } from "src/base/Roles/CrossChain/MultiChainLayerZeroTellerWithMultiAssetSupport.sol"; +import { MultiChainLayerZeroTellerWithMultiAssetSupport } from + "src/base/Roles/CrossChain/MultiChainLayerZeroTellerWithMultiAssetSupport.sol"; import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRateProviders.sol"; import { CrossChainTellerBase } from "src/base/Roles/CrossChain/CrossChainTellerBase.sol"; import { BridgeData } from "src/base/Roles/CrossChain/CrossChainTellerBase.sol"; @@ -51,7 +52,7 @@ contract TestScript is Script { // ERC20 WETH = ERC20(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000); address BORING_VAULT = 0x52E4d8989fa8b3E1C06696e7b16DEf5d7707A0d1; address TELLER = 0xB52C7d88F0514796877B04cF945E56cC4C66CD05; - + teller = CrossChainTellerBase(TELLER); require(teller.isSupported(WETH), "asset not supported"); @@ -61,19 +62,19 @@ contract TestScript is Script { // teller.deposit(WETH, 1000000000, 1000000000); BridgeData memory data = BridgeData({ - chainSelector: 30280, + chainSelector: 30_280, destinationChainReceiver: broadcaster, bridgeFeeToken: NATIVE, messageGas: 100_000, data: "" }); - uint256 fee = teller.previewFee(1000000000, data); + uint256 fee = teller.previewFee(1_000_000_000, data); - teller.depositAndBridge{value:fee}(WETH, 1, 1, data); + teller.depositAndBridge{ value: fee }(WETH, 1, 1, data); // boring_vault = new BoringVault(owner, "Test Boring Vault", "BV", 18); // manager = new ManagerWithMerkleVerification(owner, address(boring_vault), balancerVault); } -} \ No newline at end of file +} diff --git a/script/deploy/deployAll.s.sol b/script/deploy/deployAll.s.sol index d02c159..5699d49 100644 --- a/script/deploy/deployAll.s.sol +++ b/script/deploy/deployAll.s.sol @@ -94,8 +94,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/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index bbbc83c..e716e25 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -9,6 +9,7 @@ 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; @@ -63,7 +64,7 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { ); require(address(teller.endpoint()) == config.lzEndpoint, "OP Teller must have messenger set"); - // check if the DVN is configured and print a message to the screen to inform the deployer if not. + _checkUlnConfig(config); return address(teller); } @@ -73,34 +74,40 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { bytes memory configBytes = endpoint.getConfig(config.teller, 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; + isDead = true; } } + for (uint256 i; i < numRequiredDVN; ++i) { if (ulnConfig.optionalDVNs[i] == dead) { - _setConfig(endpoint, lib, config); + isDead = true; + } + } + + if(!isDead){ + string memory a = vm.prompt("There is a default configuration for this chain/peerEid combination. Would you like to use it? (y/n)"); + if(compareStrings(a,"y")){ + console2.log("using default config"); return; + }else{ + console2.log("setting LayerZero ULN config using provided in config file"); + _setConfig(endpoint, lib, config); } } - } + } 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; bytes memory ulnConfigBytes = - abi.encode(UlnConfig(config.dvnBlockConfirmationsRequiredIfNoDefault, 1, 0, 0, requiredDVNs, optionalDVNs)); + abi.encode(UlnConfig(config.dvnBlockConfirmationsRequired, uint8(config.requiredDnvs.length), uint8(config.optionalDvns.length), config.optionalDvnThreshold, config.requiredDnvs, config.optionalDvns)); SetConfigParam[] memory setConfigParams = new SetConfigParam[](1); setConfigParams[0] = SetConfigParam(config.peerEid, 2, ulnConfigBytes); From 38820a6fecba3b637712c8f9ccf006132cdf12be Mon Sep 17 00:00:00 2001 From: Carson Date: Tue, 20 Aug 2024 14:50:34 -0400 Subject: [PATCH 03/29] fix: leftPaddedBytes32 for peer with check --- deployment-config/mydeploy.json | 9 +- script/ConfigReader.s.sol | 11 +- ...LayerZeroTellerWithMultiAssetSupport.s.sol | 103 ++++++++++++++---- 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/deployment-config/mydeploy.json b/deployment-config/mydeploy.json index 8b31319..cc7ba15 100644 --- a/deployment-config/mydeploy.json +++ b/deployment-config/mydeploy.json @@ -31,7 +31,7 @@ "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000a", "maxGasForPeer": 100000, "minGasForPeer": 0, - "peerEid": 0, + "peerEid": 30280, "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", "assets": [ "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", @@ -39,7 +39,12 @@ ], "dvnIfNoDefault":{ "required":["0x589dEDbD617e0CBcB916A9223F4d1300c294236b"], - "optional":[], + "optional":[ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], "blockConfirmationsRequiredIfNoDefault": 15, "optionalThreshold": 1 }, diff --git a/script/ConfigReader.s.sol b/script/ConfigReader.s.sol index b8018e0..acc11f6 100644 --- a/script/ConfigReader.s.sol +++ b/script/ConfigReader.s.sol @@ -28,7 +28,7 @@ library ConfigReader { address balancerVault; bytes32 tellerSalt; uint32 peerEid; - address[] requiredDnvs; + address[] requiredDvns; address[] optionalDvns; uint64 dvnBlockConfirmationsRequired; uint8 optionalDvnThreshold; @@ -87,10 +87,11 @@ library ConfigReader { config.assets = _config.readAddressArray(".teller.assets"); config.peerEid = uint32(_config.readUint(".teller.peerEid")); - config.requiredDnvs = _config.readAddressArray(".teller.dvnIfNoDefault.requiredDvns"); - config.optionalDvns = _config.readAddressArray(".teller.dvnIfNoDefault.optionalDvns"); - config.dvnBlockConfirmationsRequired = uint64(_config.readUint(".teller.dvnIfNoDefault.blockConfirmationsRequiredIfNoDefault")); - config.optionalDvnThreshold = uint8(_config.readUint(".teller.dvnIfNoDefault.optionalDvnThreshold")); + 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/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index e716e25..c111977 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -52,8 +52,15 @@ 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"); @@ -62,20 +69,35 @@ 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, "OP Teller must have messenger 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(config, sendLib); + _checkUlnConfig(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); - _checkUlnConfig(config); return address(teller); } - function _checkUlnConfig(ConfigReader.Config memory config) internal { + function _checkUlnConfig(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); UlnConfig memory ulnConfig = abi.decode(configBytes, (UlnConfig)); - - uint8 numRequiredDVN = ulnConfig.requiredDVNCount; uint8 numOptionalDVN = ulnConfig.optionalDVNCount; bool isDead; @@ -86,31 +108,72 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { } } - for (uint256 i; i < numRequiredDVN; ++i) { + for (uint256 i; i < numOptionalDVN; ++i) { if (ulnConfig.optionalDVNs[i] == dead) { isDead = true; } } - if(!isDead){ - string memory a = vm.prompt("There is a default configuration for this chain/peerEid combination. Would you like to use it? (y/n)"); - if(compareStrings(a,"y")){ - console2.log("using default config"); - return; - }else{ - console2.log("setting LayerZero ULN config using provided in config file"); + // 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(endpoint, lib, config); } + }else{ + console2.log("No default configuration for this chain/peerEid combination. Using params provided in config file"); + _setConfig(endpoint, lib,config); } - } - function _setConfig(ILayerZeroEndpointV2 endpoint, address lib, ConfigReader.Config memory config) internal { + } - bytes memory ulnConfigBytes = - abi.encode(UlnConfig(config.dvnBlockConfirmationsRequired, uint8(config.requiredDnvs.length), uint8(config.optionalDvns.length), config.optionalDvnThreshold, config.requiredDnvs, config.optionalDvns)); + function _setConfig(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); } -} + + function sortAddresses(address[] memory addresses) internal pure returns (address[] memory) { + uint length = addresses.length; + if(length < 2){return addresses;} + + for (uint i; i < length - 1; ++i) { + for (uint 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; + } + +} \ No newline at end of file From 5898682bb0ee20b8230fc734a6ff984df9147039 Mon Sep 17 00:00:00 2001 From: Carson Date: Tue, 20 Aug 2024 15:25:27 -0400 Subject: [PATCH 04/29] refactor: dead address constant --- script/Send1WeiAccrossChain.s.sol | 17 ++++---- ...LayerZeroTellerWithMultiAssetSupport.s.sol | 42 +++++++++++-------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/script/Send1WeiAccrossChain.s.sol b/script/Send1WeiAccrossChain.s.sol index 2248a2d..401bb95 100644 --- a/script/Send1WeiAccrossChain.s.sol +++ b/script/Send1WeiAccrossChain.s.sol @@ -24,7 +24,7 @@ import { console2 } from "forge-std/console2.sol"; import { Test, stdStorage, StdStorage, stdError, console } from "@forge-std/Test.sol"; interface IWETH { - function deposit(uint256) external payable; + function deposit() external payable; function approve(address, uint256) external; } @@ -48,9 +48,10 @@ contract TestScript is Script { vm.startBroadcast(privateKey); ERC20 NATIVE = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); - ERC20 WETH = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); + ERC20 WETH = ERC20(0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8); + // ERC20 WETH = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // ERC20 WETH = ERC20(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000); - address BORING_VAULT = 0x52E4d8989fa8b3E1C06696e7b16DEf5d7707A0d1; + address BORING_VAULT = 0x9fAaEA2CDd810b21594E54309DC847842Ae301Ce; address TELLER = 0xB52C7d88F0514796877B04cF945E56cC4C66CD05; teller = CrossChainTellerBase(TELLER); @@ -58,21 +59,21 @@ contract TestScript is Script { require(teller.isSupported(WETH), "asset not supported"); // WETH.approve(BORING_VAULT, 1 ether); - // IWETH(address(WETH)).deposit{value: 0.0001 ether}(0.0001 ether); + // IWETH(address(WETH)).deposit{value: 1}; // teller.deposit(WETH, 1000000000, 1000000000); BridgeData memory data = BridgeData({ - chainSelector: 30_280, + chainSelector: 30101, destinationChainReceiver: broadcaster, bridgeFeeToken: NATIVE, messageGas: 100_000, data: "" }); - uint256 fee = teller.previewFee(1_000_000_000, data); - - teller.depositAndBridge{ value: fee }(WETH, 1, 1, data); + uint256 fee = teller.previewFee(1, data); + // teller.depositAndBridge{ value: fee }(WETH, 1, 1, data); + teller.bridge{value: fee}(1, data); // boring_vault = new BoringVault(owner, "Test Boring Vault", "BV", 18); // manager = new ManagerWithMerkleVerification(owner, address(boring_vault), balancerVault); diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index c111977..681d16c 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -14,7 +14,7 @@ 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; @@ -55,8 +55,12 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { 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"); + // 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); @@ -76,13 +80,14 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { 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(config, sendLib); _checkUlnConfig(config, receiveLib); // confirm the library is set sendLib = endpoint.getSendLibrary(config.teller, config.peerEid); - (receiveLib, ) = endpoint.getReceiveLibrary(config.teller, config.peerEid); + (receiveLib,) = endpoint.getReceiveLibrary(config.teller, config.peerEid); require(sendLib != address(0), "No sendLib"); require(receiveLib != address(0), "no receiveLib"); @@ -103,18 +108,19 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { bool isDead; for (uint256 i; i < numRequiredDVN; ++i) { - if (ulnConfig.requiredDVNs[i] == dead) { + if (ulnConfig.requiredDVNs[i] == DEAD) { isDead = true; } } for (uint256 i; i < numOptionalDVN; ++i) { - if (ulnConfig.optionalDVNs[i] == dead) { + if (ulnConfig.optionalDVNs[i] == DEAD) { isDead = true; } } - // if no dead address in the ulnConfig, prompt for use of default onchain config, otherwise just use what's in config file + // 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)" @@ -125,11 +131,12 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { console2.log("setting LayerZero ULN config using params provided in config file"); _setConfig(endpoint, lib, config); } - }else{ - console2.log("No default configuration for this chain/peerEid combination. Using params provided in config file"); - _setConfig(endpoint, lib,config); + } else { + console2.log( + "No default configuration for this chain/peerEid combination. Using params provided in config file" + ); + _setConfig(endpoint, lib, config); } - } function _setConfig(ILayerZeroEndpointV2 endpoint, address lib, ConfigReader.Config memory config) internal { @@ -157,11 +164,11 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { } function sortAddresses(address[] memory addresses) internal pure returns (address[] memory) { - uint length = addresses.length; - if(length < 2){return addresses;} + uint256 length = addresses.length; + if (length < 2) return addresses; - for (uint i; i < length - 1; ++i) { - for (uint j; j < length - i - 1; ++j) { + 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]; @@ -172,8 +179,7 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { return addresses; } - function addressToBytes32LeftPad(address addr) internal returns(bytes32 leftPadBytes32){ + function addressToBytes32LeftPad(address addr) internal returns (bytes32 leftPadBytes32) { leftPadBytes32 = bytes32(bytes20(addr)) >> 0x60; } - -} \ No newline at end of file +} From 41dabdb05aaee1fd570daf6b1df06f6a7a1f948a Mon Sep 17 00:00:00 2001 From: Carson Date: Wed, 21 Aug 2024 15:26:36 -0400 Subject: [PATCH 05/29] feat: new lzConfigCheck.cjs file --- .../{mydeploy.json => exampleL1.json} | 0 deployment-config/exampleL2.json | 67 ++ .../layerzero/dvn-deployments.json | 725 ++++++++++++++++++ lzConfigCheck.cjs | 126 +++ lzConfigCheck.py | 97 +++ script/Send1WeiAccrossChain.s.sol | 13 +- ...LayerZeroTellerWithMultiAssetSupport.s.sol | 2 +- 7 files changed, 1023 insertions(+), 7 deletions(-) rename deployment-config/{mydeploy.json => exampleL1.json} (100%) create mode 100644 deployment-config/exampleL2.json create mode 100644 deployment-config/layerzero/dvn-deployments.json create mode 100644 lzConfigCheck.cjs create mode 100644 lzConfigCheck.py diff --git a/deployment-config/mydeploy.json b/deployment-config/exampleL1.json similarity index 100% rename from deployment-config/mydeploy.json rename to deployment-config/exampleL1.json diff --git a/deployment-config/exampleL2.json b/deployment-config/exampleL2.json new file mode 100644 index 0000000..ee14c1c --- /dev/null +++ b/deployment-config/exampleL2.json @@ -0,0 +1,67 @@ +{ + "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", + + "boringVault":{ + "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", + "boringVaultName": "Ion Vault L2", + "boringVaultSymbol": "IVT", + + "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + }, + + "manager":{ + "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000a", + + "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" + }, + + "accountant":{ + "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000a", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "2000", + + "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" + }, + + "teller": { + "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000a", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 30280, + "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", + "assets": [ + ], + "dvnIfNoDefault":{ + "required":["0x6788f52439aca6bff597d3eec2dc9a44b8fee842"], + "optional":[ + "0x1feb08b1a53a9710afce82d380b8c2833c69a37e", + "0x87048402c32632b7c4d0a892d82bc1160e8b2393", + "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "0xbd00c87850416db0995ef8030b104f875e1bdd15" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 + }, + + "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000a", + "strategist": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", + "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", + + "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000a", + + "address": "0x00000000004F96C07B83e86600D86F0000000000" + } + +} \ No newline at end of file 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/lzConfigCheck.cjs b/lzConfigCheck.cjs new file mode 100644 index 0000000..45911fe --- /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 havea 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/lzConfigCheck.py b/lzConfigCheck.py new file mode 100644 index 0000000..984f29d --- /dev/null +++ b/lzConfigCheck.py @@ -0,0 +1,97 @@ +import json + +def load_dvns(): + # Load the JSON data from the dvns file + with open('./deployment-config/layerzero/dvn-deployments.json', 'r') as file: + dvn_json_data = json.load(file) + return dvn_json_data + +def find_address_in_json(addresses, json_data, searchKey=""): + results = [] + + for parent_key, parent_value in json_data.items(): + for key, value in parent_value.items(): + addresses = [a.lower() for a in addresses] + if value.lower() in addresses: + results.append((parent_key, key, value)) + + if searchKey == "": + if len(results) == 1: + parent_key, key, value = results[0] + return True, key, parent_key + else: + return False, None, None + else: + for result in results: + parent_key, key, value = result + if key == searchKey: + return True, key, parent_key + + return False, None, None + +def get_findings_in_config(config_name): + dvn_json_data = load_dvns() + + with open("./deployment-config/"+config_name, 'r') as file: + config_json_data = json.load(file) + + # Example addresses to search for + required = config_json_data['teller']['dvnIfNoDefault']['required'] + optional = config_json_data['teller']['dvnIfNoDefault']['optional'] + addresses = required + optional + + # first use find_address_in_json to find the chain + chain = "" + for address in addresses: + found, key, parent_key = find_address_in_json([address], dvn_json_data) + if found: + chain = key + break + + if chain == "": + raise Exception("All provided configs have duplicates or are not found in the DVN registry") + + # second create a findings array + findings = [] + + for address in addresses: + found, key, parent_key = find_address_in_json([address], dvn_json_data, chain) + if found: + findings.append({'address': address, 'chain': key, 'provider': parent_key}) + else: + print("Not Found ",address) + + return {'findings': findings, 'requiredCount': len(required), 'optionalCount': len(optional), 'confirmations': config_json_data['teller']['dvnIfNoDefault']['blockConfirmationsRequiredIfNoDefault'], 'threshold': config_json_data['teller']['dvnIfNoDefault']['optionalThreshold']} + + +def main(): + file1Name = input("enter the name of the first config deployment file in deployment-config/ (ex. exampleL1.json):\n") + file2Name = input("enter the name of the first config deployment file in deployment-config/ (ex. exampleL2.json):\n") + # file1Name = "exampleL1.json" + # file2Name = "exampleL2.json" + + findings1 = get_findings_in_config(file1Name) + + findings2 = get_findings_in_config(file2Name) + + assert(findings1['confirmations'] == findings2['confirmations']) + assert(findings1['threshold'] == findings2['threshold']) + assert(findings1['requiredCount'] == findings2['requiredCount']) + assert(findings1['optionalCount'] == findings2['optionalCount']) + + chain1 = findings1['findings'][0]['chain'] + providers1 = [] + for finding in findings1['findings']: + providers1.append(finding['provider']) + assert(finding['chain'] == chain1) + + chain2 = findings2['findings'][0]['chain'] + for finding in findings2['findings']: + assert(finding['provider'] in providers1) + assert(finding['chain'] == chain2) + + print("✅ Config check passed") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/script/Send1WeiAccrossChain.s.sol b/script/Send1WeiAccrossChain.s.sol index 401bb95..ed27022 100644 --- a/script/Send1WeiAccrossChain.s.sol +++ b/script/Send1WeiAccrossChain.s.sol @@ -48,22 +48,23 @@ contract TestScript is Script { vm.startBroadcast(privateKey); ERC20 NATIVE = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); - ERC20 WETH = ERC20(0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8); + ERC20 WETH = ERC20(0xFC00000000000000000000000000000000000006); // ERC20 WETH = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // ERC20 WETH = ERC20(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000); - address BORING_VAULT = 0x9fAaEA2CDd810b21594E54309DC847842Ae301Ce; - address TELLER = 0xB52C7d88F0514796877B04cF945E56cC4C66CD05; + address BORING_VAULT = 0x647Ea8b492832e9D99A06DE8cc9A05e58FcCdF02; + address TELLER = 0xD9395622c8Ec792D1cb6F39B562095fDa240BA57; teller = CrossChainTellerBase(TELLER); require(teller.isSupported(WETH), "asset not supported"); // WETH.approve(BORING_VAULT, 1 ether); - // IWETH(address(WETH)).deposit{value: 1}; + // payable(address(WETH)).call{value: 1}(""); + // require(WETH.balanceOf(broadcaster) > 1, "No WETH"); // teller.deposit(WETH, 1000000000, 1000000000); BridgeData memory data = BridgeData({ - chainSelector: 30101, + chainSelector: 30_101, destinationChainReceiver: broadcaster, bridgeFeeToken: NATIVE, messageGas: 100_000, @@ -73,7 +74,7 @@ contract TestScript is Script { uint256 fee = teller.previewFee(1, data); // teller.depositAndBridge{ value: fee }(WETH, 1, 1, data); - teller.bridge{value: fee}(1, data); + teller.bridge{ value: fee }(1, data); // boring_vault = new BoringVault(owner, "Test Boring Vault", "BV", 18); // manager = new ManagerWithMerkleVerification(owner, address(boring_vault), balancerVault); diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index 681d16c..f7a64d8 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -80,7 +80,7 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { 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(config, sendLib); _checkUlnConfig(config, receiveLib); From d08740b24f692227a5b364a271cde84f9638d136 Mon Sep 17 00:00:00 2001 From: Carson Date: Wed, 21 Aug 2024 15:29:03 -0400 Subject: [PATCH 06/29] refactor: cleanup and added script to package.json --- lzConfigCheck.py | 97 ------------------------------------------------ package.json | 3 +- 2 files changed, 2 insertions(+), 98 deletions(-) delete mode 100644 lzConfigCheck.py diff --git a/lzConfigCheck.py b/lzConfigCheck.py deleted file mode 100644 index 984f29d..0000000 --- a/lzConfigCheck.py +++ /dev/null @@ -1,97 +0,0 @@ -import json - -def load_dvns(): - # Load the JSON data from the dvns file - with open('./deployment-config/layerzero/dvn-deployments.json', 'r') as file: - dvn_json_data = json.load(file) - return dvn_json_data - -def find_address_in_json(addresses, json_data, searchKey=""): - results = [] - - for parent_key, parent_value in json_data.items(): - for key, value in parent_value.items(): - addresses = [a.lower() for a in addresses] - if value.lower() in addresses: - results.append((parent_key, key, value)) - - if searchKey == "": - if len(results) == 1: - parent_key, key, value = results[0] - return True, key, parent_key - else: - return False, None, None - else: - for result in results: - parent_key, key, value = result - if key == searchKey: - return True, key, parent_key - - return False, None, None - -def get_findings_in_config(config_name): - dvn_json_data = load_dvns() - - with open("./deployment-config/"+config_name, 'r') as file: - config_json_data = json.load(file) - - # Example addresses to search for - required = config_json_data['teller']['dvnIfNoDefault']['required'] - optional = config_json_data['teller']['dvnIfNoDefault']['optional'] - addresses = required + optional - - # first use find_address_in_json to find the chain - chain = "" - for address in addresses: - found, key, parent_key = find_address_in_json([address], dvn_json_data) - if found: - chain = key - break - - if chain == "": - raise Exception("All provided configs have duplicates or are not found in the DVN registry") - - # second create a findings array - findings = [] - - for address in addresses: - found, key, parent_key = find_address_in_json([address], dvn_json_data, chain) - if found: - findings.append({'address': address, 'chain': key, 'provider': parent_key}) - else: - print("Not Found ",address) - - return {'findings': findings, 'requiredCount': len(required), 'optionalCount': len(optional), 'confirmations': config_json_data['teller']['dvnIfNoDefault']['blockConfirmationsRequiredIfNoDefault'], 'threshold': config_json_data['teller']['dvnIfNoDefault']['optionalThreshold']} - - -def main(): - file1Name = input("enter the name of the first config deployment file in deployment-config/ (ex. exampleL1.json):\n") - file2Name = input("enter the name of the first config deployment file in deployment-config/ (ex. exampleL2.json):\n") - # file1Name = "exampleL1.json" - # file2Name = "exampleL2.json" - - findings1 = get_findings_in_config(file1Name) - - findings2 = get_findings_in_config(file2Name) - - assert(findings1['confirmations'] == findings2['confirmations']) - assert(findings1['threshold'] == findings2['threshold']) - assert(findings1['requiredCount'] == findings2['requiredCount']) - assert(findings1['optionalCount'] == findings2['optionalCount']) - - chain1 = findings1['findings'][0]['chain'] - providers1 = [] - for finding in findings1['findings']: - providers1.append(finding['provider']) - assert(finding['chain'] == chain1) - - chain2 = findings2['findings'][0]['chain'] - for finding in findings2['findings']: - assert(finding['provider'] in providers1) - assert(finding['chain'] == chain2) - - print("✅ Config check passed") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/package.json b/package.json index 5438095..f6f8aaa 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "deploy-createx-l1": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L1_RPC_URL --private-key $PRIVATE_KEY --slow", "deploy-createx-l2": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --slow", "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" + "deploy-l2": "forge script script/deploy/deployAll.s.sol -f $L2_RPC_URL --private-key=$PRIVATE_KEY --slow", + "check-configs": "bun lzConfigCheck.cjs" }, "devDependencies": { "@layerzerolabs/lz-definitions": "^2.3.25", From dcc199ef7e7f357e5c6024aa01c800cfdf41f26f Mon Sep 17 00:00:00 2001 From: Jun Kim <64379343+junkim012@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:27:41 +0900 Subject: [PATCH 07/29] fix: do not hardcode boring vault decimals --- deployment-config/boba-eth-l1-08-09-24.json | 2 +- deployment-config/boba-eth-l2-08-09-24.json | 2 +- deployment-config/fraxtal-eth-l1-08-13-24.json | 2 +- deployment-config/fraxtal-eth-l2-08-13-24.json | 2 +- deployment-config/sei-eth-l1-08-08-24.json | 2 +- deployment-config/sei-eth-l2-08-08-24.json | 2 +- .../{rswBTC-l1.json => swell-btc-l1-08-22-24.json} | 14 +++++++------- script/ConfigReader.s.sol | 4 ++-- script/deploy/single/02_DeployBoringVault.s.sol | 7 +++++-- .../04_DeployAccountantWithRateProviders.s.sol | 4 ++-- 10 files changed, 22 insertions(+), 19 deletions(-) rename deployment-config/{rswBTC-l1.json => swell-btc-l1-08-22-24.json} (87%) 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/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/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/script/ConfigReader.s.sol b/script/ConfigReader.s.sol index 2cdb0e7..efe99cd 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; @@ -58,7 +58,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"); 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 From 9ccf8e99c77adf10e7d190f95433e0c0dbf78239 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 22 Aug 2024 11:27:45 -0400 Subject: [PATCH 08/29] refactor: nucleus vault and removed convinence script --- deployment-config/exampleL1.json | 4 +- deployment-config/exampleL2.json | 4 +- script/Send1WeiAccrossChain.s.sol | 82 ------------------------------- 3 files changed, 4 insertions(+), 86 deletions(-) delete mode 100644 script/Send1WeiAccrossChain.s.sol diff --git a/deployment-config/exampleL1.json b/deployment-config/exampleL1.json index cc7ba15..c9cd7c5 100644 --- a/deployment-config/exampleL1.json +++ b/deployment-config/exampleL1.json @@ -3,8 +3,8 @@ "boringVault":{ "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", - "boringVaultName": "Ion Vault", - "boringVaultSymbol": "IVT", + "boringVaultName": "Nucleus Vault", + "boringVaultSymbol": "NV", "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" }, diff --git a/deployment-config/exampleL2.json b/deployment-config/exampleL2.json index ee14c1c..1730f3f 100644 --- a/deployment-config/exampleL2.json +++ b/deployment-config/exampleL2.json @@ -3,8 +3,8 @@ "boringVault":{ "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", - "boringVaultName": "Ion Vault L2", - "boringVaultSymbol": "IVT", + "boringVaultName": "Nucleus Vault", + "boringVaultSymbol": "NV", "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" }, diff --git a/script/Send1WeiAccrossChain.s.sol b/script/Send1WeiAccrossChain.s.sol deleted file mode 100644 index ed27022..0000000 --- a/script/Send1WeiAccrossChain.s.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.21; - -import { MainnetAddresses } from "test/resources/MainnetAddresses.sol"; -import { BoringVault } from "src/base/BoringVault.sol"; -import { ManagerWithMerkleVerification } from "src/base/Roles/ManagerWithMerkleVerification.sol"; -import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol"; -import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol"; -import { ERC20 } from "@solmate/tokens/ERC20.sol"; -import { BalancerVault } from "src/interfaces/BalancerVault.sol"; -import { EtherFiLiquidDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/EtherFiLiquidDecoderAndSanitizer.sol"; -import { RolesAuthority, Authority } from "@solmate/auth/authorities/RolesAuthority.sol"; -import { TellerWithMultiAssetSupport } from "src/base/Roles/TellerWithMultiAssetSupport.sol"; -import { MultiChainLayerZeroTellerWithMultiAssetSupport } from - "src/base/Roles/CrossChain/MultiChainLayerZeroTellerWithMultiAssetSupport.sol"; -import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRateProviders.sol"; -import { CrossChainTellerBase } from "src/base/Roles/CrossChain/CrossChainTellerBase.sol"; -import { BridgeData } from "src/base/Roles/CrossChain/CrossChainTellerBase.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 "@forge-std/Script.sol"; -import "@forge-std/StdJson.sol"; -import { console2 } from "forge-std/console2.sol"; -import { Test, stdStorage, StdStorage, stdError, console } from "@forge-std/Test.sol"; - -interface IWETH { - function deposit() external payable; - function approve(address, uint256) external; -} - -/** - * source .env && forge script script/DeployTestBoringVault.s.sol:DeployTestBoringVaultScript --with-gas-price - * 30000000000 --slow --broadcast --etherscan-api-key $ETHERSCAN_KEY --verify - * @dev Optionally can change --with-gas-price to something more reasonable - */ -contract TestScript is Script { - uint256 public privateKey; - address broadcaster; - - CrossChainTellerBase teller; - - function setUp() external { - privateKey = vm.envUint("PRIVATE_KEY"); - broadcaster = vm.addr(privateKey); - } - - function run() external { - vm.startBroadcast(privateKey); - - ERC20 NATIVE = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); - ERC20 WETH = ERC20(0xFC00000000000000000000000000000000000006); - // ERC20 WETH = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); - // ERC20 WETH = ERC20(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000); - address BORING_VAULT = 0x647Ea8b492832e9D99A06DE8cc9A05e58FcCdF02; - address TELLER = 0xD9395622c8Ec792D1cb6F39B562095fDa240BA57; - - teller = CrossChainTellerBase(TELLER); - - require(teller.isSupported(WETH), "asset not supported"); - - // WETH.approve(BORING_VAULT, 1 ether); - // payable(address(WETH)).call{value: 1}(""); - // require(WETH.balanceOf(broadcaster) > 1, "No WETH"); - - // teller.deposit(WETH, 1000000000, 1000000000); - BridgeData memory data = BridgeData({ - chainSelector: 30_101, - destinationChainReceiver: broadcaster, - bridgeFeeToken: NATIVE, - messageGas: 100_000, - data: "" - }); - - uint256 fee = teller.previewFee(1, data); - - // teller.depositAndBridge{ value: fee }(WETH, 1, 1, data); - teller.bridge{ value: fee }(1, data); - // boring_vault = new BoringVault(owner, "Test Boring Vault", "BV", 18); - - // manager = new ManagerWithMerkleVerification(owner, address(boring_vault), balancerVault); - } -} From 75486a13d93acb68eb7c9eb38a2db3ebfff274bd Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 22 Aug 2024 12:30:12 -0400 Subject: [PATCH 09/29] feat: incrementSalt.cjs --- deployment-config/exampleL1.json | 121 ++++++++++++++----------------- deployment-config/exampleL2.json | 116 +++++++++++++---------------- incrementSalt.cjs | 46 ++++++++++++ 3 files changed, 153 insertions(+), 130 deletions(-) create mode 100644 incrementSalt.cjs diff --git a/deployment-config/exampleL1.json b/deployment-config/exampleL1.json index c9cd7c5..0f02959 100644 --- a/deployment-config/exampleL1.json +++ b/deployment-config/exampleL1.json @@ -1,69 +1,58 @@ { - "protocolAdmin": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", - - "boringVault":{ - "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", - "boringVaultName": "Nucleus Vault", - "boringVaultSymbol": "NV", - - "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + "protocolAdmin": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000e", + "boringVaultName": "Nucleus Vault", + "boringVaultSymbol": "NV", + "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000e", + "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000e", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "2000", + "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000e", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 30280, + "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", + "assets": [ + "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", + "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110" + ], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" + ], + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 }, - - "manager":{ - "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000a", - - "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" - }, - - "accountant":{ - "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000a", - "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", - "allowedExchangeRateChangeUpper": "10003", - "allowedExchangeRateChangeLower": "9998", - "minimumUpdateDelayInSeconds": "3600", - "managementFee": "2000", - - "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" - }, - - "teller": { - "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000a", - "maxGasForPeer": 100000, - "minGasForPeer": 0, - "peerEid": 30280, - "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", - "assets": [ - "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", - "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110" - ], - "dvnIfNoDefault":{ - "required":["0x589dEDbD617e0CBcB916A9223F4d1300c294236b"], - "optional":[ - "0x380275805876Ff19055EA900CDb2B46a94ecF20D", - "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", - "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", - "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" - ], - "blockConfirmationsRequiredIfNoDefault": 15, - "optionalThreshold": 1 - }, - - "address": "0x00000000004F96C07B83e86600D86F0000000000" - }, - - "rolesAuthority": { - "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000a", - "strategist": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", - "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", - - "address": "0x00000000004F96C07B83e86600D86F0000000000" - }, - - "decoder": { - "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000a", - - "address": "0x00000000004F96C07B83e86600D86F0000000000" - } - + "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/exampleL2.json b/deployment-config/exampleL2.json index 1730f3f..cc8ba58 100644 --- a/deployment-config/exampleL2.json +++ b/deployment-config/exampleL2.json @@ -1,67 +1,55 @@ { - "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", - - "boringVault":{ - "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", - "boringVaultName": "Nucleus Vault", - "boringVaultSymbol": "NV", - - "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000e", + "boringVaultName": "Nucleus Vault", + "boringVaultSymbol": "NV", + "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000e", + "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000e", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "2000", + "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000e", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 30280, + "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", + "assets": [], + "dvnIfNoDefault": { + "required": [ + "0x6788f52439aca6bff597d3eec2dc9a44b8fee842" + ], + "optional": [ + "0x1feb08b1a53a9710afce82d380b8c2833c69a37e", + "0x87048402c32632b7c4d0a892d82bc1160e8b2393", + "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", + "0xbd00c87850416db0995ef8030b104f875e1bdd15" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 }, - - "manager":{ - "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000a", - - "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" - }, - - "accountant":{ - "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000a", - "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", - "allowedExchangeRateChangeUpper": "10003", - "allowedExchangeRateChangeLower": "9998", - "minimumUpdateDelayInSeconds": "3600", - "managementFee": "2000", - - "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" - }, - - "teller": { - "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000a", - "maxGasForPeer": 100000, - "minGasForPeer": 0, - "peerEid": 30280, - "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", - "assets": [ - ], - "dvnIfNoDefault":{ - "required":["0x6788f52439aca6bff597d3eec2dc9a44b8fee842"], - "optional":[ - "0x1feb08b1a53a9710afce82d380b8c2833c69a37e", - "0x87048402c32632b7c4d0a892d82bc1160e8b2393", - "0xd24972c11f91c1bb9eaee97ec96bb9c33cf7af24", - "0xbd00c87850416db0995ef8030b104f875e1bdd15" - ], - "blockConfirmationsRequiredIfNoDefault": 15, - "optionalThreshold": 1 - }, - - "address": "0x00000000004F96C07B83e86600D86F0000000000" - }, - - "rolesAuthority": { - "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000a", - "strategist": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", - "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", - - "address": "0x00000000004F96C07B83e86600D86F0000000000" - }, - - "decoder": { - "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000a", - - "address": "0x00000000004F96C07B83e86600D86F0000000000" - } - + "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/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 From 730e53d3a2ef1cdab774dcf781e2f3452339f106 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 22 Aug 2024 12:51:37 -0400 Subject: [PATCH 10/29] feat: optional --sig run(string memory) configFile deployment script call --- script/deploy/deployAll.s.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/script/deploy/deployAll.s.sol b/script/deploy/deployAll.s.sol index 5699d49..b4711e2 100644 --- a/script/deploy/deployAll.s.sol +++ b/script/deploy/deployAll.s.sol @@ -56,6 +56,10 @@ contract DeployAll is BaseScript { 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) { address boringVault = new DeployIonBoringVaultScript().deploy(config); config.boringVault = boringVault; From 5d9f961461c8aa524a4854ee1a05992a6be6724c Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 22 Aug 2024 13:11:23 -0400 Subject: [PATCH 11/29] removed old live tests --- ...ssChainOPTellerWithMultiAssetSupport.t.sol | 51 ----- ...LayerZeroTellerWithMultiAssetSupport.t.sol | 185 ------------------ 2 files changed, 236 deletions(-) delete mode 100644 test/CrossChain/live/LIVECrossChainOPTellerWithMultiAssetSupport.t.sol delete mode 100644 test/CrossChain/live/LIVEMultiChainLayerZeroTellerWithMultiAssetSupport.t.sol 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); - } -} From 8eddf81b9d32d66e3cbeebc7e83fe77d00d25409 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 22 Aug 2024 15:11:29 -0400 Subject: [PATCH 12/29] fix: bug in deployment script --- ...ainLayerZeroTellerWithMultiAssetSupport.s.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index f7a64d8..f5d92f4 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -82,8 +82,8 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { require(receiveLib != address(0), "receiveLib = 0, check peerEid"); // check if a default config exists for these libraries and if not set the config - _checkUlnConfig(config, sendLib); - _checkUlnConfig(config, receiveLib); + _checkUlnConfig(address(teller), config, sendLib); + _checkUlnConfig(address(teller), config, receiveLib); // confirm the library is set sendLib = endpoint.getSendLibrary(config.teller, config.peerEid); @@ -97,10 +97,10 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { return address(teller); } - function _checkUlnConfig(ConfigReader.Config memory config, address lib) internal { + function _checkUlnConfig(address newTeller, ConfigReader.Config memory config, address lib) internal { ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(config.lzEndpoint); - 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)); uint8 numRequiredDVN = ulnConfig.requiredDVNCount; @@ -129,17 +129,17 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { console2.log("using default onchain config"); } else { console2.log("setting LayerZero ULN config using params provided in config file"); - _setConfig(endpoint, lib, config); + _setConfig(newTeller, endpoint, lib, config); } } else { console2.log( "No default configuration for this chain/peerEid combination. Using params provided in config file" ); - _setConfig(endpoint, lib, config); + _setConfig(newTeller, endpoint, lib, config); } } - function _setConfig(ILayerZeroEndpointV2 endpoint, address lib, ConfigReader.Config memory config) internal { + 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"); @@ -160,7 +160,7 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { 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) { From 29b9d21b02de599f565fe07cd710418449dadf88 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 22 Aug 2024 15:14:19 -0400 Subject: [PATCH 13/29] refactor: fmt --- ...yMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index f5d92f4..e73de6f 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -139,7 +139,14 @@ contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { } } - function _setConfig(address newTeller, ILayerZeroEndpointV2 endpoint, address lib, ConfigReader.Config memory config) internal { + 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"); From 4bcbf6ae9ba450d0cde23cf92f50f3751b3379f8 Mon Sep 17 00:00:00 2001 From: Carson Date: Fri, 23 Aug 2024 14:09:42 -0400 Subject: [PATCH 14/29] test: beginings of live tests. Passing --- script/Base.s.sol | 1 + script/deploy/deployAll.s.sol | 2 + test/LiveDeploy.t.sol | 77 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 test/LiveDeploy.t.sol diff --git a/script/Base.s.sol b/script/Base.s.sol index 6470942..c832210 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -56,6 +56,7 @@ abstract contract BaseScript is Script { // if this chain doesn't have a CREATEX deployment, deploy it ourselves if (address(CREATEX).code.length == 0) { + console.log("Current Chain ID: ", block.chainid); revert("CREATEX Not Deployed on this chain. Use the DeployCustomCreatex script to deploy it"); } } diff --git a/script/deploy/deployAll.s.sol b/script/deploy/deployAll.s.sol index b4711e2..95a171b 100644 --- a/script/deploy/deployAll.s.sol +++ b/script/deploy/deployAll.s.sol @@ -87,6 +87,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) { diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol new file mode 100644 index 0000000..78652c1 --- /dev/null +++ b/test/LiveDeploy.t.sol @@ -0,0 +1,77 @@ +// 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"; + +// We use this so that we can use the inheritance linearization to start the fork before other constructors +abstract contract ForkTest is Test { + constructor() { + _startFork("MAINNET_RPC_URL"); + } + + function _startFork(string memory rpcKey) internal virtual returns (uint256 forkId) { + forkId = vm.createFork(vm.envString(rpcKey)); + vm.selectFork(forkId); + } +} + +contract LiveDeploy is ForkTest, DeployAll { + using FixedPointMathLib for uint256; + + uint256 ONE_SHARE; + + function setUp() public virtual { + // we have to start the fork again... I don't exactly know why + _startFork("MAINNET_RPC_URL"); + + // Setup forked environment. + run("exampleL1.json"); + + ONE_SHARE = 10 ** BoringVault(payable(mainConfig.boringVault)).decimals(); + } + + 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" + ); + } + + function testDepositASupportedAsset(uint256 depositAmount, uint256 indexOfSupported) public { + uint256 assetsCount = mainConfig.assets.length; + indexOfSupported = bound(indexOfSupported, 0, assetsCount); + depositAmount = bound(depositAmount, 1, 10_000e18); + + uint256 expected_shares; + AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); + + for (uint256 i; i < assetsCount; ++i) { + expected_shares += + depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i]))); + _depositAssetWithApprove(ERC20(mainConfig.assets[i]), depositAmount); + } + + BoringVault boringVault = BoringVault(payable(mainConfig.boringVault)); + assertEq(boringVault.balanceOf(address(this)), expected_shares, "Should have received expected shares"); + } + + function _depositAssetWithApprove(ERC20 asset, uint256 depositAmount) internal { + deal(address(asset), address(this), depositAmount); + asset.approve(mainConfig.boringVault, depositAmount); + TellerWithMultiAssetSupport(mainConfig.teller).deposit(asset, depositAmount, depositAmount); + } +} From 9bec8406278a5a321b25daa87e3ef7569bddc116 Mon Sep 17 00:00:00 2001 From: Carson Date: Fri, 23 Aug 2024 16:56:14 -0400 Subject: [PATCH 15/29] test: included bulk withdrawal in test --- test/LiveDeploy.t.sol | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index 78652c1..e85956e 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -10,6 +10,7 @@ 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"; // We use this so that we can use the inheritance linearization to start the fork before other constructors abstract contract ForkTest is Test { @@ -27,6 +28,7 @@ contract LiveDeploy is ForkTest, DeployAll { using FixedPointMathLib for uint256; uint256 ONE_SHARE; + uint8 constant SOLVER_ROLE = 42; function setUp() public virtual { // we have to start the fork again... I don't exactly know why @@ -36,6 +38,13 @@ contract LiveDeploy is ForkTest, DeployAll { run("exampleL1.json"); 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 testDepositBaseAsset(uint256 depositAmount) public { @@ -49,6 +58,10 @@ contract LiveDeploy is ForkTest, DeployAll { 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 testDepositASupportedAsset(uint256 depositAmount, uint256 indexOfSupported) public { @@ -56,17 +69,26 @@ contract LiveDeploy is ForkTest, DeployAll { indexOfSupported = bound(indexOfSupported, 0, assetsCount); depositAmount = bound(depositAmount, 1, 10_000e18); - uint256 expected_shares; + uint256 expecteShares; AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); - + uint[] memory expectedSharesByAsset = new uint[](assetsCount); for (uint256 i; i < assetsCount; ++i) { - expected_shares += + 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)), expected_shares, "Should have received expected shares"); + 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 _depositAssetWithApprove(ERC20 asset, uint256 depositAmount) internal { From 7cf84b05c825836bbaed014cc05b48d3a0d760ea Mon Sep 17 00:00:00 2001 From: Carson Date: Mon, 26 Aug 2024 13:03:31 -0400 Subject: [PATCH 16/29] test: passing test for rate change --- test/LiveDeploy.t.sol | 92 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 15 deletions(-) diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index e85956e..dab323d 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -12,10 +12,13 @@ import { TellerWithMultiAssetSupport } from "src/base/Roles/TellerWithMultiAsset import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRateProviders.sol"; import { RolesAuthority } from "@solmate/auth/authorities/RolesAuthority.sol"; +string constant RPC_URL_ENV = "MAINNET_RPC_URL"; +string constant FILE_NAME = "exampleL1.json"; + // We use this so that we can use the inheritance linearization to start the fork before other constructors abstract contract ForkTest is Test { constructor() { - _startFork("MAINNET_RPC_URL"); + _startFork(RPC_URL_ENV); } function _startFork(string memory rpcKey) internal virtual returns (uint256 forkId) { @@ -31,22 +34,69 @@ contract LiveDeploy is ForkTest, DeployAll { uint8 constant SOLVER_ROLE = 42; function setUp() public virtual { - // we have to start the fork again... I don't exactly know why - _startFork("MAINNET_RPC_URL"); + // 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(RPC_URL_ENV); - // Setup forked environment. - run("exampleL1.json"); + // Run the deployment scripts + run(FILE_NAME); + // 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); + rolesAuthority.setRoleCapability( + SOLVER_ROLE, mainConfig.teller, TellerWithMultiAssetSupport.bulkWithdraw.selector, true + ); vm.stopPrank(); } + function testDepositBaseAssetAndUpdateRate(uint256 depositAmount, uint96 rateChange) public { + 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; + + // mint a bunch of extra tokens to the vault for if rate increased + deal(mainConfig.base, mainConfig.boringVault, depositAmount); + + 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" + ); + + // update the rate + vm.startPrank(mainConfig.exchangeRateBot); + uint96 newRate = uint96(accountant.getRate()) * rateChange / 10_000; + accountant.updateExchangeRate(newRate); + vm.stopPrank(); + + 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 testDepositBaseAsset(uint256 depositAmount) public { depositAmount = bound(depositAmount, 1, 10_000e18); _depositAssetWithApprove(ERC20(mainConfig.base), depositAmount); @@ -60,8 +110,14 @@ contract LiveDeploy is ForkTest, DeployAll { ); // 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"); + 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 testDepositASupportedAsset(uint256 depositAmount, uint256 indexOfSupported) public { @@ -71,12 +127,12 @@ contract LiveDeploy is ForkTest, DeployAll { uint256 expecteShares; AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); - uint[] memory expectedSharesByAsset = new uint[](assetsCount); + uint256[] memory expectedSharesByAsset = new uint256[](assetsCount); for (uint256 i; i < assetsCount; ++i) { - expectedSharesByAsset[i] = + expectedSharesByAsset[i] = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i]))); expecteShares += expectedSharesByAsset[i]; - + _depositAssetWithApprove(ERC20(mainConfig.assets[i]), depositAmount); } @@ -84,11 +140,17 @@ contract LiveDeploy is ForkTest, DeployAll { 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"); + 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 _depositAssetWithApprove(ERC20 asset, uint256 depositAmount) internal { From dba7e367e61d7c4e178fb962734c36e05327c582 Mon Sep 17 00:00:00 2001 From: Carson Date: Tue, 27 Aug 2024 11:06:14 -0400 Subject: [PATCH 17/29] test: including rate change for non-base assets --- deployment-config/chains/liveDeploy.json | 1 + deployment-config/exampleL1.json | 6 ++ deployment-config/exampleL2.json | 6 ++ script/deploy/01_DeployRateProviders.s.sol | 15 +++- test/LiveDeploy.t.sol | 79 +++++++++++++++++++++- 5 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 deployment-config/chains/liveDeploy.json diff --git a/deployment-config/chains/liveDeploy.json b/deployment-config/chains/liveDeploy.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/deployment-config/chains/liveDeploy.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/deployment-config/exampleL1.json b/deployment-config/exampleL1.json index 0f02959..0b320c3 100644 --- a/deployment-config/exampleL1.json +++ b/deployment-config/exampleL1.json @@ -54,5 +54,11 @@ "decoder": { "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + "rateProvider": { + "maxTimeFromLastUpdate": "86400", + "rateProviderSalt": "0x0000000000000000000000000000000000000000000000000000000000000000", + + "address": "0x0000000000000000000000000000000000000000" } } \ No newline at end of file diff --git a/deployment-config/exampleL2.json b/deployment-config/exampleL2.json index cc8ba58..795f69c 100644 --- a/deployment-config/exampleL2.json +++ b/deployment-config/exampleL2.json @@ -51,5 +51,11 @@ "decoder": { "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", "address": "0x00000000004F96C07B83e86600D86F0000000000" + }, + "rateProvider": { + "maxTimeFromLastUpdate": "86400", + "rateProviderSalt": "0x0000000000000000000000000000000000000000000000000000000000000000", + + "address": "0x0000000000000000000000000000000000000000" } } \ No newline at end of file diff --git a/script/deploy/01_DeployRateProviders.s.sol b/script/deploy/01_DeployRateProviders.s.sol index 987c1f3..6fcc332 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, bool ignoreExisting) public { + string memory path = string.concat(CONFIG_PATH_ROOT, configFileName); + string memory config = vm.readFile(path); + _run(fileName, config, ignoreExisting); + } + function run() public { string memory config = requestConfigFileFromUser(); + _run(Strings.toString(block.chainid), config, false); + } + + function _run(string memory fileName, string memory config, bool ignoreExisting) internal { string memory chainConfig = getChainConfigFile(); address[] memory assets = config.readAddressArray(".teller.assets"); @@ -29,7 +39,7 @@ contract DeployRateProviders is BaseScript { string(abi.encodePacked(".assetToRateProviderAndPriceFeed.", assets[i].toHexString(), ".rateProvider")); address rateProvider = chainConfig.readAddress(rateProviderKey); // must deploy new rate provider and set the value - if (rateProvider == address(0)) { + if (ignoreExisting || rateProvider == address(0)) { address priceFeed = chainConfig.readAddress( string(abi.encodePacked(".assetToRateProviderAndPriceFeed.", assets[i].toHexString(), ".priceFeed")) ); @@ -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/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index dab323d..ba7e9dc 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -11,6 +11,7 @@ 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"; string constant RPC_URL_ENV = "MAINNET_RPC_URL"; string constant FILE_NAME = "exampleL1.json"; @@ -37,7 +38,7 @@ contract LiveDeploy is ForkTest, DeployAll { // 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(RPC_URL_ENV); - + // (new DeployRateProviders()).run("liveDeploy", FILE_NAME, true); // Run the deployment scripts run(FILE_NAME); // warp forward the minimumUpdateDelay for the accountant to prevent it from pausing on update test @@ -120,6 +121,82 @@ contract LiveDeploy is ForkTest, DeployAll { ); } + uint256 constant DELTA = 10_000; + + 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 + vm.startPrank(mainConfig.exchangeRateBot); + uint96 newRate = uint96(accountant.getRate()) * rateChange / 10_000; + accountant.updateExchangeRate(newRate); + vm.stopPrank(); + + // withdrawal the assets for the same amount back + for (uint256 i; i < assetsCount; ++i) { + assertEq( + accountant.getRateInQuote(ERC20(mainConfig.assets[i])), + rateInQuoteBefore[i] * rateChange / 10_000, + "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 + ); + + // console.log("Deposit Amount: ",depositAmount); + // console.log("RateInQuoteBefore: ", rateInQuoteBefore[i]); + // console.log("RateInQuoteNow: ", accountant.getRateInQuote(ERC20(mainConfig.assets[i]))); + // console.log("AccountantRate: ", accountant.getRate()); + // console.log("Rate Change: ", rateChange); + // console.log("expectedAssetsBack: ", expectedAssetsBack); + + // sometimes passes... Sometimes doesn't... Rounding errors? + 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); From 1fa6eba305bee5811f3df1ccd63f47ba76620429 Mon Sep 17 00:00:00 2001 From: Carson Date: Tue, 27 Aug 2024 15:28:04 -0400 Subject: [PATCH 18/29] feat: makefile for checkL1 and checkL2 --- Makefile | 9 ++++++++ test/LiveDeploy.t.sol | 8 +++---- test/TellerWithMultiAssetSupport.t.sol | 32 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4bf4c2f --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +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} \ No newline at end of file diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index ba7e9dc..22a8ce3 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -13,8 +13,7 @@ import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRatePr import { RolesAuthority } from "@solmate/auth/authorities/RolesAuthority.sol"; import { DeployRateProviders } from "script/deploy/01_DeployRateProviders.s.sol"; -string constant RPC_URL_ENV = "MAINNET_RPC_URL"; -string constant FILE_NAME = "exampleL1.json"; +string constant RPC_URL_ENV = "USING_FORK_FLAG"; // We use this so that we can use the inheritance linearization to start the fork before other constructors abstract contract ForkTest is Test { @@ -23,8 +22,8 @@ abstract contract ForkTest is Test { } function _startFork(string memory rpcKey) internal virtual returns (uint256 forkId) { - forkId = vm.createFork(vm.envString(rpcKey)); - vm.selectFork(forkId); + // forkId = vm.createFork(vm.envString(rpcKey)); + // vm.selectFork(forkId); } } @@ -40,6 +39,7 @@ contract LiveDeploy is ForkTest, DeployAll { _startFork(RPC_URL_ENV); // (new DeployRateProviders()).run("liveDeploy", FILE_NAME, true); // Run the deployment scripts + string memory FILE_NAME = vm.envString("LIVE_DEPLOY_READ_FILE_NAME"); run(FILE_NAME); // warp forward the minimumUpdateDelay for the accountant to prevent it from pausing on update test vm.warp(block.timestamp + mainConfig.minimumUpdateDelayInSeconds); diff --git a/test/TellerWithMultiAssetSupport.t.sol b/test/TellerWithMultiAssetSupport.t.sol index 6de8c91..76b253a 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 @@ -108,6 +110,36 @@ contract TellerWithMultiAssetSupportTest is Test, MainnetAddresses { accountant.setRateProviderData(WEETH, false, address(WEETH_RATE_PROVIDER)); } + function testMath(uint depositAmount, uint rateChange) external{ + depositAmount = bound(depositAmount, 1, 1_000_000_000e18); + rateChange = bound(rateChange, 9998, 10002); + // make sure starting rate is not 1 + uint startRateWEETH = accountant.getRate(); + assertNotEq(startRateWEETH, 1, "Start Rate for WEETH is 0"); + + // get the expected assets back after rate change + uint256 expectedAssetsBack = ((depositAmount).mulDivDown(rateChange, 10_000)); + // get the shares back when depositing before rate change + uint depositShares = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(ERC20(WEETH))); + + // change the rate + uint96 newRate = uint96(accountant.getRate().mulDivDown(uint96(rateChange), 10_000)); + vm.warp(1 days + block.timestamp); + accountant.updateExchangeRate(newRate); + + // calculate the assets out at the new rate + uint256 assetsOut = depositShares.mulDivDown( + accountant.getRateInQuoteSafe(ERC20(WEETH)), (ONE_SHARE) + ); + + // print if the expected > out and assert they're the same + console.log("expectedAssetsBack > realAssetsOut: ", expectedAssetsBack > assetsOut); + console.log("expectedAssetsBack: ", expectedAssetsBack); + console.log("assetsOut: ", assetsOut); + assertTrue(expectedAssetsBack >= assetsOut, "BIG PROBLEM, not in protocol's favor"); + // assertApproxEqAbs(expectedAssetsBack, assetsOut, 1, "deposit * rateChange != depositAmount with getRateInQuoteSafe math"); + } + function testDepositReverting(uint256 amount) external { amount = bound(amount, 0.0001e18, 10_000e18); // Turn on share lock period, and deposit reverting From 906e20ea7dac299a71353a39e4506514228064f6 Mon Sep 17 00:00:00 2001 From: Carson Date: Wed, 28 Aug 2024 20:42:26 -0400 Subject: [PATCH 19/29] test: LiveDeploy complete, working on RateMath --- .../Roles/AccountantWithRateProviders.sol | 6 +- test/LiveDeploy.t.sol | 114 +++++++++++- test/RateMath.t.sol.working | 171 ++++++++++++++++++ test/TellerWithMultiAssetSupport.t.sol | 34 ++-- 4 files changed, 311 insertions(+), 14 deletions(-) create mode 100644 test/RateMath.t.sol.working diff --git a/src/base/Roles/AccountantWithRateProviders.sol b/src/base/Roles/AccountantWithRateProviders.sol index fb240c9..1bfcdc8 100644 --- a/src/base/Roles/AccountantWithRateProviders.sol +++ b/src/base/Roles/AccountantWithRateProviders.sol @@ -7,6 +7,7 @@ import { ERC20 } from "@solmate/tokens/ERC20.sol"; import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol"; import { BoringVault } from "src/base/BoringVault.sol"; import { Auth, Authority } from "@solmate/auth/Auth.sol"; +import { console } from "@forge-std/Test.sol"; /** * @title AccountantWithRateProviders @@ -356,7 +357,10 @@ contract AccountantWithRateProviders is Auth, IRateProvider { } else { uint256 quoteRate = data.rateProvider.getRate(); uint256 oneQuote = 10 ** quoteDecimals; - rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate); + rateInQuote = oneQuote.mulDivDown((exchangeRateInQuoteDecimals), quoteRate); + console.log("Quote Rate: ", quoteRate); + console.log("One Quote: ", oneQuote); + console.log("Exchange Rate In Quote Decimals: ", exchangeRateInQuoteDecimals); } } } diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index 22a8ce3..95a65fe 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -13,6 +13,14 @@ import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRatePr import { RolesAuthority } from "@solmate/auth/authorities/RolesAuthority.sol"; import { DeployRateProviders } from "script/deploy/01_DeployRateProviders.s.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 RPC_URL_ENV = "USING_FORK_FLAG"; // We use this so that we can use the inheritance linearization to start the fork before other constructors @@ -30,6 +38,7 @@ abstract contract ForkTest is Test { contract LiveDeploy is ForkTest, DeployAll { using FixedPointMathLib for uint256; + ERC20 constant NATIVE_ERC20 = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); uint256 ONE_SHARE; uint8 constant SOLVER_ROLE = 42; @@ -57,6 +66,15 @@ contract LiveDeploy is ForkTest, DeployAll { 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, uint96 rateChange) public { AccountantWithRateProviders accountant = AccountantWithRateProviders(mainConfig.accountant); // manual bounding done because bound() doesn't exist for uint96 @@ -159,9 +177,10 @@ contract LiveDeploy is ForkTest, DeployAll { // withdrawal the assets for the same amount back for (uint256 i; i < assetsCount; ++i) { - assertEq( + assertApproxEqAbs( accountant.getRateInQuote(ERC20(mainConfig.assets[i])), rateInQuoteBefore[i] * rateChange / 10_000, + 1, "Rate change did not apply to asset" ); @@ -235,4 +254,97 @@ contract LiveDeploy is ForkTest, DeployAll { asset.approve(mainConfig.boringVault, depositAmount); TellerWithMultiAssetSupport(mainConfig.teller).deposit(asset, depositAmount, depositAmount); } + + 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)); + + // vm.expectEmit(); + // emit CrossChainOPTellerWithMultiAssetSupportTest.SentMessageExtension1(address(sourceTeller), 0); + 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))); + } } diff --git a/test/RateMath.t.sol.working b/test/RateMath.t.sol.working new file mode 100644 index 0000000..4ac2bbd --- /dev/null +++ b/test/RateMath.t.sol.working @@ -0,0 +1,171 @@ +// 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 ONE_SHARE; + uint exchangeRateInBase; + uint baseDecimals; + uint quoteDecimals; + uint quoteRateDecimals; + uint quoteRate; + + function setUp() external { + // hard coded at 18 since in deploy script vault is set to 18 decimals, and this is set to that + ONE_SHARE = 1e18; + } + + function testAtomicDepositAndWithdraw_18Decimals(uint depositAmount, uint256 startQuoteRate, uint256 startExchangeRate) external{ + // set decimals + baseDecimals = 18; + quoteDecimals = 18; + quoteRateDecimals = 18; + + // bound values + depositAmount = bound(depositAmount, 1, 100_000_000e18); + quoteRate = bound(startQuoteRate, 1e18, 10_000e18); + exchangeRateInBase = bound(startExchangeRate, 8e17, 2e18); + + // get shares out if deposit done + uint shares = depositAssetForShares(depositAmount); + + // get assets back if all shares are withdrawn immediatelly + uint assetsBack = withdrawSharesForAssets(shares); + + assertFalse(assetsBack > depositAmount, "The assets back should not be > deposit amount when atomic"); + assertApproxEqAbs(assetsBack, depositAmount, 2, "assetsBack != depositAmount when atomic"); + } + + function testDepositAndWithdrawWithRateChange_18Decimals(uint depositAmount, uint256 startQuoteRate, uint256 startExchangeRate, uint256 rateChange) external{ + // set decimals + baseDecimals = 18; + quoteDecimals = 18; + quoteRateDecimals = 18; + + // bound values + depositAmount = bound(depositAmount, 1, 100_000_000e18); + quoteRate = bound(startQuoteRate, 1e18, 10_000e18); + exchangeRateInBase = bound(startExchangeRate, 8e17, 2e18); + rateChange = bound(rateChange, 9_980, 10_020); + + // get shares out if deposit done + uint shares = depositAssetForShares(depositAmount); + + // update the rate according to rate change + exchangeRateInBase = exchangeRateInBase.mulDivDown(rateChange, 10_000); + + // get assets back if all shares are withdrawn immediatelly + uint assetsBack = withdrawSharesForAssets(shares); + + if(assetsBack > depositAmount){ + console.log("Problem. assets back should not be > deposit amount"); + console.log("AssetsBack: ", assetsBack); + console.log("DepositAmount: ", depositAmount); + console.log("Difference: ", assetsBack - depositAmount); + } + assertFalse(assetsBack > depositAmount, "The assets back should not be > deposit amount"); + assertApproxEqAbs(assetsBack, depositAmount, 2, "assetsBack != depositAmount with rate change"); + } + + function testDepositAndWithdrawWithRateChange_18Decimals_Quote6(uint depositAmount, uint256 startQuoteRate, uint256 startExchangeRate, uint256 rateChange) external{ + // set decimals + baseDecimals = 18; + quoteDecimals = 6; + quoteRateDecimals = 18; + + // bound values + depositAmount = bound(depositAmount, 1, 100_000_000e6); + quoteRate = bound(startQuoteRate, 1e18, 10_000e18); + exchangeRateInBase = bound(startExchangeRate, 8e17, 2e18); + rateChange = bound(rateChange, 9_980, 10_020); + + // get shares out if deposit done + uint shares = depositAssetForShares(depositAmount); + + // update the rate according to rate change + exchangeRateInBase = exchangeRateInBase.mulDivDown(rateChange, 10_000); + + // get assets back if all shares are withdrawn immediatelly + uint assetsBack = withdrawSharesForAssets(shares); + + if(assetsBack > depositAmount){ + console.log("Problem. assets back should not be > deposit amount"); + console.log("AssetsBack: ", assetsBack); + console.log("DepositAmount: ", depositAmount); + console.log("Difference: ", assetsBack - depositAmount); + } + assertFalse(assetsBack > depositAmount, "The assets back should not be > deposit amount"); + //assertApproxEqAbs(assetsBack, depositAmount, 2, "assetsBack != depositAmount with rate change"); + } + + // function testMath(uint256 depositAmount, uint256 rateChange) external { + // depositAmount = bound(depositAmount, 1, 1_000_000_000e18); + // rateChange = bound(rateChange, 9998, 10_002); + // // get the expected assets back after rate change + // uint256 expectedAssetsBack = ((depositAmount).mulDivDown(rateChange, 10_000)); + + // // get the shares back when depositing before rate change + // uint accountantRateBefore = accountant.getRateInQuoteSafe(ERC20(WEETH)); + // assertNotEq(accountantRateBefore, 1e18, "accountantRateBefore for WEETH equal to 1"); + // uint256 depositShares = depositAmount.mulDivDown(ONE_SHARE, accountantRateBefore); + // console.log("Shares * Rate:\t\t", depositShares * ONE_SHARE); + // console.log("accountantRateBefore:\t\t", accountantRateBefore); + + // // todo- atomic + // // change the rate + // uint96 newRate = uint96(accountant.getRate().mulDivDown(uint96(rateChange), 10_000)); + // vm.warp(1 days + block.timestamp); + // accountant.updateExchangeRate(newRate); + + // // calculate the assets out at the new rate + // uint accountantRateAfter = accountant.getRateInQuoteSafe(ERC20(WEETH)); + // assertApproxEqAbs(accountantRateBefore.mulDivDown(rateChange, 10_000), accountantRateAfter, 1, "accountantRateBefore not equal to after with rate applied"); + // console.log("Shares * Rate:\t", depositShares * accountantRateAfter); + // console.log("one_share:\t\t", ONE_SHARE); + // uint256 assetsOut = depositShares.mulDivDown(accountantRateAfter, (ONE_SHARE)); + + // // print if the expected > out and assert they're the same + // console.log("expectedAssetsBack >= realAssetsOut: ", expectedAssetsBack >= assetsOut); + // console.log("expectedAssetsBack: ", expectedAssetsBack); + // console.log("assetsOut: ", assetsOut); + // // assertTrue(expectedAssetsBack >= assetsOut, "BIG PROBLEM, not in protocol's favor"); + // assertApproxEqAbs(expectedAssetsBack, assetsOut, 1, "deposit * rateChange != depositAmount with"); + // // getRateInQuoteSafe math"); + // } + + function withdrawSharesForAssets(uint shareAmount) public returns(uint assetsOut){ + assetsOut = shareAmount.mulDivDown(getRateInQuote(), ONE_SHARE); + } + + function depositAssetForShares(uint depositAmount) public returns(uint shares){ + if (depositAmount == 0) revert("depositAssetForShares amount = 0"); + shares = depositAmount.mulDivDown(ONE_SHARE, getRateInQuote()); + // if (shares < minimumMint) revert ("); + } + + function getRateInQuote() public view returns (uint256 rateInQuote) { + uint256 exchangeRateInQuoteDecimals = changeDecimals(exchangeRateInBase, baseDecimals, quoteDecimals); + + uint256 oneQuote = 10 ** quoteDecimals; + rateInQuote = oneQuote.mulDivDown((exchangeRateInQuoteDecimals), quoteRate); + // console.log("Quote Rate: ",quoteRate); + // console.log("One Quote: ", oneQuote); + // console.log("Exchange Rate In Quote Decimals: ", exchangeRateInQuoteDecimals); + } + + function changeDecimals(uint256 amount, uint fromDecimals, uint 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); + } + } + +} \ No newline at end of file diff --git a/test/TellerWithMultiAssetSupport.t.sol b/test/TellerWithMultiAssetSupport.t.sol index 76b253a..017dba8 100644 --- a/test/TellerWithMultiAssetSupport.t.sol +++ b/test/TellerWithMultiAssetSupport.t.sol @@ -110,34 +110,44 @@ contract TellerWithMultiAssetSupportTest is Test, MainnetAddresses { accountant.setRateProviderData(WEETH, false, address(WEETH_RATE_PROVIDER)); } - function testMath(uint depositAmount, uint rateChange) external{ + function testMath(uint256 depositAmount, uint256 rateChange) external { depositAmount = bound(depositAmount, 1, 1_000_000_000e18); - rateChange = bound(rateChange, 9998, 10002); - // make sure starting rate is not 1 - uint startRateWEETH = accountant.getRate(); - assertNotEq(startRateWEETH, 1, "Start Rate for WEETH is 0"); - + rateChange = bound(rateChange, 9998, 10_002); // get the expected assets back after rate change uint256 expectedAssetsBack = ((depositAmount).mulDivDown(rateChange, 10_000)); + // get the shares back when depositing before rate change - uint depositShares = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(ERC20(WEETH))); + uint256 accountantRateBefore = accountant.getRateInQuoteSafe(ERC20(WEETH)); + assertNotEq(accountantRateBefore, 1e18, "accountantRateBefore for WEETH equal to 1"); + uint256 depositShares = depositAmount.mulDivDown(ONE_SHARE, accountantRateBefore); + console.log("Shares * Rate:\t\t", depositShares * ONE_SHARE); + console.log("accountantRateBefore:\t\t", accountantRateBefore); + // todo- atomic // change the rate uint96 newRate = uint96(accountant.getRate().mulDivDown(uint96(rateChange), 10_000)); vm.warp(1 days + block.timestamp); accountant.updateExchangeRate(newRate); // calculate the assets out at the new rate - uint256 assetsOut = depositShares.mulDivDown( - accountant.getRateInQuoteSafe(ERC20(WEETH)), (ONE_SHARE) + uint256 accountantRateAfter = accountant.getRateInQuoteSafe(ERC20(WEETH)); + assertApproxEqAbs( + accountantRateBefore.mulDivDown(rateChange, 10_000), + accountantRateAfter, + 1, + "accountantRateBefore not equal to after with rate applied" ); + console.log("Shares * Rate:\t", depositShares * accountantRateAfter); + console.log("one_share:\t\t", ONE_SHARE); + uint256 assetsOut = depositShares.mulDivDown(accountantRateAfter, (ONE_SHARE)); // print if the expected > out and assert they're the same - console.log("expectedAssetsBack > realAssetsOut: ", expectedAssetsBack > assetsOut); + console.log("expectedAssetsBack >= realAssetsOut: ", expectedAssetsBack >= assetsOut); console.log("expectedAssetsBack: ", expectedAssetsBack); console.log("assetsOut: ", assetsOut); - assertTrue(expectedAssetsBack >= assetsOut, "BIG PROBLEM, not in protocol's favor"); - // assertApproxEqAbs(expectedAssetsBack, assetsOut, 1, "deposit * rateChange != depositAmount with getRateInQuoteSafe math"); + // assertTrue(expectedAssetsBack >= assetsOut, "BIG PROBLEM, not in protocol's favor"); + assertApproxEqAbs(expectedAssetsBack, assetsOut, 1, "deposit * rateChange != depositAmount with"); + // getRateInQuoteSafe math"); } function testDepositReverting(uint256 amount) external { From d6304bb952021498dc83f30d21bd5b4992d469bd Mon Sep 17 00:00:00 2001 From: Carson Date: Wed, 28 Aug 2024 20:52:39 -0400 Subject: [PATCH 20/29] fix: live test now works with default --- test/LiveDeploy.t.sol | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index 95a65fe..bf18474 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -21,17 +21,19 @@ import { CrossChainOPTellerWithMultiAssetSupport } from import { MultiChainLayerZeroTellerWithMultiAssetSupport } from "src/base/Roles/CrossChain/MultiChainLayerZeroTellerWithMultiAssetSupport.sol"; -string constant RPC_URL_ENV = "USING_FORK_FLAG"; +string constant DEFAULT_RPC_URL = "L1_RPC_URL"; // We use this so that we can use the inheritance linearization to start the fork before other constructors abstract contract ForkTest is Test { constructor() { - _startFork(RPC_URL_ENV); + _startFork(DEFAULT_RPC_URL); } function _startFork(string memory rpcKey) internal virtual returns (uint256 forkId) { - // forkId = vm.createFork(vm.envString(rpcKey)); - // vm.selectFork(forkId); + if (block.chainid == 31_337) { + forkId = vm.createFork(vm.envString(rpcKey)); + vm.selectFork(forkId); + } } } @@ -43,12 +45,19 @@ contract LiveDeploy is ForkTest, DeployAll { uint8 constant SOLVER_ROLE = 42; function setUp() public virtual { + string memory FILE_NAME; + if (block.chainid == 31_337) { + FILE_NAME = "exampleL1.json"; + } else { + FILE_NAME = vm.envString("LIVE_DEPLOY_READ_FILE_NAME"); + } + // 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(RPC_URL_ENV); + _startFork(DEFAULT_RPC_URL); // (new DeployRateProviders()).run("liveDeploy", FILE_NAME, true); // Run the deployment scripts - string memory FILE_NAME = vm.envString("LIVE_DEPLOY_READ_FILE_NAME"); + run(FILE_NAME); // warp forward the minimumUpdateDelay for the accountant to prevent it from pausing on update test vm.warp(block.timestamp + mainConfig.minimumUpdateDelayInSeconds); From 1dc11230df0eff3433cacedcafdca8229ebe52ab Mon Sep 17 00:00:00 2001 From: Carson Date: Wed, 28 Aug 2024 20:55:12 -0400 Subject: [PATCH 21/29] fix: removed testMath in teller test --- test/TellerWithMultiAssetSupport.t.sol | 40 -------------------------- 1 file changed, 40 deletions(-) diff --git a/test/TellerWithMultiAssetSupport.t.sol b/test/TellerWithMultiAssetSupport.t.sol index 017dba8..5ee783e 100644 --- a/test/TellerWithMultiAssetSupport.t.sol +++ b/test/TellerWithMultiAssetSupport.t.sol @@ -110,46 +110,6 @@ contract TellerWithMultiAssetSupportTest is Test, MainnetAddresses { accountant.setRateProviderData(WEETH, false, address(WEETH_RATE_PROVIDER)); } - function testMath(uint256 depositAmount, uint256 rateChange) external { - depositAmount = bound(depositAmount, 1, 1_000_000_000e18); - rateChange = bound(rateChange, 9998, 10_002); - // get the expected assets back after rate change - uint256 expectedAssetsBack = ((depositAmount).mulDivDown(rateChange, 10_000)); - - // get the shares back when depositing before rate change - uint256 accountantRateBefore = accountant.getRateInQuoteSafe(ERC20(WEETH)); - assertNotEq(accountantRateBefore, 1e18, "accountantRateBefore for WEETH equal to 1"); - uint256 depositShares = depositAmount.mulDivDown(ONE_SHARE, accountantRateBefore); - console.log("Shares * Rate:\t\t", depositShares * ONE_SHARE); - console.log("accountantRateBefore:\t\t", accountantRateBefore); - - // todo- atomic - // change the rate - uint96 newRate = uint96(accountant.getRate().mulDivDown(uint96(rateChange), 10_000)); - vm.warp(1 days + block.timestamp); - accountant.updateExchangeRate(newRate); - - // calculate the assets out at the new rate - uint256 accountantRateAfter = accountant.getRateInQuoteSafe(ERC20(WEETH)); - assertApproxEqAbs( - accountantRateBefore.mulDivDown(rateChange, 10_000), - accountantRateAfter, - 1, - "accountantRateBefore not equal to after with rate applied" - ); - console.log("Shares * Rate:\t", depositShares * accountantRateAfter); - console.log("one_share:\t\t", ONE_SHARE); - uint256 assetsOut = depositShares.mulDivDown(accountantRateAfter, (ONE_SHARE)); - - // print if the expected > out and assert they're the same - console.log("expectedAssetsBack >= realAssetsOut: ", expectedAssetsBack >= assetsOut); - console.log("expectedAssetsBack: ", expectedAssetsBack); - console.log("assetsOut: ", assetsOut); - // assertTrue(expectedAssetsBack >= assetsOut, "BIG PROBLEM, not in protocol's favor"); - assertApproxEqAbs(expectedAssetsBack, assetsOut, 1, "deposit * rateChange != depositAmount with"); - // getRateInQuoteSafe math"); - } - function testDepositReverting(uint256 amount) external { amount = bound(amount, 0.0001e18, 10_000e18); // Turn on share lock period, and deposit reverting From a33b2f862a8d2356877a44472d2b348e9e16f5d6 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 29 Aug 2024 14:14:03 -0400 Subject: [PATCH 22/29] test: refactoring tests according to PR comments --- deployment-config/chains/liveDeploy.json | 1 - deployment-config/exampleL1.json | 6 - deployment-config/exampleL2.json | 6 - script/ConfigReader.s.sol | 1 - script/deploy/deployAll.s.sol | 6 - .../Roles/AccountantWithRateProviders.sol | 4 - test/LiveDeploy.t.sol | 114 +++++++++++++----- 7 files changed, 83 insertions(+), 55 deletions(-) delete mode 100644 deployment-config/chains/liveDeploy.json diff --git a/deployment-config/chains/liveDeploy.json b/deployment-config/chains/liveDeploy.json deleted file mode 100644 index 9e26dfe..0000000 --- a/deployment-config/chains/liveDeploy.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/deployment-config/exampleL1.json b/deployment-config/exampleL1.json index 0b320c3..0f02959 100644 --- a/deployment-config/exampleL1.json +++ b/deployment-config/exampleL1.json @@ -54,11 +54,5 @@ "decoder": { "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", "address": "0x00000000004F96C07B83e86600D86F0000000000" - }, - "rateProvider": { - "maxTimeFromLastUpdate": "86400", - "rateProviderSalt": "0x0000000000000000000000000000000000000000000000000000000000000000", - - "address": "0x0000000000000000000000000000000000000000" } } \ No newline at end of file diff --git a/deployment-config/exampleL2.json b/deployment-config/exampleL2.json index 795f69c..cc8ba58 100644 --- a/deployment-config/exampleL2.json +++ b/deployment-config/exampleL2.json @@ -51,11 +51,5 @@ "decoder": { "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", "address": "0x00000000004F96C07B83e86600D86F0000000000" - }, - "rateProvider": { - "maxTimeFromLastUpdate": "86400", - "rateProviderSalt": "0x0000000000000000000000000000000000000000000000000000000000000000", - - "address": "0x0000000000000000000000000000000000000000" } } \ No newline at end of file diff --git a/script/ConfigReader.s.sol b/script/ConfigReader.s.sol index acc11f6..b1c4659 100644 --- a/script/ConfigReader.s.sol +++ b/script/ConfigReader.s.sol @@ -46,7 +46,6 @@ library ConfigReader { address rolesAuthority; bytes32 decoderSalt; address decoder; - address rateProvider; bytes32 rateProviderSalt; uint256 maxTimeFromLastUpdate; address[] assets; diff --git a/script/deploy/deployAll.s.sol b/script/deploy/deployAll.s.sol index 95a171b..8b7f687 100644 --- a/script/deploy/deployAll.s.sol +++ b/script/deploy/deployAll.s.sol @@ -50,12 +50,6 @@ 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())); } diff --git a/src/base/Roles/AccountantWithRateProviders.sol b/src/base/Roles/AccountantWithRateProviders.sol index 1bfcdc8..e7eef72 100644 --- a/src/base/Roles/AccountantWithRateProviders.sol +++ b/src/base/Roles/AccountantWithRateProviders.sol @@ -7,7 +7,6 @@ import { ERC20 } from "@solmate/tokens/ERC20.sol"; import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol"; import { BoringVault } from "src/base/BoringVault.sol"; import { Auth, Authority } from "@solmate/auth/Auth.sol"; -import { console } from "@forge-std/Test.sol"; /** * @title AccountantWithRateProviders @@ -358,9 +357,6 @@ contract AccountantWithRateProviders is Auth, IRateProvider { uint256 quoteRate = data.rateProvider.getRate(); uint256 oneQuote = 10 ** quoteDecimals; rateInQuote = oneQuote.mulDivDown((exchangeRateInQuoteDecimals), quoteRate); - console.log("Quote Rate: ", quoteRate); - console.log("One Quote: ", oneQuote); - console.log("Exchange Rate In Quote Decimals: ", exchangeRateInQuoteDecimals); } } } diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index bf18474..c8ff380 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -12,6 +12,8 @@ import { TellerWithMultiAssetSupport } from "src/base/Roles/TellerWithMultiAsset 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 } from "@forge-std/StdJson.sol"; import { CrossChainOPTellerWithMultiAssetSupportTest } from "test/CrossChain/CrossChainOPTellerWithMultiAssetSupport.t.sol"; @@ -26,6 +28,8 @@ string constant DEFAULT_RPC_URL = "L1_RPC_URL"; // 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); } @@ -38,6 +42,8 @@ abstract contract ForkTest is Test { } contract LiveDeploy is ForkTest, DeployAll { + using Strings for address; + using StdJson for string; using FixedPointMathLib for uint256; ERC20 constant NATIVE_ERC20 = ERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); @@ -46,19 +52,43 @@ contract LiveDeploy is ForkTest, DeployAll { 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"); } - // 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); - // (new DeployRateProviders()).run("liveDeploy", FILE_NAME, true); + // todo - include deploying rate providers IF not already deployed on this chain + // (new DeployRateProviders()).run("liveDeploy.json", FILE_NAME, true); + // 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); @@ -84,22 +114,22 @@ contract LiveDeploy is ForkTest, DeployAll { } else { } } - function testDepositBaseAssetAndUpdateRate(uint256 depositAmount, uint96 rateChange) public { + function testDepositBaseAssetAndUpdateRate(uint256 depositAmount, uint256 rateChange256) public { 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; + // 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); - 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, @@ -107,10 +137,7 @@ contract LiveDeploy is ForkTest, DeployAll { ); // update the rate - vm.startPrank(mainConfig.exchangeRateBot); - uint96 newRate = uint96(accountant.getRate()) * rateChange / 10_000; - accountant.updateExchangeRate(newRate); - vm.stopPrank(); + _updateRate(rateChange, accountant); uint256 expectedAssetsBack = depositAmount * rateChange / 10_000; @@ -125,6 +152,35 @@ contract LiveDeploy is ForkTest, DeployAll { ); } + 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); @@ -179,10 +235,7 @@ contract LiveDeploy is ForkTest, DeployAll { assertEq(boringVault.balanceOf(address(this)), expecteShares, "Should have received expected shares"); // update the rate - vm.startPrank(mainConfig.exchangeRateBot); - uint96 newRate = uint96(accountant.getRate()) * rateChange / 10_000; - accountant.updateExchangeRate(newRate); - vm.stopPrank(); + _updateRate(rateChange, accountant); // withdrawal the assets for the same amount back for (uint256 i; i < assetsCount; ++i) { @@ -202,14 +255,7 @@ contract LiveDeploy is ForkTest, DeployAll { accountant.getRateInQuoteSafe(ERC20(mainConfig.assets[i])), ONE_SHARE ); - // console.log("Deposit Amount: ",depositAmount); - // console.log("RateInQuoteBefore: ", rateInQuoteBefore[i]); - // console.log("RateInQuoteNow: ", accountant.getRateInQuote(ERC20(mainConfig.assets[i]))); - // console.log("AccountantRate: ", accountant.getRate()); - // console.log("Rate Change: ", rateChange); - // console.log("expectedAssetsBack: ", expectedAssetsBack); - - // sometimes passes... Sometimes doesn't... Rounding errors? + // Delta must be set very high to pass assertApproxEqAbs(assetsOut, expectedAssetsBack, DELTA, "assets out not equal to expected assets back"); TellerWithMultiAssetSupport(mainConfig.teller).bulkWithdraw( @@ -261,7 +307,7 @@ contract LiveDeploy is ForkTest, DeployAll { function _depositAssetWithApprove(ERC20 asset, uint256 depositAmount) internal { deal(address(asset), address(this), depositAmount); asset.approve(mainConfig.boringVault, depositAmount); - TellerWithMultiAssetSupport(mainConfig.teller).deposit(asset, depositAmount, depositAmount); + TellerWithMultiAssetSupport(mainConfig.teller).deposit(asset, depositAmount, 0); } function _testLZDepositAndBridge(ERC20 asset, uint256 amount) internal { @@ -344,8 +390,6 @@ contract LiveDeploy is ForkTest, DeployAll { uint256 wethBefore = asset.balanceOf(address(boringVault)); - // vm.expectEmit(); - // emit CrossChainOPTellerWithMultiAssetSupportTest.SentMessageExtension1(address(sourceTeller), 0); sourceTeller.depositAndBridge{ value: quote }(asset, amount, shares, data); assertEq(boringVault.balanceOf(user), 0, "Should have burned shares."); @@ -356,4 +400,12 @@ contract LiveDeploy is ForkTest, DeployAll { 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(); + } } From 6f1b314e786f1e1271c6380e89e24e09dfa97951 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 29 Aug 2024 14:15:26 -0400 Subject: [PATCH 23/29] chore: removed .working file and moved it to another branch --- test/RateMath.t.sol.working | 171 ------------------------------------ 1 file changed, 171 deletions(-) delete mode 100644 test/RateMath.t.sol.working diff --git a/test/RateMath.t.sol.working b/test/RateMath.t.sol.working deleted file mode 100644 index 4ac2bbd..0000000 --- a/test/RateMath.t.sol.working +++ /dev/null @@ -1,171 +0,0 @@ -// 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 ONE_SHARE; - uint exchangeRateInBase; - uint baseDecimals; - uint quoteDecimals; - uint quoteRateDecimals; - uint quoteRate; - - function setUp() external { - // hard coded at 18 since in deploy script vault is set to 18 decimals, and this is set to that - ONE_SHARE = 1e18; - } - - function testAtomicDepositAndWithdraw_18Decimals(uint depositAmount, uint256 startQuoteRate, uint256 startExchangeRate) external{ - // set decimals - baseDecimals = 18; - quoteDecimals = 18; - quoteRateDecimals = 18; - - // bound values - depositAmount = bound(depositAmount, 1, 100_000_000e18); - quoteRate = bound(startQuoteRate, 1e18, 10_000e18); - exchangeRateInBase = bound(startExchangeRate, 8e17, 2e18); - - // get shares out if deposit done - uint shares = depositAssetForShares(depositAmount); - - // get assets back if all shares are withdrawn immediatelly - uint assetsBack = withdrawSharesForAssets(shares); - - assertFalse(assetsBack > depositAmount, "The assets back should not be > deposit amount when atomic"); - assertApproxEqAbs(assetsBack, depositAmount, 2, "assetsBack != depositAmount when atomic"); - } - - function testDepositAndWithdrawWithRateChange_18Decimals(uint depositAmount, uint256 startQuoteRate, uint256 startExchangeRate, uint256 rateChange) external{ - // set decimals - baseDecimals = 18; - quoteDecimals = 18; - quoteRateDecimals = 18; - - // bound values - depositAmount = bound(depositAmount, 1, 100_000_000e18); - quoteRate = bound(startQuoteRate, 1e18, 10_000e18); - exchangeRateInBase = bound(startExchangeRate, 8e17, 2e18); - rateChange = bound(rateChange, 9_980, 10_020); - - // get shares out if deposit done - uint shares = depositAssetForShares(depositAmount); - - // update the rate according to rate change - exchangeRateInBase = exchangeRateInBase.mulDivDown(rateChange, 10_000); - - // get assets back if all shares are withdrawn immediatelly - uint assetsBack = withdrawSharesForAssets(shares); - - if(assetsBack > depositAmount){ - console.log("Problem. assets back should not be > deposit amount"); - console.log("AssetsBack: ", assetsBack); - console.log("DepositAmount: ", depositAmount); - console.log("Difference: ", assetsBack - depositAmount); - } - assertFalse(assetsBack > depositAmount, "The assets back should not be > deposit amount"); - assertApproxEqAbs(assetsBack, depositAmount, 2, "assetsBack != depositAmount with rate change"); - } - - function testDepositAndWithdrawWithRateChange_18Decimals_Quote6(uint depositAmount, uint256 startQuoteRate, uint256 startExchangeRate, uint256 rateChange) external{ - // set decimals - baseDecimals = 18; - quoteDecimals = 6; - quoteRateDecimals = 18; - - // bound values - depositAmount = bound(depositAmount, 1, 100_000_000e6); - quoteRate = bound(startQuoteRate, 1e18, 10_000e18); - exchangeRateInBase = bound(startExchangeRate, 8e17, 2e18); - rateChange = bound(rateChange, 9_980, 10_020); - - // get shares out if deposit done - uint shares = depositAssetForShares(depositAmount); - - // update the rate according to rate change - exchangeRateInBase = exchangeRateInBase.mulDivDown(rateChange, 10_000); - - // get assets back if all shares are withdrawn immediatelly - uint assetsBack = withdrawSharesForAssets(shares); - - if(assetsBack > depositAmount){ - console.log("Problem. assets back should not be > deposit amount"); - console.log("AssetsBack: ", assetsBack); - console.log("DepositAmount: ", depositAmount); - console.log("Difference: ", assetsBack - depositAmount); - } - assertFalse(assetsBack > depositAmount, "The assets back should not be > deposit amount"); - //assertApproxEqAbs(assetsBack, depositAmount, 2, "assetsBack != depositAmount with rate change"); - } - - // function testMath(uint256 depositAmount, uint256 rateChange) external { - // depositAmount = bound(depositAmount, 1, 1_000_000_000e18); - // rateChange = bound(rateChange, 9998, 10_002); - // // get the expected assets back after rate change - // uint256 expectedAssetsBack = ((depositAmount).mulDivDown(rateChange, 10_000)); - - // // get the shares back when depositing before rate change - // uint accountantRateBefore = accountant.getRateInQuoteSafe(ERC20(WEETH)); - // assertNotEq(accountantRateBefore, 1e18, "accountantRateBefore for WEETH equal to 1"); - // uint256 depositShares = depositAmount.mulDivDown(ONE_SHARE, accountantRateBefore); - // console.log("Shares * Rate:\t\t", depositShares * ONE_SHARE); - // console.log("accountantRateBefore:\t\t", accountantRateBefore); - - // // todo- atomic - // // change the rate - // uint96 newRate = uint96(accountant.getRate().mulDivDown(uint96(rateChange), 10_000)); - // vm.warp(1 days + block.timestamp); - // accountant.updateExchangeRate(newRate); - - // // calculate the assets out at the new rate - // uint accountantRateAfter = accountant.getRateInQuoteSafe(ERC20(WEETH)); - // assertApproxEqAbs(accountantRateBefore.mulDivDown(rateChange, 10_000), accountantRateAfter, 1, "accountantRateBefore not equal to after with rate applied"); - // console.log("Shares * Rate:\t", depositShares * accountantRateAfter); - // console.log("one_share:\t\t", ONE_SHARE); - // uint256 assetsOut = depositShares.mulDivDown(accountantRateAfter, (ONE_SHARE)); - - // // print if the expected > out and assert they're the same - // console.log("expectedAssetsBack >= realAssetsOut: ", expectedAssetsBack >= assetsOut); - // console.log("expectedAssetsBack: ", expectedAssetsBack); - // console.log("assetsOut: ", assetsOut); - // // assertTrue(expectedAssetsBack >= assetsOut, "BIG PROBLEM, not in protocol's favor"); - // assertApproxEqAbs(expectedAssetsBack, assetsOut, 1, "deposit * rateChange != depositAmount with"); - // // getRateInQuoteSafe math"); - // } - - function withdrawSharesForAssets(uint shareAmount) public returns(uint assetsOut){ - assetsOut = shareAmount.mulDivDown(getRateInQuote(), ONE_SHARE); - } - - function depositAssetForShares(uint depositAmount) public returns(uint shares){ - if (depositAmount == 0) revert("depositAssetForShares amount = 0"); - shares = depositAmount.mulDivDown(ONE_SHARE, getRateInQuote()); - // if (shares < minimumMint) revert ("); - } - - function getRateInQuote() public view returns (uint256 rateInQuote) { - uint256 exchangeRateInQuoteDecimals = changeDecimals(exchangeRateInBase, baseDecimals, quoteDecimals); - - uint256 oneQuote = 10 ** quoteDecimals; - rateInQuote = oneQuote.mulDivDown((exchangeRateInQuoteDecimals), quoteRate); - // console.log("Quote Rate: ",quoteRate); - // console.log("One Quote: ", oneQuote); - // console.log("Exchange Rate In Quote Decimals: ", exchangeRateInQuoteDecimals); - } - - function changeDecimals(uint256 amount, uint fromDecimals, uint 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); - } - } - -} \ No newline at end of file From 8b31ff5012bd9d32e9ef10519a6e9d22c85c8442 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 29 Aug 2024 14:16:28 -0400 Subject: [PATCH 24/29] fix: import error --- test/LiveDeploy.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index c8ff380..c527d91 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -13,7 +13,7 @@ import { AccountantWithRateProviders } from "src/base/Roles/AccountantWithRatePr 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 } from "@forge-std/StdJson.sol"; +import { stdJson as StdJson } from "@forge-std/StdJson.sol"; import { CrossChainOPTellerWithMultiAssetSupportTest } from "test/CrossChain/CrossChainOPTellerWithMultiAssetSupport.t.sol"; From 4bb93207249f9eb2ffa6f6c798fedd29f2592e31 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 29 Aug 2024 20:10:46 -0400 Subject: [PATCH 25/29] test: ERC20 check --- test/LiveDeploy.t.sol | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/LiveDeploy.t.sol b/test/LiveDeploy.t.sol index c527d91..543eb2a 100644 --- a/test/LiveDeploy.t.sol +++ b/test/LiveDeploy.t.sol @@ -304,6 +304,22 @@ contract LiveDeploy is ForkTest, DeployAll { } } + function testAssetsAreAllNormalERC20() public { + 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, 1 ether); + assertEq(asset.balanceOf(user1), 1 ether, "asset did not deal to user1 correctly"); + uint256 totalSupplyStart = asset.totalSupply(); + vm.prank(user1); + asset.transfer(user2, 0.5 ether); + assertEq(asset.balanceOf(user1), 0.5 ether, "user1 balance not removed after transfer"); + assertEq(asset.balanceOf(user2), 0.5 ether, "user2 balance not incremented after transfer"); + } + } + function _depositAssetWithApprove(ERC20 asset, uint256 depositAmount) internal { deal(address(asset), address(this), depositAmount); asset.approve(mainConfig.boringVault, depositAmount); From 34eb07b6a7bd6d65d1ec061a14a3b7e584c91561 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 29 Aug 2024 21:36:24 -0400 Subject: [PATCH 26/29] chore: chain config sepolia --- deployment-config/chains/11155111.json | 6 ++ .../form-testnet-l1-08-30-24.json | 56 +++++++++++++++++++ script/Base.s.sol | 2 +- script/DeployCustomCreatex.s.sol | 2 +- 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 deployment-config/chains/11155111.json create mode 100644 deployment-config/form-testnet-l1-08-30-24.json diff --git a/deployment-config/chains/11155111.json b/deployment-config/chains/11155111.json new file mode 100644 index 0000000..5f29a22 --- /dev/null +++ b/deployment-config/chains/11155111.json @@ -0,0 +1,6 @@ +{ + "base": "0xb16F35c0Ae2912430DAc15764477E179D9B9EbEa", + "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "opMessenger": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + "lzEndpoint": "0x6EDCE65403992e310A62460808c4b910D972f10f" + } \ No newline at end of file diff --git a/deployment-config/form-testnet-l1-08-30-24.json b/deployment-config/form-testnet-l1-08-30-24.json new file mode 100644 index 0000000..5a49730 --- /dev/null +++ b/deployment-config/form-testnet-l1-08-30-24.json @@ -0,0 +1,56 @@ +{ + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "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": "MultiChainLayerZeroTellerWithMultiAssetSupport", + "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/script/Base.s.sol b/script/Base.s.sol index c832210..e5dbc4b 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -19,7 +19,7 @@ abstract contract BaseScript is Script { string constant CONFIG_CHAIN_ROOT = "./deployment-config/chains/"; /// Custom base params - ICreateX CREATEX = ICreateX(0xD7d6e6C50507d278b9F43f62Bc7b9310ECeff2C5); + ICreateX CREATEX = ICreateX(0x1C64d5eBCf22AC237d00cF7bB9Be6395e59B23b7); /// @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"; diff --git a/script/DeployCustomCreatex.s.sol b/script/DeployCustomCreatex.s.sol index 2dba87c..21f882c 100644 --- a/script/DeployCustomCreatex.s.sol +++ b/script/DeployCustomCreatex.s.sol @@ -10,7 +10,7 @@ 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 = 0xD7d6e6C50507d278b9F43f62Bc7b9310ECeff2C5; + address constant EXPECTED = 0x1C64d5eBCf22AC237d00cF7bB9Be6395e59B23b7; bytes32 constant SALT = 0x8888888833388888888000000000000000000000000000000000000000000000; constructor() { From 770d84ac4b8ff89fe41cc84c8f99cf242e1a6461 Mon Sep 17 00:00:00 2001 From: Carson Date: Fri, 30 Aug 2024 13:38:37 -0400 Subject: [PATCH 27/29] test: prep for rate apxETH rate provider and test --- deployment-config/chains/1.json | 7 +- deployment-config/exampleL1.json | 14 +-- deployment-config/exampleL2.json | 2 +- .../form-btc-testnet-l1-08-30-24.json | 110 +++++++++--------- .../form-usd-testnet-l1-08-30-24.json | 110 +++++++++--------- script/Base.s.sol | 2 +- script/DeployCustomCreatex.s.sol | 2 +- src/helper/Constants.sol | 1 + .../ion/oracles/EthPerTokenRateProvider.t.sol | 30 ++++- 9 files changed, 152 insertions(+), 126 deletions(-) diff --git a/deployment-config/chains/1.json b/deployment-config/chains/1.json index 195e5b6..1d48dbc 100644 --- a/deployment-config/chains/1.json +++ b/deployment-config/chains/1.json @@ -50,12 +50,13 @@ "rateProvider": "0x318Da095d602C08eF41319f4c4bA0646d318C906", "decimals": 8 }, - "":{ + "0x9ba021b0a9b958b5e75ce9f6dff97c7ee52cb3e6":{ "priceFeed": "0x19219bc90f48dee4d5cf202e09c438faacfd8bea", - "rateProvider": "", + "rateProvider": "0x0000000000000000000000000000000000000000", "decimals": 18, - "description": "STETH / ETH", + "description": "apxETH/ETH", "priceFeedType": 1 + } } diff --git a/deployment-config/exampleL1.json b/deployment-config/exampleL1.json index 8fea879..4967aa3 100644 --- a/deployment-config/exampleL1.json +++ b/deployment-config/exampleL1.json @@ -1,20 +1,20 @@ { + "base": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "protocolAdmin": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", "boringVaultAndBaseDecimals": "18", "boringVault": { - "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000e", + "boringVaultSalt": "0x1ddd634c506ad203da17ff000000000000000000000000000000000000000010", "boringVaultName": "Nucleus Vault", "boringVaultSymbol": "NV", "address": "0x0000000000E7Ab44153eEBEF2343ba5289F65dAC" }, "manager": { - "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000e", + "managerSalt": "0x30432d4b4ec00003b4a250000000000000000000000000000000000000000010", "address": "0x0000000000fAd6Db23abdC1a85621B97bd1Dc82f" }, "accountant": { - "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000e", + "accountantSalt": "0x6a184dbea6f3cc0318679f000000000000000000000000000000000000000010", "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", "allowedExchangeRateChangeUpper": "10003", "allowedExchangeRateChangeLower": "9998", "minimumUpdateDelayInSeconds": "3600", @@ -22,7 +22,7 @@ "address": "0x00000000004F96C07B83e86600D86F9479bB43fa" }, "teller": { - "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000e", + "tellerSalt": "0x51f8968749a56d01202c91000000000000000000000000000000000000000010", "maxGasForPeer": 100000, "minGasForPeer": 0, "peerEid": 30280, @@ -47,13 +47,13 @@ "address": "0x00000000004F96C07B83e86600D86F0000000000" }, "rolesAuthority": { - "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000e", + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a000000000000000000000000000000000000000010", "strategist": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", "address": "0x00000000004F96C07B83e86600D86F0000000000" }, "decoder": { - "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", + "decoderSalt": "0x48b53893da2e0b0248268c000000000000000000000000000000000000000010", "address": "0x00000000004F96C07B83e86600D86F0000000000" } } \ No newline at end of file diff --git a/deployment-config/exampleL2.json b/deployment-config/exampleL2.json index 01fd6d2..8a65696 100644 --- a/deployment-config/exampleL2.json +++ b/deployment-config/exampleL2.json @@ -1,4 +1,5 @@ { + "base":"0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8", "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", "boringVaultAndBaseDecimals": "18", "boringVault": { @@ -14,7 +15,6 @@ "accountant": { "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000e", "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "base": "0x5f207d42F869fd1c71d7f0f81a2A67Fc20FF7323", "allowedExchangeRateChangeUpper": "10003", "allowedExchangeRateChangeLower": "9998", "minimumUpdateDelayInSeconds": "3600", diff --git a/deployment-config/form-btc-testnet-l1-08-30-24.json b/deployment-config/form-btc-testnet-l1-08-30-24.json index 7dccdc1..5dd02a0 100644 --- a/deployment-config/form-btc-testnet-l1-08-30-24.json +++ b/deployment-config/form-btc-testnet-l1-08-30-24.json @@ -1,59 +1,57 @@ { - "base": "0x92f3B59a79bFf5dc60c0d59eA13a44D082B2bdFC", - "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "boringVaultAndBaseDecimals": "8", - "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": [ - + "base": "0x92f3B59a79bFf5dc60c0d59eA13a44D082B2bdFC", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "8", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff000000000000000000000000000000000000000012", + "boringVaultName": "Form ETH", + "boringVaultSymbol": "FETH", + "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" ], - "dvnIfNoDefault": { - "required": [ - "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" - ], - "optional": [ - "0x380275805876Ff19055EA900CDb2B46a94ecF20D", - "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", - "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", - "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" - ], - "blockConfirmationsRequiredIfNoDefault": 15, - "optionalThreshold": 1 - }, - "address": "0x0000000000000000000000000000000000000000" - }, - "rolesAuthority": { - "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000e", - "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "address": "0x0000000000000000000000000000000000000000" + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 }, - "decoder": { - "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", - "address": "0x0000000000000000000000000000000000000000" - } - } \ No newline at end of file + "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/form-usd-testnet-l1-08-30-24.json b/deployment-config/form-usd-testnet-l1-08-30-24.json index 2401f6e..68774af 100644 --- a/deployment-config/form-usd-testnet-l1-08-30-24.json +++ b/deployment-config/form-usd-testnet-l1-08-30-24.json @@ -1,59 +1,57 @@ { - "base": "0x51fCe89b9f6D4c530698f181167043e1bB4abf89", - "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "boringVaultAndBaseDecimals": "6", - "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": [ - + "base": "0x51fCe89b9f6D4c530698f181167043e1bB4abf89", + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "boringVaultAndBaseDecimals": "6", + "boringVault": { + "boringVaultSalt": "0x1ddd634c506ad203da17ff000000000000000000000000000000000000000010", + "boringVaultName": "Form ETH", + "boringVaultSymbol": "FETH", + "address": "0x0000000000000000000000000000000000000000" + }, + "manager": { + "managerSalt": "0x30432d4b4ec00003b4a250000000000000000000000000000000000000000010", + "address": "0x0000000000000000000000000000000000000000" + }, + "accountant": { + "accountantSalt": "0x6a184dbea6f3cc0318679f000000000000000000000000000000000000000010", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10003", + "allowedExchangeRateChangeLower": "9998", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "0", + "address": "0x0000000000000000000000000000000000000000" + }, + "teller": { + "tellerSalt": "0x51f8968749a56d01202c91000000000000000000000000000000000000000010", + "maxGasForPeer": 100000, + "minGasForPeer": 0, + "peerEid": 40270, + "tellerContractName": "TellerWithMultiAssetSupport", + "opMessenger": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", + "assets": [], + "dvnIfNoDefault": { + "required": [ + "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" ], - "dvnIfNoDefault": { - "required": [ - "0x589dEDbD617e0CBcB916A9223F4d1300c294236b" - ], - "optional": [ - "0x380275805876Ff19055EA900CDb2B46a94ecF20D", - "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", - "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", - "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" - ], - "blockConfirmationsRequiredIfNoDefault": 15, - "optionalThreshold": 1 - }, - "address": "0x0000000000000000000000000000000000000000" - }, - "rolesAuthority": { - "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000e", - "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "address": "0x0000000000000000000000000000000000000000" + "optional": [ + "0x380275805876Ff19055EA900CDb2B46a94ecF20D", + "0x8FafAE7Dd957044088b3d0F67359C327c6200d18", + "0xa59BA433ac34D2927232918Ef5B2eaAfcF130BA5", + "0xe552485d02EDd3067FE7FCbD4dd56BB1D3A998D2" + ], + "blockConfirmationsRequiredIfNoDefault": 15, + "optionalThreshold": 1 }, - "decoder": { - "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000e", - "address": "0x0000000000000000000000000000000000000000" - } - } \ No newline at end of file + "address": "0x0000000000000000000000000000000000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a000000000000000000000000000000000000000010", + "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "address": "0x0000000000000000000000000000000000000000" + }, + "decoder": { + "decoderSalt": "0x48b53893da2e0b0248268c000000000000000000000000000000000000000010", + "address": "0x0000000000000000000000000000000000000000" + } +} \ No newline at end of file diff --git a/script/Base.s.sol b/script/Base.s.sol index cb758d9..035d400 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(0x1C64d5eBCf22AC237d00cF7bB9Be6395e59B23b7); + ICreateX CREATEX = ICreateX(0x1077f8ea07EA34D9F23BC39256BF234665FB391f); /// @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"; diff --git a/script/DeployCustomCreatex.s.sol b/script/DeployCustomCreatex.s.sol index 6676362..e2be751 100644 --- a/script/DeployCustomCreatex.s.sol +++ b/script/DeployCustomCreatex.s.sol @@ -10,7 +10,7 @@ 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 = 0x1C64d5eBCf22AC237d00cF7bB9Be6395e59B23b7; + address constant EXPECTED = 0x1077f8ea07EA34D9F23BC39256BF234665FB391f; bytes32 constant SALT = 0x8888888833388888888000000000000000000000000000000000000000000000; constructor() { diff --git a/src/helper/Constants.sol b/src/helper/Constants.sol index 17cc9cc..b44c710 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_REDSTOME = IPriceFeed(0x19219BC90F48DeE4d5cF202E09c438FAacFd8Bea); address constant SWBTC = 0x8DB2350D78aBc13f5673A411D4700BCF87864dDE; address constant WBTC_ETHEREUM = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; diff --git a/test/ion/oracles/EthPerTokenRateProvider.t.sol b/test/ion/oracles/EthPerTokenRateProvider.t.sol index aaf6c71..3775f5c 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_REDSTOME } 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_REDSTOME, + 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_REDSTOME, + MAX_TIME_FROM_LAST_UPDATE, + 18, + EthPerTokenRateProvider.PriceFeedType.REDSTONE + ); + } +} From bca4f725a0ec99c136ad110789e0342a48eb97f6 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 5 Sep 2024 23:52:35 -0400 Subject: [PATCH 28/29] refactor: spell error --- test/ion/oracles/EthPerTokenRateProvider.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ion/oracles/EthPerTokenRateProvider.t.sol b/test/ion/oracles/EthPerTokenRateProvider.t.sol index 3775f5c..3a0140d 100644 --- a/test/ion/oracles/EthPerTokenRateProvider.t.sol +++ b/test/ion/oracles/EthPerTokenRateProvider.t.sol @@ -9,7 +9,7 @@ import { ETH_PER_RSETH_CHAINLINK, ETH_PER_RSWETH_CHAINLINK, ETH_PER_PUFETH_REDSTONE, - ETH_PER_APXETH_REDSTOME + ETH_PER_APXETH_REDSTONE } from "./../../../src/helper/Constants.sol"; import { Test } from "@forge-std/Test.sol"; @@ -204,7 +204,7 @@ contract ApxEthRateProviderTest is EthPerTokenRateProviderTest { ethPerTokenRateProvider = new EthPerTokenRateProvider( "apxETH/ETH", - ETH_PER_APXETH_REDSTOME, + ETH_PER_APXETH_REDSTONE, MAX_TIME_FROM_LAST_UPDATE, 18, EthPerTokenRateProvider.PriceFeedType.REDSTONE @@ -215,7 +215,7 @@ contract ApxEthRateProviderTest is EthPerTokenRateProviderTest { vm.expectRevert(EthPerTokenRateProvider.InvalidDescription.selector); ethPerTokenRateProvider = new EthPerTokenRateProvider( incorrectDescription, - ETH_PER_APXETH_REDSTOME, + ETH_PER_APXETH_REDSTONE, MAX_TIME_FROM_LAST_UPDATE, 18, EthPerTokenRateProvider.PriceFeedType.REDSTONE From fcb8dd14590e4f772fdfc305c1e80363e41549dd Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 5 Sep 2024 23:57:20 -0400 Subject: [PATCH 29/29] refactor: spell error, unsaved file --- src/helper/Constants.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/Constants.sol b/src/helper/Constants.sol index b44c710..5664215 100644 --- a/src/helper/Constants.sol +++ b/src/helper/Constants.sol @@ -8,7 +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_REDSTOME = IPriceFeed(0x19219BC90F48DeE4d5cF202E09c438FAacFd8Bea); +IPriceFeed constant ETH_PER_APXETH_REDSTONE = IPriceFeed(0x19219BC90F48DeE4d5cF202E09c438FAacFd8Bea); address constant SWBTC = 0x8DB2350D78aBc13f5673A411D4700BCF87864dDE; address constant WBTC_ETHEREUM = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;