diff --git a/.gitignore b/.gitignore index 73ebb4f..ff476bf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,9 @@ .env .env.local .env.production -.env.development + +# test +/deployed.json # dependencies /node_modules diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml new file mode 100644 index 0000000..7dc1249 --- /dev/null +++ b/.idea/git_toolbox_blame.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/liquid-staking-vault-cli.iml b/.idea/liquid-staking-vault-cli.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/liquid-staking-vault-cli.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3a9b7dc --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/abi/VaultFactory.ts b/abi/VaultFactory.ts new file mode 100644 index 0000000..2a12328 --- /dev/null +++ b/abi/VaultFactory.ts @@ -0,0 +1,272 @@ +export const VaultFactoryAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_owner", + type: "address" + }, + { + internalType: "address", + name: "_stakingVaultImpl", + type: "address" + }, + { + internalType: "address", + name: "_delegationImpl", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, + { + inputs: [ + { + internalType: "address", + name: "implementation", + type: "address" + } + ], + name: "BeaconInvalidImplementation", + type: "error" + }, + { + inputs: [], + name: "ERC1167FailedCreateClone", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address" + } + ], + name: "OwnableInvalidOwner", + type: "error" + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address" + } + ], + name: "OwnableUnauthorizedAccount", + type: "error" + }, + { + inputs: [ + { + internalType: "string", + name: "", + type: "string" + } + ], + name: "ZeroArgument", + type: "error" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "admin", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "delegation", + type: "address" + } + ], + name: "DelegationCreated", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address" + } + ], + name: "OwnershipTransferred", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "implementation", + type: "address" + } + ], + name: "Upgraded", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address" + }, + { + indexed: true, + internalType: "address", + name: "vault", + type: "address" + } + ], + name: "VaultCreated", + type: "event" + }, + { + inputs: [ + { + internalType: "bytes", + name: "_stakingVaultParams", + type: "bytes" + }, + { + components: [ + { + internalType: "uint256", + name: "managementFee", + type: "uint256" + }, + { + internalType: "uint256", + name: "performanceFee", + type: "uint256" + }, + { + internalType: "address", + name: "manager", + type: "address" + }, + { + internalType: "address", + name: "operator", + type: "address" + } + ], + internalType: "struct IDelegation.InitializationParams", + name: "_initializationParams", + type: "tuple" + }, + { + internalType: "address", + name: "_lidoAgent", + type: "address" + } + ], + name: "createVault", + outputs: [ + { + internalType: "contract IStakingVault", + name: "vault", + type: "address" + }, + { + internalType: "contract IDelegation", + name: "delegation", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "delegationImpl", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "implementation", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address" + } + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "newImplementation", + type: "address" + } + ], + name: "upgradeTo", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const; + + diff --git a/abi/index.ts b/abi/index.ts index 506ac62..6d6cc60 100644 --- a/abi/index.ts +++ b/abi/index.ts @@ -1,2 +1,3 @@ export * from "./StakingVault"; export * from "./VaultHub"; +export * from "./VaultFactory"; diff --git a/configs/constants.ts b/configs/constants.ts new file mode 100644 index 0000000..a9b8be7 --- /dev/null +++ b/configs/constants.ts @@ -0,0 +1,4 @@ +// import { Chain } from "viem/chains"; +import { holesky, mainnet } from 'viem/chains'; + +export const SUPPORTED_CHAINS_LIST = [holesky, mainnet]; diff --git a/configs/deployed-holesky-vaults-devnet-0.json b/configs/deployed-holesky-vaults-devnet-1.json similarity index 54% rename from configs/deployed-holesky-vaults-devnet-0.json rename to configs/deployed-holesky-vaults-devnet-1.json index 5c808b0..23c4c46 100644 --- a/configs/deployed-holesky-vaults-devnet-0.json +++ b/configs/deployed-holesky-vaults-devnet-1.json @@ -1,54 +1,64 @@ { "accounting": { - "contract": "contracts/0.8.9/Accounting.sol", - "address": "0x0AC1dA6AA962906dA7dDBE5e89fD672Cefb0AA75", - "constructorArgs": [ - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", - "0x56305bbD11C88c36ceAc6e32451DBa04b44DA811", - "0x1E5B4dF03cA640e5b769140B439813629A29b03a", - "0xB5506A7438c3a928A8Cb3428c064A8049E560661" - ] + "proxy": { + "contract": "contracts/0.8.9/proxy/OssifiableProxy.sol", + "address": "0xa9843a9214595f97fBF3434FC0Ea408bC598f232", + "constructorArgs": [ + "0x4810b7089255cfFDfd5F7dCD1997954fe1C86413", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + "0x" + ] + }, + "implementation": { + "contract": "contracts/0.8.25/Accounting.sol", + "address": "0x4810b7089255cfFDfd5F7dCD1997954fe1C86413", + "constructorArgs": [ + "0xBEC5b7D2eD56AA3040f9a80877cCF655c95F8D65", + "0xf8B477d407A230b4BCc0245050Ae83e91f85A61C", + "0xd40E43682A0Bf1EAbBD148D17378C24e3a112CdA" + ] + } }, "accountingOracle": { "deployParameters": { - "consensusVersion": 1 + "consensusVersion": 2 }, "proxy": { "contract": "contracts/0.8.9/proxy/OssifiableProxy.sol", - "address": "0x079705e95cdffbA56bD085a601460d3A916d6deE", + "address": "0x4B12C08Cc2FF439c655fD72e4e1Eaf9873a15779", "constructorArgs": [ - "0xaA44d9cab3Dc8982D3238aA2199a4894a87b02F9", - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", + "0x3e6dE85fc813D1CD3Be8cDA399C3870631A54738", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", "0x" ] }, "implementation": { "contract": "contracts/0.8.9/oracle/AccountingOracle.sol", - "address": "0xaA44d9cab3Dc8982D3238aA2199a4894a87b02F9", + "address": "0x3e6dE85fc813D1CD3Be8cDA399C3870631A54738", "constructorArgs": [ - "0x56305bbD11C88c36ceAc6e32451DBa04b44DA811", - "0x3f3B4F94e72e1d228E301d0d597838cc9636984d", + "0xBEC5b7D2eD56AA3040f9a80877cCF655c95F8D65", + "0x364344aE838544e3cE89424642a3FD4F168d82b8", 12, - 1639659600 + 1695902400 ] } }, "apmRegistryFactory": { "contract": "@aragon/os/contracts/factory/APMRegistryFactory.sol", - "address": "0xeBDB38D6412Ba9B3f2A77B107e476f4164B53EAf", + "address": "0x6052DDB672C083B5CC0c083fFF12D027CeF55159", "constructorArgs": [ - "0x76faff3102fFFf51396A44a3C3fCe5010B6B8cbA", - "0x010b51303106318E2F3C6Bce9AABB2Fa450290b7", - "0xdD2d34dD82e56b8e41311a39866F8Da26eF6CB1a", - "0xC1C1a2B157fB41c69509450FE1D3746F7178f9d7", - "0x794b3f32bdBA10f7513F9A751685B04Df6d8dfc3", + "0x558AD50d4EAD305e48CebB5a3F43a777DEd37b39", + "0xb89680dD40c7D9182849cb631D765eB2f407e69D", + "0x149D824176ECAF89855B082744E00b1c84732d6d", + "0x70371f312fA590c4114849aA303425d51790A84e", + "0x20F3A751d0877819F96092BeCB000369B9ecE268", "0x0000000000000000000000000000000000000000" ] }, "app:aragon-agent": { "implementation": { "contract": "@aragon/apps-agent/contracts/Agent.sol", - "address": "0x96aCA063681daAe3E61B8Aa1B2952951D5184c1D", + "address": "0x66ac7E71FF09A36668d62167349403DAB768194A", "constructorArgs": [] }, "aragonApp": { @@ -57,10 +67,10 @@ "id": "0x701a4fd1f5174d12a0f1d9ad2c88d0ad11ab6aad0ac72b7d9ce621815f8016a9" }, "proxy": { - "address": "0xB5506A7438c3a928A8Cb3428c064A8049E560661", + "address": "0xd40E43682A0Bf1EAbBD148D17378C24e3a112CdA", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0x701a4fd1f5174d12a0f1d9ad2c88d0ad11ab6aad0ac72b7d9ce621815f8016a9", "0x8129fc1c" ] @@ -69,7 +79,7 @@ "app:aragon-finance": { "implementation": { "contract": "@aragon/apps-finance/contracts/Finance.sol", - "address": "0xd46ac1EFC432bD95BB9c6Bf6965544105419C765", + "address": "0x191c29778A3047CdfA5ce668B93aB93bb3D5E895", "constructorArgs": [] }, "aragonApp": { @@ -78,19 +88,19 @@ "id": "0x5c9918c99c4081ca9459c178381be71d9da40e49e151687da55099c49a4237f1" }, "proxy": { - "address": "0x232C8d9b0CC14f0466e24a67D95E303628152f23", + "address": "0xb1AE4aD42D220981368D35C12200cFea0de5Fb28", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0x5c9918c99c4081ca9459c178381be71d9da40e49e151687da55099c49a4237f1", - "0x1798de81000000000000000000000000b5506a7438c3a928a8cb3428c064a8049e5606610000000000000000000000000000000000000000000000000000000000278d00" + "0x1798de81000000000000000000000000d40e43682a0bf1eabbd148d17378c24e3a112cda0000000000000000000000000000000000000000000000000000000000278d00" ] } }, "app:aragon-token-manager": { "implementation": { "contract": "@aragon/apps-lido/apps/token-manager/contracts/TokenManager.sol", - "address": "0x054E98A5e063c3d7589FF167Ab03b05cC5427324", + "address": "0x044035487bD1c3b77c7FF5574511D9D123FBFe22", "constructorArgs": [] }, "aragonApp": { @@ -99,10 +109,10 @@ "id": "0xcd567bdf93dd0f6acc3bc7f2155f83244d56a65abbfbefb763e015420102c67b" }, "proxy": { - "address": "0x79B48B8c15fBF4A80F6771a46af1ff49D6A7F7C7", + "address": "0x0cc5Ed95F24870da89ae995F272EDeb0c5Cffce6", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0xcd567bdf93dd0f6acc3bc7f2155f83244d56a65abbfbefb763e015420102c67b", "0x" ] @@ -111,7 +121,7 @@ "app:aragon-voting": { "implementation": { "contract": "@aragon/apps-lido/apps/voting/contracts/Voting.sol", - "address": "0x0Af17BFd40b9dF93512209B17dEFF0287f51f399", + "address": "0x27277234aa4Cd0b8c55dA8858b802589941627ea", "constructorArgs": [] }, "aragonApp": { @@ -120,19 +130,19 @@ "id": "0x0abcd104777321a82b010357f20887d61247493d89d2e987ff57bcecbde00e1e" }, "proxy": { - "address": "0xd3835fe7E2268EaeA917106B2Ba872c686688e50", + "address": "0x7a55843cc05B5023aEcAcB96de07b47396248070", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0x0abcd104777321a82b010357f20887d61247493d89d2e987ff57bcecbde00e1e", - "0x13e09453000000000000000000000000b3a9b35ad7c60e1a8a0fc252bb92daea45fe346900000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000384000000000000000000000000000000000000000000000000000000000000012c" + "0x13e0945300000000000000000000000014b34103938e67af28bbfd2c3dd36323559c2d3d00000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000384000000000000000000000000000000000000000000000000000000000000012c" ] } }, "app:lido": { "implementation": { "contract": "contracts/0.4.24/Lido.sol", - "address": "0xA36CFE98B582A5Be4c247B5aFb7CaAa77A2bc80F", + "address": "0x6786CF7509043c454644B8E9a6d1d54173E320BF", "constructorArgs": [] }, "aragonApp": { @@ -141,10 +151,10 @@ "id": "0x3ca7c3e38968823ccb4c78ea688df41356f182ae1d159e4ee608d30d68cef320" }, "proxy": { - "address": "0x1E5B4dF03cA640e5b769140B439813629A29b03a", + "address": "0xf8B477d407A230b4BCc0245050Ae83e91f85A61C", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0x3ca7c3e38968823ccb4c78ea688df41356f182ae1d159e4ee608d30d68cef320", "0x" ] @@ -153,7 +163,7 @@ "app:node-operators-registry": { "implementation": { "contract": "contracts/0.4.24/nos/NodeOperatorsRegistry.sol", - "address": "0x9498c2fEf38BfeacF184EaDC5b310C2F40aA7997", + "address": "0x0E853A6cF06C9F0D29D92A7c27d5e03277239c1A", "constructorArgs": [] }, "aragonApp": { @@ -162,10 +172,10 @@ "id": "0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d" }, "proxy": { - "address": "0x13F9Ef0CAC8679a1Edb22BACc08940828D5450A2", + "address": "0x1e52Ca7bE92b4CA66bF8f91716371A2487eC5EF2", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d", "0x" ] @@ -174,7 +184,7 @@ "app:oracle": { "implementation": { "contract": "contracts/0.4.24/oracle/LegacyOracle.sol", - "address": "0xEBeD4Dd48bF50ffD3849da1AedCFEd8052162B56", + "address": "0x733e2affc6887f3CD879f7D74aa18ae0fcBf61c9", "constructorArgs": [] }, "aragonApp": { @@ -183,10 +193,10 @@ "id": "0x8b47ba2a8454ec799cd91646e7ec47168e91fd139b23f017455f3e5898aaba93" }, "proxy": { - "address": "0x3f3B4F94e72e1d228E301d0d597838cc9636984d", + "address": "0x364344aE838544e3cE89424642a3FD4F168d82b8", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0x8b47ba2a8454ec799cd91646e7ec47168e91fd139b23f017455f3e5898aaba93", "0x" ] @@ -199,10 +209,10 @@ "id": "0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4" }, "proxy": { - "address": "0xe4deA753f8F29782E14c2a03Db8b79cd87676911", + "address": "0xA02c524Bf737BeAD8d703a94EFb32607330B534B", "contract": "@aragon/os/contracts/apps/AppProxyUpgradeable.sol", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0xe1635b63b5f7b5e545f2a637558a4029dea7905361a2f0fc28c66e9136cf86a4", "0x" ] @@ -211,13 +221,13 @@ "aragon-acl": { "implementation": { "contract": "@aragon/os/contracts/acl/ACL.sol", - "address": "0x0dC5cA1a9B671d1FF885668510d2E8BcaCC4c937", + "address": "0x43175FF60E2aCab56e0D79B680C6F179519c6FdB", "constructorArgs": [] }, "proxy": { - "address": "0xcb83f3B61e84e8C868eBa4723655a579a76C1Fb0", + "address": "0xBe2378978eaAfAef6fD2c2190C42C62D657c971e", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a", "0x00" ], @@ -231,19 +241,19 @@ "aragon-apm-registry": { "implementation": { "contract": "@aragon/os/contracts/apm/APMRegistry.sol", - "address": "0x010b51303106318E2F3C6Bce9AABB2Fa450290b7", + "address": "0xb89680dD40c7D9182849cb631D765eB2f407e69D", "constructorArgs": [] }, "proxy": { - "address": "0x30bc5fd2e870B74D0036F0A652e068DF84465b4a", + "address": "0x8e5537a5F8a21A26cdE8D9909DB1cf638eafa7D7", "contract": "@aragon/os/contracts/apm/APMRegistry.sol" } }, "aragon-evm-script-registry": { "proxy": { - "address": "0x1AA9F6869478fBaF138b39a510EfE12a491633Bf", + "address": "0x99d26EB0ABC80Dd688B5806D2d42ac8bC8475b84", "constructorArgs": [ - "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "0x208863a96e363157D1fef5CfDa64061b3010085F", "0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61", "0x00" ], @@ -254,7 +264,7 @@ "id": "0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61" }, "implementation": { - "address": "0xaaBd0570189Bca9C905b5DFC3f4A62A125FB3015", + "address": "0x3DEe956e6c65d3eA63C7cB11446bE53431946F7C", "contract": "@aragon/os/contracts/evmscript/EVMScriptRegistry.sol", "constructorArgs": [] } @@ -262,27 +272,27 @@ "aragon-kernel": { "implementation": { "contract": "@aragon/os/contracts/kernel/Kernel.sol", - "address": "0x812858282119C6267f466224E07A734AcA4dBbA5", + "address": "0x8BAaF7029C3a74c444F33e592D5c7e4B938Ed932", "constructorArgs": [true] }, "proxy": { - "address": "0xDd01d45B8C7409e685a359d77d24BeA513128947", + "address": "0x208863a96e363157D1fef5CfDa64061b3010085F", "contract": "@aragon/os/contracts/kernel/KernelProxy.sol", - "constructorArgs": ["0x812858282119C6267f466224E07A734AcA4dBbA5"] + "constructorArgs": ["0x8BAaF7029C3a74c444F33e592D5c7e4B938Ed932"] } }, "aragon-repo-base": { "contract": "@aragon/os/contracts/apm/Repo.sol", - "address": "0xdD2d34dD82e56b8e41311a39866F8Da26eF6CB1a", + "address": "0x149D824176ECAF89855B082744E00b1c84732d6d", "constructorArgs": [] }, "aragonEnsLabelName": "aragonpm", "aragonID": { - "address": "0xf605D4351Ed0Ab2592E58C085B4B0d1b031b2db9", + "address": "0xfcE523DaA916AbD5159eD139b1278e623D6EC83b", "contract": "@aragon/id/contracts/FIFSResolvingRegistrar.sol", "constructorArgs": [ - "0x794b3f32bdBA10f7513F9A751685B04Df6d8dfc3", - "0xA58844869dC3c07452cDD3cf4115019875699D8D", + "0x20F3A751d0877819F96092BeCB000369B9ecE268", + "0xfa0f59C62571A4180281FBc1597b1693eF9fF579", "0x7e74a86b6e146964fb965db04dc2590516da77f720bb6759337bf5632415fd86" ] }, @@ -292,17 +302,17 @@ "totalNonCoverSharesBurnt": "0" }, "contract": "contracts/0.8.9/Burner.sol", - "address": "0xfCc2A958730f0766478a3D1AAf6Bb6964A54de80", + "address": "0x042C857A4043d963C2cb56d1168B86952EFAe484", "constructorArgs": [ - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", - "0x56305bbD11C88c36ceAc6e32451DBa04b44DA811", - "0x1E5B4dF03cA640e5b769140B439813629A29b03a", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + "0xBEC5b7D2eD56AA3040f9a80877cCF655c95F8D65", + "0xf8B477d407A230b4BCc0245050Ae83e91f85A61C", "0", "0" ] }, "callsScript": { - "address": "0x4576eE717E00ec24fA7Bd95aca0388E30Fec3f22", + "address": "0xE551ceEfaa4DEb5dcDBa3307CCd12d2D7cfDbDEA", "contract": "@aragon/os/contracts/evmscript/executors/CallsScript.sol", "constructorArgs": [] }, @@ -310,18 +320,18 @@ "chainSpec": { "slotsPerEpoch": 32, "secondsPerSlot": 12, - "genesisTime": 1639659600, + "genesisTime": 1695902400, "depositContract": "0x4242424242424242424242424242424242424242" }, - "createAppReposTx": "0xa89180c57d0991e3a420aa4cab4e0647b12651f02b2c9a936a2380b1d2ae4a3b", + "createAppReposTx": "0x3f1c65d8fea4c25e0827e50d37cdd63947a6117d09c7a8621e9ff77a26ff1ce9", "daoAragonId": "lido-dao", "daoFactory": { - "address": "0x76faff3102fFFf51396A44a3C3fCe5010B6B8cbA", + "address": "0x558AD50d4EAD305e48CebB5a3F43a777DEd37b39", "contract": "@aragon/os/contracts/factory/DAOFactory.sol", "constructorArgs": [ - "0x812858282119C6267f466224E07A734AcA4dBbA5", - "0x0dC5cA1a9B671d1FF885668510d2E8BcaCC4c937", - "0x1D6BC250f5eE924BCc24b218D092d15Cd39e16A9" + "0x8BAaF7029C3a74c444F33e592D5c7e4B938Ed932", + "0x43175FF60E2aCab56e0D79B680C6F179519c6FdB", + "0x1142B39283A56f7e7C9596A1b26eab54442DBe7F" ] }, "daoInitialSettings": { @@ -341,43 +351,38 @@ "symbol": "TLDO" } }, - "deployer": "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", + "delegationImpl": { + "contract": "contracts/0.8.25/vaults/Delegation.sol", + "address": "0xac65d8Ddc91CDCE43775BA5dbF165D523D34D618", + "constructorArgs": ["0xf8B477d407A230b4BCc0245050Ae83e91f85A61C"] + }, + "deployer": "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", "depositSecurityModule": { "deployParameters": { - "maxDepositsPerBlock": 150, - "minDepositBlockDistance": 5, + "maxOperatorsPerUnvetting": 200, "pauseIntentValidityPeriodBlocks": 6646, - "usePredefinedAddressInstead": null + "usePredefinedAddressInstead": "0x22f05077bE05be96d213C6bDBD61C8f506CcD126" }, - "contract": "contracts/0.8.9/DepositSecurityModule.sol", - "address": "0xc4f5Fdcc2f5f20256876947F094a7E94AfDBbA0B", - "constructorArgs": [ - "0x1E5B4dF03cA640e5b769140B439813629A29b03a", - "0x4242424242424242424242424242424242424242", - "0x9Fd7Fa0615E72012C6Df1D0d46093B4b252957Cc", - 150, - 5, - 6646 - ] + "address": "0x22f05077be05be96d213c6bdbd61c8f506ccd126" }, "dummyEmptyContract": { "contract": "contracts/0.8.9/utils/DummyEmptyContract.sol", - "address": "0x368f850c98713E68F83ceB9d3852aa2a07359BAe", + "address": "0x176049Fa88115E6634d901eDfBe545827e1E1D2d", "constructorArgs": [] }, "eip712StETH": { "contract": "contracts/0.8.9/EIP712StETH.sol", - "address": "0xA9F7C23D49494555Ff5aa1AF2a44015c4Ed6b9CA", - "constructorArgs": ["0x1E5B4dF03cA640e5b769140B439813629A29b03a"] + "address": "0x7D762E9fe34Ad5a2a1f3d36daCd4C6ec66B9508D", + "constructorArgs": ["0xf8B477d407A230b4BCc0245050Ae83e91f85A61C"] }, "ens": { - "address": "0x794b3f32bdBA10f7513F9A751685B04Df6d8dfc3", - "constructorArgs": ["0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B"], + "address": "0x20F3A751d0877819F96092BeCB000369B9ecE268", + "constructorArgs": ["0x8928cB0EdcB60806900471049719dD2EFc0bDDc1"], "contract": "@aragon/os/contracts/lib/ens/ENS.sol" }, "ensFactory": { "contract": "@aragon/os/contracts/factory/ENSFactory.sol", - "address": "0x847C07DE654a56E4a2E7Ad312Fa109e8Ef8d3739", + "address": "0xDEB7f630bbDDc0230793e343Ea5e16f885Bd05E7", "constructorArgs": [] }, "ensNode": { @@ -387,19 +392,19 @@ "ensSubdomainRegistrar": { "implementation": { "contract": "@aragon/os/contracts/ens/ENSSubdomainRegistrar.sol", - "address": "0xC1C1a2B157fB41c69509450FE1D3746F7178f9d7", + "address": "0x70371f312fA590c4114849aA303425d51790A84e", "constructorArgs": [] } }, "evmScriptRegistryFactory": { "contract": "@aragon/os/contracts/factory/EVMScriptRegistryFactory.sol", - "address": "0x1D6BC250f5eE924BCc24b218D092d15Cd39e16A9", + "address": "0x1142B39283A56f7e7C9596A1b26eab54442DBe7F", "constructorArgs": [] }, "executionLayerRewardsVault": { "contract": "contracts/0.8.9/LidoExecutionLayerRewardsVault.sol", - "address": "0xd4fa4434AdA6d6F7905318620CED67D940998280", - "constructorArgs": ["0x1E5B4dF03cA640e5b769140B439813629A29b03a", "0xB5506A7438c3a928A8Cb3428c064A8049E560661"] + "address": "0x70D28986454Fa353dD6A6eBffe9281165505EB6c", + "constructorArgs": ["0xf8B477d407A230b4BCc0245050Ae83e91f85A61C", "0xd40E43682A0Bf1EAbBD148D17378C24e3a112CdA"] }, "gateSeal": { "address": null, @@ -414,15 +419,15 @@ "epochsPerFrame": 12 }, "contract": "contracts/0.8.9/oracle/HashConsensus.sol", - "address": "0xc108faD7D391cEaaD9185BE04125aF8e7A6b26cD", + "address": "0x5E1f8Bc90bf7EB188b8f8C1E85E49b2643A6514E", "constructorArgs": [ 32, 12, - 1639659600, + 1695902400, 12, 10, - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", - "0x079705e95cdffbA56bD085a601460d3A916d6deE" + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + "0x4B12C08Cc2FF439c655fD72e4e1Eaf9873a15779" ] }, "hashConsensusForValidatorsExitBusOracle": { @@ -431,22 +436,22 @@ "epochsPerFrame": 4 }, "contract": "contracts/0.8.9/oracle/HashConsensus.sol", - "address": "0x2ba358129B731066E11bae1121c13C1F6C7e5daD", + "address": "0x182e1A4F82312A14d823b3015C379f32094e36F6", "constructorArgs": [ 32, 12, - 1639659600, + 1695902400, 4, 10, - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", - "0xd4F1D70065Ef307807624fc0C6CB1fb011790823" + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + "0xB713d077276270dD2085aC2F2F1eeE916657952f" ] }, "ldo": { - "address": "0xB3A9b35Ad7C60E1A8a0fC252BB92daea45FE3469", + "address": "0x14B34103938E67af28BBFD2c3DD36323559C2D3D", "contract": "@aragon/minime/contracts/MiniMeToken.sol", "constructorArgs": [ - "0x053bA0A9Bf49FEae8Ff39Ab7987475d5d52BD9ea", + "0xcE3aD3640e040041D6d3F05E039c024c99048cD0", "0x0000000000000000000000000000000000000000", 0, "TEST Lido DAO Token", @@ -465,64 +470,68 @@ "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae", "0x90a9580abeb24937fc658e497221c81ce8553b560304f9525821f32b17dbdaec" ], - "deployTx": "0x801fe6cf2dfe2ed77bbda195754192d8b90bb12da21c3401deef9f9c119e97f5", - "address": "0xeC64689883Daed637b933533737e231Dad1Ef238" + "deployTx": "0x15995278c2de902a67d1b2ba02911b70100d1537f95eab78dd207a84e9d86763", + "address": "0xa5691e2F7845BEc116da22b09f6A6e121f40D26d" }, "lidoApmEnsName": "lidopm.eth", "lidoApmEnsRegDurationSec": 94608000, "lidoLocator": { "proxy": { "contract": "contracts/0.8.9/proxy/OssifiableProxy.sol", - "address": "0x56305bbD11C88c36ceAc6e32451DBa04b44DA811", + "address": "0xBEC5b7D2eD56AA3040f9a80877cCF655c95F8D65", "constructorArgs": [ - "0x368f850c98713E68F83ceB9d3852aa2a07359BAe", - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", + "0x176049Fa88115E6634d901eDfBe545827e1E1D2d", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", "0x" ] }, "implementation": { "contract": "contracts/0.8.9/LidoLocator.sol", - "address": "0x1c4DeB0666B6103059dF231c9e9f83b5DC3c05CD", + "address": "0xcd7F7aB3D3307b1624272079B68958e724207735", "constructorArgs": [ - [ - "0x079705e95cdffbA56bD085a601460d3A916d6deE", - "0xc4f5Fdcc2f5f20256876947F094a7E94AfDBbA0B", - "0xd4fa4434AdA6d6F7905318620CED67D940998280", - "0x3f3B4F94e72e1d228E301d0d597838cc9636984d", - "0x1E5B4dF03cA640e5b769140B439813629A29b03a", - "0xC40058aAD940f0eC1c1F54281F9B180A726B11D7", - "0xcbcCf679706C3c8bFf1F3CE11dBe1C63B157A382", - "0xfCc2A958730f0766478a3D1AAf6Bb6964A54de80", - "0x9Fd7Fa0615E72012C6Df1D0d46093B4b252957Cc", - "0xB5506A7438c3a928A8Cb3428c064A8049E560661", - "0xd4F1D70065Ef307807624fc0C6CB1fb011790823", - "0x4A4418BC9c06bA46C47e9Ab34a0D43f5d9EC3401", - "0x57bbC7542B9e682CF77F32F854D18E400F53dE00", - "0x0D691E92D5D0092A7a0D01abF42D745AA92375Ef", - "0x0AC1dA6AA962906dA7dDBE5e89fD672Cefb0AA75" - ] + { + "accountingOracle": "0x4B12C08Cc2FF439c655fD72e4e1Eaf9873a15779", + "depositSecurityModule": "0x22f05077bE05be96d213C6bDBD61C8f506CcD126", + "elRewardsVault": "0x70D28986454Fa353dD6A6eBffe9281165505EB6c", + "legacyOracle": "0x364344aE838544e3cE89424642a3FD4F168d82b8", + "lido": "0xf8B477d407A230b4BCc0245050Ae83e91f85A61C", + "oracleReportSanityChecker": "0x739e95c5FCCe141a41FEE2b7c070959f331d251D", + "postTokenRebaseReceiver": "0x0000000000000000000000000000000000000000", + "burner": "0x042C857A4043d963C2cb56d1168B86952EFAe484", + "stakingRouter": "0xf6F4a3eaF9a4Edd29ce8E9d41b70d87230813A14", + "treasury": "0xd40E43682A0Bf1EAbBD148D17378C24e3a112CdA", + "validatorsExitBusOracle": "0xB713d077276270dD2085aC2F2F1eeE916657952f", + "withdrawalQueue": "0x06099Fb9769960f6877dCa51CEe9fA1e39C3A623", + "withdrawalVault": "0x4eE9FaE342b9D8E77C2c2DE98f55DEF8D830EEBC", + "oracleDaemonConfig": "0x9FEE22428742b6eE03e9cad0f09121249b49D4c6", + "accounting": "0xa9843a9214595f97fBF3434FC0Ea408bC598f232" + } ] } }, "lidoTemplate": { "contract": "contracts/0.4.24/template/LidoTemplate.sol", - "address": "0x8433fd6842A830FbFEF0FC2F1FE77cd712e6C586", + "address": "0x06790abb259525Ec946c6DF68E7888437BAE40f9", "constructorArgs": [ - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", - "0x76faff3102fFFf51396A44a3C3fCe5010B6B8cbA", - "0x794b3f32bdBA10f7513F9A751685B04Df6d8dfc3", - "0x053bA0A9Bf49FEae8Ff39Ab7987475d5d52BD9ea", - "0xf605D4351Ed0Ab2592E58C085B4B0d1b031b2db9", - "0xeBDB38D6412Ba9B3f2A77B107e476f4164B53EAf" + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + "0x558AD50d4EAD305e48CebB5a3F43a777DEd37b39", + "0x20F3A751d0877819F96092BeCB000369B9ecE268", + "0xcE3aD3640e040041D6d3F05E039c024c99048cD0", + "0xfcE523DaA916AbD5159eD139b1278e623D6EC83b", + "0x6052DDB672C083B5CC0c083fFF12D027CeF55159" ], - "deployBlock": 2598198 + "deployBlock": 2909413 + }, + "lidoTemplateCreateStdAppReposTx": "0xc62a1f6ddf97e11d29cbeb13627a02e5a19bb1cb99c9c01a6506136794b12263", + "lidoTemplateNewDaoTx": "0xb04ecae4fdabfb8c77a55022010f52729793bfbc70100a61f6c1a75fe317be74", + "minFirstAllocationStrategy": { + "contract": "contracts/common/lib/MinFirstAllocationStrategy.sol", + "address": "0x99528570B420F4348519C4AB86dF5958A4BCfA11", + "constructorArgs": [] }, - "lidoTemplateCreateStdAppReposTx": "0x440936d67545ae94f30b534ecdf252ef85463c3b6786c48b9334a26f20997d25", - "lidoTemplateNewDaoTx": "0xfe1b7269188f4b23f329a9a3bc695198584ed5a0afc8a50ad9486bf51dc2979b", "miniMeTokenFactory": { - "address": "0x053bA0A9Bf49FEae8Ff39Ab7987475d5d52BD9ea", + "address": "0xcE3aD3640e040041D6d3F05E039c024c99048cD0", "contract": "@aragon/minime/contracts/MiniMeToken.sol", - "contractName": "MiniMeTokenFactory", "constructorArgs": [] }, "networkId": 17000, @@ -545,70 +554,87 @@ "FINALIZATION_MAX_NEGATIVE_REBASE_EPOCH_SHIFT": 1350 }, "contract": "contracts/0.8.9/OracleDaemonConfig.sol", - "address": "0x0D691E92D5D0092A7a0D01abF42D745AA92375Ef", - "constructorArgs": ["0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", []] + "address": "0x9FEE22428742b6eE03e9cad0f09121249b49D4c6", + "constructorArgs": ["0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", []] }, "oracleReportSanityChecker": { "deployParameters": { - "churnValidatorsPerDayLimit": 1500, - "oneOffCLBalanceDecreaseBPLimit": 500, + "exitedValidatorsPerDayLimit": 1500, + "appearedValidatorsPerDayLimit": 1500, + "deprecatedOneOffCLBalanceDecreaseBPLimit": 500, "annualBalanceIncreaseBPLimit": 1000, "simulatedShareRateDeviationBPLimit": 250, "maxValidatorExitRequestsPerReport": 2000, - "maxAccountingExtraDataListItemsCount": 100, - "maxNodeOperatorsPerExtraDataItemCount": 100, + "maxItemsPerExtraDataTransaction": 8, + "maxNodeOperatorsPerExtraDataItem": 24, "requestTimestampMargin": 128, - "maxPositiveTokenRebase": 5000000 + "maxPositiveTokenRebase": 5000000, + "initialSlashingAmountPWei": 1000, + "inactivityPenaltiesAmountPWei": 101, + "clBalanceOraclesErrorUpperBPLimit": 50 }, "contract": "contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol", - "address": "0xC40058aAD940f0eC1c1F54281F9B180A726B11D7", + "address": "0x739e95c5FCCe141a41FEE2b7c070959f331d251D", "constructorArgs": [ - "0x56305bbD11C88c36ceAc6e32451DBa04b44DA811", - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", - [1500, 500, 1000, 2000, 100, 100, 128, 5000000], - [[], [], [], [], [], [], [], [], [], []] + "0xBEC5b7D2eD56AA3040f9a80877cCF655c95F8D65", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + [1500, 1500, 1000, 2000, 8, 24, 128, 5000000, 1000, 101, 50] ] }, - "scratchDeployGasUsed": "128397470", + "scratchDeployGasUsed": "135112418", "simpleDvt": { "deployParameters": { - "stakingModuleTypeId": "curated-onchain-v1", + "stakingModuleTypeId": "simple-dvt-onchain-v1", "stuckPenaltyDelay": 432000 } }, "stakingRouter": { "proxy": { "contract": "contracts/0.8.9/proxy/OssifiableProxy.sol", - "address": "0x9Fd7Fa0615E72012C6Df1D0d46093B4b252957Cc", + "address": "0xf6F4a3eaF9a4Edd29ce8E9d41b70d87230813A14", "constructorArgs": [ - "0x2563ff1dF32A679fA5b5bb1d9081AefBf686BDC0", - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", + "0x0436AdbF0b556d2798E66d294Dc2fEF7Cc9E6b34", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", "0x" ] }, "implementation": { "contract": "contracts/0.8.9/StakingRouter.sol", - "address": "0x2563ff1dF32A679fA5b5bb1d9081AefBf686BDC0", + "address": "0x0436AdbF0b556d2798E66d294Dc2fEF7Cc9E6b34", "constructorArgs": ["0x4242424242424242424242424242424242424242"] } }, + "stakingVaultFactory": { + "contract": "contracts/0.8.25/vaults/VaultFactory.sol", + "address": "0x2250A629B2d67549AcC89633fb394e7C7c0B9c4b", + "constructorArgs": [ + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", + "0x6F3c4b0A577B9fb223E831804bAAaD99de7c3Cc8", + "0xac65d8Ddc91CDCE43775BA5dbF165D523D34D618" + ] + }, + "stakingVaultImpl": { + "contract": "contracts/0.8.25/vaults/StakingVault.sol", + "address": "0x6F3c4b0A577B9fb223E831804bAAaD99de7c3Cc8", + "constructorArgs": ["0xa9843a9214595f97fBF3434FC0Ea408bC598f232", "0x4242424242424242424242424242424242424242"] + }, "validatorsExitBusOracle": { "deployParameters": { "consensusVersion": 1 }, "proxy": { "contract": "contracts/0.8.9/proxy/OssifiableProxy.sol", - "address": "0xd4F1D70065Ef307807624fc0C6CB1fb011790823", + "address": "0xB713d077276270dD2085aC2F2F1eeE916657952f", "constructorArgs": [ - "0x901d768A22Bf3f53cf4714e54A75F26ECaB4A419", - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", + "0x263f466495B0BcBeFBE7220b657F5438e9155AB0", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", "0x" ] }, "implementation": { "contract": "contracts/0.8.9/oracle/ValidatorsExitBusOracle.sol", - "address": "0x901d768A22Bf3f53cf4714e54A75F26ECaB4A419", - "constructorArgs": [12, 1639659600, "0x56305bbD11C88c36ceAc6e32451DBa04b44DA811"] + "address": "0x263f466495B0BcBeFBE7220b657F5438e9155AB0", + "constructorArgs": [12, 1695902400, "0xBEC5b7D2eD56AA3040f9a80877cCF655c95F8D65"] } }, "vestingParams": { @@ -617,7 +643,7 @@ "0xCD1f9954330AF39a74Fd6e7B25781B4c24ee373f": "820000000000000000000000", "0xaa6bfBCD634EE744CB8FE522b29ADD23124593D3": "60000000000000000000000", "0xBA59A84C6440E8cccfdb5448877E26F1A431Fc8B": "60000000000000000000000", - "0xB5506A7438c3a928A8Cb3428c064A8049E560661": "60000000000000000000000" + "0xd40E43682A0Bf1EAbBD148D17378C24e3a112CdA": "60000000000000000000000" }, "start": 0, "cliff": 0, @@ -632,35 +658,35 @@ }, "proxy": { "contract": "contracts/0.8.9/proxy/OssifiableProxy.sol", - "address": "0x4A4418BC9c06bA46C47e9Ab34a0D43f5d9EC3401", + "address": "0x06099Fb9769960f6877dCa51CEe9fA1e39C3A623", "constructorArgs": [ - "0x655c6400dfD52E40EacE5552126F838906dFEB34", - "0x7D48d42F7DfcC967f7fCF54B32D5388371cD6b8B", + "0x37b59aEA4fFCEC7Aadd2E1D349ae8D0Fc1F24816", + "0x8928cB0EdcB60806900471049719dD2EFc0bDDc1", "0x" ] }, "implementation": { "contract": "contracts/0.8.9/WithdrawalQueueERC721.sol", - "address": "0x655c6400dfD52E40EacE5552126F838906dFEB34", - "constructorArgs": ["0xA91593Ca53b802d0F0Dc0a873e811Dd219CA8cAC", "Lido: stETH Withdrawal NFT", "unstETH"] + "address": "0x37b59aEA4fFCEC7Aadd2E1D349ae8D0Fc1F24816", + "constructorArgs": ["0xA97518A4C440a0047D7b997e06F7908AbcF25b45", "Lido: stETH Withdrawal NFT", "unstETH"] } }, "withdrawalVault": { "implementation": { "contract": "contracts/0.8.9/WithdrawalVault.sol", - "address": "0x19238F6ec1FF68ee29560326E3471b9341689881", - "constructorArgs": ["0x1E5B4dF03cA640e5b769140B439813629A29b03a", "0xB5506A7438c3a928A8Cb3428c064A8049E560661"] + "address": "0xfAbDC590Bac69A7D693b8953590a622DF2C2ffb5", + "constructorArgs": ["0xf8B477d407A230b4BCc0245050Ae83e91f85A61C", "0xd40E43682A0Bf1EAbBD148D17378C24e3a112CdA"] }, "proxy": { "contract": "contracts/0.8.4/WithdrawalsManagerProxy.sol", - "address": "0x57bbC7542B9e682CF77F32F854D18E400F53dE00", - "constructorArgs": ["0xd3835fe7E2268EaeA917106B2Ba872c686688e50", "0x19238F6ec1FF68ee29560326E3471b9341689881"] + "address": "0x4eE9FaE342b9D8E77C2c2DE98f55DEF8D830EEBC", + "constructorArgs": ["0x7a55843cc05B5023aEcAcB96de07b47396248070", "0xfAbDC590Bac69A7D693b8953590a622DF2C2ffb5"] }, - "address": "0x57bbC7542B9e682CF77F32F854D18E400F53dE00" + "address": "0x4eE9FaE342b9D8E77C2c2DE98f55DEF8D830EEBC" }, "wstETH": { "contract": "contracts/0.6.12/WstETH.sol", - "address": "0xA91593Ca53b802d0F0Dc0a873e811Dd219CA8cAC", - "constructorArgs": ["0x1E5B4dF03cA640e5b769140B439813629A29b03a"] + "address": "0xA97518A4C440a0047D7b997e06F7908AbcF25b45", + "constructorArgs": ["0xf8B477d407A230b4BCc0245050Ae83e91f85A61C"] } } diff --git a/configs/deployed.ts b/configs/deployed.ts index f894b03..156f294 100644 --- a/configs/deployed.ts +++ b/configs/deployed.ts @@ -1,32 +1,100 @@ import { lstatSync } from "fs"; import { resolve } from "path"; +import { zeroAddress, Address, Chain } from "viem"; +import { getValueByPath, resolvePath, validateConfig } from "@utils"; +import { JSONConfig } from "@types"; import { envs } from "./envs"; -import { getValueByPath } from "@utils"; -import { zeroAddress, Address } from "viem"; +import { SUPPORTED_CHAINS_LIST } from "./constants"; -export const importConfigFile = (path?: string) => { - const fullPath = resolve("configs", path ?? ""); - const json: Record> = {}; +export const importDeployFile = () => { + const fullPath = resolve("configs", envs?.DEPLOYED ?? ""); + if (!fullPath) { + throw new Error("Deployed contracts file is not set, check .env file"); + } + + let json: Record = {}; if (lstatSync(fullPath).isFile()) { - // eslint-disable-next-line @typescript-eslint/no-var-requires - Object.assign(json, require(fullPath)); + json = structuredClone(require(fullPath)); } return json; }; -export const getContracts = () => { - const deployedFile = envs?.DEPLOYED; +export const importConfigFile = () => { + const path = envs?.CONFIG ?? ''; + const fullPath = resolvePath(path, __dirname); - if (!deployedFile) { - throw new Error("Deployed contracts file is not set, check .env file"); + let json = {} as JSONConfig; + + if (lstatSync(fullPath).isFile()) { + json = structuredClone(require(fullPath)); + } + + return json; +}; + +export const getConfig = (() => { + const configJSON = importConfigFile(); + const errors = validateConfig(configJSON as unknown as JSONConfig); + const errorKeys = Object.keys(errors); + if (errorKeys.length > 0) { + errorKeys.forEach((key) => console.error(`${errors[key as keyof JSONConfig]}`)); + return () => null; + } + + return () => configJSON; +})(); + +export const getDeployed = (() => { + const deployedJSON = importDeployFile(); + + return () => deployedJSON; +})(); + +export const getChainId = (() => { + let chainId: number; + const config = getConfig(); + const deployed = getDeployed(); + + if (config) { + chainId = config.chainId as number; + } else if (deployed.chainId) { + chainId = deployed.chainId; + } else { + chainId = Number(process.env.CHAIN_ID); + } + + return () => chainId; +})(); + +export const getChain = (chainId?: number): Chain => { + const id = chainId ?? getChainId(); + const chain = SUPPORTED_CHAINS_LIST.find(chain => chain.id === id); + return chain ?? SUPPORTED_CHAINS_LIST[0] as Chain; +}; + +export const getRpcUrl = (() => { + let rpcUrl: string; + const config = getConfig(); + + if (config) { + rpcUrl = config.rpcLink as string; } - const mainDeployedJSON = importConfigFile(envs?.DEPLOYED); - const extraDeployedJSON = importConfigFile(`extra-${envs?.DEPLOYED}`); + return () => rpcUrl; +})(); + +export const getContracts = () => { + const config = getConfig(); + const deployedJSON = getDeployed(); + + if (config) { + const { lidoLocator, accounting } = config; + return { ...deployedJSON, lidoLocator, accounting } + } - return { ...mainDeployedJSON, ...extraDeployedJSON }; + return { ...deployedJSON }; }; export const getContractDeploy = (path: string) => { @@ -47,8 +115,8 @@ export const getDeployedAddress = (...contractKeys: string[]) => { throw new Error(`Contracts by ${contractKeys} not found`); } - if ("proxyAddress" in contract) { - return contract.proxyAddress as Address; + if ("proxy" in contract && typeof contract.proxy === 'object' && "address" in contract.proxy!) { + return contract.proxy.address as Address; } if ("address" in contract) { @@ -70,22 +138,22 @@ export const getAddressMap = () => { const contracts = getContracts(); return Object.entries(contracts).reduce((acc, [key, value]) => { - const name = value.contract || key; - const proxyAddress = - value.proxyAddress || (value.implementation && value.address); - const implementation = value.implementation; - const isNotProxy = !implementation && !proxyAddress; - - if (proxyAddress) { - acc[proxyAddress.toLowerCase()] = `Proxy (${name})`; + const name = value?.contract || key; + const proxy = + value?.proxy || (value?.implementation && value?.address); + const implementation = value?.implementation.address; + const isNotProxy = !implementation && !proxy; + + if (proxy) { + acc[proxy.toLowerCase()] = `Proxy (${name})`; } if (implementation) { acc[implementation.toLowerCase()] = `Implementation (${name})`; } - if (isNotProxy && value.address) { - acc[value.address.toLowerCase()] = name; + if (isNotProxy && value?.address) { + acc[value?.address.toLowerCase()] = name; } return acc; diff --git a/configs/envs.ts b/configs/envs.ts index 90b249b..1f529c9 100644 --- a/configs/envs.ts +++ b/configs/envs.ts @@ -2,15 +2,12 @@ import * as dotenv from "dotenv"; const { parsed } = dotenv.config(); -export const envs = parsed; +export const envs = structuredClone(parsed); if (envs) { - envs.DEPLOYED = envs?.DEPLOYED || (process.env.DEPLOYED as string); - envs.RPC_URL_1 = envs?.RPC_URL_1 || (process.env.RPC_URL_1 as string); - envs.RPC_URL_17000 = - envs?.RPC_URL_17000 || (process.env.RPC_URL_17000 as string); - - envs.PRIVATE_KEY_1 = - envs?.PRIVATE_KEY_1 || (process.env.PRIVATE_KEY_1 as string); - envs.PRIVATE_KEY_17000 = - envs?.PRIVATE_KEY_137 || (process.env.PRIVATE_KEY_137 as string); + envs.DEPLOYED = (process.env.DEPLOYED as string) ?? envs?.DEPLOYED; + envs.CONFIG = (process.env.CONFIG as string) ?? envs?.CONFIG ; + envs.RPC_URL_1 = (process.env.RPC_URL_1 as string) ?? envs?.RPC_URL_1; + envs.RPC_URL_17000 = (process.env.RPC_URL_17000 as string) ?? envs?.RPC_URL_17000; + envs.PRIVATE_KEY_1 = (process.env.PRIVATE_KEY_1 as string) ?? envs?.PRIVATE_KEY_1; + envs.PRIVATE_KEY_17000 = (process.env.PRIVATE_KEY_17000 as string) ?? envs?.PRIVATE_KEY_17000; } diff --git a/configs/extra-deployed-holesky-vaults-devnet-0.json b/configs/extra-deployed-holesky-vaults-devnet-1.json similarity index 100% rename from configs/extra-deployed-holesky-vaults-devnet-0.json rename to configs/extra-deployed-holesky-vaults-devnet-1.json diff --git a/contracts/index.ts b/contracts/index.ts index 5c5bf23..320bf1d 100644 --- a/contracts/index.ts +++ b/contracts/index.ts @@ -1,2 +1,3 @@ export * from "./vault-hub"; +export * from "./vault-factory"; export * from "./vault"; diff --git a/contracts/vault-factory.ts b/contracts/vault-factory.ts new file mode 100644 index 0000000..3971c8f --- /dev/null +++ b/contracts/vault-factory.ts @@ -0,0 +1,17 @@ +import { getContract, createPublicClient, http } from "viem"; +import { VaultFactoryAbi } from "abi"; +import { getDeployedAddress, envs, getRpcUrl, getChain } from "@configs"; + +export const getVaultFactoryContract = (chainId: number) => { + const rpcUrls = getRpcUrl() ?? envs?.[`RPC_URL_${chainId}`]; + const url = rpcUrls.split(',')[0]; + + return getContract({ + address: getDeployedAddress("stakingVaultFactory"), + abi: VaultFactoryAbi, + client: createPublicClient({ + chain: getChain(chainId), + transport: http(url), + }), + }); +}; diff --git a/contracts/vault-hub.ts b/contracts/vault-hub.ts index b0c7944..6bb81b4 100644 --- a/contracts/vault-hub.ts +++ b/contracts/vault-hub.ts @@ -1,18 +1,16 @@ -import { getContract, createPublicClient, http, Chain } from "viem"; +import { getContract, createPublicClient, http } from "viem"; import { VaultHubAbi } from "abi"; -import { getDeployedAddress, envs } from "@configs"; +import {getDeployedAddress, envs, getChain} from "@configs"; -export const getVaultHubContract = (chainId?: Chain) => { +export const getVaultHubContract = (chainId?: number) => { const rpcUrl = envs?.[`RPC_URL_${chainId || process.env.CHAIN_ID}`]; - const vaultHubContract = getContract({ + return getContract({ address: getDeployedAddress("accounting"), abi: VaultHubAbi, client: createPublicClient({ - chain: chainId, + chain: getChain(chainId), transport: http(rpcUrl), }), }); - - return vaultHubContract; }; diff --git a/contracts/vault.ts b/contracts/vault.ts index c09917a..389ebbe 100644 --- a/contracts/vault.ts +++ b/contracts/vault.ts @@ -5,7 +5,7 @@ import { envs } from "@configs"; export const getStakingVaultContract = (address: Address, chainId?: Chain) => { const rpcUrl = envs?.[`RPC_URL_${chainId || process.env.CHAIN_ID}`]; - const vaultHubContract = getContract({ + return getContract({ address, abi: StakingVaultAbi, client: createPublicClient({ @@ -13,6 +13,4 @@ export const getStakingVaultContract = (address: Address, chainId?: Chain) => { transport: http(rpcUrl), }), }); - - return vaultHubContract; }; diff --git a/features/index.ts b/features/index.ts new file mode 100644 index 0000000..f5444af --- /dev/null +++ b/features/index.ts @@ -0,0 +1 @@ +export * from './vault-factory'; diff --git a/features/vault-factory.ts b/features/vault-factory.ts new file mode 100644 index 0000000..bc816c1 --- /dev/null +++ b/features/vault-factory.ts @@ -0,0 +1,36 @@ +import {getChain, getChainId, getDeployedAddress} from "@configs"; +import { getAccount } from "@providers"; +import { VaultPayload } from "@types"; +import { getVaultFactoryContract } from "@contracts"; + +export async function* createVault({ + chainId, + manager, + operator, + quantity, + managementFee, + performanceFee, +}: VaultPayload) { + const id = chainId ?? getChainId() + const contract = getVaultFactoryContract(id); + const chain = getChain(id); + + for (let _ of Array.from(Array(quantity))) { + yield await contract.write.createVault( + [ + '0x', + { + managementFee, + performanceFee, + manager, + operator, + }, + getDeployedAddress('app:aragon-agent'), + ], + { + account: getAccount(chain.id), + chain, + } + ); + } +} diff --git a/package.json b/package.json index bbb7d19..93dec3c 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,12 @@ }, "devDependencies": { "@swc/core": "^1.7.42", - "@types/node": "^22.8.5", + "@types/node": "^22.10.2", "semantic-release": "^24.2.0", "ts-node": "^10.9.2", "tsc-alias": "^1.8.10", "tsconfig-paths": "^4.2.0", - "typescript": "^5.6.3" + "typescript": "^5.7.2" }, "release": { "branches": [ diff --git a/programs/config.ts b/programs/config.ts new file mode 100644 index 0000000..d04bfd3 --- /dev/null +++ b/programs/config.ts @@ -0,0 +1,35 @@ +import { readFileSync, existsSync } from "node:fs"; +import { resolve } from "node:path"; + +import { program } from "@command"; +import { validateConfig } from "@utils"; +import { JSONConfig } from "@types"; + +program + .command('conf ') + .description('Load and validate a JSON configuration file') + .action((filePath) => { + try { + const absolutePath = resolve(filePath); + if (!existsSync(absolutePath)) { + program.error(`File not found: ${absolutePath}`, { exitCode: 1 }); + } + + const rawData = readFileSync(absolutePath, 'utf-8'); + const config = JSON.parse(rawData); + + const errors = validateConfig(config); + const errorKeys = Object.keys(errors); + if (errorKeys.length > 0) { + errorKeys.forEach((key) => program.error(`${key} - ${errors[key as keyof JSONConfig]}`)); + process.exit(1); + } + + console.log('Configuration is valid!'); + } catch (error) { + if (error instanceof Error) { + console.error('Error loading or validating JSON file:', error.message); + } + process.exit(1); + } + }); diff --git a/programs/index.ts b/programs/index.ts index 5c5bf23..ab0d75c 100644 --- a/programs/index.ts +++ b/programs/index.ts @@ -1,2 +1,3 @@ export * from "./vault-hub"; export * from "./vault"; +export * from "./vault-factory"; diff --git a/programs/vault-factory.ts b/programs/vault-factory.ts new file mode 100644 index 0000000..5754b9a --- /dev/null +++ b/programs/vault-factory.ts @@ -0,0 +1,59 @@ +import { Address, isAddress, isAddressEqual } from "viem"; +import { program } from "@command"; +import { ChainOption } from "@types"; +import { createVault } from "@features"; + +const vaultFactory = program.command("vf").description("vault factory contract"); + +vaultFactory + .command("create-vault") + .description("create vault contract and assign manager and operator") + .option("-c, --chainId ", "chainId") + .option("-m, --manager ", "manager address") + .option("-o, --operator ", "operator address") + .option("-q, --quantity ", "quantity of vaults to create, default 1, max 10") + .argument("", "Vault owner fee, for e.g. 100 == 1%") + .argument("", "Node operator fee, for e.g. 100 == 1%") + .action( + async ( + ownerFee: string, + operatorFee: string, + { chainId, manager, operator, quantity = '1' }: ChainOption & { manager: Address, operator: Address, quantity: string } + ) => { + const managementFee = BigInt(ownerFee); + const performanceFee = BigInt(operatorFee); + const qnt = parseInt(quantity); + + if (!isAddress(manager)) { + program.error("manager address is not valid", { exitCode: 1 }); + } + + if (!isAddress(operator)) { + program.error("operator address is not valid", { exitCode: 1 }); + } + + if (isAddressEqual(manager, operator)) { + program.error("manager address can't be equal operator address", { exitCode: 1 }); + } + + if (isNaN(qnt)) { + program.error("quantity must be a number", { exitCode: 1 }); + } + + const payload = { + quantity: qnt, + chainId, + manager, + operator, + managementFee, + performanceFee, + } + + const transactions = [] + for await (const tx of createVault(payload)) { + transactions.push(tx); + } + + console.table(transactions); + } + ); diff --git a/programs/vault-hub.ts b/programs/vault-hub.ts index eb78787..1936816 100644 --- a/programs/vault-hub.ts +++ b/programs/vault-hub.ts @@ -1,21 +1,35 @@ +import { Address } from "viem"; import { program } from "@command"; import { getVaultHubContract } from "@contracts"; import { getAccount } from "@providers"; +import { ChainOption } from "@types"; +import {getChain} from "@configs"; const vaultHub = program.command("vh").description("vault hub contract"); +// constants - get vault hub constants +// v-count - get vaults count +// vi - get vault and vault socket by index +// va - get vault socket by address +// v-connect - connects a vault to the hub +// v-force-rebalance - force rebalance of the vault to have sufficient reserve ratio +// v-role-admin - returns the admin role that controls `role` +// v-role-member - returns one of the accounts that have `role` +// v-role-member-count - returns the number of accounts that have `role` +// v-role-has - returns `true` if `account` has been granted `role` + vaultHub .command("constants") .description("get vault hub constants") .option("-c, --chainId ", "chainId") - .action(async ({ chainId }) => { + .action(async ({ chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const VAULT_MASTER_ROLE = await contract.read.VAULT_MASTER_ROLE(); const DEFAULT_ADMIN_ROLE = await contract.read.DEFAULT_ADMIN_ROLE(); const STETH = await contract.read.stETH(); const TREASURY = await contract.read.treasury(); - const address = await contract.address; + const address = contract.address; console.table({ VAULT_MASTER_ROLE, @@ -30,7 +44,7 @@ vaultHub .command("v-count") .description("get vaults count") .option("-c, --chainId ", "chainId") - .action(async ({ chainId }) => { + .action(async ({ chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const vaultsCount = await contract.read.vaultsCount(); @@ -41,22 +55,35 @@ vaultHub }); vaultHub - .command("v") - .description("get vault") + .command("vi") + .description("get vault and vault socket by index") .option("-c, --chainId ", "chainId") .argument("", "index") - .action(async (index, { chainId }) => { + .action(async (index: readonly [bigint], { chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const vault = await contract.read.vault(index); const vaultSocket = await contract.read.vaultSocket(index); console.table({ - vault, - vaultSocket, + Vault: vault, + "Vault Socket": vaultSocket, }); }); +vaultHub + .command("va") + .description("get vault socket by address") + .option("-c, --chainId ", "chainId") + .argument("
", "address") + .action(async (address: readonly [Address], { chainId }: ChainOption) => { + const contract = getVaultHubContract(chainId); + + const vaultSocket = await contract.read.vaultSocket(address); + + console.table({ "Vault Socket": vaultSocket }); + }); + vaultHub .command("v-connect") .description("connects a vault to the hub") @@ -74,12 +101,12 @@ vaultHub .argument("", "treasury fee in basis points") .action( async ( - vault, - shareLimit, - reserveRatio, - reserveRatioThreshold, - treasuryFeeBP, - { chainId } + vault: Address, + shareLimit: bigint, + reserveRatio: bigint, + reserveRatioThreshold: bigint, + treasuryFeeBP: bigint, + { chainId }: ChainOption ) => { const contract = getVaultHubContract(chainId); @@ -87,13 +114,11 @@ vaultHub [vault, shareLimit, reserveRatio, reserveRatioThreshold, treasuryFeeBP], { account: getAccount(chainId), - chain: chainId, + chain: getChain(chainId), } ); - console.table({ - Transaction: tx, - }); + console.table({ Transaction: tx }); } ); @@ -102,12 +127,12 @@ vaultHub .description("force rebalance of the vault to have sufficient reserve ratio") .option("-c, --chainId ", "chainId") .argument("", "vault address") - .action(async (vault, { chainId }) => { + .action(async (vault: Address, { chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const tx = await contract.write.forceRebalance([vault], { account: getAccount(chainId), - chain: chainId, + chain: getChain(chainId), }); console.table({ @@ -121,7 +146,7 @@ vaultHub .description("returns the admin role that controls `role`") .option("-c, --chainId ", "chainId") .argument("", "role") - .action(async (role, { chainId }) => { + .action(async (role: readonly [Address], { chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const roleAdmin = await contract.read.getRoleAdmin(role); @@ -137,7 +162,11 @@ vaultHub .option("-c, --chainId ", "chainId") .argument("", "role") .argument("", "index") - .action(async (role, index, { chainId }) => { + .action(async ( + role: readonly [Address, bigint], + index, + { chainId }: ChainOption + ) => { const contract = getVaultHubContract(chainId); const roleMember = await contract.read.getRoleMember(role, index); @@ -153,7 +182,7 @@ vaultHub .option("-c, --chainId ", "chainId") .argument("", "role") .argument("", "index") - .action(async (role, index, { chainId }) => { + .action(async (role: readonly [Address], index, { chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const roleMemberCount = await contract.read.getRoleMemberCount(role, index); @@ -169,7 +198,7 @@ vaultHub .option("-c, --chainId ", "chainId") .argument("", "role") .argument("", "account") - .action(async (role, account, { chainId }) => { + .action(async (role: readonly [Address, Address], account, { chainId }: ChainOption) => { const contract = getVaultHubContract(chainId); const roleHas = await contract.read.hasRole(role, account); diff --git a/programs/vault.ts b/programs/vault.ts index edd5578..69b90f8 100644 --- a/programs/vault.ts +++ b/programs/vault.ts @@ -1,11 +1,27 @@ import { program } from "@command"; import { getStakingVaultContract } from "@contracts"; import { getAccount } from "@providers"; -import { parseEther } from "viem"; +import {Address, parseEther} from "viem"; const vault = program.command("v").description("vault contract"); // Views +// info - get vault base info +// l-report - get latest vault report +// valuation - get vault valuation +// is-healthy - get vault isHealthy +// unlocked - get vault unlocked +// wc - get vault withdrawal credentials +// fund - fund vault +// withdraw - withdraw from vault +// rebalance - rebalance vault // ?? +// no-deposit-beacon -deposit to beacon chain +// no-val-exit - request to exit validator + +// ? - quick creation any number of Vaults +// delta - inOutDelta +// ? - connect Vaults to VaultHub through protocol voting +// ? - change user permissions / roles by quorum of a pair of addresses vault .command("info") @@ -97,7 +113,6 @@ vault }); // Functions - vault .command("fund") .description("fund vault") @@ -152,7 +167,6 @@ vault }); // NOs - vault .command("no-deposit-beacon") .description("deposit to beacon chain") @@ -191,3 +205,16 @@ vault console.table({ Transaction: tx }); }); + +vault + .command("delta") + .description("the net difference between deposits and withdrawals") + .argument("", "vault address") + .option("-c, --chainId ", "chainId") + .action(async (vault: Address, { chainId }) => { + const contract = getStakingVaultContract(vault, chainId); + + const inOutDelta = await contract.read.inOutDelta(); + + console.table({ 'In Out Delta': inOutDelta }); + }); diff --git a/providers/wallet.ts b/providers/wallet.ts index 48aa4eb..15528b8 100644 --- a/providers/wallet.ts +++ b/providers/wallet.ts @@ -1,37 +1,40 @@ -import { Address, Chain, createWalletClient, http } from "viem"; +import { Address, createWalletClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -import { envs } from "@configs"; +import { envs, getConfig, getChainId, getRpcUrl, getChain } from "@configs"; -export const getWalletClient = (chainId?: Chain) => { - const rpcUrl = envs?.[`RPC_URL_${chainId || process.env.CHAIN_ID}`]; +export const getWalletClient = (chainId?: number) => { + const id = getChainId() ?? chainId; + const rpcUrls = getRpcUrl() ?? envs?.[`RPC_URL_${id}`]; + const url = rpcUrls.split(',')[0]; const client = createWalletClient({ - chain: chainId, - transport: http(rpcUrl), + chain: getChain(id), + transport: http(url), }); return client; }; -export const getAccount = (chainId?: Chain) => { - const privateKey = envs?.[`PRIVATE_KEY_${chainId || process.env.CHAIN_ID}`]; +export const getAccount = (chainId?: number) => { + const config = getConfig(); + const id = chainId ?? getChainId(); + const privateKey = config?.privateKey ?? envs?.[`PRIVATE_KEY_${id}`]; if (!privateKey) { - throw new Error(`PRIVATE_KEY_${chainId} is not set`); + throw new Error(`Private key for ${id} chain is not set`); } - const account = privateKeyToAccount(privateKey as Address); - - return account; + return privateKeyToAccount(privateKey as Address); }; -export const getWalletWithAccount = (chainId?: Chain) => { +export const getWalletWithAccount = (chainId?: number) => { const rpcUrl = envs?.[`RPC_URL_${chainId || process.env.CHAIN_ID}`]; + const id = chainId ?? getChainId(); - const account = getAccount(chainId); + const account = getAccount(id); const client = createWalletClient({ account, - chain: chainId, + chain: getChain(id), transport: http(rpcUrl), }); diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..3a10310 --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +yarn --silent node ./dist/index.js "$@" diff --git a/tsconfig.json b/tsconfig.json index 744ad82..e2092e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,9 @@ "@scripts": ["scripts"], "@utils": ["utils"], "@abi": ["abi"], - "@providers": ["providers"] + "@providers": ["providers"], + "@features": ["features"], + "@types": ["types"] }, "outDir": "dist", "sourceMap": true, diff --git a/types/common.ts b/types/common.ts new file mode 100644 index 0000000..dffe0fc --- /dev/null +++ b/types/common.ts @@ -0,0 +1,10 @@ +export type ChainOption = { chainId: number }; + +export interface VaultPayload { + chainId: number; + manager: string; + operator: string; + quantity: number; + managementFee: bigint; + performanceFee: bigint; +} diff --git a/types/config.ts b/types/config.ts new file mode 100644 index 0000000..77f491c --- /dev/null +++ b/types/config.ts @@ -0,0 +1,7 @@ +export interface JSONConfig { + rpcLink: string | undefined; + privateKey: string | undefined; + chainId: number | undefined; + lidoLocator: string | undefined; + accounting: string | undefined; +} diff --git a/types/index.ts b/types/index.ts new file mode 100644 index 0000000..82e9bc5 --- /dev/null +++ b/types/index.ts @@ -0,0 +1,2 @@ +export * from "./config"; +export * from "./common"; diff --git a/utils/data-validators.ts b/utils/data-validators.ts new file mode 100644 index 0000000..f3aeca8 --- /dev/null +++ b/utils/data-validators.ts @@ -0,0 +1,47 @@ +import { isAddress } from "viem"; + +import { JSONConfig } from "@types"; + +export const validateConfig = (config: JSONConfig) => { + const errors = {} as Record; + + if (!isValidUrl(config.rpcLink)) { + errors.rpcLink = 'Invalid rpcLink: must be a valid URL.'; + } + + if (typeof config.privateKey !== 'string' || !config.privateKey) { + errors.privateKey = 'Invalid privateKey: must be a non-empty string.'; + } + + if (typeof config.chainId !== 'number' || isNaN(config.chainId)) { + errors.chainId = 'Invalid chainId: must be a string representing a number.'; + } + + if (typeof config.lidoLocator !== 'string' || !isAddress(config.lidoLocator)) { + errors.lidoLocator = 'Invalid lidoLocator: must be a valid Ethereum address.'; + } + + if (typeof config.accounting !== 'string' || !isAddress(config.accounting)) { + errors.accounting = 'Invalid accounting: must be a valid Ethereum address.'; + } + + return errors; +} + +export const isValidUrl = (value: string | undefined): boolean => { + if (!value) { + return false; + } + + if ('canParse' in URL) { + return URL.canParse(value); + } + + try { + // used global here to avid types issue + new global.URL(value); + return true; + } catch { + return false; + } +} diff --git a/utils/index.ts b/utils/index.ts index 50816ce..bc91468 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -1 +1,3 @@ export * from "./get-value"; +export * from "./data-validators"; +export * from "./resolve-path"; diff --git a/utils/resolve-path.ts b/utils/resolve-path.ts new file mode 100644 index 0000000..45c15ca --- /dev/null +++ b/utils/resolve-path.ts @@ -0,0 +1,10 @@ +import { isAbsolute, join, resolve } from "path"; +import { homedir } from "os"; + +export function resolvePath(path: string, dir: string ) { + return path.startsWith('~') + ? join(homedir(), path.slice(1)) + : isAbsolute(path) + ? path + : resolve(dir, path); +} diff --git a/yarn.lock b/yarn.lock index 5404467..b7c2752 100644 --- a/yarn.lock +++ b/yarn.lock @@ -738,12 +738,12 @@ "@tufjs/canonical-json" "2.0.0" minimatch "^9.0.5" -"@types/node@^22.8.5": - version "22.8.5" - resolved "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz" - integrity sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA== +"@types/node@^22.10.2": + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== dependencies: - undici-types "~6.19.8" + undici-types "~6.20.0" "@types/normalize-package-data@^2.4.3": version "2.4.4" @@ -3546,20 +3546,20 @@ type-fest@^4.6.0, type-fest@^4.7.1: resolved "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz" integrity sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg== -typescript@^5.6.3: - version "5.6.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz" - integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== +typescript@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" + integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== uglify-js@^3.1.4: version "3.19.3" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz" integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== -undici-types@~6.19.8: - version "6.19.8" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== unicode-emoji-modifier-base@^1.0.0: version "1.0.0"