diff --git a/deployment-config/boba-eth-l1-08-09-24.json b/deployment-config/boba-eth-l1-08-09-24.json index e7da60c..ad107ea 100644 --- a/deployment-config/boba-eth-l1-08-09-24.json +++ b/deployment-config/boba-eth-l1-08-09-24.json @@ -1,5 +1,7 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "baseDecimals": "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 548680c..547df94 100644 --- a/deployment-config/boba-eth-l2-08-09-24.json +++ b/deployment-config/boba-eth-l2-08-09-24.json @@ -1,5 +1,7 @@ { "protocolAdmin": "0x0888c3D797E13892C5e67cD802F93Ffe55Ea2826", + "base": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000", + "baseDecimals": "18", "boringVault": { "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000001", "boringVaultName": "Boba Native Yield Nucleus Token", diff --git a/deployment-config/chains/1.json b/deployment-config/chains/1.json index aad1b0f..fc8de28 100644 --- a/deployment-config/chains/1.json +++ b/deployment-config/chains/1.json @@ -1,5 +1,4 @@ { - "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", "opMessenger": "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", "lzEndpoint": "0x1a44076050125825900e736c501f859c50fE728c", @@ -46,6 +45,10 @@ "decimals": 18, "description": "", "priceFeedType": 0 + }, + "0x8db2350d78abc13f5673a411d4700bcf87864dde": { + "rateProvider": "0x318Da095d602C08eF41319f4c4bA0646d318C906", + "decimals": 8 } } } \ No newline at end of file diff --git a/deployment-config/chains/1329.json b/deployment-config/chains/1329.json index d3691e2..67171d8 100644 --- a/deployment-config/chains/1329.json +++ b/deployment-config/chains/1329.json @@ -1,5 +1,4 @@ { - "base": "0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8", "balancerVault": "0x0000000000000000000000000000000000000000", "lzEndpoint": "0x1a44076050125825900e736c501f859c50fE728c" } \ No newline at end of file diff --git a/deployment-config/chains/252.json b/deployment-config/chains/252.json index 1e7aea7..68c5b63 100644 --- a/deployment-config/chains/252.json +++ b/deployment-config/chains/252.json @@ -1,5 +1,4 @@ { - "base": "0xFC00000000000000000000000000000000000006", "balancerVault": "0x0000000000000000000000000000000000000000", "lzEndpoint": "0x1a44076050125825900e736c501f859c50fE728c" } \ No newline at end of file diff --git a/deployment-config/chains/288.json b/deployment-config/chains/288.json index 82b445f..1d0cca9 100644 --- a/deployment-config/chains/288.json +++ b/deployment-config/chains/288.json @@ -1,5 +1,4 @@ { - "base": "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000", "balancerVault": "0x0000000000000000000000000000000000000000", "lzEndpoint": "0x0000000000000000000000000000000000000000" } \ No newline at end of file diff --git a/deployment-config/fraxtal-eth-l1-08-13-24.json b/deployment-config/fraxtal-eth-l1-08-13-24.json index d2fad36..a688703 100644 --- a/deployment-config/fraxtal-eth-l1-08-13-24.json +++ b/deployment-config/fraxtal-eth-l1-08-13-24.json @@ -1,5 +1,7 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "baseDecimals": "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 b168066..d618a44 100644 --- a/deployment-config/fraxtal-eth-l2-08-13-24.json +++ b/deployment-config/fraxtal-eth-l2-08-13-24.json @@ -1,5 +1,7 @@ { "protocolAdmin": "0x0888c3D797E13892C5e67cD802F93Ffe55Ea2826", + "base": "0xFC00000000000000000000000000000000000006", + "baseDecimals": "18", "boringVault": { "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000002", "boringVaultName": "Fraxtal Native Yield Nucleus Token", diff --git a/deployment-config/mydeploy.json b/deployment-config/mydeploy.json deleted file mode 100644 index 9f02eca..0000000 --- a/deployment-config/mydeploy.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "protocolAdmin": "0xC2d99d76bb9D46BF8Ec9449E4DfAE48C30CF0839", - - "boringVault":{ - "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", - "boringVaultName": "Ion Vault", - "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": 0, - "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", - "opMessenger": "0x0000000000000000000000000000000000000000", - "assets": [ - "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", - "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110" - ], - - "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/rates/DeployGenericRateProvider.json b/deployment-config/rates/DeployGenericRateProvider.json new file mode 100644 index 0000000..febfe7b --- /dev/null +++ b/deployment-config/rates/DeployGenericRateProvider.json @@ -0,0 +1,7 @@ +{ + "target": "0x8DB2350D78aBc13f5673A411D4700BCF87864dDE", + "signature": "pricePerShare()", + "expectedMin": "100000000", + "expectedMax": "100000000", + "salt": "0x1000000000000000000000000000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/deployment-config/rswBTC-l1.json b/deployment-config/rswBTC-l1.json new file mode 100644 index 0000000..ce53341 --- /dev/null +++ b/deployment-config/rswBTC-l1.json @@ -0,0 +1,57 @@ +{ + "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "base": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "baseDecimals": "8", + + "boringVault":{ + "boringVaultSalt": "0x100000000000000000000000000000000000000000000000000000000000000b", + "boringVaultName": "Swell Native Yield Nucleus Token", + "boringVaultSymbol": "rswBTC", + + "address": "0x0000000000000000000000000000000000000000" + }, + + "manager":{ + "managerSalt": "0x200000000000000000000000000000000000000000000000000000000000000b", + + "address": "0x0000000000000000000000000000000000000000" + }, + + "accountant":{ + "accountantSalt": "0x300000000000000000000000000000000000000000000000000000000000000b", + "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "allowedExchangeRateChangeUpper": "10030", + "allowedExchangeRateChangeLower": "9980", + "minimumUpdateDelayInSeconds": "3600", + "managementFee": "0", + + "address": "0x0000000000000000000000000000000000000000" + }, + + "teller": { + "tellerSalt": "0x400000000000000000000000000000000000000000000000000000000000000a", + "maxGasForPeer": 200000, + "minGasForPeer": 60000, + "peerEid": 0, + "tellerContractName": "TellerWithMultiAssetSupport", + "opMessenger": "0x0000000000000000000000000000000000000000", + "assets": [ + "0x8DB2350D78aBc13f5673A411D4700BCF87864dDE" + ], + "address": "0x0000000000000000000000000000000000000000" + }, + "rolesAuthority": { + "rolesAuthoritySalt": "0x500000000000000000000000000000000000000000000000000000000000000b", + "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", + "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", + + "address": "0x0000000000000000000000000000000000000000" + }, + + "decoder": { + "decoderSalt": "0x6000000000000000000000000000000000000000000000000000000000000000", + + "address": "0x0000000000000000000000000000000000000000" + } + +} \ No newline at end of file diff --git a/deployment-config/sei-eth-l1-08-08-24.json b/deployment-config/sei-eth-l1-08-08-24.json index 404936c..588851f 100644 --- a/deployment-config/sei-eth-l1-08-08-24.json +++ b/deployment-config/sei-eth-l1-08-08-24.json @@ -1,8 +1,9 @@ { "protocolAdmin": "0x0000000000417626Ef34D62C4DC189b021603f2F", - + "base": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "baseDecimals": "18", "boringVault":{ - "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000000", + "boringVaultSalt": "0x100000000000000000000000000000000000000000000000000000000000000a", "boringVaultName": "Sei Native Yield Nucleus Token", "boringVaultSymbol": "seiyanETH", @@ -10,13 +11,13 @@ }, "manager":{ - "managerSalt": "0x2000000000000000000000000000000000000000000000000000000000000000", + "managerSalt": "0x200000000000000000000000000000000000000000000000000000000000000a", "address": "0x0000000000000000000000000000000000000000" }, "accountant":{ - "accountantSalt": "0x3000000000000000000000000000000000000000000000000000000000000000", + "accountantSalt": "0x300000000000000000000000000000000000000000000000000000000000000a", "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", "allowedExchangeRateChangeUpper": "10030", "allowedExchangeRateChangeLower": "9980", @@ -27,7 +28,7 @@ }, "teller": { - "tellerSalt": "0x4000000000000000000000000000000000000000000000000000000000000000", + "tellerSalt": "0x400000000000000000000000000000000000000000000000000000000000000a", "maxGasForPeer": 200000, "minGasForPeer": 60000, "peerEid": 30280, @@ -44,7 +45,7 @@ "address": "0x0000000000000000000000000000000000000000" }, "rolesAuthority": { - "rolesAuthoritySalt": "0x5000000000000000000000000000000000000000000000000000000000000000", + "rolesAuthoritySalt": "0x500000000000000000000000000000000000000000000000000000000000000a", "strategist": "0x0000000000417626Ef34D62C4DC189b021603f2F", "exchangeRateBot": "0x0000000000417626Ef34D62C4DC189b021603f2F", diff --git a/deployment-config/sei-eth-l2-08-08-24.json b/deployment-config/sei-eth-l2-08-08-24.json index bad0b23..852d858 100644 --- a/deployment-config/sei-eth-l2-08-08-24.json +++ b/deployment-config/sei-eth-l2-08-08-24.json @@ -1,6 +1,7 @@ { "protocolAdmin": "0xF2dE1311C5b2C1BD94de996DA13F80010453e505", - + "base": "0x160345fC359604fC6e70E3c5fAcbdE5F7A9342d8", + "baseDecimals": "18", "boringVault":{ "boringVaultSalt": "0x1000000000000000000000000000000000000000000000000000000000000000", "boringVaultName": "Sei Native Yield Nucleus Token", diff --git a/deployment-config/seidry.json b/deployment-config/seidry.json deleted file mode 100644 index 4982d23..0000000 --- a/deployment-config/seidry.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "protocolAdmin": "0xbcef4940d7000e94c0048f071e28bfe91bc5066d", - - "boringVault":{ - "boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000000a", - "boringVaultName": "Ion Vault", - "boringVaultSymbol": "IVT", - - "address": "0x0000000000000000000000000000000000000000" - }, - - "manager":{ - "managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000000a", - - "address": "0x0000000000000000000000000000000000000000" - }, - - "accountant":{ - "accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000000a", - "payoutAddress": "0x0000000000417626Ef34D62C4DC189b021603f2F", - "allowedExchangeRateChangeUpper": "10003", - "allowedExchangeRateChangeLower": "9998", - "minimumUpdateDelayInSeconds": "3600", - "managementFee": "2000", - - "address": "0x0000000000000000000000000000000000000000" - }, - - "teller": { - "tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000000a", - "maxGasForPeer": 100000, - "minGasForPeer": 0, - "peerEid": 1, - "tellerContractName": "MultiChainLayerZeroTellerWithMultiAssetSupport", - "opMessenger": "0x0000000000000000000000000000000000000000", - "assets": [ - ], - "address": "0x0000000000000000000000000000000000000000" - }, - "rolesAuthority": { - "rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000000a", - "strategist": "0xbcef4940d7000e94c0048f071e28bfe91bc5066d", - "exchangeRateBot": "0x00000000004F96C07B83e86600D86F0000000000", - - "address": "0x0000000000000000000000000000000000000000" - }, - - "decoder": { - "decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000000a", - - "address": "0x0000000000000000000000000000000000000000" - }, - - "rateProvider": { - "maxTimeFromLastUpdate": "86400", - "rateProviderSalt": "0x0000000000000000000000000000000000000000000000000000000000000000", - - "address": "0x0000000000000000000000000000000000000000" - } -} \ No newline at end of file diff --git a/package.json b/package.json index 5438095..9668c7b 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "solhint": "solhint -w 0 'src/**/*.sol'", "slither": "slither src", "prepare": "husky", - "deploy-createx-l1": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L1_RPC_URL --private-key $PRIVATE_KEY --slow", - "deploy-createx-l2": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --slow", + "deploy-createx-l1": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L1_RPC_URL --private-key $PRIVATE_KEY --slow --no-metadata", + "deploy-createx-l2": "forge script script/DeployCustomCreatex.s.sol --rpc-url $L2_RPC_URL --private-key $PRIVATE_KEY --slow --no-metadata", "deploy-l1": "forge script script/deploy/deployAll.s.sol -f $L1_RPC_URL --private-key=$PRIVATE_KEY --slow", "deploy-l2": "forge script script/deploy/deployAll.s.sol -f $L2_RPC_URL --private-key=$PRIVATE_KEY --slow" }, diff --git a/script/ConfigReader.s.sol b/script/ConfigReader.s.sol index b75f017..2cdb0e7 100644 --- a/script/ConfigReader.s.sol +++ b/script/ConfigReader.s.sol @@ -14,6 +14,8 @@ library ConfigReader { struct Config { address protocolAdmin; + address base; + uint8 baseDecimals; bytes32 accountantSalt; address boringVault; address payoutAddress; @@ -28,6 +30,8 @@ library ConfigReader { address balancerVault; bytes32 tellerSalt; uint32 peerEid; + address dvnIfNoDefault; + uint64 dvnBlockConfirmationsRequiredIfNoDefault; address accountant; address opMessenger; uint64 maxGasForPeer; @@ -48,12 +52,13 @@ library ConfigReader { address[] assets; address[] rateProviders; address[] priceFeeds; - address base; } function toConfig(string memory _config, string memory _chainConfig) internal pure returns (Config memory config) { // Reading the 'protocolAdmin' config.protocolAdmin = _config.readAddress(".protocolAdmin"); + config.base = _config.readAddress(".base"); + config.baseDecimals = uint8(_config.readUint(".baseDecimals")); // Reading from the 'accountant' section config.accountant = _config.readAddress(".accountant.address"); @@ -95,7 +100,6 @@ library ConfigReader { config.decoder = _config.readAddress(".decoder.address"); // Reading from the 'chainConfig' section - config.base = _chainConfig.readAddress(".base"); config.balancerVault = _chainConfig.readAddress(".balancerVault"); config.lzEndpoint = _chainConfig.readAddress(".lzEndpoint"); diff --git a/script/deploy/DeployGenericRateProvider.s.sol b/script/deploy/DeployGenericRateProvider.s.sol new file mode 100644 index 0000000..c9e39a8 --- /dev/null +++ b/script/deploy/DeployGenericRateProvider.s.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.21; + +import { GenericRateProvider } from "./../../src/helper/GenericRateProvider.sol"; +import { BaseScript } from "../Base.s.sol"; +import { stdJson as StdJson } from "@forge-std/StdJson.sol"; +import { console2 } from "forge-std/console2.sol"; + +using StdJson for string; + +// NOTE Currently assumes that function signature arguments are empty. +contract DeployGenericRateProvider is BaseScript { + string configPath = "./deployment-config/rates/DeployGenericRateProvider.json"; + string config = vm.readFile(configPath); + + uint256 expectedMin = config.readUint(".expectedMin"); + uint256 expectedMax = config.readUint(".expectedMax"); + address target = config.readAddress(".target"); + string signature = config.readString(".signature"); + bytes32 salt = config.readBytes32(".salt"); + + function run() public broadcast returns (GenericRateProvider rateProvider) { + bytes4 functionSig = bytes4(keccak256(bytes(signature))); + console2.logBytes4(functionSig); + + bytes memory creationCode = type(GenericRateProvider).creationCode; + + rateProvider = GenericRateProvider( + CREATEX.deployCreate3( + salt, abi.encodePacked(creationCode, abi.encode(target, functionSig, 0, 0, 0, 0, 0, 0, 0, 0)) + ) + ); + + uint256 rate = rateProvider.getRate(); + + console2.log("rate: ", rate); + + require(rate != 0, "rate must not be zero"); + require(rate >= expectedMin, "rate must be greater than or equal to min"); + require(rate <= expectedMax, "rate must be less than or equal to max"); + } +} diff --git a/script/deploy/deployAll.s.sol b/script/deploy/deployAll.s.sol index d02c159..a9a72fd 100644 --- a/script/deploy/deployAll.s.sol +++ b/script/deploy/deployAll.s.sol @@ -90,6 +90,8 @@ contract DeployAll is BaseScript { teller = new DeployCrossChainOPTellerWithMultiAssetSupport().deploy(config); } else if (compareStrings(config.tellerContractName, "MultiChainLayerZeroTellerWithMultiAssetSupport")) { teller = new DeployMultiChainLayerZeroTellerWithMultiAssetSupport().deploy(config); + } else if (compareStrings(config.tellerContractName, "TellerWithMultiAssetSupport")) { + teller = new DeployTellerWithMultiAssetSupport().deploy(config); } else { revert INVALID_TELLER_CONTRACT_NAME(); } diff --git a/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol b/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol index 2b5325e..4782180 100644 --- a/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol +++ b/script/deploy/single/04_DeployAccountantWithRateProviders.s.sol @@ -30,7 +30,10 @@ contract DeployAccountantWithRateProviders is BaseScript { require(config.allowedExchangeRateChangeLower >= 0.997e4, "allowedExchangeRateChangeLower lower bound"); require(config.minimumUpdateDelayInSeconds >= 3600, "minimumUpdateDelayInSeconds"); require(config.managementFee < 1e4, "managementFee"); - require(startingExchangeRate == 1e18, "starting exchange rate must be 1e18"); + require( + startingExchangeRate == 10 ** config.baseDecimals, + "starting exchange rate must be equal to base decimals" + ); } // Create Contract bytes memory creationCode = type(AccountantWithRateProviders).creationCode; diff --git a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol index b1287f6..bbbc83c 100644 --- a/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol +++ b/script/deploy/single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol @@ -7,10 +7,24 @@ import { MultiChainLayerZeroTellerWithMultiAssetSupport } from import { BaseScript } from "./../../Base.s.sol"; 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"; contract DeployMultiChainLayerZeroTellerWithMultiAssetSupport is BaseScript { using StdJson for string; + address dead = 0x000000000000000000000000000000000000dEaD; + + struct UlnConfig { + uint64 confirmations; + // we store the length of required DVNs and optional DVNs instead of using DVN.length directly to save gas + uint8 requiredDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default) + uint8 optionalDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default) + uint8 optionalDVNThreshold; // (0, optionalDVNCount] + address[] requiredDVNs; // no duplicates. sorted an an ascending order. allowed overlap with optionalDVNs + address[] optionalDVNs; // no duplicates. sorted an an ascending order. allowed overlap with requiredDVNs + } + function run() public returns (address teller) { return deploy(getConfig()); } @@ -49,6 +63,47 @@ 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. return address(teller); } + + function _checkUlnConfig(ConfigReader.Config memory config) 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)); + + if (ulnConfig.confirmations == 0) { + _setConfig(endpoint, lib, config); + return; + } + uint8 numRequiredDVN = ulnConfig.requiredDVNCount; + uint8 numOptionalDVN = ulnConfig.optionalDVNCount; + for (uint256 i; i < numRequiredDVN; ++i) { + if (ulnConfig.requiredDVNs[i] == dead) { + _setConfig(endpoint, lib, config); + return; + } + } + for (uint256 i; i < numRequiredDVN; ++i) { + if (ulnConfig.optionalDVNs[i] == dead) { + _setConfig(endpoint, lib, config); + return; + } + } + } + + 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)); + + SetConfigParam[] memory setConfigParams = new SetConfigParam[](1); + setConfigParams[0] = SetConfigParam(config.peerEid, 2, ulnConfigBytes); + endpoint.setConfig(config.teller, lib, setConfigParams); + } } diff --git a/src/helper/Constants.sol b/src/helper/Constants.sol index 9cd9048..17cc9cc 100644 --- a/src/helper/Constants.sol +++ b/src/helper/Constants.sol @@ -8,3 +8,6 @@ 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); + +address constant SWBTC = 0x8DB2350D78aBc13f5673A411D4700BCF87864dDE; +address constant WBTC_ETHEREUM = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599; diff --git a/src/helper/GenericRateProvider.sol b/src/helper/GenericRateProvider.sol index 8f4a9e6..4e8d8da 100644 --- a/src/helper/GenericRateProvider.sol +++ b/src/helper/GenericRateProvider.sol @@ -32,7 +32,7 @@ contract GenericRateProvider is IRateProvider { constructor( address _target, - bytes4 _selctor, + bytes4 _selector, bytes32 _staticArgument0, bytes32 _staticArgument1, bytes32 _staticArgument2, @@ -43,7 +43,7 @@ contract GenericRateProvider is IRateProvider { bytes32 _staticArgument7 ) { target = _target; - selector = _selctor; + selector = _selector; staticArgument0 = _staticArgument0; staticArgument1 = _staticArgument1; staticArgument2 = _staticArgument2; diff --git a/test/ion/oracles/GenericRateProvider.t.sol b/test/ion/oracles/GenericRateProvider.t.sol new file mode 100644 index 0000000..d40c3e1 --- /dev/null +++ b/test/ion/oracles/GenericRateProvider.t.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.21; + +import { GenericRateProvider } from "./../../../src/helper/GenericRateProvider.sol"; +import { SWBTC } from "./../../../src/helper/Constants.sol"; + +import "forge-std/Test.sol"; + +abstract contract GenericRateProviderTest is Test { + GenericRateProvider rateProvider; + address target; + bytes4 selector; + bytes32 staticArgument0; + bytes32 staticArgument1; + bytes32 staticArgument2; + bytes32 staticArgument3; + + uint8 decimals; + + function setUp() public virtual { + vm.createSelectFork(vm.envString(_getRpcUrl())); + + _initialize(); + + require(address(rateProvider) != address(0), "rate provider not set"); + require(decimals > 0, "decimals not set"); + require(target != address(0), "target not set"); + require(bytes4(selector).length > 0, "selector not set"); + } + + function test_GetRateWithinExpectedBounds() public { + uint256 rate = rateProvider.getRate(); + (uint256 min, uint256 max) = _expectedRateMinMax(); + + require(rate >= min, "rate must be greater than or equal to min"); + require(rate <= max, "rate must be less than or equal to max"); + } + + function _initialize() public virtual; + + function _expectedRateMinMax() public virtual returns (uint256, uint256); + + function _getRpcUrl() public pure virtual returns (string memory); +} + +contract SwBtcRateProviderTest is GenericRateProviderTest { + function _initialize() public override { + target = SWBTC; + selector = bytes4(keccak256("pricePerShare()")); + decimals = 8; + staticArgument0 = bytes32(uint256(123)); + + rateProvider = new GenericRateProvider(target, selector, staticArgument0, 0, 0, 0, 0, 0, 0, 0); + } + + function _expectedRateMinMax() public view override returns (uint256 min, uint256 max) { + min = 1 * 10 ** decimals; + max = 1 * 10 ** decimals; + } + + function _getRpcUrl() public pure override returns (string memory) { + return "MAINNET_RPC_URL"; + } +}