diff --git a/.env.example b/.env.example deleted file mode 100644 index 42cb916..0000000 --- a/.env.example +++ /dev/null @@ -1,12 +0,0 @@ -DEPLOYER_PRIVATE_KEY= -LOCAL_DEPLOYER_PRIVATE_KEY= - -# rpc urls -API_KEY_NODE_REAL= -MAINNET_RPC_URL= -PROVIDER_URL_TESTNET= -POLYGON_ZKEVM_RPC_URL=https://zkevm-rpc.com - -# chain explorer api key for contract verification -ETHERSCAN_API_KEY= -POLYSCAN_ZKEVM_API_KEY= \ No newline at end of file diff --git a/.openzeppelin/goerli.json b/.openzeppelin/goerli.json deleted file mode 100644 index 20d181b..0000000 --- a/.openzeppelin/goerli.json +++ /dev/null @@ -1,828 +0,0 @@ -{ - "manifestVersion": "3.2", - "admin": { - "address": "0xa6A6b35d84B20077c6f3d30b86547fF837260407" - }, - "proxies": [ - { - "address": "0xb4EA9175e99232560ac5dC2Bcbe4d7C833a15D56", - "kind": "transparent" - }, - { - "address": "0x6d7888Bc794C1104C64c28F4e849B7AE68231b6d", - "kind": "transparent" - }, - { - "address": "0xd51d846ba5032b9284b12850373ae2f053f977b3", - "kind": "transparent" - }, - { - "address": "0xE92Ca437CA55AAbED0CBFFe398e384B997D4CCe9", - "kind": "transparent" - }, - { - "address": "0x750604fAbF4828d1CaA19022238bc8C0DD6C50D5", - "kind": "transparent" - }, - { - "address": "0x6DA0235202D9443674abe6d0355AdD147B6396A2", - "kind": "transparent" - }, - { - "address": "0x560B95A0Ba942A7E15645F655731244680fA030B", - "kind": "transparent" - } - ], - "impls": { - "2adfd43d16d602635934ceff3d9d7838e20c327dc2d5915ce11ca0138a9e56a8": { - "address": "0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "lrtConfig", - "offset": 2, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "_balances", - "offset": 0, - "slot": "51", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40" - }, - { - "label": "_allowances", - "offset": 0, - "slot": "52", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42" - }, - { - "label": "_totalSupply", - "offset": 0, - "slot": "53", - "type": "t_uint256", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" - }, - { - "label": "_name", - "offset": 0, - "slot": "54", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:46" - }, - { - "label": "_symbol", - "offset": 0, - "slot": "55", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:47" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)45_storage", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:376" - }, - { - "label": "_paused", - "offset": 0, - "slot": "101", - "type": "t_bool", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_uint256)45_storage": { - "label": "uint256[45]", - "numberOfBytes": "1440" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_mapping(t_address,t_uint256))": { - "label": "mapping(address => mapping(address => uint256))", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "627a5196c7edcc8832ffaf142705cf20e406cde76956390cf9376afc2b760771": { - "address": "0x673a669425457bCabeb247f56552A0Fd8141cee2", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC165Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" - }, - { - "label": "_roles", - "offset": 0, - "slot": "101", - "type": "t_mapping(t_bytes32,t_struct(RoleData)34_storage)", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:62" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:260" - }, - { - "label": "tokenMap", - "offset": 0, - "slot": "151", - "type": "t_mapping(t_bytes32,t_address)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:15" - }, - { - "label": "contractMap", - "offset": 0, - "slot": "152", - "type": "t_mapping(t_bytes32,t_address)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:16" - }, - { - "label": "isSupportedAsset", - "offset": 0, - "slot": "153", - "type": "t_mapping(t_address,t_bool)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:17" - }, - { - "label": "depositLimitByAsset", - "offset": 0, - "slot": "154", - "type": "t_mapping(t_address,t_uint256)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:18" - }, - { - "label": "assetStrategy", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_address,t_address)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:19" - }, - { - "label": "supportedAssetList", - "offset": 0, - "slot": "156", - "type": "t_array(t_address)dyn_storage", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:21" - }, - { - "label": "rsETH", - "offset": 0, - "slot": "157", - "type": "t_address", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:23" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_address)dyn_storage": { - "label": "address[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_address)": { - "label": "mapping(address => address)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_address)": { - "label": "mapping(bytes32 => address)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_struct(RoleData)34_storage)": { - "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", - "numberOfBytes": "32" - }, - "t_struct(RoleData)34_storage": { - "label": "struct AccessControlUpgradeable.RoleData", - "members": [ - { - "label": "members", - "type": "t_mapping(t_address,t_bool)", - "offset": 0, - "slot": "0" - }, - { - "label": "adminRole", - "type": "t_bytes32", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "a8a6b2c3bd5db5c9dbdd07ceddddc900d8f8019fa0423617119ce622cc8b017b": { - "address": "0x8D9CD771c51b7F6217E0000c1C735F05aDbE6594", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "_paused", - "offset": 0, - "slot": "51", - "type": "t_bool", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "52", - "type": "t_array(t_uint256)49_storage", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" - }, - { - "label": "_status", - "offset": 0, - "slot": "101", - "type": "t_uint256", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" - }, - { - "label": "maxNodeDelegatorLimit", - "offset": 0, - "slot": "151", - "type": "t_uint256", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:20" - }, - { - "label": "minAmountToDeposit", - "offset": 0, - "slot": "152", - "type": "t_uint256", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:21" - }, - { - "label": "isNodeDelegator", - "offset": 0, - "slot": "153", - "type": "t_mapping(t_address,t_uint256)", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:23" - }, - { - "label": "nodeDelegatorQueue", - "offset": 0, - "slot": "154", - "type": "t_array(t_address)dyn_storage", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:24" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_address)dyn_storage": { - "label": "address[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "ced48692d9627de5151bfa4d5451b7fd07186b3b8556632df6155efa69af0512": { - "address": "0x8E2fe2f55f295F3f141213789796fa79E709eF23", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "assetPriceOracle", - "offset": 0, - "slot": "1", - "type": "t_mapping(t_address,t_address)", - "contract": "LRTOracle", - "src": "contracts/LRTOracle.sol:20" - }, - { - "label": "rsETHPrice", - "offset": 0, - "slot": "2", - "type": "t_uint256", - "contract": "LRTOracle", - "src": "contracts/LRTOracle.sol:21" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_address)": { - "label": "mapping(address => address)", - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "dde6002f9466d5b9941650d5dffc789a220b02875ffa09a9ff87b8e83c9359e6": { - "address": "0x2Ad42D71f65F76860FCE2C39032dEf101422b3f7", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "assetPriceFeed", - "offset": 0, - "slot": "1", - "type": "t_mapping(t_address,t_address)", - "contract": "ChainlinkPriceOracle", - "src": "contracts/oracles/ChainlinkPriceOracle.sol:30" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_address)": { - "label": "mapping(address => address)", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "9e916354ed31bb6e2a6af348628e97d1b14e274b3a5228e8cbea48ea8b505f6e": { - "address": "0xf1BED40dbeE8FC0F324FA06322f2Bbd62d11c97d", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "ethXStakePoolsManagerProxyAddress", - "offset": 2, - "slot": "0", - "type": "t_address", - "contract": "EthXPriceOracle", - "src": "contracts/oracles/EthXPriceOracle.sol:20" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "0e3647e2bb0d9137c43bd6837f539a261d03295571bbecb895b380a13ae9ecbb": { - "address": "0xCF07765DA4A6D953764565309092F2026bc951c5", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "_paused", - "offset": 0, - "slot": "51", - "type": "t_bool", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "52", - "type": "t_array(t_uint256)49_storage", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" - }, - { - "label": "_status", - "offset": 0, - "slot": "101", - "type": "t_uint256", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" - }, - { - "label": "eigenPod", - "offset": 0, - "slot": "151", - "type": "t_contract(IEigenPod)5757", - "contract": "NodeDelegator", - "src": "contracts/NodeDelegator.sol:23" - }, - { - "label": "stakedButNotVerifiedEth", - "offset": 0, - "slot": "152", - "type": "t_uint256", - "contract": "NodeDelegator", - "src": "contracts/NodeDelegator.sol:26" - } - ], - "types": { - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(IEigenPod)5757": { - "label": "contract IEigenPod", - "numberOfBytes": "20" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - } - } -} diff --git a/.openzeppelin/mainnet.json b/.openzeppelin/mainnet.json deleted file mode 100644 index c7700a3..0000000 --- a/.openzeppelin/mainnet.json +++ /dev/null @@ -1,828 +0,0 @@ -{ - "manifestVersion": "3.2", - "admin": { - "address": "0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78" - }, - "proxies": [ - { - "address": "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7", - "kind": "transparent" - }, - { - "address": "0x947Cb49334e6571ccBFEF1f1f1178d8469D65ec7", - "kind": "transparent" - }, - { - "address": "0x036676389e48133B63a802f8635AD39E752D375D", - "kind": "transparent" - }, - { - "address": "0x349A73444b1a310BAe67ef67973022020d70020d", - "kind": "transparent" - }, - { - "address": "0x78C12ccE8346B936117655Dd3D70a2501Fd3d6e6", - "kind": "transparent" - }, - { - "address": "0x3D08ccb47ccCde84755924ED6B0642F9aB30dFd2", - "kind": "transparent" - }, - { - "address": "0x07b96Cf1183C9BFf2E43Acf0E547a8c4E4429473", - "kind": "transparent" - } - ], - "impls": { - "2adfd43d16d602635934ceff3d9d7838e20c327dc2d5915ce11ca0138a9e56a8": { - "address": "0x8E2fe2f55f295F3f141213789796fa79E709eF23", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "lrtConfig", - "offset": 2, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "_balances", - "offset": 0, - "slot": "51", - "type": "t_mapping(t_address,t_uint256)", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:40" - }, - { - "label": "_allowances", - "offset": 0, - "slot": "52", - "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:42" - }, - { - "label": "_totalSupply", - "offset": 0, - "slot": "53", - "type": "t_uint256", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" - }, - { - "label": "_name", - "offset": 0, - "slot": "54", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:46" - }, - { - "label": "_symbol", - "offset": 0, - "slot": "55", - "type": "t_string_storage", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:47" - }, - { - "label": "__gap", - "offset": 0, - "slot": "56", - "type": "t_array(t_uint256)45_storage", - "contract": "ERC20Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:376" - }, - { - "label": "_paused", - "offset": 0, - "slot": "101", - "type": "t_bool", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_uint256)45_storage": { - "label": "uint256[45]", - "numberOfBytes": "1440" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_mapping(t_address,t_uint256))": { - "label": "mapping(address => mapping(address => uint256))", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_string_storage": { - "label": "string", - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "627a5196c7edcc8832ffaf142705cf20e406cde76956390cf9376afc2b760771": { - "address": "0x8D9CD771c51b7F6217E0000c1C735F05aDbE6594", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC165Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" - }, - { - "label": "_roles", - "offset": 0, - "slot": "101", - "type": "t_mapping(t_bytes32,t_struct(RoleData)34_storage)", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:62" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:260" - }, - { - "label": "tokenMap", - "offset": 0, - "slot": "151", - "type": "t_mapping(t_bytes32,t_address)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:15" - }, - { - "label": "contractMap", - "offset": 0, - "slot": "152", - "type": "t_mapping(t_bytes32,t_address)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:16" - }, - { - "label": "isSupportedAsset", - "offset": 0, - "slot": "153", - "type": "t_mapping(t_address,t_bool)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:17" - }, - { - "label": "depositLimitByAsset", - "offset": 0, - "slot": "154", - "type": "t_mapping(t_address,t_uint256)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:18" - }, - { - "label": "assetStrategy", - "offset": 0, - "slot": "155", - "type": "t_mapping(t_address,t_address)", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:19" - }, - { - "label": "supportedAssetList", - "offset": 0, - "slot": "156", - "type": "t_array(t_address)dyn_storage", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:21" - }, - { - "label": "rsETH", - "offset": 0, - "slot": "157", - "type": "t_address", - "contract": "LRTConfig", - "src": "contracts/LRTConfig.sol:23" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_address)dyn_storage": { - "label": "address[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_address)": { - "label": "mapping(address => address)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_address)": { - "label": "mapping(bytes32 => address)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_struct(RoleData)34_storage)": { - "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", - "numberOfBytes": "32" - }, - "t_struct(RoleData)34_storage": { - "label": "struct AccessControlUpgradeable.RoleData", - "members": [ - { - "label": "members", - "type": "t_mapping(t_address,t_bool)", - "offset": 0, - "slot": "0" - }, - { - "label": "adminRole", - "type": "t_bytes32", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "a8a6b2c3bd5db5c9dbdd07ceddddc900d8f8019fa0423617119ce622cc8b017b": { - "address": "0x2Ad42D71f65F76860FCE2C39032dEf101422b3f7", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "_paused", - "offset": 0, - "slot": "51", - "type": "t_bool", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "52", - "type": "t_array(t_uint256)49_storage", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" - }, - { - "label": "_status", - "offset": 0, - "slot": "101", - "type": "t_uint256", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" - }, - { - "label": "maxNodeDelegatorLimit", - "offset": 0, - "slot": "151", - "type": "t_uint256", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:20" - }, - { - "label": "minAmountToDeposit", - "offset": 0, - "slot": "152", - "type": "t_uint256", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:21" - }, - { - "label": "isNodeDelegator", - "offset": 0, - "slot": "153", - "type": "t_mapping(t_address,t_uint256)", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:23" - }, - { - "label": "nodeDelegatorQueue", - "offset": 0, - "slot": "154", - "type": "t_array(t_address)dyn_storage", - "contract": "LRTDepositPool", - "src": "contracts/LRTDepositPool.sol:24" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_address)dyn_storage": { - "label": "address[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_uint256)": { - "label": "mapping(address => uint256)", - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "ced48692d9627de5151bfa4d5451b7fd07186b3b8556632df6155efa69af0512": { - "address": "0xf1BED40dbeE8FC0F324FA06322f2Bbd62d11c97d", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "assetPriceOracle", - "offset": 0, - "slot": "1", - "type": "t_mapping(t_address,t_address)", - "contract": "LRTOracle", - "src": "contracts/LRTOracle.sol:20" - }, - { - "label": "rsETHPrice", - "offset": 0, - "slot": "2", - "type": "t_uint256", - "contract": "LRTOracle", - "src": "contracts/LRTOracle.sol:21" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_address)": { - "label": "mapping(address => address)", - "numberOfBytes": "32" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "dde6002f9466d5b9941650d5dffc789a220b02875ffa09a9ff87b8e83c9359e6": { - "address": "0xD73Cd1aaE045653474B873f3275BA2BE2744c8B4", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "assetPriceFeed", - "offset": 0, - "slot": "1", - "type": "t_mapping(t_address,t_address)", - "contract": "ChainlinkPriceOracle", - "src": "contracts/oracles/ChainlinkPriceOracle.sol:30" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_address)": { - "label": "mapping(address => address)", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "9e916354ed31bb6e2a6af348628e97d1b14e274b3a5228e8cbea48ea8b505f6e": { - "address": "0x0379E85188BC416A1D43Ab04b28F38B5c63F129E", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "ethXStakePoolsManagerProxyAddress", - "offset": 2, - "slot": "0", - "type": "t_address", - "contract": "EthXPriceOracle", - "src": "contracts/oracles/EthXPriceOracle.sol:20" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - }, - "0e3647e2bb0d9137c43bd6837f539a261d03295571bbecb895b380a13ae9ecbb": { - "address": "0xeD510dea149D14c1EB5f973004E0111afdb3B179", - "layout": { - "solcVersion": "0.8.21", - "storage": [ - { - "label": "lrtConfig", - "offset": 0, - "slot": "0", - "type": "t_contract(ILRTConfig)5923", - "contract": "LRTConfigRoleChecker", - "src": "contracts/utils/LRTConfigRoleChecker.sol:14" - }, - { - "label": "_initialized", - "offset": 20, - "slot": "0", - "type": "t_uint8", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:63", - "retypedFrom": "bool" - }, - { - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:68" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "_paused", - "offset": 0, - "slot": "51", - "type": "t_bool", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:29" - }, - { - "label": "__gap", - "offset": 0, - "slot": "52", - "type": "t_array(t_uint256)49_storage", - "contract": "PausableUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol:116" - }, - { - "label": "_status", - "offset": 0, - "slot": "101", - "type": "t_uint256", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:38" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "ReentrancyGuardUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol:88" - }, - { - "label": "eigenPod", - "offset": 0, - "slot": "151", - "type": "t_contract(IEigenPod)5757", - "contract": "NodeDelegator", - "src": "contracts/NodeDelegator.sol:23" - }, - { - "label": "stakedButNotVerifiedEth", - "offset": 0, - "slot": "152", - "type": "t_uint256", - "contract": "NodeDelegator", - "src": "contracts/NodeDelegator.sol:26" - } - ], - "types": { - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_contract(IEigenPod)5757": { - "label": "contract IEigenPod", - "numberOfBytes": "20" - }, - "t_contract(ILRTConfig)5923": { - "label": "contract ILRTConfig", - "numberOfBytes": "20" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - }, - "t_uint8": { - "label": "uint8", - "numberOfBytes": "1" - } - }, - "namespaces": {} - } - } - } -} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 3b594a3..0000000 --- a/.prettierignore +++ /dev/null @@ -1,21 +0,0 @@ -# directories -broadcast -cache -cache_forge -coverage -lib -node_modules -out -.vscode -.solhint.json - -# files -*.env -*.log -.DS_Store -lcov.info -package-lock.json -yarn.lock - -# readme files -*.md \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 44c8b9a..0000000 --- a/.prettierrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "bracketSpacing": true, - "printWidth": 120, - "proseWrap": "always", - "singleQuote": false, - "tabWidth": 2, - "trailingComma": "all", - "useTabs": false -} diff --git a/.solhint.json b/.solhint.json deleted file mode 100644 index 3c6bd75..0000000 --- a/.solhint.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "solhint:recommended", - "rules": { - "code-complexity": [ - "error", - 8 - ], - "compiler-version": [ - "error", - ">=0.8.21" - ], - "func-name-mixedcase": "off", - "func-visibility": [ - "error", - { - "ignoreConstructors": true - } - ], - "max-line-length": [ - "error", - 180 - ], - "named-parameters-mapping": "warn", - "no-console": "off", - "not-rely-on-time": "off", - "one-contract-per-file": "off" - } -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index eb8dc8c..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "editor.formatOnSave": true, - "editor.tabSize": 4, - "[json]": { - "editor.formatOnSave": false, - "editor.tabSize": 2 - }, - "[toml]": { - "editor.defaultFormatter": "tamasfe.even-better-toml" - }, - "npm.exclude": "**/lib/**", - "solidity.packageDefaultDependenciesContractsDirectory": "contracts", - "solidity.packageDefaultDependenciesDirectory": "lib", - "[solidity]": { - "editor.defaultFormatter": "JuanBlanco.solidity" - }, - "solidity.formatter": "forge", - "solidity.compileUsingRemoteVersion": "v0.8.21", -} diff --git a/Makefile b/Makefile deleted file mode 100644 index a3553e4..0000000 --- a/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# include .env file and export its env vars -# (-include to ignore error if it does not exist) -# Note that any unset variables here will wipe the variables if they are set in -# .zshrc or .bashrc. Make sure that the variables are set in .env, especially if -# you're running into issues with fork tests --include .env - -# forge coverage - -coverage :; forge coverage --report lcov && lcov --remove lcov.info -o lcov.info 'test/*' 'script/*' - -# deployment commands -deploy-lrt-testnet :; forge script script/foundry-scripts/DeployLRT.s.sol:DeployLRT --rpc-url goerli --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -deploy-lrt-mainnet :; forge script script/foundry-scripts/DeployLRT.s.sol:DeployLRT --rpc-url ${MAINNET_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -deploy-lrt-local-test :; forge script script/foundry-scripts/DeployLRT.s.sol:DeployLRT --rpc-url localhost --private-key ${LOCAL_DEPLOYER_PRIVATE_KEY} --broadcast -vvv - -# deployment commands:LRTDepositPool -deploy-lrt-depositPool-testnet :; forge script script/foundry-scripts/DeployLRTDepositPool.s.sol:DeployLRTDepositPool --rpc-url goerli --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -deploy-lrt-depositPool-mainnet :; forge script script/foundry-scripts/DeployLRTDepositPool.s.sol:DeployLRTDepositPool --rpc-url ${MAINNET_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -deploy-lrt-depositPool-local-test :; forge script script/foundry-scripts/DeployLRTDepositPool.s.sol:DeployLRTDepositPool --rpc-url localhost --private-key ${LOCAL_DEPLOYER_PRIVATE_KEY} --broadcast -vvv - -# deployment commands:RSETHRate -deploy-rseth-rate-provider :; forge script script/foundry-scripts/cross-chain/RSETHRate.s.sol:DeployRSETHRateProvider --rpc-url ${MAINNET_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -deploy-rseth-rate-receiver :; forge script script/foundry-scripts/cross-chain/RSETHRate.s.sol:DeployRSETHRateReceiver --rpc-url ${POLYGON_ZKEVM_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${POLYSCAN_ZKEVM_API_KEY} --verify -vvv - -deploy-rseth-rate-local-test :; forge script script/foundry-scripts/cross-chain/RSETHRate.s.sol:DeployRSETHRateReceiver --rpc-url localhost --private-key ${LOCAL_DEPLOYER_PRIVATE_KEY} --broadcast -vvv - -# upgrade commands -upgrade-lrt-testnet :; forge script script/foundry-scripts/UpgradeLRT.s.sol:UpgradeLRT --rpc-url goerli --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -upgrade-lrt-mainnet :; forge script script/foundry-scripts/UpgradeLRT.s.sol:UpgradeLRT --rpc-url ${MAINNET_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify -vvv - -upgrade-lrt-local-test :; forge script script/foundry-scripts/UpgradeLRT.s.sol:UpgradeLRT --rpc-url localhost --private-key ${LOCAL_DEPLOYER_PRIVATE_KEY} --broadcast -vvv - -# verify commands -## example: contractAddress= contractPath= make verify-lrt-proxy-testnet -## example: contractAddress=0xE7b647ab9e0F49093926f06E457fa65d56cb456e contractPath=contracts/LRTConfig.sol:LRTConfig make verify-lrt-proxy-testnet -verify-lrt-proxy-testnet :; forge verify-contract --chain-id 5 --watch --etherscan-api-key ${GOERLI_ETHERSCAN_API_KEY} ${contractAddress} ${contractPath} - -verify-lrt-proxy-mainnet :; forge verify-contract --chain-id 1 --watch --etherscan-api-key ${ETHERSCAN_API_KEY} ${contractAddress} ${contractPath} diff --git a/README.md b/README.md index 90d6efa..cef0655 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,43 @@ # LRT-rsETH +Kelp DAO (https://www.kelpdao.xyz/restake/) is liquid restaking protocol currently building on top of EigenLayer. +It gives users access to multiple benefits like restaking rewards, staking rewards, DeFi and liquidity. + +## Table of Content + +- [Build - Deploy - Verify - Test](#getting-started) + - [Setup](#setup) + - [Build](#develop) + - [Deploy](#deploy) + - [Verify](#verify-contracts) + - [Test](#test) +- [Deployed Contracts](#deployed-contracts) + - [Goerli Testnet](#goerli-testnet) + - [Ethereum](#eth-mainnet) + - [Arbitrum](#arbitrum) + - [Manta](#manta) + - [Mode](#mode) + - [Blast](#blast) + - [Base](#base) + - [Optimism](#optimism) + - [Scroll](#scroll) + - [Linea](#linea) + - [XLayer](#xlayer) + - [ZKSync](#zksync) +- [Safe Multisigs](#safe-multisigs) +- [Bridged RSETH](#bridged-rseth) + - [CCIP (Chainlink)](#ccip-chainlink-rseth) + - [LayerZero OFT](#layerzero-oft-rseth) +- [RSETH Rate Providers](#rseth-pricerate-providers) + +. +. + +# Getting Started + ## Setup -1. Install dependencies +Install dependencies ```bash npm install @@ -10,13 +45,13 @@ npm install forge install ``` -2. copy .env.example to .env and fill in the values +copy .env.example to .env and fill in the values ```bash cp .env.example .env ``` -## Usage +## Develop This is a list of the most frequently needed commands. @@ -36,23 +71,42 @@ Compile the contracts: $ forge build ``` -### Coverage +### Format + +Format the contracts: + +```sh +$ forge fmt +``` + +### Gas Usage + +Get a gas report: + +```sh +$ forge test --gas-report +``` + +### Lint -Get a test coverage report: +Lint the contracts: ```sh -$ forge coverage +$ npm run lint ``` -### Deploy +## Deploy + +Check `Makefile` to see a list of deploy commands for different use-cases. +Below are few sample deploy commands. -## Deploy to testnet +### Deploy to testnet ```bash make deploy-lrt-testnet ``` -## Deploy to Anvil: +### Deploy to Anvil: ```bash make deploy-lrt-local-test @@ -71,43 +125,34 @@ $ forge script script/Deploy.s.sol --broadcast --fork-url http://localhost:8545 For instructions on how to deploy to a testnet or mainnet, check out the [Solidity Scripting](https://book.getfoundry.sh/tutorials/solidity-scripting.html) tutorial. - ## Verify Contracts Follow this pattern `contractAddress= contractPath= make verify-lrt-proxy-testnet` Example: + ```bash contractAddress=0xE7b647ab9e0F49093926f06E457fa65d56cb456e contractPath=contracts/LRTConfig.sol:LRTConfig make verify-lrt-proxy-testnet ``` +Verify contracts on Blockscout -### Format - -Format the contracts: - -```sh -$ forge fmt -``` - -### Gas Usage - -Get a gas report: +1. Flatten contract and copy to clipboard -```sh -$ forge test --gas-report +```bash + forge flatten contracts/LRTConfig.sol:LRTConfig | pbcopy ``` -### Lint - -Lint the contracts: +2. Go to Blockscout and click on the contract address +3. Click on the `Contract` tab +4. Click on `Verify and Publish` button +5. Paste the flattened contract in the `Contract Code` field +6. Click on `Verify and Publish` button -```sh -$ npm lint -``` +Note: you may need to find the exact EVM compiler for the contract, e.g. Paris, Shaghai, etc -### Test +## Test Run the tests: @@ -128,94 +173,349 @@ simply copy paste the path): $ npm test:coverage:report ``` -## Deployed Contracts - -### Goerli testnet - -| Contract Name | Address | -|-------------------------|------------------------------------------------| -| ProxyFactory | 0x4ae77FdfB3BBBe99598CAfaE4c369b604b6d9e02 | -| ProxyAdmin | 0xa6A6b35d84B20077c6f3d30b86547fF837260407 | -| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | - -### Contract Implementations -| Contract Name | Implementation Address | -|-------------------------|------------------------------------------------| -| LRTConfig | 0x673a669425457bCabeb247f56552A0Fd8141cee2 | -| RSETH | 0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78 | -| LRTDepositPool | 0x8D9CD771c51b7F6217E0000c1C735F05aDbE6594 | -| LRTOracle | 0x8E2fe2f55f295F3f141213789796fa79E709eF23 | -| ChainlinkPriceOracle | 0x2Ad42D71f65F76860FCE2C39032dEf101422b3f7 | -| EthXPriceOracle | 0xf1BED40dbeE8FC0F324FA06322f2Bbd62d11c97d | -| NodeDelegator | 0xD73Cd1aaE045653474B873f3275BA2BE2744c8B4 | - -### Proxy Addresses -| Contract Name | Proxy Address | -|-------------------------|------------------------------------------------| -| LRTConfig | 0x6d7888Bc794C1104C64c28F4e849B7AE68231b6d | -| RSETH | 0xb4EA9175e99232560ac5dC2Bcbe4d7C833a15D56 | -| LRTDepositPool | 0xd51d846ba5032b9284b12850373ae2f053f977b3 | -| LRTOracle | 0xE92Ca437CA55AAbED0CBFFe398e384B997D4CCe9 | -| ChainlinkPriceOracle | 0x750604fAbF4828d1CaA19022238bc8C0DD6C50D5 | -| EthXPriceOracle | 0x6DA0235202D9443674abe6d0355AdD147B6396A2 | +## Using Static Analyzer for the contracts + +Lib used [Aderyn](https://docs.cyfrin.io/) + +- Installation + +```bash +cargo install aderyn +``` + +- Run the static analysis + +```bash +aderyn [Option] [Path] +``` + +Example: + +```bash +aderyn -s contracts/FeeReceiver.sol +``` + +See List of options [here](https://docs.cyfrin.io/aderyn-static-analyzer/cli-options) +or run `aderyn --help` + +. +. + +# Deployed Contracts + +## Goerli testnet + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x4ae77FdfB3BBBe99598CAfaE4c369b604b6d9e02 | +| ProxyAdmin | 0xa6A6b35d84B20077c6f3d30b86547fF837260407 | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| -------------------- | ------------------------------------------ | +| LRTConfig | 0x6d7888Bc794C1104C64c28F4e849B7AE68231b6d | +| RSETH | 0xb4EA9175e99232560ac5dC2Bcbe4d7C833a15D56 | +| LRTDepositPool | 0xd51d846ba5032b9284b12850373ae2f053f977b3 | +| LRTOracle | 0xE92Ca437CA55AAbED0CBFFe398e384B997D4CCe9 | +| ChainlinkPriceOracle | 0x750604fAbF4828d1CaA19022238bc8C0DD6C50D5 | +| EthXPriceOracle | 0x6DA0235202D9443674abe6d0355AdD147B6396A2 | ### NodeDelegator Proxy Addresses + - NodeDelegator proxy 1: 0x560B95A0Ba942A7E15645F655731244680fA030B - NodeDelegator proxy 2: 0x32c1329fE006CDE9dac246293135E98e0070Afa0 - NodeDelegator proxy 3: 0x5520e0ECE7a82a72325417732131dbeCe0b5F0Fb - NodeDelegator proxy 4: 0x385C2636bAe9145eb9A52a05A58f181440c2fcE3 - NodeDelegator proxy 5: 0x8C58090994913Cb3cb017F544156d76F6c42F37c - -### ETH Mainnet - -| Contract Name | Address | -|-------------------------|------------------------------------------------| -| ProxyFactory | 0x673a669425457bCabeb247f56552A0Fd8141cee2 | -| ProxyAdmin | 0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78 | -| ProxyAdmin Owner | 0xb9577E83a6d9A6DE35047aa066E3758221FE0DA2  | - -### Contract Implementations -| Contract Name | Implementation Address | -|-------------------------|------------------------------------------------| -| LRTConfig | 0x8D9CD771c51b7F6217E0000c1C735F05aDbE6594 | -| RSETH | 0x8E2fe2f55f295F3f141213789796fa79E709eF23 | -| LRTDepositPool | 0x2Ad42D71f65F76860FCE2C39032dEf101422b3f7 | -| LRTOracle | 0xf1BED40dbeE8FC0F324FA06322f2Bbd62d11c97d | -| ChainlinkPriceOracle | 0xD73Cd1aaE045653474B873f3275BA2BE2744c8B4 | -| EthXPriceOracle | 0x0379E85188BC416A1D43Ab04b28F38B5c63F129E | -| SfrxETHPriceOracle | 0xD7DB9604EF925aF96CDa6B45026Be64C691C7704 | -| NodeDelegator | 0xeD510dea149D14c1EB5f973004E0111afdb3B179 | - -### Proxy Addresses -| Contract Name | Proxy Address | -|-------------------------|------------------------------------------------| -| LRTConfig | 0x947Cb49334e6571ccBFEF1f1f1178d8469D65ec7 | -| RSETH | 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7 | -| LRTDepositPool | 0x036676389e48133B63a802f8635AD39E752D375D | -| LRTOracle | 0x349A73444b1a310BAe67ef67973022020d70020d | -| ChainlinkPriceOracle | 0x78C12ccE8346B936117655Dd3D70a2501Fd3d6e6 | -| SfrxETHPriceOracle | 0x8546A7C8C3C537914C3De24811070334568eF427 | -| EthXPriceOracle | 0x3D08ccb47ccCde84755924ED6B0642F9aB30dFd2 | +## ETH Mainnet + +| Contract Name | Address | +| ----------------- | ------------------------------------------ | +| ProxyFactory | 0x673a669425457bCabeb247f56552A0Fd8141cee2 | +| ProxyAdmin | 0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78 | +| ProxyAdmin Owner | 0x49bD9989E31aD35B0A62c20BE86335196A3135B1 | +| TimeLock | 0x49bD9989E31aD35B0A62c20BE86335196A3135B1 | +| Timelock Proposer | 0xb3696a817D01C8623E66D156B6798291fa10a46d | + +| Contract Name | Proxy Address | +| -------------------- | ------------------------------------------ | +| LRTConfig | 0x947Cb49334e6571ccBFEF1f1f1178d8469D65ec7 | +| RSETH | 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7 | +| LRTDepositPool | 0x036676389e48133B63a802f8635AD39E752D375D | +| LRTOracle | 0x349A73444b1a310BAe67ef67973022020d70020d | +| ChainlinkPriceOracle | 0x78C12ccE8346B936117655Dd3D70a2501Fd3d6e6 | +| SfrxETHPriceOracle | 0x8546A7C8C3C537914C3De24811070334568eF427 | +| EthXPriceOracle | 0x3D08ccb47ccCde84755924ED6B0642F9aB30dFd2 | +| SwETHPriceOracle | 0xCB8f20a144bFA15066148A1F29F1091d15B25f93 | +| RETHPriceOracle | 0x585839c360872731Fc271183b9F703654ce08275 | +| FeeReceiver | 0xdbC3363De051550D122D9C623CBaff441AFb477C | +| KelpEarnedPoint | 0x8E3A59427B1D87Db234Dd4ff63B25E4BF94672f4 | +| MerkleDistributor | 0x2DDB11443bD9Ceb92d4951A05f55eb7096EB53d3 | +| LRTConverter | 0x598dbcb99711E5577fF76ef4577417197B939Dfa | +| LRTWithdrawalManager | 0x62De59c08eB5dAE4b7E6F7a8cAd3006d6965ec16 | +| LRTUnstakingVault | 0xc66830E2667bc740c0BED9A71F18B14B8c8184bA | ### NodeDelegator Proxy Addresses + - NodeDelegator proxy index 0: 0x07b96Cf1183C9BFf2E43Acf0E547a8c4E4429473 - NodeDelegator proxy index 1: 0x429554411C8f0ACEEC899100D3aacCF2707748b3 - NodeDelegator proxy index 2: 0x92B4f5b9ffa1b5DB3b976E89A75E87B332E6e388 - NodeDelegator proxy index 3: 0x9d2Fc9287e1c3A1A814382B40AAB13873031C4ad - NodeDelegator proxy index 4: 0xe8038228ff1aEfD007D7A22C9f08DDaadF8374E4 +- NodeDelegator proxy index 5: 0x049EA11D337f185b1Aa910d98e8Fbd991f0FBA7B +- NodeDelegator proxy index 6: 0x545D69B99759E7b670Df243b882700121d6d3AB9 +- NodeDelegator proxy index 7: 0xee5470E1519972C3eA95249d60EBD064af2D53D3 +- NodeDelegator proxy index 8: 0x4C798C4653b1257D5149910523D7a6eeD5712F83 +- NodeDelegator proxy index 9: 0x79f17234746344E0365D40be50d8d43DB9082c32 +- NodeDelegator proxy index 10: 0x395884D1974a839702bcFCBa176AC7871c788946 +- NodeDelegator proxy index 11: 0xFc561966ceaAa09f4d6CBa4AdD54778c2bF1cB85 + +## Arbitrum + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x81E5c1483c6869e95A4f5B00B41181561278179F | +| ProxyAdmin | 0x4938c803EBe999FB0A5527310662624f2E7A38C1 | +| ProxyAdmin Owner | 0x96D97D66d4290C9182A09470a5775FF90DAf922c | + +| Contract Name | Proxy Address | +| ------------- | ------------------------------------------ | +| RSETHPool | 0x376A7564AF88242D6B8598A5cfdD2E9759711B61 | + +## Manta + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x68A9EC5b93F04a60c77F486a664f283B2E4E2B72 | +| ProxyAdmin | 0x2B1CbD412565c0a2D32E62Ab7304bb464C644cc1 | +| ProxyAdmin Owner | 0x84efef1439f1b6f264866f65062ba49df764be08 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0x9dd4f9EeE9B05D1ebec1d4aAE7Ae9F5d8D235CD4 | + +## Mode + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x30c2B5f5c74B855d99792E485bDBcE1dD2f2e1A9 | +| ProxyAdmin | 0x68A9EC5b93F04a60c77F486a664f283B2E4E2B72 | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0xe7903B1F75C534Dd8159b313d92cDCfbC62cB3Cd | +| RSETHPoolV2 | 0xbDf612E616432AA8e8D7d8cC1A9c934025371c5C | + +## Blast + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x30c2B5f5c74B855d99792E485bDBcE1dD2f2e1A9 | +| ProxyAdmin | 0x68A9EC5b93F04a60c77F486a664f283B2E4E2B72 | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0xe7903B1F75C534Dd8159b313d92cDCfbC62cB3Cd | +| RSETHPoolV2 | 0x1558959f1a032F83f24A14Ff539944A926C51bdf | + +## Base + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0xAd6626758Bd6d2e6f68Da203087248f59ca4fB97 | +| ProxyAdmin | 0xDf3f5926Fd14Ed048B04941189da54BdEDD478d0 | +| ProxyAdmin Owner | 0x7Da95539762Dd11005889F6B72a6674A4888B56d | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0xEDfa23602D0EC14714057867A78d01e94176BEA0 | +| RSETHPoolV2 | 0x291088312150482826b3A37d5A69a4c54DAa9118 | + +## Optimism + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x5c6AB8B02b29cd205580C02681d27Cb6246eEFbc | +| ProxyAdmin | 0xa465eAfAfEE5629eE92832e14C37df4723816d58 | +| ProxyAdmin Owner | 0x0d30A563e38Fe2926b37783A046004A7869adE6C | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0x87eEE96D50Fb761AD85B1c982d28A042169d61b1 | +| RSETHPoolV2 | 0xaAA687e218F9B53183A6AA9639FBD9D6e69EcB73 | + +## Scroll + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x1373A61449C26CC3F48C1B4c547322eDAa36eB12 | +| ProxyAdmin | 0xAD3B3ECd2130AaaB5f1fd9aEC82879Bd8D56742D | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0xa25b25548B4C98B0c7d3d27dcA5D5ca743d68b7F | +| RSETHPoolV2 | 0xb80deaecd7F4Bca934DE201B11a8711644156a0a | + +## Linea + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0x4938c803EBe999FB0A5527310662624f2E7A38C1 | +| ProxyAdmin | 0x352E20158C9916579b337d1332F462B26A8A699c | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0xD2671165570f41BBB3B0097893300b6EB6101E6C | +| RSETHPoolV2 | 0x057297e44A3364139EDCF3e1594d6917eD7688c2 | + +## XLayer + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyFactory | 0xe119D214a6efa7d3cF60e6E59481EDe1B0064A6B | +| ProxyAdmin | 0x3222d3De5A9a3aB884751828903044CC4ADC627e | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0x5A71f5888EE05B36Ded9149e6D32eE93812EE5e9 | +| RSETHPoolV3 | 0x4Ef626efE4a3A279a9DC7e7a91C1c9CaaAE8e159 | + +| Contract Name | Address | +| ------------- | ------------------------------------------ | +| WETHOracle | 0x6F27976308001119a8e89cB447333DaaA3043CE7 | + +## ZKSync + +| Contract Name | Address | +| ---------------- | ------------------------------------------ | +| ProxyAdmin | 0xd836801C07e9b471Fa3c525bc13bC4333c51F25F | +| ProxyAdmin Owner | 0x7AAd74b7f0d60D5867B59dbD377a71783425af47 | + +| Contract Name | Proxy Address | +| ----------------- | ------------------------------------------ | +| RsETHTokenWrapper | 0xd4169E045bcF9a86cC00101225d9ED61D2F51af2 | +| RSETHPoolV2 | 0x41b300f5A619973b20931f0944C85DB229d5E27f | + +. +. + +## Safe Multisigs + +| Name | Safe Address | +| -------------------------- | ------------------------------------------- | +| ETH Mainnet Manager | 0xCbcdd778AA25476F203814214dD3E9b9c46829A1 | +| ETH Mainnet Admin | 0xb9577E83a6d9A6DE35047aa066E3758221FE0DA2  | +| ETH Mainnet External Admin | 0xb3696a817D01C8623E66D156B6798291fa10a46d | +| BSC | 0xb4222155CDB309Ecee1bA64d56c8bAb0475a95b0 | +| Optimism | 0x0d30A563e38Fe2926b37783A046004A7869adE6C | +| Arbitrum | 0x96D97D66d4290C9182A09470a5775FF90DAf922c | +| Polygon ZKEVM | 0x424Fc153C4005F8D5f23E08d94F5203D99E9B160 | +| Manta | 0x84eFeF1439F1b6F264866F65062Ba49Df764bE08 | +| ZkSync | 0xeD38DA849b20Fa27B07D073053C5F5aAe6A2dB6b | +| Base | 0x7Da95539762Dd11005889F6B72a6674A4888B56d | + +. +. + +## Bridged RSETH + +### CCIP (Chainlink) RSETH + +| Network | Address | +| -------- | ------------------------------------------ | +| Arbitrum | 0xe119D214a6efa7d3cF60e6E59481EDe1B0064A6B | +| Optimism | 0x68A9EC5b93F04a60c77F486a664f283B2E4E2B72 | +| BSC | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | + +### LayerZero OFT RSETH + +| Network | Address | +| -------- | ------------------------------------------ | +| Arbitrum | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +| Optimism | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +| Manta | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +| Mode | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +| Blast | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +| Scroll | 0x65421ba909200b81640d98B979d07487C9781B66 | +| Base | 0x1Bc71130A0e39942a7658878169764Bbd8A45993 | + +. +. + +## RSETH Price/Rate Providers + +### ETH Mainnet + +| Contract Name | Proxy Address | +| --------------------------- | ------------------------------------------ | +| RSETHMultiChainRateProvider | 0x0788906B19bA8f8d0e8a7015f0714DF3179D9aB6 | +| RSETHRateProvider | 0xF1cccBa5558D31628216489A1435e068b1fd2C8A | +| OneETHPriceOracle | 0x4cB8d6DCd56d6b371210E70837753F2a835160c4 | +| RSETHPriceFeed (Morph) | 0x4B9C66c2C0d3706AabC6d00D2a6ffD2B68A4E383 | + +### Arbitrum + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x3222d3De5A9a3aB884751828903044CC4ADC627e | + +### Optimism + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x1373A61449C26CC3F48C1B4c547322eDAa36eB12 | + +### Polygon ZKEVM + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHRateProvider on ETH mainnet as provider) | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x30CE1444834dbd91e23317179A39d875B16F0DCd | + +### Blast + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x38dd27B51E2E6868D99B615097c03A3DE7fa7AA8 | + +### Mode + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x38dd27B51E2E6868D99B615097c03A3DE7fa7AA8 | + +### Scroll + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0xc9BcFbB1Bf6dd20Ba365797c1Ac5d39FdBf095Da | + +### Base + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x7781ae9B47FeCaCEAeCc4FcA8d0b6187E3eF9ba7 | + +### Linea + +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x81E5c1483c6869e95A4f5B00B41181561278179F | +### XLayer -### Immutable Contracts -#### ETH Mainnet -| Contract Name | Proxy Address | -|-------------------------|------------------------------------------------| -| RSETHRateProvider | 0xF1cccBa5558D31628216489A1435e068b1fd2C8A | -| OneETHPriceOracle | 0x4cB8d6DCd56d6b371210E70837753F2a835160c4 | -| RSETHPriceFeed (Morph) | 0x4B9C66c2C0d3706AabC6d00D2a6ffD2B68A4E383 | +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x30CE1444834dbd91e23317179A39d875B16F0DCd | -#### Polygon ZKEVM -| Contract Name | Proxy Address | -|-------------------------|------------------------------------------------| -| RSETHRateReceiver | 0x4186BFC76E2E237523CBC30FD220FE055156b41F | +### ZKSync +| Contract Name | Proxy Address | +| ------------------------------------------------------------------------------- | ------------------------------------------ | +| RSETHRateReceiver (Uses RSETHMultiChainRateProvider as provider on ETH mainnet) | 0x6C2e862E7d03e1C9dDa1b30De69b201c7c52e3dB | diff --git a/contracts/FeeReceiver.sol b/contracts/FeeReceiver.sol new file mode 100644 index 0000000..946908f --- /dev/null +++ b/contracts/FeeReceiver.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import { LRTConstants } from "./utils/LRTConstants.sol"; +import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; +import { IFeeReceiver } from "./interfaces/IFeeReceiver.sol"; + +/// @title FeeReceiver +/// @notice Recieves rewards and distributes it +/// @dev also known as RewardReciever Contract in LRTContansts +contract FeeReceiver is IFeeReceiver, Initializable, AccessControlUpgradeable { + address public protocolTreasury; + address public depositPool; + uint256 public protocolFeePercentInBPS; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address _protocolTreasury, + address _depositPool, + uint256 _protocolFeePercentInBPS, + address admin, + address manager + ) + public + initializer + { + if ( + _protocolTreasury == address(0) || _depositPool == address(0) || _protocolFeePercentInBPS == 0 + || admin == address(0) || manager == address(0) + ) { + revert InvalidEmptyValue(); + } + + protocolTreasury = _protocolTreasury; + depositPool = _depositPool; + protocolFeePercentInBPS = _protocolFeePercentInBPS; + + __AccessControl_init(); + + // manager is both the default admin and the MANAGER role + _setupRole(DEFAULT_ADMIN_ROLE, admin); + _setupRole(LRTConstants.MANAGER, manager); + } + + /// @dev fallback to receive funds + receive() external payable { } + + /// @dev receive from NodeDelegator + function receiveFromNodeDelegator() external payable { } + + /// @dev send percentage of the contract's balance to the fee receiver + function sendFunds() external { + uint256 balance = address(this).balance; + uint256 amountToSendToProtocolTreasury = (balance * protocolFeePercentInBPS) / 10_000; + + (bool success,) = protocolTreasury.call{ value: amountToSendToProtocolTreasury }(""); + require(success, "FeeReceiver: failed to send to protocol treasury"); + + // send the remaining balance to the deposit pool + uint256 remainingAmount = address(this).balance; + ILRTDepositPool(depositPool).receiveFromRewardReceiver{ value: remainingAmount }(); + } + + /*////////////////////////////////////////////////////////////// + MANAGER FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Set the fee receiver + /// @param _protocolTreasury Address of the fee receiver + function setProtocolTreasury(address _protocolTreasury) external onlyRole(LRTConstants.MANAGER) { + if (_protocolTreasury == address(0)) revert InvalidEmptyValue(); + + protocolTreasury = _protocolTreasury; + } + + /// @dev Set the deposit pool + /// @param _depositPool Address of the deposit pool + function setDepositPool(address _depositPool) external onlyRole(LRTConstants.MANAGER) { + if (_depositPool == address(0)) revert InvalidEmptyValue(); + + depositPool = _depositPool; + } + + /// @dev Set the percentage to send + /// @param _protocolFeePercentInBPS Percentage to send + function setProtocolFeePercentage(uint256 _protocolFeePercentInBPS) external onlyRole(LRTConstants.MANAGER) { + if (_protocolFeePercentInBPS == 0) revert InvalidEmptyValue(); + protocolFeePercentInBPS = _protocolFeePercentInBPS; + } +} diff --git a/contracts/KELP/KELP.sol b/contracts/KELP/KELP.sol new file mode 100644 index 0000000..c84b62a --- /dev/null +++ b/contracts/KELP/KELP.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; + +/// @title KELP - KelpDao's protocol token +contract KELP is ERC20, ERC20Permit { + constructor(address safeAddress) ERC20("KELP", "KELP") ERC20Permit("KELP") { + _mint(safeAddress, 1_000_000_000 * 10 ** decimals()); + } +} diff --git a/contracts/KELP/KelpDepositPool.sol b/contracts/KELP/KelpDepositPool.sol new file mode 100644 index 0000000..fec6719 --- /dev/null +++ b/contracts/KELP/KelpDepositPool.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.21; + +import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/interfaces/IERC20Upgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +/// @title Kelp Staking Rewards Contract +/// @dev Implements a basic staking mechanism with rewards. +/// @dev modified from https://github.com/Synthetixio/synthetix/blob/develop/contracts/StakingRewards.sol +contract KelpDepositPool is Initializable, ReentrancyGuardUpgradeable { + using SafeERC20Upgradeable for IERC20Upgradeable; + + IERC20Upgradeable public kelpToken; + IERC20Upgradeable public rewardsToken; + + address public admin; + + uint256 public duration; + uint256 public finishAt; + uint256 public updatedAt; + uint256 public rewardRate; + uint256 public rewardPerTokenStored; + + mapping(address => uint256) public userRewardPerTokenPaid; + mapping(address => uint256) public rewards; + + uint256 public totalKelpStaked; + mapping(address => uint256) public balanceOf; + + error NotAuthorized(); + error AmountZero(); + error RewardDurationNotFinished(); + error RewardAmountGreaterThanBalance(); + error RewardRateZero(); + + /// @dev Modifier to restrict functions to the contract's admin. + modifier onlyAdmin() { + if (msg.sender != admin) revert NotAuthorized(); + _; + } + + /// @dev Modifier to update reward for an account before executing function logic. + /// @param _account The account for which rewards will be updated. + modifier updateReward(address _account) { + rewardPerTokenStored = rewardPerToken(); + updatedAt = lastTimeRewardApplicable(); + if (_account != address(0)) { + rewards[_account] = earned(_account); + userRewardPerTokenPaid[_account] = rewardPerTokenStored; + } + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initializes the contract with staking and rewards tokens addresses. + /// @param _admin The address of the admin. + /// @param _kelpToken Address of the staking token. + /// @param _rewardToken Address of the rewards token. + function initialize( + address _admin, + address _kelpToken, + address _rewardToken, + uint256 _duration + ) + public + initializer + { + admin = _admin; + kelpToken = IERC20Upgradeable(_kelpToken); + rewardsToken = IERC20Upgradeable(_rewardToken); + duration = _duration; + } + + /// @dev Returns the last timestamp rewards are applicable. + /// @return The last applicable timestamp for rewards. + function lastTimeRewardApplicable() public view returns (uint256) { + return _min(finishAt, block.timestamp); + } + + /// @dev Calculates the reward per token staked. + /// @return The calculated reward per token. + function rewardPerToken() public view returns (uint256) { + if (totalKelpStaked == 0) { + return rewardPerTokenStored; + } + return rewardPerTokenStored + (rewardRate * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalKelpStaked; + } + + /// @dev Allows a user to stake a specified amount of staking tokens. + /// @param _amount The amount of staking tokens to stake. + function stake(uint256 _amount) external nonReentrant updateReward(msg.sender) { + if (_amount == 0) revert AmountZero(); + balanceOf[msg.sender] += _amount; + totalKelpStaked += _amount; + kelpToken.safeTransferFrom(msg.sender, address(this), _amount); + } + + /// @dev Allows a user to withdraw staked tokens. + /// @param _amount The amount of staking tokens to withdraw. + function withdraw(uint256 _amount) external nonReentrant updateReward(msg.sender) { + if (_amount == 0) revert AmountZero(); + balanceOf[msg.sender] -= _amount; + totalKelpStaked -= _amount; + kelpToken.safeTransfer(msg.sender, _amount); + } + + /// @dev Calculates the amount of rewards earned by an account. + /// @param _account The account to calculate rewards for. + /// @return The amount of rewards earned. + function earned(address _account) public view returns (uint256) { + return (balanceOf[_account] * (rewardPerToken() - userRewardPerTokenPaid[_account]) / 1e18) + rewards[_account]; + } + + /// @dev Allows a user to claim their earned rewards. + function getReward() external nonReentrant updateReward(msg.sender) { + uint256 reward = rewards[msg.sender]; + if (reward > 0) { + rewards[msg.sender] = 0; + rewardsToken.safeTransfer(msg.sender, reward); + } + } + + /*////////////////////////////////////////////////////////////// + ADMIN FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Sets the duration for rewards distribution. + /// @param _duration The duration in seconds for the rewards distribution. + function setRewardsDuration(uint256 _duration) external onlyAdmin { + if (finishAt >= block.timestamp) revert RewardDurationNotFinished(); + duration = _duration; + } + + /// @dev Notifies the contract about a new reward amount to be distributed. + /// @param _amount The amount of rewards to distribute. + function notifyRewardAmount(uint256 _amount) external onlyAdmin updateReward(address(0)) { + if (_amount > rewardsToken.balanceOf(address(this))) revert RewardAmountGreaterThanBalance(); + + if (block.timestamp >= finishAt) { + rewardRate = _amount / duration; + } else { + uint256 remaining = (finishAt - block.timestamp) * rewardRate; + rewardRate = (_amount + remaining) / duration; + } + + if (rewardRate == 0) revert RewardRateZero(); + if (rewardRate * duration > rewardsToken.balanceOf(address(this))) revert RewardAmountGreaterThanBalance(); + finishAt = block.timestamp + duration; + updatedAt = block.timestamp; + } + + /*////////////////////////////////////////////////////////////// + PRIVATE FUNCTION + //////////////////////////////////////////////////////////////*/ + + /// @dev Private function to return the minimum of two values. + /// @param x First value to compare. + /// @param y Second value to compare. + /// @return The minimum value between x and y. + function _min(uint256 x, uint256 y) private pure returns (uint256) { + return x <= y ? x : y; + } +} diff --git a/contracts/KelpEarnedPoint.sol b/contracts/KelpEarnedPoint.sol new file mode 100644 index 0000000..c83b53a --- /dev/null +++ b/contracts/KelpEarnedPoint.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import { ERC20PausableUpgradeable } from + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import { ERC20PermitUpgradeable } from + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract KelpEarnedPoint is + Initializable, + ERC20Upgradeable, + ERC20PausableUpgradeable, + AccessControlUpgradeable, + ERC20PermitUpgradeable +{ + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initialize the contract + /// @param defaultAdmin The default admin role + /// @param minter The minter role + function initialize(address defaultAdmin, address minter) public initializer { + __ERC20_init("Kelp Earned Point", "KEP"); + __ERC20Permit_init("Kelp Points"); + __ERC20Pausable_init(); + __AccessControl_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin); + _grantRole(MINTER_ROLE, minter); + } + + /// @dev Mint new tokens. Only the minter can call this + /// @param to The address to mint to + /// @param amount The amount to mint + function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { + _mint(to, amount); + } + + /// @dev Burn tokens. Only calleable by the burner + /// @param from The address to burn from + /// @param amount The amount to burn + function burn(address from, uint256 amount) public onlyRole(BURNER_ROLE) { + _burn(from, amount); + } + + function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { + _pause(); + } + + function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) + internal + override(ERC20Upgradeable, ERC20PausableUpgradeable) + { + super._beforeTokenTransfer(from, to, amount); + } +} diff --git a/contracts/L2/RsETHTokenWrapper.sol b/contracts/L2/RsETHTokenWrapper.sol new file mode 100644 index 0000000..ffbe3ac --- /dev/null +++ b/contracts/L2/RsETHTokenWrapper.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.21; + +import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; +import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import { ERC20PermitUpgradeable } from + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +/// @title RsETHTokenWrapper +/// @notice This contract is a wrapper for alternative RsETH tokens in L2 chains for a canonical rsETH token for KelpDao +/// @dev it is an upgradeable ERC20 token that wraps an alternative RsETH token +/// It also uses the ERC20PermitUpgradeable extension +/// the alt rsETH tokens can be swapped 1:1 for the canonical rsETH token +contract RsETHTokenWrapper is Initializable, AccessControlUpgradeable, ERC20Upgradeable, ERC20PermitUpgradeable { + using SafeERC20Upgradeable for ERC20Upgradeable; + + bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); + + /// @dev The address of the alternative RsETH token + mapping(address allowedToken => bool isAllowed) public allowedTokens; + + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BRIDGER_ROLE = keccak256("BRIDGER_ROLE"); + + error TokenNotAllowed(); + error CannotDeposit(); + + event Deposit(address asset, address _sender, uint256 _amount); + event Withdraw(address asset, address _sender, uint256 _amount); + event BridgerDeposited(address asset, uint256 _amount); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initialize the contract + /// @param admin The address of the admin + /// @param manager The address of the manager + /// @param _altRsETH An alternative RsETH token + function initialize(address admin, address manager, address _altRsETH) public initializer { + __ERC20_init("rsETHWrapper", "wrsETH"); + __ERC20Permit_init("rsETHWrapper"); + __AccessControl_init(); + + _setupRole(DEFAULT_ADMIN_ROLE, admin); + _setupRole(MANAGER_ROLE, manager); + _setupRole(BRIDGER_ROLE, manager); + + allowedTokens[_altRsETH] = true; + } + + /// @dev Deposit altRseTH for wrsETH + /// @param asset The address of the token to deposit + ///@param _amount The amount of tokens to deposit + function deposit(address asset, uint256 _amount) external { + _deposit(asset, msg.sender, _amount); + } + + /// @dev Deposit altRseTH for wrsETH to a user + /// @param asset The address of the token to deposit + /// @param _to The user to send the XERC20 to + /// @param _amount The amount of tokens to deposit + function depositTo(address asset, address _to, uint256 _amount) external { + _deposit(asset, _to, _amount); + } + + /// @dev Withdraw altRseth tokens from wrsETH + /// @param asset The address of the token to withdraw + /// @param _amount The amount of tokens to withdraw + function withdraw(address asset, uint256 _amount) external { + _withdraw(asset, msg.sender, _amount); + } + + /// @dev Withdraw altRseth tokens from wrsETH to a user + /// @param asset The address of the token to withdraw + /// @param _to The user to withdraw to + /// @param _amount The amount of tokens to withdraw + function withdrawTo(address asset, address _to, uint256 _amount) external { + _withdraw(asset, _to, _amount); + } + + /// @notice Get the maximum amount of the bridged asset that can be deposited + /// @param _asset The address of the token to deposit + /// @return uint256 + function maxAmountToDepositBridgerAsset(address _asset) public view returns (uint256) { + if (!allowedTokens[_asset]) return 0; + + // get totalSupply of wrsETH minted + uint256 wrsETHSupply = totalSupply(); + // balance of _asset with the contract + uint256 balanceOfAssetInWrapper = ERC20Upgradeable(_asset).balanceOf(address(this)); + + if (balanceOfAssetInWrapper > wrsETHSupply) return 0; + + return wrsETHSupply - balanceOfAssetInWrapper; + } + + /*////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Withdraw altRseth tokens from wrsETH + /// @param _asset The address of the token to withdraw + /// @param _to The user to withdraw to + /// @param _amount The amount of tokens to withdraw + function _withdraw(address _asset, address _to, uint256 _amount) internal { + if (!allowedTokens[_asset]) revert TokenNotAllowed(); + + _burn(msg.sender, _amount); + + ERC20Upgradeable(_asset).safeTransfer(_to, _amount); + + emit Withdraw(_asset, _to, _amount); + } + + /// @notice Deposit tokens into the lockbox + /// @param _asset The address of the token to deposit + /// @param _to The address to send the XERC20 to + /// @param _amount The amount of tokens to deposit + function _deposit(address _asset, address _to, uint256 _amount) internal { + if (!allowedTokens[_asset]) revert TokenNotAllowed(); + + ERC20Upgradeable(_asset).safeTransferFrom(msg.sender, address(this), _amount); + + _mint(_to, _amount); + emit Deposit(_asset, _to, _amount); + } + + /*////////////////////////////////////////////////////////////// + RESTRICTED ACCESS FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @notice deposit for when the rsETH is bridged by the bridger from L1 + /// @notice so as to collateralize already minted wrsETH + /// + /// @param _asset The address of the token to deposit + /// @param _amount The amount of tokens to deposit + function depositBridgerAssets(address _asset, uint256 _amount) external onlyRole(BRIDGER_ROLE) { + if (maxAmountToDepositBridgerAsset(_asset) < _amount) { + revert CannotDeposit(); + } + + ERC20Upgradeable(_asset).safeTransferFrom(msg.sender, address(this), _amount); + + emit BridgerDeposited(_asset, _amount); + } + + /// Dont' allow to add other tokens at the moment. Only allow the altRsETH token as set in the initialize function + + /// @dev Remove a token from the allowed tokens list + /// @param _asset The address of the token to remove + function removeAllowedToken(address _asset) external onlyRole(DEFAULT_ADMIN_ROLE) { + allowedTokens[_asset] = false; + } + + /// @dev Mint wrsETH tokens + /// @param _to The address to mint the tokens to + /// @param _amount The amount of tokens to mint + function mint(address _to, uint256 _amount) external onlyRole(MINTER_ROLE) { + _mint(_to, _amount); + } +} diff --git a/contracts/LRTConfig.sol b/contracts/LRTConfig.sol index cbbf110..9724b41 100644 --- a/contracts/LRTConfig.sol +++ b/contracts/LRTConfig.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.21; import { UtilLib } from "./utils/UtilLib.sol"; import { LRTConstants } from "./utils/LRTConstants.sol"; import { ILRTConfig } from "./interfaces/ILRTConfig.sol"; -import { IStrategy } from "./interfaces/IStrategy.sol"; +import { IStrategy } from "./external/eigenlayer/interfaces/IStrategy.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; @@ -22,11 +22,6 @@ contract LRTConfig is ILRTConfig, AccessControlUpgradeable { address public rsETH; - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - modifier onlySupportedAsset(address asset) { if (!isSupportedAsset[asset]) { revert AssetNotSupported(); @@ -34,6 +29,11 @@ contract LRTConfig is ILRTConfig, AccessControlUpgradeable { _; } + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + /// @dev Initializes the contract /// @param admin Admin address /// @param stETH stETH address @@ -132,10 +132,12 @@ contract LRTConfig is ILRTConfig, AccessControlUpgradeable { GETTERS //////////////////////////////////////////////////////////////*/ function getLSTToken(bytes32 tokenKey) external view override returns (address) { + UtilLib.checkNonZeroAddress(tokenMap[tokenKey]); return tokenMap[tokenKey]; } function getContract(bytes32 contractKey) public view override returns (address) { + UtilLib.checkNonZeroAddress(contractMap[contractKey]); return contractMap[contractKey]; } diff --git a/contracts/LRTConverter.sol b/contracts/LRTConverter.sol new file mode 100644 index 0000000..9681154 --- /dev/null +++ b/contracts/LRTConverter.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { LRTConstants } from "./utils/LRTConstants.sol"; + +import { LRTConfigRoleChecker, ILRTConfig, IAccessControl } from "./utils/LRTConfigRoleChecker.sol"; +import { UtilLib } from "./utils/UtilLib.sol"; + +import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; +import { IStrategy } from "./external/eigenlayer/interfaces/IStrategy.sol"; +import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; +import { IRSETH } from "./interfaces/IRSETH.sol"; +import { IEigenDelegationManager } from "./external/eigenlayer/interfaces/IEigenDelegationManager.sol"; +import { ILRTConverter } from "./interfaces/ILRTConverter.sol"; + +import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { UnstakeStETH } from "./unstaking-adapters/UnstakeStETH.sol"; +import { UnstakeSwETH } from "./unstaking-adapters/UnstakeSwETH.sol"; + +/// @title LRTConverter - Unstakes LSTs to ETH and swaps ETH to LSTs +/// @notice This contract is responsible for unstaking LSTs to ETH and swapping ETH to LSTs +contract LRTConverter is + ILRTConverter, + LRTConfigRoleChecker, + ReentrancyGuardUpgradeable, + UnstakeSwETH, + UnstakeStETH, + IERC721Receiver +{ + using SafeERC20 for IERC20; + + mapping(bytes32 => bool) public _legacyProcessedWithdrawalRoots; + mapping(address => bool) public convertableAssets; + mapping(address => uint256) public _legacyConversionLimit; + + //needs to be added to total assets in protocol + uint256 public ethValueInWithdrawal; + + modifier onlyConvertableAsset(address asset) { + require(convertableAssets[asset], "Asset not supported"); + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initializes the contract + /// @param lrtConfigAddr LRT config address + function initialize(address lrtConfigAddr) external initializer { + UtilLib.checkNonZeroAddress(lrtConfigAddr); + __ReentrancyGuard_init(); + lrtConfig = ILRTConfig(lrtConfigAddr); + emit UpdatedLRTConfig(lrtConfigAddr); + } + + /// @dev Initializes the contract + /// @param _withdrawalQueueAddress Address of withdrawal queue (stETH) + /// @param _stETHAddress Address of stETH + /// @param _swEXITAddress Address of swEXIT (swETH) + /// @param _swETHAddress Address of swETH + function initialize2( + address _withdrawalQueueAddress, + address _stETHAddress, + address _swEXITAddress, + address _swETHAddress + ) + external + reinitializer(2) + onlyLRTAdmin + { + __ReentrancyGuard_init(); + __initializeSwETH(_swEXITAddress, _swETHAddress); + __initializeStETH(_withdrawalQueueAddress, _stETHAddress); + } + + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC721Received.selector; + } + + /// @dev fallback to receive funds + receive() external payable { } + + /*//////////////////////////////////////////////////////////// + write interactions + //////////////////////////////////////////////////////////////*/ + + /// @notice swap ETH for LST asset which is accepted by LRTConverter and send to LRTDepositPool + /// @dev use LRTOracle to get price for asset. Only callable by LRT manager + /// @param asset Asset address to swap to + /// @param minimumExpectedReturnAmount Minimum asset amount to swap to + function swapEthToAsset( + address asset, + uint256 minimumExpectedReturnAmount + ) + external + payable + onlyLRTOperator + onlyConvertableAsset(asset) + returns (uint256 returnAmount) + { + ILRTDepositPool lrtDepositPool = ILRTDepositPool(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); + uint256 ethAmountSent = msg.value; + + returnAmount = lrtDepositPool.getSwapETHToAssetReturnAmount(asset, ethAmountSent); + + if (returnAmount < minimumExpectedReturnAmount || IERC20(asset).balanceOf(address(this)) < returnAmount) { + revert NotEnoughAssetToTransfer(); + } + // account for limits and the asset value in contract + _sendEthToDepositPool(ethAmountSent); + + IERC20(asset).safeTransfer(msg.sender, returnAmount); + emit ETHSwappedForLST(ethAmountSent, asset, returnAmount); + } + + /// @notice send asset from deposit pool to LRTConverter + /// @dev Only callable by LRT manager and asset need to be approved + /// @param _asset Asset address to send + /// @param _amount Asset amount to send + function transferAssetFromDepositPool( + address _asset, + uint256 _amount + ) + external + onlyConvertableAsset(_asset) + onlyLRTManager + { + address lrtDepositPoolAddress = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); + address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); + ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); + + ethValueInWithdrawal += (_amount * lrtOracle.getAssetPrice(_asset)) / 1e18; + + IERC20(_asset).safeTransferFrom(lrtDepositPoolAddress, address(this), _amount); + } + + /// @notice raises a unstake request for steth on lido + function unstakeStEth(uint256 amountToUnstake) external onlyLRTOperator { + _unstakeStEth(amountToUnstake); + } + + /// @notice claim eth from lido for steth and sends to deposit pool + function claimStEth(uint256 _requestId, uint256 _hint) external onlyLRTOperator { + _claimStEth(_requestId, _hint); + _sendEthToDepositPool(address(this).balance); + } + + /// @notice raises a unstake request for sweth on swell + function unstakeSwEth(uint256 amountToUnstake) external onlyLRTOperator { + _unstakeSwEth(amountToUnstake); + } + + /// @notice claim eth from sweth from swell for sweth and sends to deposit pool + function claimSwEth(uint256 _tokenId) external onlyLRTOperator { + _claimSwEth(_tokenId); + _sendEthToDepositPool(address(this).balance); + } + + /*//////////////////////////////////////////////////////////// + setters interactions + //////////////////////////////////////////////////////////////*/ + + /// @notice Add convertable asset + /// @param asset Asset address + function addConvertableAsset(address asset) external onlyLRTManager { + convertableAssets[asset] = true; + } + + /// @notice Remove convertable asset + /// @param asset Asset address + function removeConvertableAsset(address asset) external onlyLRTManager { + convertableAssets[asset] = false; + } + + /*//////////////////////////////////////////////////////////// + internal functions + //////////////////////////////////////////////////////////////*/ + + function _sendEthToDepositPool(uint256 _amount) internal { + address lrtDepositPoolAddress = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); + + if (ethValueInWithdrawal > _amount) { + ethValueInWithdrawal -= _amount; + } else { + ethValueInWithdrawal = 0; + } + // Send eth to deposit pool + ILRTDepositPool(lrtDepositPoolAddress).receiveFromLRTConverter{ value: _amount }(); + emit EthTransferred(lrtDepositPoolAddress, _amount); + } +} diff --git a/contracts/LRTDepositPool.sol b/contracts/LRTDepositPool.sol index 0229271..a2e4149 100644 --- a/contracts/LRTDepositPool.sol +++ b/contracts/LRTDepositPool.sol @@ -9,20 +9,29 @@ import { IRSETH } from "./interfaces/IRSETH.sol"; import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; +import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; +import { ILRTWithdrawalManager } from "./interfaces/ILRTWithdrawalManager.sol"; +import { ILRTConverter } from "./interfaces/ILRTConverter.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title LRTDepositPool - Deposit Pool Contract for LSTs /// @notice Handles LST asset deposits contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable { + using SafeERC20 for IERC20; + uint256 public maxNodeDelegatorLimit; uint256 public minAmountToDeposit; mapping(address => uint256) public isNodeDelegator; // 0: not a node delegator, 1: is a node delegator address[] public nodeDelegatorQueue; + /// @notice maximum amount that can be ignored + uint256 public maxNegligibleAmount; + /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); @@ -40,104 +49,22 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad } /*////////////////////////////////////////////////////////////// - view functions + receive functions //////////////////////////////////////////////////////////////*/ - /// @notice gets the total asset present in protocol - /// @param asset Asset address - /// @return totalAssetDeposit total asset present in protocol - function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) { - (uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer) = - getAssetDistributionData(asset); - return (assetLyingInDepositPool + assetLyingInNDCs + assetStakedInEigenLayer); - } + receive() external payable { } - /// @notice gets the current limit of asset deposit - /// @param asset Asset address - /// @return currentLimit Current limit of asset deposit - function getAssetCurrentLimit(address asset) public view override returns (uint256) { - if (getTotalAssetDeposits(asset) > lrtConfig.depositLimitByAsset(asset)) { - return 0; - } + /// @dev receive from RewardReceiver + function receiveFromRewardReceiver() external payable { } - return lrtConfig.depositLimitByAsset(asset) - getTotalAssetDeposits(asset); - } + /// @dev receive from LRTConverter + function receiveFromLRTConverter() external payable { } - /// @dev get node delegator queue - /// @return nodeDelegatorQueue Array of node delegator contract addresses - function getNodeDelegatorQueue() external view override returns (address[] memory) { - return nodeDelegatorQueue; - } - - /// @dev provides asset amount distribution data among depositPool, NDCs and eigenLayer - /// @param asset the asset to get the total amount of - /// @return assetLyingInDepositPool asset amount lying in this LRTDepositPool contract - /// @return assetLyingInNDCs asset amount sum lying in all NDC contract - /// @return assetStakedInEigenLayer asset amount deposited in eigen layer strategies through all NDCs - function getAssetDistributionData(address asset) - public - view - override - onlySupportedAsset(asset) - returns (uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer) - { - if (asset == LRTConstants.ETH_TOKEN) { - return getETHDistributionData(); - } - assetLyingInDepositPool = IERC20(asset).balanceOf(address(this)); - - uint256 ndcsCount = nodeDelegatorQueue.length; - for (uint256 i; i < ndcsCount;) { - assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]); - assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset); - unchecked { - ++i; - } - } - } - - /// @dev provides ETH amount distribution data among depositPool, NDCs and eigenLayer - function getETHDistributionData() - public - view - override - returns (uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer) - { - ethLyingInDepositPool = address(this).balance; - - uint256 ndcsCount = nodeDelegatorQueue.length; - for (uint256 i; i < ndcsCount;) { - ethLyingInNDCs += nodeDelegatorQueue[i].balance; - ethStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getETHEigenPodBalance(); - unchecked { - ++i; - } - } - } - - /// @notice View amount of rsETH to mint for given asset amount - /// @param asset Asset address - /// @param amount Asset amount - /// @return rsethAmountToMint Amount of rseth to mint - function getRsETHAmountToMint( - address asset, - uint256 amount - ) - public - view - override - returns (uint256 rsethAmountToMint) - { - // setup oracle contract - address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); - ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); - - // calculate rseth amount to mint based on asset amount and asset exchange rate - rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.rsETHPrice(); - } + /// @dev receive from NodeDelegator + function receiveFromNodeDelegator() external payable { } /*////////////////////////////////////////////////////////////// - write functions + user interactions //////////////////////////////////////////////////////////////*/ /// @notice Allows user to deposit ETH to the protocol @@ -149,8 +76,8 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad ) external payable - whenNotPaused nonReentrant + whenNotPaused { // checks uint256 rsethAmountToMint = _beforeDeposit(LRTConstants.ETH_TOKEN, msg.value, minRSETHAmountExpected); @@ -172,51 +99,137 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad string calldata referralId ) external - whenNotPaused nonReentrant + whenNotPaused onlySupportedAsset(asset) { // checks uint256 rsethAmountToMint = _beforeDeposit(asset, depositAmount, minRSETHAmountExpected); // interactions - if (!IERC20(asset).transferFrom(msg.sender, address(this), depositAmount)) { - revert TokenTransferFailed(); - } + IERC20(asset).safeTransferFrom(msg.sender, address(this), depositAmount); _mintRsETH(rsethAmountToMint); emit AssetDeposit(msg.sender, asset, depositAmount, rsethAmountToMint, referralId); } - function _beforeDeposit( - address asset, - uint256 depositAmount, - uint256 minRSETHAmountExpected + /*////////////////////////////////////////////////////////////// + Fund movement functions + //////////////////////////////////////////////////////////////*/ + + /// @notice swap ETH for LST asset which is accepted by LRTDepositPool + /// @dev use LRTOracle to get price for toToken. Only callable by LRT manager + /// @param toAsset Asset address to swap to + /// @param minToAssetAmount Minimum asset amount to swap to + function swapETHForAssetWithinDepositPool( + address toAsset, + uint256 minToAssetAmount ) - private - view - returns (uint256 rsethAmountToMint) + external + payable + onlyLRTManager + onlySupportedAsset(toAsset) { - if (depositAmount == 0 || depositAmount < minAmountToDeposit) { - revert InvalidAmountToDeposit(); - } + // checks + uint256 ethAmountSent = msg.value; - if (depositAmount > getAssetCurrentLimit(asset)) { - revert MaximumDepositLimitReached(); - } - rsethAmountToMint = getRsETHAmountToMint(asset, depositAmount); + uint256 returnAmount = getSwapETHToAssetReturnAmount(toAsset, ethAmountSent); - if (rsethAmountToMint < minRSETHAmountExpected) { - revert MinimumAmountToReceiveNotMet(); + if (returnAmount < minToAssetAmount || IERC20(toAsset).balanceOf(address(this)) < returnAmount) { + revert NotEnoughAssetToTransfer(); } + + // interactions + IERC20(toAsset).transfer(msg.sender, returnAmount); + + emit ETHSwappedForLST(ethAmountSent, toAsset, returnAmount); } - /// @dev private function to mint rseth - /// @param rsethAmountToMint Amount of rseth minted - function _mintRsETH(uint256 rsethAmountToMint) private { - address rsethToken = lrtConfig.rsETH(); - // mint rseth for user - IRSETH(rsethToken).mint(msg.sender, rsethAmountToMint); + /// @notice transfers asset lying in this DepositPool to node delegator contract + /// @dev only callable by LRT manager + /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue + /// @param asset Asset address + /// @param amount Asset amount to transfer + function transferAssetToNodeDelegator( + uint256 ndcIndex, + address asset, + uint256 amount + ) + external + nonReentrant + onlyLRTManager + onlySupportedAsset(asset) + { + address nodeDelegator = nodeDelegatorQueue[ndcIndex]; + IERC20(asset).safeTransfer(nodeDelegator, amount); + } + + /// @notice transfers ETH lying in this DepositPool to node delegator contract + /// @dev only callable by LRT manager + /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue + /// @param amount ETH amount to transfer + function transferETHToNodeDelegator(uint256 ndcIndex, uint256 amount) external nonReentrant onlyLRTManager { + address nodeDelegator = nodeDelegatorQueue[ndcIndex]; + INodeDelegator(nodeDelegator).sendETHFromDepositPoolToNDC{ value: amount }(); + emit EthTransferred(nodeDelegator, amount); + } + + /// @notice transfers asset lying in this DepositPool to LRTUnstakingVault contract + /// @dev only callable by LRT manager + /// @param asset Asset address + /// @param amount Asset amount to transfer + function transferAssetToLRTUnstakingVault( + address asset, + uint256 amount + ) + external + nonReentrant + onlyLRTManager + onlySupportedAsset(asset) + { + address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); + IERC20(asset).safeTransfer(lrtUnstakingVault, amount); + } + + /// @notice transfers ETH lying in this DepositPool to nLRTUnstakingVault contract + /// @dev only callable by LRT manager + /// @param amount ETH amount to transfer + function transferETHToLRTUnstakingVault(uint256 amount) external nonReentrant onlyLRTManager { + address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); + ILRTUnstakingVault(lrtUnstakingVault).receiveFromLRTDepositPool{ value: amount }(); + emit EthTransferred(lrtUnstakingVault, amount); + } + + /*////////////////////////////////////////////////////////////// + Setters / Update Functions + //////////////////////////////////////////////////////////////*/ + + /// @notice maximum amount that can be ignored + /// @dev only callable by LRT admin + /// @param maxNegligibleAmount_ Maximum amount that can be ignored + function setMaxNegligibleAmount(uint256 maxNegligibleAmount_) external onlyLRTAdmin { + maxNegligibleAmount = maxNegligibleAmount_; + emit MaxNegligibleAmountUpdated(maxNegligibleAmount_); + } + + /// @notice update min amount to deposit + /// @dev only callable by LRT admin + /// @param minAmountToDeposit_ Minimum amount to deposit + function setMinAmountToDeposit(uint256 minAmountToDeposit_) external onlyLRTAdmin { + minAmountToDeposit = minAmountToDeposit_; + emit MinAmountToDepositUpdated(minAmountToDeposit_); + } + + /// @notice update max node delegator count + /// @dev only callable by LRT admin + /// @param maxNodeDelegatorLimit_ Maximum count of node delegator + function updateMaxNodeDelegatorLimit(uint256 maxNodeDelegatorLimit_) external onlyLRTAdmin { + if (maxNodeDelegatorLimit_ < nodeDelegatorQueue.length) { + revert InvalidMaximumNodeDelegatorLimit(); + } + + maxNodeDelegatorLimit = maxNodeDelegatorLimit_; + emit MaxNodeDelegatorLimitUpdated(maxNodeDelegatorLimit); } /// @notice add new node delegator contract addresses @@ -249,137 +262,187 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad /// @notice remove node delegator contract address from queue /// @dev only callable by LRT admin /// @param nodeDelegatorAddress NodeDelegator contract address - function removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) public onlyLRTAdmin { - // 1. check if node delegator contract is in queue - uint256 length = nodeDelegatorQueue.length; - uint256 ndcIndex; + function removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) external onlyLRTAdmin { + _removeNodeDelegatorContractFromQueue(nodeDelegatorAddress); + } + /// @notice remove many node delegator contracts from queue + /// @dev only callable by LRT admin + /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses + function removeManyNodeDelegatorContractsFromQueue(address[] calldata nodeDelegatorContracts) + external + onlyLRTAdmin + { + uint256 length = nodeDelegatorContracts.length; for (uint256 i; i < length;) { - if (nodeDelegatorQueue[i] == nodeDelegatorAddress) { - ndcIndex = i; - break; - } - - // 1.1 If node delegator contract is not found in queue, revert - if (i == length - 1) { - revert NodeDelegatorNotFound(); - } - + _removeNodeDelegatorContractFromQueue(nodeDelegatorContracts[i]); unchecked { ++i; } } + } - // 2. revert if node delegator contract has any asset balances. + /// @dev Triggers stopped state. Contract must not be paused. + function pause() external onlyLRTManager { + _pause(); + } - // 2.1 check if NDC has native ETH balance in eigen layer and in itself. - if ( - INodeDelegator(nodeDelegatorAddress).getETHEigenPodBalance() > 0 - || address(nodeDelegatorAddress).balance > 0 - ) { - revert NodeDelegatorHasETH(); - } + /// @dev Returns to normal state. Contract must be paused + function unpause() external onlyLRTAdmin { + _unpause(); + } - // 2.2 check if NDC has LST balance - address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); - uint256 supportedAssetsLength = supportedAssets.length; + /*////////////////////////////////////////////////////////////// + other write functions + //////////////////////////////////////////////////////////////*/ - uint256 assetBalance; - for (uint256 i; i < supportedAssetsLength; i++) { - if (supportedAssets[i] == LRTConstants.ETH_TOKEN) { - // ETH already checked above. - continue; - } + /// @notice Approves the maximum amount of an asset to the LRTConverter contract + /// @dev only supported assets can be deposited and only called by the LRT manager + /// @param asset the asset to approve + function maxApproveToLRTConverter(address asset) external onlySupportedAsset(asset) onlyLRTManager { + address lrtConverterAddress = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); + IERC20(asset).approve(lrtConverterAddress, type(uint256).max); + } - assetBalance = IERC20(supportedAssets[i]).balanceOf(nodeDelegatorAddress) - + INodeDelegator(nodeDelegatorAddress).getAssetBalance(supportedAssets[i]); + /*////////////////////////////////////////////////////////////// + view functions + //////////////////////////////////////////////////////////////*/ - if (assetBalance > 0) { - revert NodeDelegatorHasAssetBalance(supportedAssets[i], assetBalance); - } - } + /// @notice gets the total asset present in protocol + /// @param asset Asset address + /// @return totalAssetDeposit total asset present in protocol + function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) { + ( + uint256 assetLyingInDepositPool, + uint256 assetLyingInNDCs, + uint256 assetStakedInEigenLayer, + uint256 assetUnstakingFromEigenLayer, + uint256 assetLyingInConverter, + uint256 assetLyingUnstakingVault + ) = getAssetDistributionData(asset); + return ( + assetLyingInDepositPool + assetLyingInNDCs + assetStakedInEigenLayer + assetUnstakingFromEigenLayer + + assetLyingInConverter + assetLyingUnstakingVault + ); + } - // 3. remove node delegator contract from queue + /// @notice gets the current limit of asset deposit + /// @param asset Asset address + /// @return currentLimit Current limit of asset deposit + function getAssetCurrentLimit(address asset) public view override returns (uint256) { + uint256 totalAssetDeposits = getTotalAssetDeposits(asset); + if (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)) { + return 0; + } - // 3.1 remove from isNodeDelegator mapping - isNodeDelegator[nodeDelegatorAddress] = 0; - // 3.2 remove from nodeDelegatorQueue - nodeDelegatorQueue[ndcIndex] = nodeDelegatorQueue[length - 1]; - nodeDelegatorQueue.pop(); + return lrtConfig.depositLimitByAsset(asset) - totalAssetDeposits; + } - emit NodeDelegatorRemovedFromQueue(nodeDelegatorAddress); + /// @dev get node delegator queue + /// @return nodeDelegatorQueue Array of node delegator contract addresses + function getNodeDelegatorQueue() external view override returns (address[] memory) { + return nodeDelegatorQueue; } - /// @notice remove many node delegator contracts from queue - /// @dev calls internally removeNodeDelegatorContractFromQueue which is only callable by LRT admin - /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses - function removeManyNodeDelegatorContractsFromQueue(address[] calldata nodeDelegatorContracts) external { - uint256 length = nodeDelegatorContracts.length; + /// @dev provides asset amount distribution data among depositPool, NDCs and eigenLayer + /// @param asset the asset to get the total amount of + /// @return assetLyingInDepositPool asset amount lying in this LRTDepositPool contract + /// @return assetLyingInNDCs asset amount sum lying in all NDC contract + /// @return assetStakedInEigenLayer asset amount deposited in eigen layer strategies through all NDCs + /// @return assetUnstakingFromEigenLayer asset amount in delayed withdrawal from eigen layer strategies through all + /// NDCs + /// @return assetLyingInConverter asset value lying in converter + /// @return assetLyingUnstakingVault asset amount lying in UnstakingVault + function getAssetDistributionData(address asset) + public + view + override + onlySupportedAsset(asset) + returns ( + uint256 assetLyingInDepositPool, + uint256 assetLyingInNDCs, + uint256 assetStakedInEigenLayer, + uint256 assetUnstakingFromEigenLayer, + uint256 assetLyingInConverter, + uint256 assetLyingUnstakingVault + ) + { + if (asset == LRTConstants.ETH_TOKEN) { + return getETHDistributionData(); + } + assetLyingInDepositPool = IERC20(asset).balanceOf(address(this)); + + uint256 ndcsCount = nodeDelegatorQueue.length; + for (uint256 i; i < ndcsCount;) { + assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]); + assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset); - for (uint256 i; i < length;) { - removeNodeDelegatorContractFromQueue(nodeDelegatorContracts[i]); unchecked { ++i; } } + + address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); + assetUnstakingFromEigenLayer = ILRTUnstakingVault(lrtUnstakingVault).getAssetsUnstaking(asset); + assetLyingInConverter = 0; //assets in converter are accounted in there eth value => getETHDistributionData + assetLyingUnstakingVault = IERC20(asset).balanceOf(lrtUnstakingVault); } - /// @notice transfers asset lying in this DepositPool to node delegator contract - /// @dev only callable by LRT manager - /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue - /// @param asset Asset address - /// @param amount Asset amount to transfer - function transferAssetToNodeDelegator( - uint256 ndcIndex, - address asset, - uint256 amount - ) - external - nonReentrant - onlyLRTManager - onlySupportedAsset(asset) + /// @dev provides ETH amount distribution data among depositPool, NDCs and eigenLayer + /// @dev rewards are not accounted here + /// it will automatically be accounted once it is moved from feeReceiver/rewardReceiver to depositPool + function getETHDistributionData() + public + view + override + returns ( + uint256 ethLyingInDepositPool, + uint256 ethLyingInNDCs, + uint256 ethStakedInEigenLayer, + uint256 ethUnstakingFromEigenLayer, + uint256 ethLyingInConverter, + uint256 ethLyingInUnstakingVault + ) { - address nodeDelegator = nodeDelegatorQueue[ndcIndex]; - if (!IERC20(asset).transfer(nodeDelegator, amount)) { - revert TokenTransferFailed(); + ethLyingInDepositPool = address(this).balance; + + uint256 ndcsCount = nodeDelegatorQueue.length; + for (uint256 i; i < ndcsCount;) { + ethLyingInNDCs += nodeDelegatorQueue[i].balance; + ethStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getETHEigenPodBalance(); + unchecked { + ++i; + } } - } - /// @notice transfers ETH lying in this DepositPool to node delegator contract - /// @dev only callable by LRT manager - /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue - /// @param amount ETH amount to transfer - function transferETHToNodeDelegator(uint256 ndcIndex, uint256 amount) external nonReentrant onlyLRTManager { - address nodeDelegator = nodeDelegatorQueue[ndcIndex]; - INodeDelegator(nodeDelegator).sendETHFromDepositPoolToNDC{ value: amount }(); + address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); + ethUnstakingFromEigenLayer = ILRTUnstakingVault(lrtUnstakingVault).getAssetsUnstaking(LRTConstants.ETH_TOKEN); + + address lrtConverter = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); + ethLyingInConverter = ILRTConverter(lrtConverter).ethValueInWithdrawal(); + + ethLyingInUnstakingVault = lrtUnstakingVault.balance; } - /// @notice swap ETH for LST asset which is accepted by LRTDepositPool - /// @dev use LRTOracle to get price for toToken. Only callable by LRT manager - /// @param toAsset Asset address to swap to - /// @param minToAssetAmount Minimum asset amount to swap to - function swapETHForAssetWithinDepositPool( - address toAsset, - uint256 minToAssetAmount + /// @notice View amount of rsETH to mint for given asset amount + /// @param asset Asset address + /// @param amount Asset amount + /// @return rsethAmountToMint Amount of rseth to mint + function getRsETHAmountToMint( + address asset, + uint256 amount ) - external - payable - onlyLRTManager - onlySupportedAsset(toAsset) + public + view + override + returns (uint256 rsethAmountToMint) { - // checks - uint256 ethAmountSent = msg.value; - - uint256 returnAmount = getSwapETHToAssetReturnAmount(toAsset, ethAmountSent); - - if (returnAmount < minToAssetAmount || IERC20(toAsset).balanceOf(address(this)) < returnAmount) { - revert NotEnoughAssetToTransfer(); - } - - // interactions - IERC20(toAsset).transfer(msg.sender, returnAmount); + // setup oracle contract + address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); + ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); - emit ETHSwappedForLST(ethAmountSent, toAsset, returnAmount); + // calculate rseth amount to mint based on asset amount and asset exchange rate + rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.rsETHPrice(); } /// @notice get return amount for swapping ETH to asset that is accepted by LRTDepositPool @@ -403,35 +466,120 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad return ethPricePerUint * ethAmountToSend / lrtOracle.getAssetPrice(toAsset); } - /// @notice update max node delegator count - /// @dev only callable by LRT admin - /// @param maxNodeDelegatorLimit_ Maximum count of node delegator - function updateMaxNodeDelegatorLimit(uint256 maxNodeDelegatorLimit_) external onlyLRTAdmin { - if (maxNodeDelegatorLimit_ < nodeDelegatorQueue.length) { - revert InvalidMaximumNodeDelegatorLimit(); + /*////////////////////////////////////////////////////////////// + internal functions + //////////////////////////////////////////////////////////////*/ + + /// @notice internal function to remove node delegator contract address from queue + /// @param nodeDelegatorAddress NodeDelegator contract address + function _removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) internal { + // 1. check if node delegator contract is in queue and find Index + uint256 ndcIndex = _getNDCIndex(nodeDelegatorAddress); + + // 2. revert if node delegator contract has any asset balances. + // 2.1 check if NDC has native ETH balance in eigen layer or/and in itself. + _checkResidueEthBalance(nodeDelegatorAddress); + // 2.2 check if NDC has LST balance + _checkResidueLSTBalance(nodeDelegatorAddress); + + // 3. remove node delegator contract from queue + // 3.1 remove from isNodeDelegator mapping + isNodeDelegator[nodeDelegatorAddress] = 0; + // 3.2 remove from nodeDelegatorQueue + nodeDelegatorQueue[ndcIndex] = nodeDelegatorQueue[nodeDelegatorQueue.length - 1]; + nodeDelegatorQueue.pop(); + + emit NodeDelegatorRemovedFromQueue(nodeDelegatorAddress); + } + + function _getNDCIndex(address nodeDelegatorAddress) internal view returns (uint256) { + uint256 length = nodeDelegatorQueue.length; + uint256 i; + for (; i < length;) { + if (nodeDelegatorQueue[i] == nodeDelegatorAddress) { + return i; + } + unchecked { + ++i; + } } - maxNodeDelegatorLimit = maxNodeDelegatorLimit_; - emit MaxNodeDelegatorLimitUpdated(maxNodeDelegatorLimit); + // If node delegator contract is not found in queue, revert + revert NodeDelegatorNotFound(); } - /// @notice update min amount to deposit - /// @dev only callable by LRT admin - /// @param minAmountToDeposit_ Minimum amount to deposit - function setMinAmountToDeposit(uint256 minAmountToDeposit_) external onlyLRTAdmin { - minAmountToDeposit = minAmountToDeposit_; - emit MinAmountToDepositUpdated(minAmountToDeposit_); + /// @dev reverts if NDC has native ETH balance in eigen layer or/and in itself. + function _checkResidueEthBalance(address nodeDelegatorAddress) internal view { + uint256 ndcEthBalance = + INodeDelegator(nodeDelegatorAddress).getETHEigenPodBalance() + address(nodeDelegatorAddress).balance; + + if (ndcEthBalance > maxNegligibleAmount) { + revert NodeDelegatorHasETH(); + } } - /// @dev Triggers stopped state. Contract must not be paused. - function pause() external onlyLRTManager { - _pause(); + /// @dev reverts if NDC has LST balance + function _checkResidueLSTBalance(address nodeDelegatorAddress) internal view { + address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); + uint256 supportedAssetsLength = supportedAssets.length; + + uint256 assetBalance; + for (uint256 i; i < supportedAssetsLength; ++i) { + if (supportedAssets[i] == LRTConstants.ETH_TOKEN) { + // this function only checks for residual LST balance + continue; + } + + assetBalance = IERC20(supportedAssets[i]).balanceOf(nodeDelegatorAddress) + + INodeDelegator(nodeDelegatorAddress).getAssetBalance(supportedAssets[i]); + + if (assetBalance > maxNegligibleAmount) { + revert NodeDelegatorHasAssetBalance(supportedAssets[i], assetBalance); + } + } } - /// @dev Returns to normal state. Contract must be paused - function unpause() external onlyLRTAdmin { - _unpause(); + function _beforeDeposit( + address asset, + uint256 depositAmount, + uint256 minRSETHAmountExpected + ) + private + view + returns (uint256 rsethAmountToMint) + { + if (depositAmount == 0 || depositAmount < minAmountToDeposit) { + revert InvalidAmountToDeposit(); + } + + if (_checkIfDepositAmountExceedesCurrentLimit(asset, depositAmount)) { + revert MaximumDepositLimitReached(); + } + + rsethAmountToMint = getRsETHAmountToMint(asset, depositAmount); + + if (rsethAmountToMint < minRSETHAmountExpected) { + revert MinimumAmountToReceiveNotMet(); + } } - receive() external payable { } + /// @notice checks if deposit amount exceeds current limit + /// @param asset Asset address + /// @param amount Asset amount + /// @return bool true if deposit amount exceeds current limit + function _checkIfDepositAmountExceedesCurrentLimit(address asset, uint256 amount) internal view returns (bool) { + uint256 totalAssetDeposits = getTotalAssetDeposits(asset); + if (asset == LRTConstants.ETH_TOKEN) { + return (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)); + } + return (totalAssetDeposits + amount > lrtConfig.depositLimitByAsset(asset)); + } + + /// @dev private function to mint rseth + /// @param rsethAmountToMint Amount of rseth minted + function _mintRsETH(uint256 rsethAmountToMint) private { + address rsethToken = lrtConfig.rsETH(); + // mint rseth for user + IRSETH(rsethToken).mint(msg.sender, rsethAmountToMint); + } } diff --git a/contracts/LRTOracle.sol b/contracts/LRTOracle.sol index bf66c93..df5627a 100644 --- a/contracts/LRTOracle.sol +++ b/contracts/LRTOracle.sol @@ -9,16 +9,23 @@ import { IRSETH } from "./interfaces/IRSETH.sol"; import { IPriceFetcher } from "./interfaces/IPriceFetcher.sol"; import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; -import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /// @title LRTOracle Contract /// @notice oracle contract that calculates the exchange rate of assets contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable { mapping(address asset => address priceOracle) public override assetPriceOracle; + uint256 public override rsETHPrice; + uint256 public pricePercentageLimit; + + modifier onlySupportedOracle(address asset) { + if (assetPriceOracle[asset] == address(0)) { + revert AssetOracleNotSupported(); + } + _; + } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -35,20 +42,13 @@ contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable { } /*////////////////////////////////////////////////////////////// - view functions + write functions //////////////////////////////////////////////////////////////*/ - /// @notice Provides Asset/ETH exchange rate - /// @dev reads from priceFetcher interface which may fetch price from any supported oracle - /// @param asset the asset for which exchange rate is required - /// @return assetPrice exchange rate of asset - function getAssetPrice(address asset) public view onlySupportedAsset(asset) returns (uint256) { - return IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset); - } - /// @notice updates RSETH/ETH exchange rate /// @dev calculates based on stakedAsset value received from eigen layer function updateRSETHPrice() external { + uint256 oldRsETHPrice = rsETHPrice; address rsETHTokenAddress = lrtConfig.rsETH(); uint256 rsEthSupply = IRSETH(rsETHTokenAddress).totalSupply(); @@ -76,18 +76,57 @@ contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable { } rsETHPrice = totalETHInPool / rsEthSupply; - } - /*////////////////////////////////////////////////////////////// - write functions - //////////////////////////////////////////////////////////////*/ + if (_isNewPriceOffLimit(oldRsETHPrice, rsETHPrice)) revert RSETHPriceExceedsLimit(); + + emit RsETHPriceUpdate(rsETHPrice); + } - /// @dev add/update the price oracle of any supported asset + /// @dev add/update the price oracle of any asset /// @dev only onlyLRTAdmin is allowed /// @param asset asset address for which oracle price needs to be added/updated - function updatePriceOracleFor(address asset, address priceOracle) external onlyLRTAdmin onlySupportedAsset(asset) { + function updatePriceOracleFor(address asset, address priceOracle) external onlyLRTAdmin { UtilLib.checkNonZeroAddress(priceOracle); assetPriceOracle[asset] = priceOracle; emit AssetPriceOracleUpdate(asset, priceOracle); } + + /// @dev set the price percentage limit + /// @dev only onlyLRTAdmin is allowed + /// @param _pricePercentageLimit price percentage limit + function setPricePercentageLimit(uint256 _pricePercentageLimit) external onlyLRTAdmin { + pricePercentageLimit = _pricePercentageLimit; + emit PricePercentageLimitUpdate(_pricePercentageLimit); + } + + /*////////////////////////////////////////////////////////////// + view functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Provides Asset/ETH exchange rate + /// @dev reads from priceFetcher interface which may fetch price from any supported oracle + /// @param asset the asset for which exchange rate is required + /// @return assetPrice exchange rate of asset + function getAssetPrice(address asset) public view onlySupportedOracle(asset) returns (uint256) { + return IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset); + } + + /*////////////////////////////////////////////////////////////// + private functions + //////////////////////////////////////////////////////////////*/ + + /// @notice check if new price is off the price percentage limit + /// @param oldPrice old price + /// @param newPrice new price + function _isNewPriceOffLimit(uint256 oldPrice, uint256 newPrice) private view returns (bool) { + // if oldPrice == newPrice, then no need to check + if (oldPrice == newPrice) return false; + // if pricePercentageLimit is 0, then no need to check + if (pricePercentageLimit == 0) return false; + + // calculate the difference between old and new price + uint256 diff = (oldPrice > newPrice) ? oldPrice - newPrice : newPrice - oldPrice; + uint256 percentage = (diff * 100) / oldPrice; + return percentage > pricePercentageLimit; + } } diff --git a/contracts/LRTUnstakingVault.sol b/contracts/LRTUnstakingVault.sol new file mode 100644 index 0000000..fbfe23b --- /dev/null +++ b/contracts/LRTUnstakingVault.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { UtilLib } from "./utils/UtilLib.sol"; +import { LRTConstants } from "./utils/LRTConstants.sol"; +import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol"; + +import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; +import { IStrategy } from "./external/eigenlayer/interfaces/IStrategy.sol"; +import { IEigenDelegationManager } from "./external/eigenlayer/interfaces/IEigenDelegationManager.sol"; +import { IEigenDelayedWithdrawalRouter } from "./external/eigenlayer/interfaces/IEigenDelayedWithdrawalRouter.sol"; +import { ILRTWithdrawalManager } from "./interfaces/ILRTWithdrawalManager.sol"; +import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; +import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; + +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/// @title LRTUnstakingVault Contract +/// @notice The contract that handles the unstaking of assets +contract LRTUnstakingVault is + ILRTUnstakingVault, + LRTConfigRoleChecker, + PausableUpgradeable, + ReentrancyGuardUpgradeable +{ + using SafeERC20 for IERC20; + + // Mapping from asset addresses to the total number of shares currently undergoing the unstaking process in + // EigenLayer. This count is critical for accurately calculating the price of assets. + mapping(address asset => uint256) public sharesUnstaking; + + modifier onlyLRTNodeDelegator() { + ILRTDepositPool lrtDepositPool = ILRTDepositPool(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); + + if (lrtDepositPool.isNodeDelegator(msg.sender) != 1) { + revert CallerNotLRTNodeDelegator(); + } + _; + } + + modifier onlyLRTWithdrawalManager() { + if (msg.sender != lrtConfig.getContract(LRTConstants.LRT_WITHDRAW_MANAGER)) { + revert CallerNotLRTWithdrawalManager(); + } + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initializes the contract + /// @param lrtConfigAddr LRT config address + function initialize(address lrtConfigAddr) external initializer { + UtilLib.checkNonZeroAddress(lrtConfigAddr); + __Pausable_init(); + __ReentrancyGuard_init(); + + lrtConfig = ILRTConfig(lrtConfigAddr); + emit UpdatedLRTConfig(lrtConfigAddr); + } + + /*////////////////////////////////////////////////////////////// + receive functions + //////////////////////////////////////////////////////////////*/ + + receive() external payable { + emit EthReceived(msg.sender, msg.value); + } + + /// @dev receive from LRTDepositPool + function receiveFromLRTDepositPool() external payable { } + + /// @dev receive from NodeDelegator + function receiveFromNodeDelegator() external payable { } + + /*////////////////////////////////////////////////////////////// + write functions + //////////////////////////////////////////////////////////////*/ + + /// @notice This is used by withdrawal manager when unlocking assets. The unlocked assets are pulled from the vault + /// and used to pay the user. + /// @param asset The asset address. + /// @param amount The amount of asset to redeem. + function redeem(address asset, uint256 amount) external nonReentrant onlyLRTWithdrawalManager { + if (asset == LRTConstants.ETH_TOKEN) { + ILRTWithdrawalManager(msg.sender).receiveFromLRTUnstakingVault{ value: amount }(); + } else { + IERC20(asset).safeTransfer(msg.sender, amount); + } + } + + /// @notice Adds shares that are in unstaking process. + /// @param asset The asset address. + /// @param amount The amount of shares added to the unstaking pool. + /// @dev This function is only callable by the NodeDelegator contracts when it initiates unstaking process. + function addSharesUnstaking(address asset, uint256 amount) external onlyLRTNodeDelegator { + // Increase the tracking of shares currently in the process of unstaking from Eigenlayer. + sharesUnstaking[asset] += amount; + } + + /// @notice Adds shares that are in unstaking process. + /// @param asset The asset address. + /// @param amount The amount of shares added to the unstaking pool. + /// @dev This function is only callable by the NodeDelegator contracts when it initiates unstaking process. + function reduceSharesUnstaking(address asset, uint256 amount) external onlyLRTNodeDelegator { + // Increase the tracking of shares currently in the process of unstaking from Eigenlayer. + sharesUnstaking[asset] -= amount; + } + + /*////////////////////////////////////////////////////////////// + view functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Returns the total asset amount in unstaking process. + /// @param asset The asset address. + /// @return The total asset amount in unstaking process. + function getAssetsUnstaking(address asset) external view onlySupportedAsset(asset) returns (uint256) { + if (asset == LRTConstants.ETH_TOKEN) { + return sharesUnstaking[asset]; + } + + IStrategy strategy = IStrategy(lrtConfig.assetStrategy(asset)); + return strategy.sharesToUnderlyingView(sharesUnstaking[asset]); + } + + /// @notice Returns the the vaults balance of the asset. + /// @param asset The asset address. + /// @return The balance of the asset. + function balanceOf(address asset) external view returns (uint256) { + if (asset == LRTConstants.ETH_TOKEN) { + return address(this).balance; + } else { + return IERC20(asset).balanceOf(address(this)); + } + } +} diff --git a/contracts/LRTWithdrawalManager.sol b/contracts/LRTWithdrawalManager.sol new file mode 100644 index 0000000..05adc82 --- /dev/null +++ b/contracts/LRTWithdrawalManager.sol @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { UtilLib } from "./utils/UtilLib.sol"; +import { LRTConstants } from "./utils/LRTConstants.sol"; +import { DoubleEndedQueue } from "./utils/DoubleEndedQueue.sol"; + +import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol"; +import { IRSETH } from "./interfaces/IRSETH.sol"; +import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; +import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; +import { ILRTWithdrawalManager, IStrategy, IERC20 } from "./interfaces/ILRTWithdrawalManager.sol"; +import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; +import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; + +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/// @title LRTWithdrawalManager - Withdraw Manager Contract for rsETH => LSTs +/// @notice Handles LST asset withdraws +contract LRTWithdrawalManager is + ILRTWithdrawalManager, + LRTConfigRoleChecker, + PausableUpgradeable, + ReentrancyGuardUpgradeable +{ + using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque; + using SafeERC20 for IERC20; + + mapping(address asset => uint256) public minRsEthAmountToWithdraw; + uint256 public withdrawalDelayBlocks; + + // Next available nonce for withdrawal requests per asset, indicating total requests made. + mapping(address asset => uint256 nonce) public nextUnusedNonce; + + // Next nonce for which a withdrawal request remains locked. + mapping(address asset => uint256 requestNonce) public nextLockedNonce; + + // Mapping from a unique request identifier to its corresponding withdrawal request + mapping(bytes32 requestId => WithdrawalRequest) public withdrawalRequests; + + // Maps each asset to user addresses, pointing to an ordert list of their withdrawal request nonces. + // Utilizes a double-ended queue for efficient management and removal of initial requests. + mapping(address asset => mapping(address user => DoubleEndedQueue.Uint256Deque requestNonces)) public + userAssociatedNonces; + + // Asset amount commited to be withdrawn by users. + mapping(address asset => uint256 amount) public assetsCommitted; + + modifier onlySupportedStrategy(address asset) { + if (asset != LRTConstants.ETH_TOKEN && lrtConfig.assetStrategy(asset) == address(0)) { + revert StrategyNotSupported(); + } + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the contract + /// @param lrtConfigAddr LRT config address + function initialize(address lrtConfigAddr) external initializer { + UtilLib.checkNonZeroAddress(lrtConfigAddr); + __Pausable_init(); + __ReentrancyGuard_init(); + withdrawalDelayBlocks = 8 days / 12 seconds; + + lrtConfig = ILRTConfig(lrtConfigAddr); + emit UpdatedLRTConfig(lrtConfigAddr); + } + + /*////////////////////////////////////////////////////////////// + receive functions + //////////////////////////////////////////////////////////////*/ + + receive() external payable { } + + /// @dev receive from LRTUnstakingVault + function receiveFromLRTUnstakingVault() external payable { } + + /*////////////////////////////////////////////////////////////// + User Withdrawal functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Initiates a withdrawal request for converting rsETH to a specified LST. + /// @param asset The LST address the user wants to receive. + /// @param rsETHUnstaked The amount of rsETH the user wishes to unstake. + /// @dev This function is only callable by the user and is used to initiate a withdrawal request for a specific + /// asset. Will be finalised by calling `completeWithdrawal` after the manager unlocked the request and the delay + /// has past. There is an edge case were the user withdraws last underlying asset and that asset gets slashed. + function initiateWithdrawal( + address asset, + uint256 rsETHUnstaked + ) + external + override + nonReentrant + whenNotPaused + onlySupportedAsset(asset) + onlySupportedStrategy(asset) + { + if (rsETHUnstaked == 0 || rsETHUnstaked < minRsEthAmountToWithdraw[asset]) revert InvalidAmountToWithdraw(); + + IERC20(lrtConfig.rsETH()).safeTransferFrom(msg.sender, address(this), rsETHUnstaked); + + uint256 expectedAssetAmount = getExpectedAssetAmount(asset, rsETHUnstaked); + + // Ensure the withdrawal does not exceed the available shares. + if (expectedAssetAmount > getAvailableAssetAmount(asset)) revert ExceedAmountToWithdraw(); + + // preventing over-withdrawal. + assetsCommitted[asset] += expectedAssetAmount; + + _addUserWithdrawalRequest(asset, rsETHUnstaked, expectedAssetAmount); + } + + /// @notice Completes a user's withdrawal process by transferring the ETH/LST amount corresponding to the rsETH + /// unstaked. + /// @param asset The asset address the user wishes to withdraw. + function completeWithdrawal(address asset) external nonReentrant whenNotPaused onlySupportedAsset(asset) { + // Retrieve and remove the oldest withdrawal request for the user. + uint256 usersFirstWithdrawalRequestNonce = userAssociatedNonces[asset][msg.sender].popFront(); + // Ensure the request is already unlocked. + if (usersFirstWithdrawalRequestNonce >= nextLockedNonce[asset]) revert WithdrawalLocked(); + + bytes32 requestId = getRequestId(asset, usersFirstWithdrawalRequestNonce); + WithdrawalRequest memory request = withdrawalRequests[requestId]; + + delete withdrawalRequests[requestId]; + + // Check that the withdrawal delay has passed since the request's initiation. + if (block.number < request.withdrawalStartBlock + withdrawalDelayBlocks) revert WithdrawalDelayNotPassed(); + + if (asset == LRTConstants.ETH_TOKEN) { + (bool sent,) = payable(msg.sender).call{ value: request.expectedAssetAmount }(""); + if (!sent) revert EthTransferFailed(); + } else { + IERC20(asset).safeTransfer(msg.sender, request.expectedAssetAmount); + } + + emit AssetWithdrawalFinalized(msg.sender, asset, request.rsETHUnstaked, request.expectedAssetAmount); + } + + /*////////////////////////////////////////////////////////////// + operational functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Unlocks assets in the queue up to a specified limit. + /// @param asset The address of the asset to unlock. + /// @param firstExcludedIndex First withdrawal requests index that will not be considered for unlocking. + /// @param minimumAssetPrice The minimum acceptable price for the asset. + /// @param minimumRsEthPrice The minimum acceptable price for rsETH. + function unlockQueue( + address asset, + uint256 firstExcludedIndex, + uint256 minimumAssetPrice, + uint256 minimumRsEthPrice + ) + external + nonReentrant + onlySupportedAsset(asset) + onlyLRTOperator + returns (uint256 rsETHBurned, uint256 assetAmountUnlocked) + { + ILRTOracle lrtOracle = ILRTOracle(lrtConfig.getContract(LRTConstants.LRT_ORACLE)); + ILRTUnstakingVault unstakingVault = ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)); + uint256 rsETHPrice = lrtOracle.rsETHPrice(); + uint256 assetPrice = lrtOracle.getAssetPrice(asset); + + // Ensure the current prices meet or exceed the minimum required prices. + if (rsETHPrice < minimumRsEthPrice) revert RsETHPriceMustBeGreaterMinimum(rsETHPrice); + if (assetPrice < minimumAssetPrice) revert AssetPriceMustBeGreaterMinimum(assetPrice); + + uint256 totalAvailableAssets = unstakingVault.balanceOf(asset); + + if (totalAvailableAssets == 0) revert AmountMustBeGreaterThanZero(); + + // Updates and unlocks withdrawal requests up to a specified upper limit or until allocated assets are fully + // utilized. + (rsETHBurned, assetAmountUnlocked) = + _unlockWithdrawalRequests(asset, totalAvailableAssets, rsETHPrice, assetPrice, firstExcludedIndex); + + if (rsETHBurned != 0) IRSETH(lrtConfig.rsETH()).burnFrom(address(this), rsETHBurned); + //Take the amount to distribute from vault + unstakingVault.redeem(asset, assetAmountUnlocked); + + emit AssetUnlocked(asset, rsETHBurned, assetAmountUnlocked, rsETHPrice, assetPrice); + } + + /*////////////////////////////////////////////////////////////// + setters + //////////////////////////////////////////////////////////////*/ + + /// @notice update min amount to withdraw + /// @dev only callable by LRT admin + /// @param asset Asset address + /// @param minRsEthAmountToWithdraw_ Minimum amount to withdraw + function setMinRsEthAmountToWithdraw(address asset, uint256 minRsEthAmountToWithdraw_) external onlyLRTAdmin { + minRsEthAmountToWithdraw[asset] = minRsEthAmountToWithdraw_; + emit MinAmountToWithdrawUpdated(asset, minRsEthAmountToWithdraw_); + } + + /// @notice update withdrawal delay + /// @dev only callable by LRT admin + /// @param withdrawalDelayBlocks_ The amount of blocks to wait till to complete a withdraw + function setWithdrawalDelayBlocks(uint256 withdrawalDelayBlocks_) external onlyLRTAdmin { + if (7 days / 12 seconds > withdrawalDelayBlocks_) revert WithdrawalDelayTooSmall(); + withdrawalDelayBlocks = withdrawalDelayBlocks_; + emit WithdrawalDelayBlocksUpdated(withdrawalDelayBlocks); + } + + /// @dev Triggers stopped state. Contract must not be paused. + function pause() external onlyRole(LRTConstants.PAUSER_ROLE) { + _pause(); + } + + /// @dev Returns to normal state. Contract must be paused + function unpause() external onlyLRTAdmin { + _unpause(); + } + + /*////////////////////////////////////////////////////////////// + view functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Get request id + /// @param asset Asset address + /// @param requestIndex The requests index to generate id for + function getRequestId(address asset, uint256 requestIndex) public pure returns (bytes32) { + return keccak256(abi.encodePacked(asset, requestIndex)); + } + + /// @notice Get asset amount to receive when trading in rsETH + /// @param asset Asset address of LST to receive + /// @param amount rsETH amount to convert + /// @return underlyingToReceive Amount of underlying to receive + function getExpectedAssetAmount( + address asset, + uint256 amount + ) + public + view + override + returns (uint256 underlyingToReceive) + { + // setup oracle contract + ILRTOracle lrtOracle = ILRTOracle(lrtConfig.getContract(LRTConstants.LRT_ORACLE)); + + // calculate underlying asset amount to receive based on rsETH amount and asset exchange rate + underlyingToReceive = amount * lrtOracle.rsETHPrice() / lrtOracle.getAssetPrice(asset); + } + + /// @notice Calculates the amount of asset available for withdrawal. + /// @param asset The asset address. + /// @return availableAssetAmount The asset amount avaialble for withdrawal. + function getAvailableAssetAmount(address asset) public view override returns (uint256 availableAssetAmount) { + ILRTDepositPool lrtDepositPool = ILRTDepositPool(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); + uint256 totalAssets = lrtDepositPool.getTotalAssetDeposits(asset); + availableAssetAmount = totalAssets > assetsCommitted[asset] ? totalAssets - assetsCommitted[asset] : 0; + } + + /// @notice View user withdrawal request + /// @param asset Asset address + /// @param user User address + /// @param userIndex Index in list of users withdrawal request + function getUserWithdrawalRequest( + address asset, + address user, + uint256 userIndex + ) + public + view + override + returns (uint256 rsETHAmount, uint256 expectedAssetAmount, uint256 withdrawalStartBlock, uint256 userNonce) + { + userNonce = userAssociatedNonces[asset][user].at(userIndex); + bytes32 requestId = getRequestId(asset, userNonce); + rsETHAmount = withdrawalRequests[requestId].rsETHUnstaked; + expectedAssetAmount = withdrawalRequests[requestId].expectedAssetAmount; + withdrawalStartBlock = withdrawalRequests[requestId].withdrawalStartBlock; + } + + /*////////////////////////////////////////////////////////////// + internal functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Registers a new request for withdrawing an asset in exchange for rsETH. + /// @param asset The address of the asset being withdrawn. + /// @param rsETHUnstaked The amount of rsETH being exchanged. + /// @param expectedAssetAmount The expected amount of the asset to be received upon withdrawal completion. + function _addUserWithdrawalRequest(address asset, uint256 rsETHUnstaked, uint256 expectedAssetAmount) internal { + uint256 nextUnusedNonce_ = nextUnusedNonce[asset]; + + // Generate a unique identifier for the new withdrawal request. + bytes32 requestId = getRequestId(asset, nextUnusedNonce_); + + // Create and store the new withdrawal request. + withdrawalRequests[requestId] = WithdrawalRequest({ + rsETHUnstaked: rsETHUnstaked, + expectedAssetAmount: expectedAssetAmount, + withdrawalStartBlock: block.number + }); + + // Map the user to the newly created request index and increment the nonce for future requests. + userAssociatedNonces[asset][msg.sender].pushBack(nextUnusedNonce_); + nextUnusedNonce[asset] = nextUnusedNonce_ + 1; + + emit AssetWithdrawalQueued(msg.sender, asset, rsETHUnstaked, nextUnusedNonce_); + } + + /// @dev Unlocks user withdrawal requests based on current asset availability and prices. + /// Iterates through pending requests and unlocks them until the provided asset amount is fully allocated. + /// @param asset The asset's address for which withdrawals are being processed. + /// @param rsETHPrice Current rsETH to ETH exchange rate. + /// @param assetPrice Current asset to ETH exchange rate. + /// @param firstExcludedIndex First withdrawal requests index that will not be considered for unlocking. + /// @return rsETHAmountToBurn The total amount of rsETH unlocked for withdrawals. + /// @return assetAmountToUnlock The total asset amount allocated to unlocked withdrawals. + function _unlockWithdrawalRequests( + address asset, + uint256 availableAssetAmount, + uint256 rsETHPrice, + uint256 assetPrice, + uint256 firstExcludedIndex + ) + internal + returns (uint256 rsETHAmountToBurn, uint256 assetAmountToUnlock) + { + // Check that upper limit is in the range of existing withdrawal requests. If it is greater set it to the first + // nonce with no withdrawal request. + if (firstExcludedIndex > nextUnusedNonce[asset]) { + firstExcludedIndex = nextUnusedNonce[asset]; + } + + uint256 nextLockedNonce_ = nextLockedNonce[asset]; + // Revert when trying to unlock a request that has already been unlocked + if (nextLockedNonce_ >= firstExcludedIndex) revert NoPendingWithdrawals(); + + while (nextLockedNonce_ < firstExcludedIndex) { + bytes32 requestId = getRequestId(asset, nextLockedNonce_); + WithdrawalRequest storage request = withdrawalRequests[requestId]; + + // Calculate the amount user will recieve + uint256 payoutAmount = _calculatePayoutAmount(request, rsETHPrice, assetPrice); + + if (availableAssetAmount < payoutAmount) break; // Exit if not enough assets to cover this request + + assetsCommitted[asset] -= request.expectedAssetAmount; + // Set the amount the user will recieve + request.expectedAssetAmount = payoutAmount; + rsETHAmountToBurn += request.rsETHUnstaked; + availableAssetAmount -= payoutAmount; + assetAmountToUnlock += payoutAmount; + unchecked { + nextLockedNonce_++; + } + } + nextLockedNonce[asset] = nextLockedNonce_; + } + + /// @notice Determines the final amount to be disbursed to the user, based on the lesser of the initially + /// expected asset amount and the currently calculated return. + /// @param request The specific withdrawal request being processed. + /// @param rsETHPrice The latest exchange rate of rsETH to ETH. + /// @param assetPrice The latest exchange rate of the asset to ETH. + /// @return The final amount the user is going to receive. + function _calculatePayoutAmount( + WithdrawalRequest storage request, + uint256 rsETHPrice, + uint256 assetPrice + ) + private + view + returns (uint256) + { + uint256 currentReturn = (request.rsETHUnstaked * rsETHPrice) / assetPrice; + return (request.expectedAssetAmount < currentReturn) ? request.expectedAssetAmount : currentReturn; + } +} diff --git a/contracts/NodeDelegator.sol b/contracts/NodeDelegator.sol index 2f92c4f..bd0a093 100644 --- a/contracts/NodeDelegator.sol +++ b/contracts/NodeDelegator.sol @@ -1,31 +1,52 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; -import { UtilLib } from "./utils/UtilLib.sol"; -import { LRTConstants } from "./utils/LRTConstants.sol"; -import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol"; - -import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; -import { IStrategy } from "./interfaces/IStrategy.sol"; -import { IEigenStrategyManager } from "./interfaces/IEigenStrategyManager.sol"; -import { IEigenDelayedWithdrawalRouter } from "./interfaces/IEigenDelayedWithdrawalRouter.sol"; - +// openzeppelin or other standard contracts import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { IEigenPodManager } from "./interfaces/IEigenPodManager.sol"; -import { IEigenPod, BeaconChainProofs, IBeaconDeposit } from "./interfaces/IEigenPod.sol"; +// external libraries, interfaces, contracts +import { BeaconChainProofs } from "./external/eigenlayer/libraries/BeaconChainProofs.sol"; + +import { IEigenPod, IBeaconDeposit } from "./external/eigenlayer/interfaces/IEigenPod.sol"; +import { IStrategy } from "./external/eigenlayer/interfaces/IStrategy.sol"; +import { IEigenStrategyManager } from "./external/eigenlayer/interfaces/IEigenStrategyManager.sol"; +import { IEigenPodManager } from "./external/eigenlayer/interfaces/IEigenPodManager.sol"; +import { IEigenDelegationManager } from "./external/eigenlayer/interfaces/IEigenDelegationManager.sol"; +import { IEigenDelayedWithdrawalRouter } from "./external/eigenlayer/interfaces/IEigenDelayedWithdrawalRouter.sol"; + +// protocol libraries, interfaces, contracts +import { UtilLib } from "./utils/UtilLib.sol"; +import { LRTConstants } from "./utils/LRTConstants.sol"; +import { LRTConfigRoleChecker } from "./utils/LRTConfigRoleChecker.sol"; + +import { ILRTConfig } from "./interfaces/ILRTConfig.sol"; +import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; +import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; +import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; +import { IFeeReceiver } from "./interfaces/IFeeReceiver.sol"; /// @title NodeDelegator Contract /// @notice The contract that handles the depositing of assets into strategies contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable { + using SafeERC20 for IERC20; + /// @dev The EigenPod is created and owned by this contract IEigenPod public eigenPod; + /// @dev Tracks the balance staked to validators and has yet to have the credentials verified with EigenLayer. /// call verifyWithdrawalCredentialsAndBalance in EL to verify the validator credentials on EigenLayer uint256 public stakedButUnverifiedNativeETH; + /// @dev address of eigenlayer operator to which all restaked funds are delegated to + /// @dev it is only possible to delegate fully to only one operator per NDC contract + address public elOperatorDelegatedTo; + + /// @dev amount of eth expected to receive from extra eth staked for validators + uint256 public extraStakeToReceive; + /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); @@ -42,26 +63,26 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea emit UpdatedLRTConfig(lrtConfigAddr); } - function createEigenPod() external onlyLRTManager { - IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); - eigenPodManager.createPod(); - eigenPod = eigenPodManager.ownerToPod(address(this)); + /// @dev due to a bit heavy logic, eth transfer using `transfer()` and `send()` will fail + /// @dev hence please use `call()` to send eth to this contract + receive() external payable { + if (msg.sender != address(eigenPod)) { + // then these are extraStakes or rewards + uint256 extraStakeReceived = UtilLib.getMin(msg.value, extraStakeToReceive); + _reduceExtraStakes(extraStakeReceived); - emit EigenPodCreated(address(eigenPod), address(this)); + // rest are rewards + _sendRewardsToRewardReceiver(msg.value - extraStakeReceived); + } + // else if received from eigenPod + // then these are assumed to be exit validators' eth + // just receive it here + emit ETHReceived(msg.sender, msg.value); } - /// @notice Approves the maximum amount of an asset to the eigen strategy manager - /// @dev only supported assets can be deposited and only called by the LRT manager - /// @param asset the asset to deposit - function maxApproveToEigenStrategyManager(address asset) - external - override - onlySupportedAsset(asset) - onlyLRTManager - { - address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER); - IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max); - } + /*////////////////////////////////////////////////////////////// + EigenLayer Interactions + //////////////////////////////////////////////////////////////*/ /// @notice Deposits an asset lying in this NDC into its strategy /// @dev only supported assets can be deposited and only called by the LRT manager @@ -69,8 +90,8 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea function depositAssetIntoStrategy(address asset) external override - whenNotPaused nonReentrant + whenNotPaused onlySupportedAsset(asset) onlyLRTManager { @@ -89,79 +110,43 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea emit AssetDepositIntoStrategy(asset, strategy, balance); } - /// @notice Transfers an asset back to the LRT deposit pool - /// @dev only supported assets can be transferred and only called by the LRT manager - /// @param asset the asset to transfer - /// @param amount the amount to transfer - function transferBackToLRTDepositPool( - address asset, - uint256 amount + /// @notice Delegates shares (accrued by restaking LSTs/native eth) to an EigenLayer operator + /// @param elOperator The address of the operator to delegate to + /// @param approverSignatureAndExpiry Verifies the operator approves of this delegation + /// @param approverSalt A unique single use value tied to an individual signature. + /// @dev delegationManager.delegateTo will check if the operator is valid, if ndc is already delegated to + function delegateTo( + address elOperator, + IEigenDelegationManager.SignatureWithExpiry memory approverSignatureAndExpiry, + bytes32 approverSalt ) external - whenNotPaused - nonReentrant - onlySupportedAsset(asset) onlyLRTManager { - address lrtDepositPool = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); - - bool success; - if (asset == LRTConstants.ETH_TOKEN) { - (success,) = payable(lrtDepositPool).call{ value: amount }(""); - } else { - success = IERC20(asset).transfer(lrtDepositPool, amount); - } - - if (!success) { - revert TokenTransferFailed(); - } - } - - /// @notice Fetches balance of all assets staked in eigen layer through this contract - /// @return assets the assets that the node delegator has deposited into strategies - /// @return assetBalances the balances of the assets that the node delegator has deposited into strategies - function getAssetBalances() - external - view - override - returns (address[] memory assets, uint256[] memory assetBalances) - { - address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER); - - (IStrategy[] memory strategies,) = - IEigenStrategyManager(eigenlayerStrategyManagerAddress).getDeposits(address(this)); - - uint256 strategiesLength = strategies.length; - assets = new address[](strategiesLength); - assetBalances = new uint256[](strategiesLength); + UtilLib.checkNonZeroAddress(elOperator); + elOperatorDelegatedTo = elOperator; - for (uint256 i = 0; i < strategiesLength;) { - assets[i] = address(IStrategy(strategies[i]).underlyingToken()); - assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this)); - unchecked { - ++i; - } - } + IEigenDelegationManager elDelegationManager = + IEigenDelegationManager(lrtConfig.getContract(LRTConstants.EIGEN_DELEGATION_MANAGER)); + elDelegationManager.delegateTo(elOperator, approverSignatureAndExpiry, approverSalt); + emit ElSharesDelegated(elOperator); } - /// @dev Returns the balance of an asset that the node delegator has deposited into the strategy - /// @param asset the asset to get the balance of - /// @return stakedBalance the balance of the asset - function getAssetBalance(address asset) external view override returns (uint256) { - address strategy = lrtConfig.assetStrategy(asset); - if (strategy == address(0)) { - return 0; - } + function createEigenPod() external onlyLRTManager { + IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); + eigenPodManager.createPod(); + eigenPod = eigenPodManager.ownerToPod(address(this)); - return IStrategy(strategy).userUnderlyingView(address(this)); + emit EigenPodCreated(address(eigenPod), address(this)); } - /// @dev Returns the balance of an asset that the node delegator has deposited into its EigenPod strategy - function getETHEigenPodBalance() external view override returns (uint256 ethStaked) { - // TODO: Implement functionality to manage pending withdrawals and accommodate negative shares once withdrawal - // feature is activated. Additionally, ensure verification of both staked but unverified and staked and verified - // ETH native supply NDCs as provided to Eigenlayer. - ethStaked = stakedButUnverifiedNativeETH; + /// @dev activates eigenPod, i.e. enables all M2 functions + /// restricts execution of few functions, check `hasEnabledRestaking` modifier in EigenPod + /// NOTE: creates a delayedWithdrawal for the eth accumulated on eigenPod (skimmed from beacon chain) + /// NOTE: newly created M2 pods are already activated + function activateRestaking() external onlyLRTManager { + eigenPod.activateRestaking(); + emit RestakingActivated(); } /// @notice Stake ETH from NDC into EigenLayer. it calls the stake function in the EigenPodManager @@ -181,12 +166,12 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea whenNotPaused onlyLRTOperator { - IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); - eigenPodManager.stake{ value: 32 ether }(pubkey, signature, depositDataRoot); - // tracks staked but unverified native ETH stakedButUnverifiedNativeETH += 32 ether; + IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); + eigenPodManager.stake{ value: 32 ether }(pubkey, signature, depositDataRoot); + emit ETHStaked(pubkey, 32 ether); } @@ -214,38 +199,282 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea if (expectedDepositRoot != actualDepositRoot) { revert InvalidDepositRoot(expectedDepositRoot, actualDepositRoot); } - IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); - eigenPodManager.stake{ value: 32 ether }(pubkey, signature, depositDataRoot); // tracks staked but unverified native ETH stakedButUnverifiedNativeETH += 32 ether; + IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); + eigenPodManager.stake{ value: 32 ether }(pubkey, signature, depositDataRoot); + emit ETHStaked(pubkey, 32 ether); } - /// @dev initiate a delayed withdraw of the ETH before the eigenpod is verified - /// which will be available to claim after withdrawalDelay blocks - function initiateWithdrawRewards() external onlyLRTOperator { - uint256 eigenPodBalance = address(eigenPod).balance; - uint256 ethValidatorMinBalanceThreshold = 16 ether; - if (eigenPodBalance > ethValidatorMinBalanceThreshold) { - revert InvalidRewardAmount(); + /** + * @notice This function verifies that the withdrawal credentials of validator(s) owned by the this NDC are pointed + * to EigenPod. It also verifies the effective balance of the validator. It verifies the provided proof of the + * ETH validator against the beacon chain state root, marks the validator as 'active' in EigenLayer, and credits the + * restaked ETH in Eigenlayer. + * @param oracleTimestamp is the Beacon Chain timestamp whose state root the `proof` will be proven against. + * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs + * @param withdrawalCredentialProofs is an array of proofs, where each proof proves each ETH validator's balance and + * withdrawal credentials against a beacon chain state root + * @param validatorFields are the fields of the "Validator Container", refer to consensus specs + * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator + */ + function verifyWithdrawalCredentials( + uint64 oracleTimestamp, + BeaconChainProofs.StateRootProof calldata stateRootProof, + uint40[] calldata validatorIndices, + bytes[] calldata withdrawalCredentialProofs, + bytes32[][] calldata validatorFields + ) + external + onlyLRTOperator + { + // reduce the eth amount that is verified + stakedButUnverifiedNativeETH -= (validatorFields.length * (32 ether)); + + eigenPod.verifyWithdrawalCredentials( + oracleTimestamp, stateRootProof, validatorIndices, withdrawalCredentialProofs, validatorFields + ); + } + + /// @notice undelegates from operator and removes all currently active shares + function undelegate() external whenNotPaused onlyLRTManager { + elOperatorDelegatedTo = address(0); + + IEigenDelegationManager elDelegationManager = + IEigenDelegationManager(lrtConfig.getContract(LRTConstants.EIGEN_DELEGATION_MANAGER)); + ILRTUnstakingVault lrtUnstakingVault = + ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)); + address beaconChainETHStrategy = lrtConfig.getContract(LRTConstants.BEACON_CHAIN_ETH_STRATEGY); + + // Gather strategies and shares which will be removed from staker/operator during undelegation + (IStrategy[] memory strategies, uint256[] memory shares) = + elDelegationManager.getDelegatableShares(address(this)); + + // update shares unstaking in LRT unstaking vault + for (uint256 i = 0; i < strategies.length;) { + if (beaconChainETHStrategy == address(strategies[i])) { + lrtUnstakingVault.addSharesUnstaking(LRTConstants.ETH_TOKEN, shares[i]); + } else { + address token = address(strategies[i].underlyingToken()); + lrtUnstakingVault.addSharesUnstaking(token, shares[i]); + } + unchecked { + ++i; + } + } + + uint256 nonce = elDelegationManager.cumulativeWithdrawalsQueued(address(this)); + bytes32[] memory withdrawalRoots = elDelegationManager.undelegate(address(this)); + + emit WithdrawalQueued(nonce, address(this), withdrawalRoots); + emit Undelegated(); + } + + /// @notice Queues a withdrawal from the strategies + /// @param strategies Array of strategies withdrawals + /// @param shares Array of shares to withdraw + function initiateUnstaking( + IStrategy[] calldata strategies, + uint256[] calldata shares + ) + public + override + nonReentrant + whenNotPaused + onlyLRTOperator + returns (bytes32 withdrawalRoot) + { + IEigenDelegationManager.QueuedWithdrawalParams memory queuedWithdrawalParam = IEigenDelegationManager + .QueuedWithdrawalParams({ strategies: strategies, shares: shares, withdrawer: address(this) }); + + address beaconChainETHStrategy = lrtConfig.getContract(LRTConstants.BEACON_CHAIN_ETH_STRATEGY); + + ILRTUnstakingVault lrtUnstakingVault = + ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)); + for (uint256 i = 0; i < queuedWithdrawalParam.strategies.length;) { + if (beaconChainETHStrategy == address(queuedWithdrawalParam.strategies[i])) { + lrtUnstakingVault.addSharesUnstaking(LRTConstants.ETH_TOKEN, queuedWithdrawalParam.shares[i]); + } else { + address token = address(queuedWithdrawalParam.strategies[i].underlyingToken()); + address strategy = lrtConfig.assetStrategy(token); + + if (strategy != address(queuedWithdrawalParam.strategies[i])) { + revert StrategyIsNotSetForAsset(); + } + lrtUnstakingVault.addSharesUnstaking(token, queuedWithdrawalParam.shares[i]); + } + + unchecked { + ++i; + } + } + address elDelegationManagerAddr = lrtConfig.getContract(LRTConstants.EIGEN_DELEGATION_MANAGER); + IEigenDelegationManager elDelegationManager = IEigenDelegationManager(elDelegationManagerAddr); + + IEigenDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = + new IEigenDelegationManager.QueuedWithdrawalParams[](1); + queuedWithdrawalParams[0] = queuedWithdrawalParam; + uint256 nonce = elDelegationManager.cumulativeWithdrawalsQueued(address(this)); + bytes32[] memory withdrawalRoots = elDelegationManager.queueWithdrawals(queuedWithdrawalParams); + withdrawalRoot = withdrawalRoots[0]; + + emit WithdrawalQueued(nonce, address(this), withdrawalRoots); + } + + /// @notice Finalizes Eigenlayer withdrawal to enable processing of queued withdrawals + /// @param withdrawal Struct containing all data for the withdrawal + /// @param assets Array specifying the `token` input for each strategy's 'withdraw' function. + /// @param middlewareTimesIndex Index in the middleware times array for withdrawal eligibility check. + function completeUnstaking( + IEigenDelegationManager.Withdrawal calldata withdrawal, + IERC20[] calldata assets, + uint256 middlewareTimesIndex + ) + external + nonReentrant + whenNotPaused + onlyLRTOperator + { + uint256 assetCount = assets.length; + if (assetCount == 0 || assetCount != withdrawal.shares.length) { + // asset length and strategies length is checked by eigenlayer contracts in `completeQueuedWithdrawal` + revert InvalidWithdrawalData(); + } + + address elDelegationManagerAddr = lrtConfig.getContract(LRTConstants.EIGEN_DELEGATION_MANAGER); + address beaconChainETHStrategy = lrtConfig.getContract(LRTConstants.BEACON_CHAIN_ETH_STRATEGY); + address lrtUnstakingVaultAddr = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); + + ILRTUnstakingVault lrtUnstakingVault = ILRTUnstakingVault(lrtUnstakingVaultAddr); + + uint256[] memory balancesBefore = new uint256[](assetCount); + for (uint256 i = 0; i < assetCount;) { + lrtUnstakingVault.reduceSharesUnstaking(address(assets[i]), withdrawal.shares[i]); + if (address(beaconChainETHStrategy) != address(withdrawal.strategies[i])) { + balancesBefore[i] = assets[i].balanceOf(address(this)); + } else { + balancesBefore[i] = address(this).balance; + } + unchecked { + i++; + } } + // Finalize withdrawal with Eigenlayer Delegation Manager + IEigenDelegationManager(elDelegationManagerAddr).completeQueuedWithdrawal( + withdrawal, assets, middlewareTimesIndex, true + ); + + for (uint256 i = 0; i < assetCount;) { + if (address(beaconChainETHStrategy) != address(withdrawal.strategies[i])) { + uint256 amount = assets[i].balanceOf(address(this)) - balancesBefore[i]; + assets[i].transfer(lrtUnstakingVaultAddr, amount); + } + unchecked { + i++; + } + } + emit EigenLayerWithdrawalCompleted(withdrawal.staker, withdrawal.nonce, msg.sender); + } + + /// @notice initiate a delayed withdraw of ETH available at eigenPod + /// @dev this eth will be available to claim after withdrawalDelay blocks + /// @dev this method will be deprecated once eigenPod is activated + /// TODO: remove this function after eigenPod activation + function withdrawBeforeRestaking() external onlyLRTOperator { eigenPod.withdrawBeforeRestaking(); - emit ETHRewardsWithdrawInitiated(eigenPodBalance); } - /// @dev claims back the withdrawal amount initiated to this nodeDelegator contract - /// once withdrawal amount is claimable - function claimRewards(uint256 maxNumberOfDelayedWithdrawalsToClaim) external onlyLRTOperator { - uint256 balanceBefore = address(this).balance; + /// @notice claim delayed withdrawal entries (rewards + extraStakes) + /// @param maxNumberOfDelayedWithdrawalsToClaim the max number of delayed withdrawals to claim + /// @dev available to claim after a waiting period of withdrawalBlockDelay set by eigenLayer + /// @dev permissionless call + function claimDelayedWithdrawals(uint256 maxNumberOfDelayedWithdrawalsToClaim) external { address delayedRouterAddr = eigenPod.delayedWithdrawalRouter(); IEigenDelayedWithdrawalRouter elDelayedRouter = IEigenDelayedWithdrawalRouter(delayedRouterAddr); elDelayedRouter.claimDelayedWithdrawals(address(this), maxNumberOfDelayedWithdrawalsToClaim); - uint256 balanceAfter = address(this).balance; + } + + /*////////////////////////////////////////////////////////////// + Operational Functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Sends ETH from the LRT deposit pool to this contract + function sendETHFromDepositPoolToNDC() external payable override { + // only allow LRT deposit pool to send ETH to this contract + address lrtDepositPool = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); + if (msg.sender != lrtDepositPool) { + revert InvalidETHSender(); + } + + emit ETHDepositFromDepositPool(msg.value); + } + + /// @notice Transfers an asset back to the LRT deposit pool + /// @dev only supported assets can be transferred and only called by the LRT manager + /// @param asset the asset to transfer + /// @param amount the amount to transfer + function transferBackToLRTDepositPool( + address asset, + uint256 amount + ) + external + nonReentrant + whenNotPaused + onlySupportedAsset(asset) + onlyLRTManager + { + address lrtDepositPool = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); + + if (asset == LRTConstants.ETH_TOKEN) { + ILRTDepositPool(lrtDepositPool).receiveFromNodeDelegator{ value: amount }(); + emit EthTransferred(lrtDepositPool, amount); + } else { + IERC20(asset).safeTransfer(lrtDepositPool, amount); + } + } + + /// @notice Transfers ETH back to the LRT Unstaking Vault + /// @dev only supported assets can be transferred and only called by the LRT manager + /// @param amount the amount to transfer + function transferETHToLRTUnstakingVault(uint256 amount) external nonReentrant whenNotPaused onlyLRTManager { + address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); + ILRTUnstakingVault(lrtUnstakingVault).receiveFromNodeDelegator{ value: amount }(); + emit EthTransferred(lrtUnstakingVault, amount); + } + + /*////////////////////////////////////////////////////////////// + Other Write Functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Approves the maximum amount of an asset to the eigen strategy manager + /// @dev only supported assets can be deposited and only called by the LRT manager + /// @param asset the asset to deposit + function maxApproveToEigenStrategyManager(address asset) + external + override + onlySupportedAsset(asset) + onlyLRTManager + { + address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER); + IERC20(asset).approve(eigenlayerStrategyManagerAddress, type(uint256).max); + } - emit ETHRewardsClaimed(balanceAfter - balanceBefore); + /*////////////////////////////////////////////////////////////// + Setters / Update Functions + //////////////////////////////////////////////////////////////*/ + + /// @dev increments the amount of eth expected to receive from extra eth staked for validators + /// @param amount the amount to increment + function incrementExtraStakeToReceive(uint256 amount) external onlyLRTOperator { + extraStakeToReceive += amount; + if (extraStakeToReceive > stakedButUnverifiedNativeETH) { + revert InsufficientStakedButUnverifiedNativeETH(); + } + emit ETHExtraStakeToReceiveIncremented(amount); } /// @dev Triggers stopped state. Contract must not be paused. @@ -258,17 +487,84 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea _unpause(); } - /// @dev allow NodeDelegator to receive ETH - function sendETHFromDepositPoolToNDC() external payable override { - // only allow LRT deposit pool to send ETH to this contract - address lrtDepositPool = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); - if (msg.sender != lrtDepositPool) { - revert InvalidETHSender(); + /*////////////////////////////////////////////////////////////// + View Functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Fetches balance of all assets staked in eigen layer through this contract + /// @return assets the assets that the node delegator has deposited into strategies + /// @return assetBalances the balances of the assets that the node delegator has deposited into strategies + function getAssetBalances() + external + view + override + returns (address[] memory assets, uint256[] memory assetBalances) + { + address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER); + + (IStrategy[] memory strategies,) = + IEigenStrategyManager(eigenlayerStrategyManagerAddress).getDeposits(address(this)); + + uint256 strategiesLength = strategies.length; + assets = new address[](strategiesLength); + assetBalances = new uint256[](strategiesLength); + + for (uint256 i = 0; i < strategiesLength;) { + assets[i] = address(IStrategy(strategies[i]).underlyingToken()); + assetBalances[i] = IStrategy(strategies[i]).userUnderlyingView(address(this)); + unchecked { + ++i; + } } + } - emit ETHDepositFromDepositPool(msg.value); + /// @dev Returns the balance of an asset that the node delegator has deposited into the strategy + /// @param asset the asset to get the balance of + /// @return stakedBalance the balance of the asset + function getAssetBalance(address asset) external view override returns (uint256) { + address strategy = lrtConfig.assetStrategy(asset); + if (strategy == address(0)) { + return 0; + } + + return IStrategy(strategy).userUnderlyingView(address(this)); + } + + /// @dev Returns the amount of eth staked in eigenlayer through this ndc + function getETHEigenPodBalance() external view override returns (uint256 ethStaked) { + IEigenPodManager eigenPodManager = IEigenPodManager(lrtConfig.getContract(LRTConstants.EIGEN_POD_MANAGER)); + int256 nativeEthShares = eigenPodManager.podOwnerShares(address(this)); + + if (nativeEthShares < 0) { + // native eth shares are negative due to slashing and queue of more amount of eth withdrawal + uint256 nativeEthSharesDeficit = uint256(-nativeEthShares); + if (nativeEthSharesDeficit > stakedButUnverifiedNativeETH) { + return 0; + } else { + return stakedButUnverifiedNativeETH - nativeEthSharesDeficit; + } + } + + return stakedButUnverifiedNativeETH + uint256(nativeEthShares); + } + + /*////////////////////////////////////////////////////////////// + internal functions + //////////////////////////////////////////////////////////////*/ + + function _reduceExtraStakes(uint256 extraStakeReceived) internal { + if (extraStakeReceived <= 0) return; + + extraStakeToReceive -= extraStakeReceived; + stakedButUnverifiedNativeETH -= extraStakeReceived; + emit ExtraStakeReceived(extraStakeReceived); } - /// @dev allow NodeDelegator to receive ETH - receive() external payable { } + function _sendRewardsToRewardReceiver(uint256 rewardsAmount) internal { + if (rewardsAmount == 0) return; + + address rewardReceiver = lrtConfig.getContract(LRTConstants.REWARD_RECEIVER); + IFeeReceiver(rewardReceiver).receiveFromNodeDelegator{ value: rewardsAmount }(); + emit ETHRewardsReceived(rewardsAmount); + } } diff --git a/contracts/ccip/ConfirmedOwnerWithProposal.sol b/contracts/ccip/ConfirmedOwnerWithProposal.sol new file mode 100644 index 0000000..1eee520 --- /dev/null +++ b/contracts/ccip/ConfirmedOwnerWithProposal.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +interface IOwnable { + function owner() external returns (address); + + function transferOwnership(address recipient) external; + + function acceptOwnership() external; +} + +/** + * @title The ConfirmedOwner contract + * @notice A contract with helpers for basic contract ownership. + */ +contract ConfirmedOwnerWithProposal is IOwnable { + address private s_owner; + address private s_pendingOwner; + + event OwnershipTransferRequested(address indexed from, address indexed to); + event OwnershipTransferred(address indexed from, address indexed to); + + constructor(address newOwner, address pendingOwner) { + require(newOwner != address(0), "Cannot set owner to zero"); + + s_owner = newOwner; + if (pendingOwner != address(0)) { + _transferOwnership(pendingOwner); + } + } + + /** + * @notice Allows an owner to begin transferring ownership to a new address, + * pending. + */ + function transferOwnership(address to) public override onlyOwner { + _transferOwnership(to); + } + + /** + * @notice Allows an ownership transfer to be completed by the recipient. + */ + function acceptOwnership() external override { + require(msg.sender == s_pendingOwner, "Must be proposed owner"); + + address oldOwner = s_owner; + s_owner = msg.sender; + s_pendingOwner = address(0); + + emit OwnershipTransferred(oldOwner, msg.sender); + } + + /** + * @notice Get the current owner + */ + function owner() public view override returns (address) { + return s_owner; + } + + /** + * @notice validate, transfer ownership, and emit relevant events + */ + function _transferOwnership(address to) private { + require(to != msg.sender, "Cannot transfer to self"); + + s_pendingOwner = to; + + emit OwnershipTransferRequested(s_owner, to); + } + + /** + * @notice validate access + */ + function _validateOwnership() internal view { + require(msg.sender == s_owner, "Only callable by owner"); + } + + /** + * @notice Reverts if called by anyone other than the contract owner. + */ + modifier onlyOwner() { + _validateOwnership(); + _; + } +} diff --git a/contracts/ccip/ERC677.sol b/contracts/ccip/ERC677.sol new file mode 100644 index 0000000..c287f05 --- /dev/null +++ b/contracts/ccip/ERC677.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; + +interface IERC677Receiver { + function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external; +} + +interface IERC677 { + event Transfer(address indexed from, address indexed to, uint256 value, bytes data); + + /// @notice Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver + /// @param to The address which you want to transfer to + /// @param amount The amount of tokens to be transferred + /// @param data bytes Additional data with no specified format, sent in call to `to` + /// @return true unless throwing + function transferAndCall(address to, uint256 amount, bytes memory data) external returns (bool); +} + +contract ERC677 is IERC677, ERC20 { + using Address for address; + + constructor(string memory name, string memory symbol) ERC20(name, symbol) { } + + /// @inheritdoc IERC677 + function transferAndCall(address to, uint256 amount, bytes memory data) public returns (bool success) { + super.transfer(to, amount); + emit Transfer(msg.sender, to, amount, data); + if (to.isContract()) { + IERC677Receiver(to).onTokenTransfer(msg.sender, amount, data); + } + return true; + } +} diff --git a/contracts/ccip/IBurnMintERC20.sol b/contracts/ccip/IBurnMintERC20.sol new file mode 100644 index 0000000..bc2f998 --- /dev/null +++ b/contracts/ccip/IBurnMintERC20.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface IBurnMintERC20 is IERC20 { + /// @notice Mints new tokens for a given address. + /// @param account The address to mint the new tokens to. + /// @param amount The number of tokens to be minted. + /// @dev this function increases the total supply. + function mint(address account, uint256 amount) external; + + /// @notice Burns tokens from the sender. + /// @param amount The number of tokens to be burned. + /// @dev this function decreases the total supply. + function burn(uint256 amount) external; + + /// @notice Burns tokens from a given address.. + /// @param account The address to burn tokens from. + /// @param amount The number of tokens to be burned. + /// @dev this function decreases the total supply. + function burn(address account, uint256 amount) external; + + /// @notice Burns tokens from a given address.. + /// @param account The address to burn tokens from. + /// @param amount The number of tokens to be burned. + /// @dev this function decreases the total supply. + function burnFrom(address account, uint256 amount) external; +} diff --git a/contracts/ccip/WrappedRSETH.sol b/contracts/ccip/WrappedRSETH.sol new file mode 100644 index 0000000..6daf8d1 --- /dev/null +++ b/contracts/ccip/WrappedRSETH.sol @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { IBurnMintERC20, IERC20 } from "./IBurnMintERC20.sol"; + +import { ERC677, IERC677 } from "./ERC677.sol"; + +import { ConfirmedOwnerWithProposal } from "./ConfirmedOwnerWithProposal.sol"; + +import { ERC20Burnable } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; + +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/// @notice An audited ERC677 compatible token contract with burn and minting roles. +/// @dev reference: +/// https://github.com/smartcontractkit/ccip/blob/ccip-develop/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol +/// @dev The total supply can be limited during deployment. +contract WrappedRSETH is IBurnMintERC20, ERC677, IERC165, ERC20Burnable, ConfirmedOwnerWithProposal { + using EnumerableSet for EnumerableSet.AddressSet; + + error SenderNotMinter(address sender); + error SenderNotBurner(address sender); + error MaxSupplyExceeded(uint256 supplyAfterMint); + + event MintAccessGranted(address indexed minter); + event BurnAccessGranted(address indexed burner); + event MintAccessRevoked(address indexed minter); + event BurnAccessRevoked(address indexed burner); + + // @dev the allowed minter addresses + EnumerableSet.AddressSet internal s_minters; + // @dev the allowed burner addresses + EnumerableSet.AddressSet internal s_burners; + + /// @dev The number of decimals for the token + uint8 internal immutable i_decimals; + + /// @dev The maximum supply of the token, 0 if unlimited + uint256 internal immutable i_maxSupply; + + constructor( + string memory name, + string memory symbol, + uint8 decimals_, + uint256 maxSupply_, + address _owner + ) + ERC677(name, symbol) + ConfirmedOwnerWithProposal(_owner, address(0)) + { + i_decimals = decimals_; + i_maxSupply = maxSupply_; + } + + function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) { + return interfaceId == type(IERC20).interfaceId || interfaceId == type(IERC677).interfaceId + || interfaceId == type(IBurnMintERC20).interfaceId || interfaceId == type(IERC165).interfaceId; + } + + // ================================================================ + // | ERC20 | + // ================================================================ + + /// @dev Returns the number of decimals used in its user representation. + function decimals() public view virtual override returns (uint8) { + return i_decimals; + } + + /// @dev Returns the max supply of the token, 0 if unlimited. + function maxSupply() public view virtual returns (uint256) { + return i_maxSupply; + } + + /// @dev Uses OZ ERC20 _transfer to disallow sending to address(0). + /// @dev Disallows sending to address(this) + function _transfer(address from, address to, uint256 amount) internal virtual override validAddress(to) { + super._transfer(from, to, amount); + } + + /// @dev Uses OZ ERC20 _approve to disallow approving for address(0). + /// @dev Disallows approving for address(this) + function _approve(address owner, address spender, uint256 amount) internal virtual override validAddress(spender) { + super._approve(owner, spender, amount); + } + + /// @dev Exists to be backwards compatible with the older naming convention. + function decreaseApproval(address spender, uint256 subtractedValue) external returns (bool success) { + return decreaseAllowance(spender, subtractedValue); + } + + /// @dev Exists to be backwards compatible with the older naming convention. + function increaseApproval(address spender, uint256 addedValue) external { + increaseAllowance(spender, addedValue); + } + + /// @notice Check if recipient is valid (not this contract address). + /// @param recipient the account we transfer/approve to. + /// @dev Reverts with an empty revert to be compatible with the existing link token when + /// the recipient is this contract address. + modifier validAddress(address recipient) virtual { + // solhint-disable-next-line reason-string, custom-errors + if (recipient == address(this)) revert(); + _; + } + + // ================================================================ + // | Burning & minting | + // ================================================================ + + /// @inheritdoc ERC20Burnable + /// @dev Uses OZ ERC20 _burn to disallow burning from address(0). + /// @dev Decreases the total supply. + function burn(uint256 amount) public override(IBurnMintERC20, ERC20Burnable) onlyBurner { + super.burn(amount); + } + + /// @inheritdoc IBurnMintERC20 + /// @dev Alias for BurnFrom for compatibility with the older naming convention. + /// @dev Uses burnFrom for all validation & logic. + function burn(address account, uint256 amount) public virtual override { + burnFrom(account, amount); + } + + /// @inheritdoc ERC20Burnable + /// @dev Uses OZ ERC20 _burn to disallow burning from address(0). + /// @dev Decreases the total supply. + function burnFrom(address account, uint256 amount) public override(IBurnMintERC20, ERC20Burnable) onlyBurner { + super.burnFrom(account, amount); + } + + /// @inheritdoc IBurnMintERC20 + /// @dev Uses OZ ERC20 _mint to disallow minting to address(0). + /// @dev Disallows minting to address(this) + /// @dev Increases the total supply. + function mint(address account, uint256 amount) external override onlyMinter validAddress(account) { + if (i_maxSupply != 0 && totalSupply() + amount > i_maxSupply) revert MaxSupplyExceeded(totalSupply() + amount); + + _mint(account, amount); + } + + // ================================================================ + // | Roles | + // ================================================================ + + /// @notice grants both mint and burn roles to `burnAndMinter`. + /// @dev calls public functions so this function does not require + /// access controls. This is handled in the inner functions. + function grantMintAndBurnRoles(address burnAndMinter) external { + grantMintRole(burnAndMinter); + grantBurnRole(burnAndMinter); + } + + /// @notice Grants mint role to the given address. + /// @dev only the owner can call this function. + function grantMintRole(address minter) public onlyOwner { + if (s_minters.add(minter)) { + emit MintAccessGranted(minter); + } + } + + /// @notice Grants burn role to the given address. + /// @dev only the owner can call this function. + function grantBurnRole(address burner) public onlyOwner { + if (s_burners.add(burner)) { + emit BurnAccessGranted(burner); + } + } + + /// @notice Revokes mint role for the given address. + /// @dev only the owner can call this function. + function revokeMintRole(address minter) public onlyOwner { + if (s_minters.remove(minter)) { + emit MintAccessRevoked(minter); + } + } + + /// @notice Revokes burn role from the given address. + /// @dev only the owner can call this function + function revokeBurnRole(address burner) public onlyOwner { + if (s_burners.remove(burner)) { + emit BurnAccessRevoked(burner); + } + } + + /// @notice Returns all permissioned minters + function getMinters() public view returns (address[] memory) { + return s_minters.values(); + } + + /// @notice Returns all permissioned burners + function getBurners() public view returns (address[] memory) { + return s_burners.values(); + } + + // ================================================================ + // | Access | + // ================================================================ + + /// @notice Checks whether a given address is a minter for this token. + /// @return true if the address is allowed to mint. + function isMinter(address minter) public view returns (bool) { + return s_minters.contains(minter); + } + + /// @notice Checks whether a given address is a burner for this token. + /// @return true if the address is allowed to burn. + function isBurner(address burner) public view returns (bool) { + return s_burners.contains(burner); + } + + /// @notice Checks whether the msg.sender is a permissioned minter for this token + /// @dev Reverts with a SenderNotMinter if the check fails + modifier onlyMinter() { + if (!isMinter(msg.sender)) revert SenderNotMinter(msg.sender); + _; + } + + /// @notice Checks whether the msg.sender is a permissioned burner for this token + /// @dev Reverts with a SenderNotBurner if the check fails + modifier onlyBurner() { + if (!isBurner(msg.sender)) revert SenderNotBurner(msg.sender); + _; + } +} diff --git a/contracts/cross-chain/CrossChainRateProvider.sol b/contracts/cross-chain/CrossChainRateProvider.sol index ec7e411..cbcf60d 100644 --- a/contracts/cross-chain/CrossChainRateProvider.sol +++ b/contracts/cross-chain/CrossChainRateProvider.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.21; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import { ILayerZeroEndpoint } from "../interfaces/ILayerZeroEndpoint.sol"; +import { ILayerZeroEndpoint } from "contracts/external/layerzero/interfaces/ILayerZeroEndpoint.sol"; /// @title Cross chain rate provider. By witherblock reference: https://github.com/witherblock/gyarados /// @notice Provides a rate to a receiver contract on a different chain than the one this contract is deployed on @@ -22,7 +22,7 @@ abstract contract CrossChainRateProvider is Ownable, ReentrancyGuard { /// @notice LayerZero endpoint address address public layerZeroEndpoint; - /// @notice Rate Reciever address address + /// @notice Rate Receiver address address address public rateReceiver; /// @notice Information of which token and base token rate is being provided diff --git a/contracts/cross-chain/CrossChainRateReceiver.sol b/contracts/cross-chain/CrossChainRateReceiver.sol index be915c6..4ba5af3 100644 --- a/contracts/cross-chain/CrossChainRateReceiver.sol +++ b/contracts/cross-chain/CrossChainRateReceiver.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.21; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { ILayerZeroReceiver } from "../interfaces/ILayerZeroReceiver.sol"; +import { ILayerZeroReceiver } from "contracts/external/layerzero/interfaces/ILayerZeroReceiver.sol"; /// @title Cross chain rate receiver. By witherblock reference: https://github.com/witherblock/gyarados /// @notice Receives a rate from a provider contract on a different chain than the one this contract is deployed on diff --git a/contracts/cross-chain/MultiChainRateProvider.sol b/contracts/cross-chain/MultiChainRateProvider.sol index 93ec06a..24e41b1 100644 --- a/contracts/cross-chain/MultiChainRateProvider.sol +++ b/contracts/cross-chain/MultiChainRateProvider.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.21; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import { ILayerZeroEndpoint } from "../interfaces/ILayerZeroEndpoint.sol"; +import { ILayerZeroEndpoint } from "contracts/external/layerzero/interfaces/ILayerZeroEndpoint.sol"; /// @title Multi chain rate provider. By witherblock reference: https://github.com/witherblock/gyarados /// @notice Provides a rate to a multiple receiver contracts on a different chain than the one this contract is deployed diff --git a/contracts/cross-chain/README.md b/contracts/cross-chain/README.md new file mode 100644 index 0000000..7646126 --- /dev/null +++ b/contracts/cross-chain/README.md @@ -0,0 +1,39 @@ +## Verification Checklist for Native Restaking on L2s Before Usage + +## 1. OFT Contract +### From `https://github.com/Kelp-DAO/kelp-dao-lz` Repo +- [ ] Check that an OFT contract is deployed on the L2. (OFT is from LayerZero (LZ) v2.) [LayerZero V2](https://docs.layerzero.network/v2) +- [ ] Check that all the configuration in `layerzero.config.js` is properly set up. Use `npx hardhat lz:oapp:wire --oapp-config layerzero.config.js` to wire it up if not. +- [ ] Check that ownership of the OFT contract is set to the L2 multisig, `0x7AAd74b7f0d60D5867B59dbD377a71783425af47` or to `0x3924a9a1706285f5e92486dc19945e43fb2f98cf`. +- [ ] Check that all contracts are verified on the L2 explorer. +- [ ] Check if DVN is set up on the OFT contract. + +## 2. Deployed Native Restaking on L2 +### From `https://github.com/Kelp-DAO/KelpDAO-contracts/` Repo +- [ ] Check that `RSETHPoolV2` has been deployed. +- [ ] Check if `RSETHPoolV2` is an upgradeable contract. +- [ ] Check that `RSETHPoolV2`'s deposit function require native toke swap. If not set `isEthDepositEnabled` to `false`. +- [ ] Check that `RsETHTokenWrapper` is deployed. +- [ ] Check if `RsETHTokenWrapper` is an upgradeable contract. +- [ ] Check MINTER_ROLE for `RSETHPoolV2` is properly set up on `RsETHTokenWrapper` contract. +- [ ] Check if LZ_OFT address is a supported asset on `RsEthTokenWrapper` contract. +- [ ] Check implementations of both contracts have the right bytecode. +- [ ] Check the right proxy admin is set for both contracts. +- [ ] Check that the owner of the proxy admin is L2 multisig or `0x7AAd74b7f0d60D5867B59dbD377a71783425af47` +- [ ] Check that BRIDGER_ROLE is set for `RSETHPoolV2`. It should be `0x3924a9a1706285f5e92486dc19945e43fb2f98cf`. +- [ ] Check that DEFAULT_ADMIN_ROLE is set to the L2 Kelp Multisig, `0x7AAd74b7f0d60D5867B59dbD377a71783425af47` or to `0x3924a9a1706285f5e92486dc19945e43fb2f98cf`. +- [] Check that the contracts are verified. + +## 3. Rate Receiver +### From `https://github.com/Kelp-DAO/KelpDAO-contracts/` Repo +- [ ] Check that there is an `RSETHRateReceiver` for this L2. (We use LayerZero (LZ) v1 for it.) +- [ ] Check that ownership of the OFT contract is set to the L2 multisig, `0x7AAd74b7f0d60D5867B59dbD377a71783425af47` or to `0x3924a9a1706285f5e92486dc19945e43fb2f98cf`. +- [ ] Check that `RSETHRateReceiver` is properly set up with endpoint chain ID and endpoint address. See [LayerZero Mainnet Addresses](https://docs.layerzero.network/v1/developers/technical-reference/mainnet/mainnet-addresses). +- [ ] Check that `RSETHMultiChainRateProvider` on the ETH mainnet is wired up to send rates to the `RSETHRateReceiver` address on L2. +- [ ] Check that the contract is verified. + +## Deployed Proxy Admin on L2 +### From `https://github.com/Kelp-DAO/KelpDAO-contracts/` Repo +- [ ] Check that there is a `ProxyAdmin` contract deployed on the L2. +- [ ] Check that the `ProxyAdmin` contract is verified. +- [ ] Check that the `ProxyAdmin` contract is owned by the L2 multisig, `0x7AAd74b7f0d60D5867B59dbD377a71783425af47` or to `0x3924a9a1706285f5e92486dc19945e43fb2f98cf`. \ No newline at end of file diff --git a/contracts/cross-chain/RSETHMultiChainRateProvider.sol b/contracts/cross-chain/RSETHMultiChainRateProvider.sol new file mode 100644 index 0000000..5586959 --- /dev/null +++ b/contracts/cross-chain/RSETHMultiChainRateProvider.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.21; + +import { MultiChainRateProvider } from "./MultiChainRateProvider.sol"; + +import { ILRTOracle } from "../interfaces/ILRTOracle.sol"; + +/// @title rsETH multi chain rate provider +/// @notice Provides the current exchange rate of rsETH to various receiver contract on a different chains +contract RSETHMultiChainRateProvider is MultiChainRateProvider { + address public rsETHPriceOracle; + + constructor(address _rsETHPriceOracle, address _layerZeroEndpoint) { + rsETHPriceOracle = _rsETHPriceOracle; + + rateInfo = RateInfo({ + tokenSymbol: "rsETH", + tokenAddress: 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7, // rsETH token address on ETH mainnet + baseTokenSymbol: "ETH", + baseTokenAddress: address(0) // Address 0 for native tokens + }); + + layerZeroEndpoint = _layerZeroEndpoint; + } + + /// @notice Returns the latest rate from the rsETH contract + function getLatestRate() public view override returns (uint256) { + return ILRTOracle(rsETHPriceOracle).rsETHPrice(); + } + + /// @notice Calls the getLatestRate function and returns the rate + function getRate() external view returns (uint256) { + return getLatestRate(); + } +} diff --git a/contracts/cross-chain/RSETHRateProvider.sol b/contracts/cross-chain/RSETHRateProvider.sol index 6afea34..11a9296 100644 --- a/contracts/cross-chain/RSETHRateProvider.sol +++ b/contracts/cross-chain/RSETHRateProvider.sol @@ -28,4 +28,9 @@ contract RSETHRateProvider is CrossChainRateProvider { function getLatestRate() public view override returns (uint256) { return ILRTOracle(rsETHPriceOracle).rsETHPrice(); } + + /// @notice Calls the getLatestRate function and returns the rate + function getRate() external view returns (uint256) { + return getLatestRate(); + } } diff --git a/contracts/external/eigenlayer/interfaces/IEigenDelayedWithdrawalRouter.sol b/contracts/external/eigenlayer/interfaces/IEigenDelayedWithdrawalRouter.sol new file mode 100644 index 0000000..820fcc6 --- /dev/null +++ b/contracts/external/eigenlayer/interfaces/IEigenDelayedWithdrawalRouter.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +interface IEigenDelayedWithdrawalRouter { + // struct used to pack data into a single storage slot + struct DelayedWithdrawal { + uint224 amount; + uint32 blockCreated; + } + + // struct used to store a single users delayedWithdrawal data + struct UserDelayedWithdrawals { + uint256 delayedWithdrawalsCompleted; + DelayedWithdrawal[] delayedWithdrawals; + } + + function getUserDelayedWithdrawals(address user) external view returns (DelayedWithdrawal[] memory); + + function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfDelayedWithdrawalsToClaim) external; + + function userWithdrawals(address user) external view returns (UserDelayedWithdrawals memory); + + function userWithdrawalsLength(address user) external view returns (uint256); +} diff --git a/contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol b/contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol new file mode 100644 index 0000000..79d8a34 --- /dev/null +++ b/contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import "./IStrategy.sol"; + +/** + * @title DelegationManager + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice This is the contract for delegation in EigenLayer. The main functionalities of this contract are + * - enabling anyone to register as an operator in EigenLayer + * - allowing operators to specify parameters related to stakers who delegate to them + * - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a + * single operator at a time) + * - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the + * withdrawal process, initiated through the StrategyManager) + */ +interface IEigenDelegationManager { + // @notice Struct used for storing information about a single operator who has registered with EigenLayer + struct OperatorDetails { + // @notice address to receive the rewards that the operator earns via serving applications built on EigenLayer. + address earningsReceiver; + /** + * @notice Address to verify signatures when a staker wishes to delegate to the operator, as well as controlling + * "forced undelegations". + * @dev Signature verification follows these rules: + * 1) If this address is left as address(0), then any staker will be free to delegate to the operator, i.e. no + * signature verification will be performed. + * 2) If this address is an EOA (i.e. it has no code), then we follow standard ECDSA signature verification for + * delegations to the operator. + * 3) If this address is a contract (i.e. it has code) then we forward a call to the contract and verify that it + * returns the correct EIP-1271 "magic value". + */ + address delegationApprover; + /** + * @notice A minimum delay -- measured in blocks -- enforced between: + * 1) the operator signalling their intent to register for a service, via calling `Slasher.optIntoSlashing` + * and + * 2) the operator completing registration for the service, via the service ultimately calling + * `Slasher.recordFirstStakeUpdate` + * @dev note that for a specific operator, this value *cannot decrease*, i.e. if the operator wishes to modify + * their OperatorDetails, + * then they are only allowed to either increase this value or keep it the same. + */ + uint32 stakerOptOutWindowBlocks; + } + + /** + * @notice Abstract struct used in calculating an EIP712 signature for a staker to approve that they (the staker + * themselves) delegate to a specific operator. + * @dev Used in computing the `STAKER_DELEGATION_TYPEHASH` and as a reference in the computation of the + * stakerDigestHash in the `delegateToBySignature` function. + */ + struct StakerDelegation { + // the staker who is delegating + address staker; + // the operator being delegated to + address operator; + // the staker's nonce + uint256 nonce; + // the expiration timestamp (UTC) of the signature + uint256 expiry; + } + + /** + * @notice Abstract struct used in calculating an EIP712 signature for an operator's delegationApprover to approve + * that a specific staker delegate to the operator. + * @dev Used in computing the `DELEGATION_APPROVAL_TYPEHASH` and as a reference in the computation of the + * approverDigestHash in the `_delegate` function. + */ + struct DelegationApproval { + // the staker who is delegating + address staker; + // the operator being delegated to + address operator; + // the operator's provided salt + bytes32 salt; + // the expiration timestamp (UTC) of the signature + uint256 expiry; + } + + /** + * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is + * stored. + * In functions that operate on existing queued withdrawals -- e.g. completeQueuedWithdrawal`, the data is + * resubmitted and the hash of the submitted + * data is computed by `calculateWithdrawalRoot` and checked against the stored hash in order to confirm the + * integrity of the submitted data. + */ + struct Withdrawal { + // The address that originated the Withdrawal + address staker; + // The address that the staker was delegated to at the time that the Withdrawal was created + address delegatedTo; + // The address that can complete the Withdrawal + will receive funds when completing the withdrawal + address withdrawer; + // Nonce used to guarantee that otherwise identical withdrawals have unique hashes + uint256 nonce; + // Block number when the Withdrawal was created + uint32 startBlock; + // Array of strategies that the Withdrawal contains + IStrategy[] strategies; + // Array containing the amount of shares in each Strategy in the `strategies` array + uint256[] shares; + } + + struct QueuedWithdrawalParams { + // Array of strategies that the QueuedWithdrawal contains + IStrategy[] strategies; + // Array containing the amount of shares in each Strategy in the `strategies` array + uint256[] shares; + // The address of the withdrawer + address withdrawer; + } + + // @notice Emitted when a new operator registers in EigenLayer and provides their OperatorDetails. + event OperatorRegistered(address indexed operator, OperatorDetails operatorDetails); + + /// @notice Emitted when an operator updates their OperatorDetails to @param newOperatorDetails + event OperatorDetailsModified(address indexed operator, OperatorDetails newOperatorDetails); + + /** + * @notice Emitted when @param operator indicates that they are updating their MetadataURI string + * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain + * indexing + */ + event OperatorMetadataURIUpdated(address indexed operator, string metadataURI); + + /// @notice Emitted whenever an operator's shares are increased for a given strategy. Note that shares is the delta + /// in the operator's shares. + event OperatorSharesIncreased(address indexed operator, address staker, IStrategy strategy, uint256 shares); + + /// @notice Emitted whenever an operator's shares are decreased for a given strategy. Note that shares is the delta + /// in the operator's shares. + event OperatorSharesDecreased(address indexed operator, address staker, IStrategy strategy, uint256 shares); + + /// @notice Emitted when @param staker delegates to @param operator. + event StakerDelegated(address indexed staker, address indexed operator); + + /// @notice Emitted when @param staker undelegates from @param operator. + event StakerUndelegated(address indexed staker, address indexed operator); + + /// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself + event StakerForceUndelegated(address indexed staker, address indexed operator); + + /** + * @notice Emitted when a new withdrawal is queued. + * @param withdrawalRoot Is the hash of the `withdrawal`. + * @param withdrawal Is the withdrawal itself. + */ + event WithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal); + + /// @notice Emitted when a queued withdrawal is completed + event WithdrawalCompleted(bytes32 withdrawalRoot); + + /// @notice Emitted when a queued withdrawal is *migrated* from the StrategyManager to the DelegationManager + event WithdrawalMigrated(bytes32 oldWithdrawalRoot, bytes32 newWithdrawalRoot); + + /// @notice Emitted when the `minWithdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`. + event MinWithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue); + + /// @notice Emitted when the `strategyWithdrawalDelayBlocks` variable is modified from `previousValue` to + /// `newValue`. + event StrategyWithdrawalDelayBlocksSet(IStrategy strategy, uint256 previousValue, uint256 newValue); + + function pendingWithdrawals(bytes32 withdrawalRoot) external view returns (bool); + + /** + * @notice Registers the caller as an operator in EigenLayer. + * @param registeringOperatorDetails is the `OperatorDetails` for the operator. + * @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator. + * + * @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered + * "delegated to themself". + * @dev This function will revert if the caller attempts to set their `earningsReceiver` to address(0). + * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event + */ + function registerAsOperator( + OperatorDetails calldata registeringOperatorDetails, + string calldata metadataURI + ) + external; + + /** + * @notice Updates an operator's stored `OperatorDetails`. + * @param newOperatorDetails is the updated `OperatorDetails` for the operator, to replace their current + * OperatorDetails`. + * + * @dev The caller must have previously registered as an operator in EigenLayer. + * @dev This function will revert if the caller attempts to set their `earningsReceiver` to address(0). + */ + function modifyOperatorDetails(OperatorDetails calldata newOperatorDetails) external; + + /** + * @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has + * updated. + * @param metadataURI The URI for metadata associated with an operator + * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event + */ + function updateOperatorMetadataURI(string calldata metadataURI) external; + + /** + * @notice Undelegates the staker from the operator who they are delegated to. Puts the staker into the + * "undelegation limbo" mode of the EigenPodManager + * and queues a withdrawal of all of the staker's shares in the StrategyManager (to the staker), if necessary. + * @param staker The account to be undelegated. + * @return withdrawalRoot The root of the newly queued withdrawal, if a withdrawal was queued. Otherwise just + * bytes32(0). + * + * @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves. + * @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's + * specified "delegationApprover" + * @dev Reverts if the `staker` is already undelegated. + */ + function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot); + + /** + * Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed + * from the staker. If the staker is delegated, withdrawn shares/strategies are also removed from + * their operator. + * + * All withdrawn shares/strategies are placed in a queue and can be fully withdrawn after a delay. + */ + function queueWithdrawals(QueuedWithdrawalParams[] calldata queuedWithdrawalParams) + external + returns (bytes32[] memory); + + /** + * @notice Used to complete the specified `withdrawal`. The caller must match `withdrawal.withdrawer` + * @param withdrawal The Withdrawal to complete. + * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th + * Strategy in the `withdrawal.strategies` array. + * This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this + * input will be unused) + * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was + * delegated to's middleware times array + * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified + * strategies themselves + * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the + * specified strategies + * will simply be transferred to the caller directly. + * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index + * that satisfies `slasher.canWithdraw` + * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and + * `withdrawal.withdrawer != withdrawal.staker`, note that + * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred + * to the withdrawer, unlike shares in + * any other strategies, which will be transferred to the withdrawer. + */ + function completeQueuedWithdrawal( + Withdrawal calldata withdrawal, + IERC20[] calldata tokens, + uint256 middlewareTimesIndex, + bool receiveAsTokens + ) + external; + + /** + * @notice Array-ified version of `completeQueuedWithdrawal`. + * Used to complete the specified `withdrawals`. The function caller must match `withdrawals[...].withdrawer` + * @param withdrawals The Withdrawals to complete. + * @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single + * array. + * @param middlewareTimesIndexes One index to reference per Withdrawal. See `completeQueuedWithdrawal` for the usage + * of a single index. + * @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for + * the usage of a single boolean. + * @dev See `completeQueuedWithdrawal` for relevant dev tags + */ + function completeQueuedWithdrawals( + Withdrawal[] calldata withdrawals, + IERC20[][] calldata tokens, + uint256[] calldata middlewareTimesIndexes, + bool[] calldata receiveAsTokens + ) + external; + + /** + * @notice Increases a staker's delegated share balance in a strategy. + * @param staker The address to increase the delegated shares for their operator. + * @param strategy The strategy in which to increase the delegated shares. + * @param shares The number of shares to increase. + * + * @dev *If the staker is actively delegated*, then increases the `staker`'s delegated shares in `strategy` by + * `shares`. Otherwise does nothing. + * @dev Callable only by the StrategyManager or EigenPodManager. + */ + function increaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; + + /** + * @notice Decreases a staker's delegated share balance in a strategy. + * @param staker The address to increase the delegated shares for their operator. + * @param strategy The strategy in which to decrease the delegated shares. + * @param shares The number of shares to decrease. + * + * @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated shares in `strategy` by + * `shares`. Otherwise does nothing. + * @dev Callable only by the StrategyManager or EigenPodManager. + */ + function decreaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external; + + /** + * @notice returns the address of the operator that `staker` is delegated to. + * @notice Mapping: staker => operator whom the staker is currently delegated to. + * @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator. + */ + function delegatedTo(address staker) external view returns (address); + + /** + * @notice Returns the OperatorDetails struct associated with an `operator`. + */ + function operatorDetails(address operator) external view returns (OperatorDetails memory); + + /* + * @notice Returns the earnings receiver address for an operator + */ + function earningsReceiver(address operator) external view returns (address); + + /** + * @notice Returns the delegationApprover account for an operator + */ + function delegationApprover(address operator) external view returns (address); + + /** + * @notice Returns the stakerOptOutWindowBlocks for an operator + */ + function stakerOptOutWindowBlocks(address operator) external view returns (uint256); + + /** + * @notice Given array of strategies, returns array of shares for the operator + */ + function getOperatorShares( + address operator, + IStrategy[] memory strategies + ) + external + view + returns (uint256[] memory); + + /** + * @notice Given a list of strategies, return the minimum number of blocks that must pass to withdraw + * from all the inputted strategies. Return value is >= minWithdrawalDelayBlocks as this is the global min + * withdrawal delay. + * @param strategies The strategies to check withdrawal delays for + */ + function getWithdrawalDelay(IStrategy[] calldata strategies) external view returns (uint256); + + /** + * @notice returns the total number of shares in `strategy` that are delegated to `operator`. + * @notice Mapping: operator => strategy => total number of shares in the strategy delegated to the operator. + * @dev By design, the following invariant should hold for each Strategy: + * (operator's shares in delegation manager) = sum (shares above zero of all stakers delegated to operator) + * = sum (delegateable shares of all stakers delegated to the operator) + */ + function operatorShares(address operator, IStrategy strategy) external view returns (uint256); + + /** + * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise. + */ + function isDelegated(address staker) external view returns (bool); + + /** + * @notice Returns true is an operator has previously registered for delegation. + */ + function isOperator(address operator) external view returns (bool); + + /// @notice Mapping: staker => number of signed delegation nonces (used in `delegateToBySignature`) from the staker + /// that the contract has already checked + function stakerNonce(address staker) external view returns (uint256); + + /** + * @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the + * delegationApprover. + * @dev Salts are used in the `delegateTo` and `delegateToBySignature` functions. Note that these functions only + * process the delegationApprover's + * signature + the provided salt if the operator being delegated to has specified a nonzero address as their + * `delegationApprover`. + */ + function delegationApproverSaltIsSpent(address _delegationApprover, bytes32 salt) external view returns (bool); + + /** + * @notice Minimum delay enforced by this contract for completing queued withdrawals. Measured in blocks, and + * adjustable by this contract's owner, + * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). + * Note that strategies each have a separate withdrawal delay, which can be greater than this value. So the minimum + * number of blocks that must pass + * to withdraw a strategy is MAX(minWithdrawalDelayBlocks, strategyWithdrawalDelayBlocks[strategy]) + */ + function minWithdrawalDelayBlocks() external view returns (uint256); + + /** + * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in + * blocks, and adjustable by this contract's owner, + * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). + */ + function strategyWithdrawalDelayBlocks(IStrategy strategy) external view returns (uint256); + + /** + * @notice Calculates the digestHash for a `staker` to sign to delegate to an `operator` + * @param staker The signing staker + * @param operator The operator who is being delegated to + * @param expiry The desired expiry time of the staker's signature + */ + function calculateCurrentStakerDelegationDigestHash( + address staker, + address operator, + uint256 expiry + ) + external + view + returns (bytes32); + + /** + * @notice Calculates the digest hash to be signed and used in the `delegateToBySignature` function + * @param staker The signing staker + * @param _stakerNonce The nonce of the staker. In practice we use the staker's current nonce, stored at + * `stakerNonce[staker]` + * @param operator The operator who is being delegated to + * @param expiry The desired expiry time of the staker's signature + */ + function calculateStakerDelegationDigestHash( + address staker, + uint256 _stakerNonce, + address operator, + uint256 expiry + ) + external + view + returns (bytes32); + + /** + * @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` + * and `delegateToBySignature` functions. + * @param staker The account delegating their stake + * @param operator The account receiving delegated stake + * @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in + * general) + * @param approverSalt A unique and single use value associated with the approver signature. + * @param expiry Time after which the approver's signature becomes invalid + */ + function calculateDelegationApprovalDigestHash( + address staker, + address operator, + address _delegationApprover, + bytes32 approverSalt, + uint256 expiry + ) + external + view + returns (bytes32); + + /// @notice The EIP-712 typehash for the contract's domain + function DOMAIN_TYPEHASH() external view returns (bytes32); + + /// @notice The EIP-712 typehash for the StakerDelegation struct used by the contract + function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32); + + /// @notice The EIP-712 typehash for the DelegationApproval struct used by the contract + function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32); + + /** + * @notice Getter function for the current EIP-712 domain separator for this contract. + * + * @dev The domain separator will change in the event of a fork that changes the ChainID. + * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature + * collision. + * for more detailed information please read EIP-712. + */ + function domainSeparator() external view returns (bytes32); + + /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated. + /// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals + /// have unique hashes. + function cumulativeWithdrawalsQueued(address staker) external view returns (uint256); + + /// @notice Returns the keccak256 hash of `withdrawal`. + function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32); + + // @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for + // stack management. + struct SignatureWithExpiry { + // the signature itself, formatted as a single bytes object + bytes signature; + // the expiration timestamp (UTC) of the signature + uint256 expiry; + } + + /** + * @notice Caller delegates their stake to an operator. + * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on + * EigenLayer. + * @param approverSignatureAndExpiry Verifies the operator approves of this delegation + * @param approverSalt A unique single use value tied to an individual signature. + * @dev The approverSignatureAndExpiry is used in the event that: + * 1) the operator's `delegationApprover` address is set to a non-zero value. + * AND + * 2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the + * operator + * or their delegationApprover is the `msg.sender`, then approval is assumed. + * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's + * recommended to use an empty input + * in this case to save on complexity + gas costs + */ + function delegateTo( + address operator, + SignatureWithExpiry memory approverSignatureAndExpiry, + bytes32 approverSalt + ) + external; + + /** + * @notice Delegates from `staker` to `operator`. + * @dev requires that: + * 1) if `staker` is an EOA, then `signature` is valid ECDSA signature from `staker`, indicating their intention for + * this action + * 2) if `staker` is a contract, then `signature` must will be checked according to EIP-1271 + */ + function delegateToBySignature(address staker, address operator, uint256 expiry, bytes memory signature) external; + + /** + * @notice Returns the number of actively-delegatable shares a staker has across all strategies. + * @dev Returns two empty arrays in the case that the Staker has no actively-delegateable shares. + */ + function getDelegatableShares(address staker) external view returns (IStrategy[] memory, uint256[] memory); + + /// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise. + function isNotDelegated(address staker) external view returns (bool); +} diff --git a/contracts/external/eigenlayer/interfaces/IEigenPod.sol b/contracts/external/eigenlayer/interfaces/IEigenPod.sol new file mode 100644 index 0000000..640d776 --- /dev/null +++ b/contracts/external/eigenlayer/interfaces/IEigenPod.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { BeaconChainProofs } from "../libraries/BeaconChainProofs.sol"; + +interface IBeaconDeposit { + /// @notice Query the current deposit root hash. + /// @return The deposit root hash. + function get_deposit_root() external view returns (bytes32); +} + +interface IEigenPod { + enum VALIDATOR_STATUS { + INACTIVE, // doesnt exist + ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod + WITHDRAWN // withdrawn from the Beacon Chain + + } + + struct ValidatorInfo { + // index of the validator in the beacon chain + uint64 validatorIndex; + // amount of beacon chain ETH restaked on EigenLayer in gwei + uint64 restakedBalanceGwei; + //timestamp of the validator's most recent balance update + uint64 mostRecentBalanceUpdateTimestamp; + // status of the validator + VALIDATOR_STATUS status; + } + /// @notice This is the beacon chain deposit contract + + function ethPOS() external view returns (IBeaconDeposit); + + /// @return delayedWithdrawalRouter address of eigenlayer delayedWithdrawalRouter, + /// which does book keeping of delayed withdrawls + function delayedWithdrawalRouter() external view returns (address); + + /// @notice an indicator of whether or not the podOwner has ever "fully restaked" by successfully calling + /// `verifyCorrectWithdrawalCredentials`. + function hasRestaked() external view returns (bool); + + /// @notice Called by the pod owner to withdraw the balance of the pod when `hasRestaked` is set to false + function withdrawBeforeRestaking() external; + + /** + * @notice Called by the pod owner to activate restaking by withdrawing + * all existing ETH from the pod and preventing further withdrawals via + * "withdrawBeforeRestaking()" + */ + function activateRestaking() external; + + /** + * @notice This function verifies that the withdrawal credentials of validator(s) owned by the podOwner are pointed + * to + * this contract. It also verifies the effective balance of the validator. It verifies the provided proof of the + * ETH validator against the beacon chain state + * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer. + * @param oracleTimestamp is the Beacon Chain timestamp whose state root the `proof` will be proven against. + * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs + * @param withdrawalCredentialProofs is an array of proofs, where each proof proves each ETH validator's balance and + * withdrawal credentials + * against a beacon chain state root + * @param validatorFields are the fields of the "Validator Container", refer to consensus specs + * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator + */ + function verifyWithdrawalCredentials( + uint64 oracleTimestamp, + BeaconChainProofs.StateRootProof calldata stateRootProof, + uint40[] calldata validatorIndices, + bytes[] calldata withdrawalCredentialProofs, + bytes32[][] calldata validatorFields + ) + external; + + /** + * @notice This function records an update (either increase or decrease) in the pod's balance in the + * StrategyManager. + * It also verifies a merkle proof of the validator's current beacon chain balance. + * @param oracleTimestamp The oracleTimestamp whose state root the `proof` will be proven against. + * Must be within `VERIFY_BALANCE_UPDATE_WINDOW_SECONDS` of the current block. + * @param validatorIndices is the list of indices of the validators being proven, refer to consensus specs + * @param validatorFieldsProofs proofs against the `beaconStateRoot` for each validator in `validatorFields` + * @param validatorFields are the fields of the "Validator Container", refer to consensus specs + * @dev For more details on the Beacon Chain spec, see: + * https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator + */ + function verifyBalanceUpdates( + uint64 oracleTimestamp, + uint40[] calldata validatorIndices, + BeaconChainProofs.StateRootProof calldata stateRootProof, + bytes[] calldata validatorFieldsProofs, + bytes32[][] calldata validatorFields + ) + external; + + /** + * @notice This function records full and partial withdrawals on behalf of one of the Ethereum validators for this + * EigenPod + * @param oracleTimestamp is the timestamp of the oracle slot that the withdrawal is being proven against + * @param withdrawalProofs is the information needed to check the veracity of the block numbers and withdrawals + * being proven + * @param validatorFieldsProofs is the proof of the validator's fields' in the validator tree + * @param withdrawalFields are the fields of the withdrawals being proven + * @param validatorFields are the fields of the validators being proven + */ + function verifyAndProcessWithdrawals( + uint64 oracleTimestamp, + BeaconChainProofs.StateRootProof calldata stateRootProof, + BeaconChainProofs.WithdrawalProof[] calldata withdrawalProofs, + bytes[] calldata validatorFieldsProofs, + bytes32[][] calldata validatorFields, + bytes32[][] calldata withdrawalFields + ) + external; + + function mostRecentWithdrawalTimestamp() external view returns (uint64); + + function withdrawableRestakedExecutionLayerGwei() external view returns (uint64); + + function validatorPubkeyHashToInfo(bytes32) external view returns (ValidatorInfo memory); +} diff --git a/contracts/interfaces/IEigenPodManager.sol b/contracts/external/eigenlayer/interfaces/IEigenPodManager.sol similarity index 52% rename from contracts/interfaces/IEigenPodManager.sol rename to contracts/external/eigenlayer/interfaces/IEigenPodManager.sol index bb93e1c..a5433be 100644 --- a/contracts/interfaces/IEigenPodManager.sol +++ b/contracts/external/eigenlayer/interfaces/IEigenPodManager.sol @@ -4,6 +4,8 @@ pragma solidity 0.8.21; import { IEigenPod } from "./IEigenPod.sol"; interface IEigenPodManager { + /// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not). + function getPod(address podOwner) external view returns (IEigenPod); /** * @notice Creates an EigenPod for the sender. * @dev Function will revert if the `msg.sender` already has an EigenPod. @@ -13,6 +15,18 @@ interface IEigenPodManager { /// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed. function ownerToPod(address podOwner) external view returns (IEigenPod); + /** + * @notice Mapping from Pod owner owner to the number of shares they have in the virtual beacon chain ETH strategy. + * @dev The share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual + * beacon chain ETH shares can + * decrease between the pod owner queuing and completing a withdrawal. + * When the pod owner's shares would otherwise increase, this "deficit" is decreased first _instead_. + * Likewise, when a withdrawal is completed, this "deficit" is decreased and the withdrawal amount is decreased; We + * can think of this + * as the withdrawal "paying off the deficit". + */ + function podOwnerShares(address podOwner) external view returns (int256); + /** * @notice Stakes for a new beacon chain validator on the sender's EigenPod. * Also creates an EigenPod for the sender if they don't have one already. diff --git a/contracts/external/eigenlayer/interfaces/IEigenStrategyManager.sol b/contracts/external/eigenlayer/interfaces/IEigenStrategyManager.sol new file mode 100644 index 0000000..5d46795 --- /dev/null +++ b/contracts/external/eigenlayer/interfaces/IEigenStrategyManager.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import "./IStrategy.sol"; +import { IEigenDelegationManager } from "./IEigenDelegationManager.sol"; +import "./ISlasher.sol"; + +interface IEigenStrategyManager { + function slasher() external returns (ISlasher); + + function withdrawalRootPending(bytes32 withdrawalRoot) external view returns (bool); + + function withdrawalDelayBlocks() external view returns (uint256); + + /** + * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to + * `msg.sender` + * @param strategy is the specified strategy where deposit is to be made, + * @param token is the denomination in which the deposit is to be made, + * @param amount is the amount of token to be deposited in the strategy by the depositor + * @return shares The amount of new shares in the `strategy` created as part of the action. + * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on + * their behalf. + * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen). + * + * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead + * to attack vectors + * where the token balance and corresponding strategy shares are not in sync upon reentrancy. + */ + function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount) external returns (uint256 shares); + + /** + * @notice Get all details on the depositor's deposits and corresponding shares + * @return (depositor's strategies, shares in these strategies) + */ + function getDeposits(address depositor) external view returns (IStrategy[] memory, uint256[] memory); + + function stakerStrategyShares(address staker, IStrategy strategy) external view returns (uint256); + + function stakerStrategyList(address staker, uint256 index) external view returns (IStrategy); + + /// @notice Simple getter function that returns `stakerStrategyList[staker].length`. + function stakerStrategyListLength(address staker) external view returns (uint256); + + function numWithdrawalsQueued(address staker) external view returns (uint256); + + /// @notice Returns the keccak256 hash of `queuedWithdrawal`. + function calculateWithdrawalRoot(IStrategy.QueuedWithdrawal memory queuedWithdrawal) + external + pure + returns (bytes32); + + /// @notice Returns the single, central Delegation contract of EigenLayer + function delegation() external view returns (IEigenDelegationManager); + + /** + * @notice Called by a staker to queue a withdrawal of the given amount of `shares` from each of the respective + * given `strategies`. + * @dev Stakers will complete their withdrawal by calling the 'completeQueuedWithdrawal' function. + * User shares are decreased in this function, but the total number of shares in each strategy remains the same. + * The total number of shares is decremented in the 'completeQueuedWithdrawal' function instead, which is where + * the funds are actually sent to the user through use of the strategies' 'withdrawal' function. This ensures + * that the value per share reported by each strategy will remain consistent, and that the shares will continue + * to accrue gains during the enforced withdrawal waiting period. + * @param strategyIndexes is a list of the indices in `stakerStrategyList[msg.sender]` that correspond to the + * strategies + * for which `msg.sender` is withdrawing 100% of their shares + * @param strategies The Strategies to withdraw from + * @param shares The amount of shares to withdraw from each of the respective Strategies in the `strategies` array + * @param withdrawer The address that can complete the withdrawal and will receive any withdrawn funds or shares + * upon completing the withdrawal + * @param undelegateIfPossible If this param is marked as 'true' *and the withdrawal will result in `msg.sender` + * having no shares in any Strategy,* + * then this function will also make an internal call to `undelegate(msg.sender)` to undelegate the `msg.sender`. + * @return The 'withdrawalRoot' of the newly created Queued Withdrawal + * @dev Strategies are removed from `stakerStrategyList` by swapping the last entry with the entry to be removed, + * then + * popping off the last entry in `stakerStrategyList`. The simplest way to calculate the correct `strategyIndexes` + * to input + * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in + * `stakerStrategyList` to lowest index + * @dev Note that if the withdrawal includes shares in the enshrined 'beaconChainETH' strategy, then it must *only* + * include shares in this strategy, and + * `withdrawer` must match the caller's address. The first condition is because slashing of queued withdrawals + * cannot be guaranteed + * for Beacon Chain ETH (since we cannot trigger a withdrawal from the beacon chain through a smart contract) and + * the second condition is because shares in + * the enshrined 'beaconChainETH' strategy technically represent non-fungible positions (deposits to the Beacon + * Chain, each pointed at a specific EigenPod). + */ + function queueWithdrawal( + uint256[] calldata strategyIndexes, + IStrategy[] calldata strategies, + uint256[] calldata shares, + address withdrawer, + bool undelegateIfPossible + ) + external + returns (bytes32); + + /** + * @notice Used to complete the specified `queuedWithdrawal`. The function caller must match + * `queuedWithdrawal.withdrawer` + * @param queuedWithdrawal The QueuedWithdrawal to complete. + * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th + * Strategy in the `strategies` array + * of the `queuedWithdrawal`. This input can be provided with zero length if `receiveAsTokens` is set to 'false' + * (since in that case, this input will be unused) + * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was + * delegated to's middleware times array + * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the + * specified strategies themselves + * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in + * the specified strategies + * will simply be transferred to the caller directly. + * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index + * that satisfies `slasher.canWithdraw` + */ + function completeQueuedWithdrawal( + IStrategy.QueuedWithdrawal calldata queuedWithdrawal, + IERC20[] calldata tokens, + uint256 middlewareTimesIndex, + bool receiveAsTokens + ) + external; +} diff --git a/contracts/external/eigenlayer/interfaces/ISlasher.sol b/contracts/external/eigenlayer/interfaces/ISlasher.sol new file mode 100644 index 0000000..d3c992f --- /dev/null +++ b/contracts/external/eigenlayer/interfaces/ISlasher.sol @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +/** + * @title Interface for the primary 'slashing' contract for EigenLayer. + * @author Layr Labs, Inc. + * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service + * @notice See the `Slasher` contract itself for implementation details. + */ +interface ISlasher { + // struct used to store information about the current state of an operator's obligations to middlewares they are + // serving + struct MiddlewareTimes { + // The update block for the middleware whose most recent update was earliest, i.e. the 'stalest' update out of + // all middlewares the operator is serving + uint32 stalestUpdateBlock; + // The latest 'serveUntilBlock' from all of the middleware that the operator is serving + uint32 latestServeUntilBlock; + } + + // struct used to store details relevant to a single middleware that an operator has opted-in to serving + struct MiddlewareDetails { + // the block before which the contract is allowed to slash the user + uint32 contractCanSlashOperatorUntilBlock; + // the block at which the middleware's view of the operator's stake was most recently updated + uint32 latestUpdateBlock; + } + + /** + * @notice Gives the `contractAddress` permission to slash the funds of the caller. + * @dev Typically, this function must be called prior to registering for a middleware. + */ + function optIntoSlashing(address contractAddress) external; + + /** + * @notice Used for 'slashing' a certain operator. + * @param toBeFrozen The operator to be frozen. + * @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending + * a decision by a human-in-the-loop. + * @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, + * through a call to `optIntoSlashing`. + */ + function freezeOperator(address toBeFrozen) external; + + /** + * @notice Removes the 'frozen' status from each of the `frozenAddresses` + * @dev Callable only by the contract owner (i.e. governance). + */ + function resetFrozenStatus(address[] calldata frozenAddresses) external; + + /** + * @notice this function is a called by middlewares during an operator's registration to make sure the operator's + * stake at registration + * is slashable until serveUntil + * @param operator the operator whose stake update is being recorded + * @param serveUntilBlock the block until which the operator's stake at the current block is slashable + * @dev adds the middleware's slashing contract to the operator's linked list + */ + function recordFirstStakeUpdate(address operator, uint32 serveUntilBlock) external; + + /** + * @notice this function is a called by middlewares during a stake update for an operator (perhaps to free pending + * withdrawals) + * to make sure the operator's stake at updateBlock is slashable until serveUntil + * @param operator the operator whose stake update is being recorded + * @param updateBlock the block for which the stake update is being recorded + * @param serveUntilBlock the block until which the operator's stake at updateBlock is slashable + * @param insertAfter the element of the operators linked list that the currently updating middleware should be + * inserted after + * @dev insertAfter should be calculated offchain before making the transaction that calls this. this is subject to + * race conditions, + * but it is anticipated to be rare and not detrimental. + */ + function recordStakeUpdate( + address operator, + uint32 updateBlock, + uint32 serveUntilBlock, + uint256 insertAfter + ) + external; + + /** + * @notice this function is a called by middlewares during an operator's deregistration to make sure the operator's + * stake at deregistration + * is slashable until serveUntil + * @param operator the operator whose stake update is being recorded + * @param serveUntilBlock the block until which the operator's stake at the current block is slashable + * @dev removes the middleware's slashing contract to the operator's linked list and revokes the middleware's (i.e. + * caller's) ability to + * slash `operator` once `serveUntil` is reached + */ + function recordLastStakeUpdateAndRevokeSlashingAbility(address operator, uint32 serveUntilBlock) external; + + /** + * @notice Used to determine whether `staker` is actively 'frozen'. If a staker is frozen, then they are potentially + * subject to + * slashing of their funds, and cannot cannot deposit or withdraw from the strategyManager until the slashing + * process is completed + * and the staker's status is reset (to 'unfrozen'). + * @param staker The staker of interest. + * @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated + * to an operator who has their status set to frozen. Otherwise returns 'false'. + */ + function isFrozen(address staker) external view returns (bool); + + /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`. + function canSlash(address toBeSlashed, address slashingContract) external view returns (bool); + + /// @notice Returns the block until which `serviceContract` is allowed to slash the `operator`. + function contractCanSlashOperatorUntilBlock( + address operator, + address serviceContract + ) + external + view + returns (uint32); + + /// @notice Returns the block at which the `serviceContract` last updated its view of the `operator`'s stake + function latestUpdateBlock(address operator, address serviceContract) external view returns (uint32); + + /// @notice A search routine for finding the correct input value of `insertAfter` to `recordStakeUpdate` / + /// `_updateMiddlewareList`. + function getCorrectValueForInsertAfter(address operator, uint32 updateBlock) external view returns (uint256); + + /** + * @notice Returns 'true' if `operator` can currently complete a withdrawal started at the `withdrawalStartBlock`, + * with `middlewareTimesIndex` used + * to specify the index of a `MiddlewareTimes` struct in the operator's list (i.e. an index in + * `operatorToMiddlewareTimes[operator]`). The specified + * struct is consulted as proof of the `operator`'s ability (or lack thereof) to complete the withdrawal. + * This function will return 'false' if the operator cannot currently complete a withdrawal started at the + * `withdrawalStartBlock`, *or* in the event + * that an incorrect `middlewareTimesIndex` is supplied, even if one or more correct inputs exist. + * @param operator Either the operator who queued the withdrawal themselves, or if the withdrawing party is a staker + * who delegated to an operator, + * this address is the operator *who the staker was delegated to* at the time of the `withdrawalStartBlock`. + * @param withdrawalStartBlock The block number at which the withdrawal was initiated. + * @param middlewareTimesIndex Indicates an index in `operatorToMiddlewareTimes[operator]` to consult as proof of + * the `operator`'s ability to withdraw + * @dev The correct `middlewareTimesIndex` input should be computable off-chain. + */ + function canWithdraw( + address operator, + uint32 withdrawalStartBlock, + uint256 middlewareTimesIndex + ) + external + returns (bool); + + /** + * operator => + * [ + * ( + * the least recent update block of all of the middlewares it's serving/served, + * latest time that the stake bonded at that update needed to serve until + * ) + * ] + */ + function operatorToMiddlewareTimes( + address operator, + uint256 arrayIndex + ) + external + view + returns (MiddlewareTimes memory); + + /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator].length` + function middlewareTimesLength(address operator) external view returns (uint256); + + /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].stalestUpdateBlock`. + function getMiddlewareTimesIndexBlock(address operator, uint32 index) external view returns (uint32); + + /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].latestServeUntil`. + function getMiddlewareTimesIndexServeUntilBlock(address operator, uint32 index) external view returns (uint32); + + /// @notice Getter function for fetching `_operatorToWhitelistedContractsByUpdate[operator].size`. + function operatorWhitelistedContractsLinkedListSize(address operator) external view returns (uint256); + + /// @notice Getter function for fetching a single node in the operator's linked list + /// (`_operatorToWhitelistedContractsByUpdate[operator]`). + function operatorWhitelistedContractsLinkedListEntry( + address operator, + address node + ) + external + view + returns (bool, uint256, uint256); +} diff --git a/contracts/interfaces/IStrategy.sol b/contracts/external/eigenlayer/interfaces/IStrategy.sol similarity index 92% rename from contracts/interfaces/IStrategy.sol rename to contracts/external/eigenlayer/interfaces/IStrategy.sol index 7d718e1..242cbea 100644 --- a/contracts/interfaces/IStrategy.sol +++ b/contracts/external/eigenlayer/interfaces/IStrategy.sol @@ -10,6 +10,21 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; * @notice Custom `Strategy` implementations may expand extensively on this interface. */ interface IStrategy { + // packed struct for queued withdrawals; helps deal with stack-too-deep errors + struct WithdrawerAndNonce { + address withdrawer; + uint96 nonce; + } + + struct QueuedWithdrawal { + IStrategy[] strategies; + uint256[] shares; + address depositor; + WithdrawerAndNonce withdrawerAndNonce; + uint32 withdrawalStartBlock; + address delegatedAddress; + } + /** * @notice Used to deposit tokens into this Strategy * @param token is the ERC20 token being deposited diff --git a/contracts/external/eigenlayer/libraries/BeaconChainProofs.sol b/contracts/external/eigenlayer/libraries/BeaconChainProofs.sol new file mode 100644 index 0000000..07a0f00 --- /dev/null +++ b/contracts/external/eigenlayer/libraries/BeaconChainProofs.sol @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import "./Merkle.sol"; +import "./Endian.sol"; + +//Utility library for parsing and PHASE0 beacon chain block headers +//SSZ Spec: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization +//BeaconBlockHeader Spec: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader +//BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate +library BeaconChainProofs { + // constants are the number of fields and the heights of the different merkle trees used in merkleizing beacon chain + // containers + uint256 internal constant BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT = 3; + + uint256 internal constant BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT = 4; + + uint256 internal constant BEACON_STATE_FIELD_TREE_HEIGHT = 5; + + uint256 internal constant VALIDATOR_FIELD_TREE_HEIGHT = 3; + + //Note: changed in the deneb hard fork from 4->5 + uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB = 5; + uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA = 4; + + // SLOTS_PER_HISTORICAL_ROOT = 2**13, so tree height is 13 + uint256 internal constant BLOCK_ROOTS_TREE_HEIGHT = 13; + + //HISTORICAL_ROOTS_LIMIT = 2**24, so tree height is 24 + uint256 internal constant HISTORICAL_SUMMARIES_TREE_HEIGHT = 24; + + //Index of block_summary_root in historical_summary container + uint256 internal constant BLOCK_SUMMARY_ROOT_INDEX = 0; + + // tree height for hash tree of an individual withdrawal container + uint256 internal constant WITHDRAWAL_FIELD_TREE_HEIGHT = 2; + + uint256 internal constant VALIDATOR_TREE_HEIGHT = 40; + + // MAX_WITHDRAWALS_PER_PAYLOAD = 2**4, making tree height = 4 + uint256 internal constant WITHDRAWALS_TREE_HEIGHT = 4; + + //in beacon block body + // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconblockbody + uint256 internal constant EXECUTION_PAYLOAD_INDEX = 9; + + // in beacon block header + // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader + uint256 internal constant SLOT_INDEX = 0; + uint256 internal constant STATE_ROOT_INDEX = 3; + uint256 internal constant BODY_ROOT_INDEX = 4; + // in beacon state https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconstate + uint256 internal constant VALIDATOR_TREE_ROOT_INDEX = 11; + uint256 internal constant HISTORICAL_SUMMARIES_INDEX = 27; + + // in validator https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator + uint256 internal constant VALIDATOR_PUBKEY_INDEX = 0; + uint256 internal constant VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1; + uint256 internal constant VALIDATOR_BALANCE_INDEX = 2; + uint256 internal constant VALIDATOR_WITHDRAWABLE_EPOCH_INDEX = 7; + + // in execution payload header + uint256 internal constant TIMESTAMP_INDEX = 9; + + //in execution payload + uint256 internal constant WITHDRAWALS_INDEX = 14; + + // in withdrawal + uint256 internal constant WITHDRAWAL_VALIDATOR_INDEX_INDEX = 1; + uint256 internal constant WITHDRAWAL_VALIDATOR_AMOUNT_INDEX = 3; + + //Misc Constants + + /// @notice The number of slots each epoch in the beacon chain + uint64 internal constant SLOTS_PER_EPOCH = 32; + + /// @notice The number of seconds in a slot in the beacon chain + uint64 internal constant SECONDS_PER_SLOT = 12; + + /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot + uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT; + + bytes8 internal constant UINT64_MASK = 0xffffffffffffffff; + + /// @notice This struct contains the merkle proofs and leaves needed to verify a partial/full withdrawal + struct WithdrawalProof { + bytes withdrawalProof; + bytes slotProof; + bytes executionPayloadProof; + bytes timestampProof; + bytes historicalSummaryBlockRootProof; + uint64 blockRootIndex; + uint64 historicalSummaryIndex; + uint64 withdrawalIndex; + bytes32 blockRoot; + bytes32 slotRoot; + bytes32 timestampRoot; + bytes32 executionPayloadRoot; + } + + /// @notice This struct contains the root and proof for verifying the state root against the oracle block root + struct StateRootProof { + bytes32 beaconStateRoot; + bytes proof; + } + + /** + * @notice This function verifies merkle proofs of the fields of a certain validator against a beacon chain state + * root + * @param validatorIndex the index of the proven validator + * @param beaconStateRoot is the beacon chain state root to be proven against. + * @param validatorFieldsProof is the data used in proving the validator's fields + * @param validatorFields the claimed fields of the validator + */ + function verifyValidatorFields( + bytes32 beaconStateRoot, + bytes32[] calldata validatorFields, + bytes calldata validatorFieldsProof, + uint40 validatorIndex + ) + internal + view + { + require( + validatorFields.length == 2 ** VALIDATOR_FIELD_TREE_HEIGHT, + "BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length" + ); + + /** + * Note: the length of the validator merkle proof is BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1. + * There is an additional layer added by hashing the root with the length of the validator list + */ + require( + validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + BEACON_STATE_FIELD_TREE_HEIGHT), + "BeaconChainProofs.verifyValidatorFields: Proof has incorrect length" + ); + uint256 index = (VALIDATOR_TREE_ROOT_INDEX << (VALIDATOR_TREE_HEIGHT + 1)) | uint256(validatorIndex); + // merkleize the validatorFields to get the leaf to prove + bytes32 validatorRoot = Merkle.merkleizeSha256(validatorFields); + + // verify the proof of the validatorRoot against the beaconStateRoot + require( + Merkle.verifyInclusionSha256({ + proof: validatorFieldsProof, + root: beaconStateRoot, + leaf: validatorRoot, + index: index + }), + "BeaconChainProofs.verifyValidatorFields: Invalid merkle proof" + ); + } + + /** + * @notice This function verifies the latestBlockHeader against the state root. the latestBlockHeader is + * a tracked in the beacon state. + * @param beaconStateRoot is the beacon chain state root to be proven against. + * @param stateRootProof is the provided merkle proof + * @param latestBlockRoot is hashtree root of the latest block header in the beacon state + */ + function verifyStateRootAgainstLatestBlockRoot( + bytes32 latestBlockRoot, + bytes32 beaconStateRoot, + bytes calldata stateRootProof + ) + internal + view + { + require( + stateRootProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT), + "BeaconChainProofs.verifyStateRootAgainstLatestBlockRoot: Proof has incorrect length" + ); + //Next we verify the slot against the blockRoot + require( + Merkle.verifyInclusionSha256({ + proof: stateRootProof, + root: latestBlockRoot, + leaf: beaconStateRoot, + index: STATE_ROOT_INDEX + }), + "BeaconChainProofs.verifyStateRootAgainstLatestBlockRoot: Invalid latest block header root merkle proof" + ); + } + + /** + * @notice This function verifies the slot and the withdrawal fields for a given withdrawal + * @param withdrawalProof is the provided set of merkle proofs + * @param withdrawalFields is the serialized withdrawal container to be proven + */ + function verifyWithdrawal( + bytes32 beaconStateRoot, + bytes32[] calldata withdrawalFields, + WithdrawalProof calldata withdrawalProof, + uint64 denebForkTimestamp + ) + internal + view + { + require( + withdrawalFields.length == 2 ** WITHDRAWAL_FIELD_TREE_HEIGHT, + "BeaconChainProofs.verifyWithdrawal: withdrawalFields has incorrect length" + ); + + require( + withdrawalProof.blockRootIndex < 2 ** BLOCK_ROOTS_TREE_HEIGHT, + "BeaconChainProofs.verifyWithdrawal: blockRootIndex is too large" + ); + require( + withdrawalProof.withdrawalIndex < 2 ** WITHDRAWALS_TREE_HEIGHT, + "BeaconChainProofs.verifyWithdrawal: withdrawalIndex is too large" + ); + + require( + withdrawalProof.historicalSummaryIndex < 2 ** HISTORICAL_SUMMARIES_TREE_HEIGHT, + "BeaconChainProofs.verifyWithdrawal: historicalSummaryIndex is too large" + ); + + //Note: post deneb hard fork, the number of exection payload header fields increased from 15->17, adding an + // extra level to the tree height + uint256 executionPayloadHeaderFieldTreeHeight = (getWithdrawalTimestamp(withdrawalProof) < denebForkTimestamp) + ? EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA + : EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB; + require( + withdrawalProof.withdrawalProof.length + == 32 * (executionPayloadHeaderFieldTreeHeight + WITHDRAWALS_TREE_HEIGHT + 1), + "BeaconChainProofs.verifyWithdrawal: withdrawalProof has incorrect length" + ); + require( + withdrawalProof.executionPayloadProof.length + == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT + BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT), + "BeaconChainProofs.verifyWithdrawal: executionPayloadProof has incorrect length" + ); + require( + withdrawalProof.slotProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT), + "BeaconChainProofs.verifyWithdrawal: slotProof has incorrect length" + ); + require( + withdrawalProof.timestampProof.length == 32 * (executionPayloadHeaderFieldTreeHeight), + "BeaconChainProofs.verifyWithdrawal: timestampProof has incorrect length" + ); + + require( + withdrawalProof.historicalSummaryBlockRootProof.length + == 32 + * (BEACON_STATE_FIELD_TREE_HEIGHT + (HISTORICAL_SUMMARIES_TREE_HEIGHT + 1) + 1 + (BLOCK_ROOTS_TREE_HEIGHT)), + "BeaconChainProofs.verifyWithdrawal: historicalSummaryBlockRootProof has incorrect length" + ); + /** + * Note: Here, the "1" in "1 + (BLOCK_ROOTS_TREE_HEIGHT)" signifies that extra step of choosing the + * "block_root_summary" within the individual + * "historical_summary". Everywhere else it signifies merkelize_with_mixin, where the length of an array is + * hashed with the root of the array, + * but not here. + */ + uint256 historicalBlockHeaderIndex = ( + HISTORICAL_SUMMARIES_INDEX << ((HISTORICAL_SUMMARIES_TREE_HEIGHT + 1) + 1 + (BLOCK_ROOTS_TREE_HEIGHT)) + ) | (uint256(withdrawalProof.historicalSummaryIndex) << (1 + (BLOCK_ROOTS_TREE_HEIGHT))) + | (BLOCK_SUMMARY_ROOT_INDEX << (BLOCK_ROOTS_TREE_HEIGHT)) | uint256(withdrawalProof.blockRootIndex); + + require( + Merkle.verifyInclusionSha256({ + proof: withdrawalProof.historicalSummaryBlockRootProof, + root: beaconStateRoot, + leaf: withdrawalProof.blockRoot, + index: historicalBlockHeaderIndex + }), + "BeaconChainProofs.verifyWithdrawal: Invalid historicalsummary merkle proof" + ); + + //Next we verify the slot against the blockRoot + require( + Merkle.verifyInclusionSha256({ + proof: withdrawalProof.slotProof, + root: withdrawalProof.blockRoot, + leaf: withdrawalProof.slotRoot, + index: SLOT_INDEX + }), + "BeaconChainProofs.verifyWithdrawal: Invalid slot merkle proof" + ); + + { + // Next we verify the executionPayloadRoot against the blockRoot + uint256 executionPayloadIndex = + (BODY_ROOT_INDEX << (BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT)) | EXECUTION_PAYLOAD_INDEX; + require( + Merkle.verifyInclusionSha256({ + proof: withdrawalProof.executionPayloadProof, + root: withdrawalProof.blockRoot, + leaf: withdrawalProof.executionPayloadRoot, + index: executionPayloadIndex + }), + "BeaconChainProofs.verifyWithdrawal: Invalid executionPayload merkle proof" + ); + } + + // Next we verify the timestampRoot against the executionPayload root + require( + Merkle.verifyInclusionSha256({ + proof: withdrawalProof.timestampProof, + root: withdrawalProof.executionPayloadRoot, + leaf: withdrawalProof.timestampRoot, + index: TIMESTAMP_INDEX + }), + "BeaconChainProofs.verifyWithdrawal: Invalid timestamp merkle proof" + ); + + { + /** + * Next we verify the withdrawal fields against the executionPayloadRoot: + * First we compute the withdrawal_index, then we merkleize the + * withdrawalFields container to calculate the withdrawalRoot. + * + * Note: Merkleization of the withdrawals root tree uses MerkleizeWithMixin, i.e., the length of the array + * is hashed with the root of + * the array. Thus we shift the WITHDRAWALS_INDEX over by WITHDRAWALS_TREE_HEIGHT + 1 and not just + * WITHDRAWALS_TREE_HEIGHT. + */ + uint256 withdrawalIndex = + (WITHDRAWALS_INDEX << (WITHDRAWALS_TREE_HEIGHT + 1)) | uint256(withdrawalProof.withdrawalIndex); + bytes32 withdrawalRoot = Merkle.merkleizeSha256(withdrawalFields); + require( + Merkle.verifyInclusionSha256({ + proof: withdrawalProof.withdrawalProof, + root: withdrawalProof.executionPayloadRoot, + leaf: withdrawalRoot, + index: withdrawalIndex + }), + "BeaconChainProofs.verifyWithdrawal: Invalid withdrawal merkle proof" + ); + } + } + + /** + * @notice This function replicates the ssz hashing of a validator's pubkey, outlined below: + * hh := ssz.NewHasher() + * hh.PutBytes(validatorPubkey[:]) + * validatorPubkeyHash := hh.Hash() + * hh.Reset() + */ + function hashValidatorBLSPubkey(bytes memory validatorPubkey) internal pure returns (bytes32 pubkeyHash) { + require(validatorPubkey.length == 48, "Input should be 48 bytes in length"); + return sha256(abi.encodePacked(validatorPubkey, bytes16(0))); + } + + /** + * @dev Retrieve the withdrawal timestamp + */ + function getWithdrawalTimestamp(WithdrawalProof memory withdrawalProof) internal pure returns (uint64) { + return Endian.fromLittleEndianUint64(withdrawalProof.timestampRoot); + } + + /** + * @dev Converts the withdrawal's slot to an epoch + */ + function getWithdrawalEpoch(WithdrawalProof memory withdrawalProof) internal pure returns (uint64) { + return Endian.fromLittleEndianUint64(withdrawalProof.slotRoot) / SLOTS_PER_EPOCH; + } + + /** + * Indices for validator fields (refer to consensus specs): + * 0: pubkey + * 1: withdrawal credentials + * 2: effective balance + * 3: slashed? + * 4: activation elligibility epoch + * 5: activation epoch + * 6: exit epoch + * 7: withdrawable epoch + */ + + /** + * @dev Retrieves a validator's pubkey hash + */ + function getPubkeyHash(bytes32[] memory validatorFields) internal pure returns (bytes32) { + return validatorFields[VALIDATOR_PUBKEY_INDEX]; + } + + function getWithdrawalCredentials(bytes32[] memory validatorFields) internal pure returns (bytes32) { + return validatorFields[VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX]; + } + + /** + * @dev Retrieves a validator's effective balance (in gwei) + */ + function getEffectiveBalanceGwei(bytes32[] memory validatorFields) internal pure returns (uint64) { + return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_BALANCE_INDEX]); + } + + /** + * @dev Retrieves a validator's withdrawable epoch + */ + function getWithdrawableEpoch(bytes32[] memory validatorFields) internal pure returns (uint64) { + return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_WITHDRAWABLE_EPOCH_INDEX]); + } + + /** + * Indices for withdrawal fields (refer to consensus specs): + * 0: withdrawal index + * 1: validator index + * 2: execution address + * 3: withdrawal amount + */ + + /** + * @dev Retrieves a withdrawal's validator index + */ + function getValidatorIndex(bytes32[] memory withdrawalFields) internal pure returns (uint40) { + return uint40(Endian.fromLittleEndianUint64(withdrawalFields[WITHDRAWAL_VALIDATOR_INDEX_INDEX])); + } + + /** + * @dev Retrieves a withdrawal's withdrawal amount (in gwei) + */ + function getWithdrawalAmountGwei(bytes32[] memory withdrawalFields) internal pure returns (uint64) { + return Endian.fromLittleEndianUint64(withdrawalFields[WITHDRAWAL_VALIDATOR_AMOUNT_INDEX]); + } +} diff --git a/contracts/external/eigenlayer/libraries/Endian.sol b/contracts/external/eigenlayer/libraries/Endian.sol new file mode 100644 index 0000000..4dd946d --- /dev/null +++ b/contracts/external/eigenlayer/libraries/Endian.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +library Endian { + /** + * @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64 + * @param lenum little endian-formatted uint64 input, provided as 'bytes32' type + * @return n The big endian-formatted uint64 + * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a + * uint64 (i.e. 64 bits) + * through a right-shift/shr operation. + */ + function fromLittleEndianUint64(bytes32 lenum) internal pure returns (uint64 n) { + // the number needs to be stored in little-endian encoding (ie in bytes 0-8) + n = uint64(uint256(lenum >> 192)); + return (n >> 56) | ((0x00FF000000000000 & n) >> 40) | ((0x0000FF0000000000 & n) >> 24) + | ((0x000000FF00000000 & n) >> 8) | ((0x00000000FF000000 & n) << 8) | ((0x0000000000FF0000 & n) << 24) + | ((0x000000000000FF00 & n) << 40) | ((0x00000000000000FF & n) << 56); + } +} diff --git a/contracts/external/eigenlayer/libraries/Merkle.sol b/contracts/external/eigenlayer/libraries/Merkle.sol new file mode 100644 index 0000000..8f481a7 --- /dev/null +++ b/contracts/external/eigenlayer/libraries/Merkle.sol @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: MIT +// Adapted from OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity 0.8.21; + +/** + * @dev These functions deal with verification of Merkle Tree proofs. + * + * The tree and the proofs can be generated using our + * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. + * You will find a quickstart guide in the readme. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + * OpenZeppelin's JavaScript library generates merkle trees that are safe + * against this attack out of the box. + */ +library Merkle { + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. The tree is built assuming `leaf` is + * the 0 indexed `index`'th leaf from the bottom left of the tree. + * + * Note this is for a Merkle tree using the keccak/sha3 hash function + */ + function verifyInclusionKeccak( + bytes memory proof, + bytes32 root, + bytes32 leaf, + uint256 index + ) + internal + pure + returns (bool) + { + return processInclusionProofKeccak(proof, leaf, index) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. The tree is built assuming `leaf` is + * the 0 indexed `index`'th leaf from the bottom left of the tree. + * + * _Available since v4.4._ + * + * Note this is for a Merkle tree using the keccak/sha3 hash function + */ + function processInclusionProofKeccak( + bytes memory proof, + bytes32 leaf, + uint256 index + ) + internal + pure + returns (bytes32) + { + require( + proof.length != 0 && proof.length % 32 == 0, + "Merkle.processInclusionProofKeccak: proof length should be a non-zero multiple of 32" + ); + bytes32 computedHash = leaf; + for (uint256 i = 32; i <= proof.length; i += 32) { + if (index % 2 == 0) { + // if ith bit of index is 0, then computedHash is a left sibling + assembly { + mstore(0x00, computedHash) + mstore(0x20, mload(add(proof, i))) + computedHash := keccak256(0x00, 0x40) + index := div(index, 2) + } + } else { + // if ith bit of index is 1, then computedHash is a right sibling + assembly { + mstore(0x00, mload(add(proof, i))) + mstore(0x20, computedHash) + computedHash := keccak256(0x00, 0x40) + index := div(index, 2) + } + } + } + return computedHash; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. The tree is built assuming `leaf` is + * the 0 indexed `index`'th leaf from the bottom left of the tree. + * + * Note this is for a Merkle tree using the sha256 hash function + */ + function verifyInclusionSha256( + bytes memory proof, + bytes32 root, + bytes32 leaf, + uint256 index + ) + internal + view + returns (bool) + { + return processInclusionProofSha256(proof, leaf, index) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. The tree is built assuming `leaf` is + * the 0 indexed `index`'th leaf from the bottom left of the tree. + * + * _Available since v4.4._ + * + * Note this is for a Merkle tree using the sha256 hash function + */ + function processInclusionProofSha256( + bytes memory proof, + bytes32 leaf, + uint256 index + ) + internal + view + returns (bytes32) + { + require( + proof.length != 0 && proof.length % 32 == 0, + "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32" + ); + bytes32[1] memory computedHash = [leaf]; + for (uint256 i = 32; i <= proof.length; i += 32) { + if (index % 2 == 0) { + // if ith bit of index is 0, then computedHash is a left sibling + assembly { + mstore(0x00, mload(computedHash)) + mstore(0x20, mload(add(proof, i))) + if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) } + index := div(index, 2) + } + } else { + // if ith bit of index is 1, then computedHash is a right sibling + assembly { + mstore(0x00, mload(add(proof, i))) + mstore(0x20, mload(computedHash)) + if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) } + index := div(index, 2) + } + } + } + return computedHash[0]; + } + + /** + * @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash + * function + * @param leaves the leaves of the merkle tree + * @return The computed Merkle root of the tree. + * @dev A pre-condition to this function is that leaves.length is a power of two. If not, the function will + * merkleize the inputs incorrectly. + */ + function merkleizeSha256(bytes32[] memory leaves) internal pure returns (bytes32) { + //there are half as many nodes in the layer above the leaves + uint256 numNodesInLayer = leaves.length / 2; + //create a layer to store the internal nodes + bytes32[] memory layer = new bytes32[](numNodesInLayer); + //fill the layer with the pairwise hashes of the leaves + for (uint256 i = 0; i < numNodesInLayer; i++) { + layer[i] = sha256(abi.encodePacked(leaves[2 * i], leaves[2 * i + 1])); + } + //the next layer above has half as many nodes + numNodesInLayer /= 2; + //while we haven't computed the root + while (numNodesInLayer != 0) { + //overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children + for (uint256 i = 0; i < numNodesInLayer; i++) { + layer[i] = sha256(abi.encodePacked(layer[2 * i], layer[2 * i + 1])); + } + //the next layer above has half as many nodes + numNodesInLayer /= 2; + } + //the first node in the layer is the root + return layer[0]; + } +} diff --git a/contracts/interfaces/ILayerZeroEndpoint.sol b/contracts/external/layerzero/interfaces/ILayerZeroEndpoint.sol similarity index 100% rename from contracts/interfaces/ILayerZeroEndpoint.sol rename to contracts/external/layerzero/interfaces/ILayerZeroEndpoint.sol diff --git a/contracts/interfaces/ILayerZeroReceiver.sol b/contracts/external/layerzero/interfaces/ILayerZeroReceiver.sol similarity index 100% rename from contracts/interfaces/ILayerZeroReceiver.sol rename to contracts/external/layerzero/interfaces/ILayerZeroReceiver.sol diff --git a/contracts/interfaces/ILayerZeroUserApplicationConfig.sol b/contracts/external/layerzero/interfaces/ILayerZeroUserApplicationConfig.sol similarity index 100% rename from contracts/interfaces/ILayerZeroUserApplicationConfig.sol rename to contracts/external/layerzero/interfaces/ILayerZeroUserApplicationConfig.sol diff --git a/contracts/interfaces/IEigenDelayedWithdrawalRouter.sol b/contracts/interfaces/IEigenDelayedWithdrawalRouter.sol deleted file mode 100644 index 4abb93f..0000000 --- a/contracts/interfaces/IEigenDelayedWithdrawalRouter.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.21; - -interface IEigenDelayedWithdrawalRouter { - function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfDelayedWithdrawalsToClaim) external; -} diff --git a/contracts/interfaces/IEigenPod.sol b/contracts/interfaces/IEigenPod.sol deleted file mode 100644 index b486e27..0000000 --- a/contracts/interfaces/IEigenPod.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.21; - -library Endian { - /** - * @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64 - * @param lenum little endian-formatted uint64 input, provided as 'bytes32' type - * @return n The big endian-formatted uint64 - * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a - * uint64 (i.e. 64 bits) - * through a right-shift/shr operation. - */ - function fromLittleEndianUint64(bytes32 lenum) internal pure returns (uint64 n) { - // the number needs to be stored in little-endian encoding (ie in bytes 0-8) - n = uint64(uint256(lenum >> 192)); - return (n >> 56) | ((0x00FF000000000000 & n) >> 40) | ((0x0000FF0000000000 & n) >> 24) - | ((0x000000FF00000000 & n) >> 8) | ((0x00000000FF000000 & n) << 8) | ((0x0000000000FF0000 & n) << 24) - | ((0x000000000000FF00 & n) << 40) | ((0x00000000000000FF & n) << 56); - } -} - -library BeaconChainProofs { - struct ValidatorFieldsAndBalanceProofs { - bytes validatorFieldsProof; - bytes validatorBalanceProof; - bytes32 balanceRoot; - } - - /** - * - * @notice This function is parses the balanceRoot to get the uint64 balance of a validator. During merkleization - * of the - * beacon state balance tree, four uint64 values (making 32 bytes) are grouped together and treated as a single leaf - * in the merkle tree. Thus the - * validatorIndex mod 4 is used to determine which of the four uint64 values to extract from the balanceRoot. - * @param validatorIndex is the index of the validator being proven for. - * @param balanceRoot is the combination of 4 validator balances being proven for. - * @return The validator's balance, in Gwei - */ - function getBalanceFromBalanceRoot(uint40 validatorIndex, bytes32 balanceRoot) internal pure returns (uint64) { - uint256 bitShiftAmount = (validatorIndex % 4) * 64; - bytes32 validatorBalanceLittleEndian = bytes32((uint256(balanceRoot) << bitShiftAmount)); - uint64 validatorBalance = Endian.fromLittleEndianUint64(validatorBalanceLittleEndian); - return validatorBalance; - } -} - -interface IBeaconDeposit { - /// @notice Query the current deposit root hash. - /// @return The deposit root hash. - function get_deposit_root() external view returns (bytes32); -} - -interface IEigenPod { - /// @notice This is the beacon chain deposit contract - function ethPOS() external returns (IBeaconDeposit); - - /// @return delayedWithdrawalRouter address of eigenlayer delayedWithdrawalRouter, - /// which does book keeping of delayed withdrawls - function delayedWithdrawalRouter() external returns (address); - - /// @notice Called by the pod owner to withdraw the balance of the pod when `hasRestaked` is set to false - function withdrawBeforeRestaking() external; - - /** - * @notice This function verifies that the withdrawal credentials of the podOwner are pointed to - * this contract. It also verifies the current (not effective) balance of the validator. It verifies the provided - * proof of the ETH validator against the beacon chain state - * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer. - * @param oracleBlockNumber is the Beacon Chain blockNumber whose state root the `proof` will be proven against. - * @param validatorIndex is the index of the validator being proven, refer to consensus specs - * @param proofs is the bytes that prove the ETH validator's balance and withdrawal credentials against a beacon - * chain state root - * @param validatorFields are the fields of the "Validator Container", refer to consensus specs - * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator - */ - function verifyWithdrawalCredentialsAndBalance( - uint64 oracleBlockNumber, - uint40 validatorIndex, - BeaconChainProofs.ValidatorFieldsAndBalanceProofs memory proofs, - bytes32[] calldata validatorFields - ) - external; -} diff --git a/contracts/interfaces/IEigenStrategyManager.sol b/contracts/interfaces/IEigenStrategyManager.sol deleted file mode 100644 index 2ed877b..0000000 --- a/contracts/interfaces/IEigenStrategyManager.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.21; - -import "./IStrategy.sol"; - -interface IEigenStrategyManager { - /** - * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to - * `msg.sender` - * @param strategy is the specified strategy where deposit is to be made, - * @param token is the denomination in which the deposit is to be made, - * @param amount is the amount of token to be deposited in the strategy by the depositor - * @return shares The amount of new shares in the `strategy` created as part of the action. - * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on - * their behalf. - * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen). - * - * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended. This can lead - * to attack vectors - * where the token balance and corresponding strategy shares are not in sync upon reentrancy. - */ - function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount) external returns (uint256 shares); - - /** - * @notice Get all details on the depositor's deposits and corresponding shares - * @return (depositor's strategies, shares in these strategies) - */ - function getDeposits(address depositor) external view returns (IStrategy[] memory, uint256[] memory); -} diff --git a/contracts/interfaces/IFeeReceiver.sol b/contracts/interfaces/IFeeReceiver.sol new file mode 100644 index 0000000..ab4b465 --- /dev/null +++ b/contracts/interfaces/IFeeReceiver.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +interface IFeeReceiver { + // Errors + error InvalidEmptyValue(); + + // functions + function receiveFromNodeDelegator() external payable; +} diff --git a/contracts/interfaces/ILRTConverter.sol b/contracts/interfaces/ILRTConverter.sol new file mode 100644 index 0000000..895d106 --- /dev/null +++ b/contracts/interfaces/ILRTConverter.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { IEigenDelegationManager } from "contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol"; + +interface ILRTConverter { + error NotEnoughAssetToTransfer(); + error TokenTransferFailed(); + error InvalidWithdrawer(); + error WithdrawalRootNotPending(); + error WithdrawalRootAlreadyProcess(); + error ConversionLimitReached(); + error WithdrawalRootNotProcessed(); + error MinimumExpectedReturnNotReached(); + + event ConvertedEigenlayerAssetToRsEth(address indexed reciever, uint256 rsethAmount, bytes32 withdrawalRoot); + event ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount); + event EthTransferred(address to, uint256 amount); + + function ethValueInWithdrawal() external view returns (uint256); + + function transferAssetFromDepositPool(address _asset, uint256 _amount) external; +} diff --git a/contracts/interfaces/ILRTDepositPool.sol b/contracts/interfaces/ILRTDepositPool.sol index 7cece56..427d45b 100644 --- a/contracts/interfaces/ILRTDepositPool.sol +++ b/contracts/interfaces/ILRTDepositPool.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.21; interface ILRTDepositPool { //errors - error TokenTransferFailed(); error InvalidAmountToDeposit(); error NotEnoughAssetToTransfer(); error MaximumDepositLimitReached(); @@ -13,6 +12,7 @@ interface ILRTDepositPool { error NodeDelegatorNotFound(); error NodeDelegatorHasAssetBalance(address assetAddress, uint256 assetBalance); error NodeDelegatorHasETH(); + error EthTransferFailed(); //events event MaxNodeDelegatorLimitUpdated(uint256 maxNodeDelegatorLimit); @@ -27,8 +27,11 @@ interface ILRTDepositPool { ); event ETHDeposit(address indexed depositor, uint256 depositAmount, uint256 rsethMintAmount, string referralId); event MinAmountToDepositUpdated(uint256 minAmountToDeposit); + event MaxNegligibleAmountUpdated(uint256 maxNegligibleAmount); event ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount); + event EthTransferred(address to, uint256 amount); + // functions function depositAsset( address asset, uint256 depositAmount, @@ -37,6 +40,14 @@ interface ILRTDepositPool { ) external; + function getSwapETHToAssetReturnAmount( + address toAsset, + uint256 ethAmountToSend + ) + external + view + returns (uint256 returnAmount); + function getTotalAssetDeposits(address asset) external view returns (uint256); function getAssetCurrentLimit(address asset) external view returns (uint256); @@ -54,10 +65,31 @@ interface ILRTDepositPool { function getAssetDistributionData(address asset) external view - returns (uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer); + returns ( + uint256 assetLyingInDepositPool, + uint256 assetLyingInNDCs, + uint256 assetStakedInEigenLayer, + uint256 assetUnstakingFromEigenLayer, + uint256 assetLyingInConverter, + uint256 assetLyingUnstakingVault + ); function getETHDistributionData() external view - returns (uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer); + returns ( + uint256 ethLyingInDepositPool, + uint256 ethLyingInNDCs, + uint256 ethStakedInEigenLayer, + uint256 ethUnstakingFromEigenLayer, + uint256 ethLyingInConverter, + uint256 ethLyingInUnstakingVault + ); + + function isNodeDelegator(address nodeDelegatorContract) external view returns (uint256); + + // receivers + function receiveFromRewardReceiver() external payable; + function receiveFromLRTConverter() external payable; + function receiveFromNodeDelegator() external payable; } diff --git a/contracts/interfaces/ILRTOracle.sol b/contracts/interfaces/ILRTOracle.sol index bbb7fe9..d0881f7 100644 --- a/contracts/interfaces/ILRTOracle.sol +++ b/contracts/interfaces/ILRTOracle.sol @@ -2,8 +2,14 @@ pragma solidity 0.8.21; interface ILRTOracle { + // errors + error AssetOracleNotSupported(); + error RSETHPriceExceedsLimit(); + // events event AssetPriceOracleUpdate(address indexed asset, address indexed priceOracle); + event RsETHPriceUpdate(uint256 newPrice); + event PricePercentageLimitUpdate(uint256 newLimit); // methods function getAssetPrice(address asset) external view returns (uint256); diff --git a/contracts/interfaces/ILRTUnstakingVault.sol b/contracts/interfaces/ILRTUnstakingVault.sol new file mode 100644 index 0000000..19b5d5c --- /dev/null +++ b/contracts/interfaces/ILRTUnstakingVault.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { IStrategy } from "contracts/external/eigenlayer/interfaces/IStrategy.sol"; +import { IEigenDelegationManager } from "contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface ILRTUnstakingVault { + error CallerNotLRTNodeDelegator(); + error EthTransferFailed(); + error CallerNotLRTWithdrawalManager(); + + event EthReceived(address sender, uint256 amount); + + // functions + function sharesUnstaking(address asset) external view returns (uint256); + + function getAssetsUnstaking(address asset) external view returns (uint256); + + function balanceOf(address asset) external view returns (uint256); + + function addSharesUnstaking(address asset, uint256 amount) external; + + function reduceSharesUnstaking(address asset, uint256 amount) external; + + function redeem(address asset, uint256 amount) external; + + // receive functions + function receiveFromLRTDepositPool() external payable; + function receiveFromNodeDelegator() external payable; +} diff --git a/contracts/interfaces/ILRTWithdrawalManager.sol b/contracts/interfaces/ILRTWithdrawalManager.sol new file mode 100644 index 0000000..4ad97b8 --- /dev/null +++ b/contracts/interfaces/ILRTWithdrawalManager.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { IStrategy } from "contracts/external/eigenlayer/interfaces/IStrategy.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface ILRTWithdrawalManager { + //errors + error TokenTransferFailed(); + error EthTransferFailed(); + error InvalidAmountToWithdraw(); + error ExceedAmountToWithdraw(); + error WithdrawalLocked(); + error WithdrawalDelayNotPassed(); + error WithdrawalDelayTooSmall(); + error NoPendingWithdrawals(); + error AmountMustBeGreaterThanZero(); + error StrategyNotSupported(); + + error RsETHPriceMustBeGreaterMinimum(uint256 rsEthPrice); + error AssetPriceMustBeGreaterMinimum(uint256 assetPrice); + + struct WithdrawalRequest { + uint256 rsETHUnstaked; + uint256 expectedAssetAmount; + uint256 withdrawalStartBlock; + } + + //events + event AssetWithdrawalQueued( + address indexed withdrawer, address indexed asset, uint256 rsETHUnstaked, uint256 indexed userNonce + ); + + event AssetWithdrawalFinalized( + address indexed withdrawer, address indexed asset, uint256 amountBurned, uint256 amountReceived + ); + event EtherReceived(address indexed depositor, uint256 ethAmount, uint256 sharesAmount); + + event AssetUnlocked( + address indexed asset, uint256 rsEthAmount, uint256 assetAmount, uint256 rsEThPrice, uint256 assetPrice + ); + + event MinAmountToWithdrawUpdated(address asset, uint256 minRsEthAmountToWithdraw); + event WithdrawalDelayBlocksUpdated(uint256 withdrawalDelayBlocks); + + // methods + + function getExpectedAssetAmount(address asset, uint256 amount) external view returns (uint256); + + function getAvailableAssetAmount(address asset) external view returns (uint256 assetAmount); + + function getUserWithdrawalRequest( + address asset, + address user, + uint256 index + ) + external + view + returns (uint256 rsETHAmount, uint256 expectedAssetAmount, uint256 withdrawalStartBlock, uint256 userNonce); + + function initiateWithdrawal(address asset, uint256 withdrawAmount) external; + + function completeWithdrawal(address asset) external; + + function unlockQueue( + address asset, + uint256 index, + uint256 minimumAssetPrice, + uint256 minimumRsEthPrice + ) + external + returns (uint256 rsETHBurned, uint256 assetAmountUnlocked); + + // receive functions + function receiveFromLRTUnstakingVault() external payable; +} diff --git a/contracts/interfaces/INodeDelegator.sol b/contracts/interfaces/INodeDelegator.sol index 5da3a1c..1609c41 100644 --- a/contracts/interfaces/INodeDelegator.sol +++ b/contracts/interfaces/INodeDelegator.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; -import "./IStrategy.sol"; +import { IStrategy, IERC20 } from "contracts/external/eigenlayer/interfaces/IStrategy.sol"; +import { IEigenDelegationManager } from "contracts/external/eigenlayer/interfaces/IEigenDelegationManager.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface INodeDelegator { // event @@ -9,29 +11,55 @@ interface INodeDelegator { event ETHDepositFromDepositPool(uint256 depositAmount); event EigenPodCreated(address indexed eigenPod, address indexed podOwner); event ETHStaked(bytes valPubKey, uint256 amount); - event ETHRewardsClaimed(uint256 amount); + event WithdrawalQueued(uint256 nonce, address withdrawer, bytes32[] withdrawalRoots); + event EthTransferred(address to, uint256 amount); + event EigenLayerWithdrawalCompleted(address indexed depositor, uint256 nonce, address indexed caller); + event ETHRewardsReceived(uint256 amount); + event ETHExtraStakeToReceiveIncremented(uint256 amount); + event ExtraStakeReceived(uint256 amount); event ETHRewardsWithdrawInitiated(uint256 amount); + event ElSharesDelegated(address indexed elOperator); + event RestakingActivated(); + event ETHReceived(address indexed sender, uint256 amount); + event Undelegated(); // errors error TokenTransferFailed(); error StrategyIsNotSetForAsset(); error InvalidETHSender(); - error InvalidRewardAmount(); error InvalidDepositRoot(bytes32 expectedDepositRoot, bytes32 actualDepositRoot); + error StrategyMustNotBeBeaconChain(); + error InsufficientStakedButUnverifiedNativeETH(); + error InvalidWithdrawalData(); // getter - function stakedButUnverifiedNativeETH() external view returns (uint256); - // methods + // write functions function depositAssetIntoStrategy(address asset) external; - function maxApproveToEigenStrategyManager(address asset) external; + function initiateUnstaking( + IStrategy[] calldata strategies, + uint256[] calldata shares + ) + external + returns (bytes32 withdrawalRoot); + + function completeUnstaking( + IEigenDelegationManager.Withdrawal calldata withdrawal, + IERC20[] calldata assets, + uint256 middlewareTimesIndex + ) + external; + // view functions function getAssetBalances() external view returns (address[] memory, uint256[] memory); function getAssetBalance(address asset) external view returns (uint256); + function getETHEigenPodBalance() external view returns (uint256); + function transferBackToLRTDepositPool(address asset, uint256 amount) external; + function sendETHFromDepositPoolToNDC() external payable; } diff --git a/contracts/oracles/ChainlinkPriceOracle.sol b/contracts/oracles/ChainlinkPriceOracle.sol index 0e2f82f..21a8ab9 100644 --- a/contracts/oracles/ChainlinkPriceOracle.sol +++ b/contracts/oracles/ChainlinkPriceOracle.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import { UtilLib } from "../utils/UtilLib.sol"; diff --git a/contracts/oracles/EthXPriceOracle.sol b/contracts/oracles/EthXPriceOracle.sol index 287b5d3..98c2cb4 100644 --- a/contracts/oracles/EthXPriceOracle.sol +++ b/contracts/oracles/EthXPriceOracle.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import { UtilLib } from "../utils/UtilLib.sol"; @@ -17,7 +17,9 @@ interface IStaderConfig { /// @title EthXPriceOracle Contract /// @notice contract that fetches the exchange rate of ETHX/ETH contract EthXPriceOracle is IPriceFetcher, Initializable { + /// @dev deprecated address public ethXStakePoolsManagerProxyAddress; + address public ethxAddress; error InvalidAsset(); @@ -33,13 +35,16 @@ contract EthXPriceOracle is IPriceFetcher, Initializable { ethXStakePoolsManagerProxyAddress = ethXStakePoolsManagerProxyAddress_; } + function initialize2() external reinitializer(2) { + address staderConfigProxyAddress = IETHXStakePoolsManager(ethXStakePoolsManagerProxyAddress).staderConfig(); + ethxAddress = IStaderConfig(staderConfigProxyAddress).getETHxToken(); + } + /// @notice Fetches Asset/ETH exchange rate /// @param asset the asset for which exchange rate is required /// @return assetPrice exchange rate of asset function getAssetPrice(address asset) external view returns (uint256) { - address staderConfigProxyAddress = IETHXStakePoolsManager(ethXStakePoolsManagerProxyAddress).staderConfig(); - - if (asset != IStaderConfig(staderConfigProxyAddress).getETHxToken()) { + if (asset != ethxAddress) { revert InvalidAsset(); } diff --git a/contracts/oracles/OneETHPriceOracle.sol b/contracts/oracles/OneETHPriceOracle.sol index 6469695..b3c6e7e 100644 --- a/contracts/oracles/OneETHPriceOracle.sol +++ b/contracts/oracles/OneETHPriceOracle.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; -import { UtilLib } from "../utils/UtilLib.sol"; import { IPriceFetcher } from "../interfaces/IPriceFetcher.sol"; /// @title OneETHPriceOracle Contract diff --git a/contracts/oracles/RETHPriceOracle.sol b/contracts/oracles/RETHPriceOracle.sol new file mode 100644 index 0000000..ba17ead --- /dev/null +++ b/contracts/oracles/RETHPriceOracle.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { UtilLib } from "../utils/UtilLib.sol"; +import { IPriceFetcher } from "../interfaces/IPriceFetcher.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +interface IrETH { + function getExchangeRate() external view returns (uint256); +} + +/// @title RETHPriceOracle Contract +/// @notice contract that fetches the exchange rate of RETH/ETH +contract RETHPriceOracle is IPriceFetcher, Initializable { + address public rETHAddress; + + error InvalidAsset(); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initializes the contract + /// @param rETHAddress_ RETH address + function initialize(address rETHAddress_) external initializer { + UtilLib.checkNonZeroAddress(rETHAddress_); + rETHAddress = rETHAddress_; + } + + /// @notice Fetches Asset/ETH exchange rate + /// @param asset the asset for which exchange rate is required + /// @return assetPrice exchange rate of asset + function getAssetPrice(address asset) external view returns (uint256) { + if (asset != rETHAddress) { + revert InvalidAsset(); + } + + return IrETH(rETHAddress).getExchangeRate(); + } +} diff --git a/contracts/oracles/SfrxETHPriceOracle.sol b/contracts/oracles/SfrxETHPriceOracle.sol index 37e6b4f..82c43a3 100644 --- a/contracts/oracles/SfrxETHPriceOracle.sol +++ b/contracts/oracles/SfrxETHPriceOracle.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.8.21; import { UtilLib } from "../utils/UtilLib.sol"; diff --git a/contracts/oracles/SwETHPriceOracle.sol b/contracts/oracles/SwETHPriceOracle.sol new file mode 100644 index 0000000..3d3c627 --- /dev/null +++ b/contracts/oracles/SwETHPriceOracle.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { UtilLib } from "../utils/UtilLib.sol"; +import { IPriceFetcher } from "../interfaces/IPriceFetcher.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +interface ISwETH { + function getRate() external view returns (uint256); +} + +/// @title SwETHPriceOracle Contract +/// @notice contract that fetches the exchange rate of SwETH/ETH +contract SwETHPriceOracle is IPriceFetcher, Initializable { + address public swETHAddress; + + error InvalidAsset(); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initializes the contract + /// @param swETHAddress_ SwETH address + function initialize(address swETHAddress_) external initializer { + UtilLib.checkNonZeroAddress(swETHAddress_); + swETHAddress = swETHAddress_; + } + + /// @notice Fetches Asset/ETH exchange rate + /// @param asset the asset for which exchange rate is required + /// @return assetPrice exchange rate of asset + function getAssetPrice(address asset) external view returns (uint256) { + if (asset != swETHAddress) { + revert InvalidAsset(); + } + + return ISwETH(swETHAddress).getRate(); + } +} diff --git a/contracts/pools/RSETHPool.sol b/contracts/pools/RSETHPool.sol new file mode 100644 index 0000000..ebc9dbf --- /dev/null +++ b/contracts/pools/RSETHPool.sol @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { + ERC20Upgradeable, IERC20Upgradeable +} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; + +import { UtilLib } from "../utils/UtilLib.sol"; + +interface IOracle { + function getRate() external view returns (uint256); +} + +interface AggregatorV3Interface { + function decimals() external view returns (uint8); + + function latestRoundData() + external + view + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); +} + +contract RSETHPool is ERC20Upgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable { + IERC20Upgradeable public rsETH; + IERC20Upgradeable public wstETH; + uint256 public feeBps; // Basis points for fees + uint256 public feeEarnedInETH; + uint256 public feeEarnedInWstETH; + address public rsETHOracle; + address public wstETH_ETHOracle; + + bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); + + error InvalidAmount(); + error TransferFailed(); + + event SwapOccurred(address indexed user, uint256 rsETHAmount, uint256 fee, string referralId); + event FeesWithdrawn(uint256 feeEarnedInETH, uint256 feeEarnedInWstETH); + event CollectedAssetsWithdrawn(uint256 wwstETHBalanceMinusFees, uint256 ethBalanceMinusFees); + event FeeBpsSet(uint256 feeBps); + event OracleSet(address oracle); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initialize the contract + /// @param admin The admin address + /// @param manager The manager address + /// @param _rsETH The rsETH token address + /// @param _wstETH The wstETH token address + /// @param _feeBps The fee basis points + /// @param _rsETHOracle The rsETHOracle address + /// @param _wstETH_ETHOracle oracle address for wstETH/ETH + function initialize( + address admin, + address manager, + address _rsETH, + address _wstETH, + uint256 _feeBps, + address _rsETHOracle, + address _wstETH_ETHOracle + ) + public + initializer + { + UtilLib.checkNonZeroAddress(_rsETH); + UtilLib.checkNonZeroAddress(_wstETH); + + __ERC20_init("rsETH", "rsETH"); + __AccessControl_init(); + __ReentrancyGuard_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _setupRole(MANAGER_ROLE, admin); + _setupRole(MANAGER_ROLE, manager); + + rsETH = IERC20Upgradeable(_rsETH); + wstETH = IERC20Upgradeable(_wstETH); + feeBps = _feeBps; + rsETHOracle = _rsETHOracle; + wstETH_ETHOracle = _wstETH_ETHOracle; + } + + /// @dev Gets the rate from the rsETHOracle + function getRate() public view returns (uint256) { + return IOracle(rsETHOracle).getRate(); + } + + /// @dev Swaps ETH or wstETH for rsETH + /// @param wstETHAmount The amount of wstETH to swap for rsETH. Use 0 if swapping ETH for rsETH + function swapToRsETH(uint256 wstETHAmount, string calldata referralId) external payable nonReentrant { + bool isWstETH; + uint256 amount; + + if (wstETHAmount > 0) { + if (msg.value > 0) revert InvalidAmount(); // cannot send both wstETH and ETH + isWstETH = true; + amount = wstETHAmount; + wstETH.transferFrom(msg.sender, address(this), wstETHAmount); + } else { + if (msg.value == 0) revert InvalidAmount(); + amount = msg.value; + } + + (uint256 rsETHAmount, uint256 fee) = viewSwapRsETHAmountAndFee(amount, isWstETH); + + if (isWstETH) { + feeEarnedInWstETH += fee; + } else { + feeEarnedInETH += fee; + } + + rsETH.transfer(msg.sender, rsETHAmount); + + emit SwapOccurred(msg.sender, rsETHAmount, fee, referralId); + } + + /// @dev view function to get the rsETH amount for a given amount of wstETH or ETH + /// @param amount The amount of wstETH or ETH + /// @param isWstETH True if the amount is in wstETH, false if it is in ETH + /// @return rsETHAmount The amount of rsETH that will be received + /// @return fee The fee that will be charged + function viewSwapRsETHAmountAndFee( + uint256 amount, + bool isWstETH + ) + public + view + returns (uint256 rsETHAmount, uint256 fee) + { + fee = amount * feeBps / 10_000; + uint256 amountAfterFee = amount - fee; + + if (isWstETH) { + // Adjust for wstETH to ETH conversion using the oracle + (, int256 ETHPrice,,,) = AggregatorV3Interface(wstETH_ETHOracle).latestRoundData(); + + uint256 normalizedPriceForDecimalsUnit = + uint256(ETHPrice) * 1e18 / 10 ** uint256(AggregatorV3Interface(wstETH_ETHOracle).decimals()); + + amountAfterFee = amountAfterFee * normalizedPriceForDecimalsUnit / 1e18; + } + + // rate of rsETH in ETH + uint256 rsETHToETHrate = getRate(); + + // Calculate the final rsETH amount + rsETHAmount = amountAfterFee * 1e18 / rsETHToETHrate; + } + + /*////////////////////////////////////////////////////////////// + ACCESS RESTRICTED FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Withdraws fees earned by the pool + function withdrawFees(address receiver) external onlyRole(MANAGER_ROLE) { + // withdraw fees in ETH + uint256 amountToSendInETH = feeEarnedInETH; + feeEarnedInETH = 0; + (bool success,) = payable(receiver).call{ value: amountToSendInETH }(""); + if (!success) revert TransferFailed(); + + // withdraw fees in wstETH + uint256 amountToSendInWSETH = feeEarnedInWstETH; + feeEarnedInWstETH = 0; + wstETH.transfer(receiver, amountToSendInWSETH); + + emit FeesWithdrawn(amountToSendInETH, amountToSendInWSETH); + } + + /// @dev Withdraws collected assets by the pool + function withdrawCollectedAssets(address receiver) external onlyRole(MANAGER_ROLE) { + // withdraw wstETH - fees + uint256 wstETHBalanceMinusFees = wstETH.balanceOf(address(this)) - feeEarnedInWstETH; + + wstETH.transfer(receiver, wstETHBalanceMinusFees); + + // withdraw ETH - fees + uint256 ethBalanceMinusFees = address(this).balance - feeEarnedInETH; + + (bool success,) = payable(receiver).call{ value: ethBalanceMinusFees }(""); + if (!success) revert TransferFailed(); + + emit CollectedAssetsWithdrawn(wstETHBalanceMinusFees, ethBalanceMinusFees); + } + + /// @dev withdraw rsETH from the pool + /// @dev This function is only callable by the manager + /// @param receiver The address to receive the rsETH + /// @param amount The amount of rsETH to withdraw + function withdrawRsETH(address receiver, uint256 amount) external onlyRole(MANAGER_ROLE) { + rsETH.transfer(receiver, amount); + } + + /// @dev Sets the fee basis points + /// @param _feeBps The fee basis points + function setFeeBps(uint256 _feeBps) external onlyRole(MANAGER_ROLE) { + if (_feeBps > 10_000) revert InvalidAmount(); + + feeBps = _feeBps; + + emit FeeBpsSet(_feeBps); + } + + /// @dev Sets the rsETHOracle address + /// @param _rsETHOracle The rsETHOracle address + function setRSETHOracle(address _rsETHOracle) external onlyRole(MANAGER_ROLE) { + UtilLib.checkNonZeroAddress(_rsETHOracle); + + rsETHOracle = _rsETHOracle; + + emit OracleSet(_rsETHOracle); + } + + /// @dev Sets the wstETH_ETHOracle address + /// @param _wstETH_ETHOracle The wstETH_ETHOracle address + function setWstETH_ETHOracle(address _wstETH_ETHOracle) external onlyRole(MANAGER_ROLE) { + UtilLib.checkNonZeroAddress(_wstETH_ETHOracle); + + wstETH_ETHOracle = _wstETH_ETHOracle; + + emit OracleSet(_wstETH_ETHOracle); + } +} diff --git a/contracts/pools/RSETHPoolV2.sol b/contracts/pools/RSETHPoolV2.sol new file mode 100644 index 0000000..5b5091a --- /dev/null +++ b/contracts/pools/RSETHPoolV2.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { + ERC20Upgradeable, IERC20Upgradeable +} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; + +import { UtilLib } from "../utils/UtilLib.sol"; + +interface IOracle { + function getRate() external view returns (uint256); +} + +interface IERC20WstETH is IERC20Upgradeable { + function mint(address to, uint256 amount) external; +} + +contract RSETHPoolV2 is ERC20Upgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable { + IERC20WstETH public wrsETH; + uint256 public feeBps; // Basis points for fees + uint256 public feeEarnedInETH; + address public rsETHOracle; + + bytes32 public constant BRIDGER_ROLE = keccak256("BRIDGER_ROLE"); + + error InvalidAmount(); + error TransferFailed(); + + event SwapOccurred(address indexed user, uint256 rsETHAmount, uint256 fee, string referralId); + event FeesWithdrawn(uint256 feeEarnedInETH); + event AssetsMovedForBridging(uint256 ethBalanceMinusFees); + event FeeBpsSet(uint256 feeBps); + event OracleSet(address oracle); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initialize the contract + /// @param admin The admin address + /// @param bridger The bridger address + /// @param _wrsETH The rsETH token address + /// @param _feeBps The fee basis points + /// @param _rsETHOracle The rsETHOracle address + function initialize( + address admin, + address bridger, + address _wrsETH, + uint256 _feeBps, + address _rsETHOracle + ) + public + initializer + { + UtilLib.checkNonZeroAddress(_wrsETH); + UtilLib.checkNonZeroAddress(_rsETHOracle); + + __ERC20_init("rsETH", "rsETH"); + __AccessControl_init(); + __ReentrancyGuard_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _setupRole(BRIDGER_ROLE, admin); + _setupRole(BRIDGER_ROLE, bridger); + + wrsETH = IERC20WstETH(_wrsETH); + feeBps = _feeBps; + rsETHOracle = _rsETHOracle; + } + + /// @dev Gets the rate from the rsETHOracle + function getRate() public view returns (uint256) { + return IOracle(rsETHOracle).getRate(); + } + + /// @dev Swaps ETH for rsETH + /// @param referralId The referral id + function deposit(string memory referralId) external payable nonReentrant { + uint256 amount = msg.value; + + if (amount == 0) revert InvalidAmount(); + + (uint256 rsETHAmount, uint256 fee) = viewSwapRsETHAmountAndFee(amount); + + feeEarnedInETH += fee; + + wrsETH.mint(msg.sender, rsETHAmount); + + emit SwapOccurred(msg.sender, rsETHAmount, fee, referralId); + } + + /// @dev view function to get the rsETH amount for a given amount of ETH + /// @param amount The amount of ETH + /// @return rsETHAmount The amount of rsETH that will be received + /// @return fee The fee that will be charged + function viewSwapRsETHAmountAndFee(uint256 amount) public view returns (uint256 rsETHAmount, uint256 fee) { + fee = amount * feeBps / 10_000; + uint256 amountAfterFee = amount - fee; + + // rate of rsETH in ETH + uint256 rsETHToETHrate = getRate(); + + // Calculate the final rsETH amount + rsETHAmount = amountAfterFee * 1e18 / rsETHToETHrate; + } + + /*////////////////////////////////////////////////////////////// + ACCESS RESTRICTED FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Withdraws fees earned by the pool + function withdrawFees(address receiver) external onlyRole(BRIDGER_ROLE) { + // withdraw fees in ETH + uint256 amountToSendInETH = feeEarnedInETH; + feeEarnedInETH = 0; + (bool success,) = payable(receiver).call{ value: amountToSendInETH }(""); + if (!success) revert TransferFailed(); + + emit FeesWithdrawn(amountToSendInETH); + } + + /// @dev Withdraws assets from the contract for bridging + function moveAssetsForBridging() external onlyRole(BRIDGER_ROLE) { + // withdraw ETH - fees + uint256 ethBalanceMinusFees = address(this).balance - feeEarnedInETH; + + (bool success,) = msg.sender.call{ value: ethBalanceMinusFees }(""); + if (!success) revert TransferFailed(); + + emit AssetsMovedForBridging(ethBalanceMinusFees); + } + + /// @dev Sets the fee basis points + /// @param _feeBps The fee basis points + function setFeeBps(uint256 _feeBps) external onlyRole(DEFAULT_ADMIN_ROLE) { + if (_feeBps > 10_000) revert InvalidAmount(); + + feeBps = _feeBps; + + emit FeeBpsSet(_feeBps); + } + + /// @dev Sets the rsETHOracle address + /// @param _rsETHOracle The rsETHOracle address + function setRSETHOracle(address _rsETHOracle) external onlyRole(DEFAULT_ADMIN_ROLE) { + UtilLib.checkNonZeroAddress(_rsETHOracle); + + rsETHOracle = _rsETHOracle; + + emit OracleSet(_rsETHOracle); + } +} diff --git a/contracts/pools/RSETHPoolV3.sol b/contracts/pools/RSETHPoolV3.sol new file mode 100644 index 0000000..924302e --- /dev/null +++ b/contracts/pools/RSETHPoolV3.sol @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { + ERC20Upgradeable, IERC20Upgradeable +} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { UtilLib } from "../utils/UtilLib.sol"; + +interface IOracle { + function getRate() external view returns (uint256); +} + +interface IERC20WstETH is IERC20Upgradeable { + function mint(address to, uint256 amount) external; +} + +contract RSETHPoolV3 is ERC20Upgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable { + using SafeERC20 for IERC20; + + IERC20WstETH public wrsETH; + uint256 public feeBps; // Basis points for fees + uint256 public feeEarnedInETH; + address public rsETHOracle; + + bytes32 public constant BRIDGER_ROLE = keccak256("BRIDGER_ROLE"); + + bool public isEthDepositEnabled; + mapping(address token => uint256 feeEarned) public feeEarnedInToken; + mapping(address token => address oracle) public supportedTokenOracle; + address[] public supportedTokenList; + + error InvalidAmount(); + error TransferFailed(); + error UnsupportedToken(); + error UnsupportedOracle(); + error AlreadySupportedToken(); + error TokenNotFoundError(); + error EthDepositDisabled(); + + event SwapOccurred(address indexed user, uint256 rsETHAmount, uint256 fee, string referralId); + event FeesWithdrawn(uint256 feeEarnedInETH); + event FeesWithdrawn(uint256 feeEarnedInETH, address token); + event AssetsMovedForBridging(uint256 ethBalanceMinusFees); + event AssetsMovedForBridging(uint256 tokenBalanceMinusFees, address token); + event FeeBpsSet(uint256 feeBps); + event OracleSet(address oracle); + event AddSupportedToken(address token); + event RemovedSupportedToken(address token); + event IsEthDepositEnabled(bool isEthDepositEnabled); + + modifier onlySupportedToken(address token) { + if (supportedTokenOracle[token] == address(0)) revert UnsupportedToken(); + _; + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initialize the contract + /// @param admin The admin address + /// @param bridger The bridger address + /// @param _wrsETH The rsETH token address + /// @param _feeBps The fee basis points + /// @param _rsETHOracle The rsETHOracle address + function initialize( + address admin, + address bridger, + address _wrsETH, + uint256 _feeBps, + address _rsETHOracle + ) + public + initializer + { + UtilLib.checkNonZeroAddress(_wrsETH); + UtilLib.checkNonZeroAddress(_rsETHOracle); + + __ERC20_init("rsETH", "rsETH"); + __AccessControl_init(); + __ReentrancyGuard_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _setupRole(BRIDGER_ROLE, admin); + _setupRole(BRIDGER_ROLE, bridger); + + wrsETH = IERC20WstETH(_wrsETH); + feeBps = _feeBps; + rsETHOracle = _rsETHOracle; + isEthDepositEnabled = true; + } + + /// @dev Gets the rate from the rsETHOracle + function getRate() public view returns (uint256) { + return IOracle(rsETHOracle).getRate(); + } + + /// @dev Returns the list of supported tokens + function getSupportedTokens() external view returns (address[] memory) { + return supportedTokenList; + } + + /// @dev Swaps ETH for rsETH + /// @param referralId The referral id + function deposit(string memory referralId) external payable nonReentrant { + if (!isEthDepositEnabled) revert EthDepositDisabled(); + uint256 amount = msg.value; + + if (amount == 0) revert InvalidAmount(); + + (uint256 rsETHAmount, uint256 fee) = viewSwapRsETHAmountAndFee(amount); + + feeEarnedInETH += fee; + + wrsETH.mint(msg.sender, rsETHAmount); + + emit SwapOccurred(msg.sender, rsETHAmount, fee, referralId); + } + + /// @dev Swaps token for rsETH + /// @param token The token address + /// @param amount The amount of token + /// @param referralId The referral id + function deposit( + address token, + uint256 amount, + string memory referralId + ) + external + nonReentrant + onlySupportedToken(token) + { + if (amount == 0) revert InvalidAmount(); + + IERC20(token).safeTransferFrom(msg.sender, address(this), amount); + + (uint256 rsETHAmount, uint256 fee) = viewSwapRsETHAmountAndFee(amount, token); + + feeEarnedInToken[token] += fee; + + wrsETH.mint(msg.sender, rsETHAmount); + + emit SwapOccurred(msg.sender, rsETHAmount, fee, referralId); // Add token address? + } + + /// @dev view function to get the rsETH amount for a given amount of ETH + /// @param amount The amount of ETH + /// @return rsETHAmount The amount of rsETH that will be received + /// @return fee The fee that will be charged + function viewSwapRsETHAmountAndFee(uint256 amount) public view returns (uint256 rsETHAmount, uint256 fee) { + fee = amount * feeBps / 10_000; + uint256 amountAfterFee = amount - fee; + + // rate of rsETH in ETH + uint256 rsETHToETHrate = getRate(); + + // Calculate the final rsETH amount + rsETHAmount = amountAfterFee * 1e18 / rsETHToETHrate; + } + + /// @dev view function to get the rsETH amount for a given amount of token + /// @param amount The amount of token + /// @return rsETHAmount The amount of rsETH that will be received + /// @return fee The fee that will be charged + function viewSwapRsETHAmountAndFee( + uint256 amount, + address token + ) + public + view + onlySupportedToken(token) + returns (uint256 rsETHAmount, uint256 fee) + { + fee = amount * feeBps / 10_000; + uint256 amountAfterFee = amount - fee; + + // rate of rsETH in ETH + uint256 rsETHToETHrate = getRate(); + + // rate of token in ETH + uint256 tokenToETHRate = IOracle(supportedTokenOracle[token]).getRate(); + + // Calculate the final rsETH amount + rsETHAmount = amountAfterFee * tokenToETHRate / rsETHToETHrate; + } + + /*////////////////////////////////////////////////////////////// + ACCESS RESTRICTED FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @dev Withdraws fees earned by the pool + function withdrawFees(address receiver) external onlyRole(BRIDGER_ROLE) { + // withdraw fees in ETH + uint256 amountToSendInETH = feeEarnedInETH; + feeEarnedInETH = 0; + (bool success,) = payable(receiver).call{ value: amountToSendInETH }(""); + if (!success) revert TransferFailed(); + + emit FeesWithdrawn(amountToSendInETH); + } + + /// @dev Withdraws fees earned by the pool + function withdrawFees(address receiver, address token) external onlySupportedToken(token) onlyRole(BRIDGER_ROLE) { + // withdraw fees in ETH + uint256 amountToSendInToken = feeEarnedInToken[token]; + feeEarnedInToken[token] = 0; + IERC20(token).safeTransfer(receiver, amountToSendInToken); + + emit FeesWithdrawn(amountToSendInToken, token); + } + + /// @dev Withdraws assets from the contract for bridging + function moveAssetsForBridging() external onlyRole(BRIDGER_ROLE) { + // withdraw ETH - fees + uint256 ethBalanceMinusFees = address(this).balance - feeEarnedInETH; + + (bool success,) = msg.sender.call{ value: ethBalanceMinusFees }(""); + if (!success) revert TransferFailed(); + + emit AssetsMovedForBridging(ethBalanceMinusFees); + } + + /// @dev Withdraws assets from the contract for bridging + function moveAssetsForBridging(address token) external onlySupportedToken(token) onlyRole(BRIDGER_ROLE) { + // withdraw token - fees + uint256 tokenBalanceMinusFees = IERC20(token).balanceOf(address(this)) - feeEarnedInToken[token]; + + IERC20(token).safeTransfer(msg.sender, tokenBalanceMinusFees); + + emit AssetsMovedForBridging(tokenBalanceMinusFees, token); + } + + /// @dev Sets the fee basis points + /// @param _feeBps The fee basis points + function setFeeBps(uint256 _feeBps) external onlyRole(DEFAULT_ADMIN_ROLE) { + if (_feeBps > 10_000) revert InvalidAmount(); + + feeBps = _feeBps; + + emit FeeBpsSet(_feeBps); + } + + /// @dev Sets the isEthDepositEnabled flag + /// @param _isEthDepositEnabled The isEthDepositEnabled flag + function setIsEthDepositEnabled(bool _isEthDepositEnabled) external onlyRole(DEFAULT_ADMIN_ROLE) { + isEthDepositEnabled = _isEthDepositEnabled; + emit IsEthDepositEnabled(_isEthDepositEnabled); + } + + /// @dev Sets the rsETHOracle address + /// @param _rsETHOracle The rsETHOracle address + function setRSETHOracle(address _rsETHOracle) external onlyRole(DEFAULT_ADMIN_ROLE) { + UtilLib.checkNonZeroAddress(_rsETHOracle); + + rsETHOracle = _rsETHOracle; + + emit OracleSet(_rsETHOracle); + } + + /// @dev Adds a supported token + /// @param token The token address + function addSupportedToken(address token, address oracle) external onlyRole(DEFAULT_ADMIN_ROLE) { + UtilLib.checkNonZeroAddress(token); + UtilLib.checkNonZeroAddress(oracle); + + if (supportedTokenOracle[token] != address(0)) { + revert AlreadySupportedToken(); + } + if (IOracle(rsETHOracle).getRate() == 0) { + revert UnsupportedOracle(); + } + supportedTokenList.push(token); + supportedTokenOracle[token] = oracle; + + emit AddSupportedToken(token); + } + + /// @dev Removes a supported token + /// @param token The token address + function removeSupportedToken(address token, uint256 tokenIndex) external onlyRole(DEFAULT_ADMIN_ROLE) { + UtilLib.checkNonZeroAddress(token); + if (supportedTokenList[tokenIndex] != token) { + revert TokenNotFoundError(); + } + delete supportedTokenOracle[token]; + supportedTokenList[tokenIndex] = supportedTokenList[supportedTokenList.length - 1]; + supportedTokenList.pop(); + emit RemovedSupportedToken(token); + } +} diff --git a/contracts/pools/oracle/WETHOracle.sol b/contracts/pools/oracle/WETHOracle.sol new file mode 100644 index 0000000..d3a163e --- /dev/null +++ b/contracts/pools/oracle/WETHOracle.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +/// @title WETHOracle Contract +/// @notice contract that returns 1e18 as the exchange rate of WETH/ETH +contract WETHOracle { + function getRate() external pure returns (uint256) { + return 1e18; + } + + function rate() external pure returns (uint256) { + return 1e18; + } +} diff --git a/contracts/unstaking-adapters/UnstakeStETH.sol b/contracts/unstaking-adapters/UnstakeStETH.sol new file mode 100644 index 0000000..b26bc26 --- /dev/null +++ b/contracts/unstaking-adapters/UnstakeStETH.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +interface ILidoWithdrawalQueue { + function requestWithdrawals( + uint256[] calldata _amounts, + address _owner + ) + external + returns (uint256[] memory requestIds); + + /// Usage: findCheckpointHints(_requestIds, 1, getLastCheckpointIndex()) + function findCheckpointHints( + uint256[] calldata _requestIds, + uint256 _firstIndex, + uint256 _lastIndex + ) + external + view + returns (uint256[] memory hintIds); + + function getLastCheckpointIndex() external view returns (uint256); + + function claimWithdrawalsTo( + uint256[] calldata _requestIds, + uint256[] calldata _hints, + address _recipient + ) + external; + function finalize(uint256 _lastRequestIdToBeFinalized, uint256 _maxShareRate) external payable; + + function getLastRequestId() external view returns (uint256); +} + +abstract contract UnstakeStETH is Initializable { + ILidoWithdrawalQueue public withdrawalQueue; + IERC20 public stETH; + + event UnstakeStETHStarted(uint256 tokenId); + + function __initializeStETH(address _withdrawalQueue, address _stETHAddress) internal onlyInitializing { + withdrawalQueue = ILidoWithdrawalQueue(_withdrawalQueue); + stETH = IERC20(_stETHAddress); + } + + function _unstakeStEth(uint256 amountToUnstake) internal { + stETH.approve(address(withdrawalQueue), amountToUnstake); + + uint256[] memory amounts = new uint256[](1); + amounts[0] = amountToUnstake; + + uint256[] memory requestIds = withdrawalQueue.requestWithdrawals(amounts, address(this)); + + emit UnstakeStETHStarted(requestIds[0]); + } + + function _claimStEth(uint256 _requestId, uint256 _hint) internal { + uint256[] memory requestIds = new uint256[](1); + uint256[] memory hints = new uint256[](1); + requestIds[0] = _requestId; + hints[0] = _hint; + withdrawalQueue.claimWithdrawalsTo(requestIds, hints, address(this)); + } +} diff --git a/contracts/unstaking-adapters/UnstakeSwETH.sol b/contracts/unstaking-adapters/UnstakeSwETH.sol new file mode 100644 index 0000000..2348ff5 --- /dev/null +++ b/contracts/unstaking-adapters/UnstakeSwETH.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +interface IswEXIT { + function getLastTokenIdCreated() external view returns (uint256); + + function createWithdrawRequest(uint256 amount) external; + function finalizeWithdrawal(uint256 tokenId) external; + function processWithdrawals(uint256 lastTokenIdToProcess) external; +} + +abstract contract UnstakeSwETH is Initializable { + IswEXIT public swEXIT; + IERC20 public swETH; + + event UnstakeSwETHStarted(uint256 tokenId); + + function __initializeSwETH(address _swEXITAddress, address _swETHAddress) internal onlyInitializing { + swEXIT = IswEXIT(_swEXITAddress); + swETH = IERC20(_swETHAddress); + } + + function _unstakeSwEth(uint256 amountToUnstake) internal returns (uint256 tokenId) { + swETH.approve(address(swEXIT), amountToUnstake); + + // Create withdrawal request + swEXIT.createWithdrawRequest(amountToUnstake); + tokenId = swEXIT.getLastTokenIdCreated(); + emit UnstakeSwETHStarted(tokenId); + } + + function _claimSwEth(uint256 _tokenId) internal { + swEXIT.finalizeWithdrawal(_tokenId); + } +} diff --git a/contracts/utils/DoubleEndedQueue.sol b/contracts/utils/DoubleEndedQueue.sol new file mode 100644 index 0000000..f636180 --- /dev/null +++ b/contracts/utils/DoubleEndedQueue.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol) +pragma solidity ^0.8.20; + +/** + * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of + * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and + * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that + * the existing queue contents are left in storage. + * + * The struct is called `Uint256Deque`. Other types can be cast to and from `uint128`. This data structure can only be + * used in storage, and not in memory. + * ```solidity + * DoubleEndedQueue.Uint256Deque queue; + * ``` + */ +library DoubleEndedQueue { + /** + * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. + */ + error QueueEmpty(); + + /** + * @dev A push operation couldn't be completed due to the queue being full. + */ + error QueueFull(); + + /** + * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. + */ + error QueueOutOfBounds(); + + /** + * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. + */ + struct Uint256Deque { + uint128 _begin; + uint128 _end; + mapping(uint128 index => uint256) _data; + } + + /** + * @dev Inserts an item at the end of the queue. + * + * Reverts with {QueueFull} if the queue is full. + */ + function pushBack(Uint256Deque storage deque, uint256 value) internal { + unchecked { + uint128 backIndex = deque._end; + if (backIndex + 1 == deque._begin) revert QueueFull(); + deque._data[backIndex] = value; + deque._end = backIndex + 1; + } + } + + /** + * @dev Removes the item at the end of the queue and returns it. + * + * Reverts with {QueueEmpty} if the queue is empty. + */ + function popBack(Uint256Deque storage deque) internal returns (uint256 value) { + unchecked { + uint128 backIndex = deque._end; + if (backIndex == deque._begin) revert QueueEmpty(); + --backIndex; + value = deque._data[backIndex]; + delete deque._data[backIndex]; + deque._end = backIndex; + } + } + + /** + * @dev Inserts an item at the beginning of the queue. + * + * Reverts with {QueueFull} if the queue is full. + */ + function pushFront(Uint256Deque storage deque, uint256 value) internal { + unchecked { + uint128 frontIndex = deque._begin - 1; + if (frontIndex == deque._end) revert QueueFull(); + deque._data[frontIndex] = value; + deque._begin = frontIndex; + } + } + + /** + * @dev Removes the item at the beginning of the queue and returns it. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function popFront(Uint256Deque storage deque) internal returns (uint256 value) { + unchecked { + uint128 frontIndex = deque._begin; + if (frontIndex == deque._end) revert QueueEmpty(); + value = deque._data[frontIndex]; + delete deque._data[frontIndex]; + deque._begin = frontIndex + 1; + } + } + + /** + * @dev Returns the item at the beginning of the queue. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function front(Uint256Deque storage deque) internal view returns (uint256 value) { + if (empty(deque)) revert QueueEmpty(); + return deque._data[deque._begin]; + } + + /** + * @dev Returns the item at the end of the queue. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function back(Uint256Deque storage deque) internal view returns (uint256 value) { + if (empty(deque)) revert QueueEmpty(); + unchecked { + return deque._data[deque._end - 1]; + } + } + + /** + * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at + * `length(deque) - 1`. + * + * Reverts with `QueueOutOfBounds` if the index is out of bounds. + */ + function at(Uint256Deque storage deque, uint256 index) internal view returns (uint256 value) { + if (index >= length(deque)) revert QueueOutOfBounds(); + // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 + unchecked { + return deque._data[deque._begin + uint128(index)]; + } + } + + /** + * @dev Resets the queue back to being empty. + * + * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses + * out on potential gas refunds. + */ + function clear(Uint256Deque storage deque) internal { + deque._begin = 0; + deque._end = 0; + } + + /** + * @dev Returns the number of items in the queue. + */ + function length(Uint256Deque storage deque) internal view returns (uint256) { + unchecked { + return uint256(deque._end - deque._begin); + } + } + + /** + * @dev Returns true if the queue is empty. + */ + function empty(Uint256Deque storage deque) internal view returns (bool) { + return deque._end == deque._begin; + } +} diff --git a/contracts/utils/LRTConfigRoleChecker.sol b/contracts/utils/LRTConfigRoleChecker.sol index cd4d336..ae64c64 100644 --- a/contracts/utils/LRTConfigRoleChecker.sol +++ b/contracts/utils/LRTConfigRoleChecker.sol @@ -7,6 +7,7 @@ import { LRTConstants } from "./LRTConstants.sol"; import { ILRTConfig } from "../interfaces/ILRTConfig.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; /// @title LRTConfigRoleChecker - LRT Config Role Checker Contract /// @notice Handles LRT config role checks diff --git a/contracts/utils/LRTConstants.sol b/contracts/utils/LRTConstants.sol index 0179b24..7f16ad4 100644 --- a/contracts/utils/LRTConstants.sol +++ b/contracts/utils/LRTConstants.sol @@ -11,15 +11,24 @@ library LRTConstants { bytes32 public constant CB_ETH_TOKEN = keccak256("CB_ETH_TOKEN"); //ETHX token bytes32 public constant ETHX_TOKEN = keccak256("ETHX_TOKEN"); + //sfrxETH + bytes32 public constant SFRX_ETH_TOKEN = keccak256("SFRX_ETH_TOKEN"); + + bytes32 public constant BEACON_CHAIN_ETH_STRATEGY = keccak256("BEACON_CHAIN_ETH_STRATEGY"); //contracts bytes32 public constant LRT_ORACLE = keccak256("LRT_ORACLE"); bytes32 public constant LRT_DEPOSIT_POOL = keccak256("LRT_DEPOSIT_POOL"); + bytes32 public constant LRT_WITHDRAW_MANAGER = keccak256("LRT_WITHDRAW_MANAGER"); + bytes32 public constant LRT_UNSTAKING_VAULT = keccak256("LRT_UNSTAKING_VAULT"); + bytes32 public constant LRT_CONVERTER = keccak256("LRT_CONVERTER"); + bytes32 public constant EIGEN_STRATEGY_MANAGER = keccak256("EIGEN_STRATEGY_MANAGER"); //Roles bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; bytes32 public constant MANAGER = keccak256("MANAGER"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); @@ -33,4 +42,12 @@ library LRTConstants { // Operator Role bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); + + // reward receiver contract + bytes32 public constant REWARD_RECEIVER = keccak256("REWARD_RECEIVER"); + + // EigenLayer Delegation Manager + bytes32 public constant EIGEN_DELEGATION_MANAGER = keccak256("EIGEN_DELEGATION_MANAGER"); + + uint256 public constant ONE_E_9 = 1e9; } diff --git a/contracts/utils/MerkleDistributor/MerkleDistributor.sol b/contracts/utils/MerkleDistributor/MerkleDistributor.sol new file mode 100644 index 0000000..c5b25b7 --- /dev/null +++ b/contracts/utils/MerkleDistributor/MerkleDistributor.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.21; + +import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; +import { MerkleProofUpgradeable } from + "@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol"; + +interface IERC20 { + function transfer(address recipient, uint256 amount) external returns (bool); +} + +interface IMerkleDistributor { + error ZeroValueProvided(); + error NoTokensToClaim(); + error AlreadyClaimed(); + error InvalidMerkleProof(); + error TransferFailed(); + + /// @dev returns the address of the token distributed by this contract. + function token() external view returns (address); + + /// @dev Returns true if the index has been marked claimed. + /// @param index The index of the claim. + /// @param account The address to check if the claim is claimed. + function isClaimed(uint256 index, address account) external view returns (bool); + + /// @dev claim the given amount of the token to the given address. Reverts if the inputs are invalid. + /// @param index The index of the claim. + /// @param account The address to send the token to. + /// @param cumulativeAmount The cumulative amount of the claim. + /// @param merkleProof The merkle proof to verify the claim. + function claim(uint256 index, address account, uint256 cumulativeAmount, bytes32[] calldata merkleProof) external; + + event Claimed(uint256 index, address account, uint256 amount); + event MerkleRootSet(uint256 index, bytes32 currentMerkleRoot); +} + +contract MerkleDistributor is IMerkleDistributor, OwnableUpgradeable, PausableUpgradeable { + address public override token; + address public protocolTreasury; + uint256 public feeInBPS; + + uint256 public currentMerkleRootIndex; + bytes32 public currentMerkleRoot; + + struct UserClaim { + uint256 lastClaimedIndex; + uint256 cumulativeAmount; + } + + mapping(address user => UserClaim userClaim) public userClaims; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + /// @dev Initializes the contract + function initialize(address token_, address _protocolTreasury, uint256 _feeInBPS) public initializer { + if (token_ == address(0) || _protocolTreasury == address(0)) { + revert ZeroValueProvided(); + } + + __Ownable_init(); + __Pausable_init(); + + token = token_; + protocolTreasury = _protocolTreasury; + feeInBPS = _feeInBPS; + } + + /// @inheritdoc IMerkleDistributor + function isClaimed(uint256 index, address account) public view override returns (bool) { + if (index == 0) revert ZeroValueProvided(); + + return userClaims[account].lastClaimedIndex >= index; + } + + /// @inheritdoc IMerkleDistributor + function claim( + uint256 index, + address account, + uint256 cumulativeAmount, + bytes32[] calldata merkleProof + ) + external + override + whenNotPaused + { + if (currentMerkleRoot == bytes32(0)) { + revert ZeroValueProvided(); + } + + if (isClaimed(index, account)) { + revert AlreadyClaimed(); + } + + // Verify the merkle proof. + bytes32 node = keccak256(abi.encodePacked(account, cumulativeAmount)); + if (!MerkleProofUpgradeable.verify(merkleProof, currentMerkleRoot, node)) { + revert InvalidMerkleProof(); + } + + // Calculate the claimable amount + uint256 claimableAmount = cumulativeAmount - userClaims[account].cumulativeAmount; + + // Ensure there is something to claim + if (claimableAmount == 0) { + revert NoTokensToClaim(); + } + + // Update user claim info, and send the token. + userClaims[account].lastClaimedIndex = index; + userClaims[account].cumulativeAmount = cumulativeAmount; + + // Send the claimable amount to the user - deducting the fee + uint256 fee = (claimableAmount * feeInBPS) / 10_000; + uint256 amountToSend = claimableAmount - fee; + + if (!IERC20(token).transfer(account, amountToSend)) { + revert TransferFailed(); + } + + // Send the fee to the protocol treasury + if (!IERC20(token).transfer(protocolTreasury, fee)) { + revert TransferFailed(); + } + + emit Claimed(index, account, claimableAmount); + } + + /*////////////////////////////////////////////////////////////// + Admin FUNCTION + //////////////////////////////////////////////////////////////*/ + + /// @dev Set the merkle root for the given index. + /// @dev only called by the owner. + /// @param _merkleRootToSet The merkle root to set. + function setMerkleRoot(bytes32 _merkleRootToSet) external onlyOwner { + if (_merkleRootToSet == bytes32(0)) { + revert ZeroValueProvided(); + } + + currentMerkleRoot = _merkleRootToSet; + + currentMerkleRootIndex++; + + emit MerkleRootSet(currentMerkleRootIndex, currentMerkleRoot); + } + + /// @dev Set the protocol treasury address. + /// @dev only called by the owner. + /// @param _protocolTreasury The address of the protocol treasury. + function setProtocolTreasury(address _protocolTreasury) external onlyOwner { + if (_protocolTreasury == address(0)) { + revert ZeroValueProvided(); + } + + protocolTreasury = _protocolTreasury; + } + + /// @dev Set the fee in BPS. + /// @dev only called by the owner. + /// @param _feeInBPS The fee in BPS. + function setFeeInBPS(uint256 _feeInBPS) external onlyOwner { + feeInBPS = _feeInBPS; + } + + /// @dev Pause the contract + function pause() external onlyOwner { + _pause(); + } + + /// @dev Unpause the contract + function unpause() external onlyOwner { + _unpause(); + } +} diff --git a/contracts/utils/MerkleDistributor/README.md b/contracts/utils/MerkleDistributor/README.md new file mode 100644 index 0000000..fce8a42 --- /dev/null +++ b/contracts/utils/MerkleDistributor/README.md @@ -0,0 +1,34 @@ +# MerkleDistributor Contract Documentation + +## Overview + +The `MerkleDistributor` contract allows users to claim ERC20 tokens based on their entitlements stored in Merkle trees. This implementation is designed to optimize the claiming process, enabling users to claim their cumulative entitlement in a single transaction, regardless of how many distribution periods have passed since their last claim. + +## Contract Functions + +### Public and External Functions + +- `token() external view returns (address)`: Returns the address of the ERC20 token distributed by this contract. +- `isClaimed(uint256 index, address account) external view returns (bool)`: Checks if the root has already been claimed by an account. +- `claim(uint256 index, address account, uint256 cumulativeAmount, bytes32[] calldata merkleProof) external`: Allows a user to claim their tokens based on a Merkle proof. If the claim is valid, the user's account is credited with the specified amount of tokens. If user already claimed tokens for the given merkle root index, the function reverts. + +### Events + +- `Claimed(uint256 index, address account, uint256 amount)`: Emitted after a successful claim. +- `MerkleRootSet(uint256 index, bytes32 merkleRoot)`: Emitted after a new Merkle root is set in the contract by the owner. + +## How to Use the Contract + +### Claiming Tokens + +To claim tokens, a user needs to provide: +- The `index` corresponding to their position in the Merkle tree. +- Their `account` address where the tokens will be sent. +- The `cumulativeAmount` representing the total amount they are entitled to claim up to the current period. +- A valid `merkleProof` proving their entitlement. + +The contract calculates the actual claimable amount by subtracting any previously claimed amount from the `cumulativeAmount`. If the claim is valid and there are tokens to claim, the specified amount is transferred to the user's account. + +### Verifying Claim Eligibility + +Users should verify their claim eligibility and the amount they can claim using the project's off-chain services or tools, which should provide the necessary merkle root index, cumulative amount, and Merkle proof required for the claim. diff --git a/contracts/utils/UtilLib.sol b/contracts/utils/UtilLib.sol index 093f1ed..82d79ac 100644 --- a/contracts/utils/UtilLib.sol +++ b/contracts/utils/UtilLib.sol @@ -11,4 +11,14 @@ library UtilLib { function checkNonZeroAddress(address address_) internal pure { if (address_ == address(0)) revert ZeroAddressNotAllowed(); } + + function getMin(uint256 a, uint256 b) internal pure returns (uint256) { + if (a < b) return a; + return b; + } + + function getMax(uint256 a, uint256 b) internal pure returns (uint256) { + if (a > b) return a; + return b; + } } diff --git a/hardhat.config.ts b/hardhat.config.ts deleted file mode 100644 index cd8c0ad..0000000 --- a/hardhat.config.ts +++ /dev/null @@ -1,49 +0,0 @@ -import "dotenv/config"; -import { HardhatUserConfig } from "hardhat/config"; -import "@typechain/hardhat"; -import "@nomicfoundation/hardhat-verify"; -import "@openzeppelin/hardhat-upgrades"; -import "@nomicfoundation/hardhat-toolbox"; -import "@nomicfoundation/hardhat-ethers"; -import "@nomicfoundation/hardhat-foundry"; - -const config: HardhatUserConfig = { - solidity: { - compilers: [ - { - version: "0.8.21", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - outputSelection: { - "*": { - "*": ["storageLayout"], - }, - }, - }, - }, - ], - }, - defaultNetwork: "goerli", - networks: { - hardhat: {}, - goerli: { - url: `https://eth-goerli.nodereal.io/v1/${process.env.API_KEY_NODE_REAL}`, - accounts: [process.env.DEPLOYER_PRIVATE_KEY ?? ""], - }, - mainnet: { - url: `https://eth-mainnet.nodereal.io/v1/${process.env.API_KEY_NODE_REAL}`, - accounts: [process.env.DEPLOYER_PRIVATE_KEY ?? ""], - }, - }, - etherscan: { - apiKey: { - goerli: `${process.env.GOERLI_ETHERSCAN_API_KEY}`, - mainnet: `${process.env.MAINNET_ETHERSCAN_API_KEY}`, - }, - }, -}; - -export default config; diff --git a/lcov.info b/lcov.info deleted file mode 100644 index 17b9f6d..0000000 --- a/lcov.info +++ /dev/null @@ -1,328 +0,0 @@ -TN: -SF:contracts/LRTConfig.sol -FN:109,LRTConfig.updateAssetStrategy -FN:127,LRTConfig.getLSTToken -FN:131,LRTConfig.getContract -FN:135,LRTConfig.getSupportedAssetList -FN:144,LRTConfig.setRSETH -FN:149,LRTConfig.setToken -FN:156,LRTConfig._setToken -FN:165,LRTConfig.setContract -FN:172,LRTConfig._setContract -FN:41,LRTConfig.initialize -FN:73,LRTConfig.addNewSupportedAsset -FN:80,LRTConfig._addNewSupportedAsset -FN:94,LRTConfig.updateAssetDepositLimit -FNDA:6,LRTConfig.updateAssetStrategy -FNDA:3,LRTConfig.getLSTToken -FNDA:16,LRTConfig.getContract -FNDA:1,LRTConfig.getSupportedAssetList -FNDA:3,LRTConfig.setRSETH -FNDA:5,LRTConfig.setToken -FNDA:10,LRTConfig._setToken -FNDA:8,LRTConfig.setContract -FNDA:7,LRTConfig._setContract -FNDA:8,LRTConfig.initialize -FNDA:4,LRTConfig.addNewSupportedAsset -FNDA:9,LRTConfig._addNewSupportedAsset -FNDA:9,LRTConfig.updateAssetDepositLimit -FNF:13 -FNH:13 -DA:51,7 -DA:52,6 -DA:53,5 -DA:54,4 -DA:55,3 -DA:57,2 -DA:58,2 -DA:59,2 -DA:60,2 -DA:61,2 -DA:62,2 -DA:63,2 -DA:65,2 -DA:67,2 -DA:74,3 -DA:81,9 -DA:82,8 -DA:83,1 -DA:85,7 -DA:86,7 -DA:87,7 -DA:88,7 -DA:102,7 -DA:103,7 -DA:117,4 -DA:118,3 -DA:119,1 -DA:121,2 -DA:128,3 -DA:132,16 -DA:136,1 -DA:145,2 -DA:146,1 -DA:150,4 -DA:157,10 -DA:158,9 -DA:159,1 -DA:161,8 -DA:162,8 -DA:166,7 -DA:173,7 -DA:174,6 -DA:175,1 -DA:177,5 -DA:178,5 -LF:45 -LH:45 -end_of_record -TN: -SF:contracts/LRTDepositPool.sol -FN:111,LRTDepositPool.depositAsset -FN:146,LRTDepositPool._mintRsETH -FN:157,LRTDepositPool.addNodeDelegatorContractToQueue -FN:178,LRTDepositPool.transferAssetToNodeDelegator -FN:197,LRTDepositPool.updateMaxNodeDelegatorCount -FN:203,LRTDepositPool.pause -FN:208,LRTDepositPool.unpause -FN:32,LRTDepositPool.initialize -FN:48,LRTDepositPool.getAssetCurrentLimit -FN:54,LRTDepositPool.getNodeDelegatorQueue -FN:63,LRTDepositPool.getAssetDistributionData -FN:87,LRTDepositPool.getRsETHAmountToMint -FNDA:7,LRTDepositPool.depositAsset -FNDA:4,LRTDepositPool._mintRsETH -FNDA:15,LRTDepositPool.addNodeDelegatorContractToQueue -FNDA:2,LRTDepositPool.transferAssetToNodeDelegator -FNDA:2,LRTDepositPool.updateMaxNodeDelegatorCount -FNDA:3,LRTDepositPool.pause -FNDA:2,LRTDepositPool.unpause -FNDA:2,LRTDepositPool.initialize -FNDA:2,LRTDepositPool.getAssetCurrentLimit -FNDA:1,LRTDepositPool.getNodeDelegatorQueue -FNDA:1,LRTDepositPool.getAssetDistributionData -FNDA:1,LRTDepositPool.getRsETHAmountToMint -FNF:12 -FNH:12 -DA:33,2 -DA:34,1 -DA:35,1 -DA:36,1 -DA:37,1 -DA:38,1 -DA:49,7 -DA:55,1 -DA:71,1 -DA:73,1 -DA:74,1 -DA:75,3 -DA:76,3 -DA:78,3 -DA:97,5 -DA:98,5 -DA:101,5 -DA:121,6 -DA:122,1 -DA:124,5 -DA:125,1 -DA:128,4 -DA:129,0 -DA:133,4 -DA:136,4 -DA:138,4 -DA:147,4 -DA:149,4 -DA:151,4 -DA:158,14 -DA:159,14 -DA:160,1 -DA:163,13 -DA:164,19 -DA:165,19 -DA:166,19 -DA:168,19 -DA:188,1 -DA:189,1 -DA:190,0 -DA:198,1 -DA:199,1 -DA:204,2 -DA:209,1 -LF:44 -LH:42 -end_of_record -TN: -SF:contracts/LRTOracle.sol -FN:105,LRTOracle.pause -FN:110,LRTOracle.unpause -FN:29,LRTOracle.initialize -FN:45,LRTOracle.getAssetPrice -FN:52,LRTOracle.getRSETHPrice -FN:91,LRTOracle.updatePriceOracleFor -FNDA:4,LRTOracle.pause -FNDA:4,LRTOracle.unpause -FNDA:4,LRTOracle.initialize -FNDA:2,LRTOracle.getAssetPrice -FNDA:2,LRTOracle.getRSETHPrice -FNDA:4,LRTOracle.updatePriceOracleFor -FNF:6 -FNH:6 -DA:30,3 -DA:31,2 -DA:33,2 -DA:34,2 -DA:46,4 -DA:53,2 -DA:54,2 -DA:56,2 -DA:57,1 -DA:60,1 -DA:61,1 -DA:63,1 -DA:64,1 -DA:66,1 -DA:67,3 -DA:68,3 -DA:70,3 -DA:71,3 -DA:73,3 -DA:74,3 -DA:77,3 -DA:81,1 -DA:99,2 -DA:100,1 -DA:101,1 -DA:106,3 -DA:111,3 -LF:27 -LH:27 -end_of_record -TN: -SF:contracts/NodeDelegator.sol -FN:121,NodeDelegator.getAssetBalance -FN:127,NodeDelegator.pause -FN:132,NodeDelegator.unpause -FN:26,NodeDelegator.initialize -FN:38,NodeDelegator.maxApproveToEigenStrategyManager -FN:51,NodeDelegator.depositAssetIntoStrategy -FN:74,NodeDelegator.transferBackToLRTDepositPool -FN:94,NodeDelegator.getAssetBalances -FNDA:1,NodeDelegator.getAssetBalance -FNDA:6,NodeDelegator.pause -FNDA:4,NodeDelegator.unpause -FNDA:4,NodeDelegator.initialize -FNDA:3,NodeDelegator.maxApproveToEigenStrategyManager -FNDA:7,NodeDelegator.depositAssetIntoStrategy -FNDA:4,NodeDelegator.transferBackToLRTDepositPool -FNDA:1,NodeDelegator.getAssetBalances -FNF:8 -FNH:8 -DA:27,3 -DA:28,2 -DA:29,2 -DA:31,2 -DA:32,2 -DA:44,1 -DA:45,1 -DA:59,4 -DA:60,4 -DA:61,4 -DA:63,4 -DA:65,4 -DA:67,4 -DA:84,1 -DA:86,1 -DA:87,0 -DA:100,1 -DA:102,1 -DA:103,1 -DA:105,1 -DA:106,1 -DA:107,1 -DA:109,1 -DA:110,2 -DA:111,2 -DA:113,2 -DA:122,1 -DA:123,1 -DA:128,5 -DA:133,3 -LF:30 -LH:29 -end_of_record -TN: -SF:contracts/RSETH.sol -FN:32,RSETH.initialize -FN:47,RSETH.mint -FN:54,RSETH.burnFrom -FN:60,RSETH.pause -FN:66,RSETH.unpause -FN:73,RSETH.updateLRTConfig -FNDA:3,RSETH.initialize -FNDA:7,RSETH.mint -FNDA:3,RSETH.burnFrom -FNDA:6,RSETH.pause -FNDA:4,RSETH.unpause -FNDA:3,RSETH.updateLRTConfig -FNF:6 -FNH:6 -DA:33,3 -DA:34,2 -DA:36,1 -DA:37,1 -DA:38,1 -DA:39,1 -DA:40,1 -DA:41,1 -DA:48,5 -DA:55,1 -DA:61,5 -DA:67,3 -DA:74,2 -DA:75,1 -DA:76,1 -LF:15 -LH:15 -end_of_record -TN: -SF:contracts/oracles/ChainlinkPriceOracle.sol -FN:27,ChainlinkPriceOracle.initialize -FN:37,ChainlinkPriceOracle.getAssetPrice -FN:45,ChainlinkPriceOracle.updatePriceFeedFor -FNDA:4,ChainlinkPriceOracle.initialize -FNDA:2,ChainlinkPriceOracle.getAssetPrice -FNDA:4,ChainlinkPriceOracle.updatePriceFeedFor -FNF:3 -FNH:3 -DA:28,3 -DA:30,2 -DA:31,2 -DA:38,1 -DA:46,2 -DA:47,1 -DA:48,1 -LF:7 -LH:7 -end_of_record -TN: -SF:contracts/utils/LRTConfigRoleChecker.sol -FN:47,LRTConfigRoleChecker.updateLRTConfig -FNDA:0,LRTConfigRoleChecker.updateLRTConfig -FNF:1 -FNH:0 -DA:48,0 -DA:49,0 -DA:50,0 -LF:3 -LH:0 -end_of_record -TN: -SF:contracts/utils/UtilLib.sol -FN:11,UtilLib.checkNonZeroAddress -FNDA:98,UtilLib.checkNonZeroAddress -FNF:1 -FNH:1 -DA:12,98 -LF:1 -LH:1 -end_of_record diff --git a/metrics.md b/metrics.md deleted file mode 100644 index 383fe43..0000000 --- a/metrics.md +++ /dev/null @@ -1,436 +0,0 @@ - -[get in touch with Consensys Diligence](https://diligence.consensys.net)
- -[[ 🌐 ](https://diligence.consensys.net) [ 📩 ](mailto:diligence@consensys.net) [ 🔥 ](https://consensys.github.io/diligence/)] -

- - - -# Solidity Metrics for 'CLI' - -## Table of contents - -- [Scope](#t-scope) - - [Source Units in Scope](#t-source-Units-in-Scope) - - [Out of Scope](#t-out-of-scope) - - [Excluded Source Units](#t-out-of-scope-excluded-source-units) - - [Duplicate Source Units](#t-out-of-scope-duplicate-source-units) - - [Doppelganger Contracts](#t-out-of-scope-doppelganger-contracts) -- [Report Overview](#t-report) - - [Risk Summary](#t-risk) - - [Source Lines](#t-source-lines) - - [Inline Documentation](#t-inline-documentation) - - [Components](#t-components) - - [Exposed Functions](#t-exposed-functions) - - [StateVariables](#t-statevariables) - - [Capabilities](#t-capabilities) - - [Dependencies](#t-package-imports) - - [Totals](#t-totals) - -## Scope - -This section lists files that are in scope for the metrics report. - -- **Project:** `'CLI'` -- **Included Files:** - - `` -- **Excluded Paths:** - - `` -- **File Limit:** `undefined` - - **Exclude File list Limit:** `undefined` - -- **Workspace Repository:** `unknown` (`undefined`@`undefined`) - -### Source Units in Scope - -Source Units Analyzed: **`17`**
-Source Units in Scope: **`17`** (**100%**) - -| Type | File | Logic Contracts | Interfaces | Lines | nLines | nSLOC | Comment Lines | Complex. Score | Capabilities | -| ---- | ------ | --------------- | ---------- | ----- | ------ | ----- | ------------- | -------------- | ------------ | -| 📝 | contracts/LRTConfig.sol | 1 | **** | 180 | 157 | 98 | 36 | 78 | **** | -| 📝 | contracts/LRTDepositPool.sol | 1 | **** | 233 | 201 | 109 | 60 | 112 | **📤Σ** | -| 📝 | contracts/LRTOracle.sol | 1 | **** | 100 | 93 | 53 | 21 | 43 | **Σ** | -| 📝 | contracts/NodeDelegator.sol | 1 | **** | 135 | 109 | 65 | 24 | 105 | **📤Σ** | -| 📝 | contracts/RSETH.sol | 1 | **** | 66 | 66 | 35 | 21 | 43 | **** | -| 🔍 | contracts/interfaces/IEigenStrategyManager.sol | **** | 1 | 29 | 22 | 4 | 20 | 5 | **** | -| 🔍 | contracts/interfaces/ILRTConfig.sol | **** | 1 | 35 | 22 | 14 | 4 | 15 | **** | -| 🔍 | contracts/interfaces/ILRTDepositPool.sol | **** | 1 | 39 | 19 | 13 | 3 | 19 | **** | -| 🔍 | contracts/interfaces/ILRTOracle.sol | **** | 1 | 12 | 9 | 4 | 3 | 7 | **** | -| 🔍 | contracts/interfaces/INodeDelegator.sol | **** | 1 | 21 | 14 | 6 | 4 | 9 | **** | -| 🔍 | contracts/interfaces/IPriceFetcher.sol | **** | 1 | 10 | 8 | 4 | 2 | 5 | **** | -| 🔍 | contracts/interfaces/IRSETH.sol | **** | 1 | 10 | 7 | 4 | 1 | 7 | **** | -| 🔍 | contracts/interfaces/IStrategy.sol | **** | 1 | 92 | 22 | 4 | 65 | 23 | **** | -| 📝🔍 | contracts/oracles/ChainlinkPriceOracle.sol | 1 | 1 | 65 | 55 | 31 | 14 | 35 | **** | -| 🎨 | contracts/utils/LRTConfigRoleChecker.sol | 1 | **** | 59 | 59 | 39 | 9 | 28 | **** | -| 📚 | contracts/utils/LRTConstants.sol | 1 | **** | 23 | 23 | 13 | 7 | 29 | **🧮** | -| 📚 | contracts/utils/UtilLib.sol | 1 | **** | 14 | 14 | 7 | 5 | 4 | **** | -| 📝📚🔍🎨 | **Totals** | **9** | **9** | **1123** | **900** | **503** | **299** | **567** | **📤🧮Σ** | - - -Legend: [➕] - - - - -#### Out of Scope - -##### Excluded Source Units - -Source Units Excluded: **`0`** - -[➕] - - - -##### Duplicate Source Units - -Duplicate Source Units Excluded: **`0`** - -[➕] - - -##### Doppelganger Contracts - -Doppelganger Contracts: **`0`** - -[➕] - - - -## Report - -### Overview - -The analysis finished with **`0`** errors and **`0`** duplicate files. - - - - - -#### Risk - -
- -
- -#### Source Lines (sloc vs. nsloc) - -
- -
- -#### Inline Documentation - -- **Comment-to-Source Ratio:** On average there are`2.14` code lines per comment (lower=better). -- **ToDo's:** `0` - -#### Components - -| 📝Contracts | 📚Libraries | 🔍Interfaces | 🎨Abstract | -| ------------- | ----------- | ------------ | ---------- | -| 6 | 2 | 9 | 1 | - -#### Exposed Functions - -This section lists functions that are explicitly declared public or payable. Please note that getter methods for public stateVars are not included. - -| 🌐Public | 💰Payable | -| ---------- | --------- | -| 87 | 0 | - -| External | Internal | Private | Pure | View | -| ---------- | -------- | ------- | ---- | ---- | -| 82 | 58 | 4 | 1 | 40 | - -#### StateVariables - -| Total | 🌐Public | -| ---------- | --------- | -| 24 | 24 | - -#### Capabilities - -| Solidity Versions observed | 🧪 Experimental Features | 💰 Can Receive Funds | 🖥 Uses Assembly | 💣 Has Destroyable Contracts | -| -------------------------- | ------------------------ | -------------------- | ---------------- | ---------------------------- | -| `0.8.21`
`>=0.5.0` | | **** | **** | **** | - -| 📤 Transfers ETH | ⚡ Low-Level Calls | 👥 DelegateCall | 🧮 Uses Hash Functions | 🔖 ECRecover | 🌀 New/Create/Create2 | -| ---------------- | ----------------- | --------------- | ---------------------- | ------------ | --------------------- | -| `yes` | **** | **** | `yes` | **** | **** | - -| ♻️ TryCatch | Σ Unchecked | -| ---------- | ----------- | -| **** | `yes` | - -#### Dependencies / External Imports - -| Dependency / Import Path | Count | -| ------------------------ | ------ | -| @openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol | 1 | -| @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol | 2 | -| @openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol | 3 | -| @openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol | 2 | -| @openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol | 1 | -| @openzeppelin/contracts/access/IAccessControl.sol | 1 | -| @openzeppelin/contracts/interfaces/IERC20.sol | 3 | -| @openzeppelin/contracts/token/ERC20/IERC20.sol | 2 | - -#### Totals - -##### Summary - -
- -
- -##### AST Node Statistics - -###### Function Calls - -
- -
- -###### Assembly Calls - -
- -
- -###### AST Total - -
- -
- -##### Inheritance Graph - -[➕] - - -##### CallGraph - -[➕] - - -###### Contract Summary - -[➕] - -____ - -Thinking about smart contract security? We can provide training, ongoing advice, and smart contract auditing. [Contact us](https://diligence.consensys.net/contact/). - - - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 9fa464f..0000000 --- a/package-lock.json +++ /dev/null @@ -1,9857 +0,0 @@ -{ - "name": "lrt", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "lrt", - "dependencies": { - "dotenv": "^16.3.1", - "solhint": "^4.0.0" - }, - "devDependencies": { - "@nomicfoundation/hardhat-foundry": "^1.1.1", - "@nomicfoundation/hardhat-toolbox": "^3.0.0", - "@openzeppelin/hardhat-upgrades": "^2.3.3", - "hardhat": "^2.18.3", - "prettier": "^3.0.3", - "solidity-code-metrics": "^0.0.25" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", - "dev": true, - "peer": true - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz", - "integrity": "sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==", - "dev": true, - "dependencies": { - "@aws-crypto/util": "^1.2.2", - "@aws-sdk/types": "^3.1.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/util": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-1.2.2.tgz", - "integrity": "sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "^3.1.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.451.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.451.0.tgz", - "integrity": "sha512-rhK+qeYwCIs+laJfWCcrYEjay2FR/9VABZJ2NRM89jV/fKqGVQR52E5DQqrI+oEIL5JHMhhnr4N4fyECMS35lw==", - "dev": true, - "dependencies": { - "@smithy/types": "^2.5.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/types/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dev": true, - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@chainsafe/as-sha256": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", - "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==", - "dev": true - }, - "node_modules/@chainsafe/persistent-merkle-tree": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", - "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", - "dev": true, - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1" - } - }, - "node_modules/@chainsafe/ssz": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", - "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", - "dev": true, - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1", - "@chainsafe/persistent-merkle-tree": "^0.4.2", - "case": "^1.6.3" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@ethereumjs/rlp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", - "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", - "dev": true, - "peer": true, - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/util": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", - "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", - "dev": true, - "peer": true, - "dependencies": { - "@ethereumjs/rlp": "^4.0.1", - "ethereum-cryptography": "^2.0.0", - "micro-ftch": "^0.3.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", - "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/curves": "1.1.0", - "@noble/hashes": "1.3.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - } - }, - "node_modules/@ethersproject/abi": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", - "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", - "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", - "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", - "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/rlp": "^5.7.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", - "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0" - } - }, - "node_modules/@ethersproject/basex": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", - "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", - "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", - "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0" - } - }, - "node_modules/@ethersproject/contracts": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", - "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", - "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/hdnode": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", - "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "node_modules/@ethersproject/json-wallets": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", - "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", - "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@ethersproject/networks": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", - "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/pbkdf2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", - "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/providers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", - "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0", - "bech32": "1.1.4", - "ws": "7.4.6" - } - }, - "node_modules/@ethersproject/providers/node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@ethersproject/random": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", - "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", - "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/sha2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", - "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", - "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "bn.js": "^5.2.1", - "elliptic": "6.5.4", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", - "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", - "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0" - } - }, - "node_modules/@ethersproject/units": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", - "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "node_modules/@ethersproject/wallet": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", - "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", - "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@ethersproject/wordlists": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", - "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", - "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true, - "peer": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@metamask/eth-sig-util": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", - "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", - "dev": true, - "dependencies": { - "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^6.2.1", - "ethjs-util": "^0.1.6", - "tweetnacl": "^1.0.3", - "tweetnacl-util": "^0.15.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@metamask/eth-sig-util/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "dev": true, - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nomicfoundation/ethereumjs-block": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", - "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "ethereum-cryptography": "0.1.3", - "ethers": "^5.7.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-block/node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, - "node_modules/@nomicfoundation/ethereumjs-blockchain": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", - "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-ethash": "3.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "abstract-level": "^1.0.3", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "level": "^8.0.0", - "lru-cache": "^5.1.1", - "memory-level": "^1.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-common": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", - "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-util": "9.0.2", - "crc-32": "^1.2.0" - } - }, - "node_modules/@nomicfoundation/ethereumjs-ethash": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", - "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "abstract-level": "^1.0.3", - "bigint-crypto-utils": "^3.0.23", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-evm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", - "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", - "dev": true, - "dependencies": { - "@ethersproject/providers": "^5.7.1", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", - "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", - "dev": true, - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-statemanager": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", - "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "ethers": "^5.7.1", - "js-sdsl": "^4.1.4" - } - }, - "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, - "node_modules/@nomicfoundation/ethereumjs-trie": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", - "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "@types/readable-stream": "^2.3.13", - "ethereum-cryptography": "0.1.3", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", - "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", - "dev": true, - "dependencies": { - "@chainsafe/ssz": "^0.9.2", - "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", - "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", - "dev": true, - "dependencies": { - "@chainsafe/ssz": "^0.10.0", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/persistent-merkle-tree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", - "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", - "dev": true, - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", - "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", - "dev": true, - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1", - "@chainsafe/persistent-merkle-tree": "^0.5.0" - } - }, - "node_modules/@nomicfoundation/ethereumjs-vm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", - "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-blockchain": "7.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-evm": "2.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-statemanager": "2.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/hardhat-chai-matchers": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.2.tgz", - "integrity": "sha512-9Wu9mRtkj0U9ohgXYFbB/RQDa+PcEdyBm2suyEtsJf3PqzZEEjLUZgWnMjlFhATMk/fp3BjmnYVPrwl+gr8oEw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/chai-as-promised": "^7.1.3", - "chai-as-promised": "^7.1.1", - "deep-eql": "^4.0.1", - "ordinal": "^1.0.3" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "chai": "^4.2.0", - "ethers": "^6.1.0", - "hardhat": "^2.9.4" - } - }, - "node_modules/@nomicfoundation/hardhat-ethers": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz", - "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==", - "dev": true, - "peer": true, - "dependencies": { - "debug": "^4.1.1", - "lodash.isequal": "^4.5.0" - }, - "peerDependencies": { - "ethers": "^6.1.0", - "hardhat": "^2.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-foundry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.1.tgz", - "integrity": "sha512-cXGCBHAiXas9Pg9MhMOpBVQCkWRYoRFG7GJJAph+sdQsfd22iRs5U5Vs9XmpGEQd1yEvYISQZMeE68Nxj65iUQ==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2" - }, - "peerDependencies": { - "hardhat": "^2.17.2" - } - }, - "node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.9.tgz", - "integrity": "sha512-OXWCv0cHpwLUO2u7bFxBna6dQtCC2Gg/aN/KtJLO7gmuuA28vgmVKYFRCDUqrbjujzgfwQ2aKyZ9Y3vSmDqS7Q==", - "dev": true, - "peer": true, - "dependencies": { - "ethereumjs-util": "^7.1.4" - }, - "peerDependencies": { - "hardhat": "^2.9.5" - } - }, - "node_modules/@nomicfoundation/hardhat-toolbox": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-3.0.0.tgz", - "integrity": "sha512-MsteDXd0UagMksqm9KvcFG6gNKYNa3GGNCy73iQ6bEasEgg2v8Qjl6XA5hjs8o5UD5A3153B6W2BIVJ8SxYUtA==", - "dev": true, - "peerDependencies": { - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-verify": "^1.0.0", - "@typechain/ethers-v6": "^0.4.0", - "@typechain/hardhat": "^8.0.0", - "@types/chai": "^4.2.0", - "@types/mocha": ">=9.1.0", - "@types/node": ">=12.0.0", - "chai": "^4.2.0", - "ethers": "^6.4.0", - "hardhat": "^2.11.0", - "hardhat-gas-reporter": "^1.0.8", - "solidity-coverage": "^0.8.1", - "ts-node": ">=8.0.0", - "typechain": "^8.2.0", - "typescript": ">=4.5.0" - } - }, - "node_modules/@nomicfoundation/hardhat-verify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-1.1.1.tgz", - "integrity": "sha512-9QsTYD7pcZaQFEA3tBb/D/oCStYDiEVDN7Dxeo/4SCyHRSm86APypxxdOMEPlGmXsAvd+p1j/dTODcpxb8aztA==", - "dev": true, - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@ethersproject/address": "^5.0.2", - "cbor": "^8.1.0", - "chalk": "^2.4.2", - "debug": "^4.1.1", - "lodash.clonedeep": "^4.5.0", - "semver": "^6.3.0", - "table": "^6.8.0", - "undici": "^5.14.0" - }, - "peerDependencies": { - "hardhat": "^2.0.4" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", - "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", - "dev": true, - "engines": { - "node": ">= 12" - }, - "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", - "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", - "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", - "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", - "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", - "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", - "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", - "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", - "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", - "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", - "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", - "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", - "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", - "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@openzeppelin/defender-admin-client": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-admin-client/-/defender-admin-client-1.52.0.tgz", - "integrity": "sha512-CKs5mMLL7+nXyugsHaAw0aPfLwFNA+vq7ftuJ3sWUKdbQRZsJ+/189HAwp2/BJC64yUbarEeWqOh3jNpaKRJLw==", - "dev": true, - "dependencies": { - "@openzeppelin/defender-base-client": "1.52.0", - "axios": "^1.4.0", - "ethers": "^5.7.2", - "lodash": "^4.17.19", - "node-fetch": "^2.6.0" - } - }, - "node_modules/@openzeppelin/defender-admin-client/node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, - "node_modules/@openzeppelin/defender-base-client": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-base-client/-/defender-base-client-1.52.0.tgz", - "integrity": "sha512-VFNu/pjVpAnFKIfuKT1cn9dRpbcO8FO8EAmVZ2XrrAsKXEWDZ3TNBtACxmj7fAu0ad/TzRkb66o5rMts7Fv7jw==", - "dev": true, - "dependencies": { - "amazon-cognito-identity-js": "^6.0.1", - "async-retry": "^1.3.3", - "axios": "^1.4.0", - "lodash": "^4.17.19", - "node-fetch": "^2.6.0" - } - }, - "node_modules/@openzeppelin/defender-sdk-base-client": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.5.0.tgz", - "integrity": "sha512-8aN4sEE15/6LctA14ADr8c6QvEzEXfAtFlxo/Ys0N6UVfp8lRAYqDOpHd4mb8dMfkRzq5izMCuMYgAjC9GFflQ==", - "dev": true, - "dependencies": { - "amazon-cognito-identity-js": "^6.3.6", - "async-retry": "^1.3.3" - } - }, - "node_modules/@openzeppelin/defender-sdk-deploy-client": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.5.0.tgz", - "integrity": "sha512-DbE4Rpa90vSN7o5/sim5qzAVVsSWkZBJ+Z9yjkc8qPRheh2dRk6oe2GhVoQfXI/04XwMb2uNvtfU1VAH8AzgaQ==", - "dev": true, - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@openzeppelin/defender-sdk-base-client": "^1.5.0", - "axios": "^1.4.0", - "lodash": "^4.17.21" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-2.4.1.tgz", - "integrity": "sha512-IF1nQ0Jbi9bUqGWAAaX6zP5CY5tgTM3jF+ipXXatPYLooFzyGbkk7wHHWzi/+9Rx64Ar7XQVtGlwVdAohMuRcw==", - "dev": true, - "dependencies": { - "@openzeppelin/defender-admin-client": "^1.52.0", - "@openzeppelin/defender-base-client": "^1.52.0", - "@openzeppelin/defender-sdk-base-client": "^1.5.0", - "@openzeppelin/defender-sdk-deploy-client": "^1.5.0", - "@openzeppelin/upgrades-core": "^1.30.1", - "chalk": "^4.1.0", - "debug": "^4.1.1", - "ethereumjs-util": "^7.1.5", - "proper-lockfile": "^4.1.1", - "undici": "^5.14.0" - }, - "bin": { - "migrate-oz-cli-project": "dist/scripts/migrate-oz-cli-project.js" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@nomicfoundation/hardhat-verify": "^1.1.0", - "ethers": "^6.6.0", - "hardhat": "^2.0.2" - }, - "peerDependenciesMeta": { - "@nomicfoundation/hardhat-verify": { - "optional": true - } - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/hardhat-upgrades/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/upgrades-core": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.31.1.tgz", - "integrity": "sha512-BdkTZwvBxgZ9BYYfhOhuivmqZLOZ/bm6mK5eEDZ36I3Fy64a9BDL/NusaDV5XAoGn4La/j9dZSbTtgP/6d8jAQ==", - "dev": true, - "dependencies": { - "cbor": "^9.0.0", - "chalk": "^4.1.0", - "compare-versions": "^6.0.0", - "debug": "^4.1.1", - "ethereumjs-util": "^7.0.3", - "minimist": "^1.2.7", - "proper-lockfile": "^4.1.1", - "solidity-ast": "^0.4.51" - }, - "bin": { - "openzeppelin-upgrades-core": "dist/cli/cli.js" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/cbor": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.1.tgz", - "integrity": "sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==", - "dev": true, - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@openzeppelin/upgrades-core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", - "dependencies": { - "graceful-fs": "4.2.10" - }, - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/@pnpm/npm-conf": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", - "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", - "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@scure/base": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", - "integrity": "sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==", - "dev": true, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", - "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/curves": "~1.1.0", - "@noble/hashes": "~1.3.1", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", - "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@sentry/core": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", - "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", - "dev": true, - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/hub": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", - "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", - "dev": true, - "dependencies": { - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/minimal": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", - "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", - "dev": true, - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/node": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", - "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", - "dev": true, - "dependencies": { - "@sentry/core": "5.30.0", - "@sentry/hub": "5.30.0", - "@sentry/tracing": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/tracing": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", - "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", - "dev": true, - "dependencies": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", - "dev": true, - "dependencies": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@sindresorhus/is": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@smithy/types": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.6.0.tgz", - "integrity": "sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/types/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/@solidity-parser/parser": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", - "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", - "dev": true, - "peer": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "dependencies": { - "defer-to-connect": "^2.0.1" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true, - "peer": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "peer": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "peer": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "peer": true - }, - "node_modules/@typechain/ethers-v6": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.4.3.tgz", - "integrity": "sha512-TrxBsyb4ryhaY9keP6RzhFCviWYApcLCIRMPyWaKp2cZZrfaM3QBoxXTnw/eO4+DAY3l+8O0brNW0WgeQeOiDA==", - "dev": true, - "peer": true, - "dependencies": { - "lodash": "^4.17.15", - "ts-essentials": "^7.0.1" - }, - "peerDependencies": { - "ethers": "6.x", - "typechain": "^8.3.1", - "typescript": ">=4.7.0" - } - }, - "node_modules/@typechain/hardhat": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-8.0.3.tgz", - "integrity": "sha512-MytSmJJn+gs7Mqrpt/gWkTCOpOQ6ZDfRrRT2gtZL0rfGe4QrU4x9ZdW15fFbVM/XTa+5EsKiOMYXhRABibNeng==", - "dev": true, - "peer": true, - "dependencies": { - "fs-extra": "^9.1.0" - }, - "peerDependencies": { - "@typechain/ethers-v6": "^0.4.3", - "ethers": "^6.1.0", - "hardhat": "^2.9.9", - "typechain": "^8.3.1" - } - }, - "node_modules/@types/bn.js": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", - "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/chai": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", - "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", - "dev": true, - "peer": true - }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/concat-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", - "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/form-data": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", - "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" - }, - "node_modules/@types/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "peer": true - }, - "node_modules/@types/mocha": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", - "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", - "dev": true, - "peer": true - }, - "node_modules/@types/node": { - "version": "20.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz", - "integrity": "sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", - "dev": true, - "peer": true - }, - "node_modules/@types/qs": { - "version": "6.9.10", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", - "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", - "dev": true, - "peer": true - }, - "node_modules/@types/readable-stream": { - "version": "2.3.15", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", - "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "safe-buffer": "~5.1.1" - } - }, - "node_modules/@types/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/@types/secp256k1": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", - "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", - "dev": true, - "peer": true - }, - "node_modules/abstract-level": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", - "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", - "dev": true, - "dependencies": { - "buffer": "^6.0.3", - "catering": "^2.1.0", - "is-buffer": "^2.0.5", - "level-supports": "^4.0.0", - "level-transcoder": "^1.0.1", - "module-error": "^1.0.1", - "queue-microtask": "^1.2.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/abstract-level/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "dev": true, - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "dev": true, - "peer": true - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/amazon-cognito-identity-js": { - "version": "6.3.7", - "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.7.tgz", - "integrity": "sha512-tSjnM7KyAeOZ7UMah+oOZ6cW4Gf64FFcc7BE2l7MTcp7ekAPrXaCbpcW2xEpH1EiDS4cPcAouHzmCuc2tr72vQ==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-js": "1.2.2", - "buffer": "4.9.2", - "fast-base64-decode": "^1.0.0", - "isomorphic-unfetch": "^3.0.0", - "js-cookie": "^2.2.1" - } - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/antlr4": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", - "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", - "engines": { - "node": ">=16" - } - }, - "node_modules/antlr4ts": { - "version": "0.5.0-alpha.4", - "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", - "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "peer": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.3.tgz", - "integrity": "sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, - "peer": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/ast-parents": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", - "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==" - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true - }, - "node_modules/async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "dev": true, - "dependencies": { - "retry": "0.13.1" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true - }, - "node_modules/bigint-crypto-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", - "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", - "dev": true - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true - }, - "node_modules/browser-level": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", - "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", - "dev": true, - "dependencies": { - "abstract-level": "^1.0.2", - "catering": "^2.1.1", - "module-error": "^1.0.2", - "run-parallel-limit": "^1.1.0" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "dev": true, - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "dev": true, - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/c3-linearization": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/c3-linearization/-/c3-linearization-0.3.0.tgz", - "integrity": "sha512-eQNsZQhFSJAhrNrITy2FpKh7EHS98q/pniDtQhndWqqsvayiPeqZ9T6I9V9PsHcm0nc+ZYJHKUvI/hh37I33HQ==", - "dev": true - }, - "node_modules/cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "engines": { - "node": ">=14.16" - } - }, - "node_modules/cacheable-request": { - "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", - "dependencies": { - "@types/http-cache-semantics": "^4.0.2", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.3", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/case": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", - "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true, - "peer": true - }, - "node_modules/catering": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", - "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cbor": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", - "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", - "dev": true, - "peer": true, - "dependencies": { - "nofilter": "^3.1.0" - }, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", - "dev": true, - "peer": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", - "dev": true, - "peer": true, - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 5" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "peer": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/classic-level": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", - "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "abstract-level": "^1.0.2", - "catering": "^2.1.0", - "module-error": "^1.0.1", - "napi-macros": "^2.2.2", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-table": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz", - "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==", - "dev": true, - "dependencies": { - "colors": "1.0.3" - }, - "engines": { - "node": ">= 0.2.0" - } - }, - "node_modules/cli-table/node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/cli-table3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", - "dev": true, - "peer": true, - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", - "dev": true - }, - "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-usage": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", - "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^4.0.2", - "chalk": "^2.4.2", - "table-layout": "^1.0.2", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "dev": true - }, - "node_modules/compare-versions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", - "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "peer": true - }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "peer": true - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "peer": true - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/death": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", - "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", - "dev": true, - "peer": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "peer": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "peer": true - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-port": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", - "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", - "dev": true, - "peer": true, - "dependencies": { - "address": "^1.0.1", - "debug": "4" - }, - "bin": { - "detect": "bin/detect-port.js", - "detect-port": "bin/detect-port.js" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/difflib": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", - "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", - "dev": true, - "peer": true, - "dependencies": { - "heap": ">= 0.2.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "peer": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", - "dev": true, - "peer": true, - "dependencies": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.12.0" - }, - "optionalDependencies": { - "source-map": "~0.2.0" - } - }, - "node_modules/esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", - "dev": true, - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eth-gas-reporter": { - "version": "0.2.27", - "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", - "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", - "dev": true, - "peer": true, - "dependencies": { - "@solidity-parser/parser": "^0.14.0", - "axios": "^1.5.1", - "cli-table3": "^0.5.0", - "colors": "1.4.0", - "ethereum-cryptography": "^1.0.3", - "ethers": "^5.7.2", - "fs-readdir-recursive": "^1.1.0", - "lodash": "^4.17.14", - "markdown-table": "^1.1.3", - "mocha": "^10.2.0", - "req-cwd": "^2.0.0", - "sha1": "^1.1.1", - "sync-request": "^6.0.0" - }, - "peerDependencies": { - "@codechecks/client": "^0.1.0" - }, - "peerDependenciesMeta": { - "@codechecks/client": { - "optional": true - } - } - }, - "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true - }, - "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/eth-gas-reporter/node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, - "node_modules/ethereum-bloom-filters": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", - "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", - "dev": true, - "peer": true, - "dependencies": { - "js-sha3": "^0.8.0" - } - }, - "node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dev": true, - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/ethereumjs-abi": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", - "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - } - }, - "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/ethereumjs-abi/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "dev": true, - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/ethereumjs-util": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", - "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", - "dev": true, - "dependencies": { - "@types/bn.js": "^5.1.0", - "bn.js": "^5.1.2", - "create-hash": "^1.1.2", - "ethereum-cryptography": "^0.1.3", - "rlp": "^2.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/ethers": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.9.0.tgz", - "integrity": "sha512-pmfNyQzc2mseLe91FnT2vmNaTt8dDzhxZ/xItAV7uGsF4dI4ek2ufMu3rAkgQETL/TIs0GS5A+U05g9QyWnv3Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "peer": true, - "dependencies": { - "@adraffy/ens-normalize": "1.10.0", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", - "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", - "ws": "8.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "18.15.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", - "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", - "dev": true, - "peer": true - }, - "node_modules/ethers/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true, - "peer": true - }, - "node_modules/ethjs-unit": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", - "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", - "dev": true, - "peer": true, - "dependencies": { - "bn.js": "4.11.6", - "number-to-bn": "1.7.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/ethjs-unit/node_modules/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", - "dev": true, - "peer": true - }, - "node_modules/ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "dev": true, - "dependencies": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/fast-base64-decode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", - "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "peer": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "peer": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", - "engines": { - "node": ">= 14.17" - } - }, - "node_modules/fp-ts": { - "version": "1.19.3", - "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", - "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "peer": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true, - "peer": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ghost-testrpc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", - "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", - "dev": true, - "peer": true, - "dependencies": { - "chalk": "^2.4.2", - "node-emoji": "^1.10.0" - }, - "bin": { - "testrpc-sc": "index.js" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "peer": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "peer": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "12.6.1", - "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", - "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", - "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphviz": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/graphviz/-/graphviz-0.0.9.tgz", - "integrity": "sha512-SmoY2pOtcikmMCqCSy2NO1YsRfu9OO0wpTlOYW++giGjfX1a6gax/m1Fo8IdUd0/3H15cTOfR1SMKwohj4LKsg==", - "dev": true, - "dependencies": { - "temp": "~0.4.0" - }, - "engines": { - "node": ">=0.6.8" - } - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "peer": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hardhat": { - "version": "2.19.1", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.19.1.tgz", - "integrity": "sha512-bsWa63g1GB78ZyMN08WLhFElLPA+J+pShuKD1BFO2+88g3l+BL3R07vj9deIi9dMbssxgE714Gof1dBEDGqnCw==", - "dev": true, - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-blockchain": "7.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-evm": "2.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-statemanager": "2.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "@nomicfoundation/ethereumjs-vm": "7.0.2", - "@nomicfoundation/solidity-analyzer": "^0.1.0", - "@sentry/node": "^5.18.1", - "@types/bn.js": "^5.1.0", - "@types/lru-cache": "^5.1.0", - "adm-zip": "^0.4.16", - "aggregate-error": "^3.0.0", - "ansi-escapes": "^4.3.0", - "chalk": "^2.4.2", - "chokidar": "^3.4.0", - "ci-info": "^2.0.0", - "debug": "^4.1.1", - "enquirer": "^2.3.0", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^1.0.3", - "ethereumjs-abi": "^0.6.8", - "find-up": "^2.1.0", - "fp-ts": "1.19.3", - "fs-extra": "^7.0.1", - "glob": "7.2.0", - "immutable": "^4.0.0-rc.12", - "io-ts": "1.10.4", - "keccak": "^3.0.2", - "lodash": "^4.17.11", - "mnemonist": "^0.38.0", - "mocha": "^10.0.0", - "p-map": "^4.0.0", - "raw-body": "^2.4.1", - "resolve": "1.17.0", - "semver": "^6.3.0", - "solc": "0.7.3", - "source-map-support": "^0.5.13", - "stacktrace-parser": "^0.1.10", - "tsort": "0.0.1", - "undici": "^5.14.0", - "uuid": "^8.3.2", - "ws": "^7.4.6" - }, - "bin": { - "hardhat": "internal/cli/bootstrap.js" - }, - "peerDependencies": { - "ts-node": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/hardhat-gas-reporter": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", - "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", - "dev": true, - "peer": true, - "dependencies": { - "array-uniq": "1.0.3", - "eth-gas-reporter": "^0.2.25", - "sha1": "^1.1.1" - }, - "peerDependencies": { - "hardhat": "^2.0.2" - } - }, - "node_modules/hardhat/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/hardhat/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/hardhat/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/hardhat/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "dev": true, - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/hardhat/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/hardhat/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/hardhat/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/hardhat/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasha/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/heap": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", - "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", - "dev": true, - "peer": true - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/http-basic": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", - "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", - "dev": true, - "peer": true, - "dependencies": { - "caseless": "^0.12.0", - "concat-stream": "^1.6.2", - "http-response-object": "^3.0.1", - "parse-cache-control": "^1.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-response-object": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", - "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/node": "^10.0.3" - } - }, - "node_modules/http-response-object/node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true, - "peer": true - }, - "node_modules/http2-wrapper": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", - "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immutable": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/io-ts": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", - "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", - "dev": true, - "dependencies": { - "fp-ts": "^1.0.0" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", - "dev": true, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "peer": true - }, - "node_modules/isomorphic-unfetch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", - "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", - "dev": true, - "dependencies": { - "node-fetch": "^2.6.1", - "unfetch": "^4.2.0" - } - }, - "node_modules/js-cookie": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", - "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", - "dev": true - }, - "node_modules/js-sdsl": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", - "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "peer": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/keccak": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", - "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.9" - } - }, - "node_modules/latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", - "dependencies": { - "package-json": "^8.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/level": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", - "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", - "dev": true, - "dependencies": { - "browser-level": "^1.0.1", - "classic-level": "^1.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/level" - } - }, - "node_modules/level-supports": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", - "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/level-transcoder": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", - "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", - "dev": true, - "dependencies": { - "buffer": "^6.0.3", - "module-error": "^1.0.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/level-transcoder/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true, - "peer": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true, - "peer": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true, - "peer": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "peer": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "peer": true - }, - "node_modules/markdown-table": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", - "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", - "dev": true, - "peer": true - }, - "node_modules/mcl-wasm": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", - "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", - "dev": true, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/memory-level": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", - "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", - "dev": true, - "dependencies": { - "abstract-level": "^1.0.0", - "functional-red-black-tree": "^1.0.1", - "module-error": "^1.0.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micro-ftch": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", - "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", - "dev": true, - "peer": true - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "peer": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "peer": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mnemonist": { - "version": "0.38.5", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", - "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", - "dev": true, - "dependencies": { - "obliterator": "^2.0.0" - } - }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/module-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", - "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-macros": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", - "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", - "dev": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "peer": true - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "dev": true - }, - "node_modules/node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dev": true, - "peer": true, - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp-build": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", - "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==", - "dev": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", - "dev": true, - "engines": { - "node": ">=12.19" - } - }, - "node_modules/nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", - "dev": true, - "peer": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", - "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/number-to-bn": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", - "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", - "dev": true, - "peer": true, - "dependencies": { - "bn.js": "4.11.6", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/number-to-bn/node_modules/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", - "dev": true, - "peer": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obliterator": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", - "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "peer": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ordinal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", - "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", - "dev": true, - "peer": true - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/package-json": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", - "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", - "dependencies": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/package-json/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-cache-control": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", - "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", - "dev": true, - "peer": true - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dev": true, - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "peer": true - }, - "node_modules/promise": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", - "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "dev": true, - "peer": true, - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/proper-lockfile/node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dev": true, - "peer": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "peer": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "peer": true, - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/registry-auth-token": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", - "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", - "dependencies": { - "@pnpm/npm-conf": "^2.1.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", - "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/req-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", - "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", - "dev": true, - "peer": true, - "dependencies": { - "req-from": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/req-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", - "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", - "dev": true, - "peer": true, - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" - }, - "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "peer": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rlp": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", - "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", - "dev": true, - "dependencies": { - "bn.js": "^5.2.0" - }, - "bin": { - "rlp": "bin/rlp" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/run-parallel-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", - "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rustbn.js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", - "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", - "dev": true - }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/sc-istanbul": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", - "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", - "dev": true, - "peer": true, - "dependencies": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "istanbul": "lib/cli.js" - } - }, - "node_modules/sc-istanbul/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/sc-istanbul/node_modules/async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", - "dev": true, - "peer": true - }, - "node_modules/sc-istanbul/node_modules/glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", - "dev": true, - "peer": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sc-istanbul/node_modules/has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sc-istanbul/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sc-istanbul/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", - "dev": true, - "peer": true - }, - "node_modules/sc-istanbul/node_modules/supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true - }, - "node_modules/secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/sha1": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", - "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", - "dev": true, - "peer": true, - "dependencies": { - "charenc": ">= 0.0.1", - "crypt": ">= 0.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/sha1-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sha1-file/-/sha1-file-2.0.1.tgz", - "integrity": "sha512-L4Kum9Lp8cWqcGKycZcXxR6spUoG4idDIUzAKjPiELnIZWxiFlZ5HFVzFxVxuWuGPsrraeL0JoGk0nFZ7AGFEQ==", - "dev": true, - "dependencies": { - "hasha": "^5.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "peer": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/sloc": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/sloc/-/sloc-0.3.0.tgz", - "integrity": "sha512-fKmMA8q5OyeZpFCxBa3FuFywQcziQXKBw9B8jwDJ/Ra3H/pkZpQJl9g5s3MIjUo2jwUDHUnaxXgVXObXFdiJBw==", - "dev": true, - "dependencies": { - "async": "^3.2.4", - "cli-table": "^0.3.11", - "commander": "^11.0.0", - "readdirp": "^3.3.0" - }, - "bin": { - "sloc": "bin/sloc" - } - }, - "node_modules/sloc/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/solc": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", - "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", - "dev": true, - "dependencies": { - "command-exists": "^1.2.8", - "commander": "3.0.2", - "follow-redirects": "^1.12.1", - "fs-extra": "^0.30.0", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "require-from-string": "^2.0.0", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "bin": { - "solcjs": "solcjs" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/solc/node_modules/fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "node_modules/solc/node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/solc/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solhint": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-4.0.0.tgz", - "integrity": "sha512-bFViMcFvhqVd/HK3Roo7xZXX5nbujS7Bxeg5vnZc9QvH0yCWCrQ38Yrn1pbAY9tlKROc6wFr+rK1mxYgYrjZgA==", - "dependencies": { - "@solidity-parser/parser": "^0.16.0", - "ajv": "^6.12.6", - "antlr4": "^4.11.0", - "ast-parents": "^0.0.1", - "chalk": "^4.1.2", - "commander": "^10.0.0", - "cosmiconfig": "^8.0.0", - "fast-diff": "^1.2.0", - "glob": "^8.0.3", - "ignore": "^5.2.4", - "js-yaml": "^4.1.0", - "latest-version": "^7.0.0", - "lodash": "^4.17.21", - "pluralize": "^8.0.0", - "semver": "^7.5.2", - "strip-ansi": "^6.0.1", - "table": "^6.8.1", - "text-table": "^0.2.0" - }, - "bin": { - "solhint": "solhint.js" - }, - "optionalDependencies": { - "prettier": "^2.8.3" - } - }, - "node_modules/solhint/node_modules/@solidity-parser/parser": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", - "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/solhint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/solhint/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/solhint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/solhint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/solhint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/solhint/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "engines": { - "node": ">=14" - } - }, - "node_modules/solhint/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/solhint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/solhint/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solhint/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solhint/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/solhint/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solhint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/solhint/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/solidity-ast": { - "version": "0.4.55", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.55.tgz", - "integrity": "sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==", - "dev": true, - "dependencies": { - "array.prototype.findlast": "^1.2.2" - } - }, - "node_modules/solidity-code-metrics": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/solidity-code-metrics/-/solidity-code-metrics-0.0.25.tgz", - "integrity": "sha512-of1wT4B5GL0/IahPttkEQUU3Bgq2PpLfQ1GcGdE8aMOhryWrEa4V5LYYd7cqKwyzWaRYIZ/pLUnaoJtCV2HfHA==", - "dev": true, - "dependencies": { - "@solidity-parser/parser": "^0.16.1", - "glob": "^8.0.3", - "sloc": "^0.3.0", - "solidity-doppelganger": "^0.0.11", - "surya": "^0.4.6" - }, - "bin": { - "solidity-code-metrics": "src/cli.js" - } - }, - "node_modules/solidity-code-metrics/node_modules/@solidity-parser/parser": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", - "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", - "dev": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/solidity-code-metrics/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/solidity-code-metrics/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/solidity-code-metrics/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solidity-coverage": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.5.tgz", - "integrity": "sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==", - "dev": true, - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.0.9", - "@solidity-parser/parser": "^0.16.0", - "chalk": "^2.4.2", - "death": "^1.1.0", - "detect-port": "^1.3.0", - "difflib": "^0.2.4", - "fs-extra": "^8.1.0", - "ghost-testrpc": "^0.0.2", - "global-modules": "^2.0.0", - "globby": "^10.0.1", - "jsonschema": "^1.2.4", - "lodash": "^4.17.15", - "mocha": "10.2.0", - "node-emoji": "^1.10.0", - "pify": "^4.0.1", - "recursive-readdir": "^2.2.2", - "sc-istanbul": "^0.4.5", - "semver": "^7.3.4", - "shelljs": "^0.8.3", - "web3-utils": "^1.3.6" - }, - "bin": { - "solidity-coverage": "plugins/bin.js" - }, - "peerDependencies": { - "hardhat": "^2.11.0" - } - }, - "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", - "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", - "dev": true, - "peer": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/solidity-coverage/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/solidity-coverage/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "peer": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/solidity-coverage/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solidity-coverage/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solidity-coverage/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/solidity-coverage/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "peer": true - }, - "node_modules/solidity-doppelganger": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/solidity-doppelganger/-/solidity-doppelganger-0.0.11.tgz", - "integrity": "sha512-mLIuW1Gfcr49zAZuE3XiQoqvkIAOKJBsgg//3DUvX8G6PvQErfnEKSajXwrYmW27oawwB/qbdRYuFR0inpsJQQ==", - "dev": true, - "dependencies": { - "@solidity-parser/parser": "^0.16.1", - "glob": "^8.0.3", - "yargs": "^17.0.1" - } - }, - "node_modules/solidity-doppelganger/node_modules/@solidity-parser/parser": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", - "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", - "dev": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/solidity-doppelganger/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/solidity-doppelganger/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/solidity-doppelganger/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/solidity-doppelganger/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/solidity-doppelganger/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/solidity-doppelganger/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/solidity-doppelganger/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/solidity-doppelganger/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "peer": true - }, - "node_modules/stacktrace-parser": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", - "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", - "dev": true, - "dependencies": { - "type-fest": "^0.7.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/stacktrace-parser/node_modules/type-fest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", - "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", - "dev": true, - "peer": true - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "peer": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", - "dev": true, - "dependencies": { - "is-hex-prefixed": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/surya": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/surya/-/surya-0.4.11.tgz", - "integrity": "sha512-SsDGqYQ1XCkGfCutLQ5s0Es2Tt41lY4FcrxlMiiOzPVJbD3AclI+Cot2SbtXuw/CeqRqaugLE5B95tfMDsRp9g==", - "dev": true, - "dependencies": { - "@solidity-parser/parser": "^0.16.1", - "c3-linearization": "^0.3.0", - "colors": "^1.4.0", - "graphviz": "0.0.9", - "sha1-file": "^2.0.0", - "treeify": "^1.1.0", - "yargs": "^17.0.0" - }, - "bin": { - "surya": "bin/surya" - } - }, - "node_modules/surya/node_modules/@solidity-parser/parser": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", - "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", - "dev": true, - "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" - } - }, - "node_modules/surya/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/surya/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/surya/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/surya/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/surya/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/sync-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", - "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", - "dev": true, - "peer": true, - "dependencies": { - "http-response-object": "^3.0.1", - "sync-rpc": "^1.2.1", - "then-request": "^6.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/sync-rpc": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", - "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", - "dev": true, - "peer": true, - "dependencies": { - "get-port": "^3.1.0" - } - }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table-layout": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", - "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", - "dev": true, - "peer": true, - "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table-layout/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/table/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/temp": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.4.0.tgz", - "integrity": "sha512-IsFisGgDKk7qzK9erMIkQe/XwiSUdac7z3wYOsjcLkhPBy3k1SlvLoIh2dAHIlEpgA971CgguMrx9z8fFg7tSA==", - "dev": true, - "engines": [ - "node >=0.4.0" - ] - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "node_modules/then-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", - "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", - "dev": true, - "peer": true, - "dependencies": { - "@types/concat-stream": "^1.6.0", - "@types/form-data": "0.0.33", - "@types/node": "^8.0.0", - "@types/qs": "^6.2.31", - "caseless": "~0.12.0", - "concat-stream": "^1.6.0", - "form-data": "^2.2.0", - "http-basic": "^8.1.1", - "http-response-object": "^3.0.1", - "promise": "^8.0.0", - "qs": "^6.4.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/then-request/node_modules/@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", - "dev": true, - "peer": true - }, - "node_modules/then-request/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "peer": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-command-line-args": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", - "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", - "dev": true, - "peer": true, - "dependencies": { - "chalk": "^4.1.0", - "command-line-args": "^5.1.1", - "command-line-usage": "^6.1.0", - "string-format": "^2.0.0" - }, - "bin": { - "write-markdown": "dist/write-markdown.js" - } - }, - "node_modules/ts-command-line-args/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ts-command-line-args/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ts-command-line-args/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ts-command-line-args/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "peer": true - }, - "node_modules/ts-command-line-args/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-command-line-args/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-essentials": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", - "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", - "dev": true, - "peer": true, - "peerDependencies": { - "typescript": ">=3.7.0" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "peer": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsort": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", - "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", - "dev": true - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "node_modules/tweetnacl-util": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", - "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typechain": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", - "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", - "dev": true, - "peer": true, - "dependencies": { - "@types/prettier": "^2.1.1", - "debug": "^4.3.1", - "fs-extra": "^7.0.0", - "glob": "7.1.7", - "js-sha3": "^0.8.0", - "lodash": "^4.17.15", - "mkdirp": "^1.0.4", - "prettier": "^2.3.1", - "ts-command-line-args": "^2.2.0", - "ts-essentials": "^7.0.1" - }, - "bin": { - "typechain": "dist/cli/cli.js" - }, - "peerDependencies": { - "typescript": ">=4.3.0" - } - }, - "node_modules/typechain/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/typechain/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typechain/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "peer": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/typechain/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "peer": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typechain/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "peer": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/typechain/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "peer": true - }, - "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", - "devOptional": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici": { - "version": "5.28.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.1.tgz", - "integrity": "sha512-xcIIvj1LOQH9zAL54iWFkuDEaIVEjLrru7qRpa3GrEEHk6OBhb/LycuUY2m7VCcTuDeLziXCxobQVyKExyGeIA==", - "dev": true, - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/unfetch": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", - "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", - "dev": true, - "peer": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "peer": true - }, - "node_modules/web3-utils": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.3.tgz", - "integrity": "sha512-OqcUrEE16fDBbGoQtZXWdavsPzbGIDc5v3VrRTZ0XrIpefC/viZ1ZU9bGEemazyS0catk/3rkOOxpzTfY+XsyQ==", - "dev": true, - "peer": true, - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "bn.js": "^5.2.1", - "ethereum-bloom-filters": "^1.0.6", - "ethereum-cryptography": "^2.1.2", - "ethjs-unit": "0.1.6", - "number-to-bn": "1.7.0", - "randombytes": "^2.1.0", - "utf8": "3.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/web3-utils/node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/ethereum-cryptography": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", - "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/curves": "1.1.0", - "@noble/hashes": "1.3.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "peer": true - }, - "node_modules/wordwrapjs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", - "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", - "dev": true, - "peer": true, - "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/wordwrapjs/node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 80856d7..0000000 --- a/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "lrt", - "scripts": { - "clean": "rm -rf cache out", - "build": "forge build", - "lint": "npm run lint:sol && npm run prettier:check", - "lint:sol": "forge fmt --check && solhint {script,src,test}/**/*.sol", - "prettier:check": "prettier --check **/*.{json,md,yml} --ignore-path=.prettierignore", - "prettier:write": "prettier --write **/*.{json,md,yml} --ignore-path=.prettierignore", - "test": "forge test", - "test:coverage": "forge coverage", - "test:coverage:report": "forge coverage --report lcov && genhtml lcov.info --branch-coverage --output-dir coverage", - "metrics": "npx solidity-code-metrics contracts/*.sol contracts/**/*.sol > metrics.md", - "upgrade:mainnet": "npx hardhat run script/hardhat-scripts/upgrade.ts --network mainnet", - "upgrade:goerli": "npx hardhat run script/hardhat-scripts/upgrade.ts --network goerli" - }, - "devDependencies": { - "@nomicfoundation/hardhat-foundry": "^1.1.1", - "@nomicfoundation/hardhat-toolbox": "^3.0.0", - "@openzeppelin/hardhat-upgrades": "^2.3.3", - "hardhat": "^2.18.3", - "prettier": "^3.0.3", - "solidity-code-metrics": "^0.0.25" - }, - "dependencies": { - "dotenv": "^16.3.1", - "solhint": "^4.0.0" - } -} diff --git a/remappings.txt b/remappings.txt index a4639d3..e7c0836 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,4 +1,3 @@ -ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ @openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ diff --git a/script/foundry-scripts/AddNewAsset.s.sol b/script/foundry-scripts/AddNewAsset.s.sol deleted file mode 100644 index 21e5dc3..0000000 --- a/script/foundry-scripts/AddNewAsset.s.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { ProxyFactory } from "script/foundry-scripts/utils/ProxyFactory.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import { SfrxETHPriceOracle } from "contracts/oracles/SfrxETHPriceOracle.sol"; - -contract AddNewAsset is Script { - ProxyFactory public proxyFactory; - ProxyAdmin public proxyAdmin; - SfrxETHPriceOracle public assetOracle; - - address public asset; - - function run() external { - vm.startBroadcast(); - uint256 chainId = block.chainid; - if (chainId == 1) { - //mainnet - proxyFactory = ProxyFactory(0x673a669425457bCabeb247f56552A0Fd8141cee2); - proxyAdmin = ProxyAdmin(0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78); - - asset = 0xac3E018457B222d93114458476f3E3416Abbe38F; - } else if (chainId == 5) { - // goerli - proxyFactory = ProxyFactory(0x4ae77FdfB3BBBe99598CAfaE4c369b604b6d9e02); - proxyAdmin = ProxyAdmin(0xa6A6b35d84B20077c6f3d30b86547fF837260407); - - asset = 0x5E8422345238F34275888049021821E8E08CAa1f; - } else { - revert("Not Applicable"); - } - - address assetOracleImplementation = address(new SfrxETHPriceOracle()); - console.log("SfrxETHPriceOracle Implementation deployed at: %s", address(assetOracleImplementation)); - - bytes32 salt = keccak256(abi.encodePacked("SfrxETHPriceOracle")); - address assetOracleProxy = proxyFactory.create(address(assetOracleImplementation), address(proxyAdmin), salt); - console.log("SfrxETHPriceOracle Proxy deployed at: %s", address(assetOracleProxy)); - - // initialize the proxies - SfrxETHPriceOracle(address(assetOracleProxy)).initialize(asset); - - // MANUALLY using GNOSIS SAFE - - // ADMIN - // lrtConfigProxy.setToken(LRTConstants.SFRXETH_TOKEN, sfrxETHAddress); - // lrtConfigProxy.updateAssetStrategy(sfrxETHAddress, SfrxETHStrategyAddress); - - // Manager - // lrtConfigProxy.addNewSupportedAsset(sfrxETHAddress, 100_000 ether); - // lrtOracleProxy.updatePriceOracleFor(sfrxETHAddress, address(assetOracleProxy)); - - vm.stopBroadcast(); - } -} diff --git a/script/foundry-scripts/DeployLRT.s.sol b/script/foundry-scripts/DeployLRT.s.sol deleted file mode 100644 index f67f211..0000000 --- a/script/foundry-scripts/DeployLRT.s.sol +++ /dev/null @@ -1,292 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { LRTConfig, LRTConstants } from "contracts/LRTConfig.sol"; -import { RSETH } from "contracts/RSETH.sol"; -import { LRTDepositPool } from "contracts/LRTDepositPool.sol"; -import { LRTOracle } from "contracts/LRTOracle.sol"; -import { ChainlinkPriceOracle } from "contracts/oracles/ChainlinkPriceOracle.sol"; -import { EthXPriceOracle } from "contracts/oracles/EthXPriceOracle.sol"; -import { NodeDelegator } from "contracts/NodeDelegator.sol"; - -import { ProxyFactory } from "script/foundry-scripts/utils/ProxyFactory.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import { MockPriceAggregator } from "script/foundry-scripts/utils/MockPriceAggregator.sol"; - -function getLSTs() view returns (address stETH, address ethx) { - uint256 chainId = block.chainid; - - if (chainId == 1) { - // mainnet - stETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; - ethx = 0xA35b1B31Ce002FBF2058D22F30f95D405200A15b; - } else if (chainId == 5) { - // goerli - stETH = 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F; - ethx = 0x3338eCd3ab3d3503c55c931d759fA6d78d287236; - } else { - revert("Unsupported network"); - } -} - -contract DeployLRT is Script { - address public proxyAdminOwner; - ProxyAdmin public proxyAdmin; - - ProxyFactory public proxyFactory; - - LRTConfig public lrtConfigProxy; - RSETH public RSETHProxy; - LRTDepositPool public lrtDepositPoolProxy; - LRTOracle public lrtOracleProxy; - ChainlinkPriceOracle public chainlinkPriceOracleProxy; - EthXPriceOracle public ethXPriceOracleProxy; - NodeDelegator public nodeDelegatorProxy1; - NodeDelegator public nodeDelegatorProxy2; - NodeDelegator public nodeDelegatorProxy3; - NodeDelegator public nodeDelegatorProxy4; - NodeDelegator public nodeDelegatorProxy5; - address[] public nodeDelegatorContracts; - - uint256 public minAmountToDeposit; - - function maxApproveToEigenStrategyManager(address nodeDel) private { - (address stETH, address ethx) = getLSTs(); - NodeDelegator(payable(nodeDel)).maxApproveToEigenStrategyManager(stETH); - NodeDelegator(payable(nodeDel)).maxApproveToEigenStrategyManager(ethx); - } - - function getAssetStrategies() - private - view - returns (address strategyManager, address stETHStrategy, address ethXStrategy) - { - uint256 chainId = block.chainid; - // https://github.com/Layr-Labs/eigenlayer-contracts#deployments - if (chainId == 1) { - // mainnet - strategyManager = 0x858646372CC42E1A627fcE94aa7A7033e7CF075A; - stETHStrategy = 0x93c4b944D05dfe6df7645A86cd2206016c51564D; - // TODO: NEED TO HAVE ETHX STRATEGY - ethXStrategy = 0x0000000000000000000000000000000000000000; - } else { - // testnet - strategyManager = 0x779d1b5315df083e3F9E94cB495983500bA8E907; - stETHStrategy = 0xB613E78E2068d7489bb66419fB1cfa11275d14da; - // TODO: NEED TO HAVE ETHX STRATEGY - ethXStrategy = 0x0000000000000000000000000000000000000000; - } - } - - function getPriceFeeds() private returns (address stETHPriceFeed, address ethxPriceFeed) { - uint256 chainId = block.chainid; - - if (chainId == 1) { - // mainnet - stETHPriceFeed = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812; - ethxPriceFeed = address(ethXPriceOracleProxy); - } else { - // testnet - stETHPriceFeed = address(new MockPriceAggregator()); - ethxPriceFeed = address(ethXPriceOracleProxy); - } - } - - function setUpByAdmin() private { - (address stETH, address ethx) = getLSTs(); - // ----------- callable by admin ---------------- - - // add rsETH to LRT config - lrtConfigProxy.setRSETH(address(RSETHProxy)); - // add oracle to LRT config - lrtConfigProxy.setContract(LRTConstants.LRT_ORACLE, address(lrtOracleProxy)); - // add deposit pool to LRT config - lrtConfigProxy.setContract(LRTConstants.LRT_DEPOSIT_POOL, address(lrtDepositPoolProxy)); - // call updateAssetStrategy for each asset in LRTConfig - (address strategyManager, address stETHStrategy, address ethXStrategy) = getAssetStrategies(); - lrtConfigProxy.setContract(LRTConstants.EIGEN_STRATEGY_MANAGER, strategyManager); - lrtConfigProxy.updateAssetStrategy(stETH, stETHStrategy); - // TODO: NEED TO HAVE ETHX STRATEGY - // lrtConfigProxy.updateAssetStrategy(ethx, ethXStrategy); - - // grant MANAGER_ROLE to an address in LRTConfig - lrtConfigProxy.grantRole(LRTConstants.MANAGER, proxyAdminOwner); - // add minter role to lrtDepositPool so it mints rsETH - lrtConfigProxy.grantRole(LRTConstants.MINTER_ROLE, address(lrtDepositPoolProxy)); - - // add nodeDelegators to LRTDepositPool queue - nodeDelegatorContracts.push(address(nodeDelegatorProxy1)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy2)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy3)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy4)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy5)); - lrtDepositPoolProxy.addNodeDelegatorContractToQueue(nodeDelegatorContracts); - - // add min amount to deposit in LRTDepositPool - lrtDepositPoolProxy.setMinAmountToDeposit(minAmountToDeposit); - } - - function setUpByManager() private { - (address stETH, address ethx) = getLSTs(); - // --------- callable by manager ----------- - - (address stETHPriceFeed, address ethxPriceFeed) = getPriceFeeds(); - - // Add chainlink oracles for supported assets in ChainlinkPriceOracle - chainlinkPriceOracleProxy.updatePriceFeedFor(stETH, stETHPriceFeed); - - // call updatePriceOracleFor for each asset in LRTOracle - lrtOracleProxy.updatePriceOracleFor(address(stETH), address(chainlinkPriceOracleProxy)); - lrtOracleProxy.updatePriceOracleFor(address(ethx), address(ethxPriceFeed)); - - // maxApproveToEigenStrategyManager in each NodeDelegator to transfer to strategy - maxApproveToEigenStrategyManager(address(nodeDelegatorProxy1)); - maxApproveToEigenStrategyManager(address(nodeDelegatorProxy2)); - maxApproveToEigenStrategyManager(address(nodeDelegatorProxy3)); - maxApproveToEigenStrategyManager(address(nodeDelegatorProxy4)); - maxApproveToEigenStrategyManager(address(nodeDelegatorProxy5)); - } - - function run() external { - vm.startBroadcast(); - - bytes32 salt = keccak256(abi.encodePacked("LRT-Stader-Labs")); - proxyFactory = new ProxyFactory(); - proxyAdmin = new ProxyAdmin(); // msg.sender becomes the owner of ProxyAdmin - - proxyAdminOwner = proxyAdmin.owner(); - minAmountToDeposit = 0.0001 ether; - - console.log("ProxyAdmin deployed at: ", address(proxyAdmin)); - console.log("Owner of ProxyAdmin: ", proxyAdminOwner); - - // deploy implementation contracts - address lrtConfigImplementation = address(new LRTConfig()); - address RSETHImplementation = address(new RSETH()); - address lrtDepositPoolImplementation = address(new LRTDepositPool()); - address lrtOracleImplementation = address(new LRTOracle()); - address chainlinkPriceOracleImplementation = address(new ChainlinkPriceOracle()); - address ethxPriceOracleImplementation = address(new EthXPriceOracle()); - address nodeDelegatorImplementation = address(new NodeDelegator()); - - console.log("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); - console.log("LRTConfig implementation deployed at: ", lrtConfigImplementation); - console.log("RSETH implementation deployed at: ", RSETHImplementation); - console.log("LRTDepositPool implementation deployed at: ", lrtDepositPoolImplementation); - console.log("LRTOracle implementation deployed at: ", lrtOracleImplementation); - console.log("ChainlinkPriceOracle implementation deployed at: ", chainlinkPriceOracleImplementation); - console.log("EthXPriceOracle implementation deployed at: ", ethxPriceOracleImplementation); - console.log("NodeDelegator implementation deployed at: ", nodeDelegatorImplementation); - console.log("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); - - // deploy proxy contracts and initialize them - lrtConfigProxy = LRTConfig(proxyFactory.create(address(lrtConfigImplementation), address(proxyAdmin), salt)); - - // set up LRTConfig init params - (address stETH, address ethx) = getLSTs(); - address predictedRSETHAddress = proxyFactory.computeAddress(RSETHImplementation, address(proxyAdmin), salt); - console.log("predictedRSETHAddress: ", predictedRSETHAddress); - // init LRTConfig - lrtConfigProxy.initialize(proxyAdminOwner, stETH, ethx, predictedRSETHAddress); - - RSETHProxy = RSETH(proxyFactory.create(address(RSETHImplementation), address(proxyAdmin), salt)); - // init RSETH - RSETHProxy.initialize(proxyAdminOwner, address(lrtConfigProxy)); - - lrtDepositPoolProxy = LRTDepositPool( - payable(proxyFactory.create(address(lrtDepositPoolImplementation), address(proxyAdmin), salt)) - ); - // init LRTDepositPool - lrtDepositPoolProxy.initialize(address(lrtConfigProxy)); - - lrtOracleProxy = LRTOracle(proxyFactory.create(address(lrtOracleImplementation), address(proxyAdmin), salt)); - // init LRTOracle - lrtOracleProxy.initialize(address(lrtConfigProxy)); - - chainlinkPriceOracleProxy = ChainlinkPriceOracle( - proxyFactory.create(address(chainlinkPriceOracleImplementation), address(proxyAdmin), salt) - ); - // init ChainlinkPriceOracle - chainlinkPriceOracleProxy.initialize(address(lrtConfigProxy)); - - ethXPriceOracleProxy = - EthXPriceOracle(proxyFactory.create(address(ethxPriceOracleImplementation), address(proxyAdmin), salt)); - - // init EthXPriceOracle - if (block.chainid == 1) { - address staderStakingPoolManager = 0xcf5EA1b38380f6aF39068375516Daf40Ed70D299; - // mainnet - ethXPriceOracleProxy.initialize(staderStakingPoolManager); - } else { - address staderStakingPoolManager = 0xd0e400Ec6Ed9C803A9D9D3a602494393E806F823; - // testnet - ethXPriceOracleProxy.initialize(staderStakingPoolManager); - } - - nodeDelegatorProxy1 = - NodeDelegator(payable(proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), salt))); - bytes32 saltForNodeDelegator2 = keccak256(abi.encodePacked("LRT-Stader-Labs-nodeDelegator2")); - nodeDelegatorProxy2 = NodeDelegator( - payable( - proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), saltForNodeDelegator2) - ) - ); - bytes32 saltForNodeDelegator3 = keccak256(abi.encodePacked("LRT-Stader-Labs-nodeDelegator3")); - nodeDelegatorProxy3 = NodeDelegator( - payable( - proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), saltForNodeDelegator3) - ) - ); - bytes32 saltForNodeDelegator4 = keccak256(abi.encodePacked("LRT-Stader-Labs-nodeDelegator4")); - nodeDelegatorProxy4 = NodeDelegator( - payable( - proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), saltForNodeDelegator4) - ) - ); - bytes32 saltForNodeDelegator5 = keccak256(abi.encodePacked("LRT-Stader-Labs-nodeDelegator5")); - nodeDelegatorProxy5 = NodeDelegator( - payable( - proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), saltForNodeDelegator5) - ) - ); - // init NodeDelegator - nodeDelegatorProxy1.initialize(address(lrtConfigProxy)); - nodeDelegatorProxy2.initialize(address(lrtConfigProxy)); - nodeDelegatorProxy3.initialize(address(lrtConfigProxy)); - nodeDelegatorProxy4.initialize(address(lrtConfigProxy)); - nodeDelegatorProxy5.initialize(address(lrtConfigProxy)); - - console.log("LRTConfig proxy deployed at: ", address(lrtConfigProxy)); - console.log("RSETH proxy deployed at: ", address(RSETHProxy)); - console.log("LRTDepositPool proxy deployed at: ", address(lrtDepositPoolProxy)); - console.log("LRTOracle proxy deployed at: ", address(lrtOracleProxy)); - console.log("ChainlinkPriceOracle proxy deployed at: ", address(chainlinkPriceOracleProxy)); - console.log("EthXPriceOracle proxy deployed at: ", address(ethXPriceOracleProxy)); - console.log("NodeDelegator proxy 1 deployed at: ", address(nodeDelegatorProxy1)); - console.log("NodeDelegator proxy 2 deployed at: ", address(nodeDelegatorProxy2)); - console.log("NodeDelegator proxy 3 deployed at: ", address(nodeDelegatorProxy3)); - console.log("NodeDelegator proxy 4 deployed at: ", address(nodeDelegatorProxy4)); - console.log("NodeDelegator proxy 5 deployed at: ", address(nodeDelegatorProxy5)); - - // setup - setUpByAdmin(); - setUpByManager(); - - // update rsETHPrice - lrtOracleProxy.updateRSETHPrice(); - - // TODO: Check for the correct multisig addresses - address manager = 0xFc015a866aA06dDcaD27Fe425bdd362a8927544D; - lrtConfigProxy.grantRole(LRTConstants.MANAGER, manager); - lrtConfigProxy.revokeRole(LRTConstants.MANAGER, proxyAdminOwner); - address admin = 0xA65E2f72930219C4ce846FB245Ae18700296C328; - lrtConfigProxy.grantRole(LRTConstants.DEFAULT_ADMIN_ROLE, admin); - lrtConfigProxy.revokeRole(LRTConstants.DEFAULT_ADMIN_ROLE, proxyAdminOwner); - proxyAdmin.transferOwnership(admin); - - vm.stopBroadcast(); - } -} diff --git a/script/foundry-scripts/DeployLRTDepositPool.s.sol b/script/foundry-scripts/DeployLRTDepositPool.s.sol deleted file mode 100644 index 90ae104..0000000 --- a/script/foundry-scripts/DeployLRTDepositPool.s.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { LRTConfig, LRTConstants } from "contracts/LRTConfig.sol"; -import { LRTDepositPool } from "contracts/LRTDepositPool.sol"; -import { NodeDelegator } from "contracts/NodeDelegator.sol"; -import { RSETH } from "contracts/RSETH.sol"; - -import { ProxyFactory } from "script/foundry-scripts/utils/ProxyFactory.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -contract DeployLRTDepositPool is Script { - address public proxyAdminOwner; - ProxyAdmin public proxyAdmin; - - ProxyFactory public proxyFactory; - - LRTConfig public lrtConfigProxy; - LRTDepositPool public lrtDepositPoolProxy; - RSETH public RSETHProxy; - - NodeDelegator public nodeDelegatorProxy1; - NodeDelegator public nodeDelegatorProxy2; - NodeDelegator public nodeDelegatorProxy3; - NodeDelegator public nodeDelegatorProxy4; - NodeDelegator public nodeDelegatorProxy5; - address[] public nodeDelegatorContracts; - - function setUpByAdmin() private { - // add deposit pool to LRT config - lrtConfigProxy.setContract(LRTConstants.LRT_DEPOSIT_POOL, address(lrtDepositPoolProxy)); - - // add minter role to lrtDepositPool so it mint rsETH - lrtConfigProxy.grantRole(LRTConstants.MINTER_ROLE, address(lrtDepositPoolProxy)); - address oldDepositPoolProxy = 0x55052ba1a135c43a17cf6CeE58a59c782CeF1Bcf; - lrtConfigProxy.revokeRole(LRTConstants.MINTER_ROLE, oldDepositPoolProxy); - - // add nodeDelegators to LRTDepositPool queue - nodeDelegatorContracts.push(address(nodeDelegatorProxy1)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy2)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy3)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy4)); - nodeDelegatorContracts.push(address(nodeDelegatorProxy5)); - lrtDepositPoolProxy.addNodeDelegatorContractToQueue(nodeDelegatorContracts); - } - - function run() external { - vm.startBroadcast(); - console.log("Deployment started..."); - - proxyFactory = ProxyFactory(0x4ae77FdfB3BBBe99598CAfaE4c369b604b6d9e02); - proxyAdmin = ProxyAdmin(0x503DCfd945dC6612FAa18823501C05410D7eB646); - proxyAdminOwner = proxyAdmin.owner(); - lrtConfigProxy = LRTConfig(0x99Abf439a4e9910934Dea47082286a04986820b5); - RSETHProxy = RSETH(0xDa3FF613C5A44F743E5F46c43D1f6F897F425205); - nodeDelegatorProxy1 = NodeDelegator(payable(0x89cD79e873DEA08D1AfA173B9160c8D31e4Bc9f0)); - nodeDelegatorProxy2 = NodeDelegator(payable(0x5c5720246d3210E90875015c8439230c027a104b)); - nodeDelegatorProxy3 = NodeDelegator(payable(0x68FBD2a42e5d598dA91161f69a8346aFc9Ad9BA8)); - nodeDelegatorProxy4 = NodeDelegator(payable(0x6E6a5770A3A9A8b8614600d5F0A9d6bDc695CF68)); - nodeDelegatorProxy5 = NodeDelegator(payable(0x51975b2e6E29738B8aaaC8479f929a04c5E1D54c)); - - console.log("ProxyAdmin deployed at: ", address(proxyAdmin)); - console.log("Owner of ProxyAdmin: ", proxyAdminOwner); - console.log("LRTConfig proxy present at: ", address(lrtConfigProxy)); - - console.log("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); - address lrtDepositPoolImplementation = address(new LRTDepositPool()); - console.log("LRTDepositPool implementation deployed at: ", lrtDepositPoolImplementation); - console.log("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); - - bytes32 salt = keccak256(abi.encodePacked("LRT-Stader-Labs")); - lrtDepositPoolProxy = LRTDepositPool( - payable(proxyFactory.create(address(lrtDepositPoolImplementation), address(proxyAdmin), salt)) - ); - // init LRTDepositPool - lrtDepositPoolProxy.initialize(address(lrtConfigProxy)); - console.log("LRTDepositPool proxy deployed at: ", address(lrtDepositPoolProxy)); - - setUpByAdmin(); - - console.log("Deployment Done."); - console.log("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); - } -} diff --git a/script/foundry-scripts/DeployNodeDelegatorImplementation.s.sol b/script/foundry-scripts/DeployNodeDelegatorImplementation.s.sol deleted file mode 100644 index 0c5ef41..0000000 --- a/script/foundry-scripts/DeployNodeDelegatorImplementation.s.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { NodeDelegator } from "contracts/NodeDelegator.sol"; - -contract DeployNodeDelegatorImplementation is Script { - NodeDelegator public nodeDelegatorImplementation; - - function run() external { - vm.startBroadcast(); - nodeDelegatorImplementation = new NodeDelegator(); - - console.log("New NodeDelegator implementation deployed at: %s", address(nodeDelegatorImplementation)); - - vm.stopBroadcast(); - } -} diff --git a/script/foundry-scripts/DeployNodeDelegatorProxy.s.sol b/script/foundry-scripts/DeployNodeDelegatorProxy.s.sol deleted file mode 100644 index 832c320..0000000 --- a/script/foundry-scripts/DeployNodeDelegatorProxy.s.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { ProxyFactory } from "script/foundry-scripts/utils/ProxyFactory.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import { NodeDelegator } from "contracts/NodeDelegator.sol"; - -contract DeployNodeDelegatorProxy is Script { - ProxyFactory public proxyFactory; - ProxyAdmin public proxyAdmin; - NodeDelegator public nodeDelegatorImplementation; - - address lrtConfigAddr; - - function run() external { - vm.startBroadcast(); - uint256 chainId = block.chainid; - if (chainId == 1) { - //mainnet - proxyFactory = ProxyFactory(0x673a669425457bCabeb247f56552A0Fd8141cee2); - proxyAdmin = ProxyAdmin(0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78); - nodeDelegatorImplementation = NodeDelegator(payable(0xeD510dea149D14c1EB5f973004E0111afdb3B179)); - lrtConfigAddr = 0x947Cb49334e6571ccBFEF1f1f1178d8469D65ec7; - } else if (chainId == 5) { - // goerli - proxyFactory = ProxyFactory(0x4ae77FdfB3BBBe99598CAfaE4c369b604b6d9e02); - proxyAdmin = ProxyAdmin(0xa6A6b35d84B20077c6f3d30b86547fF837260407); - nodeDelegatorImplementation = NodeDelegator(payable(0xD73Cd1aaE045653474B873f3275BA2BE2744c8B4)); - lrtConfigAddr = 0x6d7888Bc794C1104C64c28F4e849B7AE68231b6d; - } else { - revert("Not Applicable"); - } - - bytes32 saltOne = keccak256(abi.encodePacked("NodeDelegatorProxy index 5")); - address nodeDelegatorProxyIndexFive = - proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), saltOne); - - console.log("NodeDelegator deployed at: %s", address(nodeDelegatorProxyIndexFive)); - - bytes32 saltTwo = keccak256(abi.encodePacked("NodeDelegatorProxy index 6")); - address nodeDelegatorProxyIndexSix = - proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), saltTwo); - console.log("NodeDelegator deployed at: %s", address(nodeDelegatorProxyIndexSix)); - - // initialize the proxies - NodeDelegator(payable(nodeDelegatorProxyIndexFive)).initialize(lrtConfigAddr); - NodeDelegator(payable(nodeDelegatorProxyIndexSix)).initialize(lrtConfigAddr); - - vm.stopBroadcast(); - } -} diff --git a/script/foundry-scripts/UpdateAssetStrategy.s.sol b/script/foundry-scripts/UpdateAssetStrategy.s.sol deleted file mode 100644 index 3e97f66..0000000 --- a/script/foundry-scripts/UpdateAssetStrategy.s.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { LRTConfig, LRTConstants } from "contracts/LRTConfig.sol"; - -/// @dev script to update asset strategy -contract UpdateAssetStrategy is Script { - LRTConfig public lrtConfigProxy; - - function setUp() public { - address lrtConfigProxyAddress = 0x0000000000000000000000000000000000000000; - lrtConfigProxy = LRTConfig(lrtConfigProxyAddress); - } - - function run() external { - vm.startBroadcast(); - console.log("UpdateAssetStrategy started..."); - - address asset = 0x0000000000000000000000000000000000000000; - address assetStrategy = 0x0000000000000000000000000000000000000000; - // update asset strategy - lrtConfigProxy.updateAssetStrategy(asset, assetStrategy); - - vm.stopBroadcast(); - console.log("UpdateAssetStrategy finished."); - } -} diff --git a/script/foundry-scripts/UpgradeLRT.s.sol b/script/foundry-scripts/UpgradeLRT.s.sol deleted file mode 100644 index 2a38645..0000000 --- a/script/foundry-scripts/UpgradeLRT.s.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; -import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -// import contract to be upgraded -// e.g. import "contracts/LRTConfig.sol"; -import { NodeDelegator } from "contracts/NodeDelegator.sol"; - -contract UpgradeLRT is Script { - ProxyAdmin public proxyAdmin; - - address public proxyAddress; - address public newImplementation; - - function run() public { - uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); - vm.startBroadcast(deployerPrivateKey); // must be the ProxyAdmin owner - - uint256 chainId = block.chainid; - if (chainId == 1) { - // mainnet - proxyAdmin = ProxyAdmin(address(0)); - proxyAddress = address(0); - newImplementation = address(0); - } else if (chainId == 5) { - // goerli - proxyAdmin = ProxyAdmin(0x19b912EdE7056943B23d237752814438338A9666); - proxyAddress = 0x991837c651902661fa88B80791d58dF56FD0Dd92; // example NodeDelegatorProxy1 - newImplementation = address(new NodeDelegator()); - } else { - revert("Unsupported network"); - } - - // upgrade contract - proxyAdmin.upgrade(ITransparentUpgradeableProxy(proxyAddress), newImplementation); - - vm.stopBroadcast(); - } -} diff --git a/script/foundry-scripts/cross-chain/RSETHRate.s.sol b/script/foundry-scripts/cross-chain/RSETHRate.s.sol deleted file mode 100644 index 6542e1d..0000000 --- a/script/foundry-scripts/cross-chain/RSETHRate.s.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Script.sol"; - -import { RSETHRateProvider } from "contracts/cross-chain/RSETHRateProvider.sol"; -import { RSETHRateReceiver } from "contracts/cross-chain/RSETHRateReceiver.sol"; - -contract DeployRSETHRateProvider is Script { - function run() external { - vm.startBroadcast(); - - if (block.chainid != 1) { - revert("Must be deployed on mainnet"); - } - - address rsETHOracle = 0x349A73444b1a310BAe67ef67973022020d70020d; - uint16 layerZeroDstChainId = 158; // Layer Zero id for Polygon ZKEVM - address layerZeroEndpoint = 0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675; - - address rsETHRateProviderContractAddress = - address(new RSETHRateProvider(rsETHOracle, layerZeroDstChainId, layerZeroEndpoint)); - - console.log("RSETHRateProvider deployed at: %s", address(rsETHRateProviderContractAddress)); - - vm.stopBroadcast(); - } -} - -contract DeployRSETHRateReceiver is Script { - function run() external { - vm.startBroadcast(); - - if (block.chainid != 1101) { - revert("Must be deployed on polygon ZKEVM"); - } - - address rateProviderOnEthMainnet = 0xF1cccBa5558D31628216489A1435e068b1fd2C8A; - uint16 layerZeroSrcChainId = 101; // Layer Zero id for Ethereum mainnet - address layerZeroEndpoint = 0x9740FF91F1985D8d2B71494aE1A2f723bb3Ed9E4; // LZ endpoint for polygon ZKEVM - - address rsETHRateReceiverContractAddress = - address(new RSETHRateReceiver(layerZeroSrcChainId, rateProviderOnEthMainnet, layerZeroEndpoint)); - - console.log("RSETHRateReceiver deployed at: %s", address(rsETHRateReceiverContractAddress)); - - vm.stopBroadcast(); - } -} diff --git a/script/foundry-scripts/utils/MockPriceAggregator.sol b/script/foundry-scripts/utils/MockPriceAggregator.sol deleted file mode 100644 index 7c370bd..0000000 --- a/script/foundry-scripts/utils/MockPriceAggregator.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -contract MockPriceAggregator { - uint256 public price; - - constructor() { - price = 1 ether; - } - - function decimals() external pure returns (uint8) { - return 18; - } - - function latestRoundData() - external - view - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - return (0, int256(price), 0, 0, 0); - } - - function setPrice(uint256 price_) external { - price = price_; - } -} diff --git a/script/foundry-scripts/utils/ProxyFactory.sol b/script/foundry-scripts/utils/ProxyFactory.sol deleted file mode 100644 index 59ae0ec..0000000 --- a/script/foundry-scripts/utils/ProxyFactory.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.21; - -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; - -/// @title ProxyFactory Contract -/// @notice The contract that handles the creation of proxies for the LRT contracts -contract ProxyFactory { - /// @dev Creates a proxy for the given implementation - /// @param implementation the implementation to proxy - /// @param proxyAdmin the proxy admin to use - /// @param salt the salt to use for the proxy - /// @return the address of the created proxy - function create(address implementation, address proxyAdmin, bytes32 salt) external returns (address) { - TransparentUpgradeableProxy proxy = - new TransparentUpgradeableProxy{ salt: salt }(implementation, proxyAdmin, ""); - return address(proxy); - } - - /// @dev Computes the address of a proxy for the given implementation - /// @param implementation the implementation to proxy - /// @param proxyAdmin the proxy admin to use - /// @param salt the salt to use for the proxy - /// @return the address of the created proxy - function computeAddress(address implementation, address proxyAdmin, bytes32 salt) external view returns (address) { - bytes memory creationCode = type(TransparentUpgradeableProxy).creationCode; - bytes memory contractBytecode = abi.encodePacked(creationCode, abi.encode(implementation, proxyAdmin, "")); - - return Create2.computeAddress(salt, keccak256(contractBytecode)); - } -} diff --git a/script/hardhat-scripts/deploy.ts b/script/hardhat-scripts/deploy.ts deleted file mode 100644 index df4fe59..0000000 --- a/script/hardhat-scripts/deploy.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ethers, upgrades } from 'hardhat' - -async function main() { - - console.log('starting deployment process...') - const [deployer] = await ethers.getSigners() - const rETH = process.env.R_ETH ?? '' - const stETH = process.env.ST_ETH ?? '' - const cbETH = process.env.CB_ETH ?? '' - - const lrtConfigFactory = await ethers.getContractFactory('LRTConfig') - const lrtConfig = await upgrades.deployProxy(lrtConfigFactory, [deployer.address, - stETH, - rETH, - cbETH, - cbETH]) - console.log('LRT config deployed at ', lrtConfig.target) - - const rsETHFactory = await ethers.getContractFactory('RSETH') - const rsETHToken = await upgrades.deployProxy(rsETHFactory, [deployer.address,lrtConfig.target]) - console.log('rsETH Token deployed at ', rsETHToken.target) - - const lrtDepositPoolFactory = await ethers.getContractFactory('LRTDepositPool') - const lrtDepositPool = await upgrades.deployProxy(lrtDepositPoolFactory, [lrtConfig.target]) - console.log('lrtDepositPool deployed at ', lrtDepositPool.target) - - const lrtOracleFactory = await ethers.getContractFactory('LRTOracle') - const lrtOracle = await upgrades.deployProxy(lrtOracleFactory, [lrtConfig.target]) - console.log('lrtOracle deployed at ', lrtOracle.target) - - const chainlinkOracleFactory = await ethers.getContractFactory('ChainlinkPriceOracle') - const chailinkOracle = await upgrades.deployProxy(chainlinkOracleFactory, [lrtConfig.target]) - console.log('chailinkOracle deployed at ', await chailinkOracle.getAddress()) - - const nodeDelegatorFactory = await ethers.getContractFactory('NodeDelegator') - const nodeDelegator1 = await upgrades.deployProxy(nodeDelegatorFactory, [lrtConfig.target]) - console.log('nodeDelegator1 deployed at ', nodeDelegator1.target) - const nodeDelegator2 = await upgrades.deployProxy(nodeDelegatorFactory, [lrtConfig.target]) - console.log('nodeDelegator2 deployed at ', nodeDelegator2.target) - const nodeDelegator3 = await upgrades.deployProxy(nodeDelegatorFactory, [lrtConfig.target]) - console.log('nodeDelegator3 deployed at ', nodeDelegator3.target) - const nodeDelegator4 = await upgrades.deployProxy(nodeDelegatorFactory, [lrtConfig.target]) - console.log('nodeDelegator4 deployed at ', nodeDelegator4.target) - const nodeDelegator5 = await upgrades.deployProxy(nodeDelegatorFactory, [lrtConfig.target]) - console.log('nodeDelegator5 deployed at ', nodeDelegator5.target) - -} - -main() diff --git a/script/hardhat-scripts/depositAsset.ts b/script/hardhat-scripts/depositAsset.ts deleted file mode 100644 index 1a5f6b7..0000000 --- a/script/hardhat-scripts/depositAsset.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ethers } from "hardhat"; - -async function main() { - const lrtDepositPool = process.env.LRT_DEPOSIT_POOL ?? ""; - const lrtDepositPoolFactory = await ethers.getContractFactory("LRTDepositPool"); - const lrtDepositPoolInstance = await lrtDepositPoolFactory.attach(lrtDepositPool); - - const assetAddress = process.env.ASSET_ADDRESS ?? ""; - const depositAmount = ethers.utils.parseEther("0.005"); - const minimumAmountOfRSETHForDeposit = lrtDepositPool.getRsETHAmountToMint(assetAddress, depositAmount); - const referralId = 0; - const depositTx = await lrtDepositPoolInstance.depositAsset( - assetAddress, - depositAmount, - minimumAmountOfRSETHForDeposit, - referralId, - ); - depositTx.wait(); - console.log(`deposited ${depositAmount} successfully`); -} - -main(); diff --git a/script/hardhat-scripts/upgrade.ts b/script/hardhat-scripts/upgrade.ts deleted file mode 100644 index bb0e9df..0000000 --- a/script/hardhat-scripts/upgrade.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as hardhat from "hardhat"; - -export class Upgrader { - private async getArtifacts() { - return { - NodeDelegator: await hardhat.ethers.getContractFactory("NodeDelegator"), - LRTDepositPool: await hardhat.ethers.getContractFactory("LRTDepositPool"), - LRTOracle: await hardhat.ethers.getContractFactory("LRTOracle"), - ChainlinkPriceOracle: await hardhat.ethers.getContractFactory("ChainlinkPriceOracle"), - EthXPriceOracle: await hardhat.ethers.getContractFactory("EthXPriceOracle"), - LRTConfig: await hardhat.ethers.getContractFactory("LRTConfig"), - RSETH: await hardhat.ethers.getContractFactory("RSETH"), - }; - } - - // use to validate upgrade before running it or passing it to Gnosis Safe - async validateUpgrade(contractName: string, contractAddress: string) { - const artifacts = await this.getArtifacts(); - - const contractArtifact = artifacts[contractName]; - - if (contractArtifact === undefined) { - throw new Error(`Contract ${contractName} not found`); - } - - await hardhat.upgrades.validateUpgrade(contractAddress, contractArtifact, { kind: "transparent" }); - } - - // used to store impl record for proxies in .openzeppelin folder - async forceImportDeployedProxies(contractName: string, contractAddress: string) { - const artifacts = await this.getArtifacts(); - - const contractArtifact = artifacts[contractName]; - - if (contractArtifact === undefined) { - throw new Error(`Contract ${contractName} not found`); - } - - await hardhat.upgrades.forceImport(contractAddress, contractArtifact, { kind: "transparent" }); - } - - async run(contractName: string, contractAddress: string) { - const artifacts = await this.getArtifacts(); - - const contractArtifact = artifacts[contractName]; - - if (contractArtifact === undefined) { - throw new Error(`Contract ${contractName} not found`); - } - - const contractInstance = await hardhat.upgrades.upgradeProxy(contractAddress, contractArtifact, {}); - await contractInstance.deployTransaction.wait(); - - const proxyAdmin = await hardhat.upgrades.admin.getInstance(); - const contractImpl = await proxyAdmin.callStatic.getProxyImplementation(contractInstance.address); - console.log("Contract implementation ", contractImpl); - } -} - -async function main() { - console.log("START!"); - - const upgrader = new Upgrader(); - // (contractName: string, contractAddress: string) - // await upgrader.validateUpgrade("", ""); - // await upgrader.run("", ""); - - console.log("END!"); -} - -// We recommend this pattern to be able to use async/await everywhere -// and properly handle errors. -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/script/hardhat-scripts/upgradeDepositPool.ts b/script/hardhat-scripts/upgradeDepositPool.ts deleted file mode 100644 index 97893ee..0000000 --- a/script/hardhat-scripts/upgradeDepositPool.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ethers, upgrades } from 'hardhat' - -async function main() { - const lrtDepositPool = process.env.LRT_DEPOSIT_POOL ?? '' - const lrtDepositPoolFactory = await ethers.getContractFactory('LRTDepositPool') - const lrtDepositPoolInstance = await lrtDepositPoolFactory.attach(lrtDepositPool) - - const lrtDepositPoolUpgraded = await upgrades.upgradeProxy(lrtDepositPoolInstance, lrtDepositPoolFactory) - - console.log('lrt deposit pool proxy address ', lrtDepositPoolUpgraded.address) - - console.log('upgraded lrt deposit pool contract') -} - -main() diff --git a/script/hardhat-scripts/upgradeNDC.ts b/script/hardhat-scripts/upgradeNDC.ts deleted file mode 100644 index 609831b..0000000 --- a/script/hardhat-scripts/upgradeNDC.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ethers, upgrades } from 'hardhat' - -async function main() { - const NDC = process.env.NODE_DELEGATOR ?? '' - const ndcFactory = await ethers.getContractFactory('NodeDelegator') - const ndcInstance = await ndcFactory.attach(NDC) - - const ndcUpgraded = await upgrades.upgradeProxy(ndcInstance, ndcFactory) - - console.log('ndc proxy address ', ndcUpgraded.address) - - console.log('upgraded ndc contract') -} - -main() diff --git a/script/hardhat-scripts/verifyContracts.ts b/script/hardhat-scripts/verifyContracts.ts deleted file mode 100644 index 1cea2ef..0000000 --- a/script/hardhat-scripts/verifyContracts.ts +++ /dev/null @@ -1,42 +0,0 @@ -const hre = require('hardhat') - -// Array of contract addresses to be verified - -const lrtConfig = process.env.LRT_CONFIG ?? '' -const lrtOracle = process.env.LRT_ORACLE ?? '' -const lrtDepositPool = process.env.LRT_DEPOSIT_POOL ?? '' -const rsETH = process.env.RS_ETH ?? '' -const nodeDelegator = process.env.NODE_DELEGATOR ?? '' -const nodeDelegator2 = process.env.NODE_DELEGATOR2 ?? '' -const nodeDelegator3 = process.env.NODE_DELEGATOR3 ?? '' - - -const contractAddresses = [ - lrtConfig, - lrtOracle, - lrtDepositPool, - rsETH, - nodeDelegator, - nodeDelegator2, - nodeDelegator3 -] - -async function main() { - // Loop through all contract addresses and verify them - for (const contractAddress of contractAddresses) { - try { - // Run the hardhat verify task for the current contract address - await hre.run('verify:verify', { - address: contractAddress, - }) - - console.log(`Contract at address ${contractAddress} verified successfully!`) - } catch (error) { - console.error(`Failed to verify contract at address ${contractAddress}.`) - console.error(error) - } - } -} - -// Call the main function to start verifying contracts -main() diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol deleted file mode 100644 index 06f102c..0000000 --- a/test/BaseTest.t.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import { Test } from "forge-std/Test.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract MockToken is ERC20 { - constructor(string memory name, string memory symbol) ERC20(name, symbol) { } - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } -} - -contract BaseTest is Test { - MockToken public stETH; - MockToken public ethX; - - MockToken public rETH; - MockToken public cbETH; - - address public admin = makeAddr("admin"); - - address public alice = makeAddr("alice"); - address public bob = makeAddr("bob"); - address public carol = makeAddr("carol"); - - uint256 public oneThousand = 1000 ** 18; - - function setUp() public virtual { - stETH = new MockToken("staked ETH", "stETH"); - ethX = new MockToken("ETHX", "ethX"); - rETH = new MockToken("rETH", "rETH"); - cbETH = new MockToken("cbETH", "cbETH"); - - // mint LST tokens to alice, bob and carol - mintLSTTokensForUsers(stETH); - mintLSTTokensForUsers(ethX); - mintLSTTokensForUsers(rETH); - mintLSTTokensForUsers(cbETH); - - // give ETH to alice, bob and carol - vm.deal(alice, oneThousand); - vm.deal(bob, oneThousand); - vm.deal(carol, oneThousand); - } - - function mintLSTTokensForUsers(MockToken asset) internal { - asset.mint(alice, oneThousand); - asset.mint(bob, oneThousand); - asset.mint(carol, oneThousand); - } - - /// @dev Expects an event to be emitted by checking all three topics and the data. As mentioned - /// in the Foundry - /// Book, the extra `true` arguments don't hurt. - function expectEmit() internal { - vm.expectEmit({ checkTopic1: true, checkTopic2: true, checkTopic3: true, checkData: true }); - } -} diff --git a/test/ChainlinkPriceOracleTest.t.sol b/test/ChainlinkPriceOracleTest.t.sol deleted file mode 100644 index 21766d1..0000000 --- a/test/ChainlinkPriceOracleTest.t.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import { LRTConfigTest, ILRTConfig, LRTConstants, UtilLib } from "./LRTConfigTest.t.sol"; -import { ChainlinkPriceOracle } from "../contracts/oracles/ChainlinkPriceOracle.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; - -contract MockPriceAggregator { - function decimals() external pure returns (uint8) { - return 18; - } - - function latestRoundData() - external - pure - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - return (0, int256(1 ether + 5), 0, 0, 0); - } -} - -contract ChainlinkPriceOracleTest is LRTConfigTest { - ChainlinkPriceOracle public priceOracle; - - event UpdatedLRTConfig(address indexed lrtConfig); - event AssetPriceFeedUpdate(address indexed asset, address indexed priceFeed); - - function setUp() public virtual override { - super.setUp(); - - // initialize LRTConfig - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - // add manager role - vm.prank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - - ProxyAdmin proxyAdmin = new ProxyAdmin(); - ChainlinkPriceOracle priceOracleImpl = new ChainlinkPriceOracle(); - TransparentUpgradeableProxy priceOracleProxy = - new TransparentUpgradeableProxy(address(priceOracleImpl), address(proxyAdmin), ""); - - priceOracle = ChainlinkPriceOracle(address(priceOracleProxy)); - } -} - -contract ChainlinkPriceOracleInitialize is ChainlinkPriceOracleTest { - function test_RevertInitializeIfAlreadyInitialized() external { - priceOracle.initialize(address(lrtConfig)); - - vm.startPrank(admin); - // cannot initialize again - vm.expectRevert("Initializable: contract is already initialized"); - priceOracle.initialize(address(lrtConfig)); - vm.stopPrank(); - } - - function test_RevertInitializeIfLRTConfigIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - priceOracle.initialize(address(0)); - vm.stopPrank(); - } - - function test_SetInitializableValues() external { - expectEmit(); - emit UpdatedLRTConfig(address(lrtConfig)); - priceOracle.initialize(address(lrtConfig)); - - assertEq(address(priceOracle.lrtConfig()), address(lrtConfig)); - } -} - -contract ChainlinkPriceOracleSetPriceFeed is ChainlinkPriceOracleTest { - MockPriceAggregator public priceFeed; - - function setUp() public override { - super.setUp(); - priceOracle.initialize(address(lrtConfig)); - - priceFeed = new MockPriceAggregator(); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - priceOracle.updatePriceFeedFor(address(ethX), address(priceFeed)); - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.startPrank(manager); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - priceOracle.updatePriceFeedFor(randomAddress, address(priceFeed)); - vm.stopPrank(); - } - - function test_RevertWhenPriceFeedIsZero() external { - vm.startPrank(manager); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - priceOracle.updatePriceFeedFor(address(ethX), address(0)); - vm.stopPrank(); - } - - function test_SetAssetPriceFeed() external { - assertEq(priceOracle.assetPriceFeed(address(ethX)), address(0)); - - vm.startPrank(manager); - expectEmit(); - emit AssetPriceFeedUpdate(address(ethX), address(priceFeed)); - priceOracle.updatePriceFeedFor(address(ethX), address(priceFeed)); - vm.stopPrank(); - - assertEq(priceOracle.assetPriceFeed(address(ethX)), address(priceFeed)); - } -} - -contract ChainlinkPriceOracleFetchAssetPrice is ChainlinkPriceOracleTest { - MockPriceAggregator public priceFeed; - - function setUp() public override { - super.setUp(); - priceOracle.initialize(address(lrtConfig)); - priceFeed = new MockPriceAggregator(); - - vm.prank(manager); - priceOracle.updatePriceFeedFor(address(ethX), address(priceFeed)); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - priceOracle.getAssetPrice(randomAddress); - } - - function test_FetchAssetPrice() external { - uint256 ethXPrice = priceOracle.getAssetPrice(address(ethX)); - assertEq(ethXPrice, 1 ether + 5); - } -} diff --git a/test/LRTConfigTest.t.sol b/test/LRTConfigTest.t.sol deleted file mode 100644 index 1884b48..0000000 --- a/test/LRTConfigTest.t.sol +++ /dev/null @@ -1,446 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import { BaseTest, MockToken } from "./BaseTest.t.sol"; -import { LRTConfig, ILRTConfig } from "contracts/LRTConfig.sol"; -import { LRTConstants } from "contracts/utils/LRTConstants.sol"; -import { UtilLib } from "contracts/utils/UtilLib.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; - -contract MockStrategy { - IERC20 public underlyingToken_; - uint256 public mockUserUnderlyingViewBal; - - constructor(address _underlyingToken, uint256 _mockUserUnderlyingViewBal) { - underlyingToken_ = IERC20(_underlyingToken); - - mockUserUnderlyingViewBal = _mockUserUnderlyingViewBal; - } - - function underlyingToken() external view returns (IERC20) { - return underlyingToken_; - } - - function userUnderlyingView(address) external view returns (uint256) { - return mockUserUnderlyingViewBal; - } -} - -contract MockLRTDepositPool { - address public ndc1; - address public ndc2; - - constructor() { - ndc1 = address(0x1); - ndc2 = address(0x2); - } - - function getNodeDelegatorQueue() external view returns (address[] memory) { - address[] memory ndcs = new address[](2); - ndcs[0] = ndc1; - ndcs[1] = ndc2; - - return ndcs; - } -} - -contract LRTConfigTest is BaseTest { - LRTConfig public lrtConfig; - - event AssetDepositLimitUpdate(address indexed asset, uint256 depositLimit); - event RemovedSupportedAsset(address indexed asset); - - address public manager; - address public rsethMock; - - function setUp() public virtual override { - super.setUp(); - - manager = makeAddr("manager"); - rsethMock = makeAddr("rsethMock"); - - ProxyAdmin proxyAdmin = new ProxyAdmin(); - LRTConfig lrtConfigImpl = new LRTConfig(); - TransparentUpgradeableProxy lrtConfigProxy = - new TransparentUpgradeableProxy(address(lrtConfigImpl), address(proxyAdmin), ""); - - lrtConfig = LRTConfig(address(lrtConfigProxy)); - } -} - -contract LRTConfigInitialize is LRTConfigTest { - function test_RevertInitializeIfAlreadyInitialized() external { - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - vm.startPrank(admin); - // cannot initialize again - vm.expectRevert("Initializable: contract is already initialized"); - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - vm.stopPrank(); - } - - function test_RevertInitializeIfAdminIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.initialize(address(0), address(stETH), address(ethX), rsethMock); - vm.stopPrank(); - } - - function test_RevertInitializeIfStETHIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.initialize(admin, address(0), address(ethX), rsethMock); - vm.stopPrank(); - } - - function test_RevertInitializeIfETHXIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.initialize(admin, address(stETH), address(0), rsethMock); - vm.stopPrank(); - } - - function test_RevertWhenRSETHIsZeroAddress() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.initialize(admin, address(stETH), address(ethX), address(0)); - vm.stopPrank(); - } - - function test_SetInitializableValues() external { - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - assertEq(lrtConfig.tokenMap(LRTConstants.ST_ETH_TOKEN), address(stETH)); - assertEq(lrtConfig.tokenMap(LRTConstants.ETHX_TOKEN), address(ethX)); - - assertTrue(lrtConfig.hasRole(lrtConfig.DEFAULT_ADMIN_ROLE(), admin)); - - uint256 depositLimit = 100_000 ether; - assertEq(lrtConfig.depositLimitByAsset(address(stETH)), depositLimit); - assertEq(lrtConfig.depositLimitByAsset(address(ethX)), depositLimit); - } -} - -contract LRTConfigAddNewSupportedAssetTest is LRTConfigTest { - function setUp() public override { - super.setUp(); - - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - vm.stopPrank(); - } - - function test_RevertWhenAssetIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.addNewSupportedAsset(address(0), 1000); - vm.stopPrank(); - } - - function test_RevertAddNewSupportedAssetIfNotAdmin() external { - vm.startPrank(alice); - vm.expectRevert( - "AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.addNewSupportedAsset(address(stETH), 1000); - vm.stopPrank(); - } - - function test_RevertAddNewSupportedAssetIfAssetAlreadySupported() external { - vm.startPrank(admin); - vm.expectRevert(ILRTConfig.AssetAlreadySupported.selector); - lrtConfig.addNewSupportedAsset(address(stETH), 1000); - vm.stopPrank(); - } - - function test_AddNewSupportedAsset() external { - uint256 depositLimit = 1000; - MockToken newToken = new MockToken("New Token", "NT"); - - vm.startPrank(admin); - lrtConfig.addNewSupportedAsset(address(newToken), depositLimit); - vm.stopPrank(); - - assertEq(lrtConfig.depositLimitByAsset(address(newToken)), depositLimit); - } -} - -contract LRTConfigUpdateAssetDepositLimitTest is LRTConfigTest { - function setUp() public override { - super.setUp(); - - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - vm.stopPrank(); - } - - function test_RevertUpdateAssetDepositLimitIfNotManager() external { - vm.startPrank(alice); - vm.expectRevert( - "AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0xaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c" - ); - lrtConfig.updateAssetDepositLimit(address(stETH), 1000); - vm.stopPrank(); - } - - function test_RevertUpdateAssetDepositLimitWhenNotAcceptedAsset() external { - vm.startPrank(manager); - MockToken randomToken = new MockToken("Random Token", "RT"); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtConfig.updateAssetDepositLimit(address(randomToken), 1000); - vm.stopPrank(); - } - - function test_UpdateAssetDepositLimit() external { - uint256 depositLimit = 1000; - - vm.startPrank(manager); - lrtConfig.updateAssetDepositLimit(address(stETH), depositLimit); - - expectEmit(); - emit AssetDepositLimitUpdate(address(ethX), depositLimit); - lrtConfig.updateAssetDepositLimit(address(ethX), depositLimit); - - vm.stopPrank(); - - assertEq(lrtConfig.depositLimitByAsset(address(stETH)), depositLimit); - assertEq(lrtConfig.depositLimitByAsset(address(ethX)), depositLimit); - } -} - -contract LRTConfigUpdateAssetStrategyTest is LRTConfigTest { - address public strategy; - address public depositPool; - - function setUp() public override { - super.setUp(); - - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - // set deposit pool address in config contract - bytes32 depositPoolKey = LRTConstants.LRT_DEPOSIT_POOL; - depositPool = address(new MockLRTDepositPool()); - lrtConfig.setContract(depositPoolKey, depositPool); - vm.stopPrank(); - } - - function test_RevertUpdateAssetStrategyIfNotAdmin() external { - vm.startPrank(alice); - vm.expectRevert( - "AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.updateAssetStrategy(address(stETH), address(this)); - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupported() external { - MockToken randomToken = new MockToken("Random Token", "RT"); - address strategy = address(new MockStrategy(address(randomToken), 1 ether)); - - vm.startPrank(admin); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtConfig.updateAssetStrategy(address(randomToken), strategy); - vm.stopPrank(); - } - - function test_RevertWhenStrategyAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.updateAssetStrategy(address(stETH), address(0)); - vm.stopPrank(); - } - - function test_RevertWhenSameStrategyWasAlreadyAddedBeforeForAsset() external { - address strategy = address(new MockStrategy(address(stETH), 1 ether)); - vm.startPrank(admin); - lrtConfig.updateAssetStrategy(address(stETH), strategy); - - // revert when same strategy was already added before for asset - vm.expectRevert(ILRTConfig.ValueAlreadyInUse.selector); - lrtConfig.updateAssetStrategy(address(stETH), strategy); - vm.stopPrank(); - } - - function test_RevertWhenStrategyHasFundsInNDC() external { - address strategy = address(new MockStrategy(address(stETH), 1 ether)); - vm.startPrank(admin); - lrtConfig.updateAssetStrategy(address(stETH), strategy); - - // revert when strategy has funds in NDC - address newStrategy = address(new MockStrategy(address(stETH), 0)); - bytes memory errorData = abi.encodeWithSelector( - ILRTConfig.CannotUpdateStrategyAsItHasFundsNDCFunds.selector, - MockLRTDepositPool(depositPool).ndc1(), - 1 ether - ); - - vm.expectRevert(errorData); - lrtConfig.updateAssetStrategy(address(stETH), newStrategy); - vm.stopPrank(); - } - - function test_UpdateAssetStrategy() external { - address strategy = address(new MockStrategy(address(stETH), 0)); - - vm.startPrank(admin); - lrtConfig.updateAssetStrategy(address(stETH), strategy); - vm.stopPrank(); - - assertEq(lrtConfig.assetStrategy(address(stETH)), strategy); - } -} - -contract LRTConfigGettersTest is LRTConfigTest { - function setUp() public override { - super.setUp(); - - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - vm.stopPrank(); - } - - function test_GetLSTToken() external { - assertEq(lrtConfig.getLSTToken(LRTConstants.ST_ETH_TOKEN), address(stETH)); - assertEq(lrtConfig.getLSTToken(LRTConstants.ETHX_TOKEN), address(ethX)); - } - - function test_GetContract() external { - vm.startPrank(admin); - address oracle = makeAddr("oracle"); - address depositPool = makeAddr("depositPool"); - address eigenStrategyManager = makeAddr("eigenStrategyManager"); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, oracle); - lrtConfig.setContract(LRTConstants.LRT_DEPOSIT_POOL, depositPool); - lrtConfig.setContract(LRTConstants.EIGEN_STRATEGY_MANAGER, eigenStrategyManager); - vm.stopPrank(); - - assertEq(lrtConfig.getContract(LRTConstants.LRT_ORACLE), address(oracle)); - assertEq(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL), address(depositPool)); - assertEq(lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER), address(eigenStrategyManager)); - } -} - -contract LRTConfigSettersTest is LRTConfigTest { - address public newRSETH; - - function setUp() public override { - super.setUp(); - - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - vm.stopPrank(); - - newRSETH = makeAddr("newRSETH"); - } - - function test_RevertSetRSETHIfNotAdmin() external { - vm.startPrank(alice); - vm.expectRevert( - "AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.setRSETH(newRSETH); - vm.stopPrank(); - } - - function test_RevertSetRSETHIfRSETHAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.setRSETH(address(0)); - vm.stopPrank(); - } - - function test_SetRSETH() external { - vm.startPrank(admin); - lrtConfig.setRSETH(newRSETH); - vm.stopPrank(); - - assertEq(lrtConfig.rsETH(), newRSETH); - } - - function test_RevertSetTokenIfNotAdmin() external { - vm.startPrank(alice); - vm.expectRevert( - "AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, address(this)); - vm.stopPrank(); - } - - function test_RevertSetTokenIfTokenAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, address(0)); - vm.stopPrank(); - } - - function test_RevertSetTokenIfTokenAlreadySet() external { - address newToken = makeAddr("newToken"); - vm.startPrank(admin); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, newToken); - - // revert when same token was already set before - vm.expectRevert(ILRTConfig.ValueAlreadyInUse.selector); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, newToken); - vm.stopPrank(); - } - - function test_SetToken() external { - address newToken = makeAddr("newToken"); - - vm.startPrank(admin); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, newToken); - vm.stopPrank(); - - assertEq(lrtConfig.tokenMap(LRTConstants.ST_ETH_TOKEN), newToken); - } - - function test_RevertSetContractIfNotAdmin() external { - vm.startPrank(alice); - vm.expectRevert( - "AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(this)); - vm.stopPrank(); - } - - function test_RevertSetContractIfContractAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(0)); - vm.stopPrank(); - } - - function test_RevertSetContractIfContractAlreadySet() external { - address newContract = makeAddr("newContract"); - vm.startPrank(admin); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, newContract); - - // revert when same contract was already set before - vm.expectRevert(ILRTConfig.ValueAlreadyInUse.selector); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, newContract); - vm.stopPrank(); - } - - function test_SetContract() external { - address newContract = makeAddr("newContract"); - - vm.startPrank(admin); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, newContract); - vm.stopPrank(); - - assertEq(lrtConfig.contractMap(LRTConstants.LRT_ORACLE), newContract); - } -} diff --git a/test/LRTDepositPoolTest.t.sol b/test/LRTDepositPoolTest.t.sol deleted file mode 100644 index 8c22c88..0000000 --- a/test/LRTDepositPoolTest.t.sol +++ /dev/null @@ -1,1091 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import { BaseTest } from "./BaseTest.t.sol"; -import { LRTDepositPool } from "contracts/LRTDepositPool.sol"; -import { RSETHTest, ILRTConfig, UtilLib, LRTConstants } from "./RSETHTest.t.sol"; -import { ILRTDepositPool } from "contracts/interfaces/ILRTDepositPool.sol"; - -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -contract LRTOracleMock { - function getAssetPrice(address) external pure returns (uint256) { - return 1e18; - } - - function rsETHPrice() external pure returns (uint256) { - return 1e18; - } -} - -contract MockNodeDelegator { - address[] public assets; - uint256[] public assetBalances; - uint256 public mockAssetBalance; - - uint256 private _stakedButUnverifiedNativeETH; - uint256 private _eigenPodBalance; - - constructor(address[] memory _assets, uint256[] memory _assetBalances) { - assets = _assets; - assetBalances = _assetBalances; - mockAssetBalance = 1e18; - } - - function getAssetBalance(address) external view returns (uint256) { - return mockAssetBalance; - } - - function getAssetBalances() external view returns (address[] memory, uint256[] memory) { - return (assets, assetBalances); - } - - function getETHEigenPodBalance() external view returns (uint256) { - return _eigenPodBalance; - } - - function removeAssetBalance() external { - assetBalances[0] = 0; - assetBalances[1] = 0; - mockAssetBalance = 0; - } - - function transferBackToLRTDepositPool(address asset, uint256 amount) external { - // do nothing - } - - function sendETHFromDepositPoolToNDC() external payable { - // do nothing - } - - function stakedButUnverifiedNativeETH() external view returns (uint256) { - return _stakedButUnverifiedNativeETH; - } - - function setStakedButUnverifiedNativeETH(uint256 amount) external { - _stakedButUnverifiedNativeETH = amount; - } - - function setEigenPodBalance(uint256 amount) external { - _eigenPodBalance = amount; - } -} - -contract LRTDepositPoolTest is BaseTest, RSETHTest { - LRTDepositPool public lrtDepositPool; - - uint256 public minimunAmountOfRSETHToReceive; - string public referralId; - - event ETHDeposit(address indexed depositor, uint256 depositAmount, uint256 rsethMintAmount, string referralId); - - function setUp() public virtual override(RSETHTest, BaseTest) { - super.setUp(); - - // deploy LRTDepositPool - ProxyAdmin proxyAdmin = new ProxyAdmin(); - LRTDepositPool contractImpl = new LRTDepositPool(); - TransparentUpgradeableProxy contractProxy = - new TransparentUpgradeableProxy(address(contractImpl), address(proxyAdmin), ""); - - lrtDepositPool = LRTDepositPool(payable(contractProxy)); - - // initialize RSETH. LRTCOnfig is already initialized in RSETHTest - rseth.initialize(address(admin), address(lrtConfig)); - vm.startPrank(admin); - // add rsETH to LRT config - lrtConfig.setRSETH(address(rseth)); - // add oracle to LRT config - lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(new LRTOracleMock())); - - // add minter role for rseth to lrtDepositPool - lrtConfig.grantRole(LRTConstants.MINTER_ROLE, address(lrtDepositPool)); - - vm.stopPrank(); - - minimunAmountOfRSETHToReceive = 0; - referralId = "42"; - - // add manager role within LRTConfig - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - // set ETH as supported token - lrtConfig.addNewSupportedAsset(LRTConstants.ETH_TOKEN, 100_000 ether); - vm.stopPrank(); - } -} - -contract LRTDepositPoolInitialize is LRTDepositPoolTest { - function test_RevertWhenLRTConfigIsZeroAddress() external { - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtDepositPool.initialize(address(0)); - } - - function test_InitializeContractsVariables() external { - lrtDepositPool.initialize(address(lrtConfig)); - - assertEq(lrtDepositPool.maxNodeDelegatorLimit(), 10, "Max node delegator count is not set"); - assertEq(address(lrtConfig), address(lrtDepositPool.lrtConfig()), "LRT config address is not set"); - } -} - -contract LRTDepositPoolDepositETH is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_RevertWhenDepositAmountIsZero() external { - vm.expectRevert(ILRTDepositPool.InvalidAmountToDeposit.selector); - lrtDepositPool.depositETH{ value: 0 }(minimunAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenDepositAmountIsLessThanMinAmountToDeposit() external { - uint256 minAmountToDeposit = lrtDepositPool.minAmountToDeposit(); - uint256 amountToDeposit = minAmountToDeposit / 2; - - vm.expectRevert(ILRTDepositPool.InvalidAmountToDeposit.selector); - lrtDepositPool.depositETH{ value: amountToDeposit }(minimunAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenMinAmountToReceiveIsNotMetWhenCallingDepositETH() external { - vm.startPrank(alice); - - // increase the minimum amount of rsETH to receive to an amount that is not met - minimunAmountOfRSETHToReceive = 100 ether; - - vm.expectRevert(ILRTDepositPool.MinimumAmountToReceiveNotMet.selector); - lrtDepositPool.depositETH{ value: 1 ether }(minimunAmountOfRSETHToReceive, referralId); - - vm.stopPrank(); - } - - function test_DepositETH() external { - vm.startPrank(alice); - - // alice balance of rsETH before deposit - uint256 aliceBalanceBefore = rseth.balanceOf(address(alice)); - - minimunAmountOfRSETHToReceive = lrtDepositPool.getRsETHAmountToMint(LRTConstants.ETH_TOKEN, 1 ether); - - expectEmit(); - emit ETHDeposit(alice, 1 ether, minimunAmountOfRSETHToReceive, referralId); - lrtDepositPool.depositETH{ value: 1 ether }(minimunAmountOfRSETHToReceive, referralId); - - // alice balance of rsETH after deposit - uint256 aliceBalanceAfter = rseth.balanceOf(address(alice)); - vm.stopPrank(); - - assertEq(address(lrtDepositPool).balance, 1 ether, "Total ETH deposits is not set"); - assertGt(aliceBalanceAfter + 1, aliceBalanceBefore + minimunAmountOfRSETHToReceive, "Alice balance is not set"); - } -} - -contract LRTDepositPoolDepositAsset is LRTDepositPoolTest { - address public ethXAddress; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - ethXAddress = address(ethX); - } - - function test_RevertWhenDepositAmountIsZero() external { - vm.expectRevert(ILRTDepositPool.InvalidAmountToDeposit.selector); - lrtDepositPool.depositAsset(ethXAddress, 0, minimunAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenDepositAmountIsLessThanMinAmountToDeposit() external { - vm.startPrank(admin); - lrtDepositPool.setMinAmountToDeposit(1 ether); - vm.stopPrank(); - - vm.expectRevert(ILRTDepositPool.InvalidAmountToDeposit.selector); - lrtDepositPool.depositAsset(ethXAddress, 0.5 ether, minimunAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAsset = makeAddr("randomAsset"); - - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtDepositPool.depositAsset(randomAsset, 1 ether, minimunAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenDepositAmountExceedsLimit() external { - vm.prank(manager); - lrtConfig.updateAssetDepositLimit(ethXAddress, 1 ether); - - vm.expectRevert(ILRTDepositPool.MaximumDepositLimitReached.selector); - lrtDepositPool.depositAsset(ethXAddress, 2 ether, minimunAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenMinAmountToReceiveIsNotMet() external { - vm.startPrank(alice); - - ethX.approve(address(lrtDepositPool), 2 ether); - - // increase the minimum amount of rsETH to receive to an amount that is not met - minimunAmountOfRSETHToReceive = 100 ether; - - vm.expectRevert(ILRTDepositPool.MinimumAmountToReceiveNotMet.selector); - lrtDepositPool.depositAsset(ethXAddress, 0.5 ether, minimunAmountOfRSETHToReceive, referralId); - - vm.stopPrank(); - } - - function test_DepositAsset() external { - vm.startPrank(alice); - - // alice balance of rsETH before deposit - uint256 aliceBalanceBefore = rseth.balanceOf(address(alice)); - - minimunAmountOfRSETHToReceive = lrtDepositPool.getRsETHAmountToMint(ethXAddress, 2 ether); - - ethX.approve(address(lrtDepositPool), 2 ether); - lrtDepositPool.depositAsset(ethXAddress, 2 ether, minimunAmountOfRSETHToReceive, referralId); - - // alice balance of rsETH after deposit - uint256 aliceBalanceAfter = rseth.balanceOf(address(alice)); - vm.stopPrank(); - - assertEq(lrtDepositPool.getTotalAssetDeposits(ethXAddress), 2 ether, "Total asset deposits is not set"); - assertGt(aliceBalanceAfter, aliceBalanceBefore, "Alice balance is not set"); - } - - function test_FuzzDepositAsset(uint256 amountDeposited) external { - uint256 stETHDepositLimit = lrtConfig.depositLimitByAsset(address(stETH)); - vm.assume(amountDeposited > 0 && amountDeposited <= stETHDepositLimit); - - uint256 aliceBalanceBefore = rseth.balanceOf(address(alice)); - - vm.startPrank(alice); - stETH.approve(address(lrtDepositPool), amountDeposited); - lrtDepositPool.depositAsset(address(stETH), amountDeposited, minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - uint256 aliceBalanceAfter = rseth.balanceOf(address(alice)); - - assertEq( - lrtDepositPool.getTotalAssetDeposits(address(stETH)), amountDeposited, "Total asset deposits is not set" - ); - assertGt(aliceBalanceAfter, aliceBalanceBefore, "Alice balance is not set"); - } -} - -contract LRTDepositPoolGetRsETHAmountToMint is LRTDepositPoolTest { - address public ethXAddress; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - ethXAddress = address(ethX); - } - - function test_GetRsETHAmountToMintWhenAssetIsLST() external { - uint256 amountToDeposit = 1 ether; - vm.startPrank(manager); - lrtConfig.updateAssetDepositLimit(ethXAddress, amountToDeposit); - vm.stopPrank(); - - assertEq( - lrtDepositPool.getRsETHAmountToMint(ethXAddress, amountToDeposit), - 1 ether, - "RsETH amount to mint is incorrect" - ); - } - - function test_GetRsETHAmountToMintWhenAssetisNativeETH() external { - uint256 amountToDeposit = 1 ether; - - assertEq( - lrtDepositPool.getRsETHAmountToMint(address(0), amountToDeposit), - 1 ether, - "RsETH amount to mint is incorrect" - ); - } -} - -contract LRTDepositPoolGetAssetCurrentLimit is LRTDepositPoolTest { - address public ethXAddress; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - ethXAddress = address(ethX); - } - - function test_GetAssetCurrentLimit() external { - vm.startPrank(manager); - lrtConfig.updateAssetDepositLimit(address(stETH), 1 ether); - vm.stopPrank(); - - assertEq(lrtDepositPool.getAssetCurrentLimit(address(stETH)), 1 ether, "Asset current limit is not set"); - } - - function test_GetAssetCurrentLimitAfterAssetIsDeposited() external { - vm.startPrank(manager); - lrtConfig.updateAssetDepositLimit(address(stETH), 10 ether); - vm.stopPrank(); - - // deposit 1 ether stETH - vm.startPrank(alice); - stETH.approve(address(lrtDepositPool), 6 ether); - lrtDepositPool.depositAsset(address(stETH), 6 ether, minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - assertEq(lrtDepositPool.getAssetCurrentLimit(address(stETH)), 4 ether, "Asset current limit is not set"); - } -} - -contract LRTDepositPoolGetNodeDelegatorQueue is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_GetNodeDelegatorQueue() external { - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - - address nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - address[] memory nodeDelegatorQueue = new address[](3); - nodeDelegatorQueue[0] = nodeDelegatorContractOne; - nodeDelegatorQueue[1] = nodeDelegatorContractTwo; - nodeDelegatorQueue[2] = nodeDelegatorContractThree; - - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueue); - vm.stopPrank(); - - assertEq(lrtDepositPool.getNodeDelegatorQueue(), nodeDelegatorQueue, "Node delegator queue is not set"); - } -} - -contract LRTDepositPoolGetTotalAssetDeposits is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_GetTotalAssetDeposits() external { - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - - address nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - address[] memory nodeDelegatorQueue = new address[](3); - nodeDelegatorQueue[0] = nodeDelegatorContractOne; - nodeDelegatorQueue[1] = nodeDelegatorContractTwo; - nodeDelegatorQueue[2] = nodeDelegatorContractThree; - - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueue); - vm.stopPrank(); - - uint256 amountToDeposit = 1 ether; - - uint256 totalDepositsBefore = lrtDepositPool.getTotalAssetDeposits(address(ethX)); - - // deposit ethX - vm.startPrank(alice); - ethX.approve(address(lrtDepositPool), amountToDeposit); - lrtDepositPool.depositAsset(address(ethX), amountToDeposit, minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - assertEq( - lrtDepositPool.getTotalAssetDeposits(address(ethX)), - totalDepositsBefore + amountToDeposit, - "Incorrect total asset deposits amount" - ); - } -} - -contract LRTDepositPoolGetAssetDistributionData is LRTDepositPoolTest { - address public ethXAddress; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - ethXAddress = address(ethX); - } - - function test_GetAssetDistributionData() external { - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - - address nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - address[] memory nodeDelegatorQueue = new address[](3); - nodeDelegatorQueue[0] = nodeDelegatorContractOne; - nodeDelegatorQueue[1] = nodeDelegatorContractTwo; - nodeDelegatorQueue[2] = nodeDelegatorContractThree; - - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueue); - vm.stopPrank(); - - // deposit 3 ether ethX - vm.startPrank(alice); - ethX.approve(address(lrtDepositPool), 3 ether); - lrtDepositPool.depositAsset(ethXAddress, 3 ether, minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - (uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer) = - lrtDepositPool.getAssetDistributionData(ethXAddress); - - assertEq(assetLyingInDepositPool, 3 ether, "Asset lying in deposit pool is not set"); - assertEq(assetLyingInNDCs, 0, "Asset lying in NDCs is not set"); - assertEq(assetStakedInEigenLayer, 3 ether, "Asset staked in eigen layer is not set"); - } -} - -contract LRTDepositPoolGetETHDistributionData is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_GetETHDistributionData() external { - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - - address nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - address nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - address[] memory nodeDelegatorQueue = new address[](3); - nodeDelegatorQueue[0] = nodeDelegatorContractOne; - nodeDelegatorQueue[1] = nodeDelegatorContractTwo; - nodeDelegatorQueue[2] = nodeDelegatorContractThree; - - // mock adding function from NodeDelegator contract to EigenLayer - MockNodeDelegator(nodeDelegatorContractOne).setEigenPodBalance(1 ether); - MockNodeDelegator(nodeDelegatorContractTwo).setEigenPodBalance(1 ether); - MockNodeDelegator(nodeDelegatorContractThree).setEigenPodBalance(1 ether); - - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueue); - vm.stopPrank(); - - // deposit 3 ether - vm.startPrank(alice); - lrtDepositPool.depositETH{ value: 5 ether }(minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - (uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer) = - lrtDepositPool.getETHDistributionData(); - - assertEq(ethLyingInDepositPool, 5 ether, "ETH lying in deposit pool is not set"); - assertEq(ethLyingInNDCs, 0, "ETH lying in NDCs is not set"); - assertEq(ethStakedInEigenLayer, 3 ether, "ETH staked in eigen layer is not set First test"); - - // check using getAssetDistributionData - (ethLyingInDepositPool, ethLyingInNDCs, ethStakedInEigenLayer) = - lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - - assertEq(ethLyingInDepositPool, 5 ether, "ETH lying in deposit pool is not set"); - assertEq(ethLyingInNDCs, 0, "ETH lying in NDCs is not set"); - assertEq(ethStakedInEigenLayer, 3 ether, "ETH staked in eigen layer is not set Second Test"); - } -} - -contract LRTDepositPoolAddNodeDelegatorContractToQueue is LRTDepositPoolTest { - address public nodeDelegatorContractOne; - address public nodeDelegatorContractTwo; - address public nodeDelegatorContractThree; - - address[] public nodeDelegatorQueueProspectives; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - - nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - nodeDelegatorQueueProspectives.push(nodeDelegatorContractOne); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractTwo); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractThree); - } - - function test_RevertWhenNotCalledByLRTConfigAdmin() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - - vm.stopPrank(); - } - - function test_RevertWhenNodeDelegatorLimitExceedsLimit() external { - vm.startPrank(admin); - - uint256 maxDelegatorCount = lrtDepositPool.maxNodeDelegatorLimit(); - - for (uint256 i = 0; i < maxDelegatorCount; i++) { - address madeUpNodeDelegatorAddress = makeAddr(string(abi.encodePacked("nodeDelegatorContract", i))); - - address[] memory nodeDelegatorContractArray = new address[](1); - nodeDelegatorContractArray[0] = madeUpNodeDelegatorAddress; - - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorContractArray); - } - - // add one more node delegator contract to go above limit - vm.expectRevert(ILRTDepositPool.MaximumNodeDelegatorLimitReached.selector); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - - vm.stopPrank(); - } - - function test_AddNodeDelegatorContractToQueue() external { - // get node delegator queue length before adding node delegator contracts - uint256 nodeDelegatorQueueLengthBefore = lrtDepositPool.getNodeDelegatorQueue().length; - - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - - // assert node delegator queue length is the same as nodeDelegatorQueueProspectives length - assertEq( - lrtDepositPool.getNodeDelegatorQueue().length, - nodeDelegatorQueueProspectives.length + nodeDelegatorQueueLengthBefore, - "Node delegator queue length is not set" - ); - - assertEq( - lrtDepositPool.nodeDelegatorQueue(0), - nodeDelegatorQueueProspectives[0], - "Node delegator index 0 contract is not added" - ); - assertEq( - lrtDepositPool.nodeDelegatorQueue(1), - nodeDelegatorQueueProspectives[1], - "Node delegator index 1 contract is not added" - ); - assertEq( - lrtDepositPool.nodeDelegatorQueue(2), - nodeDelegatorQueueProspectives[2], - "Node delegator index 2 contract is not added" - ); - - // if we add the same node delegator contract again, it should not be added - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - - assertEq( - lrtDepositPool.getNodeDelegatorQueue().length, - nodeDelegatorQueueProspectives.length + nodeDelegatorQueueLengthBefore, - "Node delegator queue length is not set" - ); - vm.stopPrank(); - } -} - -contract LRTDepositPoolRemoveNodeDelegatorFromQueue is LRTDepositPoolTest { - address public nodeDelegatorContractOne; - address public nodeDelegatorContractTwo; - address public nodeDelegatorContractThree; - - address[] public nodeDelegatorQueueProspectives; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - - nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - nodeDelegatorQueueProspectives.push(nodeDelegatorContractOne); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractTwo); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractThree); - - // add node delegator contracts to queue - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - vm.stopPrank(); - } - - function test_RevertWhenNotCalledByLRTConfigAdmin() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.removeNodeDelegatorContractFromQueue(address(nodeDelegatorContractOne)); - - vm.stopPrank(); - } - - function test_RevertWhenNodeDelegatorIndexIsNotValid() external { - address nodeDelegatorContractFour = address(new MockNodeDelegator(new address[](0), new uint256[](0))); - - vm.startPrank(admin); - - vm.expectRevert(ILRTDepositPool.NodeDelegatorNotFound.selector); - lrtDepositPool.removeNodeDelegatorContractFromQueue(nodeDelegatorContractFour); - - vm.stopPrank(); - } - - function test_RevertWhenNodeDelegatorHasAssetBalance() external { - vm.startPrank(admin); - - uint256 amountToDeposit = 1 ether; - bytes memory errorData = abi.encodeWithSelector( - ILRTDepositPool.NodeDelegatorHasAssetBalance.selector, - address(stETH), // asset - amountToDeposit // asset balance - ); - - vm.expectRevert(errorData); - lrtDepositPool.removeNodeDelegatorContractFromQueue(nodeDelegatorContractOne); - - vm.stopPrank(); - } - - function test_RemoveNodeDelegatorContractFromQueue() external { - // mock contract function to remove asset balance from node delegator contract two - MockNodeDelegator(nodeDelegatorContractTwo).removeAssetBalance(); - - // remove node delegator contract one from queue - vm.startPrank(admin); - lrtDepositPool.removeNodeDelegatorContractFromQueue(nodeDelegatorContractTwo); - vm.stopPrank(); - - assertEq(lrtDepositPool.getNodeDelegatorQueue().length, 2, "Node delegator queue length is not set"); - assertEq( - lrtDepositPool.nodeDelegatorQueue(0), nodeDelegatorContractOne, "Node delegator index 0 contract is not set" - ); - assertEq( - lrtDepositPool.nodeDelegatorQueue(1), - nodeDelegatorContractThree, - "Node delegator index 1 contract is not set" - ); - } - - function test_RemoveManyNodeDelegatorContractsFromQueue() external { - // mock contract function to remove asset balance from node delegator contract one - MockNodeDelegator(nodeDelegatorContractOne).removeAssetBalance(); - MockNodeDelegator(nodeDelegatorContractTwo).removeAssetBalance(); - - // remove node delegator contract one from queue - address[] memory nodeDelegatorContractsToRemove = new address[](2); - nodeDelegatorContractsToRemove[0] = nodeDelegatorContractOne; - nodeDelegatorContractsToRemove[1] = nodeDelegatorContractTwo; - - vm.startPrank(admin); - lrtDepositPool.removeManyNodeDelegatorContractsFromQueue(nodeDelegatorContractsToRemove); - vm.stopPrank(); - - assertEq(lrtDepositPool.getNodeDelegatorQueue().length, 1, "Node delegator queue length is not set"); - assertEq( - lrtDepositPool.nodeDelegatorQueue(0), - nodeDelegatorContractThree, - "Node delegator index 0 contract is not set" - ); - } -} - -contract LRTDepositPoolTransferAssetToNodeDelegator is LRTDepositPoolTest { - address public nodeDelegatorContractOne; - address public nodeDelegatorContractTwo; - address public nodeDelegatorContractThree; - - address[] public nodeDelegatorQueueProspectives; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - nodeDelegatorQueueProspectives.push(nodeDelegatorContractOne); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractTwo); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractThree); - - // add node delegator contracts to queue - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - vm.stopPrank(); - } - - function test_RevertWhenNotCalledByLRTConfigManager() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - lrtDepositPool.transferAssetToNodeDelegator(0, address(ethX), 1 ether); - - vm.stopPrank(); - } - - function test_TransferAssetToNodeDelegator() external { - // deposit 3 ether ethX - vm.startPrank(alice); - ethX.approve(address(lrtDepositPool), 3 ether); - lrtDepositPool.depositAsset(address(ethX), 3 ether, minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - uint256 indexOfNodeDelegatorContractOneInNDArray; - address[] memory nodeDelegatorArray = lrtDepositPool.getNodeDelegatorQueue(); - for (uint256 i = 0; i < nodeDelegatorArray.length; i++) { - if (lrtDepositPool.nodeDelegatorQueue(i) == nodeDelegatorContractOne) { - indexOfNodeDelegatorContractOneInNDArray = i; - break; - } - } - - // transfer 1 ether ethX to node delegator contract one - vm.startPrank(manager); - lrtDepositPool.transferAssetToNodeDelegator(indexOfNodeDelegatorContractOneInNDArray, address(ethX), 1 ether); - vm.stopPrank(); - - assertEq(ethX.balanceOf(address(lrtDepositPool)), 2 ether, "Asset amount in lrtDepositPool is incorrect"); - assertEq(ethX.balanceOf(nodeDelegatorContractOne), 1 ether, "Asset is not transferred to node delegator"); - } -} - -contract LRTDepositTransferETHToNodeDelegator is LRTDepositPoolTest { - address public nodeDelegatorContractOne; - address public nodeDelegatorContractTwo; - address public nodeDelegatorContractThree; - - address[] public nodeDelegatorQueueProspectives; - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - address[] memory assets = new address[](2); - assets[0] = address(stETH); - assets[1] = address(ethX); - - uint256[] memory assetBalances = new uint256[](2); - assetBalances[0] = 1 ether; - assetBalances[1] = 1 ether; - nodeDelegatorContractOne = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractTwo = address(new MockNodeDelegator(assets, assetBalances)); - nodeDelegatorContractThree = address(new MockNodeDelegator(assets, assetBalances)); - - nodeDelegatorQueueProspectives.push(nodeDelegatorContractOne); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractTwo); - nodeDelegatorQueueProspectives.push(nodeDelegatorContractThree); - - // add node delegator contracts to queue - vm.startPrank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(nodeDelegatorQueueProspectives); - vm.stopPrank(); - } - - function test_RevertWhenNotCalledByLRTConfigManager() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - lrtDepositPool.transferETHToNodeDelegator(0, 1 ether); - - vm.stopPrank(); - } - - function test_TransferETHToNodeDelegator() external { - // deposit 3 ether - vm.startPrank(alice); - lrtDepositPool.depositETH{ value: 3 ether }(minimunAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - uint256 indexOfNodeDelegatorContractOneInNDArray; - address[] memory nodeDelegatorArray = lrtDepositPool.getNodeDelegatorQueue(); - for (uint256 i = 0; i < nodeDelegatorArray.length; i++) { - if (lrtDepositPool.nodeDelegatorQueue(i) == nodeDelegatorContractOne) { - indexOfNodeDelegatorContractOneInNDArray = i; - break; - } - } - - // transfer 1 ether to node delegator contract one - vm.startPrank(manager); - lrtDepositPool.transferETHToNodeDelegator(indexOfNodeDelegatorContractOneInNDArray, 1 ether); - vm.stopPrank(); - - assertEq(address(lrtDepositPool).balance, 2 ether, "ETH amount in lrtDepositPool is incorrect"); - assertEq(address(nodeDelegatorContractOne).balance, 1 ether, "ETH is not transferred to node delegator"); - } -} - -contract LRTDepositPoolSwapETHForAssetWithinDepositPool is LRTDepositPoolTest { - event ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount); - - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - - // send 5 stETH to lrtDepositPool - vm.prank(alice); - stETH.transfer(address(lrtDepositPool), 10 ether); - - // give 5 eth to manager - vm.startPrank(alice); - payable(manager).transfer(5 ether); - vm.stopPrank(); - } - - function test_RevertWhenNotCalledByLRTConfigManager() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - lrtDepositPool.swapETHForAssetWithinDepositPool{ value: 1 ether }(address(stETH), 1 ether); - - vm.stopPrank(); - } - - function test_SwapAssetFromDepositPool() external { - uint256 amountToSwap = 3 ether; - - uint256 minimumAmountOfEthToReceive = lrtDepositPool.getSwapETHToAssetReturnAmount(address(stETH), amountToSwap); - - uint256 balanceOfEthBefore = address(lrtDepositPool).balance; - uint256 balanceOfStethBefore = stETH.balanceOf(address(lrtDepositPool)); - - uint256 managerBalanceOfEthBefore = address(manager).balance; - uint256 managerBalanceOfStethBefore = stETH.balanceOf(manager); - - vm.startPrank(manager); - stETH.approve(address(lrtDepositPool), amountToSwap); - - expectEmit(); - emit ETHSwappedForLST(amountToSwap, address(stETH), minimumAmountOfEthToReceive); - lrtDepositPool.swapETHForAssetWithinDepositPool{ value: amountToSwap }( - address(stETH), minimumAmountOfEthToReceive - ); - vm.stopPrank(); - - uint256 balanceOfEthAfter = address(lrtDepositPool).balance; - uint256 balanceOfStethAfter = stETH.balanceOf(address(lrtDepositPool)); - - uint256 managerBalanceOfEthAfter = address(manager).balance; - uint256 managerBalanceOfStethAfter = stETH.balanceOf(manager); - - assertEq( - balanceOfEthAfter, - balanceOfEthBefore + minimumAmountOfEthToReceive, - "Eth was not added properly from lrtDepositPool" - ); - assertEq( - balanceOfStethAfter, balanceOfStethBefore - amountToSwap, "StETH was not removed properly to lrtDepositPool" - ); - - assertEq( - managerBalanceOfEthAfter, - managerBalanceOfEthBefore - minimumAmountOfEthToReceive, - "Eth was not taken properly from the manager" - ); - assertEq( - managerBalanceOfStethAfter, - managerBalanceOfStethBefore + amountToSwap, - "StETH was not given properly to the manager" - ); - } -} - -contract LRTDepositPoolGetSwapETHToAssetReturnAmount is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_GetSwapAssetReturnAmount() external { - uint256 amountToSwap = 3 ether; - - uint256 minimumAmountOfEthToReceive = lrtDepositPool.getSwapETHToAssetReturnAmount(address(stETH), amountToSwap); - - assertGt(minimumAmountOfEthToReceive, 1 ether, "Minimum amount of eth to receive is incorrect"); - } -} - -contract LRTDepositPoolUpdateMaxNodeDelegatorLimit is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_RevertWhenNotCalledByLRTConfigAdmin() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.updateMaxNodeDelegatorLimit(10); - - vm.stopPrank(); - } - - function test_UpdateMaxNodeDelegatorLimit() external { - vm.startPrank(admin); - lrtDepositPool.updateMaxNodeDelegatorLimit(10); - vm.stopPrank(); - - assertEq(lrtDepositPool.maxNodeDelegatorLimit(), 10, "Max node delegator count is not set"); - } -} - -contract LRTDepositPoolSetMinAmountToDeposit is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_RevertWhenNotCalledByLRTConfigAdmin() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.setMinAmountToDeposit(1 ether); - - vm.stopPrank(); - } - - function test_SetMinAmountToDeposit() external { - vm.startPrank(admin); - lrtDepositPool.setMinAmountToDeposit(1 ether); - vm.stopPrank(); - - assertEq(lrtDepositPool.minAmountToDeposit(), 1 ether, "Min amount to deposit is not set"); - } -} - -contract LRTDepositPoolPause is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_RevertWhenNotCalledByLRTConfigManager() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - lrtDepositPool.pause(); - - vm.stopPrank(); - } - - function test_Pause() external { - vm.startPrank(manager); - lrtDepositPool.pause(); - vm.stopPrank(); - - assertTrue(lrtDepositPool.paused(), "LRTDepositPool is not paused"); - } -} - -contract LRTDepositPoolUnpause is LRTDepositPoolTest { - function setUp() public override { - super.setUp(); - - // initialize LRTDepositPool - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_RevertWhenNotCalledByLRTConfigAdmin() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.unpause(); - - vm.stopPrank(); - } - - function test_Unpause() external { - vm.prank(manager); - lrtDepositPool.pause(); - vm.prank(admin); - lrtDepositPool.unpause(); - - assertFalse(lrtDepositPool.paused(), "LRTDepositPool is not unpaused"); - } -} diff --git a/test/LRTOracleTest.t.sol b/test/LRTOracleTest.t.sol deleted file mode 100644 index c368563..0000000 --- a/test/LRTOracleTest.t.sol +++ /dev/null @@ -1,188 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import { LRTConfigTest, ILRTConfig, LRTConstants, UtilLib, MockToken } from "./LRTConfigTest.t.sol"; -import { LRTOracle } from "contracts/LRTOracle.sol"; -import { UtilLib } from "contracts/utils/UtilLib.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract MockPriceOracle { - function getAssetPrice(address) external pure returns (uint256) { - return 2 ether; - } -} - -contract MockLRTDepositPool { - function getAssetDistributionData(address) - external - pure - returns (uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer) - { - return (0, 0, 1 ether); - } - - function getTotalAssetDeposits(address) external pure returns (uint256) { - return 1 ether; - } -} - -contract LRTOracleTest is LRTConfigTest { - LRTOracle public lrtOracle; - MockLRTDepositPool public lrtDepositPoolMock; - MockToken public rsETHMock; - - event UpdatedLRTConfig(address indexed lrtConfig); - event AssetPriceOracleUpdate(address indexed asset, address indexed priceOracle); - - function setUp() public virtual override { - super.setUp(); - - rsETHMock = new MockToken("rsETH", "rsETH"); - - // initialize LRTConfig - lrtConfig.initialize(admin, address(stETH), address(ethX), address(rsETHMock)); - - lrtDepositPoolMock = new MockLRTDepositPool(); - - // add manager role - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - lrtConfig.setContract(LRTConstants.LRT_DEPOSIT_POOL, address(lrtDepositPoolMock)); - vm.stopPrank(); - - ProxyAdmin proxyAdmin = new ProxyAdmin(); - LRTOracle lrtOracleImpl = new LRTOracle(); - TransparentUpgradeableProxy lrtOracleProxy = - new TransparentUpgradeableProxy(address(lrtOracleImpl), address(proxyAdmin), ""); - - lrtOracle = LRTOracle(address(lrtOracleProxy)); - } -} - -contract LRTOracleInitialize is LRTOracleTest { - function test_RevertInitializeIfAlreadyInitialized() external { - lrtOracle.initialize(address(lrtConfig)); - - vm.startPrank(admin); - // cannot initialize again - vm.expectRevert("Initializable: contract is already initialized"); - lrtOracle.initialize(address(lrtConfig)); - vm.stopPrank(); - } - - function test_RevertInitializeIfLRTConfigIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtOracle.initialize(address(0)); - vm.stopPrank(); - } - - function test_SetInitializableValues() external { - expectEmit(); - emit UpdatedLRTConfig(address(lrtConfig)); - lrtOracle.initialize(address(lrtConfig)); - - assertEq(address(lrtOracle.lrtConfig()), address(lrtConfig)); - } -} - -contract LRTOracleSetPriceOracle is LRTOracleTest { - MockPriceOracle public priceOracle; - - function setUp() public override { - super.setUp(); - lrtOracle.initialize(address(lrtConfig)); - - priceOracle = new MockPriceOracle(); - } - - function test_RevertWhenCallerIsNotLRTAdmin() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtOracle.updatePriceOracleFor(address(ethX), address(priceOracle)); - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.startPrank(admin); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtOracle.updatePriceOracleFor(randomAddress, address(priceOracle)); - vm.stopPrank(); - } - - function test_RevertWhenPriceOracleIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtOracle.updatePriceOracleFor(address(ethX), address(0)); - vm.stopPrank(); - } - - function test_SetAssetPriceFeed() external { - assertEq(lrtOracle.assetPriceOracle(address(ethX)), address(0)); - - vm.startPrank(admin); - expectEmit(); - emit AssetPriceOracleUpdate(address(ethX), address(priceOracle)); - lrtOracle.updatePriceOracleFor(address(ethX), address(priceOracle)); - vm.stopPrank(); - - assertEq(lrtOracle.assetPriceOracle(address(ethX)), address(priceOracle)); - } -} - -contract LRTOracleFetchAssetPrice is LRTOracleTest { - MockPriceOracle public priceOracle; - - function setUp() public override { - super.setUp(); - lrtOracle.initialize(address(lrtConfig)); - priceOracle = new MockPriceOracle(); - - vm.prank(admin); - lrtOracle.updatePriceOracleFor(address(ethX), address(priceOracle)); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtOracle.getAssetPrice(randomAddress); - } - - function test_FetchAssetPrice() external { - uint256 ethXPrice = lrtOracle.getAssetPrice(address(ethX)); - assertEq(ethXPrice, 2 ether); - } -} - -contract LRTOracleFetchRSETHPrice is LRTOracleTest { - MockPriceOracle public priceOracle; - - function setUp() public override { - super.setUp(); - - lrtOracle.initialize(address(lrtConfig)); - priceOracle = new MockPriceOracle(); - - vm.startPrank(admin); - lrtOracle.updatePriceOracleFor(address(ethX), address(priceOracle)); - lrtOracle.updatePriceOracleFor(address(stETH), address(priceOracle)); - vm.stopPrank(); - } - - function test_FetchRSETHPriceWhenRSETHSupplyIsZero() external { - lrtOracle.updateRSETHPrice(); - assertEq(rsETHMock.totalSupply(), 0); - assertEq(lrtOracle.rsETHPrice(), 1 ether); - } - - function test_FetchRSETHPrice() external { - vm.mockCall(address(rsETHMock), abi.encodeWithSelector(ERC20.totalSupply.selector), abi.encode(4 ether)); - lrtOracle.updateRSETHPrice(); - assertEq(rsETHMock.totalSupply(), 4 ether); - assertEq(lrtOracle.rsETHPrice(), 1 ether); - } -} diff --git a/test/NodeDelegatorTest.t.sol b/test/NodeDelegatorTest.t.sol deleted file mode 100644 index 93567cf..0000000 --- a/test/NodeDelegatorTest.t.sol +++ /dev/null @@ -1,594 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/console.sol"; - -import { LRTConfigTest, ILRTConfig, LRTConstants, UtilLib, MockStrategy, IERC20 } from "./LRTConfigTest.t.sol"; -import { IStrategy } from "contracts/interfaces/IStrategy.sol"; -import { NodeDelegator, INodeDelegator } from "contracts/NodeDelegator.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -import { BeaconChainProofs } from "contracts/interfaces/IEigenPod.sol"; - -contract MockEigenStrategyManager { - mapping(address depositor => mapping(address strategy => uint256 shares)) public depositorStrategyShareBalances; - - address[] public strategies; - - function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount) external returns (uint256 shares) { - token.transferFrom(msg.sender, address(strategy), amount); - - shares = amount; - - depositorStrategyShareBalances[msg.sender][address(strategy)] += shares; - - strategies.push(address(strategy)); - - return shares; - } - - function getDeposits(address depositor) external view returns (IStrategy[] memory, uint256[] memory) { - uint256[] memory shares = new uint256[](strategies.length); - IStrategy[] memory strategies_ = new IStrategy[](strategies.length); - - for (uint256 i = 0; i < strategies.length; i++) { - strategies_[i] = IStrategy(strategies[i]); - shares[i] = depositorStrategyShareBalances[depositor][strategies[i]]; - } - - return (strategies_, shares); - } -} - -contract MockEigenPodManager { - mapping(address => address) public ownerToPod; - - function createPod() external { - if (ownerToPod[msg.sender] != address(0)) { - return; - } - ownerToPod[msg.sender] = address(new MockEigenPod()); - } - - function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable { - // do nothing - } -} - -contract MockEigenPod { - function verifyWithdrawalCredentialsAndBalance( - uint64 oracleBlockNumber, - uint40 validatorIndex, - BeaconChainProofs.ValidatorFieldsAndBalanceProofs memory proofs, - bytes32[] calldata validatorFields - ) - external - view - returns (uint256) - { - return 32 gwei; - } - - receive() external payable { } -} - -contract NodeDelegatorTest is LRTConfigTest { - NodeDelegator public nodeDel; - address public operator; - - MockEigenStrategyManager public mockEigenStrategyManager; - - MockStrategy public stETHMockStrategy; - MockStrategy public ethXMockStrategy; - address public mockLRTDepositPool; - - MockEigenPodManager public mockEigenPodManager; - - event UpdatedLRTConfig(address indexed lrtConfig); - event AssetDepositIntoStrategy(address indexed asset, address indexed strategy, uint256 depositAmount); - event ETHDepositFromDepositPool(uint256 depositAmount); - - uint256 public mockUserUnderlyingViewBalance; - - function setUp() public virtual override { - super.setUp(); - - operator = makeAddr("operator"); - - // initialize LRTConfig - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - // add mockEigenStrategyManager to LRTConfig - mockEigenStrategyManager = new MockEigenStrategyManager(); - vm.startPrank(admin); - lrtConfig.setContract(LRTConstants.EIGEN_STRATEGY_MANAGER, address(mockEigenStrategyManager)); - - mockEigenPodManager = new MockEigenPodManager(); - lrtConfig.setContract(LRTConstants.EIGEN_POD_MANAGER, address(mockEigenPodManager)); - - // add manager role - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - - // add operator role - lrtConfig.grantRole(LRTConstants.OPERATOR_ROLE, operator); - - // add mockStrategy to LRTConfig - mockUserUnderlyingViewBalance = 10 ether; - ethXMockStrategy = new MockStrategy(address(ethX), mockUserUnderlyingViewBalance); - stETHMockStrategy = new MockStrategy(address(stETH), mockUserUnderlyingViewBalance); - - lrtConfig.updateAssetStrategy(address(ethX), address(ethXMockStrategy)); - lrtConfig.updateAssetStrategy(address(stETH), address(stETHMockStrategy)); - - // add mockLRTDepositPool to LRTConfig - mockLRTDepositPool = makeAddr("mockLRTDepositPool"); - lrtConfig.setContract(LRTConstants.LRT_DEPOSIT_POOL, mockLRTDepositPool); - vm.stopPrank(); - - // deploy NodeDelegator - ProxyAdmin proxyAdmin = new ProxyAdmin(); - NodeDelegator nodeDelImpl = new NodeDelegator(); - TransparentUpgradeableProxy nodeDelProxy = - new TransparentUpgradeableProxy(address(nodeDelImpl), address(proxyAdmin), ""); - - nodeDel = NodeDelegator(payable(nodeDelProxy)); - } -} - -contract NodeDelegatorInitialize is NodeDelegatorTest { - function test_RevertInitializeIfAlreadyInitialized() external { - nodeDel.initialize(address(lrtConfig)); - - vm.startPrank(admin); - // cannot initialize again - vm.expectRevert("Initializable: contract is already initialized"); - nodeDel.initialize(address(lrtConfig)); - vm.stopPrank(); - } - - function test_RevertInitializeIfLRTConfigIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - nodeDel.initialize(address(0)); - vm.stopPrank(); - } - - function test_SetInitializableValues() external { - expectEmit(); - emit UpdatedLRTConfig(address(lrtConfig)); - nodeDel.initialize(address(lrtConfig)); - - assertEq(address(nodeDel.lrtConfig()), address(lrtConfig)); - } -} - -contract NodeDelegatorCreateEigenPod is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDel.createEigenPod(); - vm.stopPrank(); - } - - function test_CreateEigenPod() external { - assertEq(address(nodeDel.eigenPod()), address(0)); - - vm.startPrank(manager); - nodeDel.createEigenPod(); - vm.stopPrank(); - - assertFalse(address(nodeDel.eigenPod()) == address(0)); - } -} - -contract NodeDelegatorMaxApproveToEigenStrategyManager is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDel.maxApproveToEigenStrategyManager(address(ethX)); - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.startPrank(manager); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - nodeDel.maxApproveToEigenStrategyManager(randomAddress); - vm.stopPrank(); - } - - function test_MaxApproveToEigenStrategyManager() external { - vm.startPrank(manager); - nodeDel.maxApproveToEigenStrategyManager(address(ethX)); - vm.stopPrank(); - - // check that the nodeDelegator has max approved the eigen strategy manager - assertEq(ethX.allowance(address(nodeDel), address(mockEigenStrategyManager)), type(uint256).max); - } -} - -contract NodeDelegatorDepositAssetIntoStrategy is NodeDelegatorTest { - uint256 public amountDeposited; - - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - // sends token to nodeDelegator so it can deposit it into the strategy - amountDeposited = 10 ether; - vm.prank(bob); - ethX.transfer(address(nodeDel), amountDeposited); - - // max approve nodeDelegator to deposit into strategy - vm.prank(manager); - nodeDel.maxApproveToEigenStrategyManager(address(ethX)); - } - - function test_RevertWhenContractIsPaused() external { - vm.startPrank(manager); - nodeDel.pause(); - - vm.expectRevert("Pausable: paused"); - nodeDel.depositAssetIntoStrategy(address(ethX)); - - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.startPrank(manager); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - nodeDel.depositAssetIntoStrategy(randomAddress); - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDel.depositAssetIntoStrategy(address(ethX)); - vm.stopPrank(); - } - - function test_RevertWhenAnStrategyIsNotSetForAsset() external { - address randomAddress = address(0x123); - uint256 depositLimit = 100 ether; - vm.prank(admin); - lrtConfig.addNewSupportedAsset(randomAddress, depositLimit); - - vm.startPrank(manager); - vm.expectRevert(INodeDelegator.StrategyIsNotSetForAsset.selector); - nodeDel.depositAssetIntoStrategy(randomAddress); - vm.stopPrank(); - } - - function test_DepositAssetIntoStrategy() external { - vm.startPrank(manager); - expectEmit(); - emit AssetDepositIntoStrategy(address(ethX), address(ethXMockStrategy), amountDeposited); - nodeDel.depositAssetIntoStrategy(address(ethX)); - vm.stopPrank(); - - // check that strategy received LST via the eigen strategy manager - assertEq(ethX.balanceOf(address(ethXMockStrategy)), amountDeposited); - } -} - -contract NodeDelegatorTransferBackToLRTDepositPool is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - vm.prank(admin); - lrtConfig.addNewSupportedAsset(LRTConstants.ETH_TOKEN, 100_000 ether); - nodeDel.initialize(address(lrtConfig)); - - // transfer ethX to NodeDelegator - vm.prank(bob); - ethX.transfer(address(nodeDel), 10 ether); - } - - function test_RevertWhenContractIsPaused() external { - vm.startPrank(manager); - nodeDel.pause(); - - vm.expectRevert("Pausable: paused"); - nodeDel.transferBackToLRTDepositPool(address(ethX), 10 ether); - - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDel.transferBackToLRTDepositPool(address(ethX), 10 ether); - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomAddress = address(0x123); - vm.startPrank(manager); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - nodeDel.transferBackToLRTDepositPool(randomAddress, 10 ether); - vm.stopPrank(); - } - - function test_TransferBackToLRTDepositPool() external { - uint256 amountToDeposit = 3 ether; - - uint256 nodeDelBalanceBefore = ethX.balanceOf(address(nodeDel)); - - // transfer funds in NodeDelegator to to LRTDepositPool - vm.startPrank(manager); - nodeDel.transferBackToLRTDepositPool(address(ethX), amountToDeposit); - vm.stopPrank(); - - uint256 nodeDelBalanceAfter = ethX.balanceOf(address(nodeDel)); - - assertLt(nodeDelBalanceAfter, nodeDelBalanceBefore, "NodeDelegator balance did not increase"); - assertEq(nodeDelBalanceAfter, nodeDelBalanceBefore - amountToDeposit, "NodeDelegator balance did not increase"); - - assertEq(ethX.balanceOf(mockLRTDepositPool), amountToDeposit, "LRTDepositPool balance did not increase"); - } - - function test_TransferETHBackToLRTDepositPool() external { - uint256 amountToDeposit = 3 ether; - - vm.deal(address(nodeDel), 100 ether); - uint256 nodeDelBalanceBefore = address(nodeDel).balance; - - // transfer funds in NodeDelegator to to LRTDepositPool - vm.prank(manager); - nodeDel.transferBackToLRTDepositPool(LRTConstants.ETH_TOKEN, amountToDeposit); - - uint256 nodeDelBalanceAfter = address(nodeDel).balance; - - assertLt(nodeDelBalanceAfter, nodeDelBalanceBefore, "NodeDelegator balance did not increase"); - assertEq(nodeDelBalanceAfter, nodeDelBalanceBefore - amountToDeposit, "NodeDelegator balance did not increase"); - - assertEq(mockLRTDepositPool.balance, amountToDeposit, "LRTDepositPool balance did not increase"); - } -} - -contract NodeDelegatorGetAssetBalances is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - // sends token to nodeDelegator so it can deposit it into the strategy - vm.startPrank(bob); - ethX.transfer(address(nodeDel), 10 ether); - stETH.transfer(address(nodeDel), 5 ether); - vm.stopPrank(); - - // max approve nodeDelegator to deposit into strategy - vm.startPrank(manager); - nodeDel.maxApproveToEigenStrategyManager(address(ethX)); - nodeDel.maxApproveToEigenStrategyManager(address(stETH)); - vm.stopPrank(); - } - - function test_GetAssetBalances() external { - // deposit NodeDelegator balance into strategy - vm.startPrank(manager); - nodeDel.depositAssetIntoStrategy(address(ethX)); - nodeDel.depositAssetIntoStrategy(address(stETH)); - vm.stopPrank(); - - // get asset balances in strategies - (address[] memory assets, uint256[] memory assetBalances) = nodeDel.getAssetBalances(); - - assertEq(assets.length, 2, "Incorrect number of assets"); - assertEq(assets[0], address(ethX), "Incorrect asset"); - assertEq(assets[1], address(stETH), "Incorrect asset"); - assertEq(assetBalances.length, 2, "Incorrect number of asset balances"); - assertEq(assetBalances[0], mockUserUnderlyingViewBalance, "Incorrect asset balance for ethX"); - assertEq(assetBalances[1], mockUserUnderlyingViewBalance, "Incorrect asset balance for stETH"); - } -} - -contract NodeDelegatorGetAssetBalance is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - // sends token to nodeDelegator so it can deposit it into the strategy - vm.prank(bob); - ethX.transfer(address(nodeDel), 6 ether); - - // max approve nodeDelegator to deposit into strategy - vm.prank(manager); - nodeDel.maxApproveToEigenStrategyManager(address(ethX)); - } - - function test_GetAssetBalance() external { - // deposit NodeDelegator balance into strategy - vm.startPrank(manager); - nodeDel.depositAssetIntoStrategy(address(ethX)); - vm.stopPrank(); - - // get asset balances in strategies - (uint256 ethXNodeDelBalance) = nodeDel.getAssetBalance(address(ethX)); - - assertEq(ethXNodeDelBalance, mockUserUnderlyingViewBalance, "Incorrect asset balance"); - } -} - -contract NodeDelegatorGetETHEigenPodBalance is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - vm.prank(manager); - nodeDel.createEigenPod(); - - // add ETH to nodeDelegator so it can deposit it into the EigenPodManager - vm.deal(address(nodeDel), 1000 ether); - - // stake ETH in EigenPodManager - vm.prank(operator); - nodeDel.stake32Eth(hex"", hex"", hex""); - } - - function test_GetETHEigenPodBalance() external { - uint256 ethEigenPodBalance = nodeDel.getETHEigenPodBalance(); - assertEq(ethEigenPodBalance, 32 ether, "Incorrect ETH balance in EigenPod"); - } -} - -contract NodeDelegatorStakeETH is NodeDelegatorTest { - uint256 public amount; - - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - amount = 32 ether; - - vm.prank(manager); - nodeDel.createEigenPod(); - - // add ETH to nodeDelegator so it can deposit it into the EigenPodManager - vm.deal(address(nodeDel), amount); - } - - function test_revertWhenCallerIsNotLRTOperator() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigOperator.selector); - nodeDel.stake32Eth(hex"", hex"", hex""); - vm.stopPrank(); - } - - function test_stakeETH() external { - uint256 nodeDelBalanceBefore = address(nodeDel).balance; - uint256 ethEigenPodBalanceBefore = nodeDel.getETHEigenPodBalance(); - - vm.prank(operator); - nodeDel.stake32Eth(hex"", hex"", hex""); - - uint256 nodeDelBalanceAfter = address(nodeDel).balance; - - assertLt(nodeDelBalanceAfter, nodeDelBalanceBefore, "NodeDelegator balance did not increase"); - assertEq(nodeDelBalanceAfter, nodeDelBalanceBefore - amount, "NodeDelegator balance did not increase"); - - uint256 ethEigenPodBalance = nodeDel.getETHEigenPodBalance(); - assertEq(ethEigenPodBalance, amount + ethEigenPodBalanceBefore, "Incorrect ETH balance in EigenPod"); - - uint256 stakedButUnverifiedNativeETH = nodeDel.stakedButUnverifiedNativeETH(); - assertEq(stakedButUnverifiedNativeETH, amount, "Incorrect staked but not verified ETH"); - } -} - -contract NodeDelegatorPause is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDel.pause(); - vm.stopPrank(); - } - - function test_RevertWhenContractIsAlreadyPaused() external { - vm.startPrank(manager); - nodeDel.pause(); - - vm.expectRevert("Pausable: paused"); - nodeDel.pause(); - - vm.stopPrank(); - } - - function test_Pause() external { - vm.startPrank(manager); - nodeDel.pause(); - - vm.stopPrank(); - - assertTrue(nodeDel.paused(), "Contract is not paused"); - } -} - -contract NodeDelegatorUnpause is NodeDelegatorTest { - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - vm.startPrank(manager); - nodeDel.pause(); - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotLRTAdmin() external { - vm.startPrank(alice); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - nodeDel.unpause(); - vm.stopPrank(); - } - - function test_RevertWhenContractIsNotPaused() external { - vm.startPrank(admin); - nodeDel.unpause(); - - vm.expectRevert("Pausable: not paused"); - nodeDel.unpause(); - - vm.stopPrank(); - } - - function test_Unpause() external { - vm.startPrank(admin); - nodeDel.unpause(); - - vm.stopPrank(); - - assertFalse(nodeDel.paused(), "Contract is still paused"); - } -} - -contract NodeDelegatorSendETHFromDepositPoolToNDC is NodeDelegatorTest { - address public lrtDepositPool; - uint256 public amount; - - function setUp() public override { - super.setUp(); - nodeDel.initialize(address(lrtConfig)); - - amount = 32 ether; - - // add ETH to LRTDepositPool - lrtDepositPool = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); - vm.deal(lrtDepositPool, amount); - } - - function test_RevertWhenCallerIsNotLRTDepositPool() external { - vm.startPrank(alice); - vm.expectRevert(INodeDelegator.InvalidETHSender.selector); - nodeDel.sendETHFromDepositPoolToNDC(); - vm.stopPrank(); - } - - function test_SendETHFromDepositPoolToNDC() external { - assertEq(address(nodeDel).balance, 0, "Incorrect balance before sending ETH from LRTDepositPool"); - // it is callable by LRTDepositPool - vm.startPrank(lrtDepositPool); - expectEmit(); - emit ETHDepositFromDepositPool(amount); - nodeDel.sendETHFromDepositPoolToNDC{ value: amount }(); - vm.stopPrank(); - - assertEq(address(nodeDel).balance, amount, "Incorrect balance after sending ETH from LRTDepositPool"); - } -} diff --git a/test/RSETHTest.t.sol b/test/RSETHTest.t.sol deleted file mode 100644 index 0febc63..0000000 --- a/test/RSETHTest.t.sol +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import { BaseTest } from "./BaseTest.t.sol"; -import { RSETH } from "contracts/RSETH.sol"; -import { LRTConfigTest, ILRTConfig, UtilLib, LRTConstants } from "./LRTConfigTest.t.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -contract RSETHTest is BaseTest, LRTConfigTest { - RSETH public rseth; - - event UpdatedLRTConfig(address indexed _lrtConfig); - - function setUp() public virtual override(LRTConfigTest, BaseTest) { - super.setUp(); - - // initialize LRTConfig - lrtConfig.initialize(admin, address(stETH), address(ethX), rsethMock); - - ProxyAdmin proxyAdmin = new ProxyAdmin(); - RSETH tokenImpl = new RSETH(); - TransparentUpgradeableProxy tokenProxy = - new TransparentUpgradeableProxy(address(tokenImpl), address(proxyAdmin), ""); - - rseth = RSETH(address(tokenProxy)); - } -} - -contract RSETHInitialize is RSETHTest { - function test_RevertWhenAdminIsZeroAddress() external { - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - rseth.initialize(address(0), address(lrtConfig)); - } - - function test_RevertWhenLRTConfigIsZeroAddress() external { - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - rseth.initialize(address(admin), address(0)); - } - - function test_InitializeContractsVariables() external { - rseth.initialize(address(admin), address(lrtConfig)); - - assertTrue(lrtConfig.hasRole(LRTConstants.DEFAULT_ADMIN_ROLE, admin), "Admin address is not set"); - assertEq(address(lrtConfig), address(rseth.lrtConfig()), "LRT config address is not set"); - - assertEq(rseth.name(), "rsETH", "Name is not set"); - assertEq(rseth.symbol(), "rsETH", "Symbol is not set"); - } -} - -contract RSETHMint is RSETHTest { - address public minter = makeAddr("minter"); - - function setUp() public override { - super.setUp(); - - rseth.initialize(address(admin), address(lrtConfig)); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - lrtConfig.grantRole(LRTConstants.MINTER_ROLE, minter); - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotMinter() external { - vm.startPrank(alice); - - string memory stringRole = string(abi.encodePacked(LRTConstants.MINTER_ROLE)); - bytes memory revertData = abi.encodeWithSelector(ILRTConfig.CallerNotLRTConfigAllowedRole.selector, stringRole); - - vm.expectRevert(revertData); - - rseth.mint(address(this), 100 ether); - vm.stopPrank(); - } - - function test_RevertMintIsPaused() external { - vm.startPrank(manager); - rseth.pause(); - vm.stopPrank(); - - vm.startPrank(minter); - vm.expectRevert("Pausable: paused"); - rseth.mint(address(this), 1 ether); - vm.stopPrank(); - } - - function test_Mint() external { - vm.startPrank(admin); - - lrtConfig.grantRole(LRTConstants.MINTER_ROLE, msg.sender); - - vm.stopPrank(); - - vm.startPrank(minter); - - rseth.mint(address(this), 100 ether); - - assertEq(rseth.balanceOf(address(this)), 100 ether, "Balance is not correct"); - - vm.stopPrank(); - } -} - -contract RSETHBurnFrom is RSETHTest { - address public burner = makeAddr("burner"); - - function setUp() public override { - super.setUp(); - rseth.initialize(address(admin), address(lrtConfig)); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - lrtConfig.grantRole(LRTConstants.BURNER_ROLE, burner); - - // give minter role to admin - lrtConfig.grantRole(LRTConstants.MINTER_ROLE, admin); - rseth.mint(address(this), 100 ether); - - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotBurner() external { - vm.startPrank(bob); - - string memory roleStr = string(abi.encodePacked(LRTConstants.BURNER_ROLE)); - bytes memory revertData = abi.encodeWithSelector(ILRTConfig.CallerNotLRTConfigAllowedRole.selector, roleStr); - - vm.expectRevert(revertData); - - rseth.burnFrom(address(this), 100 ether); - vm.stopPrank(); - } - - function test_RevertBurnIsPaused() external { - vm.prank(manager); - rseth.pause(); - - vm.prank(burner); - vm.expectRevert("Pausable: paused"); - rseth.burnFrom(address(this), 100 ether); - } - - function test_BurnFrom() external { - vm.prank(burner); - rseth.burnFrom(address(this), 100 ether); - - assertEq(rseth.balanceOf(address(this)), 0, "Balance is not correct"); - } -} - -contract RSETHPause is RSETHTest { - function setUp() public override { - super.setUp(); - rseth.initialize(address(admin), address(lrtConfig)); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, manager); - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - - rseth.pause(); - vm.stopPrank(); - } - - function test_RevertWhenContractIsAlreadyPaused() external { - vm.startPrank(manager); - rseth.pause(); - - vm.expectRevert("Pausable: paused"); - rseth.pause(); - - vm.stopPrank(); - } - - function test_Pause() external { - vm.startPrank(manager); - rseth.pause(); - - vm.stopPrank(); - - assertTrue(rseth.paused(), "Contract is not paused"); - } -} - -contract RSETHUnpause is RSETHTest { - function setUp() public override { - super.setUp(); - rseth.initialize(address(admin), address(lrtConfig)); - - vm.startPrank(admin); - lrtConfig.grantRole(LRTConstants.MANAGER, admin); - rseth.pause(); - vm.stopPrank(); - } - - function test_RevertWhenCallerIsNotLRTAdmin() external { - vm.startPrank(alice); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - - rseth.unpause(); - vm.stopPrank(); - } - - function test_RevertWhenContractIsNotPaused() external { - vm.startPrank(admin); - rseth.unpause(); - - vm.expectRevert("Pausable: not paused"); - rseth.unpause(); - - vm.stopPrank(); - } - - function test_Unpause() external { - vm.startPrank(admin); - rseth.unpause(); - - vm.stopPrank(); - - assertFalse(rseth.paused(), "Contract is still paused"); - } -} diff --git a/test/integration/LRTIntegrationETHMainnet.t.sol b/test/integration/LRTIntegrationETHMainnet.t.sol deleted file mode 100644 index 23a6a34..0000000 --- a/test/integration/LRTIntegrationETHMainnet.t.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/console.sol"; - -import { - LRTIntegrationTest, - ERC20, - NodeDelegator, - LRTOracle, - RSETH, - LRTConfig, - LRTDepositPool -} from "./LRTIntegrationTest.t.sol"; - -import { RSETHPriceFeed } from "../../contracts/oracles/RSETHPriceFeed.sol"; - -contract LRTIntegrationTestETHMainnet is LRTIntegrationTest { - function setUp() public override { - string memory ethMainnetRPC = vm.envString("MAINNET_RPC_URL"); - fork = vm.createSelectFork(ethMainnetRPC); - - admin = 0xb9577E83a6d9A6DE35047aa066E3758221FE0DA2; - manager = 0xCbcdd778AA25476F203814214dD3E9b9c46829A1; - - stWhale = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; - ethXWhale = 0x1a0EBB8B15c61879a8e8DA7817Bb94374A7c4007; - - stEthOracle = 0x4cB8d6DCd56d6b371210E70837753F2a835160c4; - ethxPriceOracle = 0x3D08ccb47ccCde84755924ED6B0642F9aB30dFd2; - - EIGEN_STRATEGY_MANAGER = 0x858646372CC42E1A627fcE94aa7A7033e7CF075A; - EIGEN_STETH_STRATEGY = 0x93c4b944D05dfe6df7645A86cd2206016c51564D; - EIGEN_ETHX_STRATEGY = 0x9d7eD45EE2E8FC5482fa2428f15C971e6369011d; - - lrtDepositPool = LRTDepositPool(payable(0x036676389e48133B63a802f8635AD39E752D375D)); - lrtConfig = LRTConfig(0x947Cb49334e6571ccBFEF1f1f1178d8469D65ec7); - rseth = RSETH(0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7); - lrtOracle = LRTOracle(0x349A73444b1a310BAe67ef67973022020d70020d); - nodeDelegator1 = NodeDelegator(payable(0x07b96Cf1183C9BFf2E43Acf0E547a8c4E4429473)); - - stETHAddress = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; - ethXAddress = 0xA35b1B31Ce002FBF2058D22F30f95D405200A15b; - - amountToTransfer = 0.11 ether; - - vm.startPrank(ethXWhale); - ERC20(ethXAddress).approve(address(lrtDepositPool), amountToTransfer); - lrtDepositPool.depositAsset(ethXAddress, amountToTransfer, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - uint256 indexOfNodeDelegator = 0; - - vm.prank(manager); - lrtDepositPool.transferAssetToNodeDelegator(indexOfNodeDelegator, ethXAddress, amountToTransfer); - } - - function test_morphoPriceFeed() public { - address ethToUSDAggregatorAddress = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; - address rsETHOracle = 0x349A73444b1a310BAe67ef67973022020d70020d; - RSETHPriceFeed priceFeed = new RSETHPriceFeed(ethToUSDAggregatorAddress, rsETHOracle, "RSETH / USD"); - - console.log("desc", priceFeed.description()); - console.log("decimals", priceFeed.decimals()); - console.log("version", priceFeed.version()); - // fetch answer from latestRound - (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = - priceFeed.latestRoundData(); - - console.log("roundId", roundId); - console.log("answer", uint256(answer)); - console.log("startedAt", startedAt); - console.log("updatedAt", updatedAt); - console.log("answeredInRound", answeredInRound); - } -} diff --git a/test/integration/LRTIntegrationTest.t.sol b/test/integration/LRTIntegrationTest.t.sol deleted file mode 100644 index 698a834..0000000 --- a/test/integration/LRTIntegrationTest.t.sol +++ /dev/null @@ -1,822 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity 0.8.21; - -import "forge-std/Test.sol"; -import { LRTDepositPool, ILRTDepositPool, LRTConstants } from "contracts/LRTDepositPool.sol"; -import { LRTConfig, ILRTConfig } from "contracts/LRTConfig.sol"; -import { RSETH } from "contracts/RSETH.sol"; -import { LRTOracle } from "contracts/LRTOracle.sol"; -import { NodeDelegator } from "contracts/NodeDelegator.sol"; -import { UtilLib } from "contracts/utils/UtilLib.sol"; -import { getLSTs } from "script/foundry-scripts/DeployLRT.s.sol"; - -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract LRTIntegrationTest is Test { - uint256 public fork; - - LRTDepositPool public lrtDepositPool; - LRTConfig public lrtConfig; - RSETH public rseth; - LRTOracle public lrtOracle; - NodeDelegator public nodeDelegator1; - - address public admin; - address public manager; - - address public stETHAddress; - address public ethXAddress; - - address public stWhale; - address public ethXWhale; - - address public stEthOracle; - address public ethxPriceOracle; - - address public EIGEN_STRATEGY_MANAGER; - address public EIGEN_STETH_STRATEGY; - address public EIGEN_ETHX_STRATEGY; - - uint256 public minAmountOfRSETHToReceive; - string public referralId = "0"; - - uint256 amountToTransfer; - - uint256 indexOfNodeDelegator; - - function setUp() public virtual { - string memory goerliRPC = vm.envString("PROVIDER_URL_TESTNET"); - fork = vm.createSelectFork(goerliRPC); - - admin = 0xA65E2f72930219C4ce846FB245Ae18700296C328; - manager = 0xFc015a866aA06dDcaD27Fe425bdd362a8927544D; - - stWhale = 0xD5d883B90030311530620E0ABEe93189c8aAe032; - ethXWhale = 0xF6349eEe20aEcD62C9891159fB714a1b5adE93Cd; - - stEthOracle = 0x750604fAbF4828d1CaA19022238bc8C0DD6C50D5; - ethxPriceOracle = 0x6DA0235202D9443674abe6d0355AdD147B6396A2; - - EIGEN_STRATEGY_MANAGER = 0x779d1b5315df083e3F9E94cB495983500bA8E907; - EIGEN_STETH_STRATEGY = 0xB613E78E2068d7489bb66419fB1cfa11275d14da; - EIGEN_ETHX_STRATEGY = 0x5d1E9DC056C906CBfe06205a39B0D965A6Df7C14; - - lrtDepositPool = LRTDepositPool(payable(0xd51d846ba5032b9284b12850373ae2f053f977b3)); - lrtConfig = LRTConfig(0x6d7888Bc794C1104C64c28F4e849B7AE68231b6d); - rseth = RSETH(0xb4EA9175e99232560ac5dC2Bcbe4d7C833a15D56); - lrtOracle = LRTOracle(0xE92Ca437CA55AAbED0CBFFe398e384B997D4CCe9); - nodeDelegator1 = NodeDelegator(payable(0x560B95A0Ba942A7E15645F655731244680fA030B)); - - stETHAddress = 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F; - ethXAddress = 0x3338eCd3ab3d3503c55c931d759fA6d78d287236; - - amountToTransfer = 1 ether; - - vm.startPrank(stWhale); - ERC20(stETHAddress).approve(address(lrtDepositPool), amountToTransfer); - lrtDepositPool.depositAsset(stETHAddress, amountToTransfer, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - address[] memory nodeDelegatorArray = lrtDepositPool.getNodeDelegatorQueue(); - for (uint256 i = 0; i < nodeDelegatorArray.length; i++) { - if (nodeDelegatorArray[i] == address(nodeDelegator1)) { - indexOfNodeDelegator = i; - break; - } - } - - vm.prank(manager); - lrtDepositPool.transferAssetToNodeDelegator(indexOfNodeDelegator, stETHAddress, amountToTransfer); - } - - function test_LRTDepositPoolSetup() public { - assertEq(address(lrtConfig), address(lrtDepositPool.lrtConfig())); - assertEq(address(nodeDelegator1), address(lrtDepositPool.nodeDelegatorQueue(0))); - } - - function test_LRTDepositPoolIsAlreadyInitialized() public { - // attempt to initialize LRTDepositPool again reverts - vm.expectRevert("Initializable: contract is already initialized"); - lrtDepositPool.initialize(address(lrtConfig)); - } - - function test_RevertWhenDepositAmountIsZeroForDepositAsset() external { - vm.expectRevert(ILRTDepositPool.InvalidAmountToDeposit.selector); - - lrtDepositPool.depositAsset(ethXAddress, 0, minAmountOfRSETHToReceive, referralId); - } - - function test_RevertWhenAssetIsNotSupportedForDepositAsset() external { - address randomAsset = makeAddr("randomAsset"); - - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtDepositPool.depositAsset(randomAsset, 1 ether, minAmountOfRSETHToReceive, referralId); - } - - function test_DepositAssetSTETHWorksWhenUsingTheCorrectConditions() external { - if (block.chainid == 1) { - // skip test on mainnet - console.log("Skipping test as STETH has reached deposit limit pm mainnet"); - vm.skip(true); - } - - uint256 amountToDeposit = 2 ether; - - // stWhale balance of rsETH before deposit - uint256 stWhaleBalanceBefore = rseth.balanceOf(stWhale); - // total asset deposits before deposit for stETH - uint256 totalAssetDepositsBefore = lrtDepositPool.getTotalAssetDeposits(stETHAddress); - // balance of lrtDepositPool before deposit - uint256 lrtDepositPoolBalanceBefore = ERC20(stETHAddress).balanceOf(address(lrtDepositPool)); - - uint256 whaleStETHBalBefore = ERC20(stETHAddress).balanceOf(address(stWhale)); - vm.startPrank(stWhale); - ERC20(stETHAddress).approve(address(lrtDepositPool), amountToDeposit); - lrtDepositPool.depositAsset(stETHAddress, amountToDeposit, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - uint256 whaleStETHBalAfter = ERC20(stETHAddress).balanceOf(address(stWhale)); - - console.log("whale stETH amount transfer:", whaleStETHBalBefore - whaleStETHBalAfter); - - // stWhale balance of rsETH after deposit - uint256 stWhaleBalanceAfter = rseth.balanceOf(address(stWhale)); - - assertApproxEqAbs( - lrtDepositPool.getTotalAssetDeposits(stETHAddress), - totalAssetDepositsBefore + amountToDeposit, - 20, - "Total asset deposits check is incorrect" - ); - assertApproxEqAbs( - ERC20(stETHAddress).balanceOf(address(lrtDepositPool)), - lrtDepositPoolBalanceBefore + amountToDeposit, - 20, - "lrtDepositPool balance is not set" - ); - assertGt(stWhaleBalanceAfter, stWhaleBalanceBefore, "Alice balance is not set"); - } - - function test_DepositAssetETHXWorksWhenUsingTheCorrectConditions() external { - uint256 amountToDeposit = 2 ether; - - // ethXWhale balance of rsETH before deposit - uint256 ethXWhaleBalanceBefore = rseth.balanceOf(ethXWhale); - // total asset deposits before deposit for ethXETH - uint256 totalAssetDepositsBefore = lrtDepositPool.getTotalAssetDeposits(ethXAddress); - // balance of lrtDepositPool before deposit - uint256 lrtDepositPoolBalanceBefore = ERC20(ethXAddress).balanceOf(address(lrtDepositPool)); - - uint256 whaleethXBalBefore = ERC20(ethXAddress).balanceOf(address(ethXWhale)); - vm.startPrank(ethXWhale); - ERC20(ethXAddress).approve(address(lrtDepositPool), amountToDeposit); - lrtDepositPool.depositAsset(ethXAddress, amountToDeposit, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - uint256 whaleethXBalAfter = ERC20(ethXAddress).balanceOf(address(ethXWhale)); - - console.log("whale ethXETH amount transfer:", whaleethXBalBefore - whaleethXBalAfter); - - // ethXWhale balance of rsETH after deposit - uint256 ethXWhaleBalanceAfter = rseth.balanceOf(address(ethXWhale)); - - assertEq( - lrtDepositPool.getTotalAssetDeposits(ethXAddress), - totalAssetDepositsBefore + amountToDeposit, - "Total asset deposits check is incorrect" - ); - assertEq( - ERC20(ethXAddress).balanceOf(address(lrtDepositPool)), - lrtDepositPoolBalanceBefore + amountToDeposit, - "lrtDepositPool balance is not set" - ); - assertGt(ethXWhaleBalanceAfter, ethXWhaleBalanceBefore, "Alice balance is not set"); - } - - function test_GetCurrentAssetLimitAfterAssetIsDepositedInLRTDepositPool() external { - if (block.chainid == 1) { - // skip test on mainnet - console.log("Skipping test as STETH has reached deposit limit pm mainnet"); - vm.skip(true); - } - - uint256 depositAmount = 3 ether; - - uint256 stETHDepositLimitBefore = lrtDepositPool.getAssetCurrentLimit(stETHAddress); - - vm.startPrank(stWhale); - ERC20(stETHAddress).approve(address(lrtDepositPool), depositAmount); - lrtDepositPool.depositAsset(stETHAddress, depositAmount, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - uint256 stETHDepositLimitAfter = lrtDepositPool.getAssetCurrentLimit(stETHAddress); - - assertGt(stETHDepositLimitBefore, stETHDepositLimitAfter, "Deposit limit is not set"); - } - - function test_RevertWhenCallingAddNodeDelegatorByANonLRTAdmin() external { - address randomAddress = makeAddr("randomAddress"); - - address[] memory addNodeDelegatorArray = new address[](1); - addNodeDelegatorArray[0] = randomAddress; - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.addNodeDelegatorContractToQueue(addNodeDelegatorArray); - } - - function test_IsAbleToAddNodeDelegatorByLRTAdmin() external { - address randomAddress = makeAddr("randomAddress"); - - address[] memory addNodeDelegatorArray = new address[](1); - addNodeDelegatorArray[0] = randomAddress; - - vm.prank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(addNodeDelegatorArray); - - // find index of newly added nodeDelegator - uint256 indexOfNodeDelegator_; - address[] memory nodeDelegatorArray = lrtDepositPool.getNodeDelegatorQueue(); - for (uint256 i = 0; i < nodeDelegatorArray.length; i++) { - if (nodeDelegatorArray[i] == randomAddress) { - indexOfNodeDelegator_ = i; - break; - } - } - - // 5 nodeDelegators were already added in contract at the time of deployment - assertEq(lrtDepositPool.nodeDelegatorQueue(indexOfNodeDelegator_), randomAddress, "Node delegator is not added"); - } - - function test_RevertWhenCallingTransferAssetToNodeDelegatorWhenNotCalledByManager() external { - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - indexOfNodeDelegator = 0; - lrtDepositPool.transferAssetToNodeDelegator(indexOfNodeDelegator, stETHAddress, 1 ether); - } - - function test_TransferAssetSTETHToNodeDelegatorWhenCalledbyManager() external { - if (block.chainid == 1) { - // skip test on mainnet - console.log("Skipping test as STETH has reached deposit limit pm mainnet"); - vm.skip(true); - } - - uint256 lrtDepositPoolBalanceBefore = ERC20(stETHAddress).balanceOf(address(lrtDepositPool)); - - vm.startPrank(stWhale); - ERC20(stETHAddress).approve(address(lrtDepositPool), amountToTransfer); - lrtDepositPool.depositAsset(stETHAddress, amountToTransfer, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - assertApproxEqAbs( - ERC20(stETHAddress).balanceOf(address(lrtDepositPool)), - lrtDepositPoolBalanceBefore + amountToTransfer, - 2, - "lrtDepositPool balance is not set" - ); - - uint256 getTotalAssetDepositsBeforeDeposit = lrtDepositPool.getTotalAssetDeposits(stETHAddress); - - uint256 nodeDelegator1BalanceBefore = ERC20(stETHAddress).balanceOf(address(nodeDelegator1)); - - vm.prank(manager); - lrtDepositPool.transferAssetToNodeDelegator(indexOfNodeDelegator, stETHAddress, amountToTransfer); - - uint256 nodeDelegator1BalanceAfter = ERC20(stETHAddress).balanceOf(address(nodeDelegator1)); - - assertApproxEqAbs( - lrtDepositPool.getTotalAssetDeposits(stETHAddress), - getTotalAssetDepositsBeforeDeposit, - 2, - "Total asset deposits has not changed when transfering asset from deposit pool to node delegator" - ); - - // assert nodeDelegator1 balance before + 1 ether is equal to nodeDelegator1 balance after - assertApproxEqAbs( - nodeDelegator1BalanceAfter, - nodeDelegator1BalanceBefore + amountToTransfer, - 2, - "node delegator 1 balance before is different from node delegator 1 balance after" - ); - } - - function test_TransferAssetETHXToNodeDelegatorWhenCalledbyManager() external { - uint256 lrtDepositPoolBalanceBefore = ERC20(ethXAddress).balanceOf(address(lrtDepositPool)); - - vm.startPrank(ethXWhale); - ERC20(ethXAddress).approve(address(lrtDepositPool), amountToTransfer); - lrtDepositPool.depositAsset(ethXAddress, amountToTransfer, minAmountOfRSETHToReceive, referralId); - vm.stopPrank(); - - assertEq( - ERC20(ethXAddress).balanceOf(address(lrtDepositPool)), - lrtDepositPoolBalanceBefore + amountToTransfer, - "lrtDepositPool balance is not set" - ); - - uint256 _indexOfNodeDelegator; - // find index of nodeDelegator1 - address[] memory nodeDelegatorArray = lrtDepositPool.getNodeDelegatorQueue(); - for (uint256 i = 0; i < nodeDelegatorArray.length; i++) { - if (nodeDelegatorArray[i] == address(nodeDelegator1)) { - _indexOfNodeDelegator = i; - break; - } - } - - uint256 getTotalAssetDepositsBeforeDeposit = lrtDepositPool.getTotalAssetDeposits(ethXAddress); - - uint256 nodeDelegator1BalanceBefore = ERC20(ethXAddress).balanceOf(address(nodeDelegator1)); - - vm.prank(manager); - lrtDepositPool.transferAssetToNodeDelegator(_indexOfNodeDelegator, ethXAddress, amountToTransfer); - - uint256 nodeDelegator1BalanceAfter = ERC20(ethXAddress).balanceOf(address(nodeDelegator1)); - - assertEq( - lrtDepositPool.getTotalAssetDeposits(ethXAddress), - getTotalAssetDepositsBeforeDeposit, - "Total asset deposits has not changed when transfering asset from deposit pool to node delegator" - ); - - // assert nodeDelegator1 balance before + 1 ether is equal to nodeDelegator1 balance after - assertEq( - nodeDelegator1BalanceAfter, - nodeDelegator1BalanceBefore + amountToTransfer, - "node delegator 1 balance before is different from node delegator 1 balance after" - ); - } - - function test_RevertUpdateMaxNodeDelegatorLimitWhenNotCalledByLRTConfigAdmin() external { - vm.prank(stWhale); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.updateMaxNodeDelegatorLimit(10); - } - - function test_UpdateMaxNodeDelegatorLimitWhenCalledByAdmin() external { - vm.startPrank(admin); - lrtDepositPool.updateMaxNodeDelegatorLimit(100); - vm.stopPrank(); - - assertEq(lrtDepositPool.maxNodeDelegatorLimit(), 100, "Max node delegator count is not set"); - } - - function test_RevertPauseWhenNotCalledByLRTConfigManager() external { - vm.prank(stWhale); - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - lrtDepositPool.pause(); - } - - function test_PauseAndUnpauseWhenCalledByManagerAndAdmin() external { - vm.prank(manager); - lrtDepositPool.pause(); - - assertTrue(lrtDepositPool.paused(), "LRTDepositPool is not paused"); - - vm.prank(stWhale); // cannot unpause - vm.expectRevert(ILRTConfig.CallerNotLRTConfigAdmin.selector); - lrtDepositPool.unpause(); - - vm.prank(admin); - lrtDepositPool.unpause(); - - assertFalse(lrtDepositPool.paused(), "LRTDepositPool is not unpaused"); - } - - function test_LRTConfigSetup() public { - // priviledged roles - assertTrue(lrtConfig.hasRole(LRTConstants.DEFAULT_ADMIN_ROLE, admin)); - assertTrue(lrtConfig.hasRole(LRTConstants.MANAGER, manager)); - - // tokens - assertEq(stETHAddress, lrtConfig.getLSTToken(LRTConstants.ST_ETH_TOKEN)); - assertEq(ethXAddress, lrtConfig.getLSTToken(LRTConstants.ETHX_TOKEN)); - assertEq(address(rseth), lrtConfig.rsETH()); - - assertTrue(lrtConfig.isSupportedAsset(stETHAddress)); - assertTrue(lrtConfig.isSupportedAsset(ethXAddress)); - - assertEq(EIGEN_STETH_STRATEGY, lrtConfig.assetStrategy(stETHAddress)); - - assertEq(EIGEN_ETHX_STRATEGY, lrtConfig.assetStrategy(ethXAddress)); - - assertEq(EIGEN_STRATEGY_MANAGER, lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER)); - assertEq(address(lrtDepositPool), lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); - assertEq(address(lrtOracle), lrtConfig.getContract(LRTConstants.LRT_ORACLE)); - } - - function test_LRTConfigIsAlreadyInitialized() public { - // attempt to initialize LRTConfig again reverts - vm.expectRevert("Initializable: contract is already initialized"); - lrtConfig.initialize(admin, stETHAddress, ethXAddress, address(rseth)); - } - - function test_RevertWhenCallingAddNewAssetByANonLRTManager() external { - address randomAssetAddress = makeAddr("randomAssetAddress"); - uint256 randomAssetDepositLimit = 100 ether; - // Example of error message. Unfortunaly vm.expectRevert does not support the result of string casting. - // string memory errorMessage = string( - // abi.encodePacked( - // "AccessControl: account ", - // Strings.toHexString(address(this)), - // " is missing role ", - // Strings.toHexString(uint256(LRTConstants.MANAGER), 32) - // ) - // ); - vm.expectRevert( - "AccessControl: account 0x7fa9385be102ac3eac297483dd6233d62b3e1496 is missing role 0xaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c" - ); - - lrtConfig.addNewSupportedAsset(randomAssetAddress, randomAssetDepositLimit); - } - - function test_IsAbleToAddNewAssetByManager() external { - address randomAssetAddress = makeAddr("randomAssetAddress"); - uint256 randomAssetDepositLimit = 100 ether; - - vm.prank(manager); - lrtConfig.addNewSupportedAsset(randomAssetAddress, randomAssetDepositLimit); - - assertEq(lrtConfig.depositLimitByAsset(randomAssetAddress), randomAssetDepositLimit); - } - - function test_RevertUpdateAssetDepositLimitIfNotManager() external { - vm.expectRevert( - "AccessControl: account 0x7fa9385be102ac3eac297483dd6233d62b3e1496 is missing role 0xaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c" - ); - - lrtConfig.updateAssetDepositLimit(stETHAddress, 1000); - } - - function test_UpdateAssetDepositLimit() external { - uint256 depositLimit = 1000; - - vm.startPrank(manager); - lrtConfig.updateAssetDepositLimit(stETHAddress, depositLimit); - - assertEq(lrtConfig.depositLimitByAsset(stETHAddress), depositLimit); - } - - function test_RevertUpdateAssetStrategyIfNotAdmin() external { - vm.expectRevert( - "AccessControl: account 0x7fa9385be102ac3eac297483dd6233d62b3e1496 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.updateAssetStrategy(stETHAddress, address(this)); - } - - function test_RevertWhenAssetIsNotSupported() external { - address randomToken = makeAddr("randomToken"); - address strategy = makeAddr("strategy"); - - vm.startPrank(admin); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - lrtConfig.updateAssetStrategy(address(randomToken), strategy); - vm.stopPrank(); - } - - function test_RevertWhenStrategyAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.updateAssetStrategy(stETHAddress, address(0)); - vm.stopPrank(); - } - - function test_RevertWhenSameStrategyWasAlreadyAddedBeforeForAsset() external { - // TODO: remove when contract is upgraded - console.log("Skipping UpdateStrategy tests until contract is upgraded"); - vm.skip(true); - - address strategy = lrtConfig.assetStrategy(stETHAddress); - vm.startPrank(admin); - // revert when same strategy was already added before for asset - vm.expectRevert(ILRTConfig.ValueAlreadyInUse.selector); - lrtConfig.updateAssetStrategy(stETHAddress, strategy); - vm.stopPrank(); - } - - function test_UpdateAssetStrategy() external { - // TODO: remove when contract is upgraded - console.log("Skipping UpdateStrategy tests until contract is upgraded"); - vm.skip(true); - - address strategy = makeAddr("strategy"); // TODO: Deploy a mock strategy contract - - vm.prank(admin); - lrtConfig.updateAssetStrategy(stETHAddress, strategy); - - assertEq(lrtConfig.assetStrategy(stETHAddress), strategy); - } - - function test_RevertSetRSETHIfNotAdmin() external { - address newRSETH = makeAddr("newRSETH"); - - vm.expectRevert( - "AccessControl: account 0x7fa9385be102ac3eac297483dd6233d62b3e1496 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.setRSETH(newRSETH); - } - - function test_RevertSetRSETHIfRSETHAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.setRSETH(address(0)); - vm.stopPrank(); - } - - function test_SetRSETH() external { - address newRSETH = makeAddr("newRSETH"); - vm.prank(admin); - lrtConfig.setRSETH(newRSETH); - - assertEq(lrtConfig.rsETH(), newRSETH); - } - - function test_RevertSetTokenIfNotAdmin() external { - vm.expectRevert( - "AccessControl: account 0x7fa9385be102ac3eac297483dd6233d62b3e1496 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, address(this)); - } - - function test_RevertSetTokenIfTokenAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, address(0)); - vm.stopPrank(); - } - - function test_RevertSetTokenIfTokenAlreadySet() external { - address newToken = makeAddr("newToken"); - vm.startPrank(admin); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, newToken); - - // revert when same token was already set before - vm.expectRevert(ILRTConfig.ValueAlreadyInUse.selector); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, newToken); - vm.stopPrank(); - } - - function test_SetToken() external { - address newToken = makeAddr("newToken"); - - vm.prank(admin); - lrtConfig.setToken(LRTConstants.ST_ETH_TOKEN, newToken); - - assertEq(lrtConfig.tokenMap(LRTConstants.ST_ETH_TOKEN), newToken); - } - - function test_RevertSetContractIfNotAdmin() external { - vm.expectRevert( - "AccessControl: account 0x7fa9385be102ac3eac297483dd6233d62b3e1496 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000" - ); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(this)); - } - - function test_RevertSetContractIfContractAddressIsZero() external { - vm.startPrank(admin); - vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, address(0)); - vm.stopPrank(); - } - - function test_RevertSetContractIfContractAlreadySet() external { - address newContract = makeAddr("newContract"); - vm.startPrank(admin); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, newContract); - - // revert when same contract was already set before - vm.expectRevert(ILRTConfig.ValueAlreadyInUse.selector); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, newContract); - vm.stopPrank(); - } - - function test_SetContract() external { - address newContract = makeAddr("newContract"); - - vm.prank(admin); - lrtConfig.setContract(LRTConstants.LRT_ORACLE, newContract); - - assertEq(lrtConfig.contractMap(LRTConstants.LRT_ORACLE), newContract); - } - - function test_LRTOracleSetup() public { - assertLt(lrtOracle.getAssetPrice(ethXAddress), 1.2 ether); - assertGt(lrtOracle.getAssetPrice(ethXAddress) + 1, 1 ether); - - assertLt(lrtOracle.getAssetPrice(stETHAddress), 1.2 ether); - assertGt(lrtOracle.getAssetPrice(stETHAddress), 0.9 ether); - - assertEq(lrtOracle.assetPriceOracle(stETHAddress), stEthOracle); - assertEq(lrtOracle.assetPriceOracle(ethXAddress), ethxPriceOracle); - } - - function test_LRTOracleIsAlreadyInitialized() public { - // attempt to initialize LRTOracle again reverts - vm.expectRevert("Initializable: contract is already initialized"); - lrtOracle.initialize(address(lrtConfig)); - } - - function test_RevertWhenCallingUpdatePriceOracleForByANonLRTManager() external { - address randomAssetAddress = makeAddr("randomAssetAddress"); - address randomPriceOracleAddress = makeAddr("randomPriceOracleAddress"); - - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - lrtOracle.updatePriceOracleFor(randomAssetAddress, randomPriceOracleAddress); - } - - function test_IsAbleToUpdatePriceOracleForAssetByLRTManager() external { - address randomPriceOracleAddress = makeAddr("randomPriceOracleAddress"); - - vm.prank(manager); - lrtOracle.updatePriceOracleFor(stETHAddress, randomPriceOracleAddress); - - assertEq(lrtOracle.assetPriceOracle(stETHAddress), randomPriceOracleAddress); - } - - function test_RSETHSetup() public { - // check if lrtDepositPool has MINTER role - assertTrue(lrtConfig.hasRole(LRTConstants.MINTER_ROLE, address(lrtDepositPool))); - - // check if lrtConfig is set in rsETH - assertEq(address(rseth.lrtConfig()), address(lrtConfig)); - } - - function test_RSETHIsAlreadyInitialized() public { - // attempt to initialize RSETH again reverts - vm.expectRevert("Initializable: contract is already initialized"); - rseth.initialize(address(admin), address(lrtConfig)); - } - - function test_RevertWhenCallerIsNotLRTManager() external { - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - rseth.pause(); - } - - function test_RevertWhenContractIsAlreadyPaused() external { - vm.startPrank(manager); - rseth.pause(); - - vm.expectRevert("Pausable: paused"); - rseth.pause(); - - vm.stopPrank(); - } - - function test_Pause() external { - vm.startPrank(manager); - rseth.pause(); - - vm.stopPrank(); - - assertTrue(rseth.paused(), "Contract is not paused"); - } - - function test_Unpause() external { - vm.prank(manager); - rseth.pause(); - - assertTrue(rseth.paused(), "Contract is not paused"); - - vm.prank(admin); - rseth.unpause(); - - assertFalse(rseth.paused(), "Contract is not unpaused"); - } - - function test_NodeDelegatorIsAlreadyInitialized() public { - // attempt to initialize NodeDelegator again reverts - vm.expectRevert("Initializable: contract is already initialized"); - nodeDelegator1.initialize(address(lrtConfig)); - } - - function test_RevertWhenCallerIsNotLRTManagerNodeDelegator() external { - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDelegator1.pause(); - } - - function test_RevertWhenContractIsAlreadyPausedNodeDelegator() external { - vm.startPrank(manager); - nodeDelegator1.pause(); - - vm.expectRevert("Pausable: paused"); - nodeDelegator1.pause(); - - vm.stopPrank(); - } - - function test_PauseNodeDelegator() external { - vm.startPrank(manager); - nodeDelegator1.pause(); - - vm.stopPrank(); - - assertTrue(nodeDelegator1.paused(), "Contract is not paused"); - } - - function test_UnpauseNodeDelegator() external { - vm.prank(manager); - nodeDelegator1.pause(); - - assertTrue(nodeDelegator1.paused(), "Contract is not paused"); - - vm.prank(admin); - nodeDelegator1.unpause(); - - assertFalse(nodeDelegator1.paused(), "Contract is not unpaused"); - } - - function test_RevertWhenCallingMaxApproveToEigenStrategyManagerByCallerIsNotLRTManager() external { - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDelegator1.maxApproveToEigenStrategyManager(stETHAddress); - } - - function test_RevertWhenAssetIsNotSupportedInMaxApproveToEigenStrategyFunction() external { - address randomAddress = address(0x123); - vm.prank(manager); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - nodeDelegator1.maxApproveToEigenStrategyManager(randomAddress); - } - - function test_MaxApproveToEigenStrategyManager() external { - address eigenlayerStrategyManagerAddress = lrtConfig.getContract(LRTConstants.EIGEN_STRATEGY_MANAGER); - - vm.prank(manager); - nodeDelegator1.maxApproveToEigenStrategyManager(stETHAddress); - - // check that the nodeDelegator has max approved the eigen strategy manager - assertEq( - ERC20(stETHAddress).allowance(address(nodeDelegator1), eigenlayerStrategyManagerAddress), type(uint256).max - ); - } - - function test_RevertWhenCallingDepositAssetIntoStrategyAndNodeDelegatorIsPaused() external { - vm.startPrank(manager); - nodeDelegator1.pause(); - - vm.expectRevert("Pausable: paused"); - nodeDelegator1.depositAssetIntoStrategy(stETHAddress); - - vm.stopPrank(); - } - - function test_RevertWhenAssetIsNotSupportedInDepositAssetIntoStrategyFunction() external { - address randomAddress = address(0x123); - vm.prank(manager); - vm.expectRevert(ILRTConfig.AssetNotSupported.selector); - nodeDelegator1.depositAssetIntoStrategy(randomAddress); - } - - function test_RevertWhenCallingDepositAssetIntoStrategyAndCallerIsNotManager() external { - vm.expectRevert(ILRTConfig.CallerNotLRTConfigManager.selector); - nodeDelegator1.depositAssetIntoStrategy(stETHAddress); - } - - function test_DepositAssetIntoStrategyFromNodeDelegator() external { - if (block.chainid == 1) { - console.log("Skipping test_DepositAssetIntoStrategyFromNodeDelegator for mainnet"); - vm.skip(true); - } - - console.log( - "nodeDel stETH balance before submitting to strategy:", - ERC20(stETHAddress).balanceOf(address(nodeDelegator1)) - ); - - (uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer) = - lrtDepositPool.getAssetDistributionData(stETHAddress); - - console.log("#######"); - console.log("getAssetDistributionData for stETH BEFORE submitting funds to strategy"); - console.log("assetLyingInDepositPool", assetLyingInDepositPool); - console.log("assetLyingInNDCs", assetLyingInNDCs); - console.log("assetStakedInEigenLayer", assetStakedInEigenLayer); - console.log("#######"); - - address eigenlayerSTETHStrategyAddress = lrtConfig.assetStrategy(stETHAddress); - uint256 balanceOfStrategyBefore = ERC20(stETHAddress).balanceOf(eigenlayerSTETHStrategyAddress); - console.log("balanceOfStrategyBefore", balanceOfStrategyBefore); - - vm.startPrank(manager); - nodeDelegator1.maxApproveToEigenStrategyManager(stETHAddress); - nodeDelegator1.depositAssetIntoStrategy(stETHAddress); - vm.stopPrank(); - - uint256 balanceOfStrategyAfter = ERC20(stETHAddress).balanceOf(eigenlayerSTETHStrategyAddress); - console.log("balanceOfStrategyAfter", balanceOfStrategyAfter); - - console.log("stETH amount submitted to strategy", balanceOfStrategyAfter - balanceOfStrategyBefore); - - (assetLyingInDepositPool, assetLyingInNDCs, assetStakedInEigenLayer) = - lrtDepositPool.getAssetDistributionData(stETHAddress); - console.log("#######"); - console.log("getAssetDistributionData for stETH AFTER submitting funds to strategy"); - console.log("assetLyingInDepositPool", assetLyingInDepositPool); - console.log("assetLyingInNDCs", assetLyingInNDCs); - console.log("assetStakedInEigenLayer", assetStakedInEigenLayer); - - assertGt( - balanceOfStrategyAfter, - balanceOfStrategyBefore, - "Balance of strategy after is not greater than balance of strategy before tx" - ); - } -} diff --git a/test/integration/LRTNativeEthStakingIntegrationTest.t.sol b/test/integration/LRTNativeEthStakingIntegrationTest.t.sol deleted file mode 100644 index a02b512..0000000 --- a/test/integration/LRTNativeEthStakingIntegrationTest.t.sol +++ /dev/null @@ -1,318 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.21; - -import "forge-std/Test.sol"; - -import { ProxyFactory } from "script/foundry-scripts/utils/ProxyFactory.sol"; -import { LRTConfig, ILRTConfig, LRTConstants } from "contracts/LRTConfig.sol"; -import { RSETH } from "contracts/RSETH.sol"; -import { LRTOracle } from "contracts/LRTOracle.sol"; -import { OneETHPriceOracle } from "contracts/oracles/OneETHPriceOracle.sol"; -import { NodeDelegator } from "contracts/NodeDelegator.sol"; -import { LRTDepositPool } from "contracts/LRTDepositPool.sol"; -import { UtilLib } from "contracts/utils/UtilLib.sol"; -import { getLSTs } from "script/foundry-scripts/DeployLRT.s.sol"; -import { IEigenPod, IBeaconDeposit } from "contracts/interfaces/IEigenPod.sol"; - -import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -contract LRTNativeEthStakingIntegrationTest is Test { - uint256 public fork; - address public admin; - address public manager; - address public operator; - - ProxyFactory proxyFactory; - ProxyAdmin proxyAdmin; - LRTDepositPool public lrtDepositPool; - LRTConfig public lrtConfig; - RSETH public rseth; - LRTOracle public lrtOracle; - NodeDelegator public nodeDelegator1; - - function _upgradeAllContracts() internal { - vm.startPrank(admin); - - // upgrade lrtConfig - address proxyAddress = address(lrtConfig); - address newImplementation = address(new LRTConfig()); - proxyAdmin.upgrade(ITransparentUpgradeableProxy(proxyAddress), newImplementation); - - // upgrade lrtDepositPool - proxyAddress = address(lrtDepositPool); - newImplementation = address(new LRTDepositPool()); - proxyAdmin.upgrade(ITransparentUpgradeableProxy(proxyAddress), newImplementation); - - // upgrade all ndcs - address[] memory ndcs = lrtDepositPool.getNodeDelegatorQueue(); - newImplementation = address(new NodeDelegator()); - for (uint256 i = 0; i < ndcs.length; i++) { - proxyAddress = address(ndcs[i]); - proxyAdmin.upgrade(ITransparentUpgradeableProxy(proxyAddress), newImplementation); - } - - vm.stopPrank(); - - // Add eth as supported asset - vm.prank(admin); - lrtConfig.addNewSupportedAsset(LRTConstants.ETH_TOKEN, 100_000 ether); - - // add oracle for ETH - address oneETHOracle = address(new OneETHPriceOracle()); - vm.startPrank(manager); - lrtOracle.updatePriceOracleFor(LRTConstants.ETH_TOKEN, oneETHOracle); - vm.stopPrank(); - } - - function setUp() public { - string memory ethMainnetRPC = vm.envString("MAINNET_RPC_URL"); - fork = vm.createSelectFork(ethMainnetRPC); - - admin = 0xb9577E83a6d9A6DE35047aa066E3758221FE0DA2; - manager = 0xCbcdd778AA25476F203814214dD3E9b9c46829A1; - operator = makeAddr("operator"); - - proxyFactory = ProxyFactory(0x673a669425457bCabeb247f56552A0Fd8141cee2); - proxyAdmin = ProxyAdmin(0xb61e0E39b6d4030C36A176f576aaBE44BF59Dc78); - lrtDepositPool = LRTDepositPool(payable(0x036676389e48133B63a802f8635AD39E752D375D)); - lrtConfig = LRTConfig(0x947Cb49334e6571ccBFEF1f1f1178d8469D65ec7); - rseth = RSETH(0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7); - lrtOracle = LRTOracle(0x349A73444b1a310BAe67ef67973022020d70020d); - nodeDelegator1 = NodeDelegator(payable(0x07b96Cf1183C9BFf2E43Acf0E547a8c4E4429473)); - - // set eigen pod manager in lrt config - address eigenPodManager = 0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338; - vm.startPrank(admin); - lrtConfig.setContract(LRTConstants.EIGEN_POD_MANAGER, eigenPodManager); - lrtConfig.grantRole(LRTConstants.OPERATOR_ROLE, operator); - vm.stopPrank(); - - _upgradeAllContracts(); - } - - function test_completeNativeEthFlow() external { - address alice = makeAddr("alice"); - vm.deal(alice, 100 ether); - - // deposit by user alice - uint256 aliceBalanceBefore = alice.balance; - uint256 depositPoolBalanceBefore = address(lrtDepositPool).balance; - ( - uint256 assetLyingInDepositPoolInitially, - uint256 assetLyingInNDCsInitially, - uint256 assetStakedInEigenLayerInitially - ) = lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - - uint256 depositAmount = 66 ether; - vm.prank(alice); - lrtDepositPool.depositETH{ value: depositAmount }(0, ""); - - uint256 aliceBalanceAfter = alice.balance; - uint256 depositPoolBalanceAfter = address(lrtDepositPool).balance; - (uint256 assetLyingInDepositPoolNow, uint256 assetLyingInNDCsNow, uint256 assetStakedInEigenLayerNow) = - lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - - assertEq(aliceBalanceAfter, aliceBalanceBefore - depositAmount); - assertEq(depositPoolBalanceAfter, depositPoolBalanceBefore + depositAmount); - assertEq( - assetLyingInDepositPoolNow, - assetLyingInDepositPoolInitially + depositAmount, - "eth not transferred to deposit pool" - ); - assertEq(assetLyingInNDCsNow, assetLyingInNDCsInitially); - assertEq(assetStakedInEigenLayerNow, assetStakedInEigenLayerInitially); - - // move eth from deposit pool to ndc - vm.prank(manager); - lrtDepositPool.transferETHToNodeDelegator(0, depositAmount); - - (assetLyingInDepositPoolNow, assetLyingInNDCsNow, assetStakedInEigenLayerNow) = - lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - assertEq(assetLyingInDepositPoolNow, assetLyingInDepositPoolInitially); - assertEq(assetLyingInNDCsNow, assetLyingInNDCsInitially + depositAmount, "eth not transferred to ndc 0"); - assertEq(assetStakedInEigenLayerNow, assetStakedInEigenLayerInitially); - - // create eigen pod - vm.prank(manager); - nodeDelegator1.createEigenPod(); - - address eigenPod = address(nodeDelegator1.eigenPod()); - // same eigenPod address should be created - assertEq(eigenPod, 0xf7483e448c1B94Ea557A53d99ebe7b4feE0c91df, "Wrong eigenPod address"); - - // stake 32 eth for validator1 - bytes memory pubkey = - hex"8ff0088bf2bc73a41c74d1b1c6c997e4963ceffde55a09fef27596016d919b74b45372e8aa69fda5aac38a0c1a38dfd5"; - bytes memory signature = hex"95e07ee28de0316ecdf9b528c222d81242898ee0095e284582bb453d331b7760" - hex"6d8dca23ab8980459ea8a9b9710e2f740fceb1a1c221a7fd75eb3ef4a6b68809" - hex"f3e76387f01f5d31718e6306375b20b29cb08d1374c7fb125d50c1b2f5a5cc0b"; - - bytes32 depositDataRoot = hex"6f30f44f0d8dada6ba5d8fd617c727020c01c697587d1a04ff6661be656198bc"; - - vm.prank(operator); - nodeDelegator1.stake32Eth(pubkey, signature, depositDataRoot); - - (assetLyingInDepositPoolNow, assetLyingInNDCsNow, assetStakedInEigenLayerNow) = - lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - assertEq(assetLyingInDepositPoolNow, assetLyingInDepositPoolInitially); - assertEq(assetLyingInNDCsNow, assetLyingInNDCsInitially + depositAmount - 32 ether); - assertEq( - assetStakedInEigenLayerNow, - assetStakedInEigenLayerInitially + 32 ether, - "eth not staked at eigen layer for val1" - ); - - // stake 32 eth for validator2 - pubkey = hex"8f943ad38a85397243a5b2805cad3956f6bc46bcf001f58415ec9a14260fa449b1597a917393560f4a21d59852df30cc"; - signature = hex"88fda50f5197b4d3fc497bcabcd86f5d3c76ad67ff8e752bec96b74fc589ad27" - hex"3eee3aa72e836a26447680966f5d70900eff7eaaa4d047fe6da5c3d6093aa63c" - hex"614b443a82c74c9ebc1837efe2bef59e600e3f8008c7aac6bd2eacbffdbae6c4"; - - depositDataRoot = hex"fb0f1cf653ff793cd5973b3847e2f91c8cbab3dd22d1c59a8cf86fc5879dc592"; - - vm.prank(operator); - nodeDelegator1.stake32Eth(pubkey, signature, depositDataRoot); - - (assetLyingInDepositPoolNow, assetLyingInNDCsNow, assetStakedInEigenLayerNow) = - lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - assertEq(assetLyingInDepositPoolNow, assetLyingInDepositPoolInitially); - assertEq(assetLyingInNDCsNow, assetLyingInNDCsInitially + depositAmount - 64 ether); - assertEq( - assetStakedInEigenLayerNow, - assetStakedInEigenLayerInitially + 64 ether, - "eth not staked at eigen layer for val2" - ); - - // transfer 2 ether back to deposit pool - vm.prank(manager); - nodeDelegator1.transferBackToLRTDepositPool(LRTConstants.ETH_TOKEN, 2 ether); - - (assetLyingInDepositPoolNow, assetLyingInNDCsNow, assetStakedInEigenLayerNow) = - lrtDepositPool.getAssetDistributionData(LRTConstants.ETH_TOKEN); - assertEq(assetLyingInDepositPoolNow, assetLyingInDepositPoolInitially + 2 ether); - assertEq(assetLyingInNDCsNow, assetLyingInNDCsInitially); - assertEq( - assetStakedInEigenLayerNow, - assetStakedInEigenLayerInitially + 64 ether, - "eth not transferred back to deposit pool" - ); - } - - function test_stake32EthValidated() external returns (bytes32) { - // create eigen pod - vm.prank(manager); - nodeDelegator1.createEigenPod(); - - address eigenPod = address(nodeDelegator1.eigenPod()); - // same eigenPod address should be created - assertEq(eigenPod, 0xf7483e448c1B94Ea557A53d99ebe7b4feE0c91df, "Wrong eigenPod address"); - - // stake 32 eth for validator1 - bytes memory pubkey = - hex"8ff0088bf2bc73a41c74d1b1c6c997e4963ceffde55a09fef27596016d919b74b45372e8aa69fda5aac38a0c1a38dfd5"; - bytes memory signature = hex"95e07ee28de0316ecdf9b528c222d81242898ee0095e284582bb453d331b7760" - hex"6d8dca23ab8980459ea8a9b9710e2f740fceb1a1c221a7fd75eb3ef4a6b68809" - hex"f3e76387f01f5d31718e6306375b20b29cb08d1374c7fb125d50c1b2f5a5cc0b"; - - bytes32 depositDataRoot = hex"6f30f44f0d8dada6ba5d8fd617c727020c01c697587d1a04ff6661be656198bc"; - - IBeaconDeposit depositContract = IEigenPod(eigenPod).ethPOS(); - bytes32 expectedDepositRoot = depositContract.get_deposit_root(); - - vm.deal(address(nodeDelegator1), 32 ether); - uint256 balanceBefore = address(nodeDelegator1).balance; - - vm.startPrank(operator); - nodeDelegator1.stake32EthValidated(pubkey, signature, depositDataRoot, expectedDepositRoot); - - uint256 balanceAfter = address(nodeDelegator1).balance; - assertEq(balanceAfter, balanceBefore - 32 ether, "stake32eth unsuccesful"); - - return expectedDepositRoot; - } - - function test_withdrawRewards() external { - // create eigen pod - vm.prank(manager); - nodeDelegator1.createEigenPod(); - - address eigenPod = address(nodeDelegator1.eigenPod()); - // same eigenPod address should be created - assertEq(eigenPod, 0xf7483e448c1B94Ea557A53d99ebe7b4feE0c91df, "Wrong eigenPod address"); - - // stake 32 eth for validator1 - bytes memory pubkey = - hex"8ff0088bf2bc73a41c74d1b1c6c997e4963ceffde55a09fef27596016d919b74b45372e8aa69fda5aac38a0c1a38dfd5"; - bytes memory signature = hex"95e07ee28de0316ecdf9b528c222d81242898ee0095e284582bb453d331b7760" - hex"6d8dca23ab8980459ea8a9b9710e2f740fceb1a1c221a7fd75eb3ef4a6b68809" - hex"f3e76387f01f5d31718e6306375b20b29cb08d1374c7fb125d50c1b2f5a5cc0b"; - - bytes32 depositDataRoot = hex"6f30f44f0d8dada6ba5d8fd617c727020c01c697587d1a04ff6661be656198bc"; - - vm.deal(address(nodeDelegator1), 32 ether); - vm.startPrank(operator); - nodeDelegator1.stake32Eth(pubkey, signature, depositDataRoot); - - // eigenPod receives some rewards - uint256 rewardsAmount = 2.5 ether; - vm.deal(address(eigenPod), rewardsAmount); - - assertEq(address(eigenPod).balance, rewardsAmount); - - nodeDelegator1.initiateWithdrawRewards(); - - // rewards moves to delayedWithdrawalRouter - assertEq(address(eigenPod).balance, 0); - - console.log("block number before vm.roll: ", block.number); - // set block to 7 days after so that rewards can be claimed - vm.roll(block.number + 50_400); - console.log("block number after vm.roll: ", block.number); - - uint256 ndcBalanceBefore = address(nodeDelegator1).balance; - - nodeDelegator1.claimRewards(1); - - assertEq(address(nodeDelegator1).balance, ndcBalanceBefore + rewardsAmount); - - vm.stopPrank(); - } - - function test_removeNDCs() external { - // ------ STEP1: add NDCs --------- - - NodeDelegator nodeDelegatorImplementation = new NodeDelegator(); - bytes32 salt1 = keccak256(abi.encodePacked("test-ndc1")); - NodeDelegator testNodeDelegatorProxy1 = NodeDelegator( - payable(proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), salt1)) - ); - - bytes32 salt2 = keccak256(abi.encodePacked("test-ndc2")); - NodeDelegator testNodeDelegatorProxy2 = NodeDelegator( - payable(proxyFactory.create(address(nodeDelegatorImplementation), address(proxyAdmin), salt2)) - ); - - testNodeDelegatorProxy1.initialize(address(lrtConfig)); - testNodeDelegatorProxy2.initialize(address(lrtConfig)); - - address[] memory testNDCArray = new address[](2); - testNDCArray[0] = address(testNodeDelegatorProxy1); - testNDCArray[1] = address(testNodeDelegatorProxy2); - - // add ndcs to queue - vm.prank(admin); - lrtDepositPool.addNodeDelegatorContractToQueue(testNDCArray); - - assertTrue(lrtDepositPool.isNodeDelegator(address(testNodeDelegatorProxy1)) != 0); - assertTrue(lrtDepositPool.isNodeDelegator(address(testNodeDelegatorProxy2)) != 0); - - // ------ STEP2: remove NDCs --------- - - vm.prank(admin); - lrtDepositPool.removeManyNodeDelegatorContractsFromQueue(testNDCArray); - - assertTrue(lrtDepositPool.isNodeDelegator(address(testNodeDelegatorProxy1)) == 0); - assertTrue(lrtDepositPool.isNodeDelegator(address(testNodeDelegatorProxy2)) == 0); - } -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 5b23064..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true - } -}