diff --git a/.gitmodules b/.gitmodules
index 409e7e1f7..0c911cbe2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,26 +1,10 @@
-[submodule "scripts/ledger/resources/app-bitcoin"]
- path = scripts/ledger/resources/app-bitcoin
- url = https://github.com/LedgerHQ/app-bitcoin-new.git
-[submodule "scripts/ledger/resources/app-ethereum"]
- path = scripts/ledger/resources/app-ethereum
- url = https://github.com/LedgerHQ/app-ethereum.git
-[submodule "scripts/ledger/resources/app-solana"]
- path = scripts/ledger/resources/app-solana
- url = https://github.com/LedgerHQ/app-solana.git
-[submodule "scripts/ledger/resources/speculos"]
- path = scripts/ledger/resources/speculos
- url = https://github.com/LedgerHQ/speculos.git
-[submodule "scripts/trezor/resources/trezor-user-env"]
- path = scripts/trezor/resources/trezor-user-env
- url = https://github.com/trezor/trezor-user-env.git
[submodule "contracts/ethereum/scripts/resources/ssv-network"]
path = contracts/ethereum/scripts/resources/ssv-network
url = https://github.com/bloxapp/ssv-network.git
- branch = contract-v3
+ branch = jato-v2
[submodule "contracts/ethereum/lib/forge-std"]
path = contracts/ethereum/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "services/oracle/scripts/resources/rockx-dkg-cli"]
path = services/oracle/scripts/resources/rockx-dkg-cli
- url = https://github.com/RockX-SG/rockx-dkg-cli.git
- branch = main
+ url = https://github.com/consensusnetworks/rockx-dkg-cli.git
diff --git a/README.md b/README.md
index eca5280a3..5db9bc1d1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
# Casimir
@@ -41,15 +41,11 @@ Configure the following prerequisite global dependency versions.
1. [Docker (v24.x)](https://docs.docker.com/engine/install/).
-2. [Git (v2.x)](https://git-scm.com/downloads)
+2. [Go (v1.18.x)](https://golang.org/doc/install).
- > 🚩 GitHub submodule support: You also need to make sure to have at least one SSH authentication key on your GitHub account (for the git cloning of submodules in various scripts). See [Adding a new SSH key to your GitHub account](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account).
+3. [Node.js (v18.x)](https://nodejs.org/en/download/).
-3. [Go (v1.18.x)](https://golang.org/doc/install).
-
-4. [Node.js (v18.x)](https://nodejs.org/en/download/).
-
-5. [Optional: AWS CLI (v2.x)](https://aws.amazon.com/cli/)
+4. [Optional: AWS CLI (v2.x)](https://aws.amazon.com/cli/)
> 🚩 **Consensus Networks team only**: Create an [AWS profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) named `consensus-networks-dev`.
@@ -129,13 +125,9 @@ echo "USE_SECRETS=false" > .env
| `VIEWS_ADDRESS` | Views contract address | (predicted views address) |
| `CRYPTO_COMPARE_API_KEY` | CryptoCompare API key | `` |
| `TUNNEL` | Whether to tunnel local network RPC URLs (for remote wallets) | `false` |
-| `EMULATE` | Whether to emulate wallets | `false` |
-| `LEDGER_APP` | Ledger app name | `ethereum` |
| `MOCK_SERVICES` | Whether to mock backend services | `true` |
| `BUILD_PREVIEW` | Whether to preview web app production build | `false` |
- > 🚩 While running the Ledger Speculos emulator on MacOS (with EMULATORS=true), if you get a surprising error that port 5000 is in use, go to > System Preferences... > Sharing and uncheck Airplay Receiver.
-
### Apps
The apps packages provide a UI to end-users.
@@ -192,8 +184,6 @@ The common packages provide shared code for the project:
- [@casimir/aws](common/aws): AWS helpers
- [@casimir/data](common/data): data schemas and operational workflows
-- [@casimir/helpers](common/helpers): general utilities
-- [@casimir/speculos](common/speculos): Ledger emulator helpers
- [@casimir/ssv](common/ssv): SSV helpers
- [@casimir/types](common/types): shared types
- [@casimir/uniswap](common/uniswap): Uniswap helpers
diff --git a/apps/landing/package.json b/apps/landing/package.json
index f64faa219..5fc9a9bd3 100644
--- a/apps/landing/package.json
+++ b/apps/landing/package.json
@@ -5,7 +5,7 @@
"version": "0.0.1",
"scripts": {
"dev": "vite",
- "build": "vue-tsc --noEmit && vite build",
+ "build": "vite build",
"preview": "vite preview"
},
"dependencies": {
diff --git a/apps/web/src/composables/contracts.ts b/apps/web/src/composables/contracts.ts
index 6c1483437..fb06259ea 100644
--- a/apps/web/src/composables/contracts.ts
+++ b/apps/web/src/composables/contracts.ts
@@ -1,9 +1,9 @@
import { ref, readonly } from 'vue'
import { ethers } from 'ethers'
import { CasimirManager, CasimirRegistry, CasimirViews } from '@casimir/ethereum/build/@types'
-import ICasimirManagerAbi from '@casimir/ethereum/build/abi/ICasimirManager.json'
-import ICasimirRegistryAbi from '@casimir/ethereum/build/abi/ICasimirRegistry.json'
-import ICasimirViewsAbi from '@casimir/ethereum/build/abi/ICasimirViews.json'
+import CasimirManagerAbi from '@casimir/ethereum/build/abi/CasimirManager.json'
+import CasimirRegistryAbi from '@casimir/ethereum/build/abi/CasimirRegistry.json'
+import CasimirViewsAbi from '@casimir/ethereum/build/abi/CasimirViews.json'
import useEnvironment from './environment'
import useEthers from '@/composables/ethers'
import useLedger from '@/composables/ledger'
@@ -14,9 +14,9 @@ import { Operator } from '@casimir/ssv'
const { ethereumUrl, managerAddress, registryAddress, viewsAddress } = useEnvironment()
const provider = new ethers.providers.JsonRpcProvider(ethereumUrl)
-const manager: CasimirManager & ethers.Contract = new ethers.Contract(managerAddress, ICasimirManagerAbi, provider) as CasimirManager
-const views: CasimirViews & ethers.Contract = new ethers.Contract(viewsAddress, ICasimirViewsAbi, provider) as CasimirViews
-const registry: CasimirRegistry & ethers.Contract = new ethers.Contract(registryAddress, ICasimirRegistryAbi, provider) as CasimirRegistry
+const manager: CasimirManager & ethers.Contract = new ethers.Contract(managerAddress, CasimirManagerAbi, provider) as CasimirManager
+const views: CasimirViews & ethers.Contract = new ethers.Contract(viewsAddress, CasimirViewsAbi, provider) as CasimirViews
+const registry: CasimirRegistry & ethers.Contract = new ethers.Contract(registryAddress, CasimirRegistryAbi, provider) as CasimirRegistry
const operators = ref([])
const { ethersProviderList, getEthersBrowserSigner } = useEthers()
@@ -107,7 +107,7 @@ export default function useContracts() {
async function _querySSVOperators(address: string) {
try {
const network = 'prater'
- const url = `https://api.ssv.network/api/v3/${network}/operators/owned_by/${address}`
+ const url = `https://api.ssv.network/api/v4/${network}/operators/owned_by/${address}`
const response = await fetch(url)
const { operators } = await response.json()
return operators
diff --git a/apps/web/src/composables/environment.ts b/apps/web/src/composables/environment.ts
index 277831f60..0b4791602 100644
--- a/apps/web/src/composables/environment.ts
+++ b/apps/web/src/composables/environment.ts
@@ -13,7 +13,7 @@ export default function useEnvironment() {
const speculosUrl = import.meta.env.PUBLIC_SPECULOS_URL ? 'http://localhost:5001' : ''
const cryptoCompareApiKey = import.meta.env.PUBLIC_CRYPTO_COMPARE_API_KEY || ''
const ssvNetworkAddress = import.meta.env.PUBLIC_SSV_NETWORK_ADDRESS
- const ssvNetworkViewsAddress = import.meta.env.PUBLIC_SSV_NETWORK_VIEWS_ADDRESS
+ const ssvViewsAddress = import.meta.env.PUBLIC_SSV_VIEWS_ADDRESS
const walletConnectProjectId = import.meta.env.PUBLIC_WALLET_CONNECT_PROJECT_ID
return {
@@ -26,7 +26,7 @@ export default function useEnvironment() {
registryAddress,
speculosUrl,
ssvNetworkAddress,
- ssvNetworkViewsAddress,
+ ssvViewsAddress,
usersUrl,
viewsAddress,
walletConnectProjectId
diff --git a/apps/web/src/composables/operators.ts b/apps/web/src/composables/operators.ts
index c6625c318..2b39dd992 100644
--- a/apps/web/src/composables/operators.ts
+++ b/apps/web/src/composables/operators.ts
@@ -9,7 +9,7 @@ import useLedger from '@/composables/ledger'
import useTrezor from '@/composables/trezor'
const { manager, registry, views } = useContracts()
-const { ethereumUrl, ssvNetworkAddress, ssvNetworkViewsAddress, usersUrl } = useEnvironment()
+const { ethereumUrl, ssvNetworkAddress, ssvViewsAddress, usersUrl } = useEnvironment()
const { ethersProviderList, getEthersBrowserSigner } = useEthers()
const { getEthersLedgerSigner } = useLedger()
const { getEthersTrezorSigner } = useTrezor()
@@ -51,7 +51,7 @@ export default function useOperators() {
const scanner = new Scanner({
ethereumUrl,
ssvNetworkAddress,
- ssvNetworkViewsAddress
+ ssvViewsAddress
})
const ssvOperators: Operator[] = []
@@ -68,14 +68,14 @@ export default function useOperators() {
const pools = await _getPools(operator.id)
// TODO: Replace these Public Nodes URLs once we have this working again
const operatorStore = {
- '654': 'https://nodes.casimir.co/eth/goerli/dkg/1',
- '655': 'https://nodes.casimir.co/eth/goerli/dkg/2',
- '656': 'https://nodes.casimir.co/eth/goerli/dkg/3',
- '657': 'https://nodes.casimir.co/eth/goerli/dkg/4',
- '658': 'https://nodes.casimir.co/eth/goerli/dkg/5',
- '659': 'https://nodes.casimir.co/eth/goerli/dkg/6',
- '660': 'https://nodes.casimir.co/eth/goerli/dkg/7',
- '661': 'https://nodes.casimir.co/eth/goerli/dkg/8'
+ '200': 'https://nodes.casimir.co/eth/goerli/dkg/1',
+ '201': 'https://nodes.casimir.co/eth/goerli/dkg/2',
+ '202': 'https://nodes.casimir.co/eth/goerli/dkg/3',
+ '203': 'https://nodes.casimir.co/eth/goerli/dkg/4',
+ '156': 'https://nodes.casimir.co/eth/goerli/dkg/5',
+ '157': 'https://nodes.casimir.co/eth/goerli/dkg/6',
+ '158': 'https://nodes.casimir.co/eth/goerli/dkg/7',
+ '159': 'https://nodes.casimir.co/eth/goerli/dkg/8'
}
const url = operatorStore[operator.id.toString() as keyof typeof operatorStore]
casimirOperators.push({
@@ -108,7 +108,7 @@ export default function useOperators() {
]
for (const poolId of poolIds) {
- const poolDetails = await views.getPoolDetails(poolId)
+ const poolDetails = await views.getPool(poolId)
const pool = {
...poolDetails,
operatorIds: poolDetails.operatorIds.map(id => id.toNumber()),
diff --git a/casimir.png b/casimir.png
new file mode 100644
index 000000000..2579c9134
Binary files /dev/null and b/casimir.png differ
diff --git a/common/aws/src/index.ts b/common/aws/src/index.ts
index 774c0097b..3d3e6188e 100644
--- a/common/aws/src/index.ts
+++ b/common/aws/src/index.ts
@@ -15,6 +15,9 @@ export async function getSecret(id: string) {
}
)
)
+ if (!SecretString) {
+ throw new Error(`No secret found for ${id}`)
+ }
return SecretString
}
diff --git a/common/data/notebooks/dkg.ipynb b/common/data/notebooks/dkg.ipynb
index fa36b335f..9c7e9c0a0 100644
--- a/common/data/notebooks/dkg.ipynb
+++ b/common/data/notebooks/dkg.ipynb
@@ -9,7 +9,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 2,
"metadata": {},
"outputs": [
{
diff --git a/common/data/notebooks/ethereum.ipynb b/common/data/notebooks/ethereum.ipynb
index 05755ad8a..dbd920ca4 100644
--- a/common/data/notebooks/ethereum.ipynb
+++ b/common/data/notebooks/ethereum.ipynb
@@ -9,16 +9,15 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Casimir mainnet node is fully synced\n",
- "Casimir goerli node is fully synced\n",
- "Casimir hardhat node is fully synced\n"
+ "Local goerli node is fully synced\n",
+ "Casimir goerli node is fully synced\n"
]
}
],
@@ -29,15 +28,15 @@
"from requests.auth import HTTPBasicAuth\n",
"\n",
"networks = {\n",
- " \"mainnet\": {\n",
- " \"requires_auth\": True\n",
- " },\n",
+ " # \"mainnet\": {\n",
+ " # \"requires_auth\": True\n",
+ " # },\n",
" \"goerli\": {\n",
" \"requires_auth\": True\n",
" },\n",
- " \"hardhat\": {\n",
- " \"requires_auth\": False\n",
- " }\n",
+ " # \"hardhat\": {\n",
+ " # \"requires_auth\": False\n",
+ " # }\n",
"}\n",
"\n",
"for network, requires_auth in networks.items():\n",
diff --git a/common/data/src/index.ts b/common/data/src/index.ts
index 227729d09..49667d698 100644
--- a/common/data/src/index.ts
+++ b/common/data/src/index.ts
@@ -5,6 +5,7 @@ import eventSchema from './schemas/event.schema.json'
import nonceSchema from './schemas/nonce.schema.json'
import operatorSchema from './schemas/operator.schema.json'
import operatorStore from './mock/operator.store.json'
+import reshareStore from './mock/reshare.store.json'
import userAccountSchema from './schemas/user_account.schema.json'
import userSchema from './schemas/user.schema.json'
import userStore from './mock/user.store.json'
@@ -21,6 +22,7 @@ export {
nonceSchema,
operatorSchema,
operatorStore,
+ reshareStore,
userAccountSchema,
userSchema,
userStore,
diff --git a/common/data/src/mock/operator.store.json b/common/data/src/mock/operator.store.json
index 0a966e755..e80cd6f6d 100644
--- a/common/data/src/mock/operator.store.json
+++ b/common/data/src/mock/operator.store.json
@@ -1,10 +1,10 @@
{
- "654": "https://nodes.casimir.co/eth/goerli/dkg/1",
- "655": "https://nodes.casimir.co/eth/goerli/dkg/2",
- "656": "https://nodes.casimir.co/eth/goerli/dkg/3",
- "657": "https://nodes.casimir.co/eth/goerli/dkg/4",
- "658": "https://nodes.casimir.co/eth/goerli/dkg/5",
- "659": "https://nodes.casimir.co/eth/goerli/dkg/6",
- "660": "https://nodes.casimir.co/eth/goerli/dkg/7",
- "661": "https://nodes.casimir.co/eth/goerli/dkg/8"
+ "200": "https://nodes.casimir.co/eth/goerli/dkg/1",
+ "201": "https://nodes.casimir.co/eth/goerli/dkg/2",
+ "202": "https://nodes.casimir.co/eth/goerli/dkg/3",
+ "203": "https://nodes.casimir.co/eth/goerli/dkg/4",
+ "156": "https://nodes.casimir.co/eth/goerli/dkg/5",
+ "157": "https://nodes.casimir.co/eth/goerli/dkg/6",
+ "158": "https://nodes.casimir.co/eth/goerli/dkg/7",
+ "159": "https://nodes.casimir.co/eth/goerli/dkg/8"
}
\ No newline at end of file
diff --git a/common/data/src/mock/reshare.store.json b/common/data/src/mock/reshare.store.json
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/common/data/src/mock/reshare.store.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/common/data/src/mock/validator.store.json b/common/data/src/mock/validator.store.json
index 160a4daaa..493df82b3 100644
--- a/common/data/src/mock/validator.store.json
+++ b/common/data/src/mock/validator.store.json
@@ -1,110 +1,110 @@
{
- "0xBE5F02D2d08994288aCF53ddC47d8150d41fb3A8": [
+ "0x728474D29c2F81eb17a669a7582A2C17f1042b57": [
{
- "depositDataRoot": "0x19a73151c03825f77d9189c63cac4dbb1e7612169d197ae8f250e6ba4292921d",
- "publicKey": "0xa0b59a472e7285b483209c9c2767e12f58cc63942d4ec0693eed8de63970ffe709648fdcb2df5978daed79e07a7d32f9",
+ "depositDataRoot": "0x7f015dfc19584b9ed78aa63b2633ed4874dacedcd9cebd35aa1f3a286b86c2ea",
+ "publicKey": "0xb82225b10959ffe81b2cd29583ed3086bd78dacc3f87b6e59259ab2c8f9e462a302bf548e1525c5db4502865200b14fa",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0xb910dc5253f89cd35a0d32aa074abd87a0e9be983e28353d036822dc8b6ad711427427fb63d7fe725c164583a9c8136e086b3bd07ca0ea3b8fbcb200f27a3e3907d277721055661e917d6c863f6ea1100edfb3e18ae9d6362f7efe939aadba64b0c023dbf48fce54d7a7c8e3659ad3d750903a0a1e7177d22c8008c764181a9e760e480b599f4569549b98be9e89ccce929ebf2026e8c0fcd65a7bc5f78962b387287b3dc1d51abc4ecc0edc8970b175f206bd23f97dfc40b3ac56fc1db8cff48170e0778a8dc3a23643e546a1eb5e7a9fc2198110f62a2b073c7dc082cc44f7b1c362efde11d7103ef542af3f6ae5cd9580df5da3fa8a6f5f798dada01045aedb67d1b4293e229b80e05fb68b723107551d1edbe2d92bcb9c3942de8048b7588e90b2d15c085a76b485830d4eb5953e44b8d772f0644e0c792f296784c9d229cd12f917c635390c0621a78d1f83586135d5e68545c237516168b6b02160abb64cba187e7af3de58c89f780d248c17efc1b87286d2cb361bf0be0d462ba1dac8448919b4c8201285a3df545ed829d413f701979080ab38372a4c08edaa5e4bd61ffff751ee8e8aae3a84315acf738720db28305b82664e99cb77b1bf29c0e520cb73899d3c816a58616dae3c99d80b86c0ee3c642292c21606e07e3a01af6418d4292d00a3409700861504fcc35ae6481dbb47f8236a31b8db4ff66a19a2e1daa7bac3f06e1f13d12cdb8195d874fee520c88a56ec170154f727df9f573290af247bced65fb749c150e9f55c36fd9a7f4e27847f44784b4168c4e84f640c1985eab2db3a10ea86c39db72bbf7887fca68c1bb57acb9fc4e026e472b5b20f6a7d94e008a7927a711bb6984291a9eb13d09dd37ee1c3c10ee98df8af3a7d5385d43a75b0345b583aae3eff7b473bddc50beb0b8065d56ddf6f9e40a5a0fce138ea7283bd1edb9d9598ebda8f61d8d1f32a5d3f24b5a511e44e43aba80c5781eafd2be8f7faee3e35eef64d17dd886e19ba9f5007d6e34503fecc10e6aee471f6379e79e3dddce69be24c6d1ba26bdfdc91253fe2478c6491604d20a981795397c17a68ea25bc1997de04367a528f4f49c8e800b46d0b936239f044d4748e7c278ca46f277ecaf26db8ddabcc30a080f7ed016a8d70d2b59544566cb9a0219cb06e6e91a8dc6f8bcbab1a5a0e5a87266bce146e0549b11ede56fe9011a045c33c51bdc83d1d976da81503d062464a0988e6236ba5f83e96d64b7498fade79b9ba61314860e6c7f44fbaa59b033e455860e158a524c90131c300b2dba5254893e404ec8a72e7f1fa3e1c70a2b3b33eb4aab2971b8428ee040d36b31e0513a9cb0c64967507731d6e5924cf6d322ae12578717d4d2c5d9de23161146813ba78af79979f81d85abba6e5d68afed7ef861a501955d393b6082b47906e30e2cd9cd29d6c05bfb8908d2353664de40cb87c2015b7159615a734b86537ed32cedb1a9f29fc8a3327647a2e54447a579b35774d628f0a00d696773dbd6d429d61a2df7eaf68b0c744520659673177ad8e1471e97cf450133350634de544b869a7518108bd8d8e321a67194f322fea9c104e92198f0566cd43da3113706676b8341a3eab774cf38b4886b7874595a1548fe11e1da2c9ba2b5fc493dd08b6aba8639fb2af44349184d7c614295b31e5c8196d47df49a91f18e39c300171fa9b78142b20ebe99f096e2da65effbe169d4693a3333fac0602fb4f7cab2bfde990498357db24a34a2b46546448945d339789aca7dbb23b0cb1dbedc8518b5a9f7d0023eec098ec7cd92851f0b47080f5d321766ccc48a716d18ef8993f0c0969bc1cbca011aeb28a",
- "signature": "0x96de39e812d39644d96d7a2ffaa0dd30d9eef10ffd2c8349dd04edcf3744e956670f99706219fea001e8fc77b8643fb20e3f26d15e5068f430f0eae7ac5d5687f9f88f11141698d406ec05e57ad2280304796bf6a459d442899b2e240eee3068",
- "withdrawalCredentials": "0x010000000000000000000000A53116986049763045bDF08042f85928DC66621A"
+ "shares": "0xb70b8ccaf8627cf16adfd75f228f81432b21235bef7ca4e5750b2b95cd444a86092e4094edaf0365e69d8cdccf937480182c97286fab6eaae460d19e01a3bda8a6ba66ca3b3bd05e97edb6652b89cfd8d0c63c6cf8e1a085e18a271301c0ab1694a7819dc29733b75ff227aa04bb4c95a04c4522a6f1b4c2552bb35f1dde0cb2609c8c0c8b297290c3f4ab9d6013422baf1d7a1109fdbed050632aec8730529dc16e6b0365a87da72dd2aa6c763ffdac09297fe0343a6a615be1300345807dc6a3cf0e774c1078c8a815213db3023325456674e5469b364abf5dc534c8f53eadfdb3c36bf881268195c5fbcab5523b03b9b6d322af21dda4922e73a3ed8ab7747c622e22939dfcb9624e9a07b4ef761bf0d381acd45c9c14481977aeee72fe080d5b76b9d427d8e1c020e858f7d97071e0e0d3a362d6fcd3bb40520e4bab8ad1a021b78ea1d46cda64bdcba91935fe94806c94b1c5957e4ed42121ecef5e670ce3aacfb8775526591771a8ea6a754379747afa7162d3d4a9be79275e8889903718d95aadc4943a0a0c2c4e6b4fa2b7f058ca6028ac5baa30641f977856854e086cc0cc8b850e78c0d3457b2c1b43a0a718c39f2878b0ca3bf82265204934773e4ead6a5245fb54ab99635cbd32910f57c3790f3fd3d34a932e0d9405dfd8a17db39f1cb559e0f3cfdd9bff7863dae8f2ca2599c64b8e6d24f050350d14c4bcef2d090a247e8fc85c06897ac35134b035e64e6585fb61da7ca37985e9bc655e7253edc4f821b1a4ee57c069c6ab40c60aaef5ff8b513b9039cbdf9ce1c0801607fc0f2b9f023e5bc94e43e7bb5dbf11688ee407d3a180b4e1eb31e16ccdcdcad14bf50c0ac2d6710d4d34bb44a6c5eb270bf3ed81313a85e19846bdd3b54039034c36c6ac38057c3f0c6cda11a1720174ed8e81c8b8b0c3f5cd49b66bd6a245101a63f378a20074eac226602fca453b61300b3715081296b3ef4a48ce4d357272cefba661542bb6ef163584dfd4a091a6bfa491c7b76b9f50e2d6e2562c59cabb7e561b5f3c04161996bc65b54d50f93b27ff0b0604721fa1cd482f80e685e9a357fe27ae8eb5419a1dded99b51423b79750d2cd97ab0595835f713b0450622521b21296e963df98841531348d592d48570a0869872ee0535956e00857b7ab71c43f9f997c78b0890cff16783fdd69b324260e49d7be8c484ca0f7ced21ce020da61150cf7e270dc0282864dd339ffc221165c9378fcdc6c21dc0c52b284a533993b22056e2229f7a472fae5fccfdb8e7d980554acfd64caa922beb70574c329bde6c32cb754122748ecb595bec0936e7a81453fb1e65fd0bdcb87aecdf55b5d9776f9405be198e050be8c7cc8919375a992b47364d8ab11bf57fcdc3bcf8a2badb82fc6cad0c4b60f0730b2f84ac53687f6124913fd5db5088e0f86134547cf372f2c17946387fd84a7a257b3d0523b5ecf1d1e8f4bd4cac17e0f089cf750d0f138aa02b3ac5ffec144fac312abf3c1dcc04519a8af1801651e751affd1876ddba8855a732d0b71ce9a3d4eedf2a23dfcbbb07aed4d792ae60825fad355063b1b0ec68db7714a801be3842330f64c4db543a0c5b1b425a94686e0729702abe92869e5d9495f497cc8b2e42e8c4207044ad00578a34f3c876651e33e53feb4ae10fcb44a9b0f52bad53bd00c4697b96e111bce70564016ecfbcce63c7ad354a24b1cdf0fc8c0e72afa1d1c685e9fb3683166c076fc3de3d4d0f9d5b50da32a9faa0a502a2b75c488287d624a8e6bf9929a322e9ee1dbf6b7344e3c496f6ed9ef4b4652843efa12195259a2d75e50e8092d9a9d088bd969c5d1598f0b145e70ed9",
+ "signature": "0x94d1daf098db8aa66fe0b8f72e989b2c6c48eed03992d994a009d5edf079859d1bc6d0f9ce184f65b7bd5a1a8ce1f9a10a4ece448f26c4c96fb60deba9b5262712d91f80377ac6e08f968db9d4a870e4da428d7044820e9099514924c41a3510",
+ "withdrawalCredentials": "0x0100000000000000000000000608e29035e1473bC06dA28657Ac84EC0c7C6Dc5"
},
{
- "depositDataRoot": "0xe4a6a66c8f632dd2e078705477ec8b0df8f0dfdf978797e8d99443e9d88329b4",
- "publicKey": "0x91781a6a132266827642ea0fce9192323acda3178d84de810300c01f6f56089a4c8dace9f5e7af05e1d711eada64378d",
+ "depositDataRoot": "0xcc79977d1ca98815d48000ef0335425bd962affe0b0f62a1e18b1b593480d1c9",
+ "publicKey": "0xa0d09f5d9d3cbd119d3de3a14bb6bb1bc9c5237d1a24ad280c962fa1f394e693dd951616aeb6fedecb716e8d2b60dab1",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0x96e2375c6a346efb3733d533bb6fb5b1783768ad00192ab4124a6423f0849de148b9729140c4d6cd5a142b4be318c3960e343a353d700fa29a548b0d2c4874fbf925d7abbc12893e1714a3af1466ab66f9b447e750aac23a56a3e3111f507e5285464070440d04f26ae76ddf131d10a31f174ed44e8b33ce6c63e89a394a82bd044f24fcb6ce209765d25b58517b3298a68735f7e9da46a2c1265e555e89d5d9f58df624667c9b1cb554d875b3eeabddea33cfa58d1009c7543ad1d1ef24325fa3cf8bc53217d43fbf9129bd55dd931fa70fe158cdb37f5110591a0ab318831930f99138b4587d5c9398a59a1c9720a0b9d1db59d6b5cd88a5a5aa91f34150caccddf515cd68d06bfb0192bc05cc609b95e4ad957f2279ecbcfa139948bbcdc75753142152bdaa2e36d81755d87ba18cc4af6bddbba6c6b14646cb0e4928708bcb31d1fc78cc3c6e8cccc929a51cee2d128537e696e482bbe2ecb565fe0bf0f8dff117be1ed0cb895ad0a62ec4c6347a6aeede6c7186c86faced81a35fad92490d210e858c88e6cba428a017075bef10e5d17f78847676cfc77123f5a5a29167c4b87179030b5e884091b1d026d10a790dd4573957707de752ff4f4374de4004395b03ce487167c68b448ea9f5b848086d065cc1f85a520b0391460291ec312efab6fb1939793e8215817f978abe99b4afd8b21cd12db58e9eca691b310109df84abcf3a23d8fec7b8b11cdd15a36ea8e14f7a24bc7d6997d8e1ccd64aa5264140cf3da6b5252fcf41255c391eeea079311b1f1fd761206ccaa14a133654221af543d34bea0ec835c1a8511d5f83a4dd87b59b3da7a45e42a30afce4f30c7af1de61bfe7c0fcd435ac4d1061fdabc2455ea2ddb97acdc3afcff42af4b424c236be6f2ee9833e88397128cb25dd935ad2089dd5727c3519b14270de2c1f460c3e9ce4f260363b14e19378403ef8d8602bf7f8b8e61a508ed872b81d6d41e1b416fd29353b4f49df50d38ef36939d2de804d7522f28aaf80b8e1bfaa86a128b35a4f7e911bfa8e4c87e9f181e3d92f9cab2d64b28a618c482d80335232c3751bfb15cfca1fe9933d4809b55faa619619d6a1b2212d7e4a8de62eb91ab33863f01f920ced2f22cfde05c3f326dd16d768e9a5d7c7901eac3fd6e86a4754741c3d019d272b0f17d45b1731f63e22f73e5f456d5b9ad181f5c8a0fa6113ab55a930203e3360fac5d990c8080de248700f1e068e7f91ac1ce315c0569c3ef7ffc91cb143ca3883b18e1accb135c310548b95a5f24534510fb96e3d750db85185aaf9121ebf7f1eeba3a48efb5cb21146d747ff0261e9edd08743fb2ca163d5a4dcdd5e8891ccb08160899af6ae586120b59f9e062f4b6dc448938ebbf675ef5469325f4a62d3141a6cf38e895bf5f2c66d22a38a41a63ec7152a5b36af5da65df13668b1eadf63c6c488683561982e46d09f81f13c3777b3628b84411c2d63945b9b7c9b4d1a31fbf31d513b736c176c32a9e5f4b8c6f9aed1fa5d6ca2637ac0f2c1f21644b21c6758f37c6d134ac5b265588b19560c57c74420f6dbbe91117a6cb7a1e00923fff4b728f6019720f3167a6dbe1269954bbca1d0c2b5049dfc2fb298b3ec9966843c0b5d028f0d322b2a7c86ce5c1b07d46d5db3c19af916f827b92d0c2278bd28901d75c4067ffcfab5e488c04c31f18abda455129c0e762be3aab30c6210156d3f8bbec163422f1b3669088f2faeb6505a257d610f0cf401790f521fa45852842f601502e7400a2704a01a9a8845b0900b800c8dc3f3f638a9df0c4293aee5065e46741c8c7dc51c18b75d3cef3ac94b41ba8eda8210175960e7213a",
- "signature": "0x84dd0c8cb2e4501d1fe9a18ca5b66982e5f2485f4bd128905f34ee0d4afb98d6ad5ef8dc4ca69c0847234814885be88f11e77caefdf7208eaac6a780ac4b7084d8ed2ee9399dd11e86e39fb3785a27d70a5a67e1abff2d4c095ecdcf3bf2051a",
- "withdrawalCredentials": "0x010000000000000000000000b388e67E3F80A4e6130F7AE8B29CF8d7AbA33Ce2"
+ "shares": "0xa280a4b20b0258efa6509ba64cb98681c4b0ed64640332463489f4da64a56d9561a07af45389d049cf600869cbfe9cf813a746ab30f8028e7a6e4b13e106a32b2e8179a2e7d12ee2dfc0e309d8737bdbe485cc6f8f9e7c0b6ac8c07313637dd49682422fa8768bc7fc5d88418cb17566f4ece4ec1c44c0daf0e9069481c53acef96942617bf55f7efde75045fa57899db21e8eb0ffabba04f558b33322a755807e827291ef5d8407b899519d8929bbb6beafe859f869941bba0b192ac48e078cab7c1946d33c50916efe290b05e582c7d3e890284471d6e36f2e967ce9896600991a99a5cecb05ffb958aabea534d0f9b8388ba9dd71290e00c37209af19823cff468f7bc84dc61e9940d6eb9cd9b0dad14381452faa15cddb368f1266d86484b70d3c5777c541afebb29bf59d0a71d7e04c7d9d9a816fb9e0b83f2d6ca98e3fcbdab10a6fcbb5f0c255df9b5683181c625f78bc9e200e3ef043fb213882564473be03daaca2078d6d1a34e491f053f56e48b1ac166c17896c544103fff4fcfb64988d0e1916f0dc77e224542e56244a37fbe7e4d09b8a30146fe083055dea3b4fe648e7157f1029aebc21544aebe7d1be1e4120a10fe6912b292f2d49a6909936aa183c7b794626f586c4cb8f1f6d11ea3b19699a8717278388880384ca7ccb8838c2e47f0e81e6096f938d0bca7db5b51b33804036f33a034ffb31b11f81919184e5f1d4998ba0da69d96a0412c6607e65217e4db8747e28f5c47ac081893a854894703dace89fb67bed28deb7c0c3cb78e0458ff99f6fa1d1efff1c4a3679076d587734436481cd5cfb480e2078cb34a116c5b0aee0feb25f07d71428b284fd7d810909704cb2eb46308251f11ae9283635b052f8620c057502d183dd6c613a9da31edb1ad37a37565c5b75035acad3b75d3c7bad9d22c9bb388d872332abd789a840969e41c664b627d1b192d4a7a304708dff4f3908615b5adfa3473393579a74bb7d1b0fa8b69d48e7026d45493bdc0e5e07620997b7f193222b1fa9938aa47643d6879591ec4f736097ffd62ee4c9fe00ff2cc40126abcd1c14bb94291da4b9439c48a0a3a95b8f575b3b173aa3a1f7d58ca5189ff3df28968702e79574fee4db7a035ce9f55c51c1d2b44d848b02aa4ae475d1d662eddbdbea25ca48d384cd0747b8c3962637e709e182f950178172f4b469bdd86f08062dc8dae1883a2bcd9bfc04d8b2f2e444db2899e17746549ff94f8887c82bb1fa639ec931d362e40567cb056dddac8ab5ac1f96136e8f4a3a71520ed4e0137179f3d3ee25d11e622f30f78cdb9acf0734395f61bf91dc9ce858f0d3ab72f19e56cae7f37cbf26cef3b6e1fd7ed031c079dc273207e01aeb59d2772465cb5f1b0ec1c21a975a20b767a977fb097cde569e8ee5b6d0298429e3467ee38610cab1efe4757af059abbf85d870c313c916c3ba60111abce27b6851b8c48f11e2de7d6cca1ffcfb0c55b4e4936ded193e363fec574950b4801e2b931c0d900acdce9451fec98b17c09bf8c56084815b3d95c45521e30877a1e80fc1bc0f725c9bcbefcc3db99b7fa0e6df82faa66672db8e80a4b91a47ef6570d975641aa9ab00c9e6c844cc5b6739cd32593f79081ec26dc74ad9ba4a49766b1b43c451c0b5a540eedbd3ceb42f3c93a17186c20a3be5b13de790c1e22f77461639c6ac19e1a2da355c40df79ddf004451199e1b1b3c18df0a1db9e352f4d2f2d6fb63bb0e6376b463796781b3d2482ffe021727b0bc87fd0060e585c1bdf28434fe15b41efe5c2fad6881291264c323add6f811b0be17439e9f1c3c157d3bb990d9fed272e2f5e80c69e16d93e96",
+ "signature": "0x8679dca34563d50bc2c5d679b7d5b216e1d4dcaab35082665a5d3b4e4ed9301e6988b4fd6ed0fada9783f42908285e8f00b8cfc0522c7c22cfc917b8beeaefb669393adbb365ce5b2864b0379acd0ab116e1b9ba9cba8771265192c3ce81d553",
+ "withdrawalCredentials": "0x01000000000000000000000020AAF956520988cD1Be05c49fdCC41FABBEDc6CE"
},
{
- "depositDataRoot": "0x2612701dec2a18eaf52b145c67ec8fa99f60aea9da6f62a18a18dd0525b69612",
- "publicKey": "0xb84f49042e4dae4ae991403f01bbbe5b0be397914305918ac7286eacd39a6fcbf47f6662ddea5a8b2fa68f2a3dbe277e",
+ "depositDataRoot": "0xc9e658b733c107ae5030044290226cf3fc71bb3995696df22eb97d82638491cb",
+ "publicKey": "0x8e849b6b245beb56ce9f89ece0d244e7d8e3c730d27cc9a4ebcedc8012d3d4fc0fc231fe4313fd7fe06e81e57f768799",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0x87f3abaa495ecadf5ab8119d8424d875efb64880b4d6dfe13ea63680bfaa471afcdf1e28ac1ba3eeefa7f4fec6d670fa05057c3ca30c0beb0279c651146c748f83439b529fa2166683d28bdf9f4c9873fae6331fc66ea50d4b4bca1f7092e73aa14b03254d5366c80008ac2ac5d87c3d6e027924a03a25282de266b0206784f8bf67d3fcba787a70ccf663b8948b562b853bc890e95691d8050271164427a49ed6ae7d15ede9ffa5cb5decf47834668730e25c2fc1768d00c552645ec817ca049998a15964b953ee19812ea88f6f2b1ee33adda19e045443de7d410921f8f9efdf58cbdebeb83203538068be0acbdb43994af1e5ad88812aa5653bf16b5dd9cf3b9002a55f355e4fa06556362e273fb81ddb0f218b937c7f35655bc592e8dbf9968a453fe37dce27c290bb52c8d26ab95cfdc760c4651dbe39645279731fed1fa4269ec40de1c6777e1412ad22e345d663128aa1975b7a16a277a5b93fcb4a3c461a2f5363536a59e9e6389378cbdfaf4b2e1f21543068afc239af5dd265717783dcc2a2705ab949db73061005c205bf60aed7095dc5b022007ef9b96aa5483893c5d60596df6cd38a1afe4593a4f50da481e29a48fece3a164aea9874fe0d613bc0f5ff74d15ac7cd1ee95f0783b624d097bbbf61922d2cfef1eddf960727fd12466be0cecbc4a3371d76f49a908f55f27976fe6b06c6377c12b78f2741813da7bb3cbd52ae3d227f28cfedbea07524bd124f3c5e9583b77617c08deb9c8f83b9e5e34dd7bae9c101de9ee63042d71fb5c450977862f8dcb73d993673c15936846e5fc4007be0c542f4762e8e48a3af5daca88e649203160636878cc09db666d6b1fdfbae47b3930b01b00e891a1276b638832d27f382d47024954c0a15133d73c97d206a746d68b7ca04b5764ac0b2b0f694d2efdc516d9b8b135eaeabfa2699fa4e19ccea48410b76408a556331fe54e87c4767456a426dda0633ba406f97693bdf9cc2bda20f78eb999d4c6c8d8ec957188955a97b6417bf1be4c1a96c96eb40c087e3af077652c8ba4767a0c470b319dcd4da3983aa90e223302f42b2f6c23a7d4231a1451c086511dea39b3be2219a76b45236563218ba67dcd570b6a54915f70cf04502e96777006f3e66cd7ec0b87cd5b21f61780461cb286d10e2539be597b0fb777c690b50e1841caa615b8df5590814fdc704b758d9de34424ec14a7b026ce4d618c9bcce6fa410bb0e0b97a7534e08d505dad0c66f7bbef49ad6a77b54a87935dc8b453dea2d0ab195738cdedf72705490b88e63ef268bb4e3bac397ce5f45787b2b6911d26cf0cd7274986afe6f7348860473b1080d4ca108cb16229078baaab73eae8033228e5a6f7d21d2a75c18d1c488e3f8eed273c594f5f2570270e9ae5a247f37604e2f99bf0def57c3dda38176cf77688a17838cbca860dc7cffec71ba7a21f1f50d3cbe75a1b61125755bcdf653485bb11a0bff78fe0fa46ab177c719604b14646e4340bbcb0402a6328d69c0c14891a57372057ac12865632e63ac3ff5af6a0ff0c555ce55b40a1472b397c2ee48433f2d8e151d9fac88df4107713aef754f5886d6fe3a8f286cda3710cbfa247f75952e41feedccf7a9cf661a3391d64f3b52c08c93ed9db10ec4f3b1f0b79963063c6460a2b2b23715839fa64695a9a03e758cfb1d79c116f6a876e5b7d185311fa0c6f64810070740a0d29cb5392ee326ab57b855f443d6c0a8dde24deb2221d85ffc7afedbeae708d75617be6ea478dff08134bccdfb5053ab8ad03942397361a653a5b883a6a654097bf08b3ed76d4bc6119489607d7ddcb34cd7fe1264846b23298a9c5bef",
- "signature": "0x96623db53eb22695b0012b3568d9d1a875118bb21988388e0837f18cfdf16ec692b0c2af4c46c02e5cbe5e39a8599ed9018bde19987bfe33a7c4a4349895f1cec9dc809af674b7ec26578b2938fe19a8363bc06450a161ed94c17e6a99de0cc8",
- "withdrawalCredentials": "0x0100000000000000000000001e8dA6b8A851f352D5a1F39dEccFdf2f6EF27ee9"
+ "shares": "0xa8df1efabb303db62b3d446077d5cc705c91caafc297aef1ea4b76d3f9694718b4772925b69167b37036cd0417966a820cf2ca386eb21a58aac45f012e616ca9da413d38d560d973e18a903a0adcb56adde4f8dbd0d81eccb1fa9cbf4bed98aa95e89552d1e0435e3404acff0ccee2a537faca1c4d391675ea57034ba4a51b7a35f1bffb92500d159c490aaf98fac921802f9d25b256c79982f35b353900619fdc40df6de6fe9f10fab909da8b8507778ff3f287fdcdcac5a6096107a4a24a0d8bb5c9a347d99b0f41b48d4ace9bc1ca482bc739feec310bd1178644d21291fb95ffc7f117fcb13ec825d54ad7e10606a578b40c88e7c66b25595b299753768cf716d2e1c8b725bec8975db7a4fb872717e50e2526b4573c826596d2f48ad4e87a5dc83706aef3e467c4bbc8c4f13b2b6067f7689e5077ad71aa72c9a5f5f38f0f37a6a1f083c5d34fbf660bfa0d9c63ad7087396e6b5806db739a7844f756c9e5801e7f05568f7ce3838cd0a84d6782066cae2e037a5d8a5d2c35bf26728eb99ec2ca4ff7464ae0b25a016f288ddc2332e8aedbe970f6ae309d493dbfae63bd707b57a718e878f8f8fdd3afa816e28cd52385b53b79d8c324e0571f5b182040e9ea419fed5bb7c0a65b013363dd4159076a0402a4e4e18732f885aa897a6ba885454bf709f554e4927013e4e6f60a9eef5cab128393d71577164ed8acdac4a63a1a3e9f9aea83f1cd0c50817111f518eaf184048cc7112273e4f5a2cd34df494b47145de63524d80328e019572a499fbf0cbcc7624764148537893fbbae5099fc4c6041eeeb2d28d97eb3e418d74d8dfd42520b1b880f8530a20c2ae1e68d37ea18974be8cd335cd7e093352b369a6ee7d38f9c3f57d2afbc01072650f9ba59a61a97d746bfda052fbb6954e0dfb875dfa114555f6cb33c58ebfd04e0068938637137b90bed5b15020b32d5422e4074c1f62c4ec95b367a2ff73302dd26e8f4f453a27c313aacad518596968e27a92fe47436b51b04b95840a8ed08d3d2f9b8330bdd2406617d84bbcf4ba653d43307728ac49110b91a97885dd5c1a6d5b49215084eba63a543b2048c70665c88f6f858032cf088375dc3f9d5f8122ec4106a480e7aad0db62b1d05470e47124e69c158e86346b219ac462ffc72f9cc77ab02a1855599f1085f3ea6e3214b8f3114199fc2bb0be645ac279f817e978e9b8746e2a3b31af12d66c5aa9fbde3d9af05418de4cea41a860a2cd5abcc64a49d0920ae1e7562433653905443215aaa2c29e9ffd21eb579fe7f3b93517bc05ce4b3f9c7b17c5bfbbd9d4b08807486384b5a7ad9cd39300905c3e270c8c254bf28e514559bf152103d7e09d5518b6392a16ac1566ef1218ef2ba650e8aa873e7c251430448ec3e2e119540ed4f724a390db8d0d5b32156d2c2588f900426e995eba4c59d8eba9ff02debb2bbcc24bd650745303c5b910be9635efe677fb120a36218043d15fe32ee0e9f3db02ddfed31e8a7e2607c6a4fe6f5e1dd87ac136c387bef4d44d431e04aeddf6a68002358257688d103432dbc71e3d90201de50a935da791b0c2794084ba890b4094a7b5c2692485c8d0228ee2569853818e8a3a326433563fa44d9074279ddc53b0eb866de3bc8663e6f129524ef0c80f4c7647b8497a929f6157092320b71b4551fa87a8abf43e2a5ff120f9e170c4320e720970a6ba86765662a143fc9de26b8de3af78af9b69aad3e49433d6aa041cd16a50dd49e987c3b07f5d74d644cbc281a5e585c3054defd9f5d6edf70b79a8acac291edb5e9a071649c514b4eea5dd2adcfacfd6925316863d49fc05271c70811ef4aa18b4ad9",
+ "signature": "0xa1d956dc10173ca6a6bd79d5410641e214855f4462e90af7bdc7842aeb9340caf6682371d967c22d40207d389b5d3c6a06a4f94b82792640bd54bca598096790b615efcd4bbf754b9ffa5843689974cb7bb1359ba452bd48517b96684a827147",
+ "withdrawalCredentials": "0x010000000000000000000000608CAf3aaf623E0dcCb1EA40Cf2d544094a9Fe61"
},
{
- "depositDataRoot": "0xbcabc7eff8c26cc9578676cd40c625d910ed48d04ad0d005fd2f887ab7bd466c",
- "publicKey": "0xa3bece6c357799b33e2f6d5e82877624afb2ece0439db51676a17ac931b9284525f2f139f21a6708c17a28a1b0ba3235",
+ "depositDataRoot": "0xa1263e2c112620a29b57997a921a53915b1fbd3fd699c7fec24bc525680d898d",
+ "publicKey": "0x95d84c705530916a6d1884edf7c7d279bff502d41ecc9dc18a4814b0e98ad5b6ba568fcd28c7a006b24065c0cf1a041e",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0xab1384dbe637ccc17ea18be577f313e97e63dd9f3085cd478b6fb4343770adb73987e56061cb93fb09bbf67263c506c210d70f687b3394377d2d894a087179079ee7b97314473f859b2a75c2c366425aa3a23e6d804709b690f4ec9785d20906823bb4fb203dbddef88abb311e44c3d14e0b22bd2fbde110e5242c6bc64ff6f08a727c6363b6f663f079ded5c260e867a42cbdb2a22a4191711a9f32d18aa2029206b23afcb5ef29c55fb95b817d62fe4dd7bb4462fbc874b7d71b3a88953d2c90b5c85bf066c5a319c03470bf24ee9e040bf22083238e88a59ccf90bdb05840d9801f59e0045d9e8fc7cbc9dc6e55a7a64c7736d98fbee6334b6d4ab11ef43ed1b01cacdd3fe97462cbc478f604d2bb618a5f13deb889fe0c800741507d1033676db3544505d5716731bda1b113025f0f114ab3c70e4dd22cc5be96bb910770ba9f4f331102fd9beb660134e02af5555582977d1eacb44a75625dd10e278b5df203a097343203c1287810e4b820845dc92601c6b1282c8a2d6b46ae993070f6c2c67a11453e8f28a3724835036689600ee25dbb738b4e84e788b01eea0eee9d54e09d594cba875464e156b8799712f7a42250eee47ea2b36961c4072aa7c74cffc587ec84a46544d29f6a69a37c991c9fe84c7e75ebd20e8fa6808ac017c146ab0deb6c1e808ba640bce7265a4e7ecf1326a666719bba9e693d3fc00d044b04856b6f38f39b7fe8bf38b3f5dd8dcd899e9d96a7f23528c2980a2733bd5933a25499d726d8213163d507410c845c6a13f2ecc9bcfb5d80fd29cb41a40e7fdd961217ba5bd7ff4b002b2cab518f293bd5a9e925ad603b97fb885cac97b3aae21ffd12eff07cd1fbd993364e6cf3821707cb94a7a7f004272a98b3c77ac792a8d9c8b95bf65a131fb96d0ce381eaf6e82fd2de31ff8e37cd77a87dab6b671053eaf5d245effab1563d77af07929d081b81184c79ebb9d886ed33e151cf3bcb8a7d4698aaca4b6aae7652dfdf4c22ff24a13f499915dea98f5fa5bb762df170c1eda1065440daba6a88a007f1bea0a7e8e8ae77b00cc2b710e2f59d1a2faf2acca94ebd3379d65d51e742abfb532cef3b2c0bd5f05dfdddec617926709fa567eb1dad244992d82d372e2f3b7314c87c0947d6f8970af0dc8ca33afbe03f6ac7916d3d5c5ce53ffb12062754756e551620a8b19dfc71917fcaf067a098c032af97c2a03a01c85fa5cb1f0ee61d4bc85ccc24d2eeda83924daba97f6f487d5d030878ab7e9c122cfc1725f2ddd234184af86697620df8b3927a333a5f8672be99902650edb77c26651871d2daa1df90ecd83ff99e014bd95561f3abaf32d08e8012ef3927f600b60e131223cd8449e340db0a0c6f7337b32e425db235281b5615a1f49402004b3638ebd01d64c3bd0e47f73362b9771b6667d1ebab803e1701fa2afcee1f765733f601b3cb3a9ce151aa4ef075c347239a001b394a00702f5bf7bf2367a51d2decba43d057fa73ba921beff8dbe7cfa97290ae2d4223811328cf85cc3ce55380f0512b34f462f3bffd06645e3f1275c8cca42ca582f0e42c102a6c6e7196b70c11e862aa99b024ce8f8b13a9e453595920d488dd912b12f75b191fb1421f0455ab0d9703efafc8168df0280c7502d1e7fb472b0f5197e84290db70ce4891e8f21e510e82d822847cba7fcd343a72679cc5c7bc8803ec86e729a988d9122eb0f1ed011a6e0272d58fead3aebdb4948550a996789c6163bf026ca642e81cefca1c40984ee8d23d8fb0bbbfdec9b1f03cf06e2ddb3099b763073ec2bf4a640293a436b025037adbdef6aed68c0af223d52862b8e8773ebb5a3f9f24a934",
- "signature": "0x8f00e26fd17ce8dd92eebe23d0d4bfb7eff7561fbb643349de1731049da5433c812c9f8add1df70dd10ec061499cb22705e4a74cab68a067462f46aa599e4e161d4025d1de79eec87b05f519c8b7679857be50cf0a7bd94cd13454d531cae6eb",
- "withdrawalCredentials": "0x0100000000000000000000000961cAf05cc7FCdA0D024FC66f7D6DA2FF6E45ee"
+ "shares": "0x8d0fcb92dc352ad75955a16f8c2762145b4f3a997d97bee8ea877bc304d16b2f2ce6d691f25d5f6ebb812e8bbd8ad1c90bd8e79747f7a97527bf2cb09bbef41b6465abe12df743b50717a292ec7919199016bf77198c7f87424584962419a248b327e81cce7804ea91f9cf98faaa68eeb9ac0103e137b2aad159c8cde557402d017ea914435c84b26487a6a3ea7ff3318463c7dd36f59da0a8f69c4517b7bcf605214097d03472379e8d4f120bc3e6682aafd4481c7a5980cf1b75f2199b0e0099b5fe9e9dcfa85e4fd2eb56e6837e4e6b772dc83c290aa7030b4528d1b78d021689721ed2f0f7371fe32d5fb856a1e8a58a9d4fb86db0928bcf5b67729c144e953f576788b37c66a1522e6dfbc898d333c0ff636662f2db6e4521f2dacb4cfd1a68ed080a80aa4302c1b75af441020339e9f9f5ee0deb50739768d064517eb8945915c0fa7f5bdc803d1934550415aeb445cbb4c30ee84b2dab1cf5457448513d979157758ed63d7dd1e0c59b0fc15b2e85137637c256fd64cab6ca41c607bc20cb202239c811910f2859c0ceae43233207c2db95845558d710a45288d74a1bc590aa3d7369b90a004310bd231d94a31d5e7292d2c4b16a0200c45e74ac2360815f53bdd34a21f9597ab374ff23959aca6a4b73e22f59affa5ff4fb3d7c946c9d6e9f20506b257432f34e65e53189693d71ac9a3f80e832f6f12e330357fc8efa746ddf6d8405dfcf1d67ece6d6fc16a694b84ea3029aff059b6386e32acd5731beced9a445220172f0a66d8b4950924a3d2343d7adfbc9063b05bb0112534fc570ac7e78987fdcbbad27e015dd9d13bd820283e8dfdb2c266b55a7761aba9383dad1a81f8f525ee36067629d9923713289b11341f48a2ff22ea76747a7cef7c56b51fe1a540efada538488f360d7ad90342499c62e33e62670098a24cf473275597a4016ec56add75d93a942c8866ecb4b85e382c561ae1ccf226fae2e8f098b6d57439d64119d4674876eb28d91caac47965e28605492648605e7a3bfce9e7e0ff53e8273bb00b0b74555f55c17e37f85368323ec604e00cbdf186d07a3a0d8d51d6ed2a622c7fa26b889187d1b21318e5bb345c03e006b468f1781e3cfdba397774957f76603311f57548331a0ad13ed5a133b6a0182c34007de4697ec2bec01e1d9fe64128383c763190f9771e63de0e6acec0ab641d589ccfb7e4138362ca4723425528cfd0b579c7f00a5825df98a6fbac1f78c2ff451c8905f136b9f92ec5f9f3982faf3dcbb3b794d6f1e9df0100e851da61aa7769b38df4216083797c0dde24ba9dfc5522de1e9562cf3ddbc6d447611a9e113dcbcb1a64745db285dfa400767e16ff1d07a749d7f22e0d7b79af241359ce99e39c00dcfc9b1aa99171b24651f0cc08f0eb056e61270727bf594041d1423326b49710cebdb9b51731b9cdd21c5acf660d23c138f2adf8528ce3dfdf0a38819c2b3879412a6d423b00c96c6dd88b41e30743b6cf357a7e6c47046c4c05d0bb7cda7256a83c4daa7588589a7380ea989fe99586a4928b7ce26e9bd1686aac6cfd84097a763cad1222077a4d57822a039ea219dc7c78ddfe3f34991008d25348a42fd24418db7e9546b0544fd580242c837a1b9355bf4ee86d4234f7371f34c552ef105e0ddacfdfeda9d91caf38dba942738c98b54782a6733794ab6bc65da9c20924aa4f508b8e5983f3dfeacc2e96cdb4140f75f67a188ecbb57ae229187de4d110f5a5b5046205d5c756c8ad8ec6edef1620e49a03e7c92f53dc25c2ec0f294cc8e50f4dcbcb18066e991b727a0d80c98b0e93f62e18153bc025dfbcf322e938ab4205abadd629b",
+ "signature": "0xab15809a50d862519d8bdc2d2d936d2579c55e2cc88fd19c73796bedaeae42feb4a9e15ec7bd5d087f6502d7fce003d409054eb32590cd11c8a25fb28fa83b7088a14208cabe3104a4bd1171bfd3f1c94036d32ec92036f09f2094b7bdb52bf8",
+ "withdrawalCredentials": "0x01000000000000000000000014B15017a2Cbb28EF5Be787ae8Fd32c5abCB8dd2"
}
],
- "0x7F3ab92B170aD525C5B1Cc63928d159F59A0eC80": [
+ "0x0086C88CA523F27e4bD7f233bF7C722154757044": [
{
- "depositDataRoot": "0xc7768eec2e10b1f62c35079875533f6af3d25228607259620956c1d9776f64f0",
- "publicKey": "0xb394748e1e378c03dabe0eacffbf72e3421682892dbcdb5842c4cb9e8c63a22b3f97d459a6244f35ad59cb5c088a4d31",
+ "depositDataRoot": "0xf8f610feb4b0f8cd0a26ac350e002d0464e54d70249d517ac66317b29fc9b1a6",
+ "publicKey": "0xb5c4df5bb5de73c4b9f8ec701095e4993e86670c861a7ad11a1365175676539f73ff2e7ea017c88be05d420f8dad667e",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0xb81b71ed285cb36b263a914682cc10b1f0a51d5f82dfd0ecae2d6d4445abfbded7aec90bd3504d6ef280b97274c0034a141c267b30ed907bc653640e093b653cb1e224b1a868fb270387bdfe9f0d47e9dffa3b5f029cb089f4af240a02083e82b04e210b3228800b7b1ecf6b000d12c63f653b4ebcf971ae2c3c62947a62f7131aef1bec750c541eaeeecc87b8fd252693ce2025fecd86a66f4152d830d5e340f4088cf4c648c110cb97a2b7d5b06aabcb37f3e55f47f34d7698db7fa6e1c79e931b616690fdeccfda745a85fd430c30290198605b28e6240dfad87b971502ebc032e9b8f1508b7c058e1124ebca4d3a801c6ae15c6d7b73fe001a25497e006a669d6d42ba44a7385052e782d2ccd71fad87804b01fcce2e0e93597b7a372c873791ad785174e44f005040c4eef6d1fd7d591f9499456cf03113ae8bb625fd758a25d7d6a0ee9d299e0cc6b710720e3f49d6f132b0e2bee63339922588f43ab0c4269bf7bc719194f7ef826c33ed8ad0fca9e9fafb3984ed2b50fa65ad377f07653dd3cca3c11e5b9375158c73e8f68b3120fe065c94bbb400a740ebf01c92c93e94ed17e2aafd13808a58b193d0aa77d50ca1b8eaf172f29cb9ef00fefac73a8ab6bbfbe4a9db216d23d6fb73fdcf765cd457bb2ac7698a490a2a64f05ea07466cdc5ff6d0145365a12f2d338b33619ad943833ba385461e1f9cd5bef912778bc09561d0f98cb810d3ac0f52054d410ff4cf073e899813189ae077554f4e8f25a5fbfb01dd8accf531b0f2043495532883c7c9b56d82736c03ea8bcdd66687488f3f1db3e537935e80a13ba8614f623a20cc20cf7d8e1369e28860223a0cbf6e874f032fbc995ae38542a5b146de40a232cfe30f712103c6c29dda17c2ac0fe533d39a2f5dc5a2c1b89cf0ad1983facc4602519d25d05ad9bcc8c799b80b254ed90a6125eafa9d57cd8b3e39664553f38d3808153ee3c70bfefed0c44e6a7b0366bfc5de8d3f9292a595cb4fc1e0c3c0fafe4d484fefbff3d4762763bb325eb2749bffd9510a81120cf4987622f4d4916a348d51da9f0cd2f6ff563a550c2e28738b54e8743583424e71a0450f5465122adb6ccfa9e24b77635d3e5b66f2ac420539fcc11697693ccc3158e4cf8842576f3f90144bce174c09f21de3380417854e61c77126297d2b1403135c6c6af8bf8ec7098cb160a0cfae0e73c8ac7f27548c315acc66bdfb2a7a7a87c129c4dfbc8702489b32427d3d82f73b9ddf082e16ea33db4e1a43bcc4ddd8bb6d11a22809bc2232fbddb4b4d4973d405ada6b1deac9201213725cf0e15444e371280c7d00b9dfe6d1d876786fa3a3f371ed1315645cc6271ae674e3c8c47f9de7eee33ce0d8aa5709ad7d73c3274373ce36df30c01d095323c9472d11df5d5822102e624f918fafd8603fb4572fe979e7ab3cf80f1b8002b7db9d0a55d99a154f9ad35a232fdc5b9409f70b16ff81822e9537f889440282b767026c7c9528de1f5faad18641e24d2e8fe7d843d6cdb4be4bb910fc5b1dc1eb189a21f51d7e6d36ccfc6df2f9912b038878c6b85fc670af78a7bdf1e2e494c416bbf765a18a362b02b05e63c4bbafd9781c581eb25d9db3de6f47e0c22b5af6f5d38643b1ad3b3f37b6338a6f5cf0762927e57748d32ac3d04e4bc88a06c824b7dc8026aaa5a5f41b51af34e527cdf8e0b5e533ffbcfe8e1437b7baacd6c479759d8ed37b34e2203fe0e24441d5a6eaa561f7dfb7b5c10e7d17c19c7cc0814e1588a5c7fe0bc4255b688b1724b5fadbeb91ed7e07732682b33cb8c19a9da19374c4d3947a611601b0b4a442f31ad8254ecfd9451439e995ea6add7",
- "signature": "0x82e35386c263772f7083f8c49a3b3ca7c361d96f487d690c038b7192dc0bebe241c4578ba24b7b7ced55c06e46df88630085f27bb5bc38652e7dd916c3938e2427d1aaea8869b6338728ea36e45b7dc4b99f8d9e9b42906428c0753532111de9",
- "withdrawalCredentials": "0x0100000000000000000000007B6845218526444db5e4c80DEb3E317DCb229c0C"
+ "shares": "0xa9cd17d4968ae5be8e316d7d09c3c22b06f1d3728d65f1740e2ac786b64675501dccafc7963aedd45372910506ee3b66002b41128fe117c8d1053c4d871ef945a7883934e51a21aa12a8178f528733dea9b1266f0628b05368ec95694dd2a1b2aba631a81fac70f87cfbbbe14f0dad57847b1693edf2b7976084727d51f3ffa1d4aa52687689d5508fc31bef978622b290cfa4f3194e9d3b3d40248aa83459d4d97ba43cf1b2bfff1e2d40e9702bcb91f4f1281da851e7a644f8a38f89e4bdbe8e89c843025781dfa1a30ce22faa5db0d116604d8780059f6f91b06e9f9588c0ba2e84dfee2ca885a0e228e02066a9488bfc3e28efb601481407a84cdd23d6b4f797c02781cf0f0e2c9dd233d8a9697fe71df76b46a5c004da54b1627976a29429c55e014f733abdade651fb32815d5ae2bc18fa2e7c7c79887c3563f7164616a23b22e6b4ce2acd3cd1ab46c5e41783eb36e230c9ef7af02bdddd11b56518357274b6da59d83c03c5f5b83ee40020eb9625fcfdeb5423e934a7936e3567c5babe59f681a0758f1b7ae5704f5143c11a4da1cc0914042490d70571e0efbcceb9ddc86addbbb49266059555d220277ce37e6389b6ef32101988aa22b384c2e69d1a002f80703b1729605543d1bc6075143a012c1c93d761bdbef7731cf46254117b9eda352c06531d555c85f56e0a20b3136ce2067ea79a525e0bb19700c3e7dfa2a8a7c2adf9a8e678bb2f41c70fd01e61ab4bb523d0b18247095b5e4fb8db6d7c164d2bcd0f55473ba09eaf4ba38eb4b4374de2bc15ebdb8ab91b8533a76ba2432f934846205403658a69cf70f3f2fef497d6727459ccb41f0fda967e319b3fb842953a42567f5ec437a5015d7110d9cc6230b96a45386805ff33b3577041d2ee924c63f2662a1c3f64b775327bbeb1a63d29d5184315816053b7dd91ce18e5399b831a27eb3e2b720e907b97b0441e6154d4c214d7d2e4269484663be11148696e7629ee0984c08ed9ed3c098f6c80308b72f12d4a25824ac9c74f553d7c63875328543e31d83dbc97b9d35c4d7736757a3998ac19023ffc3ecca3481e2778fbf8a8c2ce4c235456b1c28db20e06f042821478cf26d90d7a33f02903914f42326c97e6b008799a02a0bea1cda368fe03c536a73d7303b8cb9b87716176ffaf71772336336023b7081340d38d23655ac7cf2dcd81f205f196f9fda8b0446c36644cf0e5c9a31ae62ae591597e79e66b977dd68abb8411a2b509862b3bbbf56e29d10a39509d246dbe6edcc1212dc71f73da67aba28a0395957df36ad1b65572695ffca505537d72689fa8464a6ef42a412fea004c6f63e60f29e0519593ac11bd8803bbb163f0d242b46794a4646d42fc9723e5fb8269380bff02a3b89f52b6c80717b341738fb3598748cc2db2c2ac4f89ac4fc4ea2bebd6cb009324028d92f21cf8883c785a6c1a0b2250452b3c46dc86116292e90a1ed24a12f547f399b497db12c0d3aa3a9c028f32c023c8cda8b22f8936872db94722a456fdfcd49e0bbeb5b56cadb1a7e549725799a4da895afe1ad71ca0c896e4c50cd1f6c599fc6de30ee7d28f2d48e6b069d8bdb8e5abc55e59dfd21a9bdbe9399aa79dc63ca6b3af885fbe289a76ddfeba7da2b30fa26ef522ac583de68f0855fd8a3d8e969478d9bd1469d83629ff9e2c6ed78939545050369feff516385c9eb3fac7ded8f9ef918517938c2b20d6f30c19c82f142cba48d13df25b7f916aa884d30b51ad24ec6ae2eb95378bf43244659b9df1eec3395522a948494756ddfe6e471a70b730605a22efb13690d37341e86d1411d586599b5fbaa4de55b7138ac098fa948e304f",
+ "signature": "0x91293b3b7ae03d02216bf6d165a54d43c03da5cb7fccfe36d699372c2780be0096e415d639cf8c1e6fea1ae60302f464154e1c35690504c365e80c08faa0216534832977d31a97e2fbea2a57f53d7524063a670857a504721a2e2cb80979d4bb",
+ "withdrawalCredentials": "0x0100000000000000000000008e21130B26d72298600378b359F24EF22415c528"
},
{
- "depositDataRoot": "0xd45d86ca8081a7d3a7d0d1c176396fbb8385f1a3059403bdf18c79ea4ec3b2dd",
- "publicKey": "0xb25f6e353e52d61319dad1f0bb03a5e337226e0788c99108eec8cd820a3c886c8b04fc5e606fe91394cf5c36491cc96e",
+ "depositDataRoot": "0x801155eb7f02f901d8a6b492835c49bed67d61eee7a5e5a9747e6ca11da9bfcb",
+ "publicKey": "0x877df8ed78b0be6fba09e8be7845978cc7aff8c67e72d5369402b555adc4d935403a4e74ca2faef06499a1057a9bfa45",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0xacd62ced2b6d4f605ebfe62132fe56578217bd753777ab1bedef7e97f677a86eee0925cfed2dee62ffdc476ce89bec5d0c68d29d9199c273a84b1030c968c3465caf06605570b660b45304d573534986b8426fbf6773c01976e0a449dcb679008c4f23892a9ad92520fe595428a63b6c087023186cd7e3d5f5899f036a896b82c5e7eb5df0db4669f461ec4f173766f8b73e4148422fc01376e60507d3e3b2fa299ec9d150c9c286ddea4c49a6355f540693a278f8053ef7ca834b43612f95f7b4af1b097c86cb3576343c059a639d2cd1f9e0a5b58890ad378b2cbf6b43f35d23ab1a13576558f9c0d70aac2e4b1d7399f7b410422713360f1e9d6ec8ed45296f4259eb8e3b5a1a7c2ffd0a78615fd6247020f8befccf35972862691499def081fb5fb67d39cd83129f53e0009f07352428c15be34d675d097e7e2c1ea8946e2db189040c2d088bde1d30f98cdb1392d29eec467aecce519d11f2f022c0e4303d299200fc4d448ee798f17faa77d116e098b00b9f2e19c3c9477e20db5dbe88c2fea072ede7b09ac9e2343929bd9c9a2c550d1373c4145eca61311ee59471022c5bf5e6c79be1fcbc6d4392928573867a06cdb141ff0f6c36e8e1ff0501c207ae6e219c8714cbb30bad318f20dab5ed3fd23850f7d7dc8183f29c85a480638bddda397a36d4b4c699d9620cb535c58f83a9fbfd81ff39a38a48a3d67f7dd2fc71a558f62bccf9045db9f5dd9dbec841760fb08986ed36a82342f2756d8b314c238438c11466133b7265114d0862394a85647dc74833ec65125ff7607cb5ba1939ebde1c65da55a3d63b0a66466b7062545647d92ada7c4ee9fc67fb43db1a76935deaa471ad0f838319b52b0f1a97fa3e3e5a56fa8b6522d87d0117d16e0e2d692bfa37cd612700492d526908b2a02fb910703003d0af1db78b29edf5ba5f77abbfb7c2315944fb54a942c0e077facf0e91893e510542267ecd279b243a1f4beed943d7773e21948bab9002012a61fb188300b05bc35334b10de1451dca6dbb2370549300944cafd2ca2db537e0a55293027f7ef79c5b23545e119b66548fdf8cbc2a18feb8435313c510b92b6fbf6e0507283077daa6ab5aefa1df65c71019959c710b34a272346be2ae4ffa9b03968c12cdaecc0188adc0ec9faeff7cb4222a5e406f060d3d369d869449ba72efddc649da0743c3a1d80328a49a492381c7ae01c72a5cfb6f4f0a08d5782e1cd04e4ff6c2239daa26a4ce2ff1458870890cd7078f26e936207f7d828171108fc40071a470b88d6036ac43f98971a0aae0a53d5b377ddb82a3fb1b56d3699765fd3bc89e55e9ce0df6adbcd0fcc0b26a00a26e261c7d13a59d33aaa72bb3ba754e017dc0deb68b51171459ec8a0cb4f5cad36f68d9b23e044086ed923a58b218f74ad29c1bb9c7ef7a8824a175b5ec7242c59219b7b499b2d5c1ca76c1d9dddd374f3642eb4ca55b1f2d956710e669d4ac6007528f27fe1ad718624e47e9d033ebc060fdb95a5533e8374a0abad86c03cb1e59de0e7a4b5a7b24eaba21eb1334222a3739bc2fd56cde3c67a1d8b20d00a65c64157b60180704f439dd6758d43290ef0793e5576ee9f7c683c40c4bf656f12010557ecef721f454c9e77d8490a5742e639389bc41a188c82b26c8ea6a4ec2b394682138f583d0d2fe1a6808b822968fa81cc5b905fecf95a9dd2fea23679aab7cb635322ce7bd5d568f6a123a555d9d64c4aabcb5792d290aeddf67b1cf947b2ee8207c6ba197c1af188fece0329eebb428a66d3868740e3ab9fcf58e6d2f179c2541ace19a38e20dd5883875f56759dcb4819eca9165a4abb19bd01715ed8e",
- "signature": "0x883e170141612bcc4bb22d965665ec1c7c3e1dc68aa052096ca516bb9fa4b9ba8031feae99a333eecd350670559b656c11d37c74ca4cb00056d95f8170e99403821485c82ce0655e3103287d45a27349eccd645561e4fe349ca4bcc73b716c07",
- "withdrawalCredentials": "0x010000000000000000000000d5AC20047F149cF623AF245dC9bB9dDb5e071134"
+ "shares": "0x962a489b4805d8af73b8bd1036c09317f74c08ab118efc73553f3e0ce8ec64e98539eef14f2cd47d5b66167e99d2a67b13787207d4a3cc65d4562019a1dc8a193bad0fa46dcde860f65bc71081d56bd0933bd773ee00253c4101012e9aeed6e39004ebaeb504f0d1fa43a05df0cec9d23385b86062a83945ff7f8dabf2682099b3ee9b63e0ce1c494bc058530dbc4a73a91cc23af051f5d3795cdaa169e882c233b7e24f361e6d595779fffe947ad65469c74eb8b90f26d3761d39e7e9ba66e5a6ffe9c475e21e3140661d06210508ad12e50e08efb3aacea9fb0810ec5fac7a071976245e077a939c6080cc08f016c4aea375753ddd195b8bb8801df9cc1e0322f4d6dcd1f8f5fa11d72274915d3be3a9f8aedf3137a082e3684ee210a3ea1514091b47c290d2a3743e1226574cd9f59b951cfe2f5a68206ec4441e608e9df343e0f08c8917fc23a53e5c790f72b4fc7579943a0f47aa8cd4f1bdcefe4d254e5c11017dbbfc17b563ef49ba56c68fc82f5edef77c67b84f16f3681daea7980a6249db0ce8ca84d76cec4bb9e9dc361d9a14c7178612277af25887c41de41f97e544c660a6405e72fb6d3beefa8fd05027da27304d420680160d8b9e3c9e185cacf954c236c6fe74e927d2e5b2378228a88c7443de1610cad03979f9259beb2dee0b43045b558ba776bd8747ac91bb2eea6642742e69056e1981cbb2bbd1e6c09408724254aff901c9e5ddbac101f46ddddb1283c4576ec974f49dda0542e2a186aa97ddb9ce23c6b0aff760944cb504f9f8d714fa61dc5fc62025782dfb1616cac3f146af0231f1cb892420b24f36a536ed9d3d06af9eb778657107001c9c1224feb9c866d333d28ed84243592bf1f601df9d00e6d2e2d55028ec64f85a0922c6a21f004d8394799b8d824380aeaf9c16a1a48e2510e63b1d80c305c3afe032702ef03e29781df5f6e97fa2a95e99eadf3187a59bcdd7cd2bade5f85de5daddcba84c028e4a043bd2fcbf1e9a3d8664ef864363f5ccf52280b511114ba3525bd1314dd9a124c865bdea69f25bd4937cb00b65f52ad87aa8a8613cc820668fdd6ec0c363bc91cc77eb01646926ab0fcb1391e12c4ded77b33769934fe9dfd4538a247fdf424f34274f6dac0b60e9f6d5bba4e0eee55c7f70d60afaeff0caa99aeedd37de604badd605581093794e25900d21005577134030e60c98d696665ba3c10da413eaf94e1cc959b9de73854e879bd94abaa8d30e5cb2104b4781497559055c2e872c1a3a7d6d9849e28acc6f5d1edf6dc8774bd53abdd59a799fab0bc7ddd5e994a1fe12d038540b42a0c801931f1c4e1006d10a77989aef34196469c2cbdd7c9b401a01ddcdea20ca600e646cc9fd30b7a88acb6fe632029bcb63f04adc5cffd8c3186ab8c54fdd170d0f4121202e02f9cc72eee47949447b81ca78d65cd19b9c3497099e2899e92266ff0a35d37f1a308e09b880e9cf543efc6c2eba01ca60ba7e50564753aa4232b16f6a43b00c933536b2f2294618d76d4f2906a1bb113c254522ee49069477e56de40d75cd1065ec913d277a586bbab4e48e5a8552a8a3de9e8583759625e98a973137ba38fd4fb2e5f4fa93122f235dd800c555e9ce54beb3e66cd3791c0d9056d1f10a5c9ba809eae78a21ff8910bb53bdc936e8f85903eaf1f71f674676937394afc6b63662121b1de894d48fd7441d313df8d8bbce256daa70906906dbc0e21818cb970c8cbb253b2fc4739b2172b4566007f0e1cbd0e5a9602ae589d443ae57fbcb8b45e1e2814f12d7910872008fc8cc93b36730f0e58200bfe64b75b79c48b5c8d8e57691cbf98fcf1f50bd9752a88129",
+ "signature": "0xa53db315cc4c79d5d3664af7869e854148440c735825f1441f0180f69869eb104d40f5f03477035117992e0bea0a0f7f166bb9b2e00152095e42e59b2634d281d0b3e1bf8b116a35bd2d971e63e380219d2f96c522734e3d5cbc9f5a3dac4c8b",
+ "withdrawalCredentials": "0x010000000000000000000000eF059dF731137261f72D65e2E00e8272dEE83648"
},
{
- "depositDataRoot": "0xe2745a092093d6e56b15708ca39e4e3bc8e1da05451ec883396fc8a92799dc9c",
- "publicKey": "0x9910f965b388d947c99430a66d34050da4148a1264b768a021d87ca8b4e8dcab9e5e62f84b83f61717c031a8be6703ec",
+ "depositDataRoot": "0xc3493c9e1efae58c14333ce7e6191e1aa3104d9fd2a4beb8ce2356217d07c8f8",
+ "publicKey": "0xa1ea2ed6dd60f507272e9330e96fe6b104e7c998527108c98b6ea7a4ade911812fc97f3ca8abdc5bb382bf711324941b",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0xadc64fdc78def1cbf74b465587f142b18eba38471aaa27f69a32f26c21eb81c4399e5db833c08f062862ac491d246e88006a9aab26e25eed6e5c3b21d079b9f7cd1201789e7bdc3b74d878762c65e9ec51308f4414ea58b10dc5aeb15410638eb11de2159ae441a83b2ed33ca5c719421d8c03203191364057f5a0245956489aa75acf6a38271d2c38e8482821cefe36adb58d53d785e0ced33dd5373ebf4ecba20f7dd496174b7ea3052289625c3e6ffd921334153e1a0dced30f3b0535d774afbf8915d9870d6f705a04be3f4af5d55e6aac9182e5a7f309f693e7be3a15dd61e71ba61d44b0797acc538afe254dfbac7481977d2c9229ba9f7830acd2e43bd3e9892a96a3cdb64c0cbf1fa0c79ed7df5b2c71c2aac5c21dd7ba4065898d1c8e226b3e8442c1b9c99e64c84140614f89ef94e6e46b481155e5d0ca03288a40b0c9eca13de457f55139ea0c30bb7aa189c06e39635bf312676fbd63a8b18209e3523d6009b2c38119d36aff14350a3b74e8eb4fb070520f75e5ea6ccf752de2caabd292d8c38cc51c34707ec3a318b1a06c2c6a0b040b7b198f21884a9f53c235a677f615c4f3a79c9fe5bb35ff11590ab78223fbfd493473d7872fdef481ea6f8ae51c1a30a6f8eab27e13ab6885968ba823cc21eb143b07e607f12662a5a47c704465e007774fee3b00f8070aa628dc52dbc87d6433fdcc6e99bfdef6e89518ee28f44a26b4318f88698d89ac6fadc5a715d12dee02101a359a2b50360d5f74e138221b24c89048d8936e787c873044e815ffb957d550335c8099d808cb1bad6c3ffb5de9c05e5a46863bb13252ac7bdb4b6245c9c3ab45a4b402237bf00d1f1df374be60b871186c99b0b290c83c835cb1bc028a3cc17e8cb9189b25590d5b90a8c5de51626f9dd3af86239efa1ea4beb1ebcadde1bcfc583d4c9ac7dd7cc0147e80913172a97c0951c614e4a8fd924b0de481b68f156f4bbd687cd0d64c2875ccb644d371a5ff4e3e867e35ac666d2b18439fc159646a36d1e6231b8dfd1fbfbcd0eeb9acd1787aa12e0482f1071c6ed92ef48253b3b514dcfe4df4cba632219e735f1e8bdc8c736073aed6158f720bee145d9bd7a804e7a31e2159cbf182393c617431567fc78c269d511a8fa9ad87bdbef3a33d59a22667b195b8b3c52ff914063f759c19d4c41f9176e14c5554a8971946c186a38a42932551502169265dd74e5e7c094a9cc0d9d28765b6111413d2fbe06e6ecc6aaec601d56a377ecdaed3348818a2e68fe3312c1ca35050d10a42dce1274c345a1bb110f738b839ee327a2d2ed519c44d74ced8029731a3e03373c12e1b989e08a123da0b8287fed43d04cb608e3baeb31f77ceb48ec6c93f7d1a74e1021eb38a64aa52e97668684103b23b8d9baaf52805def72aaa1863658ac1563dec4fb8e7477febbcdda1af13f06054c98fdb0127d86294cf8df72e4d798a1ff1a873e5ab6548472dd02d9a50d365b435bbe16ae6a67a5b5c4f76ea7b7408c6e8101c170c37657fe11d3b7c29aec4748167bfa8bc445228c982aad54d6cd8aef9aa0a98b8f9685966e5c7e1fb3e7710b0edbec84789baaad534230d6390059b842721e082a671d0421e810b9e2d3cb69ae54b5d461261059ad205c4a150e9d8aa6fe085c688db8dc77a4f7ed62375dc0f88548e407530057386985bc8e936bbb18cf0cd348c20436daa172a1e56ea4c739ffdda85d87dd12e500803aa3a67408af86c28fb313bb02bcc75c48a2cc9e0c14b12c448ccee44d39160e3a19963988c670ce0baf3aff28e00d37e49c773394cf0c278a76bd4a1c6c3637d3eb4eb10d09007402593de8d0a5115ec",
- "signature": "0x9825180f12712966eadb54b859240167b1688e1309f525db49b640d22b8a4991ed0a988ce7da671aeb1e8ac9d6ea7627146e09d2e7af53a63b8ca9d6e4047c1fd31359a6b3859cbd11482808d69f144f0ecb0b13088fadc1af03489cd1eb85f2",
- "withdrawalCredentials": "0x0100000000000000000000002CF895da650069d7b995B2A91450935E9E7cfE5f"
+ "shares": "0x94615bf5b1d171e25bd432c3ff4421228acd93bd8eea4e4c051c7f6bb6a3f304c2e7b0562421987dfa68129bebbd16d908ed04e58a50503be51c985efb324f0da426f68553b1dee17aa26f2c6fccc887b41b6b2fb7ed5f17d6e7600f7d1a26f9a95606a417d7168ac63c787d0cb7e8352334f61e7b9156a3365434a1d7afb0b820fe8b376ffa1f2264dcd073351185daac727ff2f9607333be5bdcdd659b74c86cc99a82140414cdc1549671ecccabe56a8666cf2e1de8a53f9d1d435dd036e7812110f94df5edfa8b827e80c1606a40df90327c60e38a92369e8790307ff8f8a3d64af2cad86790f20f6c0312ad360f940532ee2a5965c0181890b6846452f7404345a60ad3b037a11a62f7f703d5b4296be515a8829458e667a8335c1d36128b6efcee9d0642ce737277729c2e1494df5ba558e0ea681ed84443034f252d886a9ee30a730eb8eee7c62e02caefb9215909f152fff9d6f282c4afc80f2e7baac8432213c428eb963e1ec19c3c28ec0d2bde4e83353a96c73af8fd1cf45eba5ce37b2d85fab5326f4b54b1bd7fa85592110f80e329e2a7dc0b810e7cf43fcf7bec62ec1a23e04e1bbb0531ca2385435e94a09848973684661c108ca995422651b2ee05de38f737d301899e62d780259aa42f31cc51b950c5bf15e5e0cc9140eb72b0fcd5543ef0414323afd67d0a3ac9a395c159a3f6c362a923f00fe2c51069e227413e1d290ff0fe671450e1083048e3b8e660460fe264a3794737f7629baa27e3b92c21dc19c5d1ebf1ca5576ad5b358e071e6e680ec6f3b1dd16a33d1cec5e5bc482adcce1caf88f98702a9ff74314b4165e75c0ce7a062deb062879e3e1ed14d9cbe4cf4a86aa7f30193422592c0a8b026baf31ddeea6d13897e4b858c5f484e993357c557b5c2abfef258ee44fdb33412fd71c4e09886da879d68fd75a84fb9defbe68b96c3284a8568cede2efb4ce4fc4b6d896b0c68f50c61836ba43571af6067a47e8cc961978ab1281062bfd8d09bd4c5e24dbcdcd8627c2955c80fb5a9402338bcda6bcf1ebe2a232b33d357d510623a3c9b6fb5050bf9886db20cc8e8aeaffeac5a3b8e080cfd0aeb88842173664993a3250c2d77e63d995c3d3b06d20d266e73bffdad80ef8e9acda54f27380e3a704fc04c324130a8e4c6a6e066725d5ec32dfab4597e2199157a7726d403abdda16f18cde7c70a3268b681f45954ce6b889f363a05c1b5216603b8819d211f54793cabb60ed6b1cd55af543d458e3d5c28ed5a4fa429fd403c4630d56f8a91b78899f52b48d4397dba8f3de99ee61b02866015804805e9e66285f349d5bcc7e8354c543c7ea4295bbe91b69c497fe8f4417c4ec661a6492b88efc698dc595ee5020e4eb9ef9ccb9d9da04f89f0fde913d22a95ecf691bd234afef95da369982f4926238ce6343b0a311c6ccee1026fe8b14c8b79beaf2c99189aa9506fbc6421146a7b9edc485cf2d53fd5f404363044d882f458cec60c4b1a44e81b6f7a957061c669f4e509d0c7009a1c622fc0dfe2ebd3d2be2f50605dd9ed75c739ccfaea1bb4dfc9a098dd7a6681ad1143bd6c8dba0846f16718f97a08df7dc68da8145caf1217f8225fbc4708a9c0bb5327b300bbe97780b846af9449513d3d20e1b4101a7bf96a060e23cd73798ca9aa35604812a155390a7848eb110e03179a22960434cdab7b5a4c800e279a631351f72d2416671fc813b4935d1c2b6d615004c0e42c31fa6dbcde24408d93f7e9fb4846a93a1d64abdfe27c27f194a57ae3cf5451994f0937a88b8074a35836139c10c0149af53fff0fc2cc07b19cb1790c8ba1e101be332315173c5437abe8f",
+ "signature": "0xb02b7bbbe07825555086c32089d65d2a5a40dbc44b81b89a5cd0046690a411d27db4d1b370fc5aaab0368a6568b1654903dbb7f75d1735976abeda9a317d7930a0c16d1d9e9869fb977332c973f545eb8e0c4233a80a15d0d59d6e04cc2bdb63",
+ "withdrawalCredentials": "0x0100000000000000000000003C10b7C34950823c3e6CBeA660ED4f3065a3773E"
},
{
- "depositDataRoot": "0x81b902b7d1efe033de3b53dd6f8305169abb315a7e819d5e6bfc97974df8889a",
- "publicKey": "0x8821ae92f8d4ea475d1de28cc1c3283a1bf3dabd845ec3316a988618f12c92035b8e108f5acb3bb5863df511cc95d777",
+ "depositDataRoot": "0x7ac34cf40a221760dce8fce4e7831bbe001eab2eaf778176f8bf541b281cbf2e",
+ "publicKey": "0x99c60152ae490d1e415a5d6dcb3e756bb8c3c354ac51dd3d10b0af864d802b3c457ab48321a08376de9fe0a248b32810",
"operatorIds": [
- 654,
- 655,
- 656,
- 657
+ 156,
+ 157,
+ 158,
+ 159
],
- "shares": "0x8ae7526a5c5ed194611b43cba7e9f7ca8be688d207506e5fb646718432e945dcecc23deab3f6bb06a08eb0670fd8443f0e65813e42b852943fa828e8773f01e71e87e6ccde351c5288034dbddaeb3c8fbb7726ff1461ba7784306b3ceda73cc38bd4b8a961b54eb40670e4a59a810ee7212dbeb117535d5b8ae99bb0b810e72f56f45869df5279acead31b74d25c19028df1d524dffc95a30392b3e71523065990af99e1c5247dfbeb45039ea9e93273ce3dd60f317d21b9f654655ce167dceab7a8cd097d7b2cd3a598e1d53f19ed4d687af120083230176a9d6759eb90cfd0c719c696713d29cee36917feb9c45648ad554ccbcb3a658cab0c1ad4fdb60ac507a8cc2e3e688df367faf89a89b46d9e665114cd1f60ce4299ef1709412c072719410623da937935bf4e22232429fc1065d966fd5a035bec876c0c6d1aae615680241635d9bb9129963d3e91c3a886f8d65173f77816dfb884fc13cd574c7a5b0167d68f38a80f3a5fd375733c434814f7ee03e6460c0866b4bcca18eb33b7ed6ecf98f4748b7f2329b346c3b481af48dbf617a6a50814aa6e424a05566c9a0f05437baa2e8015e8ec3893f87a82c1e0580386b1c3be21dc3507201a36a94c62723d66787cca1e9fb5d72744eae6b134b56ab22ccffd03883d6d084326bc776aec3c259947a90ca5909a2b79e98e4f15751dfb4e040ff137f3fbfe48e9290d585ddef728fe5a5caf626ab23a244f745f607fb9c097879ca09dd05cc605925feb822fd63284bb8155d94f9da831e1525bd7c71c0f263dd2e00bda77cc8c25d090373bd7afec39fdf55b135f09be0a881836f48854d0ab33188db2982e80a7a9a9f1e6c2b03fa85955a03e5eef3ab7c2b0428ec5d3704dd8365948e8aa30ed42041dda3c4a2ba4c323ceef581370e6cefb252f3657fb1750ea68040a7323180653025c283e48e1f618f19d70b3cb1cae17465ce2f68a2e1b62899c4b6a8173ca27ef5e184d0948e79a99e72e9a818e1a1c62e298dea97936d67facb5d75c97a5cf74114cf9e5435711f4db8ad392dca65020d4669cbadf52d20d4aaf441a4c1d003a28422697a67716068aa118a16b861e76953e06cf6f89a7dba102b1cb9a4850a7a58687a954e2d930e82372df24b38ca941d49926d134e749e613d5129257317818f39e10216e6822eb68c0fa22cd0b930700189d78d17e31d62c9d304407da0f3019c952f98c4cd066d3a64598d292004c0988bfc954ee22301884548b1577bfb96a9f99309df26f1a0cf5eb6bbf92e58098b68ac7a348c974941ec15c574c9e2295969f44ffebe56f95ad6611b79c7d017d2a8d4d80e93ebd994b98b625987b6d859218fd719c0beb7f57e5995c1638fdb43cdbba55c9a9dfe7f393289a6894ba6a65480db9727c6e3722c250af6cf44c4165c096c7f13af4a34f1354233ed070b99c912c6e5f4f93781b8c887b49f370cf2738321e5e73ef8bddb78f2fda996a7c34d282ff486f469cf9f948be4fbf81bbdd2dfac8490f1a104ba0ca73eb6f02a35981be05dafb9677e454115e5efc4c4f89bd961193d2469493f5a4a9887fe47bd934dd1c5b5883adb7c4b77902589540865cab2812ac56bc53f6da8261bd7f181fca1e014191d295d86f5da592c2df52c1b3603b08356f15933f614662ed2b0961e5afcb4de93f27a8bdd7a307cd8ac9eef0fb01c277db088470f9c6524934eb377670dc8fa8b87a162a48b78fc4b3bb0d60e8a38f61fb2245185fd3ec334b94ec5c3d3ada4bd3ee4814f07d0ca2e0cd4c3f8f205dcfbd07150e8a17b56da332dcb3cba935bf1151c765a3e044382f450344ae76eb7a7b4198fe80fdff",
- "signature": "0x987f026c0e763babd5268a92f723853ee4b1ee812da11f796d42d5f46ffe3b32c700c2abf46bed92c29b3a1e0ea9fc6f00e80ca408d6ca2ff5f84efe9f1bd07e498d98743e53755d8ad5309c1beabd73f755ceefde6594158c96ece6ec7e1b65",
- "withdrawalCredentials": "0x0100000000000000000000004843982c750b58846a0f74dB7a4a2452BE14A01c"
+ "shares": "0xa3d3c7ad3ca4569d1df186dec501e593f7c705430f821d752d17fa74e190708727d9210e34e9f46de59194e69c0dc10e0167ea0a333e48c100007047846d3399f971f790605c61c8d17cf3de90b4b09e9f6ee12e2e794557d0f7cb08a4a95560a043760a3a3cd005e0ea9487c2f7c9e88a4e73dac465e71b3af81ad7592ba3c4aea7dff55bd7f666046f6cd14adb404d8319f09c67d8b32a6ae1d8c503565d128dd1267fe5d18b9bf18cbafe859bd703294de5ad59e546f33b07740523ce46d595fbd2ab9fa69ae80d3b1c416e0a02b7a26b314bf36ce10baa565ff2b3c94fbf7233e6ce31accc1fbd4beee17149570988f2ed48b86bba13c0356200acb9a740c3f62a00dad0d73078a41c681652b026eeb6a317b6791ea721375625469475f6b433c4bb289b093a3565e5988323082d855298a6ae8efad9c495b1fca20cda4b803c4169c89052376663b59049adcd7895a345e93c9b90de0f60fc0a871ce33359d175d192a5065dbb5e2ba348286bfaaa24620f04a66edce05e44652323362145db16455a3a23c547f336fd928c8662ea653c0412369c7f788ffba230888ba5597c29f6e63ebeae72675f8a194012b80e496b5dc3d802939677ce50b2111f00f6154f0ba64613ed6bcadab9b298f7fedd624de9c3db670d9338063b5b66b39fbcf5bc96a2668a18847cd771db7384aea1d2896d98bea41eae358a45a57c4fc473ea9aa2afd7cb0e225ff86bd72593dd860068c02cfe72a7ccda6538ebb8026067e888166d76c2c9c4e38c98a736f640f3c9c83bd6f0a7e2a176cc683ecbefc7b8f1fa1e48aa9d4c858af4dcc88c762b2310d5105b9c04293953cd41fd1ba2d5d15bac4a169c15a1b76096747125aec189ed89d401470cf6f2937d8fa34a80a252f4e51b05795f4af11e4b33375d95162930e768cac269c7d1625db216741de4faeea8aa9f7aca60b624ad2f8b2a37433982cc20c973f3acbea965b2d21a8cad859fd495132f53943a5714ccdd6119b86105d49d02a8165fdff1762585d7fd51eb6e2f021e91b01da7dba4a1dae2d22707aea7df5a89692e7e2d9cbddb5e60fe673ca1e3b1abcfcb52de5f580a882c57e1096c93cfa4ac0c6bfa2eb622f0e6708aa2470e66d76a95a1a6d8c2bd7b8d7466d0a784b9d1ca262ba752a4dc772334feff996c841def8df9482d66f4ca065e2002377efaedf638797db1e2f1662d677c5e4df924ebc945c3cffbe9042ee1c7f4173264daa458e543486824693265e878aed2ef3baedcd8d166547be542f65dfd6df67aefda0fc9964a0203dc151dbcc7a231190fb73f8170797dc9cbaf153c95f608f5e37a72f578352a3dd3a4f905a8387ede01041e3171150ee311d54c9a058fa5d4173b40ab203c713c5127360e966246da3d4dd2d68cf162815b82f562cf63432804ba058d08aeb0442c21e5955f6d0a20be5d17bf52a542497728fbd57f2e25b01dde449f5f548642194247ae257f26e8617952daf45a0a172bbbe5f8264afca7fec74499bf1e370b5b26a6e10e7d31f7730eecc78dd7cc0a060902bf660a0fb8f8be78f205d779d2d97109bfbcbac672fb7bc9fbee492828ab6a055373af10f1cbc1b134a102f8df62fe65c1e25329a740b3a73cc2af971ff1ff5351d898f0a11b3ff5ec27be3918ee0c442473897ab8b611ae8c5f39cd0a6f5f32337cadfd0e709ecbe4a48c248b177639f6f978fb04b1c0b5d3d3f9b93773b20ecb8a4f0649dd249a883f708ea2286e746dce3c66a5a2d25e41635cf7e593a381e6088eebd93126f398d6c08e947f2739064cdabb434404701f0fa3169c0830997c5be20cc07716e6203e0e8e92eb4d16b6",
+ "signature": "0xa863c2d564ca2dbcc5bcaa44361f223c01f92d65cfa860cc366d1f15bdcabe206fae9ce270b38082f83796a0ba0bc38601c6e80110d1f9793ae3e05c3c6991ca7bd6543b412ff612e53fc5c80f71e57b2cbdd7dfa1891aa0f1c738900c7194c4",
+ "withdrawalCredentials": "0x0100000000000000000000004F64df9D1B772652176F5e695CC99bab469b3089"
}
]
}
\ No newline at end of file
diff --git a/common/data/src/providers/schema.ts b/common/data/src/providers/schema.ts
index 7b016a943..e2667143c 100644
--- a/common/data/src/providers/schema.ts
+++ b/common/data/src/providers/schema.ts
@@ -1,6 +1,6 @@
import * as glue from '@aws-cdk/aws-glue-alpha'
import { JsonSchema } from '../interfaces/JsonSchema'
-import { snakeCase } from '@casimir/helpers'
+import { snakeCase } from '@casimir/format'
export type JsonType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'
export type GlueType = glue.Type
diff --git a/common/env/.gitignore b/common/env/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/common/env/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/common/env/package.json b/common/env/package.json
new file mode 100644
index 000000000..cd105a2f3
--- /dev/null
+++ b/common/env/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@casimir/env",
+ "private": "true",
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "echo '@casimir/env build not specified. Disregard this warning and any listed errors above if @casimir/env is not needed for the current project build.' && exit 0",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ }
+}
\ No newline at end of file
diff --git a/common/env/src/index.ts b/common/env/src/index.ts
new file mode 100644
index 000000000..900422a86
--- /dev/null
+++ b/common/env/src/index.ts
@@ -0,0 +1,41 @@
+const ETHEREUM_CONTRACTS = {
+ TESTNET: {
+ MANAGER_ADDRESS: '0xFBA09a098014b414A4aBD2C1Ca43383Ad63f8492',
+ REGISTRY_ADDRESS: '0x5c118E76cCfBEAd615BBB2B485c0729c69CEac1a',
+ UPKEEP_ADDRESS: '0x449AcFeb4769C283dcB94ae09779A3233A9c3653',
+ VIEWS_ADDRESS: '0x1EcF11435187dCb07aA758Db006cA98EA381817b',
+
+ FUNCTIONS_BILLING_REGISTRY_ADDRESS: '0x736fe8342E7BA5bF50757D266391b675394D9458',
+ FUNCTIONS_ORACLE_ADDRESS: '0x599E62F28a185c2F68c6DC82CD7dDd450C44d587',
+ FUNCTIONS_ORACLE_FACTORY_ADDRESS: '0x45b277aD532172c9DDc079729F233875fD8B649D',
+
+ POOL_BEACON_ADDRESS: '0x443d84cB8b116B9620F6807280160E8C6d6D4b5e',
+ REGISTRY_BEACON_ADDRESS: '0x8E1539E198CB13dB0abce5CBB62a34eA2E0aF513',
+ UPKEEP_BEACON_ADDRESS: '0xEeBc166D29A19cA47d2D15B2f0c3Fe1211F50821',
+
+ BEACON_DEPOSIT_ADDRESS: '0x07b39F4fDE4A38bACe212b546dAc87C58DfE3fDC',
+ DAO_ORACLE_ADDRESS: '',
+ KEEPER_REGISTRAR_ADDRESS: '0x57A4a13b35d25EE78e084168aBaC5ad360252467',
+ KEEPER_REGISTRY_ADDRESS: '0xE16Df59B887e3Caa439E0b29B42bA2e7976FD8b2',
+ LINK_ETH_FEED_ADDRESS: '0xb4c4a493AB6356497713A78FFA6c60FB53517c63',
+ LINK_TOKEN_ADDRESS: '0x326C977E6efc84E512bB9C30f76E30c160eD06FB',
+ SSV_NETWORK_ADDRESS: '0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D',
+ SSV_TOKEN_ADDRESS: '0x3a9f01091C446bdE031E39ea8354647AFef091E7',
+ SSV_VIEWS_ADDRESS: '0xAE2C84c48272F5a1746150ef333D5E5B51F68763',
+ SWAP_FACTORY_ADDRESS: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
+ SWAP_ROUTER_ADDRESS: '0xE592427A0AEce92De3Edee1F18E0157C05861564',
+ WETH_TOKEN_ADDRESS: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'
+ }
+}
+
+enum ETHEREUM_NETWORK_NAME {
+ MAINNET = 'mainnet',
+ TESTNET = 'goerli'
+}
+
+enum ETHEREUM_RPC_URL {
+ MAINNET = 'https://mainnet.infura.io/v3/46a379ac6895489f812f33beb726b03b',
+ TESTNET = 'https://goerli.infura.io/v3/46a379ac6895489f812f33beb726b03b'
+}
+
+export { ETHEREUM_CONTRACTS, ETHEREUM_NETWORK_NAME, ETHEREUM_RPC_URL }
\ No newline at end of file
diff --git a/common/env/tsconfig.json b/common/env/tsconfig.json
new file mode 100644
index 000000000..28ff0291b
--- /dev/null
+++ b/common/env/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "strict": true,
+ "preserveConstEnums": true,
+ "noEmit": true,
+ "sourceMap": false,
+ "module": "CommonJS",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true
+ },
+ "include": [
+ "./src/*"
+ ]
+ }
\ No newline at end of file
diff --git a/common/events/.gitignore b/common/events/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/common/events/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/common/events/package.json b/common/events/package.json
new file mode 100644
index 000000000..35eca4455
--- /dev/null
+++ b/common/events/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "@casimir/events",
+ "private": "true",
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "echo '@casimir/events build not specified. Disregard this warning and any listed errors above if @casimir/events is not needed for the current project build.' && exit 0",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "dependencies": {
+ "ethers": "^5.7.2"
+ },
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+}
diff --git a/common/events/src/index.ts b/common/events/src/index.ts
new file mode 100644
index 000000000..d5df5e8bc
--- /dev/null
+++ b/common/events/src/index.ts
@@ -0,0 +1,54 @@
+import { ethers } from 'ethers'
+
+export function getEventsIterable(input: {
+ contractFilters: {
+ abi: string[]
+ address: string
+ events: string[]
+ }[]
+ ethereumUrl?: string
+ provider?: ethers.providers.JsonRpcProvider
+ startBlock?: number
+}) {
+ const provider =
+ input.provider || new ethers.providers.JsonRpcProvider(input.ethereumUrl)
+ return (async function* () {
+ const queue: ethers.Event[][] = []
+ const enqueue = (...args: ethers.Event[]) => queue.push(args)
+ for (const filter of input.contractFilters) {
+ const contract = new ethers.Contract(
+ filter.address,
+ filter.abi,
+ provider
+ ) as ethers.Contract
+ if (input.startBlock !== undefined) {
+ for (const event of filter.events) {
+ const historicalEvents = await contract.queryFilter(
+ event,
+ input.startBlock,
+ 'latest'
+ )
+ for (const historicalEvent of historicalEvents) {
+ enqueue(historicalEvent)
+ }
+ }
+ }
+ for (const event of filter.events) {
+ contract.on(event, enqueue)
+ while (true) {
+ if (queue.length === 0) {
+ await new Promise((resolve) => {
+ const waitListener = () => {
+ contract.off(event, waitListener)
+ resolve()
+ }
+ contract.on(event, waitListener)
+ })
+ } else {
+ yield queue.shift()
+ }
+ }
+ }
+ }
+ })()
+}
diff --git a/common/events/tsconfig.json b/common/events/tsconfig.json
new file mode 100644
index 000000000..28ff0291b
--- /dev/null
+++ b/common/events/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "strict": true,
+ "preserveConstEnums": true,
+ "noEmit": true,
+ "sourceMap": false,
+ "module": "CommonJS",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true
+ },
+ "include": [
+ "./src/*"
+ ]
+ }
\ No newline at end of file
diff --git a/common/fetch/.gitignore b/common/fetch/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/common/fetch/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/common/fetch/package.json b/common/fetch/package.json
new file mode 100644
index 000000000..5bfcab6c3
--- /dev/null
+++ b/common/fetch/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@casimir/fetch",
+ "private": true,
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "echo '@casimir/fetch build not specified. Disregard this warning and any listed errors above if @casimir/fetch is not needed for the current project build.' && exit 0",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+}
diff --git a/common/fetch/src/index.ts b/common/fetch/src/index.ts
new file mode 100644
index 000000000..2b3acd879
--- /dev/null
+++ b/common/fetch/src/index.ts
@@ -0,0 +1,28 @@
+/**
+ * Retry a fetch request
+ * @param {RequestInfo} info - URL string or request object
+ * @param {RequestInit} [init] - Request init options
+ * @param {number | undefined} retriesLeft - Number of retries left (default: 25)
+ * @returns {Promise} Response
+ * @example
+ * const response = await fetchRetry('https://example.com')
+ */
+export async function fetchRetry(info: RequestInfo, init?: RequestInit, retriesLeft: number | undefined = 25): Promise {
+ if (retriesLeft === 0) {
+ throw new Error('API request failed after maximum retries')
+ }
+
+ try {
+ const response = await fetch(info, init)
+ if (response.status !== 200) {
+ await new Promise(resolve => setTimeout(resolve, 5000))
+ console.log('Retrying fetch request to', info, init)
+ return await fetchRetry(info, init || {}, retriesLeft - 1)
+ }
+ return response
+ } catch (error) {
+ await new Promise(resolve => setTimeout(resolve, 5000))
+ console.log('Retrying fetch request to', info, init)
+ return await fetchRetry(info, init || {}, retriesLeft - 1)
+ }
+}
\ No newline at end of file
diff --git a/common/helpers/tsconfig.json b/common/fetch/tsconfig.json
similarity index 100%
rename from common/helpers/tsconfig.json
rename to common/fetch/tsconfig.json
diff --git a/common/format/.gitignore b/common/format/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/common/format/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/common/format/package.json b/common/format/package.json
new file mode 100644
index 000000000..b7c4ef91c
--- /dev/null
+++ b/common/format/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@casimir/format",
+ "private": true,
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "echo '@casimir/format build not specified. Disregard this warning and any listed errors above if @casimir/format is not needed for the current project build.' && exit 0",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+}
diff --git a/common/format/src/index.ts b/common/format/src/index.ts
new file mode 100644
index 000000000..a4eed78b6
--- /dev/null
+++ b/common/format/src/index.ts
@@ -0,0 +1,55 @@
+/**
+ * Convert any string to camelCase.
+ * @param string - The input string
+ * @returns A camelCase string from the input string
+ */
+export function camelCase(string: string): string {
+ const words = string.split(/[\s_-]+/).map(word => {
+ return word.replace(/\w+/g, (word) => {
+ return word[0].toUpperCase() + word.slice(1).toLowerCase()
+ })
+ })
+ const result = words.join('')
+ return result[0].toLowerCase() + result.slice(1)
+}
+
+/**
+ * Convert any string to PascalCase
+ *
+ * @param string - The input string
+ * @returns A PascalCase string from the input string
+ *
+ */
+export function pascalCase(string: string): string {
+ const words = string.split(/[\s_-]+/).map(word => {
+ return word.replace(/\w+/g, (word) => {
+ return word[0].toUpperCase() + word.slice(1).toLowerCase()
+ })
+ })
+ const result = words.join('')
+ return result
+}
+
+/**
+ * Convert any string to snake_case.
+ * @param string - The input string
+ * @returns A snake_case string from the input string
+ */
+export function snakeCase(string: string): string {
+ return string.replace(/\W+/g, ' ')
+ .split(/ |\B(?=[A-Z])/)
+ .map(word => word.toLowerCase())
+ .join('_')
+}
+
+/**
+ * Convert any string to kebab-case.
+ * @param string - The input string
+ * @returns A kebab-case string from the input string
+ */
+export function kebabCase(string: string): string {
+ return string.replace(/\W+/g, ' ')
+ .split(/ |\B(?=[A-Z])/)
+ .map(word => word.toLowerCase())
+ .join('-')
+}
\ No newline at end of file
diff --git a/common/format/tsconfig.json b/common/format/tsconfig.json
new file mode 100644
index 000000000..eb87c3f12
--- /dev/null
+++ b/common/format/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "strict": true,
+ "preserveConstEnums": true,
+ "noEmit": true,
+ "sourceMap": false,
+ "module": "CommonJS",
+ "moduleResolution": "Node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true
+ },
+ "exclude": [
+ "node_modules"
+ ],
+ "include": [
+ "./src/*"
+ ]
+}
\ No newline at end of file
diff --git a/common/helpers/.gitignore b/common/helpers/.gitignore
deleted file mode 100644
index 04c01ba7b..000000000
--- a/common/helpers/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules/
-dist/
\ No newline at end of file
diff --git a/common/helpers/package.json b/common/helpers/package.json
deleted file mode 100644
index 327af46c8..000000000
--- a/common/helpers/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "@casimir/helpers",
- "private": true,
- "main": "src/index.ts",
- "scripts": {
- "build": "echo '@casimir/helpers build not specified. Disregard this warning and any listed errors above if @casimir/helpers is not needed for the current project build.' && exit 0",
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "dependencies": {
- "ethers": "^5.7.2"
- },
- "devDependencies": {
- "@types/node": "^17.0.38"
- }
-}
diff --git a/common/helpers/src/index.ts b/common/helpers/src/index.ts
deleted file mode 100644
index e7bf0f51b..000000000
--- a/common/helpers/src/index.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-import { exec, execSync } from 'child_process'
-import { ethers } from 'ethers'
-
-/**
- * Convert any string to camelCase.
- * @param string - The input string
- * @returns A camelCase string from the input string
- */
-export function camelCase(string: string): string {
- const words = string.split(/[\s_-]+/).map(word => {
- return word.replace(/\w+/g, (word) => {
- return word[0].toUpperCase() + word.slice(1).toLowerCase()
- })
- })
- const result = words.join('')
- return result[0].toLowerCase() + result.slice(1)
-}
-
-/**
- * Convert any string to PascalCase
- *
- * @param string - The input string
- * @returns A PascalCase string from the input string
- *
- */
-export function pascalCase(string: string): string {
- const words = string.split(/[\s_-]+/).map(word => {
- return word.replace(/\w+/g, (word) => {
- return word[0].toUpperCase() + word.slice(1).toLowerCase()
- })
- })
- const result = words.join('')
- return result
-}
-
-/**
- * Convert any string to snake_case.
- * @param string - The input string
- * @returns A snake_case string from the input string
- */
-export function snakeCase(string: string): string {
- return string.replace(/\W+/g, ' ')
- .split(/ |\B(?=[A-Z])/)
- .map(word => word.toLowerCase())
- .join('_')
-}
-
-/**
- * Convert any string to kebab-case.
- * @param string - The input string
- * @returns A kebab-case string from the input string
- */
-export function kebabCase(string: string): string {
- return string.replace(/\W+/g, ' ')
- .split(/ |\B(?=[A-Z])/)
- .map(word => word.toLowerCase())
- .join('-')
-}
-
-/**
- * Run any shell command in a child process and return a promise
- * @param command - The full command to run
- * @returns A promise that resolves when the command exits
- */
-export async function run(command: string) {
- const child = exec(command)
- let data = ''
- return new Promise((resolve, reject) => {
- child.on('error', reject)
- child.stdout?.on('data', chunk => {
- process.stdout.write(chunk.toString())
- data += chunk.toString()
- })
- child.stderr?.on('data', chunk => {
- process.stdout.write(chunk.toString())
- })
- child.on('exit', () => {
- resolve(data)
- })
- })
-}
-
-/**
- * Retry run any shell command in a child process and return a promise
- * @param command - The full command to run
- * @param retriesLeft - Number of retries left (default: 5)
- * @returns A promise that resolves when the command exits
- */
-export async function runRetry(command: string, retriesLeft: number | undefined = 25): Promise {
- if (retriesLeft === 0) {
- throw new Error('Command failed after maximum retries')
- }
- try {
- return await run(command)
- } catch (error) {
- await new Promise(resolve => setTimeout(resolve, 5000))
- console.log('Retrying command', command)
- return await runRetry(command, retriesLeft - 1)
- }
-}
-
-/**
- * Run any shell command synchronously in a child process
- * @param command - The full command to run
- * @returns The output of the command
- */
-export function runSync(command: string) {
- return execSync(command).toString()
-}
-
-/**
- * Retry a fetch request.
- * @param {RequestInfo} info - URL string or request object
- * @param {RequestInit} init - Request init options
- * @param {number | undefined} retriesLeft - Number of retries left (default: 5)
- * @returns {Promise} Response
- * @example
- * const response = await fetchRetry('https://example.com')
- */
-export async function fetchRetry(info: RequestInfo, init?: RequestInit, retriesLeft: number | undefined = 25): Promise {
- if (retriesLeft === 0) {
- throw new Error('API request failed after maximum retries')
- }
-
- try {
- const response = await fetch(info, init)
- if (response.status !== 200) {
- await new Promise(resolve => setTimeout(resolve, 5000))
- console.log('Retrying fetch request to', info, init)
- return await fetchRetry(info, init || {}, retriesLeft - 1)
- }
- return response
- } catch (error) {
- await new Promise(resolve => setTimeout(resolve, 5000))
- console.log('Retrying fetch request to', info, init)
- return await fetchRetry(info, init || {}, retriesLeft - 1)
- }
-}
-
-/**
- * Get a wallet address (optionially from a mnemonic).
- * @param mnemonic - The wallet mnemonic (optional)
- * @returns The wallet address
- */
-export async function getWalletAddress(mnemonic?: string) {
- const wallet = getWallet(mnemonic)
- return wallet.address
-}
-
-/**
- * Get a wallet keystore (optionially from a mnemonic).
- * @param mnemonic - The wallet mnemonic (optional)
- * @returns The wallet keystore
- */
-export async function getWalletKeystore(mnemonic?: string) {
- const wallet = getWallet(mnemonic)
- const keystoreString = await wallet.encrypt('')
- return JSON.parse(keystoreString)
-}
-
-/**
- * Get a wallet (optionially from a mnemonic).
- * @param mnemonic - The wallet mnemonic (optional)
- * @returns The wallet
- */
-export function getWallet(mnemonic?: string): ethers.Wallet {
- if (mnemonic) {
- return ethers.Wallet.fromMnemonic(mnemonic)
- }
- return ethers.Wallet.createRandom()
-}
-
-/**
- * Get withdrawal credentials from withdrawal address
- * @param {string} withdrawalAddress - Withdrawal address
- * @returns {string} Withdrawal credentials
- */
-export function getWithdrawalCredentials(withdrawalAddress: string): string {
- return '01' + '0'.repeat(22) + withdrawalAddress.split('0x')[1]
-}
-
-export async function getFutureContractAddress({ wallet, nonce, index }: {
- wallet: ethers.Wallet,
- nonce: number,
- index?: number
-}): Promise {
- return ethers.utils.getContractAddress({
- from: wallet.address,
- nonce: nonce + (index || 0)
- })
-}
\ No newline at end of file
diff --git a/common/images/casimir.png b/common/images/casimir.png
deleted file mode 100644
index 6df6bb420..000000000
Binary files a/common/images/casimir.png and /dev/null differ
diff --git a/common/logs/.gitignore b/common/logs/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/common/logs/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/common/logs/package.json b/common/logs/package.json
new file mode 100644
index 000000000..6885ba767
--- /dev/null
+++ b/common/logs/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@casimir/logs",
+ "private": "true",
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "echo '@casimir/logs build not specified. Disregard this warning and any listed errors above if @casimir/logs is not needed for the current project build.' && exit 0",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+}
\ No newline at end of file
diff --git a/common/logs/src/index.ts b/common/logs/src/index.ts
new file mode 100644
index 000000000..7a82c2068
--- /dev/null
+++ b/common/logs/src/index.ts
@@ -0,0 +1,19 @@
+import fs from 'fs'
+
+export function getStartBlock(blockLogPath: string) {
+ if (fs.existsSync(blockLogPath)) {
+ return parseInt(fs.readFileSync(blockLogPath, 'utf8'))
+ }
+}
+
+export function updateStartBlock(blockLogPath: string, blockNumber: number) {
+ fs.writeFileSync(blockLogPath, blockNumber.toString())
+}
+
+export function updateExecutionLog(executionLogPath: string, log: string) {
+ fs.appendFileSync(executionLogPath, `${log}\n`)
+}
+
+export function updateErrorLog(errorLogPath: string, log: string) {
+ fs.appendFileSync(errorLogPath, `${log}\n`)
+}
\ No newline at end of file
diff --git a/common/logs/tsconfig.json b/common/logs/tsconfig.json
new file mode 100644
index 000000000..28ff0291b
--- /dev/null
+++ b/common/logs/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "strict": true,
+ "preserveConstEnums": true,
+ "noEmit": true,
+ "sourceMap": false,
+ "module": "CommonJS",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true
+ },
+ "include": [
+ "./src/*"
+ ]
+ }
\ No newline at end of file
diff --git a/common/shell/.gitignore b/common/shell/.gitignore
new file mode 100644
index 000000000..b512c09d4
--- /dev/null
+++ b/common/shell/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/common/shell/package.json b/common/shell/package.json
new file mode 100644
index 000000000..32877d984
--- /dev/null
+++ b/common/shell/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@casimir/shell",
+ "private": true,
+ "main": "src/index.ts",
+ "scripts": {
+ "build": "echo '@casimir/shell build not specified. Disregard this warning and any listed errors above if @casimir/shell is not needed for the current project build.' && exit 0",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+}
diff --git a/common/shell/src/index.ts b/common/shell/src/index.ts
new file mode 100644
index 000000000..96818d2be
--- /dev/null
+++ b/common/shell/src/index.ts
@@ -0,0 +1,52 @@
+import { exec, execSync } from 'child_process'
+
+/**
+ * Run any shell command in a child process and return a promise
+ * @param command - The full command to run
+ * @returns A promise that resolves when the command exits
+ */
+export async function run(command: string) {
+ const child = exec(command)
+ let data = ''
+ return new Promise((resolve, reject) => {
+ child.on('error', reject)
+ child.stdout?.on('data', chunk => {
+ process.stdout.write(chunk.toString())
+ data += chunk.toString()
+ })
+ child.stderr?.on('data', chunk => {
+ process.stdout.write(chunk.toString())
+ })
+ child.on('exit', () => {
+ resolve(data)
+ })
+ })
+}
+
+/**
+ * Retry run any shell command in a child process and return a promise
+ * @param command - The full command to run
+ * @param retriesLeft - Number of retries left (default: 5)
+ * @returns A promise that resolves when the command exits
+ */
+export async function runRetry(command: string, retriesLeft: number | undefined = 25): Promise {
+ if (retriesLeft === 0) {
+ throw new Error('Command failed after maximum retries')
+ }
+ try {
+ return await run(command)
+ } catch (error) {
+ await new Promise(resolve => setTimeout(resolve, 5000))
+ console.log('Retrying command', command)
+ return await runRetry(command, retriesLeft - 1)
+ }
+}
+
+/**
+ * Run any shell command synchronously in a child process
+ * @param command - The full command to run
+ * @returns The output of the command
+ */
+export function runSync(command: string) {
+ return execSync(command).toString()
+}
\ No newline at end of file
diff --git a/common/shell/tsconfig.json b/common/shell/tsconfig.json
new file mode 100644
index 000000000..eb87c3f12
--- /dev/null
+++ b/common/shell/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "strict": true,
+ "preserveConstEnums": true,
+ "noEmit": true,
+ "sourceMap": false,
+ "module": "CommonJS",
+ "moduleResolution": "Node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true
+ },
+ "exclude": [
+ "node_modules"
+ ],
+ "include": [
+ "./src/*"
+ ]
+}
\ No newline at end of file
diff --git a/common/speculos/.gitignore b/common/speculos/.gitignore
deleted file mode 100644
index 04c01ba7b..000000000
--- a/common/speculos/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules/
-dist/
\ No newline at end of file
diff --git a/common/speculos/package.json b/common/speculos/package.json
deleted file mode 100644
index acfa4c697..000000000
--- a/common/speculos/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "@casimir/speculos",
- "private":"true",
- "main": "src/index.ts",
- "scripts": {
- "build": "echo '@casimir/speculos build not specified. Disregard this warning and any listed errors above if @casimir/speculos is not needed for the current project build.' && exit 0",
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "dependencies": {
- "@ledgerhq/hw-transport": "^6.27.10"
- }
-}
\ No newline at end of file
diff --git a/common/speculos/src/index.ts b/common/speculos/src/index.ts
deleted file mode 100644
index 0c0df8c55..000000000
--- a/common/speculos/src/index.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import Transport from '@ledgerhq/hw-transport'
-
-/**
- * Speculos TCP transport implementation
- *
- * @example
- * import TransportSpeculosHTTP from "@casimir/speculos-transport"
- * const transport = await TransportSpeculosHTTP.create()
- * const res = await transport.send(0xE0, 0x01, 0, 0)
- */
-export class TransportSpeculosHTTP extends Transport {
- baseURL: string
- eventStream!: EventSource
-
- constructor(baseURL: string) {
- super()
- this.baseURL = baseURL
- }
-
- static isSupported = (): Promise => Promise.resolve(true)
- // this transport is not discoverable
- static list = (): Promise => Promise.resolve([])
- static listen = () => ({
- // eslint-disable-next-line @typescript-eslint/no-empty-function
- unsubscribe: () => { },
- })
-
- static open = async (
- baseURL?: string
- ): Promise => {
- try {
- baseURL = baseURL || 'http://127.0.0.1:5000'
- const transport = new TransportSpeculosHTTP(baseURL)
- const eventSource = new EventSource(`${baseURL}/events?stream=true`)
- // eventSource.addEventListener('open', (event: Event) => console.warn('Ledger', event.type), false)
- // eventSource.addEventListener('error', (event: Event) => console.warn('Ledger', event.type, eventSource.readyState), false)
- // eventSource.addEventListener('message', (message: MessageEvent) => console.warn('Ledger', message.type, message.data), false)
- transport.eventStream = eventSource
- return transport
- } catch (error) {
- console.log(error)
- throw error
- }
- }
-
- /**
- * Press and release button
- * buttons available: left, right, both
- * @param {*} but
- */
- button = async (but: string): Promise => {
- const action = { action: 'press-and-release' }
- await fetch(`${this.baseURL}/button/${but}`, { method: 'POST', body: JSON.stringify(action) })
- }
-
- async exchange(apdu: Buffer): Promise {
- const hex = apdu.toString('hex')
- const response = await fetch(`${this.baseURL}/apdu`, { method: 'POST', body: JSON.stringify({ data: hex }) })
- const json = await response.json()
- const { data } = json
- return Buffer.from(data, 'hex')
- }
-
- async close() {
- // close event stream
- this.eventStream.close()
- return Promise.resolve()
- }
-}
diff --git a/common/speculos/tsconfig.json b/common/speculos/tsconfig.json
deleted file mode 100644
index 5499e9dfe..000000000
--- a/common/speculos/tsconfig.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "compilerOptions": {
- "target": "ESNext",
- "strict": true,
- "preserveConstEnums": true,
- "noEmit": true,
- "sourceMap": false,
- "module": "commonjs",
- "moduleResolution": "node",
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "isolatedModules": true,
- },
- "exclude": ["node_modules"],
- "include": ["./src/*"]
-}
diff --git a/common/ssv/src/interfaces/Cluster.ts b/common/ssv/src/interfaces/Cluster.ts
index cbe10c873..011c669e6 100644
--- a/common/ssv/src/interfaces/Cluster.ts
+++ b/common/ssv/src/interfaces/Cluster.ts
@@ -4,6 +4,6 @@ export interface Cluster {
validatorCount: number | ethers.BigNumber
networkFeeIndex: number | ethers.BigNumber
index: number | ethers.BigNumber
- balance: number | ethers.BigNumber
active: boolean
+ balance: number | ethers.BigNumber
}
\ No newline at end of file
diff --git a/common/ssv/src/interfaces/ScannerOptions.ts b/common/ssv/src/interfaces/ScannerOptions.ts
index a003362bd..9e23c356d 100644
--- a/common/ssv/src/interfaces/ScannerOptions.ts
+++ b/common/ssv/src/interfaces/ScannerOptions.ts
@@ -4,5 +4,5 @@ export interface ScannerOptions {
ethereumUrl?: string
provider?: ethers.providers.JsonRpcProvider
ssvNetworkAddress: string
- ssvNetworkViewsAddress: string
+ ssvViewsAddress: string
}
\ No newline at end of file
diff --git a/common/ssv/src/providers/scanner.ts b/common/ssv/src/providers/scanner.ts
index b5c04e0a4..542dba7ed 100644
--- a/common/ssv/src/providers/scanner.ts
+++ b/common/ssv/src/providers/scanner.ts
@@ -1,7 +1,8 @@
import { ethers } from 'ethers'
-import { ISSVNetwork, ISSVNetworkViews } from '@casimir/ethereum/build/@types'
-import ISSVNetworkAbi from '@casimir/ethereum/build/abi/ISSVNetwork.json'
-import ISSVNetworkViewsAbi from '@casimir/ethereum/build/abi/ISSVNetworkViews.json'
+import { ISSVClusters, ISSVOperators, ISSVViews } from '@casimir/ethereum/build/@types'
+import ISSVClustersAbi from '@casimir/ethereum/build/abi/ISSVClusters.json'
+import ISSVOperatorsAbi from '@casimir/ethereum/build/abi/ISSVOperators.json'
+import ISSVViewsAbi from '@casimir/ethereum/build/abi/ISSVViews.json'
import { GetClusterInput } from '../interfaces/GetClusterInput'
import { Cluster } from '../interfaces/Cluster'
import { Operator } from '../interfaces/Operator'
@@ -12,8 +13,9 @@ export class Scanner {
WEEK = this.DAY * 7
MONTH = this.DAY * 30
provider: ethers.providers.JsonRpcProvider
- ssvNetwork: ISSVNetwork & ethers.Contract
- ssvNetworkViews: ISSVNetworkViews & ethers.Contract
+ ssvClusters: ISSVClusters & ethers.Contract
+ ssvOperators: ISSVOperators & ethers.Contract
+ ssvViews: ISSVViews & ethers.Contract
constructor(options: ScannerOptions) {
if (options.provider) {
@@ -21,8 +23,9 @@ export class Scanner {
} else {
this.provider = new ethers.providers.JsonRpcProvider(options.ethereumUrl)
}
- this.ssvNetwork = new ethers.Contract(options.ssvNetworkAddress, ISSVNetworkAbi, this.provider) as ISSVNetwork & ethers.Contract
- this.ssvNetworkViews = new ethers.Contract(options.ssvNetworkViewsAddress, ISSVNetworkViewsAbi, this.provider) as ISSVNetworkViews & ethers.Contract
+ this.ssvClusters = new ethers.Contract(options.ssvNetworkAddress, ISSVClustersAbi, this.provider) as ISSVClusters & ethers.Contract
+ this.ssvOperators = new ethers.Contract(options.ssvNetworkAddress, ISSVOperatorsAbi, this.provider) as ISSVOperators & ethers.Contract
+ this.ssvViews = new ethers.Contract(options.ssvViewsAddress, ISSVViewsAbi, this.provider) as ISSVViews & ethers.Contract
}
/**
@@ -32,13 +35,13 @@ export class Scanner {
*/
async getCluster(input: GetClusterInput): Promise {
const { ownerAddress, operatorIds } = input
- const eventFilters = [
- this.ssvNetwork.filters.ClusterDeposited(ownerAddress),
- this.ssvNetwork.filters.ClusterWithdrawn(ownerAddress),
- this.ssvNetwork.filters.ValidatorAdded(ownerAddress),
- this.ssvNetwork.filters.ValidatorRemoved(ownerAddress),
- this.ssvNetwork.filters.ClusterLiquidated(ownerAddress),
- this.ssvNetwork.filters.ClusterReactivated(ownerAddress)
+ const contractFilters = [
+ this.ssvClusters.filters.ClusterDeposited(ownerAddress),
+ this.ssvClusters.filters.ClusterWithdrawn(ownerAddress),
+ this.ssvClusters.filters.ValidatorAdded(ownerAddress),
+ this.ssvClusters.filters.ValidatorRemoved(ownerAddress),
+ this.ssvClusters.filters.ClusterLiquidated(ownerAddress),
+ this.ssvClusters.filters.ClusterReactivated(ownerAddress)
]
let step = this.MONTH
const latestBlockNumber = await this.provider.getBlockNumber()
@@ -49,8 +52,8 @@ export class Scanner {
while (!cluster && fromBlock > 0) {
try {
const items = []
- for (const filter of eventFilters) {
- const filteredItems = await this.ssvNetwork.queryFilter(filter, fromBlock, toBlock)
+ for (const filter of contractFilters) {
+ const filteredItems = await this.ssvClusters.queryFilter(filter, fromBlock, toBlock)
items.push(...filteredItems)
}
for (const item of items) {
@@ -64,15 +67,15 @@ export class Scanner {
validatorCount,
networkFeeIndex,
index,
- balance,
- active
+ active,
+ balance
] = args.cluster
cluster = {
validatorCount,
networkFeeIndex,
index,
- balance,
- active
+ active,
+ balance
}
}
}
@@ -90,8 +93,8 @@ export class Scanner {
validatorCount: 0,
networkFeeIndex: 0,
index: 0,
- balance: 0,
- active: true
+ active: true,
+ balance: 0
}
return cluster
}
@@ -102,10 +105,10 @@ export class Scanner {
* @returns {Promise} Owner validator nonce
*/
async getNonce(ownerAddress: string): Promise {
- const eventFilter = this.ssvNetwork.filters.ValidatorAdded(ownerAddress)
+ const eventFilter = this.ssvClusters.filters.ValidatorAdded(ownerAddress)
const fromBlock = 0
const toBlock = 'latest'
- const items = await this.ssvNetwork.queryFilter(eventFilter, fromBlock, toBlock)
+ const items = await this.ssvClusters.queryFilter(eventFilter, fromBlock, toBlock)
return items.length
}
@@ -115,13 +118,13 @@ export class Scanner {
* @returns {Promise} Validator fee
*/
async getRequiredFee(operatorIds: number[]): Promise {
- const feeSum = await this.ssvNetworkViews.getNetworkFee()
+ let feeSum = await this.ssvViews.getNetworkFee()
for (const operatorId of operatorIds) {
- const operatorFee = await this.ssvNetworkViews.getOperatorFee(operatorId)
- feeSum.add(operatorFee)
+ const operatorFee = await this.ssvViews.getOperatorFee(operatorId)
+ feeSum = feeSum.add(operatorFee)
}
- const liquidationThresholdPeriod = await this.ssvNetworkViews.getLiquidationThresholdPeriod()
- return feeSum.mul(liquidationThresholdPeriod).mul(12)
+ const liquidationThresholdPeriod = await this.ssvViews.getLiquidationThresholdPeriod()
+ return feeSum.mul(liquidationThresholdPeriod).mul(6)
}
/**
@@ -130,13 +133,13 @@ export class Scanner {
* @returns {Promise} The owner's operators
*/
async getOperators(ownerAddress: string): Promise {
- const eventFilter = this.ssvNetwork.filters.OperatorAdded(null, ownerAddress)
+ const eventFilter = this.ssvOperators.filters.OperatorAdded(null, ownerAddress)
const operators: Operator[] = []
- const items = await this.ssvNetwork.queryFilter(eventFilter, 0, 'latest')
+ const items = await this.ssvOperators.queryFilter(eventFilter, 0, 'latest')
for (const item of items) {
const { args } = item
const { operatorId } = args
- const { fee, validatorCount, isPrivate } = await this.ssvNetworkViews.getOperatorById(operatorId)
+ const { fee, validatorCount, isPrivate } = await this.ssvViews.getOperatorById(operatorId)
operators.push({
id: operatorId.toNumber(),
fee,
diff --git a/common/types/src/index.ts b/common/types/src/index.ts
index 2d25eb285..7203d1bc1 100644
--- a/common/types/src/index.ts
+++ b/common/types/src/index.ts
@@ -30,6 +30,7 @@ import { TransactionRequest } from './interfaces/TransactionRequest'
import { RegisteredOperator } from './interfaces/RegisteredOperator'
import { RegisterOperatorWithCasimirParams } from './interfaces/RegisterOperatorWithCasimirParams'
import { RemoveAccountOptions } from './interfaces/RemoveAccountOptions'
+import { Reshare } from './interfaces/Reshare'
import { User } from './interfaces/User'
import { UserAddedSuccess } from './interfaces/UserAddedSuccess'
import { UserWithAccountsAndOperators } from './interfaces/UserWithAccountsAndOperators'
@@ -68,11 +69,12 @@ export type {
RegisteredOperator,
RegisterOperatorWithCasimirParams,
RemoveAccountOptions,
+ Reshare,
User,
UserAddedSuccess,
UserAnalyticsData,
UserWithAccountsAndOperators,
- Validator,
+ Validator
}
export {
diff --git a/common/types/src/interfaces/Reshare.ts b/common/types/src/interfaces/Reshare.ts
new file mode 100644
index 000000000..7d35bebbd
--- /dev/null
+++ b/common/types/src/interfaces/Reshare.ts
@@ -0,0 +1,7 @@
+export interface Reshare {
+ oldOperatorIds: number[]
+ operatorIds: number[]
+ poolId: number
+ publicKey: string
+ shares: string
+}
\ No newline at end of file
diff --git a/common/wallets/src/providers/ledger.ts b/common/wallets/src/providers/ledger.ts
index 0b480765e..5e558a79f 100644
--- a/common/wallets/src/providers/ledger.ts
+++ b/common/wallets/src/providers/ledger.ts
@@ -2,16 +2,12 @@ import { ethers } from 'ethers'
// import Btc from '@ledgerhq/hw-app-btc'
import Eth, { ledgerService } from '@ledgerhq/hw-app-eth'
import Transport from '@ledgerhq/hw-transport'
-import { TransportSpeculosHTTP } from '@casimir/speculos'
import TransportWebUSB from '@ledgerhq/hw-transport-webusb'
-import { CryptoAddress, TransactionRequest } from '@casimir/types'
+import { CryptoAddress } from '@casimir/types'
const transports = {
'usb': async function createUSBTransport(): Promise {
return await TransportWebUSB.create()
- },
- 'speculos': async function createSpeculosTransport(baseURL?: string): Promise {
- return await TransportSpeculosHTTP.open(baseURL)
}
}
@@ -126,7 +122,6 @@ export interface LedgerSignerOptions {
export class EthersLedgerSigner extends ethers.Signer {
readonly type: string = 'usb'
readonly path: string = 'm/44\'/60\'/0\'/0/0'
- readonly baseURL?: string
readonly eth?: Promise
constructor(options: LedgerSignerOptions) {
@@ -134,7 +129,6 @@ export class EthersLedgerSigner extends ethers.Signer {
if (options.type) this.type = options.type
if (options.path) this.path = options.path
- this.baseURL = options.baseURL
// Override readonly provider for ethers.Signer
if (options.provider) {
@@ -145,7 +139,7 @@ export class EthersLedgerSigner extends ethers.Signer {
const transportCreatorType = this.type as keyof typeof transports
const transportCreator = transports[transportCreatorType]
if (!transportCreator) console.log('Unknown or unsupported type', this.type)
- ethers.utils.defineReadOnly(this, 'eth', transportCreator(this.baseURL).then(transport => {
+ ethers.utils.defineReadOnly(this, 'eth', transportCreator().then(transport => {
return new Eth(transport)
}))
}
@@ -264,8 +258,7 @@ export class EthersLedgerSigner extends ethers.Signer {
const options = {
provider,
type: this.type,
- path: this.path,
- baseURL: this.baseURL
+ path: this.path
}
return new EthersLedgerSigner(options)
}
diff --git a/contracts/ethereum/.openzeppelin/goerli.json b/contracts/ethereum/.openzeppelin/goerli.json
new file mode 100644
index 000000000..7e8c81f02
--- /dev/null
+++ b/contracts/ethereum/.openzeppelin/goerli.json
@@ -0,0 +1,1385 @@
+{
+ "manifestVersion": "3.2",
+ "admin": {
+ "address": "0xb096F7EeeF63F8AAc293b307aF4012278bc5acB2",
+ "txHash": "0x789cb67a2cba8d2588e2fe3ec13affdba2445238579cb96751623d4c01fc00f1"
+ },
+ "proxies": [
+ {
+ "address": "0xFBA09a098014b414A4aBD2C1Ca43383Ad63f8492",
+ "txHash": "0x8eb5a1c0cb3ea4f76a5f14fae4b994a7f503245a3624eae4c06b74fb9b4ba18e",
+ "kind": "transparent"
+ },
+ {
+ "address": "0x1EcF11435187dCb07aA758Db006cA98EA381817b",
+ "txHash": "0xc760831b8c5af95183e5934919ed2b5139c11bda922091ee45d2b67ddf7940b9",
+ "kind": "transparent"
+ }
+ ],
+ "impls": {
+ "c811d22e19881061f0cc83b1549081d3b25644f16893670110d350a6670e7edb": {
+ "address": "0xeAfca9a5bBC9dAF315d9bcafD80616C5F7cd0f5e",
+ "txHash": "0x974bc4933792c0d982ea94ff9bcd432d7e6547c8f937a98e0627379cba634e29",
+ "layout": {
+ "solcVersion": "0.8.18",
+ "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": "_owner",
+ "offset": 0,
+ "slot": "51",
+ "type": "t_address",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "52",
+ "type": "t_array(t_uint256)49_storage",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94"
+ },
+ {
+ "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": "manager",
+ "offset": 0,
+ "slot": "151",
+ "type": "t_contract(ICasimirManager)19634",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:28"
+ },
+ {
+ "label": "registry",
+ "offset": 0,
+ "slot": "152",
+ "type": "t_contract(ICasimirRegistry)19835",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:30"
+ },
+ {
+ "label": "id",
+ "offset": 20,
+ "slot": "152",
+ "type": "t_uint32",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:32"
+ },
+ {
+ "label": "publicKey",
+ "offset": 0,
+ "slot": "153",
+ "type": "t_bytes_storage",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:34"
+ },
+ {
+ "label": "operatorIds",
+ "offset": 0,
+ "slot": "154",
+ "type": "t_array(t_uint64)dyn_storage",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:36"
+ },
+ {
+ "label": "reshares",
+ "offset": 0,
+ "slot": "155",
+ "type": "t_uint256",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:38"
+ },
+ {
+ "label": "status",
+ "offset": 0,
+ "slot": "156",
+ "type": "t_enum(PoolStatus)19642",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:40"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "157",
+ "type": "t_array(t_uint256)50_storage",
+ "contract": "CasimirPool",
+ "src": "src/v1/CasimirPool.sol:42"
+ }
+ ],
+ "types": {
+ "t_address": {
+ "label": "address",
+ "numberOfBytes": "20"
+ },
+ "t_array(t_uint256)49_storage": {
+ "label": "uint256[49]",
+ "numberOfBytes": "1568"
+ },
+ "t_array(t_uint256)50_storage": {
+ "label": "uint256[50]",
+ "numberOfBytes": "1600"
+ },
+ "t_array(t_uint64)dyn_storage": {
+ "label": "uint64[]",
+ "numberOfBytes": "32"
+ },
+ "t_bool": {
+ "label": "bool",
+ "numberOfBytes": "1"
+ },
+ "t_bytes_storage": {
+ "label": "bytes",
+ "numberOfBytes": "32"
+ },
+ "t_contract(ICasimirManager)19634": {
+ "label": "contract ICasimirManager",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ICasimirRegistry)19835": {
+ "label": "contract ICasimirRegistry",
+ "numberOfBytes": "20"
+ },
+ "t_enum(PoolStatus)19642": {
+ "label": "enum ICasimirPool.PoolStatus",
+ "members": [
+ "PENDING",
+ "ACTIVE",
+ "EXITING_FORCED",
+ "EXITING_REQUESTED",
+ "WITHDRAWN"
+ ],
+ "numberOfBytes": "1"
+ },
+ "t_uint256": {
+ "label": "uint256",
+ "numberOfBytes": "32"
+ },
+ "t_uint32": {
+ "label": "uint32",
+ "numberOfBytes": "4"
+ },
+ "t_uint64": {
+ "label": "uint64",
+ "numberOfBytes": "8"
+ },
+ "t_uint8": {
+ "label": "uint8",
+ "numberOfBytes": "1"
+ }
+ }
+ }
+ },
+ "48fb36af6728915c6ff46916fb78b9c20cb51d6d2d1d78a23b4a80659b556577": {
+ "address": "0x47299bda4B85E32815feF94F1d48b22ACAfC712D",
+ "txHash": "0x1de6a663ddcbe3bd8745315665abaf08aca87bc8317d1a53b343952d8376cdeb",
+ "layout": {
+ "solcVersion": "0.8.18",
+ "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": "_owner",
+ "offset": 0,
+ "slot": "51",
+ "type": "t_address",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "52",
+ "type": "t_array(t_uint256)49_storage",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94"
+ },
+ {
+ "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": "manager",
+ "offset": 0,
+ "slot": "151",
+ "type": "t_contract(ICasimirManager)19634",
+ "contract": "CasimirRegistry",
+ "src": "src/v1/CasimirRegistry.sol:27"
+ },
+ {
+ "label": "ssvViews",
+ "offset": 0,
+ "slot": "152",
+ "type": "t_contract(ISSVViews)13867",
+ "contract": "CasimirRegistry",
+ "src": "src/v1/CasimirRegistry.sol:29"
+ },
+ {
+ "label": "operatorIds",
+ "offset": 0,
+ "slot": "153",
+ "type": "t_array(t_uint64)dyn_storage",
+ "contract": "CasimirRegistry",
+ "src": "src/v1/CasimirRegistry.sol:31"
+ },
+ {
+ "label": "operators",
+ "offset": 0,
+ "slot": "154",
+ "type": "t_mapping(t_uint64,t_struct(Operator)19724_storage)",
+ "contract": "CasimirRegistry",
+ "src": "src/v1/CasimirRegistry.sol:33"
+ },
+ {
+ "label": "operatorPools",
+ "offset": 0,
+ "slot": "155",
+ "type": "t_mapping(t_uint64,t_mapping(t_uint32,t_bool))",
+ "contract": "CasimirRegistry",
+ "src": "src/v1/CasimirRegistry.sol:35"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "156",
+ "type": "t_array(t_uint256)50_storage",
+ "contract": "CasimirRegistry",
+ "src": "src/v1/CasimirRegistry.sol:37"
+ }
+ ],
+ "types": {
+ "t_address": {
+ "label": "address",
+ "numberOfBytes": "20"
+ },
+ "t_array(t_uint256)49_storage": {
+ "label": "uint256[49]",
+ "numberOfBytes": "1568"
+ },
+ "t_array(t_uint256)50_storage": {
+ "label": "uint256[50]",
+ "numberOfBytes": "1600"
+ },
+ "t_array(t_uint64)dyn_storage": {
+ "label": "uint64[]",
+ "numberOfBytes": "32"
+ },
+ "t_bool": {
+ "label": "bool",
+ "numberOfBytes": "1"
+ },
+ "t_contract(ICasimirManager)19634": {
+ "label": "contract ICasimirManager",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ISSVViews)13867": {
+ "label": "contract ISSVViews",
+ "numberOfBytes": "20"
+ },
+ "t_mapping(t_uint32,t_bool)": {
+ "label": "mapping(uint32 => bool)",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_uint64,t_mapping(t_uint32,t_bool))": {
+ "label": "mapping(uint64 => mapping(uint32 => bool))",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_uint64,t_struct(Operator)19724_storage)": {
+ "label": "mapping(uint64 => struct ICasimirRegistry.Operator)",
+ "numberOfBytes": "32"
+ },
+ "t_struct(Operator)19724_storage": {
+ "label": "struct ICasimirRegistry.Operator",
+ "members": [
+ {
+ "label": "id",
+ "type": "t_uint64",
+ "offset": 0,
+ "slot": "0"
+ },
+ {
+ "label": "active",
+ "type": "t_bool",
+ "offset": 8,
+ "slot": "0"
+ },
+ {
+ "label": "resharing",
+ "type": "t_bool",
+ "offset": 9,
+ "slot": "0"
+ },
+ {
+ "label": "collateral",
+ "type": "t_uint256",
+ "offset": 0,
+ "slot": "1"
+ },
+ {
+ "label": "poolCount",
+ "type": "t_uint256",
+ "offset": 0,
+ "slot": "2"
+ }
+ ],
+ "numberOfBytes": "96"
+ },
+ "t_uint256": {
+ "label": "uint256",
+ "numberOfBytes": "32"
+ },
+ "t_uint32": {
+ "label": "uint32",
+ "numberOfBytes": "4"
+ },
+ "t_uint64": {
+ "label": "uint64",
+ "numberOfBytes": "8"
+ },
+ "t_uint8": {
+ "label": "uint8",
+ "numberOfBytes": "1"
+ }
+ }
+ }
+ },
+ "387810c1df4e2578e73fd29da257e5092ae70e0a4ed20d8616d280506e85a7ae": {
+ "address": "0x873A00b4CB0660121e9C897c8eb593fa6Dd7Ffef",
+ "txHash": "0x0bb97a1f3c4898812dbe9c266290fb06d2ef37bacb80bbd37753063f4315b40a",
+ "layout": {
+ "solcVersion": "0.8.18",
+ "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": "_owner",
+ "offset": 0,
+ "slot": "51",
+ "type": "t_address",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "52",
+ "type": "t_array(t_uint256)49_storage",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94"
+ },
+ {
+ "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": "s_oracle",
+ "offset": 0,
+ "slot": "151",
+ "type": "t_contract(FunctionsOracleInterface)4175",
+ "contract": "FunctionsClient",
+ "src": "src/v1/vendor/FunctionsClient.sol:13"
+ },
+ {
+ "label": "s_pendingRequests",
+ "offset": 0,
+ "slot": "152",
+ "type": "t_mapping(t_bytes32,t_address)",
+ "contract": "FunctionsClient",
+ "src": "src/v1/vendor/FunctionsClient.sol:14"
+ },
+ {
+ "label": "manager",
+ "offset": 0,
+ "slot": "153",
+ "type": "t_contract(ICasimirManager)19634",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:36"
+ },
+ {
+ "label": "previousReportTimestamp",
+ "offset": 0,
+ "slot": "154",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:38"
+ },
+ {
+ "label": "reportStatus",
+ "offset": 0,
+ "slot": "155",
+ "type": "t_enum(ReportStatus)19848",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:40"
+ },
+ {
+ "label": "reportPeriod",
+ "offset": 1,
+ "slot": "155",
+ "type": "t_uint32",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:42"
+ },
+ {
+ "label": "reportRemainingRequests",
+ "offset": 0,
+ "slot": "156",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:44"
+ },
+ {
+ "label": "reportRequestBlock",
+ "offset": 0,
+ "slot": "157",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:46"
+ },
+ {
+ "label": "reportTimestamp",
+ "offset": 0,
+ "slot": "158",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:48"
+ },
+ {
+ "label": "reportSweptBalance",
+ "offset": 0,
+ "slot": "159",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:50"
+ },
+ {
+ "label": "reportBeaconBalance",
+ "offset": 0,
+ "slot": "160",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:52"
+ },
+ {
+ "label": "reportActivatedDeposits",
+ "offset": 0,
+ "slot": "161",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:54"
+ },
+ {
+ "label": "reportForcedExits",
+ "offset": 0,
+ "slot": "162",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:56"
+ },
+ {
+ "label": "reportCompletedExits",
+ "offset": 0,
+ "slot": "163",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:58"
+ },
+ {
+ "label": "reportCompoundablePoolIds",
+ "offset": 0,
+ "slot": "164",
+ "type": "t_array(t_uint32)5_storage",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:60"
+ },
+ {
+ "label": "finalizableActivatedDeposits",
+ "offset": 0,
+ "slot": "165",
+ "type": "t_uint256",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:62"
+ },
+ {
+ "label": "finalizableCompoundablePoolIds",
+ "offset": 0,
+ "slot": "166",
+ "type": "t_array(t_uint32)5_storage",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:64"
+ },
+ {
+ "label": "reportRequests",
+ "offset": 0,
+ "slot": "167",
+ "type": "t_mapping(t_bytes32,t_enum(RequestType)19844)",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:66"
+ },
+ {
+ "label": "reportResponseError",
+ "offset": 0,
+ "slot": "168",
+ "type": "t_bytes_storage",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:68"
+ },
+ {
+ "label": "requestSource",
+ "offset": 0,
+ "slot": "169",
+ "type": "t_string_storage",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:70"
+ },
+ {
+ "label": "defaultRequestArgs",
+ "offset": 0,
+ "slot": "170",
+ "type": "t_array(t_string_storage)dyn_storage",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:72"
+ },
+ {
+ "label": "fulfillGasLimit",
+ "offset": 0,
+ "slot": "171",
+ "type": "t_uint32",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:74"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "172",
+ "type": "t_array(t_uint256)50_storage",
+ "contract": "CasimirUpkeep",
+ "src": "src/v1/CasimirUpkeep.sol:76"
+ }
+ ],
+ "types": {
+ "t_address": {
+ "label": "address",
+ "numberOfBytes": "20"
+ },
+ "t_array(t_string_storage)dyn_storage": {
+ "label": "string[]",
+ "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_array(t_uint32)5_storage": {
+ "label": "uint32[5]",
+ "numberOfBytes": "32"
+ },
+ "t_bool": {
+ "label": "bool",
+ "numberOfBytes": "1"
+ },
+ "t_bytes32": {
+ "label": "bytes32",
+ "numberOfBytes": "32"
+ },
+ "t_bytes_storage": {
+ "label": "bytes",
+ "numberOfBytes": "32"
+ },
+ "t_contract(FunctionsOracleInterface)4175": {
+ "label": "contract FunctionsOracleInterface",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ICasimirManager)19634": {
+ "label": "contract ICasimirManager",
+ "numberOfBytes": "20"
+ },
+ "t_enum(ReportStatus)19848": {
+ "label": "enum ICasimirUpkeep.ReportStatus",
+ "members": [
+ "FINALIZED",
+ "REQUESTING",
+ "PROCESSING"
+ ],
+ "numberOfBytes": "1"
+ },
+ "t_enum(RequestType)19844": {
+ "label": "enum ICasimirUpkeep.RequestType",
+ "members": [
+ "NONE",
+ "BALANCES",
+ "DETAILS"
+ ],
+ "numberOfBytes": "1"
+ },
+ "t_mapping(t_bytes32,t_address)": {
+ "label": "mapping(bytes32 => address)",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_bytes32,t_enum(RequestType)19844)": {
+ "label": "mapping(bytes32 => enum ICasimirUpkeep.RequestType)",
+ "numberOfBytes": "32"
+ },
+ "t_string_storage": {
+ "label": "string",
+ "numberOfBytes": "32"
+ },
+ "t_uint256": {
+ "label": "uint256",
+ "numberOfBytes": "32"
+ },
+ "t_uint32": {
+ "label": "uint32",
+ "numberOfBytes": "4"
+ },
+ "t_uint8": {
+ "label": "uint8",
+ "numberOfBytes": "1"
+ }
+ }
+ }
+ },
+ "a783290b088783c30d2f7cb7873ee3469b7ffd7c3051961b6e8467a9aff82460": {
+ "address": "0x253Da121b59d5e732d3C657AE19298B4661D710b",
+ "txHash": "0x377be403e96e24c413ee75ac36d5575a22e6472bcecbfe6f4a398b79135e635e",
+ "layout": {
+ "solcVersion": "0.8.18",
+ "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": "_owner",
+ "offset": 0,
+ "slot": "51",
+ "type": "t_address",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:22"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "52",
+ "type": "t_array(t_uint256)49_storage",
+ "contract": "OwnableUpgradeable",
+ "src": "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol:94"
+ },
+ {
+ "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": "oracleAddress",
+ "offset": 0,
+ "slot": "151",
+ "type": "t_address",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:65"
+ },
+ {
+ "label": "registry",
+ "offset": 0,
+ "slot": "152",
+ "type": "t_contract(ICasimirRegistry)19835",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:67"
+ },
+ {
+ "label": "upkeep",
+ "offset": 0,
+ "slot": "153",
+ "type": "t_contract(ICasimirUpkeep)19910",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:69"
+ },
+ {
+ "label": "beaconDeposit",
+ "offset": 0,
+ "slot": "154",
+ "type": "t_contract(IDepositContract)20614",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:71"
+ },
+ {
+ "label": "functionsBillingRegistry",
+ "offset": 0,
+ "slot": "155",
+ "type": "t_contract(IFunctionsBillingRegistry)20648",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:73"
+ },
+ {
+ "label": "keeperRegistrar",
+ "offset": 0,
+ "slot": "156",
+ "type": "t_contract(IKeeperRegistrar)20676",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:75"
+ },
+ {
+ "label": "keeperRegistry",
+ "offset": 0,
+ "slot": "157",
+ "type": "t_contract(IAutomationRegistry)20574",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:77"
+ },
+ {
+ "label": "linkToken",
+ "offset": 0,
+ "slot": "158",
+ "type": "t_contract(LinkTokenInterface)7709",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:79"
+ },
+ {
+ "label": "poolBeacon",
+ "offset": 0,
+ "slot": "159",
+ "type": "t_contract(IBeaconUpgradeable)8844",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:81"
+ },
+ {
+ "label": "ssvClusters",
+ "offset": 0,
+ "slot": "160",
+ "type": "t_contract(ISSVClusters)13288",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:83"
+ },
+ {
+ "label": "ssvToken",
+ "offset": 0,
+ "slot": "161",
+ "type": "t_contract(IERC20Upgradeable)9175",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:85"
+ },
+ {
+ "label": "swapFactory",
+ "offset": 0,
+ "slot": "162",
+ "type": "t_contract(IUniswapV3Factory)12910",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:87"
+ },
+ {
+ "label": "swapRouter",
+ "offset": 0,
+ "slot": "163",
+ "type": "t_contract(ISwapRouter)13132",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:89"
+ },
+ {
+ "label": "lastPoolId",
+ "offset": 20,
+ "slot": "163",
+ "type": "t_uint32",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:91"
+ },
+ {
+ "label": "reportPeriod",
+ "offset": 24,
+ "slot": "163",
+ "type": "t_uint32",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:93"
+ },
+ {
+ "label": "functionsId",
+ "offset": 0,
+ "slot": "164",
+ "type": "t_uint64",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:95"
+ },
+ {
+ "label": "upkeepId",
+ "offset": 0,
+ "slot": "165",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:97"
+ },
+ {
+ "label": "latestBeaconBalance",
+ "offset": 0,
+ "slot": "166",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:99"
+ },
+ {
+ "label": "latestBeaconBalanceAfterFees",
+ "offset": 0,
+ "slot": "167",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:101"
+ },
+ {
+ "label": "latestActiveRewardBalance",
+ "offset": 0,
+ "slot": "168",
+ "type": "t_int256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:103"
+ },
+ {
+ "label": "finalizableCompletedExits",
+ "offset": 0,
+ "slot": "169",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:105"
+ },
+ {
+ "label": "finalizableExitedBalance",
+ "offset": 0,
+ "slot": "170",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:107"
+ },
+ {
+ "label": "finalizableRecoveredBalance",
+ "offset": 0,
+ "slot": "171",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:109"
+ },
+ {
+ "label": "tokenAddresses",
+ "offset": 0,
+ "slot": "172",
+ "type": "t_mapping(t_enum(Token)19142,t_address)",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:111"
+ },
+ {
+ "label": "users",
+ "offset": 0,
+ "slot": "173",
+ "type": "t_mapping(t_address,t_struct(User)19147_storage)",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:113"
+ },
+ {
+ "label": "stakeRatioSum",
+ "offset": 0,
+ "slot": "174",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:115"
+ },
+ {
+ "label": "requestedWithdrawals",
+ "offset": 0,
+ "slot": "175",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:117"
+ },
+ {
+ "label": "requestedWithdrawalBalance",
+ "offset": 0,
+ "slot": "176",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:119"
+ },
+ {
+ "label": "requestedWithdrawalQueue",
+ "offset": 0,
+ "slot": "177",
+ "type": "t_array(t_struct(Withdrawal)19154_storage)dyn_storage",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:121"
+ },
+ {
+ "label": "poolAddresses",
+ "offset": 0,
+ "slot": "178",
+ "type": "t_mapping(t_uint32,t_address)",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:123"
+ },
+ {
+ "label": "tipBalance",
+ "offset": 0,
+ "slot": "179",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:125"
+ },
+ {
+ "label": "recoveredBalances",
+ "offset": 0,
+ "slot": "180",
+ "type": "t_mapping(t_uint32,t_uint256)",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:127"
+ },
+ {
+ "label": "prepoolBalance",
+ "offset": 0,
+ "slot": "181",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:129"
+ },
+ {
+ "label": "exitedBalance",
+ "offset": 0,
+ "slot": "182",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:131"
+ },
+ {
+ "label": "reservedFeeBalance",
+ "offset": 0,
+ "slot": "183",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:133"
+ },
+ {
+ "label": "readyPoolIds",
+ "offset": 0,
+ "slot": "184",
+ "type": "t_array(t_uint32)dyn_storage",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:135"
+ },
+ {
+ "label": "pendingPoolIds",
+ "offset": 0,
+ "slot": "185",
+ "type": "t_array(t_uint32)dyn_storage",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:137"
+ },
+ {
+ "label": "stakedPoolIds",
+ "offset": 0,
+ "slot": "186",
+ "type": "t_array(t_uint32)dyn_storage",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:139"
+ },
+ {
+ "label": "requestedExits",
+ "offset": 0,
+ "slot": "187",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:141"
+ },
+ {
+ "label": "forcedExits",
+ "offset": 0,
+ "slot": "188",
+ "type": "t_uint256",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:143"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "189",
+ "type": "t_array(t_uint256)50_storage",
+ "contract": "CasimirManager",
+ "src": "src/v1/CasimirManager.sol:145"
+ }
+ ],
+ "types": {
+ "t_address": {
+ "label": "address",
+ "numberOfBytes": "20"
+ },
+ "t_array(t_struct(Withdrawal)19154_storage)dyn_storage": {
+ "label": "struct ICasimirManager.Withdrawal[]",
+ "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_array(t_uint32)dyn_storage": {
+ "label": "uint32[]",
+ "numberOfBytes": "32"
+ },
+ "t_bool": {
+ "label": "bool",
+ "numberOfBytes": "1"
+ },
+ "t_contract(IAutomationRegistry)20574": {
+ "label": "contract IAutomationRegistry",
+ "numberOfBytes": "20"
+ },
+ "t_contract(IBeaconUpgradeable)8844": {
+ "label": "contract IBeaconUpgradeable",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ICasimirRegistry)19835": {
+ "label": "contract ICasimirRegistry",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ICasimirUpkeep)19910": {
+ "label": "contract ICasimirUpkeep",
+ "numberOfBytes": "20"
+ },
+ "t_contract(IDepositContract)20614": {
+ "label": "contract IDepositContract",
+ "numberOfBytes": "20"
+ },
+ "t_contract(IERC20Upgradeable)9175": {
+ "label": "contract IERC20Upgradeable",
+ "numberOfBytes": "20"
+ },
+ "t_contract(IFunctionsBillingRegistry)20648": {
+ "label": "contract IFunctionsBillingRegistry",
+ "numberOfBytes": "20"
+ },
+ "t_contract(IKeeperRegistrar)20676": {
+ "label": "contract IKeeperRegistrar",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ISSVClusters)13288": {
+ "label": "contract ISSVClusters",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ISwapRouter)13132": {
+ "label": "contract ISwapRouter",
+ "numberOfBytes": "20"
+ },
+ "t_contract(IUniswapV3Factory)12910": {
+ "label": "contract IUniswapV3Factory",
+ "numberOfBytes": "20"
+ },
+ "t_contract(LinkTokenInterface)7709": {
+ "label": "contract LinkTokenInterface",
+ "numberOfBytes": "20"
+ },
+ "t_enum(Token)19142": {
+ "label": "enum ICasimirManager.Token",
+ "members": [
+ "LINK",
+ "SSV",
+ "WETH"
+ ],
+ "numberOfBytes": "1"
+ },
+ "t_int256": {
+ "label": "int256",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_address,t_struct(User)19147_storage)": {
+ "label": "mapping(address => struct ICasimirManager.User)",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_enum(Token)19142,t_address)": {
+ "label": "mapping(enum ICasimirManager.Token => address)",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_uint32,t_address)": {
+ "label": "mapping(uint32 => address)",
+ "numberOfBytes": "32"
+ },
+ "t_mapping(t_uint32,t_uint256)": {
+ "label": "mapping(uint32 => uint256)",
+ "numberOfBytes": "32"
+ },
+ "t_struct(User)19147_storage": {
+ "label": "struct ICasimirManager.User",
+ "members": [
+ {
+ "label": "stake0",
+ "type": "t_uint256",
+ "offset": 0,
+ "slot": "0"
+ },
+ {
+ "label": "stakeRatioSum0",
+ "type": "t_uint256",
+ "offset": 0,
+ "slot": "1"
+ }
+ ],
+ "numberOfBytes": "64"
+ },
+ "t_struct(Withdrawal)19154_storage": {
+ "label": "struct ICasimirManager.Withdrawal",
+ "members": [
+ {
+ "label": "user",
+ "type": "t_address",
+ "offset": 0,
+ "slot": "0"
+ },
+ {
+ "label": "amount",
+ "type": "t_uint256",
+ "offset": 0,
+ "slot": "1"
+ },
+ {
+ "label": "period",
+ "type": "t_uint256",
+ "offset": 0,
+ "slot": "2"
+ }
+ ],
+ "numberOfBytes": "96"
+ },
+ "t_uint256": {
+ "label": "uint256",
+ "numberOfBytes": "32"
+ },
+ "t_uint32": {
+ "label": "uint32",
+ "numberOfBytes": "4"
+ },
+ "t_uint64": {
+ "label": "uint64",
+ "numberOfBytes": "8"
+ },
+ "t_uint8": {
+ "label": "uint8",
+ "numberOfBytes": "1"
+ }
+ }
+ }
+ },
+ "34d2bfbc567f7989d553dd41f6a9c076423df7a32dc9dcc27daf311d99411693": {
+ "address": "0x81193D14a78ee889D75D6a921a2146e224388400",
+ "txHash": "0x64f417fcb2aaea01905d17f9a0928c41c58563abc6aa6e0f33c1365ed03903a2",
+ "layout": {
+ "solcVersion": "0.8.18",
+ "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": "manager",
+ "offset": 2,
+ "slot": "0",
+ "type": "t_contract(ICasimirManager)19634",
+ "contract": "CasimirViews",
+ "src": "src/v1/CasimirViews.sol:26"
+ },
+ {
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "t_contract(ICasimirRegistry)19835",
+ "contract": "CasimirViews",
+ "src": "src/v1/CasimirViews.sol:28"
+ },
+ {
+ "label": "__gap",
+ "offset": 0,
+ "slot": "2",
+ "type": "t_array(t_uint256)50_storage",
+ "contract": "CasimirViews",
+ "src": "src/v1/CasimirViews.sol:30"
+ }
+ ],
+ "types": {
+ "t_array(t_uint256)50_storage": {
+ "label": "uint256[50]",
+ "numberOfBytes": "1600"
+ },
+ "t_bool": {
+ "label": "bool",
+ "numberOfBytes": "1"
+ },
+ "t_contract(ICasimirManager)19634": {
+ "label": "contract ICasimirManager",
+ "numberOfBytes": "20"
+ },
+ "t_contract(ICasimirRegistry)19835": {
+ "label": "contract ICasimirRegistry",
+ "numberOfBytes": "20"
+ },
+ "t_uint256": {
+ "label": "uint256",
+ "numberOfBytes": "32"
+ },
+ "t_uint8": {
+ "label": "uint8",
+ "numberOfBytes": "1"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/contracts/ethereum/README.md b/contracts/ethereum/README.md
index 83642db3f..f37ff9bbb 100644
--- a/contracts/ethereum/README.md
+++ b/contracts/ethereum/README.md
@@ -125,17 +125,17 @@ Vendor contracts and interfaces are located in the [src/v1/vendor](./src/v1/vend
| Contract | Description |
| --- | --- |
-| AutomationRegistry | Subscribes and funds upkeeps |
+| AutomationRegistry | Provides upkeep funding operators |
| DepositContract | Accepts Beacon deposits |
| ERC20 | Standardizes tokens |
| FunctionsClient | Calls Chainlink Functions |
-| KeeperRegistrar | Allows upkeep subscription registration |
+| KeeperRegistrar | Provides upkeep registration |
| Math | Provides math helpers |
| Ownable | Provides ownable access control |
| ReentrancyGuard | Secures against reentrancy |
| SSVNetwork | Registers SSV validators |
| SSVNetworkCore | Provides base SSV logic and types |
-| SSVNetworkViews | Provides read-only access to SSV network state |
+| SSVViews | Provides read-only access to SSV network state |
| SwapRouter | Routes token swaps |
| UniswapV3Factory | Provides access to Uniswap V3 pools |
| UniswapV3PoolState | Provides access to Uniswap V3 pool state |
@@ -157,7 +157,7 @@ Casimir distributes validator key shares to operators using SSV nodes with [Rock
## Oracles
-The contract uses two oracles to automate the Casimir staking experience and ensure the security of user funds. The [Casimir Beacon oracle](https://github.com/consensusnetworks/casimir/blob/master/services/functions) and the upkeep contract report total validator balance, swept balance, and validator actions once per day using [Chainlink Functions](https://docs.chain.link/chainlink-functions) and [Chainlink Automation](https://docs.chain.link/chainlink-automation/introduction). The [Casimir DAO oracle](https://github.com/consensusnetworks/casimir/blob/master/services/oracle) watches the manager contract events and automatically executes zero-coordination distributed key generation (DKG) operations: validator creation, validator resharing, and validator exiting. The DAO oracle also submits verifiable report details in response to reported validator actions (such as an SSV cluster and operator blame amounts for a completed validator exit).
+The contract uses two oracles to automate the Casimir staking experience and ensure the security of user funds. The automated upkeep contract reports total validator balance, swept balance, and validator actions once per day using [Chainlink Functions](https://docs.chain.link/chainlink-functions) and [Chainlink Automation](https://docs.chain.link/chainlink-automation/introduction). The [@chainlink/functions service](https://github.com/consensusnetworks/casimir/blob/master/services/functions) is used for two request types per report period, balances and details, to overcome the current Chainlink DON constraints. The [Casimir DAO oracle](https://github.com/consensusnetworks/casimir/blob/master/services/oracle) watches the manager contract events and automatically executes zero-coordination distributed key generation (DKG) operations: validator creation, validator resharing, and validator exiting. The DAO oracle also submits verifiable report details in response to reported validator details (such as one or more new exited validators).
## Users
diff --git a/contracts/ethereum/foundry.toml b/contracts/ethereum/foundry.toml
index 0c978f267..04a6b7a58 100644
--- a/contracts/ethereum/foundry.toml
+++ b/contracts/ethereum/foundry.toml
@@ -1,7 +1,7 @@
[profile.default]
src = 'src/v1'
out = 'build/foundry'
-libs = ['node_modules']
+libs = ['lib', 'node_modules']
test = 'test'
cache_path = 'build/foundry/cache'
diff --git a/contracts/ethereum/hardhat.config.ts b/contracts/ethereum/hardhat.config.ts
index 97ef8f23d..e19564910 100644
--- a/contracts/ethereum/hardhat.config.ts
+++ b/contracts/ethereum/hardhat.config.ts
@@ -1,15 +1,18 @@
-import localtunnel from 'localtunnel'
+import fs from 'fs'
import os from 'os'
+import localtunnel from 'localtunnel'
import { HardhatUserConfig } from 'hardhat/types'
-import '@nomicfoundation/hardhat-foundry'
import '@typechain/hardhat'
import '@nomiclabs/hardhat-ethers'
import '@nomicfoundation/hardhat-toolbox'
+import '@openzeppelin/hardhat-upgrades'
import 'hardhat-abi-exporter'
+import 'hardhat-preprocessor'
+import { ETHEREUM_CONTRACTS } from '@casimir/env'
// Seed is provided
const mnemonic = process.env.BIP39_SEED as string
-const hid = { mnemonic, count: 10, accountsBalance: '1000000000000000000000' }
+const hid = { mnemonic, count: 10 }
// Mining interval is provided in seconds
const miningInterval = parseInt(process.env.MINING_INTERVAL as string)
@@ -27,36 +30,42 @@ const forkConfig = { url: forkUrl, blockNumber: parseInt(process.env.ETHEREUM_FO
const externalEnv = {
mainnet: {
- DAO_ORACLE_ADDRESS: '',
BEACON_DEPOSIT_ADDRESS: '0x00000000219ab540356cBB839Cbe05303d7705Fa',
+ DAO_ORACLE_ADDRESS: '',
FUNCTIONS_BILLING_REGISTRY_ADDRESS: '',
FUNCTIONS_ORACLE_ADDRESS: '',
+ KEEPER_REGISTRAR_ADDRESS: ' 0xDb8e8e2ccb5C033938736aa89Fe4fa1eDfD15a1d',
+ KEEPER_REGISTRY_ADDRESS: '0x02777053d6764996e594c3E88AF1D58D5363a2e6',
LINK_ETH_FEED_ADDRESS: '0xDC530D9457755926550b59e8ECcdaE7624181557',
- LINK_REGISTRAR_ADDRESS: ' 0xDb8e8e2ccb5C033938736aa89Fe4fa1eDfD15a1d',
- LINK_REGISTRY_ADDRESS: '0x02777053d6764996e594c3E88AF1D58D5363a2e6',
LINK_TOKEN_ADDRESS: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
+ POOL_BEACON_ADDRESS: '',
+ REGISTRY_BEACON_ADDRESS: '',
SSV_NETWORK_ADDRESS: '',
- SSV_NETWORK_VIEWS_ADDRESS: '',
SSV_TOKEN_ADDRESS: '0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54',
+ SSV_VIEWS_ADDRESS: '',
SWAP_FACTORY_ADDRESS: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
SWAP_ROUTER_ADDRESS: '0xE592427A0AEce92De3Edee1F18E0157C05861564',
+ UPKEEP_BEACON_ADDRESS: '',
WETH_TOKEN_ADDRESS: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
},
goerli: {
+ BEACON_DEPOSIT_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.BEACON_DEPOSIT_ADDRESS,
DAO_ORACLE_ADDRESS: '',
- BEACON_DEPOSIT_ADDRESS: '0x07b39F4fDE4A38bACe212b546dAc87C58DfE3fDC',
FUNCTIONS_BILLING_REGISTRY_ADDRESS: '',
FUNCTIONS_ORACLE_ADDRESS: '',
- LINK_ETH_FEED_ADDRESS: '0xb4c4a493AB6356497713A78FFA6c60FB53517c63',
- LINK_REGISTRAR_ADDRESS: '0x57A4a13b35d25EE78e084168aBaC5ad360252467',
- LINK_REGISTRY_ADDRESS: '0xE16Df59B887e3Caa439E0b29B42bA2e7976FD8b2',
- LINK_TOKEN_ADDRESS: '0x326C977E6efc84E512bB9C30f76E30c160eD06FB',
- SSV_NETWORK_ADDRESS: '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3',
- SSV_NETWORK_VIEWS_ADDRESS: '0x8dB45282d7C4559fd093C26f677B3837a5598914',
- SSV_TOKEN_ADDRESS: '0x3a9f01091C446bdE031E39ea8354647AFef091E7',
- SWAP_FACTORY_ADDRESS: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
- SWAP_ROUTER_ADDRESS: '0xE592427A0AEce92De3Edee1F18E0157C05861564',
- WETH_TOKEN_ADDRESS: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'
+ KEEPER_REGISTRAR_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.KEEPER_REGISTRAR_ADDRESS,
+ KEEPER_REGISTRY_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.KEEPER_REGISTRY_ADDRESS,
+ LINK_ETH_FEED_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.LINK_ETH_FEED_ADDRESS,
+ LINK_TOKEN_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.LINK_TOKEN_ADDRESS,
+ POOL_BEACON_ADDRESS: '',
+ REGISTRY_BEACON_ADDRESS: '',
+ SSV_NETWORK_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.SSV_NETWORK_ADDRESS,
+ SSV_TOKEN_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.SSV_TOKEN_ADDRESS,
+ SSV_VIEWS_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.SSV_VIEWS_ADDRESS,
+ SWAP_FACTORY_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.SWAP_FACTORY_ADDRESS,
+ SWAP_ROUTER_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.SWAP_ROUTER_ADDRESS,
+ UPKEEP_BEACON_ADDRESS: '',
+ WETH_TOKEN_ADDRESS: ETHEREUM_CONTRACTS.TESTNET.WETH_TOKEN_ADDRESS
}
}
@@ -86,6 +95,24 @@ const compilers = [...compilerVersions, ...externalCompilerVersions].map(version
// Go to https://hardhat.org/config/ to learn more
const config: HardhatUserConfig = {
+ mocha: {
+ timeout: 60000
+ },
+ preprocess: {
+ eachLine: () => ({
+ transform: (line: string) => {
+ if (line.match(/^\s*import /i)) {
+ for (const [from, to] of getRemappings()) {
+ if (line.includes(from)) {
+ line = line.replace(from, to)
+ break
+ }
+ }
+ }
+ return line
+ }
+ })
+ },
solidity: {
compilers,
},
@@ -135,6 +162,18 @@ const config: HardhatUserConfig = {
// Start a local tunnel for using RPC over https (e.g. for Metamask on mobile)
if (process.env.TUNNEL === 'true') {
+ runLocalTunnel()
+}
+
+function getRemappings() {
+ return fs
+ .readFileSync('remappings.txt', 'utf8')
+ .split('\n')
+ .filter(Boolean) // remove empty lines
+ .map((line) => line.trim().split('='))
+}
+
+function runLocalTunnel() {
const localSubdomain = `local-hardhat-${os.userInfo().username.toLowerCase()}`
const localUrl = `https://${localSubdomain}.loca.lt`
localtunnel({ port: 8545, subdomain: localSubdomain }).then(
diff --git a/contracts/ethereum/helpers/oracle.ts b/contracts/ethereum/helpers/oracle.ts
index c87e16b06..6cacb38e0 100644
--- a/contracts/ethereum/helpers/oracle.ts
+++ b/contracts/ethereum/helpers/oracle.ts
@@ -1,21 +1,20 @@
import { ethers } from 'hardhat'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { CasimirManager, CasimirViews } from '../build/@types'
-import { PoolStatus, Validator } from '@casimir/types'
+import { PoolStatus, Reshare, Validator } from '@casimir/types'
import { Scanner } from '@casimir/ssv'
-import { getWithdrawalCredentials } from '@casimir/helpers'
import { Factory } from '@casimir/uniswap'
-import { validatorStore } from '@casimir/data'
+import { validatorStore, reshareStore } from '@casimir/data'
const linkTokenAddress = process.env.LINK_TOKEN_ADDRESS as string
if (!linkTokenAddress) throw new Error('No link token address provided')
const ssvNetworkAddress = process.env.SSV_NETWORK_ADDRESS as string
if (!ssvNetworkAddress) throw new Error('No ssv network address provided')
-const ssvNetworkViewsAddress = process.env.SSV_NETWORK_VIEWS_ADDRESS as string
-if (!ssvNetworkViewsAddress) throw new Error('No ssv network views address provided')
+const ssvViewsAddress = process.env.SSV_VIEWS_ADDRESS as string
+if (!ssvViewsAddress) throw new Error('No ssv views address provided')
const ssvTokenAddress = process.env.SSV_TOKEN_ADDRESS as string
if (!ssvTokenAddress) throw new Error('No ssv token address provided')
-const uniswapV3FactoryAddress = process.env.UNISWAP_V3_FACTORY_ADDRESS as string
+const uniswapV3FactoryAddress = process.env.SWAP_FACTORY_ADDRESS as string
if (!uniswapV3FactoryAddress) throw new Error('No uniswap v3 factory address provided')
const wethTokenAddress = process.env.WETH_TOKEN_ADDRESS as string
if (!wethTokenAddress) throw new Error('No weth token address provided')
@@ -27,7 +26,7 @@ export async function initiateDepositHandler({ manager, signer }: { manager: Cas
from: manager.address,
nonce
})
- const poolWithdrawalCredentials = `0x${getWithdrawalCredentials(poolAddress)}`
+ const poolWithdrawalCredentials = '0x' + '01' + '0'.repeat(22) + poolAddress.split('0x')[1]
const validator = mockValidators.find((validator) => validator.withdrawalCredentials === poolWithdrawalCredentials)
if (!validator) throw new Error(`No validator found for withdrawal credentials ${poolWithdrawalCredentials}`)
@@ -43,7 +42,7 @@ export async function initiateDepositHandler({ manager, signer }: { manager: Cas
const scanner = new Scanner({
provider: ethers.provider,
ssvNetworkAddress,
- ssvNetworkViewsAddress
+ ssvViewsAddress
})
const cluster = await scanner.getCluster({
@@ -82,6 +81,82 @@ export async function initiateDepositHandler({ manager, signer }: { manager: Cas
await initiateDeposit.wait()
}
+export async function reportResharesHandler({ manager, views, signer, args }: { manager: CasimirManager, views: CasimirViews, signer: SignerWithAddress, args: Record }) {
+ const { operatorId } = args
+ if (!operatorId) throw new Error('No operator id provided')
+
+ const poolIds = [
+ ...await manager.getPendingPoolIds(),
+ ...await manager.getStakedPoolIds()
+ ]
+
+ for (const poolId of poolIds) {
+ const poolDetails = await views.getPool(poolId)
+ const oldOperatorIds = poolDetails.operatorIds.map(id => id.toNumber())
+ if (oldOperatorIds.includes(operatorId)) {
+ const mockReshares: Reshare[] = reshareStore[poolId as keyof typeof reshareStore]
+ const poolReshareCount = poolDetails.reshares.toNumber()
+ if (mockReshares.length && poolReshareCount < 2) {
+ const reshare = mockReshares.find((reshare) => {
+ return JSON.stringify(reshare.oldOperatorIds) === JSON.stringify(oldOperatorIds)
+ })
+ if (!reshare) throw new Error(`No reshare found for pool ${poolId} with old operator ids ${oldOperatorIds}`)
+
+ const newOperatorId = reshare.operatorIds.find((id) => !oldOperatorIds.includes(id)) as number
+
+ const scanner = new Scanner({
+ provider: ethers.provider,
+ ssvNetworkAddress,
+ ssvViewsAddress
+ })
+
+ const oldCluster = await scanner.getCluster({
+ operatorIds: oldOperatorIds,
+ ownerAddress: manager.address
+ })
+
+ const cluster = await scanner.getCluster({
+ operatorIds: reshare.operatorIds,
+ ownerAddress: manager.address
+ })
+
+ const requiredFee = await scanner.getRequiredFee(reshare.operatorIds)
+
+ const uniswapFactory = new Factory({
+ provider: ethers.provider,
+ uniswapV3FactoryAddress
+ })
+
+ const price = await uniswapFactory.getSwapPrice({
+ tokenIn: wethTokenAddress,
+ tokenOut: ssvTokenAddress,
+ uniswapFeeTier: 3000
+ })
+
+ const feeAmount = ethers.utils.parseEther((Number(ethers.utils.formatEther(requiredFee.sub(oldCluster.balance))) * Number(price)).toPrecision(9))
+ const minimumTokenAmount = ethers.utils.parseEther((Number(ethers.utils.formatEther(requiredFee.sub(oldCluster.balance))) * 0.99).toPrecision(9))
+
+ const reportReshare = await manager.connect(signer).reportReshare(
+ poolId,
+ reshare.operatorIds,
+ oldOperatorIds,
+ newOperatorId,
+ operatorId,
+ reshare.shares,
+ cluster,
+ oldCluster,
+ feeAmount,
+ minimumTokenAmount,
+ false
+ )
+ await reportReshare.wait()
+ } else {
+ // Exit pool
+ }
+ }
+ }
+}
+
export async function depositFunctionsBalanceHandler({ manager, signer }: { manager: CasimirManager, signer: SignerWithAddress }) {
/**
* In production, we check the functions balance before reporting
@@ -157,7 +232,7 @@ export async function reportCompletedExitsHandler({ manager, views, signer, args
let poolIndex = 0
while (remaining > 0) {
const poolId = stakedPoolIds[poolIndex]
- const poolDetails = await views.getPoolDetails(poolId)
+ const poolDetails = await views.getPool(poolId)
if (poolDetails.status === PoolStatus.EXITING_FORCED || poolDetails.status === PoolStatus.EXITING_REQUESTED) {
remaining--
@@ -177,7 +252,7 @@ export async function reportCompletedExitsHandler({ manager, views, signer, args
const scanner = new Scanner({
provider: ethers.provider,
ssvNetworkAddress,
- ssvNetworkViewsAddress
+ ssvViewsAddress
})
const cluster = await scanner.getCluster({
diff --git a/contracts/ethereum/helpers/upkeep.ts b/contracts/ethereum/helpers/upkeep.ts
index 67f5d14fe..34f65cdd7 100644
--- a/contracts/ethereum/helpers/upkeep.ts
+++ b/contracts/ethereum/helpers/upkeep.ts
@@ -3,17 +3,18 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { CasimirUpkeep, FunctionsBillingRegistry } from '../build/@types'
export async function runUpkeep({
- upkeep, keeper
+ donTransmitter, upkeep,
}: {
- upkeep: CasimirUpkeep, keeper: SignerWithAddress
+ donTransmitter: SignerWithAddress,
+ upkeep: CasimirUpkeep,
}) {
let ranUpkeep = false
const checkData = ethers.utils.toUtf8Bytes('')
- const { ...check } = await upkeep.connect(keeper).checkUpkeep(checkData)
+ const { ...check } = await upkeep.connect(donTransmitter).checkUpkeep(checkData)
const { upkeepNeeded } = check
if (upkeepNeeded) {
const performData = ethers.utils.toUtf8Bytes('')
- const performUpkeep = await upkeep.connect(keeper).performUpkeep(performData)
+ const performUpkeep = await upkeep.connect(donTransmitter).performUpkeep(performData)
await performUpkeep.wait()
ranUpkeep = true
}
@@ -21,7 +22,7 @@ export async function runUpkeep({
}
export interface ReportValues {
- activeBalance: number
+ beaconBalance: number
sweptBalance: number
activatedDeposits: number
forcedExits: number
@@ -30,66 +31,66 @@ export interface ReportValues {
}
export async function fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values
}: {
- keeper: SignerWithAddress,
+ donTransmitter: SignerWithAddress,
upkeep: CasimirUpkeep,
functionsBillingRegistry: FunctionsBillingRegistry,
values: ReportValues
}) {
- const { activeBalance, sweptBalance, activatedDeposits, forcedExits, completedExits, compoundablePoolIds } = values
+ const { beaconBalance, sweptBalance, activatedDeposits, forcedExits, completedExits, compoundablePoolIds } = values
const requestIds = (await upkeep.queryFilter(upkeep.filters.RequestSent())).slice(-2).map((event) => event.args.id)
const balancesRequestId = requestIds[0]
- const balancesResponseBytes = ethers.utils.defaultAbiCoder.encode(
+ const balancesResponse = ethers.utils.defaultAbiCoder.encode(
['uint128', 'uint128'],
- [ethers.utils.parseEther(activeBalance.toString()), ethers.utils.parseEther(sweptBalance.toString())]
+ [ethers.utils.parseEther(beaconBalance.toString()), ethers.utils.parseEther(sweptBalance.toString())]
)
await fulfillFunctionsRequest({
- keeper,
+ donTransmitter,
functionsBillingRegistry,
requestId: balancesRequestId,
- responseBytes: balancesResponseBytes
+ response: balancesResponse
})
const detailsRequestId = requestIds[1]
- const detailsResponseBytes = ethers.utils.defaultAbiCoder.encode(
+ const detailsResponse = ethers.utils.defaultAbiCoder.encode(
['uint32', 'uint32', 'uint32', 'uint32[5]'],
[activatedDeposits, forcedExits, completedExits, compoundablePoolIds]
)
await fulfillFunctionsRequest({
- keeper,
+ donTransmitter,
functionsBillingRegistry,
requestId: detailsRequestId,
- responseBytes: detailsResponseBytes
+ response: detailsResponse
})
}
export async function fulfillFunctionsRequest({
- keeper,
+ donTransmitter,
functionsBillingRegistry,
requestId,
- responseBytes
+ response
}: {
- keeper: SignerWithAddress,
+ donTransmitter: SignerWithAddress,
functionsBillingRegistry: FunctionsBillingRegistry,
requestId: string,
- responseBytes: string
+ response: string
}) {
- const dummyTransmitter = keeper.address
+ const dummyTransmitter = donTransmitter.address
const dummySigners = Array(31).fill(dummyTransmitter)
// const { success, result, resultLog } = await simulateRequest(requestConfig)
- const fulfillAndBill = await functionsBillingRegistry.connect(keeper).fulfillAndBill(
+ const fulfillAndBill = await functionsBillingRegistry.connect(donTransmitter).fulfillAndBill(
requestId,
- responseBytes,
+ response,
'0x',
dummyTransmitter,
dummySigners,
diff --git a/contracts/ethereum/lib/forge-std b/contracts/ethereum/lib/forge-std
index f18e8aa3e..518bb37cd 160000
--- a/contracts/ethereum/lib/forge-std
+++ b/contracts/ethereum/lib/forge-std
@@ -1 +1 @@
-Subproject commit f18e8aa3e72eef83518766eb34ad8c8d8e2aa0aa
+Subproject commit 518bb37cd5a76a14fde04883297e8d97a9413226
diff --git a/contracts/ethereum/package.json b/contracts/ethereum/package.json
index 4d08b5b0b..df17d8cfc 100644
--- a/contracts/ethereum/package.json
+++ b/contracts/ethereum/package.json
@@ -1,5 +1,6 @@
{
"name": "@casimir/ethereum",
+ "version": "1.0.0-beta.0",
"scripts": {
"build": "npx hardhat compile",
"build:docs": "npx esno scripts/docs.ts",
@@ -9,19 +10,21 @@
"dev:docs": "DEV=true npx esno scripts/docs.ts",
"node": "npx hardhat node",
"postinstall": "npx esno scripts/foundryup.ts",
- "test": "npx esno scripts/test.ts"
+ "test": "npx esno scripts/test.ts",
+ "upgrade": "npx hardhat run scripts/upgrade.ts"
},
"dependencies": {
"@chainlink/contracts": "^0.6.1",
- "@openzeppelin/contracts": "^4.8.0",
+ "@openzeppelin/contracts": "^4.9.3",
+ "@openzeppelin/contracts-upgradeable": "^4.9.3",
"@uniswap/v3-core": "1.0.1",
"@uniswap/v3-periphery": "^1.4.3"
},
"devDependencies": {
- "@nomicfoundation/hardhat-foundry": "^1.0.2",
"@nomicfoundation/hardhat-network-helpers": "^1.0.6",
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
"@nomiclabs/hardhat-ethers": "^2.0.6",
+ "@openzeppelin/hardhat-upgrades": "^1.28.0",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.3.1",
@@ -30,8 +33,9 @@
"@types/node": "^17.0.45",
"chai": "^4.3.6",
"esno": "^0.16.3",
- "hardhat": "^2.12.2",
+ "hardhat": "^2.12.3",
"hardhat-abi-exporter": "^2.10.1",
+ "hardhat-preprocessor": "^0.1.5",
"localtunnel": "^2.0.2",
"mocha": "^10.0.0",
"typechain": "^8.1.0"
diff --git a/contracts/ethereum/remappings.txt b/contracts/ethereum/remappings.txt
new file mode 100644
index 000000000..1076a4256
--- /dev/null
+++ b/contracts/ethereum/remappings.txt
@@ -0,0 +1,2 @@
+ds-test/=lib/forge-std/lib/ds-test/src/
+forge-std/=lib/forge-std/src/
\ No newline at end of file
diff --git a/contracts/ethereum/scripts/deploy.ts b/contracts/ethereum/scripts/deploy.ts
index 9891ca0cf..0222737db 100644
--- a/contracts/ethereum/scripts/deploy.ts
+++ b/contracts/ethereum/scripts/deploy.ts
@@ -1,40 +1,125 @@
-import { ethers } from 'hardhat'
+import { ethers, upgrades } from 'hardhat'
+import requestConfig from '@casimir/functions/Functions-request-config'
+
+upgrades.silenceWarnings()
/**
* Deploy ethereum contracts
- */
+*/
void async function () {
+ const [, daoOracle, donTransmitter] = await ethers.getSigners()
+
+ const functionsOracleFactoryFactory = await ethers.getContractFactory('FunctionsOracleFactory')
+ const functionsOracleFactory = await functionsOracleFactoryFactory.deploy()
+ await functionsOracleFactory.deployed()
+ console.log(`FunctionsOracleFactory contract deployed to ${functionsOracleFactory.address}`)
+
+ const deployNewOracle = await functionsOracleFactory.deployNewOracle()
+ const deployNewOracleReceipt = await deployNewOracle.wait()
+ if (!deployNewOracleReceipt.events) throw new Error('Functions oracle deployment failed')
+ const functionsOracleAddress = deployNewOracleReceipt.events[1].args?.don as string
+ const functionsOracle = await ethers.getContractAt('FunctionsOracle', functionsOracleAddress)
+ const acceptOwnership = await functionsOracle.acceptOwnership()
+ await acceptOwnership.wait()
+ console.log(`FunctionsOracle contract deployed to ${functionsOracle.address}`)
+
+ const functionsBillingRegistryArgs = {
+ linkTokenAddress: process.env.LINK_TOKEN_ADDRESS,
+ linkEthFeedAddress: process.env.LINK_ETH_FEED_ADDRESS,
+ functionsOracleAddress: functionsOracle.address
+ }
+ const functionsBillingRegistryFactory = await ethers.getContractFactory('FunctionsBillingRegistry')
+ const functionsBillingRegistry = await functionsBillingRegistryFactory.deploy(...Object.values(functionsBillingRegistryArgs))
+ await functionsBillingRegistry.deployed()
+ console.log(`FunctionsBillingRegistry contract deployed to ${functionsBillingRegistry.address}`)
+
+ const functionsBillingRegistryConfig = {
+ maxGasLimit: 400_000,
+ stalenessSeconds: 86_400,
+ gasAfterPaymentCalculation:
+ 21_000 + 5_000 + 2_100 + 20_000 + 2 * 2_100 - 15_000 + 7_315,
+ weiPerUnitLink: ethers.BigNumber.from('5000000000000000'),
+ gasOverhead: 100_000,
+ requestTimeoutSeconds: 300,
+ }
+
+ await functionsBillingRegistry.setConfig(
+ functionsBillingRegistryConfig.maxGasLimit,
+ functionsBillingRegistryConfig.stalenessSeconds,
+ functionsBillingRegistryConfig.gasAfterPaymentCalculation,
+ functionsBillingRegistryConfig.weiPerUnitLink,
+ functionsBillingRegistryConfig.gasOverhead,
+ functionsBillingRegistryConfig.requestTimeoutSeconds
+ )
+
+ const arrayFactory = await ethers.getContractFactory('CasimirArray')
+ const arrayLibrary = await arrayFactory.deploy()
+
+ const factoryFactory = await ethers.getContractFactory('CasimirFactory')
+ const factoryLibrary = await factoryFactory.deploy()
+
+ const poolFactory = await ethers.getContractFactory('CasimirPool')
+ const poolBeacon = await upgrades.deployBeacon(poolFactory, { unsafeAllow: ['constructor'] })
+ await poolBeacon.deployed()
+ console.log(`CasimirPool beacon deployed to ${poolBeacon.address}`)
+
+ const registryFactory = await ethers.getContractFactory('CasimirRegistry')
+ const registryBeacon = await upgrades.deployBeacon(registryFactory, { unsafeAllow: ['constructor'] })
+ await registryBeacon.deployed()
+ console.log(`CasimirRegistry beacon deployed to ${registryBeacon.address}`)
+
+ const upkeepFactory = await ethers.getContractFactory('CasimirUpkeep')
+ const upkeepBeacon = await upgrades.deployBeacon(upkeepFactory, { unsafeAllow: ['constructor'] })
+ await upkeepBeacon.deployed()
+ console.log(`CasimirUpkeep beacon deployed to ${upkeepBeacon.address}`)
+
const managerArgs = {
- daoOracleAddress: process.env.DAO_ORACLE_ADDRESS,
beaconDepositAddress: process.env.BEACON_DEPOSIT_ADDRESS,
- functionsBillingRegistryAddress: process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS,
- functionsOracleAddress: process.env.FUNCTIONS_ORACLE_ADDRESS,
- linkRegistrarAddress: process.env.LINK_REGISTRAR_ADDRESS,
- linkRegistryAddress: process.env.LINK_REGISTRY_ADDRESS,
+ daoOracleAddress: daoOracle.address,
+ functionsBillingRegistryAddress: functionsBillingRegistry.address,
+ functionsOracleAddress: functionsOracle.address,
+ keeperRegistrarAddress: process.env.KEEPER_REGISTRAR_ADDRESS,
+ keeperRegistryAddress: process.env.KEEPER_REGISTRY_ADDRESS,
linkTokenAddress: process.env.LINK_TOKEN_ADDRESS,
+ poolBeaconAddress: poolBeacon.address,
+ registryBeaconAddress: registryBeacon.address,
ssvNetworkAddress: process.env.SSV_NETWORK_ADDRESS,
- ssvNetworkViewsAddress: process.env.SSV_NETWORK_VIEWS_ADDRESS,
ssvTokenAddress: process.env.SSV_TOKEN_ADDRESS,
+ ssvViewsAddress: process.env.SSV_VIEWS_ADDRESS,
swapFactoryAddress: process.env.SWAP_FACTORY_ADDRESS,
swapRouterAddress: process.env.SWAP_ROUTER_ADDRESS,
+ upkeepBeaconAddress: upkeepBeacon.address,
wethTokenAddress: process.env.WETH_TOKEN_ADDRESS
}
- const managerFactory = await ethers.getContractFactory('CasimirManager')
- const manager = await managerFactory.deploy(...Object.values(managerArgs))
+ const managerFactory = await ethers.getContractFactory('CasimirManager', {
+ libraries: {
+ CasimirArray: arrayLibrary.address,
+ CasimirFactory: factoryLibrary.address
+ }
+ })
+ const manager = await upgrades.deployProxy(managerFactory, Object.values(managerArgs), { unsafeAllow: ['constructor', 'external-library-linking'] })
await manager.deployed()
console.log(`CasimirManager contract deployed to ${manager.address}`)
- const registryAddress = await manager.getRegistryAddress()
- console.log(`CasimirRegistry contract deployed to ${registryAddress}`)
+ const registry = await ethers.getContractAt('CasimirRegistry', await manager.getRegistryAddress())
+ console.log(`CasimirRegistry contract deployed to ${registry.address}`)
- const upkeepAddress = await manager.getUpkeepAddress()
- console.log(`CasimirUpkeep contract deployed to ${upkeepAddress}`)
+ const upkeep = await ethers.getContractAt('CasimirUpkeep', await manager.getUpkeepAddress())
+ console.log(`CasimirUpkeep contract deployed to ${upkeep.address}`)
const viewsArgs = {
managerAddress: manager.address,
- registryAddress
+ registryAddress: registry.address
}
const viewsFactory = await ethers.getContractFactory('CasimirViews')
- const views = await viewsFactory.deploy(...Object.values(viewsArgs))
+ const views = await upgrades.deployProxy(viewsFactory, Object.values(viewsArgs), { unsafeAllow: ['constructor'] })
console.log(`CasimirViews contract deployed to ${views.address}`)
+
+ requestConfig.args[1] = views.address
+ const setRequest = await manager.setFunctionsRequest(requestConfig.source, requestConfig.args, 300000)
+ await setRequest.wait()
+
+ await functionsBillingRegistry.setAuthorizedSenders([donTransmitter.address, functionsOracle.address])
+ await functionsOracle.setRegistry(functionsBillingRegistry.address)
+ await functionsOracle.addAuthorizedSenders([donTransmitter.address, manager.address])
}()
\ No newline at end of file
diff --git a/contracts/ethereum/scripts/dev.ts b/contracts/ethereum/scripts/dev.ts
index 99a7e1331..8e1599395 100644
--- a/contracts/ethereum/scripts/dev.ts
+++ b/contracts/ethereum/scripts/dev.ts
@@ -1,18 +1,21 @@
-import { CasimirManager, CasimirRegistry, ISSVNetworkViews, CasimirViews, CasimirUpkeep, FunctionsOracleFactory, FunctionsBillingRegistry } from '../build/@types'
-import { ethers, network } from 'hardhat'
+import { CasimirManager, CasimirRegistry, ISSVViews, CasimirViews, CasimirUpkeep, FunctionsOracleFactory, FunctionsBillingRegistry } from '../build/@types'
+import { ethers, network, upgrades } from 'hardhat'
import { fulfillReport, runUpkeep } from '@casimir/ethereum/helpers/upkeep'
import { round } from '@casimir/ethereum/helpers/math'
import { time, setBalance } from '@nomicfoundation/hardhat-network-helpers'
-import ISSVNetworkViewsAbi from '../build/abi/ISSVNetworkViews.json'
-import { fetchRetry, run } from '@casimir/helpers'
+import ISSVViewsAbi from '../build/abi/ISSVViews.json'
+import { fetchRetry } from '@casimir/fetch'
+import { run } from '@casimir/shell'
import { PoolStatus } from '@casimir/types'
-import { requestConfig } from '@casimir/functions'
+import requestConfig from '@casimir/functions/Functions-request-config'
+
+upgrades.silenceWarnings()
/**
* Deploy contracts to local network and run local events and oracle handling
*/
void async function () {
- const [, , , , fourthUser, keeper, daoOracle] = await ethers.getSigners()
+ const [, daoOracle, donTransmitter, firstUser] = await ethers.getSigners()
const functionsOracleFactoryFactory = await ethers.getContractFactory('FunctionsOracleFactory')
const functionsOracleFactory = await functionsOracleFactoryFactory.deploy() as FunctionsOracleFactory
@@ -57,50 +60,79 @@ void async function () {
functionsBillingRegistryConfig.requestTimeoutSeconds
)
+ const arrayFactory = await ethers.getContractFactory('CasimirArray')
+ const arrayLibrary = await arrayFactory.deploy()
+ console.log(`CasimirArray library deployed to ${arrayLibrary.address}`)
+
+ const factoryFactory = await ethers.getContractFactory('CasimirFactory')
+ const factoryLibrary = await factoryFactory.deploy()
+ console.log(`CasimirFactory library deployed to ${factoryLibrary.address}`)
+
+ const poolFactory = await ethers.getContractFactory('CasimirPool')
+ const poolBeacon = await upgrades.deployBeacon(poolFactory, { unsafeAllow: ['constructor'] })
+ await poolBeacon.deployed()
+ console.log(`CasimirPool beacon deployed to ${poolBeacon.address}`)
+
+ const registryFactory = await ethers.getContractFactory('CasimirRegistry')
+ const registryBeacon = await upgrades.deployBeacon(registryFactory, { unsafeAllow: ['constructor'] })
+ await registryBeacon.deployed()
+ console.log(`CasimirRegistry beacon deployed to ${registryBeacon.address}`)
+
+ const upkeepFactory = await ethers.getContractFactory('CasimirUpkeep')
+ const upkeepBeacon = await upgrades.deployBeacon(upkeepFactory, { unsafeAllow: ['constructor'] })
+ await upkeepBeacon.deployed()
+ console.log(`CasimirUpkeep beacon deployed to ${upkeepBeacon.address}`)
+
const managerArgs = {
- daoOracleAddress: daoOracle.address,
beaconDepositAddress: process.env.BEACON_DEPOSIT_ADDRESS,
+ daoOracleAddress: daoOracle.address,
functionsBillingRegistryAddress: functionsBillingRegistry.address,
functionsOracleAddress: functionsOracle.address,
- linkRegistrarAddress: process.env.LINK_REGISTRAR_ADDRESS,
- linkRegistryAddress: process.env.LINK_REGISTRY_ADDRESS,
+ keeperRegistrarAddress: process.env.KEEPER_REGISTRAR_ADDRESS,
+ keeperRegistryAddress: process.env.KEEPER_REGISTRY_ADDRESS,
linkTokenAddress: process.env.LINK_TOKEN_ADDRESS,
+ poolBeaconAddress: poolBeacon.address,
+ registryBeaconAddress: registryBeacon.address,
ssvNetworkAddress: process.env.SSV_NETWORK_ADDRESS,
- ssvNetworkViewsAddress: process.env.SSV_NETWORK_VIEWS_ADDRESS,
ssvTokenAddress: process.env.SSV_TOKEN_ADDRESS,
+ ssvViewsAddress: process.env.SSV_VIEWS_ADDRESS,
swapFactoryAddress: process.env.SWAP_FACTORY_ADDRESS,
swapRouterAddress: process.env.SWAP_ROUTER_ADDRESS,
+ upkeepBeaconAddress: upkeepBeacon.address,
wethTokenAddress: process.env.WETH_TOKEN_ADDRESS
}
- const managerFactory = await ethers.getContractFactory('CasimirManager')
- const manager = await managerFactory.deploy(...Object.values(managerArgs)) as CasimirManager
+ const managerFactory = await ethers.getContractFactory('CasimirManager', {
+ libraries: {
+ CasimirArray: arrayLibrary.address,
+ CasimirFactory: factoryLibrary.address
+ }
+ })
+ const manager = await upgrades.deployProxy(managerFactory, Object.values(managerArgs), { unsafeAllow: ['constructor', 'external-library-linking'] }) as CasimirManager
await manager.deployed()
console.log(`CasimirManager contract deployed to ${manager.address}`)
- const registryAddress = await manager.getRegistryAddress()
- console.log(`CasimirRegistry contract deployed to ${registryAddress}`)
+ const registry = await ethers.getContractAt('CasimirRegistry', await manager.getRegistryAddress()) as CasimirRegistry
+ console.log(`CasimirRegistry contract deployed to ${registry.address}`)
- const upkeepAddress = await manager.getUpkeepAddress()
- console.log(`CasimirUpkeep contract deployed to ${upkeepAddress}`)
+ const upkeep = await ethers.getContractAt('CasimirUpkeep', await manager.getUpkeepAddress()) as CasimirUpkeep
+ console.log(`CasimirUpkeep contract deployed to ${upkeep.address}`)
const viewsArgs = {
managerAddress: manager.address,
- registryAddress
+ registryAddress: registry.address
}
const viewsFactory = await ethers.getContractFactory('CasimirViews')
- const views = await viewsFactory.deploy(...Object.values(viewsArgs)) as CasimirViews
+ const views = await upgrades.deployProxy(viewsFactory, Object.values(viewsArgs), { unsafeAllow: ['constructor'] }) as CasimirViews
+ await views.deployed()
console.log(`CasimirViews contract deployed to ${views.address}`)
- const registry = await ethers.getContractAt('CasimirRegistry', registryAddress) as CasimirRegistry
- const upkeep = await ethers.getContractAt('CasimirUpkeep', upkeepAddress) as CasimirUpkeep
- const ssvNetworkViews = await ethers.getContractAt(ISSVNetworkViewsAbi, process.env.SSV_NETWORK_VIEWS_ADDRESS as string) as ISSVNetworkViews
-
- const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [654, 655, 656, 657]
- if (preregisteredOperatorIds.length < 4) throw new Error('Not enough operator ids provided')
+ const ssvViews = await ethers.getContractAt(ISSVViewsAbi, process.env.SSV_VIEWS_ADDRESS as string) as ISSVViews
+ const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [200, 201, 202, 203, 156, 157, 158, 159]
+ if (preregisteredOperatorIds.length < 8) throw new Error('Not enough operator ids provided')
const messengerUrl = process.env.MESSENGER_URL || 'https://nodes.casimir.co/eth/goerli/dkg/messenger'
const preregisteredBalance = ethers.utils.parseEther('10')
for (const operatorId of preregisteredOperatorIds) {
- const [operatorOwnerAddress] = await ssvNetworkViews.getOperatorById(operatorId)
+ const [operatorOwnerAddress] = await ssvViews.getOperatorById(operatorId)
const currentBalance = await ethers.provider.getBalance(operatorOwnerAddress)
const nextBalance = currentBalance.add(preregisteredBalance)
await setBalance(operatorOwnerAddress, nextBalance)
@@ -113,15 +145,13 @@ void async function () {
await result.wait()
}
- const secrets = '0x' // Parse requestConfig.secrets and encrypt if necessary
- const requestCBOR = await upkeep.generateRequest(requestConfig.source, secrets, requestConfig.args)
- const fulfillGasLimit = 300000
- const setRequest = await manager.setFunctionsRequest(requestCBOR, fulfillGasLimit)
+ requestConfig.args[1] = views.address
+ const setRequest = await manager.setFunctionsRequest(requestConfig.source, requestConfig.args, 300000)
await setRequest.wait()
- await functionsBillingRegistry.setAuthorizedSenders([keeper.address, manager.address, upkeep.address, functionsOracle.address])
+ await functionsBillingRegistry.setAuthorizedSenders([donTransmitter.address, functionsOracle.address])
await functionsOracle.setRegistry(functionsBillingRegistry.address)
- await functionsOracle.addAuthorizedSenders([keeper.address, manager.address])
+ await functionsOracle.addAuthorizedSenders([donTransmitter.address, manager.address])
/**
* We are simulating the oracle reporting on a more frequent basis
@@ -138,7 +168,7 @@ void async function () {
await time.increase(time.duration.days(1))
console.log('⌛️ Report period complete')
lastReportBlock = await ethers.provider.getBlockNumber()
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const pendingPoolIds = await manager.getPendingPoolIds()
const stakedPoolIds = await manager.getStakedPoolIds()
if (pendingPoolIds.length + stakedPoolIds.length) {
@@ -148,8 +178,8 @@ void async function () {
const exitingPoolCount = await manager.requestedExits()
const sweptExitedBalance = exitingPoolCount.toNumber() * 32
const rewardBalance = rewardPerValidator * stakedPoolIds.length
- const latestActiveBalance = await manager.latestActiveBalance()
- const nextActiveBalance = round(parseFloat(ethers.utils.formatEther(latestActiveBalance)) + activatedBalance + rewardBalance - sweptRewardBalance - sweptExitedBalance, 10)
+ const latestBeaconBalance = await manager.latestBeaconBalance()
+ const nextBeaconBalance = round(parseFloat(ethers.utils.formatEther(latestBeaconBalance)) + activatedBalance + rewardBalance - sweptRewardBalance - sweptExitedBalance, 10)
const nextActivatedDeposits = (await manager.getPendingPoolIds()).length
for (const poolId of lastStakedPoolIds) {
const poolAddress = await manager.getPoolAddress(poolId)
@@ -161,7 +191,7 @@ void async function () {
const endIndex = ethers.BigNumber.from(stakedPoolIds.length)
const compoundablePoolIds = await views.getCompoundablePoolIds(startIndex, endIndex)
const reportValues = {
- activeBalance: nextActiveBalance,
+ beaconBalance: nextBeaconBalance,
sweptBalance: sweptRewardBalance + sweptExitedBalance,
activatedDeposits: nextActivatedDeposits,
forcedExits: 0,
@@ -170,7 +200,7 @@ void async function () {
}
console.log('🧾 Report values', reportValues)
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
@@ -179,7 +209,7 @@ void async function () {
if (remaining) {
for (const poolId of stakedPoolIds) {
if (remaining === 0) break
- const poolDetails = await views.getPoolDetails(poolId)
+ const poolDetails = await views.getPool(poolId)
if (poolDetails.status === PoolStatus.EXITING_FORCED || poolDetails.status === PoolStatus.EXITING_REQUESTED) {
remaining--
const poolAddress = await manager.getPoolAddress(poolId)
@@ -194,7 +224,7 @@ void async function () {
finalizableCompletedExits = await manager.finalizableCompletedExits()
}
}
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
}
lastStakedPoolIds = stakedPoolIds
}
@@ -205,11 +235,12 @@ void async function () {
const ping = await fetchRetry(`${messengerUrl}/ping`)
const { message } = await ping.json()
if (message !== 'pong') throw new Error('DKG service is not running')
- const depositAmount = 32 * ((100 + await manager.FEE_PERCENT()) / 100)
- const depositStake = await manager.connect(fourthUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
+ const depositAmount = 64 * ((100 + await manager.FEE_PERCENT()) / 100)
+ const depositStake = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await depositStake?.wait()
}, 2500)
process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS = functionsBillingRegistry.address
+ process.env.FUNCTIONS_ORACLE_ADDRESS = functionsOracle.address
run('npm run dev --workspace @casimir/oracle')
}()
diff --git a/contracts/ethereum/scripts/docs.ts b/contracts/ethereum/scripts/docs.ts
index 4abe58e34..a2387a64a 100644
--- a/contracts/ethereum/scripts/docs.ts
+++ b/contracts/ethereum/scripts/docs.ts
@@ -1,5 +1,5 @@
import fs from 'fs'
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
void async function () {
const cargo = await run('which cargo') as string
diff --git a/contracts/ethereum/scripts/foundryup.ts b/contracts/ethereum/scripts/foundryup.ts
index 43f456839..9251a71d7 100644
--- a/contracts/ethereum/scripts/foundryup.ts
+++ b/contracts/ethereum/scripts/foundryup.ts
@@ -1,4 +1,4 @@
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
void async function () {
const forge = await run('which forge') as string
diff --git a/contracts/ethereum/scripts/resources/ssv-network b/contracts/ethereum/scripts/resources/ssv-network
index 514884702..b8e03e7d2 160000
--- a/contracts/ethereum/scripts/resources/ssv-network
+++ b/contracts/ethereum/scripts/resources/ssv-network
@@ -1 +1 @@
-Subproject commit 514884702fbc2606688330d2913f46cd718b6c18
+Subproject commit b8e03e7d2edf28a4631e16489f00052ed42a7e74
diff --git a/contracts/ethereum/scripts/test.ts b/contracts/ethereum/scripts/test.ts
index 1fc513743..1160598fd 100644
--- a/contracts/ethereum/scripts/test.ts
+++ b/contracts/ethereum/scripts/test.ts
@@ -1,4 +1,4 @@
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
/**
* Test ethereum contracts
diff --git a/contracts/ethereum/scripts/upgrade.ts b/contracts/ethereum/scripts/upgrade.ts
new file mode 100644
index 000000000..8ff02295a
--- /dev/null
+++ b/contracts/ethereum/scripts/upgrade.ts
@@ -0,0 +1,49 @@
+import { ethers, upgrades } from 'hardhat'
+
+/**
+ * Upgrade ethereum contracts
+ */
+void async function () {
+ if (!process.env.POOL_BEACON_ADDRESS) throw new Error('No pool beacon address provided')
+ if (!process.env.REGISTRY_BEACON_ADDRESS) throw new Error('No registry beacon address provided')
+ if (!process.env.UPKEEP_BEACON_ADDRESS) throw new Error('No upkeep beacon address provided')
+ if (!process.env.MANAGER_ADDRESS) throw new Error('No manager address provided')
+ if (!process.env.VIEWS_ADDRESS) throw new Error('No views address provided')
+
+ const arrayFactory = await ethers.getContractFactory('CasimirArray')
+ const arrayLibrary = await arrayFactory.deploy()
+ console.log(`CasimirArray library upgraded at ${arrayLibrary.address}`)
+
+ const factoryFactory = await ethers.getContractFactory('CasimirFactory')
+ const factoryLibrary = await factoryFactory.deploy()
+ console.log(`CasimirFactory library upgraded at ${factoryLibrary.address}`)
+
+ const poolFactory = await ethers.getContractFactory('CasimirPool')
+ const poolBeacon = await upgrades.upgradeBeacon(process.env.POOL_BEACON_ADDRESS, poolFactory, { unsafeAllow: ['constructor'] })
+ await poolBeacon.deployed()
+ console.log(`CasimirPool beacon upgraded at ${poolBeacon.address}`)
+
+ const registryFactory = await ethers.getContractFactory('CasimirRegistry')
+ const registryBeacon = await upgrades.upgradeBeacon(process.env.REGISTRY_BEACON_ADDRESS, registryFactory, { unsafeAllow: ['constructor'] })
+ await registryBeacon.deployed()
+ console.log(`CasimirRegistry beacon upgraded at ${registryBeacon.address}`)
+
+ const upkeepFactory = await ethers.getContractFactory('CasimirUpkeep')
+ const upkeepBeacon = await upgrades.upgradeBeacon(process.env.UPKEEP_BEACON_ADDRESS, upkeepFactory, { unsafeAllow: ['constructor'] })
+ await upkeepBeacon.deployed()
+ console.log(`CasimirUpkeep beacon upgraded at ${upkeepBeacon.address}`)
+
+ const managerFactory = await ethers.getContractFactory('CasimirManager', {
+ libraries: {
+ CasimirArray: arrayLibrary.address,
+ CasimirFactory: factoryLibrary.address
+ }
+ })
+ const manager = await upgrades.upgradeProxy(process.env.MANAGER_ADDRESS, managerFactory, { unsafeAllow: ['constructor', 'external-library-linking'] })
+ await manager.deployed()
+ console.log(`CasimirManager contract upgraded at ${manager.address}`)
+
+ const viewsFactory = await ethers.getContractFactory('CasimirViews')
+ const views = await upgrades.upgradeProxy(process.env.VIEWS_ADDRESS, viewsFactory, { unsafeAllow: ['constructor'] })
+ console.log(`CasimirViews contract upgraded at ${views.address}`)
+}()
\ No newline at end of file
diff --git a/contracts/ethereum/src/v1/CasimirManager.sol b/contracts/ethereum/src/v1/CasimirManager.sol
index 4ec84c02d..b9208c042 100644
--- a/contracts/ethereum/src/v1/CasimirManager.sol
+++ b/contracts/ethereum/src/v1/CasimirManager.sol
@@ -1,11 +1,9 @@
// SPDX-License-Identifier: Apache
pragma solidity 0.8.18;
-import "./CasimirPool.sol";
-import "./CasimirRegistry.sol";
-import "./CasimirUpkeep.sol";
import "./interfaces/ICasimirManager.sol";
-import "./libraries/Types.sol";
+import "./libraries/CasimirArray.sol";
+import "./libraries/CasimirFactory.sol";
import "./vendor/interfaces/IDepositContract.sol";
import "./vendor/interfaces/ISSVNetwork.sol";
import "./vendor/interfaces/IWETH9.sol";
@@ -13,11 +11,13 @@ import "./vendor/interfaces/IFunctionsBillingRegistry.sol";
import "./vendor/interfaces/IKeeperRegistrar.sol";
import "./vendor/interfaces/IAutomationRegistry.sol";
import "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
-import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
-import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
-import "@openzeppelin/contracts/utils/math/Math.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
import "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
@@ -25,30 +25,27 @@ import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
/**
* @title Manager contract that accepts and distributes deposits
*/
-contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
+contract CasimirManager is
+ ICasimirManager,
+ Initializable,
+ OwnableUpgradeable,
+ ReentrancyGuardUpgradeable
+{
/*************/
/* Libraries */
/*************/
- /** Use math for precise division */
- using Math for uint256;
/** Use internal type for uint32 array */
- using Types32Array for uint32[];
+ using CasimirArray for uint32[];
/** Use internal type for bytes array */
- using TypesBytesArray for bytes[];
+ using CasimirArray for bytes[];
/** Use internal type for withdrawal array */
- using TypesWithdrawalArray for Withdrawal[];
- /** Use internal type for address */
- using TypesAddress for address;
+ using CasimirArray for Withdrawal[];
/*************/
/* Constants */
/*************/
- /** User action period */
- uint256 private constant ACTION_PERIOD = 1 days;
- /** Max user actions per period */
- uint256 private constant MAX_ACTIONS_PER_PERIOD = 5;
/** Compound minimum (0.1 ETH) */
uint256 private constant COMPOUND_MINIMUM = 100000000 gwei;
/** Scale factor for each rewards to stake ratio */
@@ -59,40 +56,37 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 private constant POOL_CAPACITY = 32 ether;
/** Total fee percentage */
uint32 public constant FEE_PERCENT = 5;
-
- /*************/
- /* Immutable */
- /*************/
+
+ /*********/
+ /* State */
+ /*********/
/** DAO oracle address */
- address private immutable oracleAddress;
+ address private oracleAddress;
/** Registry contract */
- ICasimirRegistry private immutable registry;
+ ICasimirRegistry private registry;
/** Upkeep contract */
- ICasimirUpkeep private immutable upkeep;
+ ICasimirUpkeep private upkeep;
/** Beacon deposit contract */
- IDepositContract private immutable beaconDeposit;
+ IDepositContract private beaconDeposit;
/** Chainlink functions billing registry contract */
- IFunctionsBillingRegistry private immutable functionsBillingRegistry;
+ IFunctionsBillingRegistry private functionsBillingRegistry;
/** Keeper registrar contract */
- IKeeperRegistrar private immutable linkRegistrar;
+ IKeeperRegistrar private keeperRegistrar;
/** Automation registry contract */
- IAutomationRegistry private immutable linkRegistry;
+ IAutomationRegistry private keeperRegistry;
/** LINK ERC-20 token contract */
- LinkTokenInterface private immutable linkToken;
- /** SSV network contract */
- ISSVNetwork private immutable ssvNetwork;
+ LinkTokenInterface private linkToken;
+ /** Pool beacon contract */
+ IBeaconUpgradeable private poolBeacon;
+ /** SSV clusters contract */
+ ISSVClusters private ssvClusters;
/** SSV ERC-20 token contract */
- IERC20 private immutable ssvToken;
+ IERC20Upgradeable private ssvToken;
/** Uniswap factory contract */
- IUniswapV3Factory private immutable swapFactory;
+ IUniswapV3Factory private swapFactory;
/** Uniswap router contract */
- ISwapRouter private immutable swapRouter;
-
- /*********/
- /* State */
- /*********/
-
+ ISwapRouter private swapRouter;
/** Last pool ID created */
uint32 private lastPoolId;
/** Current report period */
@@ -101,10 +95,10 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint64 public functionsId;
/** Chainlink upkeep subscription ID */
uint256 public upkeepId;
- /** Latest active balance */
- uint256 public latestActiveBalance;
- /** Latest active balance after fees */
- uint256 private latestActiveBalanceAfterFees;
+ /** Latest beacon chain balance */
+ uint256 public latestBeaconBalance;
+ /** Latest beacon chain balance after fees */
+ uint256 private latestBeaconBalanceAfterFees;
/** Latest active rewards */
int256 private latestActiveRewardBalance;
/** Exited pool count */
@@ -117,8 +111,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
mapping(Token => address) private tokenAddresses;
/** All users */
mapping(address => User) private users;
- /** Sum of scaled rewards to balance ratios (intial value required) */
- uint256 private stakeRatioSum = 1000 ether;
+ /** Sum of scaled rewards to balance ratios */
+ uint256 private stakeRatioSum;
/** Total pending withdrawals count */
uint256 private requestedWithdrawals;
/** Total pending withdrawal amount */
@@ -147,113 +141,99 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 public requestedExits;
/** Slashed pool count */
uint256 private forcedExits;
+ /** Storage gap */
+ uint256[50] private __gap;
- /*************/
- /* Modifiers */
- /*************/
-
- /**
- * @dev Validate the caller is the authorized pool
- */
- modifier onlyPool(uint32 poolId) {
- require(msg.sender == poolAddresses[poolId], "Not pool");
- _;
- }
-
- /**
- * @dev Validate the caller is the oracle
- */
- modifier onlyOracle() {
- require(msg.sender == oracleAddress, "Not oracle");
- _;
- }
-
- /**
- * @dev Validate the caller is the oracle or registry
- */
- modifier onlyOracleOrRegistry() {
- require(
- msg.sender == oracleAddress || msg.sender == address(registry),
- "Not oracle or registry"
- );
- _;
- }
-
- /**
- * @dev Validate the caller is the registry
- */
- modifier onlyRegistry() {
- require(msg.sender == address(registry), "Not registry");
- _;
- }
-
- /**
- * @dev Validate the caller is the upkeep contract
- */
- modifier onlyUpkeep() {
- require(msg.sender == address(upkeep), "Not upkeep");
- _;
+ // @custom:oz-upgrades-unsafe-allow constructor
+ constructor() {
+ _disableInitializers();
}
/**
- * @notice Constructor
- * @param daoOracleAddress The DAO oracle address
+ * @notice Initialize the contract
* @param beaconDepositAddress The Beacon deposit address
+ * @param daoOracleAddress The DAO oracle address
* @param functionsBillingRegistryAddress The Chainlink functions billing registry address
* @param functionsOracleAddress The Chainlink functions oracle address
- * @param linkRegistrarAddress The Chainlink keeper registrar address
- * @param linkRegistryAddress The Chainlink keeper registry address
+ * @param keeperRegistrarAddress The Chainlink keeper registrar address
+ * @param keeperRegistryAddress The Chainlink keeper registry address
* @param linkTokenAddress The Chainlink token address
+ * @param poolBeaconAddress The pool beacon address
+ * @param registryBeaconAddress The registry beacon address
* @param ssvNetworkAddress The SSV network address
- * @param ssvNetworkViewsAddress The SSV network views address
+ * @param ssvViewsAddress The SSV views address
* @param ssvTokenAddress The SSV token address
* @param swapFactoryAddress The Uniswap factory address
* @param swapRouterAddress The Uniswap router address
+ * @param upkeepBeaconAddress The upkeep beacon address
* @param wethTokenAddress The WETH contract address
*/
- constructor(
- address daoOracleAddress,
+ function initialize(
address beaconDepositAddress,
+ address daoOracleAddress,
address functionsBillingRegistryAddress,
address functionsOracleAddress,
- address linkRegistrarAddress,
- address linkRegistryAddress,
+ address keeperRegistrarAddress,
+ address keeperRegistryAddress,
address linkTokenAddress,
+ address poolBeaconAddress,
+ address registryBeaconAddress,
address ssvNetworkAddress,
- address ssvNetworkViewsAddress,
address ssvTokenAddress,
+ address ssvViewsAddress,
address swapFactoryAddress,
address swapRouterAddress,
+ address upkeepBeaconAddress,
address wethTokenAddress
- ) {
- require(daoOracleAddress != address(0), "Missing oracle address");
- require(beaconDepositAddress != address(0), "Missing beacon deposit address");
- require(functionsBillingRegistryAddress != address(0), "Missing functions billing registry address");
- require(linkRegistrarAddress != address(0), "Missing link registrar address");
- require(linkRegistryAddress != address(0), "Missing link registry address");
- require(linkTokenAddress != address(0), "Missing link token address");
- require(ssvNetworkAddress != address(0), "Missing SSV network address");
- require(ssvTokenAddress != address(0), "Missing SSV token address");
- require(swapFactoryAddress != address(0), "Missing Uniswap factory address");
- require(swapRouterAddress != address(0), "Missing Uniswap router address");
- require(wethTokenAddress != address(0), "Missing WETH token address");
-
+ ) public initializer {
+ onlyAddress(beaconDepositAddress);
+ onlyAddress(daoOracleAddress);
+ onlyAddress(functionsBillingRegistryAddress);
+ onlyAddress(functionsOracleAddress);
+ onlyAddress(keeperRegistrarAddress);
+ onlyAddress(keeperRegistryAddress);
+ onlyAddress(linkTokenAddress);
+ onlyAddress(poolBeaconAddress);
+ onlyAddress(registryBeaconAddress);
+ onlyAddress(ssvNetworkAddress);
+ onlyAddress(ssvTokenAddress);
+ onlyAddress(ssvViewsAddress);
+ onlyAddress(swapFactoryAddress);
+ onlyAddress(swapRouterAddress);
+ onlyAddress(upkeepBeaconAddress);
+ onlyAddress(wethTokenAddress);
+
+ __Ownable_init();
+ __ReentrancyGuard_init();
oracleAddress = daoOracleAddress;
beaconDeposit = IDepositContract(beaconDepositAddress);
- functionsBillingRegistry = IFunctionsBillingRegistry(functionsBillingRegistryAddress);
- linkRegistrar = IKeeperRegistrar(linkRegistrarAddress);
- linkRegistry = IAutomationRegistry(linkRegistryAddress);
+ functionsBillingRegistry = IFunctionsBillingRegistry(
+ functionsBillingRegistryAddress
+ );
+ keeperRegistrar = IKeeperRegistrar(keeperRegistrarAddress);
+ keeperRegistry = IAutomationRegistry(keeperRegistryAddress);
linkToken = LinkTokenInterface(linkTokenAddress);
tokenAddresses[Token.LINK] = linkTokenAddress;
- ssvNetwork = ISSVNetwork(ssvNetworkAddress);
+ poolBeacon = IBeaconUpgradeable(poolBeaconAddress);
+ ssvClusters = ISSVClusters(ssvNetworkAddress);
tokenAddresses[Token.SSV] = ssvTokenAddress;
- ssvToken = IERC20(ssvTokenAddress);
+ ssvToken = IERC20Upgradeable(ssvTokenAddress);
swapFactory = IUniswapV3Factory(swapFactoryAddress);
swapRouter = ISwapRouter(swapRouterAddress);
tokenAddresses[Token.WETH] = wethTokenAddress;
-
- registry = new CasimirRegistry(ssvNetworkViewsAddress);
- upkeep = new CasimirUpkeep(functionsOracleAddress);
+ registry = ICasimirRegistry(
+ CasimirFactory.createRegistry(
+ registryBeaconAddress,
+ ssvViewsAddress
+ )
+ );
+ upkeep = ICasimirUpkeep(
+ CasimirFactory.createUpkeep(
+ upkeepBeaconAddress,
+ functionsOracleAddress
+ )
+ );
+ stakeRatioSum = 1000 ether;
}
/**
@@ -270,8 +250,6 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Deposit user stake
*/
function depositStake() external payable nonReentrant {
- setActionCount(msg.sender);
-
User storage user = users[msg.sender];
uint256 depositAfterFees = subtractFees(msg.value);
reservedFeeBalance += msg.value - depositAfterFees;
@@ -290,9 +268,13 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @param poolId The pool ID
*/
function depositRewards(uint32 poolId) external payable {
- require(msg.value > 0, "No rewards to deposit");
+ if (msg.value == 0) {
+ revert InvalidAmount();
+ }
address poolAddress = poolAddresses[poolId];
- require(msg.sender == poolAddress, "Not pool");
+ if (msg.sender != poolAddress) {
+ revert Unauthorized();
+ }
uint256 rewardsAfterFees = subtractFees(msg.value);
reservedFeeBalance += msg.value - rewardsAfterFees;
@@ -305,9 +287,10 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Deposit exited balance from a given pool ID
* @param poolId The pool ID
*/
- function depositExitedBalance(
- uint32 poolId
- ) external payable onlyPool(poolId) {
+ function depositExitedBalance(uint32 poolId) external payable {
+ if (msg.sender != poolAddresses[poolId]) {
+ revert Unauthorized();
+ }
uint256 balance = msg.value + recoveredBalances[poolId];
delete recoveredBalances[poolId];
delete poolAddresses[poolId];
@@ -324,7 +307,11 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
*/
function depositRecoveredBalance(
uint32 poolId
- ) external payable onlyRegistry {
+ ) external payable {
+ if (msg.sender != address(registry)) {
+ revert Unauthorized();
+ }
+
recoveredBalances[poolId] += msg.value;
finalizableRecoveredBalance += msg.value;
@@ -345,15 +332,16 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
- ) external onlyOracle {
+ ) external {
+ onlyOracle();
uint256 ssvAmount = retrieveFees(
feeAmount,
minimumTokenAmount,
tokenAddresses[Token.SSV],
processed
);
- ssvToken.approve(address(ssvNetwork), ssvAmount);
- ssvNetwork.deposit(address(this), operatorIds, ssvAmount, cluster);
+ ssvToken.approve(address(ssvClusters), ssvAmount);
+ ssvClusters.deposit(address(this), operatorIds, ssvAmount, cluster);
emit ClusterBalanceDeposited(ssvAmount);
}
@@ -368,7 +356,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
- ) external onlyOracle {
+ ) external {
+ onlyOracle();
uint256 linkAmount = retrieveFees(
feeAmount,
minimumTokenAmount,
@@ -376,18 +365,18 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
processed
);
if (functionsId == 0) {
-
functionsId = functionsBillingRegistry.createSubscription();
functionsBillingRegistry.addConsumer(functionsId, address(upkeep));
}
- require(
- linkToken.transferAndCall(
+ if (
+ !linkToken.transferAndCall(
address(functionsBillingRegistry),
linkAmount,
abi.encode(functionsId)
- ),
- "Transfer failed"
- );
+ )
+ ) {
+ revert TransferFailed();
+ }
emit FunctionsBalanceDeposited(linkAmount);
}
@@ -402,16 +391,17 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
- ) external onlyOracle {
+ ) external {
+ onlyOracle();
uint256 linkAmount = retrieveFees(
feeAmount,
minimumTokenAmount,
tokenAddresses[Token.LINK],
processed
);
- linkToken.approve(address(linkRegistrar), linkAmount);
+ linkToken.approve(address(keeperRegistrar), linkAmount);
if (upkeepId == 0) {
- upkeepId = linkRegistrar.registerUpkeep(
+ upkeepId = keeperRegistrar.registerUpkeep(
IKeeperRegistrar.RegistrationParams({
name: string("CasimirV1Upkeep"),
encryptedEmail: new bytes(0),
@@ -424,7 +414,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
})
);
} else {
- linkRegistry.addFunds(upkeepId, uint96(linkAmount));
+ keeperRegistry.addFunds(upkeepId, uint96(linkAmount));
}
emit UpkeepBalanceDeposited(linkAmount);
@@ -444,70 +434,84 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @param amount The amount of fees to withdraw
*/
function withdrawReservedFees(uint256 amount) external onlyOwner {
- require(amount <= reservedFeeBalance, "Withdrawing more than reserved");
+ if (amount > reservedFeeBalance) {
+ revert InvalidAmount();
+ }
reservedFeeBalance -= amount;
- owner().send(amount);
+ (bool success, ) = owner().call{value: amount}("");
+ if (!success) {
+ revert TransferFailed();
+ }
emit ReservedFeesWithdrawn(amount);
}
/**
* @notice Rebalance the rewards to stake ratio and redistribute swept rewards
- * @param activeBalance The active balance
+ * @param beaconBalance The beacon chain balance
* @param sweptBalance The swept balance
* @param activatedDeposits The count of activated deposits
* @param completedExits The count of withdrawn exits
*/
function rebalanceStake(
- uint256 activeBalance,
+ uint256 beaconBalance,
uint256 sweptBalance,
uint256 activatedDeposits,
uint256 completedExits
- ) external onlyUpkeep {
+ ) external {
+ onlyUpkeep();
reportPeriod++;
uint256 expectedActivatedBalance = activatedDeposits * POOL_CAPACITY;
uint256 expectedExitedBalance = completedExits * POOL_CAPACITY;
uint256 expectedEffectiveBalance = stakedPoolIds.length * POOL_CAPACITY;
- int256 rewards = int256(activeBalance + sweptBalance + finalizableRecoveredBalance) - int256(expectedEffectiveBalance + expectedExitedBalance);
+ int256 rewards = int256(
+ beaconBalance + sweptBalance + finalizableRecoveredBalance
+ ) - int256(expectedEffectiveBalance + expectedExitedBalance);
int256 change = rewards - latestActiveRewardBalance;
if (change > 0) {
uint256 gain = uint256(change);
if (rewards > 0) {
uint256 gainAfterFees = subtractFees(gain);
- stakeRatioSum += Math.mulDiv(
+ stakeRatioSum += MathUpgradeable.mulDiv(
stakeRatioSum,
gainAfterFees,
getTotalStake()
);
- latestActiveBalanceAfterFees += gainAfterFees;
+ latestBeaconBalanceAfterFees += gainAfterFees;
emit StakeRebalanced(gainAfterFees);
} else {
- stakeRatioSum += Math.mulDiv(
+ stakeRatioSum += MathUpgradeable.mulDiv(
stakeRatioSum,
gain,
getTotalStake()
);
- latestActiveBalanceAfterFees += gain;
+ latestBeaconBalanceAfterFees += gain;
emit StakeRebalanced(gain);
}
} else if (change < 0) {
uint256 loss = uint256(-change);
- stakeRatioSum -= Math.mulDiv(stakeRatioSum, loss, getTotalStake());
- latestActiveBalanceAfterFees -= loss;
+ stakeRatioSum -= MathUpgradeable.mulDiv(
+ stakeRatioSum,
+ loss,
+ getTotalStake()
+ );
+ latestBeaconBalanceAfterFees -= loss;
emit StakeRebalanced(loss);
}
- int256 sweptRewards = int256(sweptBalance + finalizableRecoveredBalance) - int256(finalizableExitedBalance);
+ int256 sweptRewards = int256(
+ sweptBalance + finalizableRecoveredBalance
+ ) - int256(finalizableExitedBalance);
if (sweptRewards > 0) {
- latestActiveBalanceAfterFees -= subtractFees(uint256(sweptRewards));
+ latestBeaconBalanceAfterFees -= subtractFees(uint256(sweptRewards));
}
- latestActiveBalanceAfterFees -= finalizableExitedBalance;
- latestActiveBalanceAfterFees += expectedActivatedBalance;
+ latestBeaconBalanceAfterFees -= finalizableExitedBalance;
+ latestBeaconBalanceAfterFees += expectedActivatedBalance;
latestActiveRewardBalance = rewards - sweptRewards;
- latestActiveBalance = activeBalance;
+ latestBeaconBalance = beaconBalance;
finalizableExitedBalance = 0;
finalizableRecoveredBalance = 0;
finalizableCompletedExits = 0;
@@ -517,7 +521,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Compound rewards given a list of pool IDs
* @param poolIds The list of pool IDs
*/
- function compoundRewards(uint32[5] memory poolIds) external onlyUpkeep {
+ function compoundRewards(uint32[5] memory poolIds) external {
+ onlyUpkeep();
for (uint256 i = 0; i < poolIds.length; i++) {
uint32 poolId = poolIds[i];
if (poolId == 0) {
@@ -532,18 +537,15 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Request to withdraw user stake
* @param amount The amount of stake to withdraw
*/
- function requestWithdrawal(
- uint256 amount
- ) external nonReentrant {
- setActionCount(msg.sender);
-
+ function requestWithdrawal(uint256 amount) external nonReentrant {
User storage user = users[msg.sender];
user.stake0 = getUserStake(msg.sender);
- require(user.stake0 >= amount, "Withdrawing more than user stake");
+ if (user.stake0 < amount) {
+ revert InvalidAmount();
+ }
user.stakeRatioSum0 = stakeRatioSum;
user.stake0 -= amount;
-
if (amount <= getWithdrawableBalance()) {
if (amount <= exitedBalance) {
exitedBalance -= amount;
@@ -563,7 +565,6 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
);
requestedWithdrawalBalance += amount;
requestedWithdrawals++;
-
uint256 coveredExitBalance = requestedExits * POOL_CAPACITY;
if (requestedWithdrawalBalance > coveredExitBalance) {
uint256 exitsRequired = (requestedWithdrawalBalance -
@@ -586,7 +587,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Fulfill a given count of pending withdrawals
* @param count The number of withdrawals to complete
*/
- function fulfillWithdrawals(uint256 count) external onlyUpkeep {
+ function fulfillWithdrawals(uint256 count) external {
+ onlyUpkeep();
uint256 withdrawalAmount;
uint256 withdrawalCount;
while (count > 0) {
@@ -598,10 +600,9 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
if (withdrawal.period > reportPeriod) {
break;
}
- requestedWithdrawalQueue.remove(0);
+ requestedWithdrawalQueue.removeWithdrawalItem(0);
withdrawalAmount += withdrawal.amount;
withdrawalCount++;
-
fulfillWithdrawal(withdrawal.user, withdrawal.amount);
}
if (withdrawalAmount <= exitedBalance) {
@@ -638,47 +639,61 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
- ) external onlyOracle {
- require(readyPoolIds.length > 0, "No ready pools");
+ ) external {
+ onlyOracle();
+ if (readyPoolIds.length == 0) {
+ revert NoReadyPools();
+ }
uint32 poolId = readyPoolIds[0];
- readyPoolIds.remove(0);
+ readyPoolIds.removeUint32Item(0);
pendingPoolIds.push(poolId);
-
- poolAddresses[poolId] = address(
- new CasimirPool(
- address(registry),
- poolId,
- publicKey,
- operatorIds
- )
+ poolAddresses[poolId] = CasimirFactory.createPool(
+ address(poolBeacon),
+ address(registry),
+ poolId,
+ publicKey,
+ operatorIds
);
-
bytes memory computedWithdrawalCredentials = abi.encodePacked(
bytes1(uint8(1)),
bytes11(0),
poolAddresses[poolId]
);
+ if (
+ keccak256(computedWithdrawalCredentials) !=
+ keccak256(withdrawalCredentials)
+ ) {
+ revert InvalidWithdrawalCredentials();
+ }
- require(
- keccak256(computedWithdrawalCredentials) ==
- keccak256(withdrawalCredentials),
- "Invalid withdrawal credentials"
- );
+ {
+ for (uint256 i = 0; i < operatorIds.length; i++) {
+ registry.addOperatorPool(operatorIds[i], poolId);
+ }
+ beaconDeposit.deposit{value: POOL_CAPACITY}(
+ publicKey,
+ withdrawalCredentials,
+ signature,
+ depositDataRoot
+ );
+ uint256 ssvAmount = retrieveFees(
+ feeAmount,
+ minimumTokenAmount,
+ tokenAddresses[Token.SSV],
+ processed
+ );
+ ssvToken.approve(address(ssvClusters), ssvAmount);
+ ssvClusters.registerValidator(
+ publicKey,
+ operatorIds,
+ shares,
+ ssvAmount,
+ cluster
+ );
- registerPool(
- poolId,
- depositDataRoot,
- publicKey,
- signature,
- withdrawalCredentials,
- operatorIds,
- shares,
- cluster,
- feeAmount,
- minimumTokenAmount,
- processed
- );
+ emit PoolRegistered(poolId);
+ }
emit DepositInitiated(poolId);
}
@@ -687,21 +702,23 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Activate a given count of the next pending pools
* @param count The number of pools to activate
*/
- function activateDeposits(uint256 count) external onlyUpkeep {
- require(pendingPoolIds.length >= count, "Not enough pending pools");
+ function activateDeposits(uint256 count) external {
+ onlyUpkeep();
+ if (pendingPoolIds.length == 0) {
+ revert NoPendingPools();
+ }
while (count > 0) {
count--;
uint32 poolId = pendingPoolIds[0];
ICasimirPool pool = ICasimirPool(poolAddresses[poolId]);
ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
- require(
- poolDetails.status == ICasimirPool.PoolStatus.PENDING,
- "Pool not pending"
- );
+ if (poolDetails.status != ICasimirPool.PoolStatus.PENDING) {
+ revert PoolNotPending();
+ }
pool.setStatus(ICasimirPool.PoolStatus.ACTIVE);
- pendingPoolIds.remove(0);
+ pendingPoolIds.removeUint32Item(0);
stakedPoolIds.push(poolId);
emit DepositActivated(poolId);
@@ -712,7 +729,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Request reports a given count of forced exits
* @param count The number of forced exits
*/
- function requestForcedExitReports(uint256 count) external onlyUpkeep {
+ function requestForcedExitReports(uint256 count) external {
+ onlyUpkeep();
emit ForcedExitReportsRequested(count);
}
@@ -720,7 +738,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Request reports for a given count of completed exits
* @param count The number of completed exits
*/
- function requestCompletedExitReports(uint256 count) external onlyUpkeep {
+ function requestCompletedExitReports(uint256 count) external {
+ onlyUpkeep();
emit CompletedExitReportsRequested(count);
}
@@ -728,7 +747,11 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Request reshares for an operator
* @param operatorId The operator ID
*/
- function requestReshares(uint64 operatorId) external onlyOracleOrRegistry {
+ function requestReshares(uint64 operatorId) external {
+ if (msg.sender != oracleAddress && msg.sender != address(registry)) {
+ revert Unauthorized();
+ }
+
emit ResharesRequested(operatorId);
}
@@ -736,20 +759,22 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Report pool forced (unrequested) exits
* @param poolIds The pool IDs
*/
- function reportForcedExits(uint32[] memory poolIds) external onlyOracle {
+ function reportForcedExits(uint32[] memory poolIds) external {
+ onlyOracle();
uint256 newForcedExits;
uint256 newRequestedExits;
for (uint256 i = 0; i < poolIds.length; i++) {
uint32 poolId = poolIds[i];
ICasimirPool pool = ICasimirPool(poolAddresses[poolId]);
ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
- require(
- poolDetails.status != ICasimirPool.PoolStatus.EXITING_FORCED,
- "Forced exit already reported"
- );
+ if (poolDetails.status == ICasimirPool.PoolStatus.EXITING_FORCED) {
+ revert ForcedExitAlreadyReported();
+ }
newForcedExits++;
- if (poolDetails.status == ICasimirPool.PoolStatus.EXITING_REQUESTED) {
+ if (
+ poolDetails.status == ICasimirPool.PoolStatus.EXITING_REQUESTED
+ ) {
newRequestedExits++;
}
pool.setStatus(ICasimirPool.PoolStatus.EXITING_FORCED);
@@ -770,18 +795,19 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 poolIndex,
uint32[] memory blamePercents,
ISSVNetworkCore.Cluster memory cluster
- ) external onlyOracle {
+ ) external {
+ onlyOracle();
uint32 poolId = stakedPoolIds[poolIndex];
ICasimirPool pool = ICasimirPool(poolAddresses[poolId]);
ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
- require(
- poolDetails.status == ICasimirPool.PoolStatus.EXITING_FORCED ||
- poolDetails.status == ICasimirPool.PoolStatus.EXITING_REQUESTED,
- "Pool not exiting"
- );
-
- stakedPoolIds.remove(poolIndex);
+ if (
+ poolDetails.status != ICasimirPool.PoolStatus.EXITING_FORCED &&
+ poolDetails.status != ICasimirPool.PoolStatus.EXITING_REQUESTED
+ ) {
+ revert PoolNotExiting();
+ }
+ stakedPoolIds.removeUint32Item(poolIndex);
if (poolDetails.status == ICasimirPool.PoolStatus.EXITING_REQUESTED) {
requestedExits--;
} else if (
@@ -789,10 +815,13 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
) {
forcedExits--;
}
-
pool.setStatus(ICasimirPool.PoolStatus.WITHDRAWN);
pool.withdrawBalance(blamePercents);
- ssvNetwork.removeValidator(poolDetails.publicKey, poolDetails.operatorIds, cluster);
+ ssvClusters.removeValidator(
+ poolDetails.publicKey,
+ poolDetails.operatorIds,
+ cluster
+ );
emit ExitCompleted(poolId);
}
@@ -823,15 +852,19 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
- ) external onlyOracle {
+ ) external {
+ onlyOracle();
ICasimirPool pool = ICasimirPool(poolAddresses[poolId]);
ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
- require(
- poolDetails.status == ICasimirPool.PoolStatus.PENDING ||
- poolDetails.status == ICasimirPool.PoolStatus.ACTIVE,
- "Pool not active"
- );
- require(poolDetails.reshares < 2, "Pool already reshared twice");
+ if (
+ poolDetails.status != ICasimirPool.PoolStatus.ACTIVE &&
+ poolDetails.status != ICasimirPool.PoolStatus.PENDING
+ ) {
+ revert PoolNotActive();
+ }
+ if (poolDetails.reshares >= 2) {
+ revert PoolAlreadyReshared();
+ }
pool.setReshares(poolDetails.reshares + 1);
@@ -844,15 +877,15 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
tokenAddresses[Token.SSV],
processed
);
- ssvToken.approve(address(ssvNetwork), ssvAmount);
+ ssvToken.approve(address(ssvClusters), ssvAmount);
- ssvNetwork.removeValidator(
+ ssvClusters.removeValidator(
poolDetails.publicKey,
oldOperatorIds,
oldCluster
);
- ssvNetwork.registerValidator(
+ ssvClusters.registerValidator(
poolDetails.publicKey,
operatorIds,
shares,
@@ -873,14 +906,16 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
uint64[] memory operatorIds,
ISSVNetworkCore.Cluster memory cluster,
uint256 amount
- ) external onlyOracle {
- ssvNetwork.withdraw(operatorIds, amount, cluster);
+ ) external {
+ onlyOracle();
+ ssvClusters.withdraw(operatorIds, amount, cluster);
}
/**
* @notice Cancel the Chainlink functions subscription
*/
- function cancelFunctions() external onlyOracle {
+ function cancelFunctions() external {
+ onlyOracle();
functionsBillingRegistry.cancelSubscription(functionsId, address(this));
functionsId = 0;
@@ -890,8 +925,9 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
/**
* @notice Cancel the Chainlink upkeep subscription
*/
- function cancelUpkeep() external onlyOracle {
- linkRegistry.cancelUpkeep(upkeepId);
+ function cancelUpkeep() external {
+ onlyOracle();
+ keeperRegistry.cancelUpkeep(upkeepId);
upkeepId = 0;
emit UpkeepCancelled();
@@ -902,7 +938,9 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @param amount The amount to withdraw
*/
function withdrawLINKBalance(uint256 amount) external onlyOwner {
- require(linkToken.transfer(owner(), amount), "Transfer failed");
+ if (!linkToken.transfer(owner(), amount)) {
+ revert TransferFailed();
+ }
emit LINKBalanceWithdrawn(amount);
}
@@ -912,41 +950,61 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @param amount The amount to withdraw
*/
function withdrawSSVBalance(uint256 amount) external onlyOwner {
- SafeERC20.safeTransfer(ssvToken, owner(), amount);
+ SafeERC20Upgradeable.safeTransfer(ssvToken, owner(), amount);
emit SSVBalanceWithdrawn(amount);
}
/**
* Set a new Chainlink functions request
- * @param newRequestCBOR The new Chainlink functions request CBOR
- * @param newFulfillGasLimit The new Chainlink functions fulfill gas limit
+ * @param newRequestSource JavaScript source code
+ * @param newRequestArgs List of arguments accessible from within the source code
+ * @param newFulfillGasLimit The new Chainlink functions fulfill gas limit
*/
function setFunctionsRequest(
- bytes calldata newRequestCBOR,
+ string calldata newRequestSource,
+ string[] calldata newRequestArgs,
uint32 newFulfillGasLimit
) external onlyOwner {
- upkeep.setRequest(newRequestCBOR, newFulfillGasLimit);
+ upkeep.setFunctionsRequest(
+ newRequestSource,
+ newRequestArgs,
+ newFulfillGasLimit
+ );
- emit FunctionsRequestSet(newRequestCBOR, newFulfillGasLimit);
+ emit FunctionsRequestSet(
+ newRequestSource,
+ newRequestArgs,
+ newFulfillGasLimit
+ );
}
/**
* @notice Set a new Chainlink functions oracle address
* @param newFunctionsOracleAddress New Chainlink functions oracle address
*/
- function setFunctionsOracleAddress(address newFunctionsOracleAddress) external onlyOwner {
- upkeep.setOracleAddress(newFunctionsOracleAddress);
+ function setFunctionsOracleAddress(
+ address newFunctionsOracleAddress
+ ) external onlyOwner {
+ upkeep.setFunctionsOracleAddress(newFunctionsOracleAddress);
emit FunctionsOracleAddressSet(newFunctionsOracleAddress);
}
/**
- * @notice Get the ready pool IDs
- * @return readyPoolIds The ready pool IDs
+ * @notice Get the eligibility of a pending withdrawal
+ * @param index The index of the pending withdrawal
+ * @param period The period to check
+ * @return pendingWithdrawalEligibility The eligibility of a pending withdrawal
*/
- function getReadyPoolIds() external view returns (uint32[] memory) {
- return readyPoolIds;
+ function getPendingWithdrawalEligibility(
+ uint256 index,
+ uint256 period
+ ) external view returns (bool pendingWithdrawalEligibility) {
+ if (requestedWithdrawals > index) {
+ pendingWithdrawalEligibility =
+ requestedWithdrawalQueue[index].period <= period;
+ }
}
/**
@@ -978,7 +1036,11 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Get the registry address
* @return registryAddress The registry address
*/
- function getRegistryAddress() external view returns (address registryAddress) {
+ function getRegistryAddress()
+ external
+ view
+ returns (address registryAddress)
+ {
registryAddress = address(registry);
}
@@ -998,7 +1060,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
function getUserStake(
address userAddress
) public view returns (uint256 userStake) {
- userStake = Math.mulDiv(
+ userStake = MathUpgradeable.mulDiv(
users[userAddress].stake0,
stakeRatioSum,
users[userAddress].stakeRatioSum0
@@ -1012,7 +1074,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
function getTotalStake() public view returns (uint256 totalStake) {
totalStake =
getBufferedBalance() +
- latestActiveBalanceAfterFees -
+ latestBeaconBalanceAfterFees -
requestedWithdrawalBalance;
}
@@ -1020,16 +1082,12 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @notice Get the buffered balance
* @return bufferedBalance The buffered balance
*/
- function getBufferedBalance() public view returns (uint256 bufferedBalance) {
- bufferedBalance = getWithdrawableBalance() + getReadyBalance();
- }
-
- /**
- * @notice Get the ready balance
- * @return readyBalance The ready balance
- */
- function getReadyBalance() public view returns (uint256 readyBalance) {
- readyBalance = readyPoolIds.length * POOL_CAPACITY;
+ function getBufferedBalance()
+ public
+ view
+ returns (uint256 bufferedBalance)
+ {
+ bufferedBalance = getWithdrawableBalance() + readyPoolIds.length * POOL_CAPACITY;
}
/**
@@ -1040,21 +1098,6 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
return prepoolBalance + exitedBalance;
}
- /**
- * @notice Get the eligibility of a pending withdrawal
- * @param index The index of the pending withdrawal
- * @param period The period to check
- * @return pendingWithdrawalEligibility The eligibility of a pending withdrawal
- */
- function getPendingWithdrawalEligibility(
- uint256 index,
- uint256 period
- ) public view returns (bool pendingWithdrawalEligibility) {
- if (requestedWithdrawals > index) {
- pendingWithdrawalEligibility = requestedWithdrawalQueue[index].period <= period;
- }
- }
-
/**
* @notice Deposit the current tip balance
*/
@@ -1095,86 +1138,12 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
* @param amount The withdrawal amount
*/
function fulfillWithdrawal(address sender, uint256 amount) private {
- sender.send(amount);
-
- emit WithdrawalFulfilled(sender, amount);
- }
-
- /**
- * Check and set a user's action count
- * @param userAddress The user address to check
- */
- function setActionCount(address userAddress) private {
- User storage user = users[userAddress];
- require(
- user.actionPeriodTimestamp == 0 ||
- user.actionCount < MAX_ACTIONS_PER_PERIOD ||
- block.timestamp >= user.actionPeriodTimestamp + ACTION_PERIOD,
- "Action period maximum reached"
- );
- if (block.timestamp >= user.actionPeriodTimestamp + ACTION_PERIOD) {
- user.actionPeriodTimestamp = block.timestamp;
- user.actionCount = 1;
- } else {
- user.actionCount++;
- }
- }
-
- /**
- * @dev Register a pool with Beacon and SSV
- * @param poolId The pool ID
- * @param depositDataRoot The deposit data root
- * @param publicKey The validator public key
- * @param signature The signature
- * @param withdrawalCredentials The withdrawal credentials
- * @param operatorIds The operator IDs
- * @param shares The operator shares
- * @param cluster The SSV cluster snapshot
- * @param feeAmount The fee amount to deposit
- * @param minimumTokenAmount The minimum SSV token amount out after processing fees
- * @param processed Whether the fee amount is already processed
- */
- function registerPool(
- uint32 poolId,
- bytes32 depositDataRoot,
- bytes memory publicKey,
- bytes memory signature,
- bytes memory withdrawalCredentials,
- uint64[] memory operatorIds,
- bytes memory shares,
- ISSVNetworkCore.Cluster memory cluster,
- uint256 feeAmount,
- uint256 minimumTokenAmount,
- bool processed
- ) private {
- for (uint256 i = 0; i < operatorIds.length; i++) {
- registry.addOperatorPool(operatorIds[i], poolId);
+ (bool success, ) = sender.call{value: amount}("");
+ if (!success) {
+ revert TransferFailed();
}
- beaconDeposit.deposit{value: POOL_CAPACITY}(
- publicKey,
- withdrawalCredentials,
- signature,
- depositDataRoot
- );
-
- uint256 ssvAmount = retrieveFees(
- feeAmount,
- minimumTokenAmount,
- tokenAddresses[Token.SSV],
- processed
- );
- ssvToken.approve(address(ssvNetwork), ssvAmount);
-
- ssvNetwork.registerValidator(
- publicKey,
- operatorIds,
- shares,
- ssvAmount,
- cluster
- );
-
- emit PoolRegistered(poolId);
+ emit WithdrawalFulfilled(sender, amount);
}
/**
@@ -1193,7 +1162,6 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
) {
count--;
index++;
-
pool.setStatus(ICasimirPool.PoolStatus.EXITING_REQUESTED);
requestedExits++;
@@ -1241,7 +1209,6 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
address(swapRouter),
wethToken.balanceOf(address(this))
);
-
IUniswapV3PoolState swapPool = IUniswapV3PoolState(
swapFactory.getPool(
tokenAddresses[Token.WETH],
@@ -1249,7 +1216,9 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
UNISWAP_FEE_TIER
)
);
- require(swapPool.liquidity() >= amount, "Not enough liquidity");
+ if (swapPool.liquidity() < amount) {
+ revert InsufficientLiquidity();
+ }
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
@@ -1273,6 +1242,37 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
function subtractFees(
uint256 amount
) private pure returns (uint256 amountAfterFees) {
- amountAfterFees = Math.mulDiv(amount, 100, 100 + FEE_PERCENT);
+ amountAfterFees = MathUpgradeable.mulDiv(
+ amount,
+ 100,
+ 100 + FEE_PERCENT
+ );
+ }
+
+ /**
+ * @dev Validate the caller is the oracle
+ */
+ function onlyOracle() private view {
+ if (msg.sender != oracleAddress) {
+ revert Unauthorized();
+ }
+ }
+
+ /**
+ * @dev Validate the caller is the upkeep contract
+ */
+ function onlyUpkeep() private view {
+ if (msg.sender != address(upkeep)) {
+ revert Unauthorized();
+ }
+ }
+
+ /**
+ * @dev Validate an address is not the zero address
+ */
+ function onlyAddress(address checkAddress) private pure {
+ if (checkAddress == address(0)) {
+ revert InvalidAddress();
+ }
}
}
diff --git a/contracts/ethereum/src/v1/CasimirPool.sol b/contracts/ethereum/src/v1/CasimirPool.sol
index d55b2a3c5..ddb665285 100644
--- a/contracts/ethereum/src/v1/CasimirPool.sol
+++ b/contracts/ethereum/src/v1/CasimirPool.sol
@@ -4,14 +4,15 @@ pragma solidity 0.8.18;
import "./interfaces/ICasimirPool.sol";
import "./interfaces/ICasimirManager.sol";
import "./interfaces/ICasimirRegistry.sol";
-import "@openzeppelin/contracts/utils/math/Math.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
-import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
/**
* @title Pool contract that accepts deposits and stakes a validator
*/
-contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard {
+contract CasimirPool is ICasimirPool, Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
/*************/
/* Constants */
/*************/
@@ -19,21 +20,16 @@ contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard {
/** Pool capacity */
uint256 private constant POOL_CAPACITY = 32 ether;
- /*************/
- /* Immutable */
- /*************/
-
- /** Manager contract */
- ICasimirManager private immutable manager;
- /** Registry contract */
- ICasimirRegistry private immutable registry;
-
/*********/
/* State */
/*********/
+ /** Manager contract */
+ ICasimirManager private manager;
+ /** Registry contract */
+ ICasimirRegistry private registry;
/** Pool ID */
- uint32 private immutable id;
+ uint32 private id;
/** Validator public key */
bytes private publicKey;
/** Operator IDs */
@@ -42,22 +38,33 @@ contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard {
uint256 private reshares;
/** Status */
PoolStatus private status;
+ /** Storage gap */
+ uint256[50] private __gap;
+
+ // @custom:oz-upgrades-unsafe-allow constructor
+ constructor() {
+ _disableInitializers();
+ }
/**
- * @notice Constructor
+ * @notice Initialize the contract
* @param registryAddress The registry address
* @param _id The pool ID
* @param _publicKey The validator public key
* @param _operatorIds The operator IDs
*/
- constructor(
+ function initialize(
address registryAddress,
uint32 _id,
bytes memory _publicKey,
uint64[] memory _operatorIds
- ) {
- require(registryAddress != address(0), "Missing registry address");
-
+ ) public initializer {
+ if (registryAddress == address(0)) {
+ revert InvalidAddress();
+ }
+
+ __Ownable_init();
+ __ReentrancyGuard_init();
manager = ICasimirManager(msg.sender);
registry = ICasimirRegistry(registryAddress);
id = _id;
@@ -69,7 +76,9 @@ contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard {
* @notice Deposit rewards from a pool to the manager
*/
function depositRewards() external onlyOwner {
- require(status == PoolStatus.ACTIVE, "Pool must be active");
+ if (status != PoolStatus.ACTIVE) {
+ revert Inactive();
+ }
uint256 balance = address(this).balance;
manager.depositRewards{value: balance}(id);
@@ -80,7 +89,9 @@ contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard {
* @param blamePercents The operator loss blame percents
*/
function withdrawBalance(uint32[] memory blamePercents) external onlyOwner {
- require(status == PoolStatus.WITHDRAWN, "Pool must be withdrawn");
+ if (status != PoolStatus.WITHDRAWN) {
+ revert NotWithdrawn();
+ }
uint256 balance = address(this).balance;
int256 rewards = int256(balance) - int256(POOL_CAPACITY);
@@ -91,7 +102,7 @@ contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard {
uint256 blameAmount;
if (rewards < 0) {
uint256 blamePercent = blamePercents[i];
- blameAmount = Math.mulDiv(uint256(-rewards), blamePercent, 100);
+ blameAmount = MathUpgradeable.mulDiv(uint256(-rewards), blamePercent, 100);
}
registry.removeOperatorPool(operatorIds[i], id, blameAmount);
}
diff --git a/contracts/ethereum/src/v1/CasimirRegistry.sol b/contracts/ethereum/src/v1/CasimirRegistry.sol
index f5998b202..1089e3807 100644
--- a/contracts/ethereum/src/v1/CasimirRegistry.sol
+++ b/contracts/ethereum/src/v1/CasimirRegistry.sol
@@ -3,21 +3,15 @@ pragma solidity 0.8.18;
import "./interfaces/ICasimirRegistry.sol";
import "./interfaces/ICasimirManager.sol";
-import "./libraries/Types.sol";
-import "./vendor/interfaces/ISSVNetworkViews.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
+import "./vendor/interfaces/ISSVViews.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
/**
* @title Registry contract that manages operators
*/
-contract CasimirRegistry is ICasimirRegistry, Ownable {
- /*************/
- /* Libraries */
- /*************/
-
- /** Use internal type for address */
- using TypesAddress for address;
-
+contract CasimirRegistry is ICasimirRegistry, Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
/*************/
/* Constants */
/*************/
@@ -25,25 +19,22 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
/** Required collateral per operator per pool */
uint256 private constant REQUIRED_COLLATERAL = 1 ether;
- /*************/
- /* Immutable */
- /*************/
-
- /** Manager contract */
- ICasimirManager private immutable manager;
- /** SSV network views contract */
- ISSVNetworkViews private immutable ssvNetworkViews;
-
/*********/
/* State */
/*********/
+ /** Manager contract */
+ ICasimirManager private manager;
+ /** SSV views contract */
+ ISSVViews private ssvViews;
/** Operator IDs */
uint64[] private operatorIds;
/** Operators */
mapping(uint64 => Operator) private operators;
/** Operator pools */
mapping(uint64 => mapping(uint32 => bool)) private operatorPools;
+ /** Storage gap */
+ uint256[50] private __gap;
/*************/
/* Modifiers */
@@ -53,26 +44,33 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
* @dev Validate the caller is owner or the authorized pool
*/
modifier onlyOwnerOrPool(uint32 poolId) {
- require(
- msg.sender == owner() ||
- msg.sender == manager.getPoolAddress(poolId),
- "Only owner or the authorized pool can call this function"
- );
+ if (
+ msg.sender != owner() &&
+ msg.sender != manager.getPoolAddress(poolId)
+ ) {
+ revert Unauthorized();
+ }
_;
}
+ // @custom:oz-upgrades-unsafe-allow constructor
+ constructor() {
+ _disableInitializers();
+ }
+
/**
- * @notice Constructor
- * @param ssvNetworkViewsAddress The SSV network views address
+ * @notice Initialize the contract
+ * @param ssvViewsAddress The SSV views address
*/
- constructor(address ssvNetworkViewsAddress) {
- require(
- ssvNetworkViewsAddress != address(0),
- "Missing SSV network views address"
- );
-
+ function initialize(address ssvViewsAddress) public initializer {
+ if (ssvViewsAddress == address(0)) {
+ revert InvalidAddress();
+ }
+
+ __Ownable_init();
+ __ReentrancyGuard_init();
manager = ICasimirManager(msg.sender);
- ssvNetworkViews = ISSVNetworkViews(ssvNetworkViewsAddress);
+ ssvViews = ISSVViews(ssvViewsAddress);
}
/**
@@ -80,16 +78,16 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
* @param operatorId The operator ID
*/
function registerOperator(uint64 operatorId) external payable {
- (address operatorOwner, , , , ) = ssvNetworkViews.getOperatorById(
+ (address operatorOwner, , , , , ) = ssvViews.getOperatorById(
operatorId
);
- require(
- msg.sender == operatorOwner,
- "Only operator owner can register"
- );
- require(operatorId != 0, "Invalid operator ID");
+ if (msg.sender != operatorOwner) {
+ revert Unauthorized();
+ }
Operator storage operator = operators[operatorId];
- require(operator.id == 0, "Operator already registered");
+ if (operator.id != 0) {
+ revert AlreadyRegistered();
+ }
operatorIds.push(operatorId);
operator.id = operatorId;
@@ -105,13 +103,12 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
*/
function depositCollateral(uint64 operatorId) external payable {
Operator storage operator = operators[operatorId];
- (address operatorOwner, , , , ) = ssvNetworkViews.getOperatorById(
+ (address operatorOwner, , , , , ) = ssvViews.getOperatorById(
operatorId
);
- require(
- msg.sender == operatorOwner,
- "Only operator owner can deposit collateral"
- );
+ if (msg.sender != operatorOwner) {
+ revert Unauthorized();
+ }
operator.collateral += msg.value;
operator.active = true;
@@ -126,19 +123,21 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
*/
function requestWithdrawal(uint64 operatorId, uint256 amount) external {
Operator storage operator = operators[operatorId];
- (address operatorOwner, , , , ) = ssvNetworkViews.getOperatorById(
+ (address operatorOwner, , , , , ) = ssvViews.getOperatorById(
operatorId
);
- require(msg.sender == operatorOwner, "Not operator owner");
- require(
- !operator.active &&
- !operator.resharing &&
- operator.collateral >= amount,
- "Not allowed to withdraw amount"
- );
+ if (msg.sender != operatorOwner) {
+ revert Unauthorized();
+ }
+ if (operator.active || operator.resharing || operator.collateral < amount) {
+ revert InvalidAmount();
+ }
operator.collateral -= amount;
- operatorOwner.send(amount);
+ (bool success, ) = operatorOwner.call{value: amount}("");
+ if (!success) {
+ revert TransferFailed();
+ }
emit WithdrawalFulfilled(operatorId, amount);
}
@@ -149,12 +148,18 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
*/
function requestDeactivation(uint64 operatorId) external {
Operator storage operator = operators[operatorId];
- (address operatorOwner, , , , ) = ssvNetworkViews.getOperatorById(
+ (address operatorOwner, , , , , ) = ssvViews.getOperatorById(
operatorId
);
- require(msg.sender == operatorOwner, "Not operator owner");
- require(operator.active, "Operator is not active");
- require(!operator.resharing, "Operator is resharing");
+ if (msg.sender != operatorOwner) {
+ revert Unauthorized();
+ }
+ if (!operator.active) {
+ revert Inactive();
+ }
+ if (operator.resharing) {
+ revert Resharing();
+ }
if (operator.poolCount == 0) {
operator.active = false;
@@ -176,12 +181,20 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
uint32 poolId
) external onlyOwner {
Operator storage operator = operators[operatorId];
- require(operator.active, "Operator not active");
- require(!operator.resharing, "Operator resharing");
- require(!operatorPools[operatorId][poolId], "Pool already active");
+ if (!operator.active) {
+ revert Inactive();
+ }
+ if (operator.resharing) {
+ revert Resharing();
+ }
+ if (operatorPools[operatorId][poolId]) {
+ revert AlreadyExists();
+ }
uint256 eligiblePools = (operator.collateral / REQUIRED_COLLATERAL) -
operator.poolCount;
- require(eligiblePools > 0, "No remaining eligible pools");
+ if (eligiblePools == 0) {
+ revert InsufficientCollateral();
+ }
operatorPools[operatorId][poolId] = true;
operator.poolCount += 1;
@@ -201,23 +214,19 @@ contract CasimirRegistry is ICasimirRegistry, Ownable {
uint256 blameAmount
) external onlyOwnerOrPool(poolId) {
Operator storage operator = operators[operatorId];
- require(
- operatorPools[operatorId][poolId],
- "Pool is not active for operator"
- );
- require(
- blameAmount <= REQUIRED_COLLATERAL,
- "Blame amount is more than collateral"
- );
+ if (!operatorPools[operatorId][poolId]) {
+ revert DoesNotExist();
+ }
+ if (blameAmount > REQUIRED_COLLATERAL) {
+ revert InvalidAmount();
+ }
operatorPools[operatorId][poolId] = false;
operator.poolCount -= 1;
-
if (operator.poolCount == 0 && operator.resharing) {
operator.active = false;
operator.resharing = false;
}
-
if (blameAmount > 0) {
operator.collateral -= blameAmount;
manager.depositRecoveredBalance{value: blameAmount}(poolId);
diff --git a/contracts/ethereum/src/v1/CasimirUpkeep.sol b/contracts/ethereum/src/v1/CasimirUpkeep.sol
index 2820d4e3f..19c3ee53e 100644
--- a/contracts/ethereum/src/v1/CasimirUpkeep.sol
+++ b/contracts/ethereum/src/v1/CasimirUpkeep.sol
@@ -4,13 +4,15 @@ pragma solidity 0.8.18;
import "./interfaces/ICasimirUpkeep.sol";
import "./interfaces/ICasimirManager.sol";
import "./vendor/FunctionsClient.sol";
-import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-import "@openzeppelin/contracts/access/Ownable.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
+import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
/**
- * @title Upkeep contract that automates and handles reports
+ * @title Upkeep contract that automates reporting operations
*/
-contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
+contract CasimirUpkeep is ICasimirUpkeep, Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable, FunctionsClient {
/*************/
/* Libraries */
/*************/
@@ -22,20 +24,18 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
/* Constants */
/*************/
- /** Oracle heartbeat */
+ /** Report-to-report heartbeat duration */
uint256 private constant REPORT_HEARTBEAT = 1 days;
- /*************/
- /* Immutable */
- /*************/
-
- /** Manager contract */
- ICasimirManager private immutable manager;
/*********/
/* State */
/*********/
+ /** Manager contract */
+ ICasimirManager private manager;
+ /** Previous report timestamp */
+ uint256 private previousReportTimestamp;
/** Current report status */
ReportStatus private reportStatus;
/** Current report period */
@@ -48,8 +48,8 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
uint256 private reportTimestamp;
/** Current report swept balance */
uint256 private reportSweptBalance;
- /** Current report active balance */
- uint256 private reportActiveBalance;
+ /** Current report beacon chain balance */
+ uint256 private reportBeaconBalance;
/** Current report deposit activations */
uint256 private reportActivatedDeposits;
/** Current report unexpected exits */
@@ -66,43 +66,71 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
mapping(bytes32 => RequestType) private reportRequests;
/** Current report response error */
bytes private reportResponseError;
- /** Binary request source code */
- bytes private requestCBOR;
+ /** Request source */
+ string requestSource;
+ /** Default request arguments */
+ string[] public defaultRequestArgs;
/** Fulfillment gas limit */
- uint32 private fulfillGasLimit;
+ uint32 public fulfillGasLimit;
+ /** Storage gap */
+ uint256[50] private __gap;
- /***************/
- /* Constructor */
- /***************/
+ // @custom:oz-upgrades-unsafe-allow constructor
+ constructor() FunctionsClient(address(0)) {
+ _disableInitializers();
+ }
/**
- * Constructor
+ * Initialize the contract
* @param functionsOracleAddress The Chainlink functions oracle address
*/
- constructor(
+ function initialize(
address functionsOracleAddress
- ) FunctionsClient(functionsOracleAddress) {
- require(
- functionsOracleAddress != address(0),
- "Missing functions oracle address"
- );
+ ) public initializer {
+ if (functionsOracleAddress == address(0)) {
+ revert InvalidAddress();
+ }
+ __Ownable_init();
+ __ReentrancyGuard_init();
+ setOracle(functionsOracleAddress);
manager = ICasimirManager(msg.sender);
}
+ /**
+ * @notice Set a new Chainlink functions oracle address
+ * @param newFunctionsOracleAddress New Chainlink functions oracle address
+ */
+ function setFunctionsOracleAddress(address newFunctionsOracleAddress) external onlyOwner {
+ if (newFunctionsOracleAddress == address(0)) {
+ revert InvalidAddress();
+ }
+
+ setOracle(newFunctionsOracleAddress);
+
+ emit FunctionsOracleAddressSet(newFunctionsOracleAddress);
+ }
+
/**
* Set a new Chainlink functions request
- * @param newRequestCBOR The new Chainlink functions request CBOR
+ * @param newRequestSource JavaScript source code
+ * @param newRequestArgs List of arguments accessible from within the source code
* @param newFulfillGasLimit The new Chainlink functions fulfill gas limit
*/
- function setRequest(
- bytes calldata newRequestCBOR,
+ function setFunctionsRequest(
+ string calldata newRequestSource,
+ string[] calldata newRequestArgs,
uint32 newFulfillGasLimit
) external onlyOwner {
- requestCBOR = newRequestCBOR;
+ requestSource = newRequestSource;
+ defaultRequestArgs = newRequestArgs;
fulfillGasLimit = newFulfillGasLimit;
- emit RequestSet(newRequestCBOR, newFulfillGasLimit);
+ emit FunctionsRequestSet(
+ newRequestSource,
+ newRequestArgs,
+ newFulfillGasLimit
+ );
}
/**
@@ -110,22 +138,28 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
*/
function performUpkeep(bytes calldata) external override {
(bool upkeepNeeded, ) = checkUpkeep("");
- require(upkeepNeeded, "Upkeep not needed");
+ if (!upkeepNeeded) {
+ revert NotNeeded();
+ }
if (reportStatus == ReportStatus.FINALIZED) {
+ previousReportTimestamp = reportTimestamp;
reportStatus = ReportStatus.REQUESTING;
reportRequestBlock = block.number;
reportTimestamp = block.timestamp;
reportPeriod = manager.reportPeriod();
- uint64 functionsId = manager.functionsId();
- reportRemainingRequests = 2;
- for (uint256 i = 0; i < reportRemainingRequests; i++) {
- bytes32 requestId = s_oracle.sendRequest(functionsId, requestCBOR, fulfillGasLimit);
- s_pendingRequests[requestId] = s_oracle.getRegistry();
- reportRequests[requestId] = RequestType(i + 1);
-
- emit RequestSent(requestId);
- }
+ Functions.Request memory request;
+ request.initializeRequest(
+ Functions.Location.Inline,
+ Functions.CodeLanguage.JavaScript,
+ requestSource
+ );
+ string[] memory requestArgs = defaultRequestArgs;
+ requestArgs[7] = StringsUpgradeable.toString(previousReportTimestamp);
+ requestArgs[8] = StringsUpgradeable.toString(reportTimestamp);
+ requestArgs[9] = StringsUpgradeable.toString(reportRequestBlock);
+ sendFunctionsRequest(request, requestArgs, RequestType.BALANCES);
+ sendFunctionsRequest(request, requestArgs, RequestType.DETAILS);
} else {
if (
manager.requestedWithdrawalBalance() > 0 &&
@@ -142,13 +176,13 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
if (!manager.getPendingWithdrawalEligibility(0, reportPeriod) && finalizableActivatedDeposits == 0) {
reportStatus = ReportStatus.FINALIZED;
manager.rebalanceStake({
- activeBalance: reportActiveBalance,
+ beaconBalance: reportBeaconBalance,
sweptBalance: reportSweptBalance,
activatedDeposits: reportActivatedDeposits,
completedExits: reportCompletedExits
});
manager.compoundRewards(reportCompoundablePoolIds);
- reportActiveBalance = 0;
+ reportBeaconBalance = 0;
reportActivatedDeposits = 0;
reportForcedExits = 0;
reportCompletedExits = 0;
@@ -159,47 +193,6 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
emit UpkeepPerformed(reportStatus);
}
- /**
- * @notice Set a new Chainlink functions oracle address
- * @param newOracleAddress New Chainlink functions oracle address
- */
- function setOracleAddress(address newOracleAddress) external onlyOwner {
- require (
- newOracleAddress != address(0),
- "Missing oracle address"
- );
-
- setOracle(newOracleAddress);
-
- emit OracleAddressSet(newOracleAddress);
- }
-
- /**
- * @notice Generate a new Functions.Request(off-chain, saving gas)
- * @param source JavaScript source code
- * @param secrets Encrypted secrets payload
- * @param args List of arguments accessible from within the source code
- */
- function generateRequest(
- string calldata source,
- bytes calldata secrets,
- string[] calldata args
- ) external pure returns (bytes memory) {
- Functions.Request memory req;
- req.initializeRequest(
- Functions.Location.Inline,
- Functions.CodeLanguage.JavaScript,
- source
- );
- if (secrets.length > 0) {
- req.addRemoteSecrets(secrets);
- }
- if (args.length > 0) {
- req.addArgs(args);
- }
- return req.encodeCBOR();
- }
-
/**
* @notice Check if the upkeep is needed
* @return upkeepNeeded True if the upkeep is needed
@@ -210,7 +203,7 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
public
view
override
- returns (bool upkeepNeeded, bytes memory)
+ returns (bool upkeepNeeded, bytes memory checkData)
{
if (reportStatus == ReportStatus.FINALIZED) {
bool checkActive = manager.getPendingPoolIds().length + manager.getStakedPoolIds().length > 0;
@@ -220,33 +213,36 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
bool finalizeReport = reportCompletedExits == manager.finalizableCompletedExits();
upkeepNeeded = finalizeReport;
}
+ return (upkeepNeeded, checkData);
}
/**
* @notice Callback that is invoked once the DON has resolved the request or hit an error
* @param requestId The request ID, returned by sendRequest()
- * @param response Aggregated response from the user code
- * @param _error Aggregated error from the user code or from the sweptStake pipeline
+ * @param response Aggregated response from the DON
+ * @param executionError Aggregated error from the code execution
* Either response or error parameter will be set, but never both
*/
function fulfillRequest(
bytes32 requestId,
bytes memory response,
- bytes memory _error
+ bytes memory executionError
) internal override {
RequestType requestType = reportRequests[requestId];
- require(requestType != RequestType.NONE, "Invalid request ID");
+ if (requestType == RequestType.NONE) {
+ revert InvalidRequest();
+ }
- reportResponseError = _error;
- if (_error.length == 0) {
+ reportResponseError = executionError;
+ if (executionError.length == 0) {
delete reportRequests[requestId];
reportRemainingRequests--;
if (requestType == RequestType.BALANCES) {
(
- uint128 activeBalance,
+ uint128 beaconBalance,
uint128 sweptBalance
) = abi.decode(response, (uint128, uint128));
- reportActiveBalance = uint256(activeBalance);
+ reportBeaconBalance = uint256(beaconBalance);
reportSweptBalance = uint256(sweptBalance);
} else {
(
@@ -273,6 +269,24 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable {
}
}
- emit OCRResponse(requestId, response, _error);
+ emit OCRResponse(requestId, response, executionError);
+ }
+
+ /**
+ * @notice Send a Chainlink functions request
+ * @param request The Chainlink functions request
+ * @param requestArgs The Chainlink functions request arguments
+ * @param requestType The Chainlink functions request type
+ */
+ function sendFunctionsRequest(
+ Functions.Request memory request,
+ string[] memory requestArgs,
+ RequestType requestType
+ ) private {
+ requestArgs[10] = StringsUpgradeable.toString(uint256(requestType));
+ request.addArgs(requestArgs);
+ bytes32 requestId = sendRequest(request, manager.functionsId(), fulfillGasLimit);
+ reportRequests[requestId] = requestType;
+ reportRemainingRequests++;
}
}
diff --git a/contracts/ethereum/src/v1/CasimirViews.sol b/contracts/ethereum/src/v1/CasimirViews.sol
index 4fb75467f..500b2d5a1 100644
--- a/contracts/ethereum/src/v1/CasimirViews.sol
+++ b/contracts/ethereum/src/v1/CasimirViews.sol
@@ -5,11 +5,12 @@ import "./interfaces/ICasimirViews.sol";
import "./interfaces/ICasimirManager.sol";
import "./interfaces/ICasimirRegistry.sol";
import "./interfaces/ICasimirPool.sol";
+import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @title Views contract that provides read-only access to the state
*/
-contract CasimirViews is ICasimirViews {
+contract CasimirViews is ICasimirViews, Initializable {
/*************/
/* Constants */
/*************/
@@ -18,22 +19,29 @@ contract CasimirViews is ICasimirViews {
uint256 private constant COMPOUND_MINIMUM = 100000000 gwei;
/*************/
- /* Immutable */
+ /* State */
/*************/
/** Manager contract */
- ICasimirManager private immutable manager;
+ ICasimirManager private manager;
/** Registry contract */
- ICasimirRegistry private immutable registry;
+ ICasimirRegistry private registry;
+ /** Storage gap */
+ uint256[50] private __gap;
+
+ // @custom:oz-upgrades-unsafe-allow constructor
+ constructor() {
+ _disableInitializers();
+ }
/**
- * @notice Constructor
+ * @notice Initialize the contract
* @param managerAddress The manager address
* @param registryAddress The registry address
*/
- constructor(address managerAddress, address registryAddress) {
- require(managerAddress != address(0), "Missing manager address");
- require(registryAddress != address(0), "Missing registry address");
+ function initialize(address managerAddress, address registryAddress) public initializer {
+ onlyAddress(managerAddress);
+ onlyAddress(registryAddress);
manager = ICasimirManager(managerAddress);
registry = ICasimirRegistry(registryAddress);
@@ -50,10 +58,16 @@ contract CasimirViews is ICasimirViews {
uint256 startIndex,
uint256 endIndex
) external view returns (uint32[5] memory poolIds) {
+ uint32[] memory pendingPoolIds = manager.getPendingPoolIds();
uint32[] memory stakedPoolIds = manager.getStakedPoolIds();
uint256 count = 0;
for (uint256 i = startIndex; i < endIndex; i++) {
- uint32 poolId = stakedPoolIds[i];
+ uint32 poolId;
+ if (i < pendingPoolIds.length) {
+ poolId = pendingPoolIds[i];
+ } else {
+ poolId = stakedPoolIds[i - pendingPoolIds.length];
+ }
ICasimirPool pool = ICasimirPool(manager.getPoolAddress(poolId));
ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
if (poolDetails.balance >= COMPOUND_MINIMUM) {
@@ -80,6 +94,68 @@ contract CasimirViews is ICasimirViews {
manager.getStakedPoolIds().length;
}
+ /**
+ * @notice Get the deposited pool public keys
+ * @param startIndex The start index
+ * @param endIndex The end index
+ * @return publicKeys The public keys
+ */
+ function getDepositedPoolPublicKeys(
+ uint256 startIndex,
+ uint256 endIndex
+ ) external view returns (bytes[] memory) {
+ bytes[] memory publicKeys = new bytes[](endIndex - startIndex);
+ uint32[] memory pendingPoolIds = manager.getPendingPoolIds();
+ uint32[] memory stakedPoolIds = manager.getStakedPoolIds();
+ uint256 count = 0;
+ for (uint256 i = startIndex; i < endIndex; i++) {
+ uint32 poolId;
+ if (i < pendingPoolIds.length) {
+ poolId = pendingPoolIds[i];
+ } else {
+ poolId = stakedPoolIds[i - pendingPoolIds.length];
+ }
+ address poolAddress = manager.getPoolAddress(poolId);
+ ICasimirPool pool = ICasimirPool(poolAddress);
+ ICasimirPool.PoolDetails memory details = pool.getDetails();
+ publicKeys[count] = details.publicKey;
+ count++;
+ }
+ return publicKeys;
+ }
+
+ /**
+ * @notice Get the deposited pool statuses
+ * @param startIndex The start index
+ * @param endIndex The end index
+ * @return statuses The pool statuses
+ */
+ function getDepositedPoolStatuses(
+ uint256 startIndex,
+ uint256 endIndex
+ ) external view returns (ICasimirPool.PoolStatus[] memory) {
+ ICasimirPool.PoolStatus[] memory statuses = new ICasimirPool.PoolStatus[](
+ endIndex - startIndex
+ );
+ uint32[] memory pendingPoolIds = manager.getPendingPoolIds();
+ uint32[] memory stakedPoolIds = manager.getStakedPoolIds();
+ uint256 count = 0;
+ for (uint256 i = startIndex; i < endIndex; i++) {
+ uint32 poolId;
+ if (i < pendingPoolIds.length) {
+ poolId = pendingPoolIds[i];
+ } else {
+ poolId = stakedPoolIds[i - pendingPoolIds.length];
+ }
+ address poolAddress = manager.getPoolAddress(poolId);
+ ICasimirPool pool = ICasimirPool(poolAddress);
+ ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
+ statuses[count] = poolDetails.status;
+ count++;
+ }
+ return statuses;
+ }
+
/**
* @notice Get operators
* @param startIndex The start index
@@ -109,7 +185,7 @@ contract CasimirViews is ICasimirViews {
* @param poolId The pool ID
* @return poolDetails The pool details
*/
- function getPoolDetails(
+ function getPool(
uint32 poolId
) external view returns (ICasimirPool.PoolDetails memory poolDetails) {
address poolAddress = manager.getPoolAddress(poolId);
@@ -120,19 +196,25 @@ contract CasimirViews is ICasimirViews {
}
/**
- * @notice Get the swept balance
+ * @notice Get the swept balance (in gwei)
* @dev Should be called off-chain
* @param startIndex The start index
* @param endIndex The end index
- * @return sweptBalance The swept balance
+ * @return sweptBalance The swept balance (in gwei)
*/
function getSweptBalance(
uint256 startIndex,
uint256 endIndex
) external view returns (uint128 sweptBalance) {
+ uint32[] memory pendingPoolIds = manager.getPendingPoolIds();
+ uint32[] memory stakedPoolIds = manager.getStakedPoolIds();
for (uint256 i = startIndex; i <= endIndex; i++) {
- uint32[] memory stakedPoolIds = manager.getStakedPoolIds();
- uint32 poolId = stakedPoolIds[i];
+ uint32 poolId;
+ if (i < pendingPoolIds.length) {
+ poolId = pendingPoolIds[i];
+ } else {
+ poolId = stakedPoolIds[i - pendingPoolIds.length];
+ }
ICasimirPool pool = ICasimirPool(manager.getPoolAddress(poolId));
ICasimirPool.PoolDetails memory poolDetails = pool.getDetails();
sweptBalance += uint128(poolDetails.balance / 1 gwei);
@@ -140,32 +222,11 @@ contract CasimirViews is ICasimirViews {
}
/**
- * @notice Get the validator public keys
- * @param startIndex The start index
- * @param endIndex The end index
- * @return validatorPublicKeys The validator public keys
+ * @dev Validate an address is not the zero address
*/
- function getValidatorPublicKeys(
- uint256 startIndex,
- uint256 endIndex
- ) external view returns (bytes[] memory) {
- bytes[] memory validatorPublicKeys = new bytes[](endIndex - startIndex);
- uint32[] memory pendingPoolIds = manager.getPendingPoolIds();
- uint32[] memory stakedPoolIds = manager.getStakedPoolIds();
- uint256 count = 0;
- for (uint256 i = startIndex; i < endIndex; i++) {
- uint32 poolId;
- if (i < pendingPoolIds.length) {
- poolId = pendingPoolIds[i];
- } else {
- poolId = stakedPoolIds[i - pendingPoolIds.length];
- }
- address poolAddress = manager.getPoolAddress(poolId);
- ICasimirPool pool = ICasimirPool(poolAddress);
- ICasimirPool.PoolDetails memory details = pool.getDetails();
- validatorPublicKeys[count] = details.publicKey;
- count++;
+ function onlyAddress(address checkAddress) private pure {
+ if (checkAddress == address(0)) {
+ revert InvalidAddress();
}
- return validatorPublicKeys;
}
}
diff --git a/contracts/ethereum/src/v1/interfaces/ICasimirManager.sol b/contracts/ethereum/src/v1/interfaces/ICasimirManager.sol
index 0b9d011db..8c05a55ad 100644
--- a/contracts/ethereum/src/v1/interfaces/ICasimirManager.sol
+++ b/contracts/ethereum/src/v1/interfaces/ICasimirManager.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache
pragma solidity 0.8.18;
-import './ICasimirPool.sol';
+import "./ICasimirPool.sol";
import "../vendor/interfaces/ISSVNetwork.sol";
interface ICasimirManager {
@@ -22,8 +22,6 @@ interface ICasimirManager {
struct User {
uint256 stake0;
uint256 stakeRatioSum0;
- uint256 actionPeriodTimestamp;
- uint256 actionCount;
}
struct Withdrawal {
address user;
@@ -40,7 +38,11 @@ interface ICasimirManager {
event DepositInitiated(uint32 indexed poolId);
event DepositActivated(uint32 indexed poolId);
event ForcedExitsReported(uint32[] poolIds);
- event FunctionsRequestSet(bytes newRequestCBOR, uint32 newFulfillGasLimit);
+ event FunctionsRequestSet(
+ string newRequestSource,
+ string[] newRequestArgs,
+ uint32 newFulfillGasLimit
+ );
event FunctionsOracleAddressSet(address newFunctionsOracleAddress);
event LINKBalanceWithdrawn(uint256 amount);
event ResharesRequested(uint64 indexed operatorId);
@@ -68,15 +70,39 @@ interface ICasimirManager {
event WithdrawalRequested(address indexed sender, uint256 amount);
event WithdrawalInitiated(address indexed sender, uint256 amount);
+ /**********/
+ /* Errors */
+ /**********/
+
+ error ActionPeriodMaximumReached();
+ error ForcedExitAlreadyReported();
+ error InsufficientLiquidity();
+ error InvalidAmount();
+ error InvalidAddress();
+ error InvalidWithdrawalCredentials();
+ error NoPendingPools();
+ error NoReadyPools();
+ error PoolAlreadyReshared();
+ error PoolNotActive();
+ error PoolNotExiting();
+ error PoolNotPending();
+ error TransferFailed();
+ error Unauthorized();
+
/*************/
/* Mutations */
/*************/
function depositStake() external payable;
+
function depositRewards(uint32 poolId) external payable;
+
function depositExitedBalance(uint32 poolId) external payable;
+
function depositRecoveredBalance(uint32 poolId) external payable;
+
function depositReservedFees() external payable;
+
function depositClusterBalance(
uint64[] memory operatorIds,
ISSVNetworkCore.Cluster memory cluster,
@@ -84,26 +110,33 @@ interface ICasimirManager {
uint256 minimumTokenAmount,
bool processed
) external;
+
function depositFunctionsBalance(
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
) external;
+
function depositUpkeepBalance(
uint256 feeAmount,
uint256 minimumTokenAmount,
bool processed
) external;
+
function rebalanceStake(
- uint256 activeBalance,
- uint256 sweptBalance,
+ uint256 beaconBalance,
+ uint256 sweptBalance,
uint256 activatedDeposits,
uint256 completedExits
) external;
+
function compoundRewards(uint32[5] memory poolIds) external;
+
function requestWithdrawal(uint256 amount) external;
+
function fulfillWithdrawals(uint256 count) external;
- function initiateDeposit(
+
+ function initiateDeposit(
bytes32 depositDataRoot,
bytes calldata publicKey,
bytes calldata signature,
@@ -115,16 +148,23 @@ interface ICasimirManager {
uint256 minimumTokenAmount,
bool processed
) external;
+
function activateDeposits(uint256 count) external;
+
function requestForcedExitReports(uint256 count) external;
+
function requestCompletedExitReports(uint256 count) external;
+
function requestReshares(uint64 operatorId) external;
+
function reportForcedExits(uint32[] memory poolIds) external;
+
function reportCompletedExit(
uint256 poolIndex,
uint32[] memory blamePercents,
ISSVNetworkCore.Cluster memory cluster
) external;
+
function reportReshare(
uint32 poolId,
uint64[] memory operatorIds,
@@ -138,11 +178,21 @@ interface ICasimirManager {
uint256 minimumTokenAmount,
bool processed
) external;
+
function withdrawLINKBalance(uint256 amount) external;
+
function withdrawSSVBalance(uint256 amount) external;
- function setFunctionsRequest(bytes calldata newRequestCBOR, uint32 newFulfillGasLimit) external;
+
+ function setFunctionsRequest(
+ string calldata newRequestSource,
+ string[] calldata newRequestArgs,
+ uint32 newFulfillGasLimit
+ ) external;
+
function setFunctionsOracleAddress(address newOracleAddress) external;
+
function cancelFunctions() external;
+
function cancelUpkeep() external;
/***********/
@@ -150,23 +200,43 @@ interface ICasimirManager {
/***********/
function functionsId() external view returns (uint64);
- function upkeepId() external view returns (uint256);
- function latestActiveBalance() external view returns (uint256);
+
+ function upkeepId() external view returns (uint256);
+
+ function latestBeaconBalance() external view returns (uint256);
+
function reservedFeeBalance() external view returns (uint256);
+
function FEE_PERCENT() external view returns (uint32);
+
function requestedWithdrawalBalance() external view returns (uint256);
+
function requestedExits() external view returns (uint256);
+
function finalizableCompletedExits() external view returns (uint256);
+
function reportPeriod() external view returns (uint32);
+
function getTotalStake() external view returns (uint256);
- function getReadyPoolIds() external view returns (uint32[] memory);
+
function getPendingPoolIds() external view returns (uint32[] memory);
+
function getStakedPoolIds() external view returns (uint32[] memory);
+
function getBufferedBalance() external view returns (uint256);
- function getPendingWithdrawalEligibility(uint256 index, uint256 period) external view returns (bool);
+
+ function getPendingWithdrawalEligibility(
+ uint256 index,
+ uint256 period
+ ) external view returns (bool);
+
function getWithdrawableBalance() external view returns (uint256);
+
function getUserStake(address userAddress) external view returns (uint256);
+
function getPoolAddress(uint32 poolId) external view returns (address);
+
function getRegistryAddress() external view returns (address);
+
function getUpkeepAddress() external view returns (address);
}
diff --git a/contracts/ethereum/src/v1/interfaces/ICasimirPool.sol b/contracts/ethereum/src/v1/interfaces/ICasimirPool.sol
index fd6919958..e022f7343 100644
--- a/contracts/ethereum/src/v1/interfaces/ICasimirPool.sol
+++ b/contracts/ethereum/src/v1/interfaces/ICasimirPool.sol
@@ -22,6 +22,14 @@ interface ICasimirPool {
event ResharesSet(uint256 reshares);
event StatusSet(PoolStatus status);
+ /**********/
+ /* Errors */
+ /**********/
+
+ error Inactive();
+ error InvalidAddress();
+ error NotWithdrawn();
+
/***********/
/* Structs */
/***********/
@@ -40,9 +48,13 @@ interface ICasimirPool {
/*************/
function depositRewards() external;
+
function withdrawBalance(uint32[] memory blamePercents) external;
+
function setOperatorIds(uint64[] memory operatorIds) external;
+
function setReshares(uint256 newReshares) external;
+
function setStatus(PoolStatus newStatus) external;
/***********/
@@ -50,4 +62,4 @@ interface ICasimirPool {
/***********/
function getDetails() external view returns (PoolDetails memory);
-}
\ No newline at end of file
+}
diff --git a/contracts/ethereum/src/v1/interfaces/ICasimirRegistry.sol b/contracts/ethereum/src/v1/interfaces/ICasimirRegistry.sol
index 754dc1aa3..850cb6166 100644
--- a/contracts/ethereum/src/v1/interfaces/ICasimirRegistry.sol
+++ b/contracts/ethereum/src/v1/interfaces/ICasimirRegistry.sol
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: Apache
pragma solidity 0.8.18;
-import './ICasimirManager.sol';
+import "./ICasimirManager.sol";
interface ICasimirRegistry {
-
/***********/
/* Structs */
/***********/
@@ -25,25 +24,56 @@ interface ICasimirRegistry {
event DeactivationRequested(uint64 indexed operatorId);
event DeregistrationCompleted(uint64 indexed operatorId);
event OperatorPoolAdded(uint64 indexed operatorId, uint32 poolId);
- event OperatorPoolRemoved(uint64 operatorId, uint32 poolId, uint256 blameAmount);
+ event OperatorPoolRemoved(
+ uint64 operatorId,
+ uint32 poolId,
+ uint256 blameAmount
+ );
event OperatorRegistered(uint64 indexed operatorId);
event WithdrawalFulfilled(uint64 indexed operatorId, uint256 amount);
+ /**********/
+ /* Errors */
+ /**********/
+
+ error AlreadyExists();
+ error AlreadyRegistered();
+ error DoesNotExist();
+ error Inactive();
+ error InsufficientCollateral();
+ error InvalidAmount();
+ error InvalidAddress();
+ error Resharing();
+ error TransferFailed();
+ error Unauthorized();
+
/*************/
/* Mutations */
/*************/
function registerOperator(uint64 operatorId) external payable;
+
function depositCollateral(uint64 operatorId) external payable;
+
function requestWithdrawal(uint64 operatorId, uint256 amount) external;
+
function requestDeactivation(uint64 operatorId) external;
+
function addOperatorPool(uint64 operatorId, uint32 poolId) external;
- function removeOperatorPool(uint64 operatorId, uint32 poolId, uint256 blameAmount) external;
+
+ function removeOperatorPool(
+ uint64 operatorId,
+ uint32 poolId,
+ uint256 blameAmount
+ ) external;
/***********/
/* Getters */
/***********/
-
- function getOperator(uint64 operatorId) external view returns (Operator memory);
+
+ function getOperator(
+ uint64 operatorId
+ ) external view returns (Operator memory);
+
function getOperatorIds() external view returns (uint64[] memory);
-}
\ No newline at end of file
+}
diff --git a/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol b/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol
index b8a3d5891..cae29f038 100644
--- a/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol
+++ b/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol
@@ -22,19 +22,39 @@ interface ICasimirUpkeep is AutomationCompatibleInterface {
/**********/
/* Events */
/**********/
-
+
event OCRResponse(bytes32 indexed requestId, bytes result, bytes err);
- event RequestSet(bytes newRequestCBOR, uint32 newFulfillGasLimit);
- event OracleAddressSet(address newOracleAddress);
+ event FunctionsRequestSet(
+ string newRequestSource,
+ string[] newRequestArgs,
+ uint32 newFulfillGasLimit
+ );
+ event FunctionsOracleAddressSet(address newFunctionsOracleAddress);
event UpkeepPerformed(ReportStatus indexed status);
+
+ /**********/
+ /* Errors */
+ /**********/
+
+ error InvalidAddress();
+ error InvalidRequest();
+ error NotNeeded();
/*************/
/* Mutations */
/*************/
function performUpkeep(bytes calldata performData) external;
- function setRequest(bytes calldata newRequestCBOR, uint32 newFulfillGasLimit) external;
- function setOracleAddress(address newOracleAddress) external;
+
+ function setFunctionsRequest(
+ string calldata newRequestSource,
+ string[] calldata newRequestArgs,
+ uint32 newFulfillGasLimit
+ ) external;
+
+ function setFunctionsOracleAddress(
+ address newFunctionsOracleAddress
+ ) external;
/***********/
/* Getters */
diff --git a/contracts/ethereum/src/v1/interfaces/ICasimirViews.sol b/contracts/ethereum/src/v1/interfaces/ICasimirViews.sol
index 010100533..45267f90b 100644
--- a/contracts/ethereum/src/v1/interfaces/ICasimirViews.sol
+++ b/contracts/ethereum/src/v1/interfaces/ICasimirViews.sol
@@ -5,6 +5,12 @@ import "./ICasimirPool.sol";
import "./ICasimirRegistry.sol";
interface ICasimirViews {
+ /**********/
+ /* Errors */
+ /**********/
+
+ error InvalidAddress();
+
/***********/
/* Getters */
/***********/
@@ -13,23 +19,33 @@ interface ICasimirViews {
uint256 startIndex,
uint256 endIndex
) external view returns (uint32[5] memory);
+
function getDepositedPoolCount()
external
view
returns (uint256 depositedPoolCount);
+
+ function getDepositedPoolPublicKeys(
+ uint256 startIndex,
+ uint256 endIndex
+ ) external view returns (bytes[] memory);
+
+ function getDepositedPoolStatuses(
+ uint256 startIndex,
+ uint256 endIndex
+ ) external view returns (ICasimirPool.PoolStatus[] memory);
+
function getOperators(
uint256 startIndex,
uint256 endIndex
) external view returns (ICasimirRegistry.Operator[] memory);
- function getPoolDetails(
+
+ function getPool(
uint32 poolId
) external view returns (ICasimirPool.PoolDetails memory);
+
function getSweptBalance(
uint256 startIndex,
uint256 endIndex
) external view returns (uint128);
- function getValidatorPublicKeys(
- uint256 startIndex,
- uint256 endIndex
- ) external view returns (bytes[] memory);
}
diff --git a/contracts/ethereum/src/v1/libraries/CasimirArray.sol b/contracts/ethereum/src/v1/libraries/CasimirArray.sol
new file mode 100644
index 000000000..50b3cdc7f
--- /dev/null
+++ b/contracts/ethereum/src/v1/libraries/CasimirArray.sol
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: Apache
+pragma solidity 0.8.18;
+
+import "../interfaces/ICasimirManager.sol";
+
+
+library CasimirArray {
+
+ error IndexOutOfBounds();
+ error EmptyArray();
+
+ function removeUint32Item(uint32[] storage uint32Array, uint index) public {
+ if (uint32Array.length == 0) {
+ revert EmptyArray();
+ }
+ if (index >= uint32Array.length) {
+ revert IndexOutOfBounds();
+ }
+ for (uint i = index; i < uint32Array.length - 1; i++) {
+ uint32Array[i] = uint32Array[i + 1];
+ }
+ uint32Array.pop();
+ }
+
+ function removeBytesItem(bytes[] storage bytesArray, uint index) public {
+ if (bytesArray.length == 0) {
+ revert EmptyArray();
+ }
+ if (index >= bytesArray.length) {
+ revert IndexOutOfBounds();
+ }
+ for (uint i = index; i < bytesArray.length - 1; i++) {
+ bytesArray[i] = bytesArray[i + 1];
+ }
+ bytesArray.pop();
+ }
+
+ function removeWithdrawalItem(
+ ICasimirManager.Withdrawal[] storage withdrawals,
+ uint index
+ ) public {
+ if (withdrawals.length == 0) {
+ revert EmptyArray();
+ }
+ if (index >= withdrawals.length) {
+ revert IndexOutOfBounds();
+ }
+ for (uint i = index; i < withdrawals.length - 1; i++) {
+ withdrawals[i] = withdrawals[i + 1];
+ }
+ withdrawals.pop();
+ }
+}
diff --git a/contracts/ethereum/src/v1/libraries/CasimirFactory.sol b/contracts/ethereum/src/v1/libraries/CasimirFactory.sol
new file mode 100644
index 000000000..d7d393ad5
--- /dev/null
+++ b/contracts/ethereum/src/v1/libraries/CasimirFactory.sol
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: Apache
+pragma solidity 0.8.18;
+
+import "../CasimirPool.sol";
+import "../CasimirRegistry.sol";
+import "../CasimirUpkeep.sol";
+import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
+
+library CasimirFactory {
+ /**
+ * @notice Create a new pool beacon proxy contract
+ * @param poolBeaconAddress The address of the pool beacon
+ * @param registryAddress The address of the registry contract
+ * @param poolId The pool ID
+ * @param publicKey The validator public key
+ * @param operatorIds The operator IDs
+ * @return poolAddress The pool contract address
+ */
+ function createPool(
+ address poolBeaconAddress,
+ address registryAddress,
+ uint32 poolId,
+ bytes memory publicKey,
+ uint64[] memory operatorIds
+ ) public returns (address poolAddress) {
+ poolAddress = address(
+ new BeaconProxy(
+ poolBeaconAddress,
+ abi.encodeWithSelector(
+ CasimirPool(address(0)).initialize.selector,
+ registryAddress,
+ poolId,
+ publicKey,
+ operatorIds
+ )
+ )
+ );
+ }
+
+ /**
+ * @notice Create a new registry beacon proxy contract
+ * @param registryBeaconAddress The address of the registry beacon
+ * @param ssvViewsAddress The address of the SSV views contract
+ * @return registryAddress The registry contract address
+ */
+ function createRegistry(
+ address registryBeaconAddress,
+ address ssvViewsAddress
+ ) public returns (address registryAddress) {
+ registryAddress = address(
+ new BeaconProxy(
+ registryBeaconAddress,
+ abi.encodeWithSelector(
+ CasimirRegistry(address(0)).initialize.selector,
+ ssvViewsAddress
+ )
+ )
+ );
+ }
+
+ /**
+ * @notice Create a new upkeep beacon proxy contract
+ * @param upkeepBeaconAddress The address of the upkeep beacon
+ * @param functionsOracleAddress The address of the functions oracle
+ * @return upkeepAddress The upkeep contract address
+ */
+ function createUpkeep(
+ address upkeepBeaconAddress,
+ address functionsOracleAddress
+ ) public returns (address upkeepAddress) {
+ upkeepAddress = address(
+ new BeaconProxy(
+ upkeepBeaconAddress,
+ abi.encodeWithSelector(
+ CasimirUpkeep(address(0)).initialize.selector,
+ functionsOracleAddress
+ )
+ )
+ );
+ }
+}
diff --git a/contracts/ethereum/src/v1/libraries/Types.sol b/contracts/ethereum/src/v1/libraries/Types.sol
deleted file mode 100644
index ca2a23fbe..000000000
--- a/contracts/ethereum/src/v1/libraries/Types.sol
+++ /dev/null
@@ -1,63 +0,0 @@
-// SPDX-License-Identifier: Apache
-pragma solidity 0.8.18;
-
-import "../interfaces/ICasimirManager.sol";
-
-library Types32Array {
- /**
- * @dev Remove a uint32 element from the array
- * @param uint32Array The array of uint32
- */
- function remove(uint32[] storage uint32Array, uint index) internal {
- require(uint32Array.length > 0, "Can't remove from empty array");
- require(index < uint32Array.length, "Index out of bounds");
- for (uint i = index; i < uint32Array.length - 1; i++) {
- uint32Array[i] = uint32Array[i + 1];
- }
- uint32Array.pop();
- }
-}
-
-library TypesBytesArray {
- /**
- * @dev Remove a bytes element from the array
- * @param bytesArray The array of bytes
- * @param index The index of the element to remove
- */
- function remove(bytes[] storage bytesArray, uint index) internal {
- require(bytesArray.length > 0, "Can't remove from empty array");
- require(index < bytesArray.length, "Index out of bounds");
- for (uint i = index; i < bytesArray.length - 1; i++) {
- bytesArray[i] = bytesArray[i + 1];
- }
- bytesArray.pop();
- }
-}
-
-library TypesWithdrawalArray {
- /**
- * @dev Remove a withdrawal from the array
- * @param withdrawals The array of withdrawals
- * @param index The index of the withdrawal to remove
- */
- function remove(ICasimirManager.Withdrawal[] storage withdrawals, uint index) internal {
- require(withdrawals.length > 0, "Can't remove from empty array");
- require(index < withdrawals.length, "Index out of bounds");
- for (uint i = index; i < withdrawals.length - 1; i++) {
- withdrawals[i] = withdrawals[i + 1];
- }
- withdrawals.pop();
- }
-}
-
-library TypesAddress {
- /**
- * @dev Send ETH to a user
- * @param user The user address
- * @param amount The amount of stake to send
- */
- function send(address user, uint256 amount) internal {
- (bool success, ) = user.call{value: amount}("");
- require(success, "Transfer failed");
- }
-}
\ No newline at end of file
diff --git a/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetwork.sol b/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetwork.sol
index f3e53fbfa..da9fd29b5 100644
--- a/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetwork.sol
+++ b/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetwork.sol
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;
-import "../../../../scripts/resources/ssv-network/contracts/ISSVNetwork.sol";
+import "../../../../scripts/resources/ssv-network/contracts/interfaces/ISSVNetwork.sol";
diff --git a/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkCore.sol b/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkCore.sol
index 147cbbe7a..c995a4b1d 100644
--- a/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkCore.sol
+++ b/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkCore.sol
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;
-import "../../../../scripts/resources/ssv-network/contracts/ISSVNetworkCore.sol";
+import "../../../../scripts/resources/ssv-network/contracts/interfaces/ISSVNetworkCore.sol";
diff --git a/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkViews.sol b/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkViews.sol
deleted file mode 100644
index cda3d403d..000000000
--- a/contracts/ethereum/src/v1/vendor/interfaces/ISSVNetworkViews.sol
+++ /dev/null
@@ -1,4 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity 0.8.18;
-
-import "../../../../scripts/resources/ssv-network/contracts/ISSVNetworkViews.sol";
diff --git a/contracts/ethereum/src/v1/vendor/interfaces/ISSVViews.sol b/contracts/ethereum/src/v1/vendor/interfaces/ISSVViews.sol
new file mode 100644
index 000000000..981692919
--- /dev/null
+++ b/contracts/ethereum/src/v1/vendor/interfaces/ISSVViews.sol
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+pragma solidity 0.8.18;
+
+import "../../../../scripts/resources/ssv-network/contracts/interfaces/ISSVViews.sol";
diff --git a/contracts/ethereum/test/fixtures/shared.ts b/contracts/ethereum/test/fixtures/shared.ts
index 65d2c0f73..af1d8d2ae 100644
--- a/contracts/ethereum/test/fixtures/shared.ts
+++ b/contracts/ethereum/test/fixtures/shared.ts
@@ -1,16 +1,17 @@
-import { ethers, network } from 'hardhat'
+import { ethers, network, upgrades } from 'hardhat'
import { loadFixture, time, setBalance } from '@nomicfoundation/hardhat-network-helpers'
-import { CasimirManager, CasimirRegistry, CasimirUpkeep, CasimirViews, FunctionsBillingRegistry, FunctionsOracleFactory, ISSVNetworkViews } from '../../build/@types'
+import { CasimirManager, CasimirRegistry, CasimirUpkeep, CasimirViews, FunctionsBillingRegistry, FunctionsOracle, FunctionsOracleFactory, ISSVViews } from '../../build/@types'
import { fulfillReport, runUpkeep } from '../../helpers/upkeep'
import { depositFunctionsBalanceHandler, depositUpkeepBalanceHandler, initiateDepositHandler, reportCompletedExitsHandler } from '../../helpers/oracle'
import { round } from '../../helpers/math'
-import ISSVNetworkViewsAbi from '../../build/abi/ISSVNetworkViews.json'
-import { requestConfig } from '@casimir/functions'
+import ISSVViewsAbi from '../../build/abi/ISSVViews.json'
+import requestConfig from '@casimir/functions/Functions-request-config'
+upgrades.silenceWarnings()
/** Fixture to deploy SSV manager contract */
export async function deploymentFixture() {
- const [owner, , , , , keeper, daoOracle] = await ethers.getSigners()
+ const [, daoOracle, donTransmitter] = await ethers.getSigners()
const functionsOracleFactoryFactory = await ethers.getContractFactory('FunctionsOracleFactory')
const functionsOracleFactory = await functionsOracleFactoryFactory.deploy() as FunctionsOracleFactory
@@ -20,7 +21,7 @@ export async function deploymentFixture() {
const deployNewOracleReceipt = await deployNewOracle.wait()
if (!deployNewOracleReceipt.events) throw new Error('Functions oracle deployment failed')
const functionsOracleAddress = deployNewOracleReceipt.events[1].args?.don as string
- const functionsOracle = await ethers.getContractAt('FunctionsOracle', functionsOracleAddress)
+ const functionsOracle = await ethers.getContractAt('FunctionsOracle', functionsOracleAddress) as FunctionsOracle
const acceptOwnership = await functionsOracle.acceptOwnership()
await acceptOwnership.wait()
@@ -52,45 +53,72 @@ export async function deploymentFixture() {
functionsBillingRegistryConfig.requestTimeoutSeconds
)
+ const arrayFactory = await ethers.getContractFactory('CasimirArray')
+ const arrayLibrary = await arrayFactory.deploy()
+
+ const factoryFactory = await ethers.getContractFactory('CasimirFactory')
+ const factoryLibrary = await factoryFactory.deploy()
+
+ const poolFactory = await ethers.getContractFactory('CasimirPool')
+ const poolBeacon = await upgrades.deployBeacon(poolFactory, { unsafeAllow: ['constructor'] })
+ await poolBeacon.deployed()
+
+ const registryFactory = await ethers.getContractFactory('CasimirRegistry')
+ const registryBeacon = await upgrades.deployBeacon(registryFactory, { unsafeAllow: ['constructor'] })
+ await registryBeacon.deployed()
+
+ const upkeepFactory = await ethers.getContractFactory('CasimirUpkeep')
+ const upkeepBeacon = await upgrades.deployBeacon(upkeepFactory, { unsafeAllow: ['constructor'] })
+ await upkeepBeacon.deployed()
+
const managerArgs = {
- daoOracleAddress: daoOracle.address,
beaconDepositAddress: process.env.BEACON_DEPOSIT_ADDRESS,
+ daoOracleAddress: daoOracle.address,
functionsBillingRegistryAddress: functionsBillingRegistry.address,
functionsOracleAddress: functionsOracle.address,
- linkRegistrarAddress: process.env.LINK_REGISTRAR_ADDRESS,
- linkRegistryAddress: process.env.LINK_REGISTRY_ADDRESS,
+ keeperRegistrarAddress: process.env.KEEPER_REGISTRAR_ADDRESS,
+ keeperRegistryAddress: process.env.KEEPER_REGISTRY_ADDRESS,
linkTokenAddress: process.env.LINK_TOKEN_ADDRESS,
+ poolBeaconAddress: poolBeacon.address,
+ registryBeaconAddress: registryBeacon.address,
ssvNetworkAddress: process.env.SSV_NETWORK_ADDRESS,
- ssvNetworkViewsAddress: process.env.SSV_NETWORK_VIEWS_ADDRESS,
ssvTokenAddress: process.env.SSV_TOKEN_ADDRESS,
+ ssvViewsAddress: process.env.SSV_VIEWS_ADDRESS,
swapFactoryAddress: process.env.SWAP_FACTORY_ADDRESS,
swapRouterAddress: process.env.SWAP_ROUTER_ADDRESS,
+ upkeepBeaconAddress: upkeepBeacon.address,
wethTokenAddress: process.env.WETH_TOKEN_ADDRESS
}
- const managerFactory = await ethers.getContractFactory('CasimirManager')
- const manager = await managerFactory.deploy(...Object.values(managerArgs)) as CasimirManager
+ const managerFactory = await ethers.getContractFactory('CasimirManager', {
+ libraries: {
+ CasimirArray: arrayLibrary.address,
+ CasimirFactory: factoryLibrary.address
+ }
+ })
+ const manager = await upgrades.deployProxy(managerFactory, Object.values(managerArgs), { unsafeAllow: ['constructor', 'external-library-linking'] }) as CasimirManager
await manager.deployed()
const registryAddress = await manager.getRegistryAddress()
+ const registry = await ethers.getContractAt('CasimirRegistry', registryAddress) as CasimirRegistry
+
const upkeepAddress = await manager.getUpkeepAddress()
+ const upkeep = await ethers.getContractAt('CasimirUpkeep', upkeepAddress) as CasimirUpkeep
const viewsArgs = {
managerAddress: manager.address,
registryAddress
}
const viewsFactory = await ethers.getContractFactory('CasimirViews')
- const views = await viewsFactory.deploy(...Object.values(viewsArgs)) as CasimirViews
-
- const registry = await ethers.getContractAt('CasimirRegistry', registryAddress) as CasimirRegistry
- const upkeep = await ethers.getContractAt('CasimirUpkeep', upkeepAddress) as CasimirUpkeep
- const ssvNetwork = await ethers.getContractAt('SSVNetwork', process.env.SSV_NETWORK_ADDRESS as string)
- const ssvNetworkViews = await ethers.getContractAt(ISSVNetworkViewsAbi, process.env.SSV_NETWORK_VIEWS_ADDRESS as string) as ISSVNetworkViews
+ const views = await upgrades.deployProxy(viewsFactory, Object.values(viewsArgs), { unsafeAllow: ['constructor'] }) as CasimirViews
+ await views.deployed()
- const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [654, 655, 656, 657]
- if (preregisteredOperatorIds.length < 4) throw new Error('Not enough operator ids provided')
+ const ssvViews = await ethers.getContractAt(ISSVViewsAbi, process.env.SSV_VIEWS_ADDRESS as string) as ISSVViews
+ const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [200, 201, 202, 203, 156, 157, 158, 159]
+ if (preregisteredOperatorIds.length < 8) throw new Error('Not enough operator ids provided')
const preregisteredBalance = ethers.utils.parseEther('10')
for (const operatorId of preregisteredOperatorIds) {
- const [operatorOwnerAddress] = await ssvNetworkViews.getOperatorById(operatorId)
+ const [operatorOwnerAddress] = await ssvViews.getOperatorById(operatorId)
+ const operatorOwnerSigner = ethers.provider.getSigner(operatorOwnerAddress)
const currentBalance = await ethers.provider.getBalance(operatorOwnerAddress)
const nextBalance = currentBalance.add(preregisteredBalance)
await setBalance(operatorOwnerAddress, nextBalance)
@@ -98,54 +126,51 @@ export async function deploymentFixture() {
method: 'hardhat_impersonateAccount',
params: [operatorOwnerAddress]
})
- const operatorSigner = ethers.provider.getSigner(operatorOwnerAddress)
- const result = await registry.connect(operatorSigner).registerOperator(operatorId, { value: preregisteredBalance })
+ const result = await registry.connect(operatorOwnerSigner).registerOperator(operatorId, { value: preregisteredBalance })
await result.wait()
}
- const secrets = '0x' // Parse requestConfig.secrets and encrypt if necessary
- const requestCBOR = await upkeep.generateRequest(requestConfig.source, secrets, requestConfig.args)
- const fulfillGasLimit = 300000
- const setRequest = await manager.setFunctionsRequest(requestCBOR, fulfillGasLimit)
+ requestConfig.args[1] = views.address
+ const setRequest = await manager.setFunctionsRequest(requestConfig.source, requestConfig.args, 300000)
await setRequest.wait()
- await functionsBillingRegistry.setAuthorizedSenders([keeper.address, manager.address, upkeep.address, functionsOracle.address])
+ await functionsBillingRegistry.setAuthorizedSenders([donTransmitter.address, functionsOracle.address])
await functionsOracle.setRegistry(functionsBillingRegistry.address)
- await functionsOracle.addAuthorizedSenders([keeper.address, manager.address])
+ await functionsOracle.addAuthorizedSenders([donTransmitter.address, manager.address])
- return { manager, registry, upkeep, views, ssvNetwork, ssvNetworkViews, owner, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter }
}
/** Fixture to stake 16 for the first user */
export async function firstUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(deploymentFixture)
- const [, firstUser] = await ethers.getSigners()
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter } = await loadFixture(deploymentFixture)
+ const [, , , firstUser] = await ethers.getSigners()
const depositAmount = round(16 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
const deposit = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await deposit.wait()
- return { manager, registry, upkeep, views, owner, firstUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser }
}
/** Fixture to stake 24 for the second user */
export async function secondUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, firstUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(firstUserDepositFixture)
- const [, , secondUser] = await ethers.getSigners()
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser } = await loadFixture(firstUserDepositFixture)
+ const [, , , , secondUser] = await ethers.getSigners()
const depositAmount = round(24 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
const deposit = await manager.connect(secondUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await deposit.wait()
-
+
await depositFunctionsBalanceHandler({ manager, signer: daoOracle })
await depositUpkeepBalanceHandler({ manager, signer: daoOracle })
await initiateDepositHandler({ manager, signer: daoOracle })
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 32,
+ beaconBalance: 32,
sweptBalance: 0,
activatedDeposits: 1,
forcedExits: 0,
@@ -154,26 +179,26 @@ export async function secondUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser }
}
/** Fixture to report increase of 0.105 in total rewards before fees */
export async function rewardsPostSecondUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(secondUserDepositFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser } = await loadFixture(secondUserDepositFixture)
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 32.105,
+ beaconBalance: 32.105,
sweptBalance: 0,
activatedDeposits: 0,
forcedExits: 0,
@@ -182,23 +207,23 @@ export async function rewardsPostSecondUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues,
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser }
}
/** Fixture to sweep 0.105 to the manager */
export async function sweepPostSecondUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(secondUserDepositFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser } = await loadFixture(secondUserDepositFixture)
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const sweptRewards = 0.105
const stakedPoolIds = await manager.getStakedPoolIds()
@@ -211,7 +236,7 @@ export async function sweepPostSecondUserDepositFixture() {
}
const compoundablePoolIds = [1, 0, 0, 0, 0]
const reportValues = {
- activeBalance: 32,
+ beaconBalance: 32,
sweptBalance: sweptRewards,
activatedDeposits: 0,
forcedExits: 0,
@@ -220,21 +245,21 @@ export async function sweepPostSecondUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues,
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser }
}
/** Fixture to stake 24 for the third user */
export async function thirdUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(sweepPostSecondUserDepositFixture)
- const [, , , thirdUser] = await ethers.getSigners()
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser } = await loadFixture(sweepPostSecondUserDepositFixture)
+ const [, , , , , thirdUser] = await ethers.getSigners()
const depositAmount = round(24 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
const deposit = await manager.connect(thirdUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
@@ -243,10 +268,10 @@ export async function thirdUserDepositFixture() {
await initiateDepositHandler({ manager, signer: daoOracle })
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 64,
+ beaconBalance: 64,
sweptBalance: 0,
activatedDeposits: 1,
forcedExits: 0,
@@ -255,26 +280,26 @@ export async function thirdUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
-
- await runUpkeep({ upkeep, keeper })
- return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry }
+ await runUpkeep({ donTransmitter, upkeep })
+
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser }
}
/** Fixture to report increase of 0.21 in total rewards before fees */
export async function rewardsPostThirdUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(thirdUserDepositFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser } = await loadFixture(thirdUserDepositFixture)
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 64.21,
+ beaconBalance: 64.21,
sweptBalance: 0,
activatedDeposits: 0,
forcedExits: 0,
@@ -283,23 +308,23 @@ export async function rewardsPostThirdUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues,
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser }
}
/** Fixture to sweep 0.21 to the manager */
export async function sweepPostThirdUserDepositFixture() {
- const { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(rewardsPostThirdUserDepositFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser } = await loadFixture(rewardsPostThirdUserDepositFixture)
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const sweptRewards = 0.21
const stakedPoolIds = await manager.getStakedPoolIds()
@@ -312,7 +337,7 @@ export async function sweepPostThirdUserDepositFixture() {
}
const compoundablePoolIds = [1, 2, 0, 0, 0]
const reportValues = {
- activeBalance: 64,
+ beaconBalance: 64,
sweptBalance: sweptRewards,
activatedDeposits: 0,
forcedExits: 0,
@@ -321,29 +346,29 @@ export async function sweepPostThirdUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser }
}
/** Fixture to partial withdraw 0.3 to the first user */
export async function firstUserPartialWithdrawalFixture() {
- const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(sweepPostThirdUserDepositFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser } = await loadFixture(sweepPostThirdUserDepositFixture)
const withdrawableBalance = await manager.getWithdrawableBalance()
const withdraw = await manager.connect(firstUser).requestWithdrawal(withdrawableBalance)
await withdraw.wait()
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 64,
+ beaconBalance: 64,
sweptBalance: 0,
activatedDeposits: 0,
forcedExits: 0,
@@ -352,21 +377,21 @@ export async function firstUserPartialWithdrawalFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser }
}
/** Fixture to stake 72 for the fourth user */
export async function fourthUserDepositFixture() {
- const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(firstUserPartialWithdrawalFixture)
- const [, , , , fourthUser] = await ethers.getSigners()
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser } = await loadFixture(firstUserPartialWithdrawalFixture)
+ const [, , , , , , fourthUser] = await ethers.getSigners()
const depositAmount = round(72 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
const deposit = await manager.connect(fourthUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
@@ -377,10 +402,10 @@ export async function fourthUserDepositFixture() {
}
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 128,
+ beaconBalance: 128,
sweptBalance: 0,
activatedDeposits: 2,
forcedExits: 0,
@@ -389,26 +414,26 @@ export async function fourthUserDepositFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser }
}
-/** Fixture to simulate a validator stake penalty that decreases the active balance */
-export async function activeBalanceLossFixture() {
- const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(fourthUserDepositFixture)
+/** Fixture to simulate a validator stake penalty that decreases the beacon chain balance */
+export async function beaconBalanceLossFixture() {
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser } = await loadFixture(fourthUserDepositFixture)
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 126,
+ beaconBalance: 126,
sweptBalance: 0,
activatedDeposits: 0,
forcedExits: 0,
@@ -417,28 +442,28 @@ export async function activeBalanceLossFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
-
- await runUpkeep({ upkeep, keeper })
- return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry }
+ await runUpkeep({ donTransmitter, upkeep })
+
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser }
}
-/** Fixture to simulate a validator reward that brings the active balance back to expected */
-export async function activeBalanceRecoveryFixture() {
- const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(activeBalanceLossFixture)
+/** Fixture to simulate a validator reward that brings the beacon chain balance back to expected */
+export async function beaconBalanceRecoveryFixture() {
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser } = await loadFixture(beaconBalanceLossFixture)
- let nextActiveBalance = 127
+ let nextBeaconBalance = 127
for (let i = 0; i < 2; i++) {
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: nextActiveBalance,
+ beaconBalance: nextBeaconBalance,
sweptBalance: 0,
activatedDeposits: 0,
forcedExits: 0,
@@ -447,33 +472,33 @@ export async function activeBalanceRecoveryFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
- nextActiveBalance += 1
+ await runUpkeep({ donTransmitter, upkeep })
+ nextBeaconBalance += 1
}
- return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser }
}
/** Fixture to full withdraw ~24.07 */
export async function thirdUserFullWithdrawalFixture() {
- const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(activeBalanceRecoveryFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser } = await loadFixture(beaconBalanceRecoveryFixture)
const thirdStake = await manager.getUserStake(thirdUser.address)
const withdraw = await manager.connect(thirdUser).requestWithdrawal(thirdStake)
await withdraw.wait()
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const sweptExitedBalance = 32
const reportValues = {
- activeBalance: 96,
+ beaconBalance: 96,
sweptBalance: sweptExitedBalance,
activatedDeposits: 0,
forcedExits: 0,
@@ -482,7 +507,7 @@ export async function thirdUserFullWithdrawalFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
@@ -496,28 +521,28 @@ export async function thirdUserFullWithdrawalFixture() {
await reportCompletedExitsHandler({ manager, views, signer: daoOracle, args: { count: 1 } })
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser }
}
/** Fixture to simulate rewards */
export async function simulationFixture() {
- const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(thirdUserFullWithdrawalFixture)
+ const { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser } = await loadFixture(thirdUserFullWithdrawalFixture)
const rewardsPerValidator = 0.105
- let nextActiveBalance = 96
+ let nextBeaconBalance = 96
let totalRewards = 0
for (let i = 0; i < 5; i++) {
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const stakedPoolIds = await manager.getStakedPoolIds()
const rewardsAmount = rewardsPerValidator * stakedPoolIds.length
totalRewards += round(rewardsAmount, 10)
- nextActiveBalance = round(nextActiveBalance + rewardsAmount, 10)
+ nextBeaconBalance = round(nextBeaconBalance + rewardsAmount, 10)
const reportValues = {
- activeBalance: nextActiveBalance,
+ beaconBalance: nextBeaconBalance,
sweptBalance: 0,
activatedDeposits: 0,
forcedExits: 0,
@@ -526,20 +551,20 @@ export async function simulationFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
}
const sweptRewards = totalRewards
const stakedPoolIds = await manager.getStakedPoolIds()
-
+
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
for (const poolId of stakedPoolIds) {
const poolAddress = await manager.getPoolAddress(poolId)
@@ -550,7 +575,7 @@ export async function simulationFixture() {
}
const compoundablePoolIds = [2, 3, 4, 0, 0]
const reportValues = {
- activeBalance: 96,
+ beaconBalance: 96,
sweptBalance: sweptRewards,
activatedDeposits: 0,
forcedExits: 0,
@@ -559,13 +584,13 @@ export async function simulationFixture() {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
- return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, functionsBillingRegistry }
+ return { manager, registry, upkeep, views, functionsBillingRegistry, ssvViews, daoOracle, donTransmitter, firstUser, secondUser, thirdUser, fourthUser }
}
\ No newline at end of file
diff --git a/contracts/ethereum/test/integration.ts b/contracts/ethereum/test/integration.ts
index 4fd4c36ad..101440341 100644
--- a/contracts/ethereum/test/integration.ts
+++ b/contracts/ethereum/test/integration.ts
@@ -1,7 +1,7 @@
import { ethers } from 'hardhat'
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'
import { expect } from 'chai'
-import { firstUserDepositFixture, rewardsPostSecondUserDepositFixture, secondUserDepositFixture, thirdUserDepositFixture, rewardsPostThirdUserDepositFixture, simulationFixture, firstUserPartialWithdrawalFixture, fourthUserDepositFixture, sweepPostSecondUserDepositFixture, sweepPostThirdUserDepositFixture, activeBalanceLossFixture, activeBalanceRecoveryFixture, thirdUserFullWithdrawalFixture } from './fixtures/shared'
+import { firstUserDepositFixture, rewardsPostSecondUserDepositFixture, secondUserDepositFixture, thirdUserDepositFixture, rewardsPostThirdUserDepositFixture, simulationFixture, firstUserPartialWithdrawalFixture, fourthUserDepositFixture, sweepPostSecondUserDepositFixture, sweepPostThirdUserDepositFixture, beaconBalanceLossFixture, beaconBalanceRecoveryFixture, thirdUserFullWithdrawalFixture } from './fixtures/shared'
describe('Integration', async function () {
@@ -23,7 +23,7 @@ describe('Integration', async function () {
expect(stakedPoolIds.length).equal(1)
const firstPoolId = stakedPoolIds[0]
- const poolDetails = await views.getPoolDetails(firstPoolId)
+ const poolDetails = await views.getPool(firstPoolId)
expect(poolDetails.publicKey).not.equal('0x')
expect(poolDetails.operatorIds.length).equal(4)
})
@@ -66,7 +66,7 @@ describe('Integration', async function () {
expect(stakedPools.length).equal(2)
const secondPoolId = stakedPools[1]
- const poolDetails = await views.getPoolDetails(secondPoolId)
+ const poolDetails = await views.getPool(secondPoolId)
expect(poolDetails.publicKey).not.equal('0x')
expect(poolDetails.operatorIds.length).equal(4)
})
@@ -123,26 +123,26 @@ describe('Integration', async function () {
expect(stakedPools.length).equal(4)
const thirdPoolId = stakedPools[2]
- const thirdPoolDetails = await views.getPoolDetails(thirdPoolId)
+ const thirdPoolDetails = await views.getPool(thirdPoolId)
expect(thirdPoolDetails.publicKey).not.equal('0x')
expect(thirdPoolDetails.operatorIds.length).equal(4)
const fourthPoolId = stakedPools[3]
- const fourthPoolDetails = await views.getPoolDetails(fourthPoolId)
+ const fourthPoolDetails = await views.getPool(fourthPoolId)
expect(fourthPoolDetails.publicKey).not.equal('0x')
expect(fourthPoolDetails.operatorIds.length).equal(4)
})
it('A loss is reported and brings the active stake below expected', async function () {
- const { manager } = await loadFixture(activeBalanceLossFixture)
- const activeBalance = await manager.latestActiveBalance()
- expect(ethers.utils.formatEther(activeBalance)).equal('126.0')
+ const { manager } = await loadFixture(beaconBalanceLossFixture)
+ const beaconBalance = await manager.latestBeaconBalance()
+ expect(ethers.utils.formatEther(beaconBalance)).equal('126.0')
})
it('Gains are reported and bring the active stake back to expected', async function () {
- const { manager } = await loadFixture(activeBalanceRecoveryFixture)
- const activeBalance = await manager.latestActiveBalance()
- expect(ethers.utils.formatEther(activeBalance)).equal('128.0')
+ const { manager } = await loadFixture(beaconBalanceRecoveryFixture)
+ const beaconBalance = await manager.latestBeaconBalance()
+ expect(ethers.utils.formatEther(beaconBalance)).equal('128.0')
})
it('Third user full withdrawal is completed on exit report', async function () {
diff --git a/contracts/ethereum/test/operators.ts b/contracts/ethereum/test/operators.ts
index 8a3b1c9e8..4eda3c325 100644
--- a/contracts/ethereum/test/operators.ts
+++ b/contracts/ethereum/test/operators.ts
@@ -25,10 +25,10 @@ describe('Operators', async function () {
it('First initiated deposit uses 4 eligible operators', async function () {
const { manager, registry, views, daoOracle } = await loadFixture(deploymentFixture)
- const [, user] = await ethers.getSigners()
+ const [firstUser] = await ethers.getSigners()
const depositAmount = round(32 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
- const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
+ const deposit = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await deposit.wait()
await initiateDepositHandler({ manager, signer: daoOracle })
@@ -45,18 +45,18 @@ describe('Operators', async function () {
})
it('Operator deregistration with 1 pool emits 1 reshare request', async function () {
- const { manager, registry, ssvNetworkViews, daoOracle } = await loadFixture(deploymentFixture)
- const [, user] = await ethers.getSigners()
+ const { manager, registry, ssvViews, daoOracle } = await loadFixture(deploymentFixture)
+ const [firstUser] = await ethers.getSigners()
const depositAmount = round(32 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
- const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
+ const deposit = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await deposit.wait()
await initiateDepositHandler({ manager, signer: daoOracle })
const operatorIds = await registry.getOperatorIds()
const deregisteringOperatorId = operatorIds[0]
- const operatorOwnerAddress = (await ssvNetworkViews.getOperatorById(deregisteringOperatorId)).owner
+ const operatorOwnerAddress = (await ssvViews.getOperatorById(deregisteringOperatorId)).owner
const operatorOwnerSigner = ethers.provider.getSigner(operatorOwnerAddress)
await network.provider.request({
method: 'hardhat_impersonateAccount',
@@ -67,18 +67,18 @@ describe('Operators', async function () {
const deregisteringOperator = await registry.getOperator(deregisteringOperatorId)
const resharesRequestedEvents = await manager.queryFilter(manager.filters.ResharesRequested(), -1)
const resharesRequestedEvent = resharesRequestedEvents[0]
-
- expect(deregisteringOperator.resharing).equal(true)
+
+ expect(deregisteringOperator.resharing).equal(true)
expect(resharesRequestedEvents.length).equal(1)
expect(resharesRequestedEvent.args?.operatorId.toNumber()).equal(deregisteringOperatorId.toNumber())
})
it('Operator deregistration with 0 pools allows immediate collateral withdrawal', async function () {
- const { manager, registry, ssvNetworkViews } = await loadFixture(deploymentFixture)
+ const { manager, registry, ssvViews } = await loadFixture(deploymentFixture)
const operatorIds = await registry.getOperatorIds()
const deregisteringOperatorId = operatorIds[0]
- const [ operatorOwnerAddress ] = await ssvNetworkViews.getOperatorById(deregisteringOperatorId)
+ const [operatorOwnerAddress] = await ssvViews.getOperatorById(deregisteringOperatorId)
const operatorOwnerSigner = ethers.provider.getSigner(operatorOwnerAddress)
await network.provider.request({
method: 'hardhat_impersonateAccount',
@@ -90,7 +90,7 @@ describe('Operators', async function () {
const resharesRequestedEvents = await manager.queryFilter(manager.filters.ResharesRequested(), -1)
expect(deregisteringOperator.active).equal(false)
- expect(deregisteringOperator.resharing).equal(false)
+ expect(deregisteringOperator.resharing).equal(false)
expect(resharesRequestedEvents.length).equal(0)
const operatorOwnerBalanceBefore = await ethers.provider.getBalance(operatorOwnerAddress)
@@ -98,13 +98,13 @@ describe('Operators', async function () {
await requestWithdrawal.wait()
const operatorOwnerBalanceAfter = await ethers.provider.getBalance(operatorOwnerAddress)
const deregisteredOperator = await registry.getOperator(deregisteringOperatorId)
-
+
expect(deregisteredOperator.collateral.toString()).equal('0')
expect(ethers.utils.formatEther(operatorOwnerBalanceAfter.sub(operatorOwnerBalanceBefore).toString())).contains('9.9')
})
it('Pool exits with 31.0 and recovers from the blamed operator', async function () {
- const { manager, registry, upkeep, views, secondUser, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(secondUserDepositFixture)
+ const { manager, registry, upkeep, views, secondUser, donTransmitter, daoOracle, functionsBillingRegistry } = await loadFixture(secondUserDepositFixture)
const secondStake = await manager.getUserStake(secondUser.address)
const withdraw = await manager.connect(secondUser).requestWithdrawal(secondStake)
@@ -116,12 +116,12 @@ describe('Operators', async function () {
const currentBalance = await ethers.provider.getBalance(withdrawnPoolAddress)
const nextBalance = currentBalance.add(ethers.utils.parseEther(sweptExitedBalance.toString()))
await setBalance(withdrawnPoolAddress, nextBalance)
-
+
await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const reportValues = {
- activeBalance: 0,
+ beaconBalance: 0,
sweptBalance: sweptExitedBalance,
activatedDeposits: 0,
forcedExits: 0,
@@ -130,18 +130,18 @@ describe('Operators', async function () {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: reportValues
})
await reportCompletedExitsHandler({ manager, views, signer: daoOracle, args: { count: 1 } })
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const stake = await manager.getTotalStake()
const userStake = await manager.getUserStake(secondUser.address)
- const blamedOperatorId = 654 // Hardcoded the first operator
+ const blamedOperatorId = 156 // Hardcoded the first operator
const blamedOperator = await registry.getOperator(blamedOperatorId)
expect(ethers.utils.formatEther(stake)).equal('16.0')
diff --git a/contracts/ethereum/test/users.ts b/contracts/ethereum/test/users.ts
index c3b4b8673..29e94ecaf 100644
--- a/contracts/ethereum/test/users.ts
+++ b/contracts/ethereum/test/users.ts
@@ -9,25 +9,25 @@ import { fulfillReport, runUpkeep } from '../helpers/upkeep'
describe('Users', async function () {
it('User\'s 16.0 stake and half withdrawal updates total and user stake, and user balance', async function () {
const { manager } = await loadFixture(deploymentFixture)
- const [, user] = await ethers.getSigners()
+ const [firstUser] = await ethers.getSigners()
const depositAmount = round(16 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
- const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
+ const deposit = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await deposit.wait()
let stake = await manager.getTotalStake()
- let userStake = await manager.getUserStake(user.address)
+ let userStake = await manager.getUserStake(firstUser.address)
expect(ethers.utils.formatEther(stake)).equal('16.0')
expect(ethers.utils.formatEther(userStake)).equal('16.0')
- const userBalanceBefore = await ethers.provider.getBalance(user.address)
- const userWithdrawalRequest = await manager.connect(user).requestWithdrawal(ethers.utils.parseEther('8.0'))
+ const userBalanceBefore = await ethers.provider.getBalance(firstUser.address)
+ const userWithdrawalRequest = await manager.connect(firstUser).requestWithdrawal(ethers.utils.parseEther('8.0'))
await userWithdrawalRequest.wait()
- const userBalanceAfter = await ethers.provider.getBalance(user.address)
+ const userBalanceAfter = await ethers.provider.getBalance(firstUser.address)
stake = await manager.getTotalStake()
- userStake = await manager.getUserStake(user.address)
+ userStake = await manager.getUserStake(firstUser.address)
expect(ethers.utils.formatEther(stake)).equal('8.0')
expect(ethers.utils.formatEther(userStake)).equal('8.0')
@@ -35,11 +35,11 @@ describe('Users', async function () {
})
it('User\'s 64.0 stake and half withdrawal updates total and user stake, and user balance', async function () {
- const { manager, upkeep, views, keeper, daoOracle, functionsBillingRegistry } = await loadFixture(deploymentFixture)
- const [, user] = await ethers.getSigners()
+ const { manager, upkeep, views, functionsBillingRegistry, daoOracle, donTransmitter } = await loadFixture(deploymentFixture)
+ const [firstUser] = await ethers.getSigners()
const depositAmount = round(64 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
- const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
+ const deposit = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
await deposit.wait()
if ((await manager.functionsId()).toNumber() === 0) {
@@ -53,14 +53,14 @@ describe('Users', async function () {
await initiateDepositHandler({ manager, signer: daoOracle })
const pendingPoolIds = await manager.getPendingPoolIds()
-
+
expect(pendingPoolIds.length).equal(2)
- await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await time.increase(time.duration.days(1))
+ await runUpkeep({ donTransmitter, upkeep })
const firstReportValues = {
- activeBalance: 64,
+ beaconBalance: 64,
sweptBalance: 0,
activatedDeposits: 2,
forcedExits: 0,
@@ -69,40 +69,40 @@ describe('Users', async function () {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: firstReportValues
})
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
const stakedPoolIds = await manager.getStakedPoolIds()
-
+
expect(stakedPoolIds.length).equal(2)
let stake = await manager.getTotalStake()
- let userStake = await manager.getUserStake(user.address)
+ let userStake = await manager.getUserStake(firstUser.address)
expect(ethers.utils.formatEther(stake)).equal('64.0')
expect(ethers.utils.formatEther(userStake)).equal('64.0')
- const userBalanceBefore = await ethers.provider.getBalance(user.address)
- const userWithdrawalRequest = await manager.connect(user).requestWithdrawal(ethers.utils.parseEther('32.0'))
+ const userBalanceBefore = await ethers.provider.getBalance(firstUser.address)
+ const userWithdrawalRequest = await manager.connect(firstUser).requestWithdrawal(ethers.utils.parseEther('32.0'))
await userWithdrawalRequest.wait()
stake = await manager.getTotalStake()
- userStake = await manager.getUserStake(user.address)
+ userStake = await manager.getUserStake(firstUser.address)
expect(ethers.utils.formatEther(stake)).equal('32.0')
expect(ethers.utils.formatEther(userStake)).equal('32.0')
- await time.increase(time.duration.days(1))
- await runUpkeep({ upkeep, keeper })
+ await time.increase(time.duration.days(1))
+ await runUpkeep({ donTransmitter, upkeep })
const sweptExitedBalance = 32
const secondReportValues = {
- activeBalance: 32,
+ beaconBalance: 32,
sweptBalance: sweptExitedBalance,
activatedDeposits: 0,
forcedExits: 0,
@@ -111,7 +111,7 @@ describe('Users', async function () {
}
await fulfillReport({
- keeper,
+ donTransmitter,
upkeep,
functionsBillingRegistry,
values: secondReportValues
@@ -125,32 +125,15 @@ describe('Users', async function () {
await reportCompletedExitsHandler({ manager, views, signer: daoOracle, args: { count: 1 } })
const finalizableCompletedExits = await manager.finalizableCompletedExits()
expect(finalizableCompletedExits.toNumber()).equal(1)
- await runUpkeep({ upkeep, keeper })
+ await runUpkeep({ donTransmitter, upkeep })
stake = await manager.getTotalStake()
- userStake = await manager.getUserStake(user.address)
+ userStake = await manager.getUserStake(firstUser.address)
- const userBalanceAfter = await ethers.provider.getBalance(user.address)
+ const userBalanceAfter = await ethers.provider.getBalance(firstUser.address)
expect(ethers.utils.formatEther(stake)).equal('32.0')
expect(ethers.utils.formatEther(userStake)).equal('32.0')
expect(ethers.utils.formatEther(userBalanceAfter.sub(userBalanceBefore))).contains('31.9')
})
-
- it('User\'s 16.0 stake and five withdrawal requests fails on the 6th daily action', async function () {
- const { manager } = await loadFixture(deploymentFixture)
- const [, user] = await ethers.getSigners()
-
- const depositAmount = round(16 * ((100 + await manager.FEE_PERCENT()) / 100), 10)
- const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) })
- await deposit.wait()
-
- for (let i = 0; i < 4; i++) {
- const withdrawalRequest = await manager.connect(user).requestWithdrawal(ethers.utils.parseEther('2.0'))
- await withdrawalRequest.wait()
- }
-
- const failedWithdrawalRequest = manager.connect(user).requestWithdrawal(ethers.utils.parseEther('2.0'))
- await expect(failedWithdrawalRequest).to.be.rejectedWith('Action period maximum reached')
- })
})
\ No newline at end of file
diff --git a/infrastructure/cdk/src/providers/analytics.ts b/infrastructure/cdk/src/providers/analytics.ts
index a3083f8e3..31f08de5a 100644
--- a/infrastructure/cdk/src/providers/analytics.ts
+++ b/infrastructure/cdk/src/providers/analytics.ts
@@ -3,7 +3,7 @@ import * as cdk from 'aws-cdk-lib'
import * as s3 from 'aws-cdk-lib/aws-s3'
import * as glue from '@aws-cdk/aws-glue-alpha'
import { Schema, eventSchema, actionSchema } from '@casimir/data'
-import { kebabCase, pascalCase, snakeCase } from '@casimir/helpers'
+import { kebabCase, pascalCase, snakeCase } from '@casimir/format'
import { Config } from './config'
import { AnalyticsStackProps } from '../interfaces/StackProps'
diff --git a/infrastructure/cdk/src/providers/config.ts b/infrastructure/cdk/src/providers/config.ts
index 7809fb889..380a95fe9 100644
--- a/infrastructure/cdk/src/providers/config.ts
+++ b/infrastructure/cdk/src/providers/config.ts
@@ -1,4 +1,4 @@
-import { pascalCase } from '@casimir/helpers'
+import { pascalCase } from '@casimir/format'
import { ProjectConfig } from '../interfaces/ProjectConfig'
import dataPackage from '@casimir/data/package.json'
diff --git a/infrastructure/cdk/src/providers/dns.ts b/infrastructure/cdk/src/providers/dns.ts
index f8fe63506..2d3d7e690 100644
--- a/infrastructure/cdk/src/providers/dns.ts
+++ b/infrastructure/cdk/src/providers/dns.ts
@@ -3,7 +3,7 @@ import * as cdk from 'aws-cdk-lib'
import * as certmgr from 'aws-cdk-lib/aws-certificatemanager'
import * as route53 from 'aws-cdk-lib/aws-route53'
import { DnsStackProps } from '../interfaces/StackProps'
-import { pascalCase } from '@casimir/helpers'
+import { pascalCase } from '@casimir/format'
import { Config } from './config'
/**
diff --git a/infrastructure/cdk/src/providers/docs.ts b/infrastructure/cdk/src/providers/docs.ts
index 39ec34c1e..c8b8c1c80 100644
--- a/infrastructure/cdk/src/providers/docs.ts
+++ b/infrastructure/cdk/src/providers/docs.ts
@@ -8,7 +8,7 @@ import * as s3Deployment from 'aws-cdk-lib/aws-s3-deployment'
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'
import * as cloudfrontOrigins from 'aws-cdk-lib/aws-cloudfront-origins'
import { DocsStackProps } from '../interfaces/StackProps'
-import { pascalCase } from '@casimir/helpers'
+import { pascalCase } from '@casimir/format'
import { Config } from './config'
/**
diff --git a/infrastructure/cdk/src/providers/landing.ts b/infrastructure/cdk/src/providers/landing.ts
index 4db887fad..7c36ab6c4 100644
--- a/infrastructure/cdk/src/providers/landing.ts
+++ b/infrastructure/cdk/src/providers/landing.ts
@@ -8,7 +8,7 @@ import * as s3Deployment from 'aws-cdk-lib/aws-s3-deployment'
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'
import * as cloudfrontOrigins from 'aws-cdk-lib/aws-cloudfront-origins'
import { LandingStackProps } from '../interfaces/StackProps'
-import { pascalCase } from '@casimir/helpers'
+import { pascalCase } from '@casimir/format'
import { Config } from './config'
/**
diff --git a/infrastructure/cdk/src/providers/network.ts b/infrastructure/cdk/src/providers/network.ts
index 4288922d0..29debec35 100644
--- a/infrastructure/cdk/src/providers/network.ts
+++ b/infrastructure/cdk/src/providers/network.ts
@@ -1,9 +1,8 @@
import { Construct } from 'constructs'
import * as cdk from 'aws-cdk-lib'
import * as ec2 from 'aws-cdk-lib/aws-ec2'
-import * as ecs from 'aws-cdk-lib/aws-ecs'
import { NetworkStackProps } from '../interfaces/StackProps'
-import { pascalCase } from '@casimir/helpers'
+import { pascalCase } from '@casimir/format'
import { Config } from './config'
/**
diff --git a/infrastructure/cdk/src/providers/nodes.ts b/infrastructure/cdk/src/providers/nodes.ts
index 976c72d17..c0d09272d 100644
--- a/infrastructure/cdk/src/providers/nodes.ts
+++ b/infrastructure/cdk/src/providers/nodes.ts
@@ -3,7 +3,7 @@ import * as cdk from 'aws-cdk-lib'
import * as route53 from 'aws-cdk-lib/aws-route53'
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'
import { NodesStackProps } from '../interfaces/StackProps'
-import { kebabCase, pascalCase } from '@casimir/helpers'
+import { kebabCase, pascalCase } from '@casimir/format'
import { Config } from './config'
/**
diff --git a/infrastructure/cdk/src/providers/users.ts b/infrastructure/cdk/src/providers/users.ts
index cedb3d288..a32864115 100644
--- a/infrastructure/cdk/src/providers/users.ts
+++ b/infrastructure/cdk/src/providers/users.ts
@@ -8,7 +8,7 @@ import * as rds from 'aws-cdk-lib/aws-rds'
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'
import { UsersStackProps } from '../interfaces/StackProps'
import { Config } from './config'
-import { kebabCase } from '@casimir/helpers'
+import { kebabCase } from '@casimir/format'
/**
* Users service stack
diff --git a/infrastructure/cdk/src/providers/web.ts b/infrastructure/cdk/src/providers/web.ts
index d97cd65c9..d4ac837f0 100644
--- a/infrastructure/cdk/src/providers/web.ts
+++ b/infrastructure/cdk/src/providers/web.ts
@@ -8,7 +8,7 @@ import * as s3Deployment from 'aws-cdk-lib/aws-s3-deployment'
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'
import * as cloudfrontOrigins from 'aws-cdk-lib/aws-cloudfront-origins'
import { WebStackProps } from '../interfaces/StackProps'
-import { pascalCase } from '@casimir/helpers'
+import { pascalCase } from '@casimir/format'
import { Config } from './config'
/**
diff --git a/package-lock.json b/package-lock.json
index f3ca3754d..7fab5f003 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -143,8 +143,11 @@
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"dev": true
},
- "common/helpers": {
- "name": "@casimir/helpers",
+ "common/env": {
+ "name": "@casimir/env"
+ },
+ "common/events": {
+ "name": "@casimir/events",
"dependencies": {
"ethers": "^5.7.2"
},
@@ -152,18 +155,60 @@
"@types/node": "^17.0.38"
}
},
- "common/helpers/node_modules/@types/node": {
+ "common/events/node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"dev": true
},
- "common/speculos": {
- "name": "@casimir/speculos",
- "dependencies": {
- "@ledgerhq/hw-transport": "^6.27.10"
+ "common/fetch": {
+ "name": "@casimir/fetch",
+ "devDependencies": {
+ "@types/node": "^17.0.38"
}
},
+ "common/fetch/node_modules/@types/node": {
+ "version": "17.0.45",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
+ "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
+ "dev": true
+ },
+ "common/format": {
+ "name": "@casimir/format",
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+ },
+ "common/format/node_modules/@types/node": {
+ "version": "17.0.45",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
+ "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
+ "dev": true
+ },
+ "common/logs": {
+ "name": "@casimir/logs",
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+ },
+ "common/logs/node_modules/@types/node": {
+ "version": "17.0.45",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
+ "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
+ "dev": true
+ },
+ "common/shell": {
+ "name": "@casimir/shell",
+ "devDependencies": {
+ "@types/node": "^17.0.38"
+ }
+ },
+ "common/shell/node_modules/@types/node": {
+ "version": "17.0.45",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
+ "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
+ "dev": true
+ },
"common/ssv": {
"name": "@casimir/ssv",
"dependencies": {
@@ -210,18 +255,20 @@
},
"contracts/ethereum": {
"name": "@casimir/ethereum",
+ "version": "1.0.0-beta.0",
"hasInstallScript": true,
"dependencies": {
"@chainlink/contracts": "^0.6.1",
- "@openzeppelin/contracts": "^4.8.0",
+ "@openzeppelin/contracts": "^4.9.3",
+ "@openzeppelin/contracts-upgradeable": "^4.9.3",
"@uniswap/v3-core": "1.0.1",
"@uniswap/v3-periphery": "^1.4.3"
},
"devDependencies": {
- "@nomicfoundation/hardhat-foundry": "^1.0.2",
"@nomicfoundation/hardhat-network-helpers": "^1.0.6",
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
"@nomiclabs/hardhat-ethers": "^2.0.6",
+ "@openzeppelin/hardhat-upgrades": "^1.28.0",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.3.1",
@@ -230,8 +277,9 @@
"@types/node": "^17.0.45",
"chai": "^4.3.6",
"esno": "^0.16.3",
- "hardhat": "^2.12.2",
+ "hardhat": "^2.12.3",
"hardhat-abi-exporter": "^2.10.1",
+ "hardhat-preprocessor": "^0.1.5",
"localtunnel": "^2.0.2",
"mocha": "^10.0.0",
"typechain": "^8.1.0"
@@ -435,15 +483,15 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/@aws-sdk/client-athena": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-athena/-/client-athena-3.418.0.tgz",
- "integrity": "sha512-DbtkYpkGOfSKBU05TCvVvLihMaKZOfWFQv0csoCQxdBe2JGOENni0aLI6Jb42Em45cw6lEx2v2dL8bXAsSFd7Q==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-athena/-/client-athena-3.421.0.tgz",
+ "integrity": "sha512-5griMVbDxz1M++hyZicLZBYOwN7tIAO8Fi7vGMhrP6Ai8zR84oPqtDLlAzJ9CBQ0joI/kxdZq12xFJrcfcE3sA==",
"peer": true,
"dependencies": {
"@aws-crypto/sha256-browser": "3.0.0",
"@aws-crypto/sha256-js": "3.0.0",
- "@aws-sdk/client-sts": "3.418.0",
- "@aws-sdk/credential-provider-node": "3.418.0",
+ "@aws-sdk/client-sts": "3.421.0",
+ "@aws-sdk/credential-provider-node": "3.421.0",
"@aws-sdk/middleware-host-header": "3.418.0",
"@aws-sdk/middleware-logger": "3.418.0",
"@aws-sdk/middleware-recursion-detection": "3.418.0",
@@ -484,14 +532,14 @@
}
},
"node_modules/@aws-sdk/client-cognito-identity": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.418.0.tgz",
- "integrity": "sha512-8Gib2gMbfCfxNz/FgSRijl47pnmV/rVvyRNoYtk24xndUydhyXKFTB0cqGVDpPv7eRb3wWQ9YZYVuaBDnEdZ1A==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.421.0.tgz",
+ "integrity": "sha512-9htG14uDA/2XhU+vRhBcCG8GAOJ29rV53cxlc6I1YRKD6imXdU+X0ZfMPZCkPjEPGT4hHTpO0vR2J7zY8FXfzg==",
"dependencies": {
"@aws-crypto/sha256-browser": "3.0.0",
"@aws-crypto/sha256-js": "3.0.0",
- "@aws-sdk/client-sts": "3.418.0",
- "@aws-sdk/credential-provider-node": "3.418.0",
+ "@aws-sdk/client-sts": "3.421.0",
+ "@aws-sdk/credential-provider-node": "3.421.0",
"@aws-sdk/middleware-host-header": "3.418.0",
"@aws-sdk/middleware-logger": "3.418.0",
"@aws-sdk/middleware-recursion-detection": "3.418.0",
@@ -531,14 +579,14 @@
}
},
"node_modules/@aws-sdk/client-secrets-manager": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.418.0.tgz",
- "integrity": "sha512-mfRfkjFrWoa6DBP10gWJ6p12L/6dQq7/bfTgH8qCgRjvk/0vF5MGgHfYV6ZIwB+eKXVTiY8Dv//FtmPs67rLkQ==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.421.0.tgz",
+ "integrity": "sha512-uwoSstFm+A60f2/CuIDHqTJdYm4hPMNCzkI3J/pKoD4A6suLIoJ9lEKGV3fdeL456vir4RTwiJG6Llzo+zI+nA==",
"dependencies": {
"@aws-crypto/sha256-browser": "3.0.0",
"@aws-crypto/sha256-js": "3.0.0",
- "@aws-sdk/client-sts": "3.418.0",
- "@aws-sdk/credential-provider-node": "3.418.0",
+ "@aws-sdk/client-sts": "3.421.0",
+ "@aws-sdk/credential-provider-node": "3.421.0",
"@aws-sdk/middleware-host-header": "3.418.0",
"@aws-sdk/middleware-logger": "3.418.0",
"@aws-sdk/middleware-recursion-detection": "3.418.0",
@@ -579,9 +627,9 @@
}
},
"node_modules/@aws-sdk/client-sso": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.418.0.tgz",
- "integrity": "sha512-fakz3YeSW/kCAOJ5w4ObrrQBxsYO8sU8i6WHLv6iWAsYZKAws2Mqa8g89P61+GitSH4z9waksdLouS6ep78/5A==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.421.0.tgz",
+ "integrity": "sha512-40CmW7K2/FZEn3CbOjbpRYeVjKu6aJQlpRHcAgEJGNoVEAnRA3YNH4H0BN2iWWITfYg3B7sIjMm5VE9fCIK1Ng==",
"dependencies": {
"@aws-crypto/sha256-browser": "3.0.0",
"@aws-crypto/sha256-js": "3.0.0",
@@ -623,13 +671,13 @@
}
},
"node_modules/@aws-sdk/client-sts": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.418.0.tgz",
- "integrity": "sha512-L0n0Hw+Pm+BhXTN1bYZ0y4JAMArYgazdHf1nUSlEHndgZicCCuQtlMLxfo3i/IbtWi0dzfZcZ9d/MdAM8p4Jyw==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.421.0.tgz",
+ "integrity": "sha512-/92NOZMcdkBcvGrINk5B/l+6DGcVzYE4Ab3ME4vcY9y//u2gd0yNn5YYRSzzjVBLvhDP3u6CbTfLX2Bm4qihPw==",
"dependencies": {
"@aws-crypto/sha256-browser": "3.0.0",
"@aws-crypto/sha256-js": "3.0.0",
- "@aws-sdk/credential-provider-node": "3.418.0",
+ "@aws-sdk/credential-provider-node": "3.421.0",
"@aws-sdk/middleware-host-header": "3.418.0",
"@aws-sdk/middleware-logger": "3.418.0",
"@aws-sdk/middleware-recursion-detection": "3.418.0",
@@ -671,11 +719,11 @@
}
},
"node_modules/@aws-sdk/credential-provider-cognito-identity": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.418.0.tgz",
- "integrity": "sha512-MakYZsT7fkG1W9IgkBz7PTXG/e6YD2oSEk+hPgwfdMv0YX76qjTU02B2qbbKSGtXichX73MNUPOvygF5XAi6oA==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.421.0.tgz",
+ "integrity": "sha512-x+C7nonKomdBAljTAPtqhU6Xzzaqy08PV1vO5Cp/YYMye+uOGQ2+1x7cfaY5uIHZbbNRUhCmUBKGnwsUyTB1cQ==",
"dependencies": {
- "@aws-sdk/client-cognito-identity": "3.418.0",
+ "@aws-sdk/client-cognito-identity": "3.421.0",
"@aws-sdk/types": "3.418.0",
"@smithy/property-provider": "^2.0.0",
"@smithy/types": "^2.3.3",
@@ -700,13 +748,13 @@
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.418.0.tgz",
- "integrity": "sha512-LTAeKKV85unlSqGNIeqEZ4N9gufaSoH+670n5YTUEk564zHCkUQW0PJomzLF5jKBco6Yfzv6rPBTukd+x9XWqw==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.421.0.tgz",
+ "integrity": "sha512-J5yH/gkpAk6FMeH5F9u5Nr6oG+97tj1kkn5q49g3XMbtWw7GiynadxdtoRBCeIg1C7o2LOQx4B1AnhNhIw1z/g==",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.418.0",
"@aws-sdk/credential-provider-process": "3.418.0",
- "@aws-sdk/credential-provider-sso": "3.418.0",
+ "@aws-sdk/credential-provider-sso": "3.421.0",
"@aws-sdk/credential-provider-web-identity": "3.418.0",
"@aws-sdk/types": "3.418.0",
"@smithy/credential-provider-imds": "^2.0.0",
@@ -720,14 +768,14 @@
}
},
"node_modules/@aws-sdk/credential-provider-node": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.418.0.tgz",
- "integrity": "sha512-VveTjtSC6m8YXj3fQDkMKEZuHv+CR2Z4u/NAN51Fi4xOtIWUtOBj5rfZ8HmBYoBjRF0DtRlPXuMiNnXAzTctfQ==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.421.0.tgz",
+ "integrity": "sha512-g1dvdvfDj0u8B/gOsHR3o1arP4O4QE/dFm2IJBYr/eUdKISMUgbQULWtg4zdtAf0Oz4xN0723i7fpXAF1gTnRA==",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.418.0",
- "@aws-sdk/credential-provider-ini": "3.418.0",
+ "@aws-sdk/credential-provider-ini": "3.421.0",
"@aws-sdk/credential-provider-process": "3.418.0",
- "@aws-sdk/credential-provider-sso": "3.418.0",
+ "@aws-sdk/credential-provider-sso": "3.421.0",
"@aws-sdk/credential-provider-web-identity": "3.418.0",
"@aws-sdk/types": "3.418.0",
"@smithy/credential-provider-imds": "^2.0.0",
@@ -756,11 +804,11 @@
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.418.0.tgz",
- "integrity": "sha512-tUF5Hg/HfaU5t+E7IuvohYlodSIlBXa28xAJPPFxhKrUnvP6AIoW6JLazOtCIQjQgJYEUILV29XX+ojUuITcaw==",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.421.0.tgz",
+ "integrity": "sha512-f8T3L5rhImL6T6RTSvbOxaWw9k2fDOT2DZbNjcPz9ITWmwXj2NNbdHGWuRi3dv2HoY/nW2IJdNxnhdhbn6Fc1A==",
"dependencies": {
- "@aws-sdk/client-sso": "3.418.0",
+ "@aws-sdk/client-sso": "3.421.0",
"@aws-sdk/token-providers": "3.418.0",
"@aws-sdk/types": "3.418.0",
"@smithy/property-provider": "^2.0.0",
@@ -787,19 +835,19 @@
}
},
"node_modules/@aws-sdk/credential-providers": {
- "version": "3.418.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.418.0.tgz",
- "integrity": "sha512-atEybTA0jvP9CpBCPKCoiPz1hjJ/lbRxf67r+fpAqPtfQKutGq/jZm78Yz5kV9F/NJEW2mK2GR/BslCAHc4H8g==",
- "dependencies": {
- "@aws-sdk/client-cognito-identity": "3.418.0",
- "@aws-sdk/client-sso": "3.418.0",
- "@aws-sdk/client-sts": "3.418.0",
- "@aws-sdk/credential-provider-cognito-identity": "3.418.0",
+ "version": "3.421.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.421.0.tgz",
+ "integrity": "sha512-Mhz3r2N0YlOAhb1ZZYrP76VA1aIlJZw3IAwYwlS+hO4sAwp8iY6wCKiumqplXkVgK+ObLxlS9W/aW+2SAKsB7w==",
+ "dependencies": {
+ "@aws-sdk/client-cognito-identity": "3.421.0",
+ "@aws-sdk/client-sso": "3.421.0",
+ "@aws-sdk/client-sts": "3.421.0",
+ "@aws-sdk/credential-provider-cognito-identity": "3.421.0",
"@aws-sdk/credential-provider-env": "3.418.0",
- "@aws-sdk/credential-provider-ini": "3.418.0",
- "@aws-sdk/credential-provider-node": "3.418.0",
+ "@aws-sdk/credential-provider-ini": "3.421.0",
+ "@aws-sdk/credential-provider-node": "3.421.0",
"@aws-sdk/credential-provider-process": "3.418.0",
- "@aws-sdk/credential-provider-sso": "3.418.0",
+ "@aws-sdk/credential-provider-sso": "3.421.0",
"@aws-sdk/credential-provider-web-identity": "3.418.0",
"@aws-sdk/types": "3.418.0",
"@smithy/credential-provider-imds": "^2.0.0",
@@ -1706,28 +1754,44 @@
"resolved": "common/data",
"link": true
},
+ "node_modules/@casimir/env": {
+ "resolved": "common/env",
+ "link": true
+ },
"node_modules/@casimir/ethereum": {
"resolved": "contracts/ethereum",
"link": true
},
- "node_modules/@casimir/functions": {
- "resolved": "services/functions",
+ "node_modules/@casimir/events": {
+ "resolved": "common/events",
+ "link": true
+ },
+ "node_modules/@casimir/fetch": {
+ "resolved": "common/fetch",
+ "link": true
+ },
+ "node_modules/@casimir/format": {
+ "resolved": "common/format",
"link": true
},
- "node_modules/@casimir/helpers": {
- "resolved": "common/helpers",
+ "node_modules/@casimir/functions": {
+ "resolved": "services/functions",
"link": true
},
"node_modules/@casimir/landing": {
"resolved": "apps/landing",
"link": true
},
+ "node_modules/@casimir/logs": {
+ "resolved": "common/logs",
+ "link": true
+ },
"node_modules/@casimir/oracle": {
"resolved": "services/oracle",
"link": true
},
- "node_modules/@casimir/speculos": {
- "resolved": "common/speculos",
+ "node_modules/@casimir/shell": {
+ "resolved": "common/shell",
"link": true
},
"node_modules/@casimir/ssv": {
@@ -2199,9 +2263,9 @@
}
},
"node_modules/@eslint-community/regexpp": {
- "version": "4.8.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.2.tgz",
- "integrity": "sha512-0MGxAVt1m/ZK+LTJp/j0qF7Hz97D9O/FH9Ms3ltnyIdDD57cbb1ACIQTkbHvNXtWDv5TPq7w5Kq56+cNukbo7g==",
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.0.tgz",
+ "integrity": "sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==",
"dev": true,
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
@@ -4033,6 +4097,7 @@
"resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz",
"integrity": "sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@types/chai-as-promised": "^7.1.3",
@@ -4047,89 +4112,6 @@
"hardhat": "^2.9.4"
}
},
- "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-foundry/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==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-foundry/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==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-foundry/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==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@nomicfoundation/hardhat-foundry/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==",
- "dev": true
- },
- "node_modules/@nomicfoundation/hardhat-foundry/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==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@nomicfoundation/hardhat-foundry/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==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-foundry/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==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"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",
@@ -4365,6 +4347,7 @@
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz",
"integrity": "sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@ethersproject/address": "^5.0.2",
@@ -4386,6 +4369,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
+ "peer": true,
"dependencies": {
"color-convert": "^1.9.0"
},
@@ -4393,11 +4377,25 @@
"node": ">=4"
}
},
+ "node_modules/@nomiclabs/hardhat-etherscan/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/@nomiclabs/hardhat-etherscan/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==",
"dev": true,
+ "peer": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@@ -4412,6 +4410,7 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
+ "peer": true,
"dependencies": {
"color-name": "1.1.3"
}
@@ -4420,13 +4419,15 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/@nomiclabs/hardhat-etherscan/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==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=0.8.0"
}
@@ -4436,6 +4437,7 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -4445,6 +4447,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -4454,6 +4457,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
+ "peer": true,
"dependencies": {
"has-flag": "^3.0.0"
},
@@ -4713,9 +4717,9 @@
}
},
"node_modules/@openzeppelin/upgrades-core": {
- "version": "1.29.0",
- "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.29.0.tgz",
- "integrity": "sha512-csZvAMNqUJjMDNBPbaXcV9Nlo4oagMD/HkOBHTpYbBTpnmUhwPVHOMv+Rl0RatBdLHuGc6hw88h80k5PWkEeWw==",
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.30.0.tgz",
+ "integrity": "sha512-guW3EaTp/cet/O1uAmEcupHhtEGMzzYGsru2LMllFL5INWmRfeCHSVQu4TjkCLpoYHJoOIGSvosjoCyJL4oEaQ==",
"dev": true,
"dependencies": {
"cbor": "^9.0.0",
@@ -4725,24 +4729,12 @@
"ethereumjs-util": "^7.0.3",
"minimist": "^1.2.7",
"proper-lockfile": "^4.1.1",
- "solidity-ast": "^0.4.26"
+ "solidity-ast": "^0.4.51"
},
"bin": {
"openzeppelin-upgrades-core": "dist/cli/cli.js"
}
},
- "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/@panva/asn1.js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz",
@@ -6221,6 +6213,7 @@
"resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.6.tgz",
"integrity": "sha512-cQLhk8fFarRVZAXUQV1xEnZgMoPxqKojBvRkqPCKPQCzEhpbbSKl1Uu75kDng7k5Ln6LQLUmNBjLlFthCgm1NA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/chai": "*"
}
@@ -6425,9 +6418,9 @@
"dev": true
},
"node_modules/@types/mime": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
- "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz",
+ "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg=="
},
"node_modules/@types/minimatch": {
"version": "5.1.2",
@@ -6437,9 +6430,9 @@
"peer": true
},
"node_modules/@types/minimist": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
- "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz",
+ "integrity": "sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==",
"dev": true
},
"node_modules/@types/mocha": {
@@ -6449,9 +6442,9 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.7.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.0.tgz",
- "integrity": "sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg=="
+ "version": "20.7.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.1.tgz",
+ "integrity": "sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg=="
},
"node_modules/@types/pbkdf2": {
"version": "3.1.0",
@@ -6490,9 +6483,9 @@
"integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg=="
},
"node_modules/@types/range-parser": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
- "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz",
+ "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA=="
},
"node_modules/@types/readable-stream": {
"version": "2.3.15",
@@ -6517,9 +6510,9 @@
"dev": true
},
"node_modules/@types/responselike": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
- "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz",
+ "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==",
"dependencies": {
"@types/node": "*"
}
@@ -6829,14 +6822,14 @@
}
},
"node_modules/@uniswap/v3-periphery": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.4.3.tgz",
- "integrity": "sha512-80c+wtVzl5JJT8UQskxVYYG3oZb4pkhY0zDe0ab/RX4+8f9+W5d8wI4BT0wLB0wFQTSnbW+QdBSpkHA/vRyGBA==",
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/@uniswap/v3-periphery/-/v3-periphery-1.4.4.tgz",
+ "integrity": "sha512-S4+m+wh8HbWSO3DKk4LwUCPZJTpCugIsHrWR86m/OrUyvSqGDTXKFfc2sMuGXCZrD1ZqO3rhQsKgdWg3Hbb2Kw==",
"dependencies": {
"@openzeppelin/contracts": "3.4.2-solc-0.7",
"@uniswap/lib": "^4.0.1-alpha",
- "@uniswap/v2-core": "1.0.1",
- "@uniswap/v3-core": "1.0.0",
+ "@uniswap/v2-core": "^1.0.1",
+ "@uniswap/v3-core": "^1.0.0",
"base64-sol": "1.0.1"
},
"engines": {
@@ -6848,14 +6841,6 @@
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz",
"integrity": "sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA=="
},
- "node_modules/@uniswap/v3-periphery/node_modules/@uniswap/v3-core": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.0.tgz",
- "integrity": "sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA==",
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@vitejs/plugin-vue": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz",
@@ -8140,9 +8125,9 @@
}
},
"node_modules/aws-cdk": {
- "version": "2.98.0",
- "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.98.0.tgz",
- "integrity": "sha512-K8WCstCTmJo7dOwzAfUxhWmRYs9FmtFMpKh0OkEOs7iJ1HsNvAOz2LUURkVMqINXgfhmqqjgK6PQxI4AfgOdGA==",
+ "version": "2.99.0",
+ "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.99.0.tgz",
+ "integrity": "sha512-zrgo/6eoBvggyRLcJc69ZmSekp3TDOyk5I6HF0vahYFAZciZpbtEPXnVUdZ4OJRX5wuwJ4Ots9FZuVrSE1zdww==",
"dev": true,
"bin": {
"cdk": "bin/cdk"
@@ -8953,6 +8938,17 @@
"ms": "2.0.0"
}
},
+ "node_modules/body-parser/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==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -9166,9 +9162,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.21.11",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.11.tgz",
- "integrity": "sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==",
+ "version": "4.22.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.0.tgz",
+ "integrity": "sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA==",
"dev": true,
"funding": [
{
@@ -9185,8 +9181,8 @@
}
],
"dependencies": {
- "caniuse-lite": "^1.0.30001538",
- "electron-to-chromium": "^1.4.526",
+ "caniuse-lite": "^1.0.30001539",
+ "electron-to-chromium": "^1.4.530",
"node-releases": "^2.0.13",
"update-browserslist-db": "^1.0.13"
},
@@ -9427,9 +9423,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001539",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz",
- "integrity": "sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==",
+ "version": "1.0.30001541",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz",
+ "integrity": "sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw==",
"dev": true,
"funding": [
{
@@ -9485,15 +9481,15 @@
}
},
"node_modules/cbor": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz",
- "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==",
+ "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": ">=12.19"
+ "node": ">=16"
}
},
"node_modules/cfb": {
@@ -9509,17 +9505,17 @@
}
},
"node_modules/chai": {
- "version": "4.3.8",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz",
- "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==",
+ "version": "4.3.10",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
+ "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
"dependencies": {
"assertion-error": "^1.1.0",
- "check-error": "^1.0.2",
- "deep-eql": "^4.1.2",
- "get-func-name": "^2.0.0",
- "loupe": "^2.3.1",
+ "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.5"
+ "type-detect": "^4.0.8"
},
"engines": {
"node": ">=4"
@@ -9530,6 +9526,7 @@
"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"
},
@@ -9589,9 +9586,12 @@
}
},
"node_modules/check-error": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
- "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
+ "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
+ "dependencies": {
+ "get-func-name": "^2.0.2"
+ },
"engines": {
"node": "*"
}
@@ -10680,17 +10680,6 @@
"node": ">=12"
}
},
- "node_modules/d3-dsv/node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
@@ -11593,9 +11582,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
- "version": "1.4.530",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.530.tgz",
- "integrity": "sha512-rsJ9O8SCI4etS8TBsXuRfHa2eZReJhnGf5MHZd3Vo05PukWHKXhk3VQGbHHnDLa8nZz9woPCpLCMQpLGgkGNRA==",
+ "version": "1.4.534",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.534.tgz",
+ "integrity": "sha512-ikY7wAMtMt3jTnHsHG0YLl4MKJiKz2tgidenGSNgwUX2StBLNZ8VCxflD9tZK/ceTs4j8gDC9+6LQQ6iGkK04g==",
"dev": true
},
"node_modules/elliptic": {
@@ -13735,6 +13724,18 @@
"node": ">=4"
}
},
+ "node_modules/external-editor/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/extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -14036,6 +14037,15 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
"dev": true
},
+ "node_modules/fmix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz",
+ "integrity": "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==",
+ "dev": true,
+ "dependencies": {
+ "imul": "^1.0.0"
+ }
+ },
"node_modules/follow-redirects": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
@@ -14241,9 +14251,9 @@
}
},
"node_modules/fx": {
- "version": "30.1.1",
- "resolved": "https://registry.npmjs.org/fx/-/fx-30.1.1.tgz",
- "integrity": "sha512-Ntv0ZqytFEwbt2UX2PZie2IYpqrBUKpxHm4lxnQ1fKvcMq5m2Ou6LpSoF7OBHD4vKL7FqXrQ2/s9Fhm+SgCDHg==",
+ "version": "30.2.0",
+ "resolved": "https://registry.npmjs.org/fx/-/fx-30.2.0.tgz",
+ "integrity": "sha512-rIYQBmx85Jfhd3pkSw06YPgvSvfTi022ZXTeFDkcCZGCs5nt3sjqFBGtcMFe1TR2S00RDz63be0ab5mhCiOLBw==",
"dev": true,
"bin": {
"fx": "index.js"
@@ -14751,9 +14761,9 @@
}
},
"node_modules/hardhat": {
- "version": "2.17.3",
- "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.17.3.tgz",
- "integrity": "sha512-SFZoYVXW1bWJZrIIKXOA+IgcctfuKXDwENywiYNT2dM3YQc4fXNaTbuk/vpPzHIF50upByx4zW5EqczKYQubsA==",
+ "version": "2.17.4",
+ "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.17.4.tgz",
+ "integrity": "sha512-YTyHjVc9s14CY/O7Dbtzcr/92fcz6AzhrMaj6lYsZpYPIPLzOrFCZHHPxfGQB6FiE6IPNE0uJaAbr7zGF79goA==",
"dev": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
@@ -14852,6 +14862,18 @@
"hardhat": "^2.0.2"
}
},
+ "node_modules/hardhat-preprocessor": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/hardhat-preprocessor/-/hardhat-preprocessor-0.1.5.tgz",
+ "integrity": "sha512-j8m44mmPxpxAAd0G8fPHRHOas/INZdzptSur0TNJvMEGcFdLDhbHHxBcqZVQ/bmiW42q4gC60AP4CXn9EF018g==",
+ "dev": true,
+ "dependencies": {
+ "murmur-128": "^0.2.1"
+ },
+ "peerDependencies": {
+ "hardhat": "^2.0.5"
+ }
+ },
"node_modules/hardhat/node_modules/@noble/hashes": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
@@ -15403,11 +15425,11 @@
"integrity": "sha512-198g3lHrs1nMr4FBfJL3cBMl89NhJat342c684JVYJPlPpjFY2RBZAzD/rpAtg8LIOGXzNjcZzIb+IQCfY4Dqw=="
},
"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==",
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
@@ -15509,6 +15531,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/imul": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz",
+ "integrity": "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -17444,9 +17475,9 @@
}
},
"node_modules/libphonenumber-js": {
- "version": "1.10.44",
- "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.44.tgz",
- "integrity": "sha512-svlRdNBI5WgBjRC20GrCfbFiclbF0Cx+sCcQob/C1r57nsoq0xg8r65QbTyVyweQIlB33P+Uahyho6EMYgcOyQ=="
+ "version": "1.10.45",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.45.tgz",
+ "integrity": "sha512-eeHcvGafEYCaKB4fo2uBINfG7j7PcGwBHUaTVfbwl/6KcjCgIKNlIOsSXVRp9BH10NQwmvvk+nQ1e/Yp4BGB7w=="
},
"node_modules/lilconfig": {
"version": "2.1.0",
@@ -18657,6 +18688,17 @@
"buffer": "^5.5.0"
}
},
+ "node_modules/murmur-128": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/murmur-128/-/murmur-128-0.2.1.tgz",
+ "integrity": "sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==",
+ "dev": true,
+ "dependencies": {
+ "encode-utf8": "^1.0.2",
+ "fmix": "^0.1.0",
+ "imul": "^1.0.0"
+ }
+ },
"node_modules/mute-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
@@ -19212,7 +19254,8 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz",
"integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/os-name": {
"version": "5.1.0",
@@ -20338,9 +20381,9 @@
}
},
"node_modules/pure-rand": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.3.tgz",
- "integrity": "sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==",
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz",
+ "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==",
"dev": true,
"funding": [
{
@@ -20618,6 +20661,17 @@
"node": ">= 0.8"
}
},
+ "node_modules/raw-body/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==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -21462,9 +21516,9 @@
}
},
"node_modules/ripple-address-codec": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-4.3.0.tgz",
- "integrity": "sha512-Tvd81i7hpDmNqHvkj6iYlj8Tv3I1Romw5gfjni9eacewJvGV2xe+p2y0FAw39z72qfciRMhQyHvpnviBcWVBNw==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-4.3.1.tgz",
+ "integrity": "sha512-Qa3+9wKVvpL/xYtT6+wANsn0A1QcC5CT6IMZbRJZ/1lGt7gmwIfsrCuz1X0+LCEO7zgb+3UT1I1dc0k/5dwKQQ==",
"dependencies": {
"base-x": "^3.0.9",
"create-hash": "^1.1.2"
@@ -21474,16 +21528,16 @@
}
},
"node_modules/ripple-binary-codec": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-1.9.0.tgz",
- "integrity": "sha512-vJlY23rRrP9XPD9bo63lAvZphjj1OGtfLzEUxlYYD7SJvDbYEaiEsriC69LKOXMft5sCFRvCsLGOeSDAdZW9hw==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-1.10.0.tgz",
+ "integrity": "sha512-qWXxubgXBV3h5NTaaLiusZ1FhPqSy+bCYHHarfZ3bMmO2alRa1Ox61jvX1Zyozok8PcF3gs3bKwZci4RTlA07w==",
"dependencies": {
"assert": "^2.0.0",
"big-integer": "^1.6.48",
"buffer": "6.0.3",
"create-hash": "^1.2.0",
"decimal.js": "^10.2.0",
- "ripple-address-codec": "^4.3.0"
+ "ripple-address-codec": "^4.3.1"
},
"engines": {
"node": ">= 10"
@@ -21513,15 +21567,15 @@
}
},
"node_modules/ripple-keypairs": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-1.3.0.tgz",
- "integrity": "sha512-LzM3Up9Pwz3dYqnczzNptimN3AxtjeGbDGeiOzREzbkslKiZcJ615b/ghBN4H23SC6W1GAL95juEzzimDi4THw==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-1.3.1.tgz",
+ "integrity": "sha512-dmPlraWKJciFJxHcoubDahGnoIalG5e/BtV6HNDUs7wLXmtnLMHt6w4ed9R8MTL2zNrVPiIdI/HCtMMo0Tm7JQ==",
"dependencies": {
"bn.js": "^5.1.1",
"brorand": "^1.0.5",
"elliptic": "^6.5.4",
"hash.js": "^1.0.3",
- "ripple-address-codec": "^4.3.0"
+ "ripple-address-codec": "^4.3.1"
},
"engines": {
"node": ">= 10"
@@ -21583,9 +21637,9 @@
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"node_modules/rollup": {
- "version": "3.29.3",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.3.tgz",
- "integrity": "sha512-T7du6Hum8jOkSWetjRgbwpM6Sy0nECYrYRSmZjayFcOddtKJWU4d17AC3HNUk7HRuqy4p+G7aEZclSHytqUmEg==",
+ "version": "3.29.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
+ "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -26407,7 +26461,6 @@
"name": "@casimir/functions",
"dependencies": {
"@chainlink/env-enc": "^1.0.5",
- "@openzeppelin/contracts": "4.8.3",
"axios": "^1.1.3",
"crypto-js": "^4.1.1",
"is-http-url": "^2.0.0",
@@ -26417,40 +26470,28 @@
"vm2": "^3.9.18"
},
"devDependencies": {
- "@chainlink/contracts": "0.5.1",
"@ethersproject/abi": "^5.7.0",
"@ethersproject/providers": "^5.7.1",
- "@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
- "@nomicfoundation/hardhat-network-helpers": "^1.0.6",
- "@nomicfoundation/hardhat-toolbox": "^2.0.0",
- "@nomiclabs/hardhat-ethers": "^2.2.2",
- "@nomiclabs/hardhat-etherscan": "^3.1.0",
- "@openzeppelin/hardhat-upgrades": "^1.22.1",
- "@typechain/ethers-v5": "^10.1.0",
- "@typechain/hardhat": "^6.1.3",
+ "cbor": "^9.0.1",
"chai": "^4.3.6",
+ "dotenv": "^16.0.3",
+ "esno": "^0.17.0",
"eth-crypto": "^2.4.0",
- "ethers": "^5.7.2",
- "hardhat": "^2.14.0",
- "typechain": "^8.1.0"
+ "ethers": "^5.7.2"
}
},
- "services/functions/node_modules/@chainlink/contracts": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.5.1.tgz",
- "integrity": "sha512-3PDBJ38Sd6Ml9h7FNK/tZQti+kTCdXUq1qzE6E59CnlzycsV9ElPvf2hTvs9Mi9C6pEx2Mmw9yhZMfBktYUInQ==",
+ "services/functions/node_modules/esno": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/esno/-/esno-0.17.0.tgz",
+ "integrity": "sha512-w78cQGlptQfsBYfootUCitsKS+MD74uR5L6kNsvwVkJsfzEepIafbvWsx2xK4rcFP4IUftt4F6J8EhagUxX+Bg==",
"dev": true,
"dependencies": {
- "@eth-optimism/contracts": "^0.5.21",
- "@openzeppelin/contracts": "^4.3.3",
- "@openzeppelin/contracts-v0.7": "npm:@openzeppelin/contracts@v3.4.2"
+ "tsx": "^3.12.7"
+ },
+ "bin": {
+ "esno": "esno.js"
}
},
- "services/functions/node_modules/@openzeppelin/contracts": {
- "version": "4.8.3",
- "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.8.3.tgz",
- "integrity": "sha512-bQHV8R9Me8IaJoJ2vPG4rXcL7seB7YVuskr4f+f5RyOStSZetwzkWtoqDMl5erkBJy0lDRUnIR2WIkPiC0GJlg=="
- },
"services/oracle": {
"name": "@casimir/oracle",
"version": "0.0.1",
diff --git a/package.json b/package.json
index 87124384a..0f7b57921 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"scripts": {
"clean": "npx esno scripts/root/clean.ts",
"deploy:cdk": "npx esno -r dotenv/config scripts/cdk/deploy.ts",
+ "deploy:ethereum": "npx esno -r dotenv/config scripts/ethereum/deploy.ts",
"dev": "npx esno -r dotenv/config scripts/root/dev.ts",
"dev:ethereum": "npx esno -r dotenv/config scripts/ethereum/dev.ts",
"dev:landing": "npm run dev --workspace @casimir/landing",
diff --git a/scripts/actions/test.ts b/scripts/actions/test.ts
index 51d5d47e3..3bce8d6c1 100755
--- a/scripts/actions/test.ts
+++ b/scripts/actions/test.ts
@@ -1,5 +1,5 @@
import { loadCredentials } from '@casimir/aws'
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
/**
* Test a workflow from `.github/workflows`
diff --git a/scripts/cdk/deploy.ts b/scripts/cdk/deploy.ts
index deb2e9777..2a3f20576 100755
--- a/scripts/cdk/deploy.ts
+++ b/scripts/cdk/deploy.ts
@@ -1,5 +1,6 @@
import { getSecret, loadCredentials } from '@casimir/aws'
-import { run } from '@casimir/helpers'
+import { ETHEREUM_CONTRACTS, ETHEREUM_RPC_URL } from '@casimir/env'
+import { run } from '@casimir/shell'
/**
* Deploy CDK stacks
@@ -12,14 +13,27 @@ void async function () {
await loadCredentials()
process.env.AWS_ACCOUNT = await getSecret('casimir-aws-account')
- process.env.ETHEREUM_RPC_URL = 'https://nodes.casimir.co/eth/hardhat'
process.env.USERS_URL = `https://users.${process.env.STAGE}.casimir.co`
-
- process.env.PUBLIC_MANAGER_ADDRESS = '0x5d35a44Db8a390aCfa997C9a9Ba3a2F878595630'
- process.env.PUBLIC_VIEWS_ADDRESS = '0xC88C4022347305336E344e624E5Fa4fB8e61c21E'
- process.env.PUBLIC_REGISTRY_ADDRESS = '0xB567C0E87Ec176177E44C91577704267C24Fbd83'
- process.env.PUBLIC_ETHEREUM_RPC_URL = process.env.ETHEREUM_RPC_URL
+ process.env.CRYPTO_COMPARE_API_KEY = await getSecret('casimir-crypto-compare-api-key')
+
+ const networkKey = process.env.NETWORK?.toUpperCase() || process.env.FORK?.toUpperCase() || 'TESTNET'
+ process.env.ETHEREUM_RPC_URL = ETHEREUM_RPC_URL[networkKey]
+ process.env.MANAGER_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.MANAGER_ADDRESS
+ process.env.REGISTRY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.REGISTRY_ADDRESS
+ process.env.UPKEEP_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.UPKEEP_ADDRESS
+ process.env.VIEWS_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.VIEWS_ADDRESS
+ process.env.SSV_NETWORK_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_NETWORK_ADDRESS
+ process.env.SSV_VIEWS_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_VIEWS_ADDRESS
+
process.env.PUBLIC_USERS_URL = process.env.USERS_URL
+ process.env.PUBLIC_CRYPTO_COMPARE_API_KEY = process.env.CRYPTO_COMPARE_API_KEY
+ process.env.PUBLIC_ETHEREUM_RPC_URL = process.env.ETHEREUM_RPC_URL
+ process.env.PUBLIC_MANAGER_ADDRESS = process.env.MANAGER_ADDRESS
+ process.env.PUBLIC_REGISTRY_ADDRESS = process.env.REGISTRY_ADDRESS
+ process.env.PUBLIC_UPKEEP_ADDRESS = process.env.UPKEEP_ADDRESS
+ process.env.PUBLIC_VIEWS_ADDRESS = process.env.VIEWS_ADDRESS
+ process.env.PUBLIC_SSV_NETWORK_ADDRESS = process.env.SSV_NETWORK_ADDRESS
+ process.env.PUBLIC_SSV_VIEWS_ADDRESS = process.env.SSV_VIEWS_ADDRESS
process.env.PUBLIC_CRYPTO_COMPARE_API_KEY = await getSecret('casimir-crypto-compare-api-key')
process.env.PUBLIC_WALLET_CONNECT_PROJECT_ID = await getSecret('casimir-wallet-connect-project-id')
diff --git a/scripts/cdk/test.ts b/scripts/cdk/test.ts
index 2eb0e3d6b..2648f8aa0 100644
--- a/scripts/cdk/test.ts
+++ b/scripts/cdk/test.ts
@@ -1,5 +1,5 @@
import { getSecret, loadCredentials } from '@casimir/aws'
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
/**
* Test CDK stacks
@@ -11,18 +11,8 @@ void async function () {
await loadCredentials()
process.env.AWS_ACCOUNT = await getSecret('casimir-aws-account')
-
- process.env.ETHEREUM_RPC_URL = 'https://nodes.casimir.co/eth/hardhat'
process.env.USERS_URL = `https://users.${process.env.STAGE}.casimir.co`
- process.env.PUBLIC_MANAGER_ADDRESS = '0x5d35a44Db8a390aCfa997C9a9Ba3a2F878595630'
- process.env.PUBLIC_VIEWS_ADDRESS = '0xC88C4022347305336E344e624E5Fa4fB8e61c21E'
- process.env.PUBLIC_REGISTRY_ADDRESS = '0xB567C0E87Ec176177E44C91577704267C24Fbd83'
- process.env.PUBLIC_ETHEREUM_RPC_URL = process.env.ETHEREUM_RPC_URL
- process.env.PUBLIC_USERS_URL = process.env.USERS_URL
- process.env.PUBLIC_CRYPTO_COMPARE_API_KEY = await getSecret('casimir-crypto-compare-api-key')
- process.env.PUBLIC_WALLET_CONNECT_PROJECT_ID = await getSecret('casimir-wallet-connect-project-id')
-
await run('npm run build --workspace @casimir/ethereum')
await run('npm run build:docs --workspace @casimir/ethereum')
await run('npm run build --workspace @casimir/landing')
diff --git a/scripts/ethereum/deploy.ts b/scripts/ethereum/deploy.ts
new file mode 100644
index 000000000..4c2397d67
--- /dev/null
+++ b/scripts/ethereum/deploy.ts
@@ -0,0 +1,24 @@
+import { loadCredentials, getSecret } from '@casimir/aws'
+import { ETHEREUM_NETWORK_NAME, ETHEREUM_RPC_URL } from '@casimir/env'
+import { run } from '@casimir/shell'
+
+/**
+ * Deploy ethereum contracts
+ */
+void async function () {
+ if (process.env.USE_SECRETS !== 'false') {
+ await loadCredentials()
+ process.env.BIP39_SEED = process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') as string
+ } else {
+ process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
+ }
+ console.log(`Your mnemonic seed is ${process.env.BIP39_SEED}`)
+
+ process.env.NETWORK = process.env.NETWORK || 'testnet'
+ process.env.ETHEREUM_RPC_URL = ETHEREUM_RPC_URL[process.env.NETWORK.toUpperCase()]
+ const networkName = ETHEREUM_NETWORK_NAME[process.env.NETWORK.toUpperCase()]
+
+ console.log(`Using ${networkName} network from ${process.env.ETHEREUM_RPC_URL}`)
+
+ run(`npm run deploy --workspace @casimir/ethereum -- --network ${networkName}`)
+}()
diff --git a/scripts/ethereum/dev.ts b/scripts/ethereum/dev.ts
index 938f4af0c..2dff56433 100644
--- a/scripts/ethereum/dev.ts
+++ b/scripts/ethereum/dev.ts
@@ -1,57 +1,48 @@
import { ethers } from 'ethers'
-import { getWallet, run } from '@casimir/helpers'
import { loadCredentials, getSecret } from '@casimir/aws'
+import { ETHEREUM_CONTRACTS, ETHEREUM_NETWORK_NAME, ETHEREUM_RPC_URL } from '@casimir/env'
+import { run } from '@casimir/shell'
/**
* Run an ethereum development environment
*/
void async function () {
-
- enum ETHEREUM_FORK_URL {
- MAINNET = 'https://mainnet.infura.io/v3/46a379ac6895489f812f33beb726b03b',
- TESTNET = 'https://goerli.infura.io/v3/46a379ac6895489f812f33beb726b03b'
- }
-
if (process.env.USE_SECRETS !== 'false') {
await loadCredentials()
+ process.env.BIP39_SEED = process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') as string
+ } else {
+ process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
}
+ console.log(`Your mnemonic seed is ${process.env.BIP39_SEED}`)
- process.env.BIP39_SEED = process.env.USE_SECRETS !== 'false' ? process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') : process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
process.env.FORK = process.env.FORK || 'testnet'
process.env.TUNNEL = process.env.TUNNEL || 'false'
process.env.MINING_INTERVAL = '12'
process.env.ETHEREUM_RPC_URL = 'http://127.0.0.1:8545'
- console.log(`Your mnemonic seed is ${process.env.BIP39_SEED}`)
-
- process.env.ETHEREUM_FORK_RPC_URL = ETHEREUM_FORK_URL[process.env.FORK.toUpperCase()]
+ process.env.ETHEREUM_FORK_RPC_URL = ETHEREUM_RPC_URL[process.env.FORK.toUpperCase()]
if (!process.env.ETHEREUM_FORK_RPC_URL) {
throw new Error(`Ethereum ${process.env.FORK} is not supported`)
}
- console.log(`Using ${process.env.FORK} fork from ${process.env.ETHEREUM_FORK_RPC_URL}`)
+ const networkName = ETHEREUM_NETWORK_NAME[process.env.FORK.toUpperCase()]
+
+ console.log(`Using ${networkName} fork from ${process.env.ETHEREUM_FORK_RPC_URL}`)
console.log(`Serving local fork at ${process.env.ETHEREUM_RPC_URL}`)
const provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_FORK_RPC_URL)
process.env.ETHEREUM_FORK_BLOCK = process.env.ETHEREUM_FORK_BLOCK || `${await provider.getBlockNumber() - 5}`
console.log(`📍 Forking started at ${process.env.ETHEREUM_FORK_BLOCK}`)
- const wallet = getWallet(process.env.BIP39_SEED)
+ const wallet = ethers.Wallet.fromMnemonic(process.env.BIP39_SEED)
+
+ // Account for the mock, beacon, and library deployments
+ const walletNonce = await provider.getTransactionCount(wallet.address) + 11
- // Account for the mock Chainlink functions deployments
- const deployerNonce = await provider.getTransactionCount(wallet.address) + 5
-
if (!process.env.MANAGER_ADDRESS) {
process.env.MANAGER_ADDRESS = ethers.utils.getContractAddress({
from: wallet.address,
- nonce: deployerNonce
- })
- }
-
- if (!process.env.VIEWS_ADDRESS) {
- process.env.VIEWS_ADDRESS = ethers.utils.getContractAddress({
- from: wallet.address,
- nonce: deployerNonce + 1
+ nonce: walletNonce
})
}
@@ -69,9 +60,16 @@ void async function () {
})
}
- process.env.SSV_NETWORK_ADDRESS = '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3'
- process.env.SSV_NETWORK_VIEWS_ADDRESS = '0x8dB45282d7C4559fd093C26f677B3837a5598914'
- process.env.UNISWAP_V3_FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984'
+ if (!process.env.VIEWS_ADDRESS) {
+ process.env.VIEWS_ADDRESS = ethers.utils.getContractAddress({
+ from: wallet.address,
+ nonce: walletNonce + 1
+ })
+ }
+
+ process.env.SSV_NETWORK_ADDRESS = ETHEREUM_CONTRACTS[process.env.FORK.toUpperCase()]?.SSV_NETWORK_ADDRESS
+ process.env.SSV_VIEWS_ADDRESS = ETHEREUM_CONTRACTS[process.env.FORK.toUpperCase()]?.SSV_VIEWS_ADDRESS
+ process.env.SWAP_FACTORY_ADDRESS = ETHEREUM_CONTRACTS[process.env.FORK.toUpperCase()]?.SWAP_FACTORY_ADDRESS
run('npm run node --workspace @casimir/ethereum')
const hardhatWaitTime = 2500
diff --git a/scripts/ethereum/test.ts b/scripts/ethereum/test.ts
index dd5b650f9..7431afcd7 100755
--- a/scripts/ethereum/test.ts
+++ b/scripts/ethereum/test.ts
@@ -1,50 +1,42 @@
import { ethers } from 'ethers'
-import { getWallet, run } from '@casimir/helpers'
import { loadCredentials, getSecret } from '@casimir/aws'
+import { ETHEREUM_CONTRACTS, ETHEREUM_NETWORK_NAME, ETHEREUM_RPC_URL } from '@casimir/env'
+import { run } from '@casimir/shell'
/**
* Test ethereum contracts and services
*/
void async function () {
-
- enum ETHEREUM_FORK_URL {
- MAINNET = 'https://mainnet.infura.io/v3/46a379ac6895489f812f33beb726b03b',
- TESTNET = 'https://goerli.infura.io/v3/46a379ac6895489f812f33beb726b03b'
- }
-
if (process.env.USE_SECRETS !== 'false') {
await loadCredentials()
+ process.env.BIP39_SEED = process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') as string
+ } else {
+ process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
}
+ console.log(`Your mnemonic is ${process.env.BIP39_SEED}`)
process.env.FORK = process.env.FORK || 'testnet'
- process.env.BIP39_SEED = process.env.USE_SECRETS !== 'false' ? process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') : process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
-
- console.log(`Your mnemonic is ${process.env.BIP39_SEED}`)
- process.env.ETHEREUM_FORK_RPC_URL = ETHEREUM_FORK_URL[process.env.FORK.toUpperCase()]
+ process.env.ETHEREUM_FORK_RPC_URL = ETHEREUM_RPC_URL[process.env.FORK.toUpperCase()]
if (!process.env.ETHEREUM_FORK_RPC_URL) {
throw new Error(`Ethereum ${process.env.FORK} is not supported`)
}
- console.log(`Using ${process.env.FORK} fork from ${process.env.ETHEREUM_FORK_RPC_URL}`)
+ const networkName = ETHEREUM_NETWORK_NAME[process.env.FORK.toUpperCase()]
+
+ console.log(`Using ${networkName} fork from ${process.env.ETHEREUM_FORK_RPC_URL}`)
const provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_FORK_RPC_URL)
- const wallet = getWallet(process.env.BIP39_SEED)
- // Account for the mock Chainlink functions deployments
- const deployerNonce = await provider.getTransactionCount(wallet.address) + 5
+ const wallet = ethers.Wallet.fromMnemonic(process.env.BIP39_SEED)
+
+ // Account for the mock, beacon, and library deployments
+ const walletNonce = await provider.getTransactionCount(wallet.address) + 11
if (!process.env.MANAGER_ADDRESS) {
process.env.MANAGER_ADDRESS = ethers.utils.getContractAddress({
from: wallet.address,
- nonce: deployerNonce
- })
- }
-
- if (!process.env.VIEWS_ADDRESS) {
- process.env.VIEWS_ADDRESS = ethers.utils.getContractAddress({
- from: wallet.address,
- nonce: deployerNonce + 1
+ nonce: walletNonce
})
}
@@ -62,9 +54,16 @@ void async function () {
})
}
- process.env.SSV_NETWORK_ADDRESS = process.env.SSV_NETWORK_ADDRESS || '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3'
- process.env.SSV_NETWORK_VIEWS_ADDRESS = process.env.SSV_NETWORK_VIEWS_ADDRESS || '0x8dB45282d7C4559fd093C26f677B3837a5598914'
- process.env.UNISWAP_V3_FACTORY_ADDRESS = process.env.UNISWAP_V3_FACTORY_ADDRESS || '0x1F98431c8aD98523631AE4a59f267346ea31F984'
+ if (!process.env.VIEWS_ADDRESS) {
+ process.env.VIEWS_ADDRESS = ethers.utils.getContractAddress({
+ from: wallet.address,
+ nonce: walletNonce + 1
+ })
+ }
+
+ process.env.SSV_NETWORK_ADDRESS = ETHEREUM_CONTRACTS[process.env.FORK.toUpperCase()]?.SSV_NETWORK_ADDRESS
+ process.env.SSV_VIEWS_ADDRESS = ETHEREUM_CONTRACTS[process.env.FORK.toUpperCase()]?.SSV_VIEWS_ADDRESS
+ process.env.SWAP_FACTORY_ADDRESS = ETHEREUM_CONTRACTS[process.env.FORK.toUpperCase()]?.SWAP_FACTORY_ADDRESS
await run('npm run generate --workspace @casimir/oracle')
run('npm run test --workspace @casimir/ethereum')
diff --git a/scripts/ethereum/upgrade.ts b/scripts/ethereum/upgrade.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/scripts/ledger/compile b/scripts/ledger/compile
deleted file mode 100755
index dc16a6056..000000000
--- a/scripts/ledger/compile
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-# Compile a ledger app
-
-# Get args
-while getopts :a: flag
-do
- case "${flag}" in
- a) app=${OPTARG};;
- esac
-done
-
-if [ -z "$app" ]; then
- app="ethereum"
- echo "app is not set, using default app $app"
-fi
-
-resource_path=scripts/ledger/resources
-
-# Compile app
-echo "🔨 Building $app app for ledger"
-cd $resource_path/app-$app
-docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder
-docker tag ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder ledger-app-builder
-docker run --rm -v "$(pwd):/app" --user $(id -u $USER):$(id -g $USER) ledger-app-builder sh -c "make clean && make && exit"
-
-# Copy app to speculos apps folder
-echo "📲 Copying $app app to speculos apps folder"
-cp bin/app.elf ../speculos/apps/$app.elf
\ No newline at end of file
diff --git a/scripts/ledger/emulate b/scripts/ledger/emulate
deleted file mode 100755
index 6158e2580..000000000
--- a/scripts/ledger/emulate
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/bash
-# Emulate a ledger with a preloaded app
-
-# Get variables from root .env
-export $(xargs < .env)
-
-# Set default profile
-profile="consensus-networks-dev"
-
-if [ ${PROFILE+x} ]; then
- echo "PROFILE is set to '$PROFILE'"
- profile=$PROFILE
-else
- export PROFILE="$profile"
- echo "PROFILE is not set, using default profile '$PROFILE'"
-fi
-
-# Get args
-while getopts :a: flag
-do
- case "${flag}" in
- a) app=${OPTARG};;
- esac
-done
-
-echo "LEDGER APP $app"
-
-if [ -z "$app" ]; then
- app="ethereum"
- echo "app is not set, using default app $app"
-fi
-
-resource_path=scripts/ledger/resources
-
-if [ ! -f "$resource_path/speculos/apps/$app.elf" ]; then
- echo "App $app not ready yet, running compile script"
- scripts/ledger/compile -a $app
-fi
-
-if [[ "$(uname -a)" = *ARM64* ]]; then
- dockerfile=../custom/speculos-aarch64.Dockerfile
-else
- dockerfile=./Dockerfile
-fi
-
-cd $resource_path/speculos
-
-# Get the secret from AWS
-seed=$(aws secretsmanager get-secret-value \
---secret-id consensus-networks-bip39-seed \
---query SecretString \
---output text \
---profile $profile)
-export SPECULOS_SEED="$seed"
-
-# Stop current speculos and proxy
-echo "🧹 Cleaning up speculos environment"
-docker ps -q --filter ancestor="speculos:latest" | xargs -r docker stop
-
-# Build and run ledger app
-echo "📺 Emulating $app app on ledger"
-
-docker build . --tag speculos -f $dockerfile
-docker run --rm -v "$(pwd)/apps:/speculos/apps" \
--p 1234:1234 -p 5000:5000 -p 40000:40000 -p 41000:41000 \
-speculos apps/$app.elf \
---display headless \
---seed "$seed"
\ No newline at end of file
diff --git a/scripts/ledger/proxy.ts b/scripts/ledger/proxy.ts
deleted file mode 100644
index 04e5f16cf..000000000
--- a/scripts/ledger/proxy.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// Speculos API server proxy https://speculos.ledger.com/user/api.html
-
-import express from 'express'
-import cors from 'cors'
-import { createProxyMiddleware } from 'http-proxy-middleware'
-
-const app = express()
-app.use(express.json())
-app.use(cors())
-
-app.use(
- '/',
- createProxyMiddleware({
- target: 'http://127.0.0.1:5000',
- changeOrigin: true
- })
-)
-
-app.listen(5001)
-console.log('Ledger proxy listening on port 5001')
diff --git a/scripts/ledger/resources/app-bitcoin b/scripts/ledger/resources/app-bitcoin
deleted file mode 160000
index b4905a4b6..000000000
--- a/scripts/ledger/resources/app-bitcoin
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit b4905a4b6c1267f630dccb6eb9ae141c9a8c5fae
diff --git a/scripts/ledger/resources/app-ethereum b/scripts/ledger/resources/app-ethereum
deleted file mode 160000
index 6bb2d8ab9..000000000
--- a/scripts/ledger/resources/app-ethereum
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 6bb2d8ab97718701ebcec2cfb6861f94ddf0e553
diff --git a/scripts/ledger/resources/app-solana b/scripts/ledger/resources/app-solana
deleted file mode 160000
index e4bcb493b..000000000
--- a/scripts/ledger/resources/app-solana
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e4bcb493bf20bdc5906ae695a798abc44434e8a8
diff --git a/scripts/ledger/resources/custom/speculos-aarch64.Dockerfile b/scripts/ledger/resources/custom/speculos-aarch64.Dockerfile
deleted file mode 100644
index 0317cae34..000000000
--- a/scripts/ledger/resources/custom/speculos-aarch64.Dockerfile
+++ /dev/null
@@ -1,47 +0,0 @@
-# This Dockerfile assembles an image with all the dependencies required to run
-# speculos from the command-line (--display headless or --display console, no
-# GUI).
-#
-
-# Building the Speculos environment
-FROM ghcr.io/ledgerhq/speculos-builder-aarch64:latest AS builder
-
-ADD . /speculos
-WORKDIR /speculos/
-
-RUN cmake -Bbuild -H. -DPRECOMPILED_DEPENDENCIES_DIR=/install -DWITH_VNC=1
-RUN make -C build
-
-
-# Preparing final image
-FROM docker.io/library/python:3.9-slim
-
-ADD . /speculos
-WORKDIR /speculos
-
-# Copying artifacts from previous build
-COPY --from=builder /speculos/speculos/resources/ /speculos/speculos/resources/
-
-RUN pip install --upgrade pip pipenv
-RUN pipenv install --deploy --system
-RUN pip install pytesseract
-
-RUN apt-get update && apt-get install -qy \
- qemu-user-static \
- libvncserver-dev \
- gdb-multiarch \
- tesseract-ocr \
- libtesseract-dev \
- && apt-get clean
-
-RUN apt-get clean && rm -rf /var/lib/apt/lists/
-
-# default port for dev env
-EXPOSE 1234
-EXPOSE 1236
-EXPOSE 9999
-EXPOSE 40000
-EXPOSE 41000
-EXPOSE 42000
-
-ENTRYPOINT [ "python", "./speculos.py" ]
diff --git a/scripts/ledger/resources/speculos b/scripts/ledger/resources/speculos
deleted file mode 160000
index 0fed1b8de..000000000
--- a/scripts/ledger/resources/speculos
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 0fed1b8de0fbaa721f1843685385724ed6e0a4b5
diff --git a/scripts/migrations/users.ts b/scripts/migrations/users.ts
index 63cfc9379..2c71b8087 100644
--- a/scripts/migrations/users.ts
+++ b/scripts/migrations/users.ts
@@ -1,7 +1,7 @@
import fs from 'fs'
import os from 'os'
import { JsonSchema, Schema, accountSchema, nonceSchema, operatorSchema, userAccountSchema, userSchema } from '@casimir/data'
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
import { getSecret } from '@casimir/aws'
/**
diff --git a/scripts/root/check.ts b/scripts/root/check.ts
index 6380977e4..5b020076c 100644
--- a/scripts/root/check.ts
+++ b/scripts/root/check.ts
@@ -1,4 +1,4 @@
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
import fs from 'fs'
/**
diff --git a/scripts/root/clean.ts b/scripts/root/clean.ts
index ae3bc27d5..2cfa0cb00 100644
--- a/scripts/root/clean.ts
+++ b/scripts/root/clean.ts
@@ -1,4 +1,4 @@
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
import fs from 'fs'
import { promisify } from 'util'
diff --git a/scripts/root/dev.ts b/scripts/root/dev.ts
index ce038f3ca..92e776fe4 100644
--- a/scripts/root/dev.ts
+++ b/scripts/root/dev.ts
@@ -1,6 +1,7 @@
import { ethers } from 'ethers'
-import { getWallet, run, runSync } from '@casimir/helpers'
import { loadCredentials, getSecret } from '@casimir/aws'
+import { ETHEREUM_CONTRACTS, ETHEREUM_NETWORK_NAME, ETHEREUM_RPC_URL } from '@casimir/env'
+import { run, runSync } from '@casimir/shell'
/**
* Run an integrated development environment
@@ -13,27 +14,20 @@ void async function () {
}
}
- enum ETHEREUM_FORK_URL {
- MAINNET = 'https://mainnet.infura.io/v3/46a379ac6895489f812f33beb726b03b',
- TESTNET = 'https://goerli.infura.io/v3/46a379ac6895489f812f33beb726b03b'
- }
-
if (process.env.USE_SECRETS !== 'false') {
await loadCredentials()
+ process.env.BIP39_SEED = process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') as string
+ } else {
+ process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
}
process.env.PROJECT = process.env.PROJECT || 'casimir'
process.env.STAGE = process.env.STAGE || 'local'
- process.env.BIP39_SEED = process.env.USE_SECRETS !== 'false' ? process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') : process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
process.env.CRYPTO_COMPARE_API_KEY = process.env.USE_SECRETS !== 'false' ? process.env.CRYPTO_COMPARE_API_KEY || await getSecret('casimir-crypto-compare-api-key') : process.env.CRYPTO_COMPARE_API_KEY || ''
process.env.WALLET_CONNECT_PROJECT_ID = process.env.USE_SECRETS !== 'false' ? await getSecret('casimir-wallet-connect-project-id') : '8e6877b49198d7a9f9561b8712805726'
- process.env.EMULATE = process.env.EMULATE || 'false'
process.env.FORK = process.env.FORK || 'testnet'
process.env.MOCK_SERVICES = process.env.MOCK_SERVICES || 'true'
process.env.BUILD_PREVIEW = process.env.BUILD_PREVIEW || 'false'
- process.env.SSV_NETWORK_ADDRESS = process.env.SSV_NETWORK_ADDRESS || '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3'
- process.env.SSV_NETWORK_VIEWS_ADDRESS = process.env.SSV_NETWORK_VIEWS_ADDRESS || '0x8dB45282d7C4559fd093C26f677B3837a5598914'
- process.env.UNISWAP_V3_FACTORY_ADDRESS = process.env.UNISWAP_V3_FACTORY_ADDRESS || '0x1F98431c8aD98523631AE4a59f267346ea31F984'
if (process.env.BUILD_PREVIEW === 'true') {
process.env.WEB_URL = process.env.WEB_URL || 'http://localhost:4173'
@@ -54,26 +48,43 @@ void async function () {
}
}
+ const networkKey = process.env.NETWORK?.toUpperCase() || process.env.FORK?.toUpperCase() || 'TESTNET'
+ process.env.SSV_NETWORK_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_NETWORK_ADDRESS
+ process.env.SSV_VIEWS_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_VIEWS_ADDRESS
+ process.env.SWAP_FACTORY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SWAP_FACTORY_ADDRESS
if (process.env.NETWORK) {
+ process.env.ETHEREUM_RPC_URL = ETHEREUM_RPC_URL[networkKey]
+ const networkName = ETHEREUM_NETWORK_NAME[networkKey]
+
+ console.log(`Using ${networkName} network from ${process.env.ETHEREUM_RPC_URL}`)
if (!process.env.ETHEREUM_RPC_URL) {
- process.env.ETHEREUM_RPC_URL = ETHEREUM_FORK_URL[process.env.NETWORK.toUpperCase()]
- if (!process.env.ETHEREUM_RPC_URL) {
- throw new Error(`Ethereum ${process.env.NETWORK} is not supported`)
- }
+ throw new Error(`Ethereum ${process.env.NETWORK} is not supported`)
}
+ process.env.MANAGER_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.MANAGER_ADDRESS
if (!process.env.MANAGER_ADDRESS) {
- throw new Error(`No MANAGER_ADDRESS set for ${process.env.NETWORK} ethereum network.`)
+ throw new Error(`No manager address provided for ${process.env.NETWORK} ethereum network.`)
+ }
+
+ process.env.REGISTRY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.REGISTRY_ADDRESS
+ if (!process.env.REGISTRY_ADDRESS) {
+ throw new Error(`No registry address provided for ${process.env.NETWORK} ethereum network.`)
}
+ process.env.UPKEEP_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.UPKEEP_ADDRESS
+ if (!process.env.UPKEEP_ADDRESS) {
+ throw new Error(`No upkeep address provided for ${process.env.NETWORK} ethereum network.`)
+ }
+
+ process.env.VIEWS_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.VIEWS_ADDRESS
if (!process.env.VIEWS_ADDRESS) {
- throw new Error(`No VIEWS_ADDRESS set for ${process.env.NETWORK} ethereum network.`)
+ throw new Error(`No views address provided for ${process.env.NETWORK} ethereum network.`)
}
} else {
- process.env.ETHEREUM_FORK_RPC_URL = ETHEREUM_FORK_URL[process.env.FORK.toUpperCase()]
+ process.env.ETHEREUM_FORK_RPC_URL = ETHEREUM_RPC_URL[networkKey]
if (!process.env.ETHEREUM_FORK_RPC_URL) {
throw new Error(`Ethereum ${process.env.FORK} is not supported`)
}
@@ -83,22 +94,15 @@ void async function () {
const provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_FORK_RPC_URL)
process.env.ETHEREUM_FORK_BLOCK = process.env.ETHEREUM_FORK_BLOCK || `${await provider.getBlockNumber() - 5}`
- const wallet = getWallet(process.env.BIP39_SEED)
+ const wallet = ethers.Wallet.fromMnemonic(process.env.BIP39_SEED)
- // Account for the mock Chainlink functions deployments
- const deployerNonce = await provider.getTransactionCount(wallet.address) + 5
+ // Account for the mock, beacon, and library deployments
+ const walletNonce = await provider.getTransactionCount(wallet.address) + 11
if (!process.env.MANAGER_ADDRESS) {
process.env.MANAGER_ADDRESS = ethers.utils.getContractAddress({
from: wallet.address,
- nonce: deployerNonce
- })
- }
-
- if (!process.env.VIEWS_ADDRESS) {
- process.env.VIEWS_ADDRESS = ethers.utils.getContractAddress({
- from: wallet.address,
- nonce: deployerNonce + 1
+ nonce: walletNonce
})
}
@@ -116,23 +120,14 @@ void async function () {
})
}
- run('npm run dev:ethereum')
- }
-
- if (process.env.EMULATE === 'true') {
-
- const port = 5001
- const existingProcess = await run(`lsof -i :${port} | grep LISTEN | awk '{print $2}'`)
- if (existingProcess) {
- throw new Error(`Port ${port} is already in use by process ${existingProcess}, but is required by speculos.`)
+ if (!process.env.VIEWS_ADDRESS) {
+ process.env.VIEWS_ADDRESS = ethers.utils.getContractAddress({
+ from: wallet.address,
+ nonce: walletNonce + 1
+ })
}
- run('npx esno scripts/ledger/proxy.ts')
- run(`scripts/ledger/emulate -a ${process.env.LEDGER_APP}`)
- run('scripts/trezor/emulate')
-
- process.env.SPECULOS_URL = `http://localhost:${port}`
- process.env.LEDGER_APP = process.env.LEDGER_APP || 'ethereum'
+ run('npm run dev:ethereum')
}
process.env.PUBLIC_STAGE = process.env.STAGE
@@ -140,14 +135,12 @@ void async function () {
process.env.PUBLIC_ETHEREUM_RPC_URL = process.env.ETHEREUM_RPC_URL
process.env.PUBLIC_MANAGER_ADDRESS = process.env.MANAGER_ADDRESS
process.env.PUBLIC_VIEWS_ADDRESS = process.env.VIEWS_ADDRESS
- process.env.PUBLIC_SSV_NETWORK_ADDRESS = process.env.SSV_NETWORK_ADDRESS
- process.env.PUBLIC_SSV_NETWORK_VIEWS_ADDRESS = process.env.SSV_NETWORK_VIEWS_ADDRESS
- process.env.PUBLIC_UNISWAP_V3_FACTORY_ADDRESS = process.env.UNISWAP_V3_FACTORY_ADDRESS
process.env.PUBLIC_REGISTRY_ADDRESS = process.env.REGISTRY_ADDRESS
process.env.PUBLIC_UPKEEP_ADDRESS = process.env.UPKEEP_ADDRESS
+ process.env.PUBLIC_SSV_NETWORK_ADDRESS = process.env.SSV_NETWORK_ADDRESS
+ process.env.PUBLIC_SSV_VIEWS_ADDRESS = process.env.SSV_VIEWS_ADDRESS
+ process.env.PUBLIC_SWAP_FACTORY_ADDRESS = process.env.SWAP_FACTORY_ADDRESS
process.env.PUBLIC_CRYPTO_COMPARE_API_KEY = process.env.CRYPTO_COMPARE_API_KEY
- process.env.PUBLIC_LEDGER_APP = process.env.LEDGER_APP
- process.env.PUBLIC_SPECULOS_URL = process.env.SPECULOS_URL
process.env.PUBLIC_ETHEREUM_FORK_BLOCK = process.env.ETHEREUM_FORK_BLOCK
process.env.PUBLIC_WALLET_CONNECT_PROJECT_ID = process.env.WALLET_CONNECT_PROJECT_ID
diff --git a/scripts/trezor/emulate b/scripts/trezor/emulate
deleted file mode 100755
index b48fd95e6..000000000
--- a/scripts/trezor/emulate
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-# Emulate a ledger with a preloaded app
-
-# Get variables from root .env
-export $(xargs < .env)
-
-# Set default profile
-profile="consensus-networks-dev"
-
-if [ ${PROFILE+x} ]; then
- echo "PROFILE is set to '$PROFILE'"
- profile=$PROFILE
-else
- export PROFILE="$profile"
- echo "PROFILE is not set, using default profile '$PROFILE'"
-fi
-
-# Todo programmatically launch emulator with seed
-# # Get the bip39 seed from AWS
-# seed_secret_id=consensus-networks-bip39-seed
-# seed=$(aws secretsmanager get-secret-value \
-# --secret-id $seed_secret_id \
-# --query SecretString \
-# --output text \
-# --profile $profile)
-
-# # Set the shared bip39 seed
-# export BIP39_SEED="$seed"
-
-export PHYSICAL_TREZOR=false
-
-resource_path=scripts/trezor/resources
-cd $resource_path/trezor-user-env
-./run.sh
\ No newline at end of file
diff --git a/scripts/trezor/resources/trezor-user-env b/scripts/trezor/resources/trezor-user-env
deleted file mode 160000
index 7ab29a7fe..000000000
--- a/scripts/trezor/resources/trezor-user-env
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 7ab29a7fe0b865c89bcfc7d9fca778b8994c882c
diff --git a/services/crawler/casimir_manager.go b/services/crawler/casimir_manager.go
index efaec9df6..f722edc44 100644
--- a/services/crawler/casimir_manager.go
+++ b/services/crawler/casimir_manager.go
@@ -39,7 +39,7 @@ type ISSVNetworkCoreCluster struct {
// MainMetaData contains all meta data concerning the Main contract.
var MainMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oracleAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"beaconDepositAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkFunctionsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkRegistrarAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkRegistryAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ssvNetworkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ssvNetworkViewsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ssvTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"swapFactoryAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"swapRouterAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"wethTokenAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"CompletedExitReportsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"DepositActivated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"DepositInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"DepositRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"ExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"ExitRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"ForcedExitReportsRequested\",\"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\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"ReshareCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"operatorId\",\"type\":\"uint64\"}],\"name\":\"ResharesRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"SlashedExitReportsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeRebalanced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TipsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"activateDeposits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[5]\",\"name\":\"poolIds\",\"type\":\"uint32[5]\"}],\"name\":\"compoundRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"depositClusterBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"depositExitedBalance\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"depositRecoveredBalance\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositReservedFees\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositRewards\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositStake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"depositUpkeepBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feePercent\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizableCompletedExits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"fulfillWithdrawals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBufferedBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bufferedBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedEffectiveBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedEffectiveBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPendingPoolIds\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"period\",\"type\":\"uint256\"}],\"name\":\"getPendingWithdrawalEligibility\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"pendingWithdrawalEligibility\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"getPoolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReadyBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"readyBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReadyPoolIds\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"registryAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReservedFeeBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakedPoolIds\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalStake\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUpkeepAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"upkeepAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUpkeepBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getUserStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"userStake\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWithdrawableBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"withdrawalCredentials\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"shares\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"initiateDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestActiveBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"activeBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sweptBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"activatedDeposits\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"completedExits\",\"type\":\"uint256\"}],\"name\":\"rebalanceStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"blamePercents\",\"type\":\"uint32[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"reportCompletedExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"poolIds\",\"type\":\"uint32[]\"}],\"name\":\"reportForcedExits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reportPeriod\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint64[]\",\"name\":\"oldOperatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint64\",\"name\":\"newOperatorId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"oldOperatorId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"shares\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"oldCluster\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"reportReshare\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"requestCompletedExitReports\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"requestForcedExitReports\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"operatorId\",\"type\":\"uint64\"}],\"name\":\"requestReshares\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requestedExits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requestedWithdrawalBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"functionsAddress\",\"type\":\"address\"}],\"name\":\"setFunctionsAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLINKBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawReservedFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawSSVBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawUpkeepBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oracleAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"beaconDepositAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkFunctionsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"keeperRegistrarAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"keeperRegistryAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ssvNetworkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ssvViewsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"ssvTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"swapFactoryAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"swapRouterAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"wethTokenAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"CompletedExitReportsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"DepositActivated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"DepositInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"DepositRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"ExitCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"ExitRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"ForcedExitReportsRequested\",\"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\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"ReshareCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"operatorId\",\"type\":\"uint64\"}],\"name\":\"ResharesRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RewardsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"SlashedExitReportsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeRebalanced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TipsDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"activateDeposits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[5]\",\"name\":\"poolIds\",\"type\":\"uint32[5]\"}],\"name\":\"compoundRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"depositClusterBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"depositExitedBalance\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"depositRecoveredBalance\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositReservedFees\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositRewards\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"depositStake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"depositUpkeepBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feePercent\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"finalizableCompletedExits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"fulfillWithdrawals\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBufferedBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"bufferedBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedEffectiveBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedEffectiveBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPendingPoolIds\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"period\",\"type\":\"uint256\"}],\"name\":\"getPendingWithdrawalEligibility\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"pendingWithdrawalEligibility\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"}],\"name\":\"getPoolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReadyBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"readyBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReadyPoolIds\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"registryAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReservedFeeBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStakedPoolIds\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"totalStake\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUpkeepAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"upkeepAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUpkeepBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepBalance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"}],\"name\":\"getUserStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"userStake\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWithdrawableBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"depositDataRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"withdrawalCredentials\",\"type\":\"bytes\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"bytes\",\"name\":\"shares\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"initiateDeposit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBeaconBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"beaconBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"sweptBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"activatedDeposits\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"completedExits\",\"type\":\"uint256\"}],\"name\":\"rebalanceStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint32[]\",\"name\":\"blamePercents\",\"type\":\"uint32[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"}],\"name\":\"reportCompletedExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"poolIds\",\"type\":\"uint32[]\"}],\"name\":\"reportForcedExits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reportPeriod\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"poolId\",\"type\":\"uint32\"},{\"internalType\":\"uint64[]\",\"name\":\"operatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint64[]\",\"name\":\"oldOperatorIds\",\"type\":\"uint64[]\"},{\"internalType\":\"uint64\",\"name\":\"newOperatorId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"oldOperatorId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"shares\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"cluster\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"validatorCount\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"networkFeeIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"}],\"internalType\":\"structISSVNetworkCore.Cluster\",\"name\":\"oldCluster\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"processed\",\"type\":\"bool\"}],\"name\":\"reportReshare\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"requestCompletedExitReports\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"requestForcedExitReports\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"operatorId\",\"type\":\"uint64\"}],\"name\":\"requestReshares\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"requestWithdrawal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requestedExits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requestedWithdrawalBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"functionsAddress\",\"type\":\"address\"}],\"name\":\"setFunctionsAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLINKBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawReservedFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawSSVBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawUpkeepBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
}
// MainABI is the input ABI used to generate the binding from.
@@ -715,12 +715,12 @@ func (_Main *MainCallerSession) GetWithdrawableBalance() (*big.Int, error) {
return _Main.Contract.GetWithdrawableBalance(&_Main.CallOpts)
}
-// LatestActiveBalance is a free data retrieval call binding the contract method 0xce54d3e3.
+// LatestBeaconBalance is a free data retrieval call binding the contract method 0xce54d3e3.
//
-// Solidity: function latestActiveBalance() view returns(uint256)
-func (_Main *MainCaller) LatestActiveBalance(opts *bind.CallOpts) (*big.Int, error) {
+// Solidity: function latestBeaconBalance() view returns(uint256)
+func (_Main *MainCaller) LatestBeaconBalance(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
- err := _Main.contract.Call(opts, &out, "latestActiveBalance")
+ err := _Main.contract.Call(opts, &out, "latestBeaconBalance")
if err != nil {
return *new(*big.Int), err
@@ -732,18 +732,18 @@ func (_Main *MainCaller) LatestActiveBalance(opts *bind.CallOpts) (*big.Int, err
}
-// LatestActiveBalance is a free data retrieval call binding the contract method 0xce54d3e3.
+// LatestBeaconBalance is a free data retrieval call binding the contract method 0xce54d3e3.
//
-// Solidity: function latestActiveBalance() view returns(uint256)
-func (_Main *MainSession) LatestActiveBalance() (*big.Int, error) {
- return _Main.Contract.LatestActiveBalance(&_Main.CallOpts)
+// Solidity: function latestBeaconBalance() view returns(uint256)
+func (_Main *MainSession) LatestBeaconBalance() (*big.Int, error) {
+ return _Main.Contract.LatestBeaconBalance(&_Main.CallOpts)
}
-// LatestActiveBalance is a free data retrieval call binding the contract method 0xce54d3e3.
+// LatestBeaconBalance is a free data retrieval call binding the contract method 0xce54d3e3.
//
-// Solidity: function latestActiveBalance() view returns(uint256)
-func (_Main *MainCallerSession) LatestActiveBalance() (*big.Int, error) {
- return _Main.Contract.LatestActiveBalance(&_Main.CallOpts)
+// Solidity: function latestBeaconBalance() view returns(uint256)
+func (_Main *MainCallerSession) LatestBeaconBalance() (*big.Int, error) {
+ return _Main.Contract.LatestBeaconBalance(&_Main.CallOpts)
}
// Owner is a free data retrieval call binding the contract method 0x8da5cb5b.
@@ -1134,23 +1134,23 @@ func (_Main *MainTransactorSession) InitiateDeposit(depositDataRoot [32]byte, pu
// RebalanceStake is a paid mutator transaction binding the contract method 0xaaf0c558.
//
-// Solidity: function rebalanceStake(uint256 activeBalance, uint256 sweptBalance, uint256 activatedDeposits, uint256 completedExits) returns()
-func (_Main *MainTransactor) RebalanceStake(opts *bind.TransactOpts, activeBalance *big.Int, sweptBalance *big.Int, activatedDeposits *big.Int, completedExits *big.Int) (*types.Transaction, error) {
- return _Main.contract.Transact(opts, "rebalanceStake", activeBalance, sweptBalance, activatedDeposits, completedExits)
+// Solidity: function rebalanceStake(uint256 beaconBalance, uint256 sweptBalance, uint256 activatedDeposits, uint256 completedExits) returns()
+func (_Main *MainTransactor) RebalanceStake(opts *bind.TransactOpts, beaconBalance *big.Int, sweptBalance *big.Int, activatedDeposits *big.Int, completedExits *big.Int) (*types.Transaction, error) {
+ return _Main.contract.Transact(opts, "rebalanceStake", beaconBalance, sweptBalance, activatedDeposits, completedExits)
}
// RebalanceStake is a paid mutator transaction binding the contract method 0xaaf0c558.
//
-// Solidity: function rebalanceStake(uint256 activeBalance, uint256 sweptBalance, uint256 activatedDeposits, uint256 completedExits) returns()
-func (_Main *MainSession) RebalanceStake(activeBalance *big.Int, sweptBalance *big.Int, activatedDeposits *big.Int, completedExits *big.Int) (*types.Transaction, error) {
- return _Main.Contract.RebalanceStake(&_Main.TransactOpts, activeBalance, sweptBalance, activatedDeposits, completedExits)
+// Solidity: function rebalanceStake(uint256 beaconBalance, uint256 sweptBalance, uint256 activatedDeposits, uint256 completedExits) returns()
+func (_Main *MainSession) RebalanceStake(beaconBalance *big.Int, sweptBalance *big.Int, activatedDeposits *big.Int, completedExits *big.Int) (*types.Transaction, error) {
+ return _Main.Contract.RebalanceStake(&_Main.TransactOpts, beaconBalance, sweptBalance, activatedDeposits, completedExits)
}
// RebalanceStake is a paid mutator transaction binding the contract method 0xaaf0c558.
//
-// Solidity: function rebalanceStake(uint256 activeBalance, uint256 sweptBalance, uint256 activatedDeposits, uint256 completedExits) returns()
-func (_Main *MainTransactorSession) RebalanceStake(activeBalance *big.Int, sweptBalance *big.Int, activatedDeposits *big.Int, completedExits *big.Int) (*types.Transaction, error) {
- return _Main.Contract.RebalanceStake(&_Main.TransactOpts, activeBalance, sweptBalance, activatedDeposits, completedExits)
+// Solidity: function rebalanceStake(uint256 beaconBalance, uint256 sweptBalance, uint256 activatedDeposits, uint256 completedExits) returns()
+func (_Main *MainTransactorSession) RebalanceStake(beaconBalance *big.Int, sweptBalance *big.Int, activatedDeposits *big.Int, completedExits *big.Int) (*types.Transaction, error) {
+ return _Main.Contract.RebalanceStake(&_Main.TransactOpts, beaconBalance, sweptBalance, activatedDeposits, completedExits)
}
// RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6.
diff --git a/services/functions/.gitignore b/services/functions/.gitignore
new file mode 100644
index 000000000..669706eb7
--- /dev/null
+++ b/services/functions/.gitignore
@@ -0,0 +1,2 @@
+.env.enc
+.log
\ No newline at end of file
diff --git a/services/functions/API-request-source.js b/services/functions/API-request-source.js
index 7da1ba3dc..6f89ad2e3 100644
--- a/services/functions/API-request-source.js
+++ b/services/functions/API-request-source.js
@@ -1,55 +1,41 @@
-/**********************/
-/** MOCK BEACON DATA **/
-const mockValidatorPublicKeys = [
- '0x88e1b777156a0945851d2940d604727fce299daaaf12aa6c04410c3e31887ab018f6a748017aa8717fbb7f242624afcf',
- '0x96c9cd76264cdfd84d6c3c704101db435c150cbfe088c031e1bef740f8f7de24fceccdd755d1d2e091ccb6e58fb93db4',
- '0x832e23566d61f2b141e1ab57e2a4362d228de7bb53acb096f0ea6d500d3490b323b41ce3ae2104772ba243ae48cdccfd',
- '0x8b65cc087ed99e559b4e1be14776a54e02b458cdd79d792394186539cdd53ea937647cd4aba333a470ba9f6393c6e612'
-]
-const mockPreviousReportSlot = 6055000
-const mockReportSlot = 6055335
-/**********************/
-
-const genesisTimestamp = args[0]
-const previousReportTimestamp = args[1]
-const reportTimestamp = args[2]
-const reportBlockNumber = '0x' + parseInt(args[3]).toString(16)
-const requestType = args[4]
-const viewsAddress = args[5]
-const getCompoundablePoolIdsSignature = args[6]
-const getDepositedPoolCountSignature = args[7]
-const getSweptBalanceSignature = args[8]
-const getValidatorPublicKeysSignature = args[9]
-const ethereumUrl = secrets.ethereumRpcUrl || 'http://localhost:8545'
-const ethereumBeaconUrl = secrets.ethereumBeaconRpcUrl || 'http://localhost:5052'
-const previousReportSlot = mockPreviousReportSlot // Math.floor((previousReportTimestamp - genesisTimestamp) / 12)
+const [
+ genesisTimestamp,
+ viewsAddress,
+ getCompoundablePoolIdsSignature,
+ getDepositedPoolCountSignature,
+ getDepositedPoolPublicKeysSignature,
+ getDepositedPoolStatusesSignature,
+ getSweptBalanceSignature,
+ previousReportTimestamp,
+ reportTimestamp,
+ reportBlockNumber,
+ requestType
+] = args
+const ethereumUrl = secrets.ethereumRpcUrl ?? 'http://127.0.0.1:8545'
+const ethereumBeaconUrl = secrets.ethereumBeaconRpcUrl ?? 'http://127.0.0.1:5052'
+const previousReportSlot = Math.floor((previousReportTimestamp - genesisTimestamp) / 12)
const previousReportEpoch = Math.floor(previousReportSlot / 32)
-const reportSlot = mockReportSlot // Math.floor((reportTimestamp - genesisTimestamp) / 12)
+const reportSlot = Math.floor((reportTimestamp - genesisTimestamp) / 12)
const reportEpoch = Math.floor(reportSlot / 32)
-try {
- switch (requestType) {
- case '1':
- return await balancesHandler()
- case '2':
- return await detailsHandler()
- default:
- throw new Error('Invalid request type')
- }
-} catch (error) {
- return Buffer.from(error.message)
+switch (requestType) {
+ case '1':
+ return await balancesHandler()
+ case '2':
+ return await detailsHandler()
+ default:
+ throw new Error('Invalid request type')
}
async function balancesHandler() {
const depositedPoolCount = await getDepositedPoolCount()
-
const startIndex = BigInt(0).toString(16).padStart(64, '0')
const endIndex = BigInt(depositedPoolCount).toString(16).padStart(64, '0')
+
+ const depositedPoolPublicKeys = await getDepositedPoolPublicKeys(startIndex, endIndex)
+ const validators = await getValidators(depositedPoolPublicKeys)
- const validatorPublicKeys = await getValidatorPublicKeys(startIndex, endIndex)
- const validators = await getValidators(validatorPublicKeys)
-
- const activeBalance = validators.reduce((accumulator, { balance }) => {
+ const beaconBalance = validators.reduce((accumulator, { balance }) => {
accumulator += parseFloat(balance)
return accumulator
}, 0)
@@ -57,24 +43,29 @@ async function balancesHandler() {
const sweptBalance = await getSweptBalance(startIndex, endIndex)
console.log("Results", {
- activeBalance,
+ beaconBalance,
sweptBalance
})
return Buffer.concat([
- encodeUint128(activeBalance),
+ encodeUint128(beaconBalance),
encodeUint128(sweptBalance)
])
}
async function detailsHandler() {
const depositedPoolCount = await getDepositedPoolCount()
-
const startIndex = BigInt(0).toString(16).padStart(64, '0')
const endIndex = BigInt(depositedPoolCount).toString(16).padStart(64, '0')
- const validatorPublicKeys = await getValidatorPublicKeys(startIndex, endIndex)
- const validators = await getValidators(validatorPublicKeys)
+ const depositedPoolPublicKeys = await getDepositedPoolPublicKeys(startIndex, endIndex)
+ const depositedPoolStatuses = await getDepositedPoolStatuses(startIndex, endIndex)
+ for (let i = 0; i < depositedPoolCount; i++) {
+ console.log("* Pool")
+ console.log("-- Public key", depositedPoolPublicKeys[i])
+ console.log("-- Status", depositedPoolStatuses[i])
+ }
+ const validators = await getValidators(depositedPoolPublicKeys)
const activatedDeposits = validators.reduce((accumulator, { validator }) => {
const { activation_epoch } = validator
@@ -85,7 +76,7 @@ async function detailsHandler() {
return accumulator
}, 0)
- const ongoingSlashes = validators.reduce((accumulator, { status, validator }) => {
+ const forcedExits = validators.reduce((accumulator, { status, validator }) => {
const { slashed } = validator
const ongoing = status !== 'withdrawal_done'
if (slashed && ongoing) {
@@ -108,14 +99,14 @@ async function detailsHandler() {
console.log("Results", {
activatedDeposits,
- ongoingSlashes,
+ forcedExits,
completedExits,
compoundablePoolIds
})
return Buffer.concat([
encodeUint32(activatedDeposits),
- encodeUint32(ongoingSlashes),
+ encodeUint32(forcedExits),
encodeUint32(completedExits),
encodeUint32Array(compoundablePoolIds)
])
@@ -134,13 +125,13 @@ async function getCompoundablePoolIds(startIndex, endIndex) {
to: viewsAddress,
data: getCompoundablePoolIdsSignature + '0'.repeat(24) + startIndex + endIndex
},
- { blockNumber: reportBlockNumber }
+ { blockNumber: '0x' + parseInt(reportBlockNumber).toString(16) }
]
}
})
if (request.error) throw new Error('Failed to get compoundable pool IDs')
- const rawPoolIds = request.data.result.slice(2);
- let poolIds = [];
+ const rawPoolIds = request.data.result.slice(2)
+ let poolIds = []
for (let i = 0; i < 5; i++) {
let start = i * 8
let end = start + 8
@@ -163,7 +154,7 @@ async function getDepositedPoolCount() {
to: viewsAddress,
data: getDepositedPoolCountSignature
},
- { blockNumber: reportBlockNumber }
+ { blockNumber: '0x' + parseInt(reportBlockNumber).toString(16) }
]
}
})
@@ -171,7 +162,7 @@ async function getDepositedPoolCount() {
return Number(request.data.result)
}
-async function getSweptBalance(startIndex, endIndex) {
+async function getDepositedPoolPublicKeys(startIndex, endIndex) {
const request = await Functions.makeHttpRequest({
url: ethereumUrl,
method: 'POST',
@@ -182,17 +173,28 @@ async function getSweptBalance(startIndex, endIndex) {
params: [
{
to: viewsAddress,
- data: getSweptBalanceSignature + '0'.repeat(24) + startIndex + endIndex
+ data: getDepositedPoolPublicKeysSignature + startIndex + endIndex
},
- { blockNumber: reportBlockNumber }
+ { blockNumber: '0x' + parseInt(reportBlockNumber).toString(16) }
]
}
})
- if (request.error) throw new Error('Failed to get swept balance')
- return parseFloat(request.data.result.slice(0, -9))
+ if (request.error) throw new Error('Failed to get validator public keys')
+ const rawPublicKeys = request.data.result.slice(2)
+ const numKeys = parseInt(rawPublicKeys.slice(64, 128), 16)
+ const publicKeys = []
+ for (let i = 0; i < numKeys; i++) {
+ let offset = 64 * 3 + i * 96
+ let length = parseInt(rawPublicKeys.slice(offset, offset + 64), 16) * 2
+ let publicKeyStart = offset + 64
+ let publicKeyEnd = publicKeyStart + length
+ let publicKey = '0x' + rawPublicKeys.slice(publicKeyStart, publicKeyEnd)
+ publicKeys.push(publicKey)
+ }
+ return publicKeys
}
-async function getValidatorPublicKeys(startIndex, endIndex) {
+async function getDepositedPoolStatuses(startIndex, endIndex) {
const request = await Functions.makeHttpRequest({
url: ethereumUrl,
method: 'POST',
@@ -203,29 +205,46 @@ async function getValidatorPublicKeys(startIndex, endIndex) {
params: [
{
to: viewsAddress,
- data: getValidatorPublicKeysSignature + startIndex + endIndex
+ data: getDepositedPoolStatusesSignature + '0'.repeat(24) + startIndex + endIndex
},
- { blockNumber: reportBlockNumber }
+ { blockNumber: '0x' + parseInt(reportBlockNumber).toString(16) }
]
}
})
- if (request.error) throw new Error('Failed to get validator public keys')
- const rawPublicKeys = request.data.result.slice(2)
- const numKeys = parseInt(rawPublicKeys.slice(64, 128), 16)
- const publicKeys = []
- for (let i = 0; i < numKeys; i++) {
- let offset = 64 * 3 + i * 96
- let length = parseInt(rawPublicKeys.slice(offset, offset + 64), 16) * 2
- let publicKeyStart = offset + 64
- let publicKeyEnd = publicKeyStart + length
- let publicKey = '0x' + rawPublicKeys.slice(publicKeyStart, publicKeyEnd)
- publicKeys.push(publicKey)
+ if (request.error) throw new Error('Failed to get validator statuses')
+ const rawStatuses = request.data.result.slice(2)
+ const statuses = []
+ for (let i = 0; i < 5; i++) {
+ let start = i * 8
+ let end = start + 8
+ let status = parseInt(rawStatuses.slice(start, end), 16)
+ statuses.push(status)
}
- return publicKeys
+ return statuses
+}
+
+async function getSweptBalance(startIndex, endIndex) {
+ const request = await Functions.makeHttpRequest({
+ url: ethereumUrl,
+ method: 'POST',
+ data: {
+ id: 1,
+ jsonrpc: '2.0',
+ method: 'eth_call',
+ params: [
+ {
+ to: viewsAddress,
+ data: getSweptBalanceSignature + '0'.repeat(24) + startIndex + endIndex
+ },
+ { blockNumber: '0x' + parseInt(reportBlockNumber).toString(16) }
+ ]
+ }
+ })
+ if (request.error) throw new Error('Failed to get swept balance')
+ return parseFloat(request.data.result.slice(0, -9))
}
async function getValidators(validatorPublicKeys) {
- validatorPublicKeys = mockValidatorPublicKeys // TODO: remove
const request = await Functions.makeHttpRequest({
url: `${ethereumBeaconUrl}/eth/v1/beacon/states/${reportSlot}/validators?id=${validatorPublicKeys.join(',')}`
})
diff --git a/services/functions/index.d.ts b/services/functions/Functions-request-config.d.ts
similarity index 69%
rename from services/functions/index.d.ts
rename to services/functions/Functions-request-config.d.ts
index a2d9605b2..bc34ce5ab 100644
--- a/services/functions/index.d.ts
+++ b/services/functions/Functions-request-config.d.ts
@@ -1,5 +1,5 @@
-declare module '@casimir/functions' {
- export const requestConfig: {
+declare module '@casimir/functions/Functions-request-config' {
+ const requestConfig: {
codeLocation: number
codeLanguage: number
source: string
@@ -10,4 +10,5 @@ declare module '@casimir/functions' {
expectedReturnType: string
secretsURLs: never[]
}
+ export default requestConfig
}
\ No newline at end of file
diff --git a/services/functions/Functions-request-config.js b/services/functions/Functions-request-config.js
index fc423bcc9..b30148f98 100644
--- a/services/functions/Functions-request-config.js
+++ b/services/functions/Functions-request-config.js
@@ -5,58 +5,59 @@ const path = require("path")
require("@chainlink/env-enc").config()
const Location = {
- Inline: 0,
- Remote: 1,
+ Inline: 0,
+ Remote: 1,
}
const CodeLanguage = {
- JavaScript: 0,
+ JavaScript: 0,
}
const ReturnType = {
- uint: "uint256",
- uint256: "uint256",
- int: "int256",
- int256: "int256",
- string: "string",
- bytes: "Buffer",
- Buffer: "Buffer",
+ uint: "uint256",
+ uint256: "uint256",
+ int: "int256",
+ int256: "int256",
+ string: "string",
+ bytes: "Buffer",
+ Buffer: "Buffer",
}
// Configure the request by setting the fields below
const requestConfig = {
- // Location of source code (only Inline is currently supported)
- codeLocation: Location.Inline,
- // Code language (only JavaScript is currently supported)
- codeLanguage: CodeLanguage.JavaScript,
- // String containing the source code to be executed
- source: fs.readFileSync(path.join(__dirname, 'API-request-source.js')).toString(),
- // Secrets can be accessed within the source code with `secrets.varName` (ie: secrets.apiKey). The secrets object can only contain string values.
- secrets: {
- // ethereumRpcUrl: process.env.ETHEREUM_RPC_URL ?? "",
- // ethereumBeaconRpcUrl: process.env.ETHEREUM_BEACON_RPC_URL ?? "",
- },
- // Per-node secrets objects assigned to each DON member. When using per-node secrets, nodes can only use secrets which they have been assigned.
- perNodeSecrets: [],
- // ETH wallet key used to sign secrets so they cannot be accessed by a 3rd party
- walletPrivateKey: process.env["PRIVATE_KEY"],
- // Args (string only array) can be accessed within the source code with `args[index]` (ie: args[0]).
- args: [
- "1616508000", // genesisTimestamp
- "1689541170", // previousReportTimestamp
- "1689627688", // reportTimestamp
- "9340689", // reportBlockNumber
- "1", // requestType
- "0x6b34d231b467fccebdc766187f7251795281dc26", // viewsAddress
- "0x0812a9fe", // getCompoundablePoolIds(uint256,uint256)
- "0x5d1e0780", // getDepositedPoolCount()
- "0x12c3456b", // getSweptBalance(uint256,uint256)
- "0xf6647134" // getValidatorPublicKeys(uint256,uint256)
- ],
- // Expected type of the returned value
- expectedReturnType: ReturnType.Buffer,
- // Redundant URLs which point to encrypted off-chain secrets
- secretsURLs: [],
+ // Location of source code (only Inline is currently supported)
+ codeLocation: Location.Inline,
+ // Code language (only JavaScript is currently supported)
+ codeLanguage: CodeLanguage.JavaScript,
+ // String containing the source code to be executed
+ source: fs.readFileSync(path.join(__dirname, 'API-request-source.js')).toString(),
+ // Secrets can be accessed within the source code with `secrets.varName` (ie: secrets.apiKey). The secrets object can only contain string values.
+ secrets: {
+ ethereumRpcUrl: process.env.ETHEREUM_RPC_URL ?? "",
+ ethereumBeaconRpcUrl: process.env.ETHEREUM_BEACON_RPC_URL ?? "",
+ },
+ // Per-node secrets objects assigned to each DON member. When using per-node secrets, nodes can only use secrets which they have been assigned.
+ perNodeSecrets: [],
+ // ETH wallet key used to sign secrets so they cannot be accessed by a 3rd party
+ walletPrivateKey: process.env.PRIVATE_KEY ?? "",
+ // Args (string only array) can be accessed within the source code with `args[index]` (ie: args[0]).
+ args: [
+ "1616508000", // genesisTimestamp
+ "0xc9F69bD5F43153FB485cBF1DB907EE1eb28c9B29", // viewsAddress
+ "0x0812a9fe", // getCompoundablePoolIds(uint256,uint256)
+ "0x5d1e0780", // getDepositedPoolCount()
+ "0xdcf25c1d", // getDepositedPoolPublicKeys(uint256,uint256)
+ "0xb29a57e4", // getDepositedPoolStatuses(uint256,uint256)
+ "0x12c3456b", // getSweptBalance(uint256,uint256)
+ "0", // previousReportTimestamp
+ "0", // reportTimestamp
+ "0", // reportBlockNumber
+ "0" // requestType
+ ],
+ // Expected type of the returned value
+ expectedReturnType: ReturnType.Buffer,
+ // Redundant URLs which point to encrypted off-chain secrets
+ secretsURLs: [],
}
module.exports = requestConfig
\ No newline at end of file
diff --git a/services/functions/index.js b/services/functions/index.js
deleted file mode 100644
index 6f6cbfb19..000000000
--- a/services/functions/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import requestConfig from './Functions-request-config'
-
-export { requestConfig }
\ No newline at end of file
diff --git a/services/functions/package.json b/services/functions/package.json
index 23da116dc..649e6f7dd 100644
--- a/services/functions/package.json
+++ b/services/functions/package.json
@@ -1,35 +1,27 @@
{
"name": "@casimir/functions",
"private": true,
- "main": "index.js",
+ "main": "src/index.ts",
"scripts": {
"compile": "hardhat compile",
+ "dev": "npx esno -r dotenv/config scripts/dev.ts",
"test": "npm run test:unit",
"test:unit": "hardhat test test/unit/*.spec.js",
"functions-simulate-javascript": "node scripts/simulateFunctionsJavaScript.js",
"functions-gen-keys": "node scripts/generateKeypair.js"
},
"devDependencies": {
- "@chainlink/contracts": "0.5.1",
"@ethersproject/abi": "^5.7.0",
"@ethersproject/providers": "^5.7.1",
- "@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
- "@nomicfoundation/hardhat-network-helpers": "^1.0.6",
- "@nomicfoundation/hardhat-toolbox": "^2.0.0",
- "@nomiclabs/hardhat-ethers": "^2.2.2",
- "@nomiclabs/hardhat-etherscan": "^3.1.0",
- "@openzeppelin/hardhat-upgrades": "^1.22.1",
- "@typechain/ethers-v5": "^10.1.0",
- "@typechain/hardhat": "^6.1.3",
+ "cbor": "^9.0.1",
"chai": "^4.3.6",
+ "dotenv": "^16.0.3",
+ "esno": "^0.17.0",
"eth-crypto": "^2.4.0",
- "ethers": "^5.7.2",
- "hardhat": "^2.14.0",
- "typechain": "^8.1.0"
+ "ethers": "^5.7.2"
},
"dependencies": {
"@chainlink/env-enc": "^1.0.5",
- "@openzeppelin/contracts": "4.8.3",
"axios": "^1.1.3",
"crypto-js": "^4.1.1",
"is-http-url": "^2.0.0",
@@ -38,4 +30,4 @@
"readline": "^1.3.0",
"vm2": "^3.9.18"
}
-}
\ No newline at end of file
+}
diff --git a/services/functions/scripts/dev.ts b/services/functions/scripts/dev.ts
new file mode 100644
index 000000000..3dd9a0f27
--- /dev/null
+++ b/services/functions/scripts/dev.ts
@@ -0,0 +1,34 @@
+import { loadCredentials, getSecret } from '@casimir/aws'
+import { ETHEREUM_CONTRACTS, ETHEREUM_RPC_URL } from '@casimir/env'
+import { run } from '@casimir/shell'
+
+/**
+ * Start the Chainlink functions service
+ */
+void async function() {
+
+ if (process.env.USE_SECRETS !== 'false') {
+ await loadCredentials()
+ process.env.BIP39_SEED = process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') as string
+ } else {
+ process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
+ }
+
+ const networkKey = process.env.NETWORK?.toUpperCase() || process.env.FORK?.toUpperCase() || 'TESTNET'
+ if (process.env.NETWORK) {
+ process.env.ETHEREUM_RPC_URL = ETHEREUM_RPC_URL[networkKey]
+ process.env.UPKEEP_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.UPKEEP_ADDRESS
+ process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.FUNCTIONS_BILLING_REGISTRY_ADDRESS
+ process.env.FUNCTIONS_ORACLE_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.FUNCTIONS_ORACLE_ADDRESS
+ }
+ if (!process.env.ETHEREUM_RPC_URL) throw new Error(`No ethereum rpc url provided for ${networkKey}`)
+ if (!process.env.UPKEEP_ADDRESS) throw new Error(`No upkeep address provided for ${networkKey}`)
+ if (!process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS) throw new Error(`No functions billing registry address provided for ${networkKey}`)
+ if (!process.env.FUNCTIONS_ORACLE_ADDRESS) throw new Error('No functions oracle address provided')
+
+ process.env.ETHEREUM_BEACON_RPC_URL = process.env.ETHEREUM_BEACON_RPC_URL || 'http://127.0.0.1:5002'
+
+ process.env.USE_LOGS = process.env.USE_LOGS || 'false'
+ run(`npx esno -r dotenv/config src/index.ts${process.env.USE_LOGS === 'true' ? ' >> .log/functions.log' : ''}`)
+ console.log('🔗 Functions service started')
+}()
\ No newline at end of file
diff --git a/services/functions/src/index.ts b/services/functions/src/index.ts
new file mode 100644
index 000000000..c26703b01
--- /dev/null
+++ b/services/functions/src/index.ts
@@ -0,0 +1,66 @@
+import { getConfig } from './providers/config'
+import { getEventsIterable } from '@casimir/events'
+import { getStartBlock, updateErrorLog, updateStartBlock } from '@casimir/logs'
+import { fulfillRequestHandler } from './providers/handlers'
+import { ethers } from 'ethers'
+
+const config = getConfig()
+
+const contracts = {
+ FunctionsOracle: {
+ abi: config.functionsOracleAbi,
+ address: config.functionsOracleAddress,
+ events: {
+ OracleRequest: fulfillRequestHandler
+ }
+ }
+}
+
+const contractFilters = Object.values(contracts).map((contract) => {
+ return {
+ abi: contract.abi,
+ address: contract.address,
+ events: Object.keys(contract.events)
+ }
+})
+
+let startBlock
+if (process.env.USE_LOGS === 'true') {
+ startBlock = getStartBlock('.log/block.log')
+}
+
+const eventsIterable = getEventsIterable({
+ contractFilters,
+ ethereumUrl: config.ethereumUrl,
+ startBlock
+})
+
+const handlers: Record Promise> = {}
+for (const contractName in contracts) {
+ const contract = contracts[contractName as keyof typeof contracts]
+ for (const [event, handler] of Object.entries(contract.events)) {
+ handlers[event as keyof typeof handlers] = handler
+ }
+}
+
+void async function () {
+ try {
+ for await (const event of eventsIterable) {
+ const details = event?.[event.length - 1] as ethers.Event
+ const input = details.args as ethers.utils.Result
+ const handler = handlers[details.event as string]
+ if (!handler) throw new Error(`No handler found for event ${details.event}`)
+ await handler(input)
+ if (process.env.USE_LOGS === 'true') {
+ updateStartBlock('.log/block.log', details.blockNumber)
+ }
+ }
+ } catch (error) {
+ if (process.env.USE_LOGS === 'true') {
+ updateErrorLog('.log/error.log', (error as Error).message)
+ } else {
+ console.log(error)
+ }
+ process.exit(1)
+ }
+}()
\ No newline at end of file
diff --git a/services/functions/src/providers/config.ts b/services/functions/src/providers/config.ts
new file mode 100644
index 000000000..075fbee04
--- /dev/null
+++ b/services/functions/src/providers/config.ts
@@ -0,0 +1,37 @@
+import { ethers } from 'ethers'
+import CasimirUpkeepAbi from '@casimir/ethereum/build/abi/CasimirUpkeep.json'
+import FunctionsOracleAbi from '@casimir/ethereum/build/abi/FunctionsOracle.json'
+import FunctionsBillingRegistryAbi from '@casimir/ethereum/build/abi/FunctionsBillingRegistry.json'
+
+export function getConfig() {
+ const ethereumUrl = process.env.ETHEREUM_RPC_URL
+ if (!ethereumUrl) throw new Error('No ethereum rpc url provided')
+
+ const mnemonic = process.env.BIP39_SEED
+ if (!mnemonic) throw new Error('No mnemonic provided')
+ const accountPath = 'm/44\'/60\'/0\'/0/2'
+ const wallet = ethers.Wallet.fromMnemonic(mnemonic, accountPath)
+
+ const upkeepAbi = CasimirUpkeepAbi
+ const upkeepAddress = process.env.UPKEEP_ADDRESS
+ if (!upkeepAddress) throw new Error('No upkeep address provided')
+
+ const functionsBillingRegistryAbi = FunctionsBillingRegistryAbi
+ const functionsBillingRegistryAddress = process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS
+ if (!functionsBillingRegistryAddress) throw new Error('No functions billing registry address provided')
+
+ const functionsOracleAbi = FunctionsOracleAbi
+ const functionsOracleAddress = process.env.FUNCTIONS_ORACLE_ADDRESS
+ if (!functionsOracleAddress) throw new Error('No functions oracle address provided')
+
+ return {
+ ethereumUrl,
+ upkeepAbi,
+ upkeepAddress,
+ functionsBillingRegistryAbi,
+ functionsBillingRegistryAddress,
+ functionsOracleAbi,
+ functionsOracleAddress,
+ wallet
+ }
+}
\ No newline at end of file
diff --git a/services/functions/src/providers/format.ts b/services/functions/src/providers/format.ts
new file mode 100644
index 000000000..df8017b65
--- /dev/null
+++ b/services/functions/src/providers/format.ts
@@ -0,0 +1,54 @@
+import { ethers } from 'ethers'
+import cbor from 'cbor'
+
+/**
+ * Decodes a CBOR hex string, and adds opening and closing brackets to the CBOR if they are not present.
+ * @param hex The hex string to decode
+ */
+export function decodeDietCBOR(hex: string) {
+ const buf = hexToBuf(hex)
+ return cbor.decodeFirstSync(addCBORMapDelimiters(buf))
+}
+
+/**
+ * Create a buffer from a hex string
+ * @param hex The hex string to convert to a buffer
+ */
+export function hexToBuf(hex: string): Buffer {
+ return Buffer.from(stripHexPrefix(hex), 'hex')
+}
+
+/**
+ * Strip the leading 0x hex prefix from a hex string
+ * @param hex The hex string to strip the leading hex prefix out of
+ */
+export function stripHexPrefix(hex: string): string {
+ if (!ethers.utils.isHexString(hex)) {
+ throw Error(`Expected valid hex string, got: "${hex}"`)
+ }
+ return hex.replace('0x', '')
+}
+
+/**
+ * Add a starting and closing map characters to a CBOR encoding if they are not already present.
+ */
+export function addCBORMapDelimiters(buffer: Buffer): Buffer {
+ if (buffer[0] >> 5 === 5) {
+ return buffer
+ }
+
+ /**
+ * This is the opening character of a CBOR map.
+ * @see https://en.wikipedia.org/wiki/CBOR#CBOR_data_item_header
+ */
+ const startIndefiniteLengthMap = Buffer.from([0xbf])
+ /**
+ * This is the closing character in a CBOR map.
+ * @see https://en.wikipedia.org/wiki/CBOR#CBOR_data_item_header
+ */
+ const endIndefiniteLengthMap = Buffer.from([0xff])
+ return Buffer.concat(
+ [startIndefiniteLengthMap, buffer, endIndefiniteLengthMap],
+ buffer.length + 2,
+ )
+}
\ No newline at end of file
diff --git a/services/functions/src/providers/handlers.ts b/services/functions/src/providers/handlers.ts
new file mode 100644
index 000000000..47db4e33c
--- /dev/null
+++ b/services/functions/src/providers/handlers.ts
@@ -0,0 +1,47 @@
+import { ethers } from 'ethers'
+import { decodeDietCBOR } from './format'
+import requestConfig from '@casimir/functions/Functions-request-config'
+import { simulateRequest } from '../../FunctionsSandboxLibrary'
+import { getConfig } from './config'
+import { FunctionsBillingRegistry } from '@casimir/ethereum/build/@types'
+import { updateExecutionLog } from '@casimir/logs'
+
+const config = getConfig()
+
+export async function fulfillRequestHandler(input: ethers.utils.Result): Promise {
+ const { requestId, data } = input
+ if (!requestId) throw new Error('No request id provided')
+ if (!data) throw new Error('No data provided')
+
+ const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
+ const signer = config.wallet.connect(provider)
+ const functionsBillingRegistry = new ethers.Contract(config.functionsBillingRegistryAddress, config.functionsBillingRegistryAbi, signer) as ethers.Contract & FunctionsBillingRegistry
+ const { args } = decodeDietCBOR(data)
+ const currentRequestConfig = {
+ ...requestConfig,
+ args
+ }
+ const { result, resultLog, success } = await simulateRequest(currentRequestConfig)
+ if (success) {
+ const dummySigners = Array(31).fill(signer.address)
+ const fulfillAndBill = await functionsBillingRegistry.fulfillAndBill(
+ requestId,
+ result,
+ '0x',
+ signer.address,
+ dummySigners,
+ 4,
+ 100_000,
+ 500_000,
+ {
+ gasLimit: 500_000,
+ }
+ )
+ await fulfillAndBill.wait()
+ if (process.env.USE_LOGS === 'true') {
+ updateExecutionLog('.log/execution.log', resultLog)
+ }
+ } else {
+ throw new Error(resultLog)
+ }
+}
\ No newline at end of file
diff --git a/services/functions/tsconfig.json b/services/functions/tsconfig.json
new file mode 100644
index 000000000..dd25f8011
--- /dev/null
+++ b/services/functions/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "strict": true,
+ "preserveConstEnums": true,
+ "noEmit": true,
+ "sourceMap": false,
+ "module": "CommonJS",
+ "moduleResolution": "Node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true,
+ "allowJs": true
+ },
+ "include": [
+ "./src/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/services/nodes/nginx.conf b/services/nodes/nginx.conf
index a7e4ab732..426de81b1 100644
--- a/services/nodes/nginx.conf
+++ b/services/nodes/nginx.conf
@@ -23,9 +23,9 @@ http {
}
upstream eth_goerli_ssv_exporter {
- keepalive 64;
- keepalive_requests 10000;
- server 127.0.0.1:16000;
+ keepalive 64;
+ keepalive_requests 10000;
+ server 127.0.0.1:16000;
}
upstream eth_goerli_dkg_messenger {
@@ -59,27 +59,27 @@ http {
}
upstream eth_goerli_dkg_5 {
- keepalive 64;
- keepalive_requests 10000;
- server 127.0.0.1:2505;
+ keepalive 64;
+ keepalive_requests 10000;
+ server 127.0.0.1:2505;
}
upstream eth_goerli_dkg_6 {
- keepalive 64;
- keepalive_requests 10000;
- server 127.0.0.1:2506;
+ keepalive 64;
+ keepalive_requests 10000;
+ server 127.0.0.1:2506;
}
upstream eth_goerli_dkg_7 {
- keepalive 64;
- keepalive_requests 10000;
- server 127.0.0.1:2507;
+ keepalive 64;
+ keepalive_requests 10000;
+ server 127.0.0.1:2507;
}
upstream eth_goerli_dkg_8 {
- keepalive 64;
- keepalive_requests 10000;
- server 127.0.0.1:2508;
+ keepalive 64;
+ keepalive_requests 10000;
+ server 127.0.0.1:2508;
}
upstream eth_prater {
@@ -137,15 +137,15 @@ http {
proxy_pass http://eth_goerli/graphql/;
}
- # Ethereum goerli ssv exporter API
- location ^~ /eth/goerli/ssv/exporter/ {
- proxy_pass http://eth_goerli_ssv_exporter/;
- }
+ # Ethereum goerli ssv exporter API
+ location ^~ /eth/goerli/ssv/exporter/ {
+ proxy_pass http://eth_goerli_ssv_exporter/;
+ }
- # Ethereum goerli dkg messenger URL
- location ^~ /eth/goerli/dkg/messenger/ {
- proxy_pass http://eth_goerli_dkg_messenger/;
- }
+ # Ethereum goerli dkg messenger URL
+ location ^~ /eth/goerli/dkg/messenger/ {
+ proxy_pass http://eth_goerli_dkg_messenger/;
+ }
# Ethereum goerli dkg broadcast URL 1
location ^~ /eth/goerli/dkg/1/ {
diff --git a/services/oracle/.gitignore b/services/oracle/.gitignore
index 614c1c82a..267b88549 100644
--- a/services/oracle/.gitignore
+++ b/services/oracle/.gitignore
@@ -1 +1,2 @@
-.out
\ No newline at end of file
+.out
+.log
\ No newline at end of file
diff --git a/services/oracle/scripts/clean.ts b/services/oracle/scripts/clean.ts
index 597d343ea..bdfd43d53 100644
--- a/services/oracle/scripts/clean.ts
+++ b/services/oracle/scripts/clean.ts
@@ -1,4 +1,4 @@
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
/**
* Clean up resources
diff --git a/services/oracle/scripts/dev.ts b/services/oracle/scripts/dev.ts
index 3e6d7a486..635921136 100644
--- a/services/oracle/scripts/dev.ts
+++ b/services/oracle/scripts/dev.ts
@@ -1,4 +1,7 @@
-import { fetchRetry, run } from '@casimir/helpers'
+import { loadCredentials, getSecret } from '@casimir/aws'
+import { ETHEREUM_CONTRACTS, ETHEREUM_RPC_URL } from '@casimir/env'
+import { fetchRetry } from '@casimir/fetch'
+import { run } from '@casimir/shell'
/**
* Start development DAO oracle service
@@ -11,19 +14,40 @@ void async function () {
process.env.MESSENGER_SRV_ADDR = process.env.MESSENGER_URL
process.env.USE_HARDCODED_OPERATORS = 'false'
- process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
- process.env.BIP39_PATH_INDEX = process.env.BIP39_PATH_INDEX || '6'
- if (!process.env.MANAGER_ADDRESS) throw new Error('Manager address not found')
- if (!process.env.VIEWS_ADDRESS) throw new Error('Views address not found')
- if (!process.env.REGISTRY_ADDRESS) throw new Error('Registry address not found')
- if (!process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS) throw new Error('Functions billing registry address not found')
- if (!process.env.LINK_REGISTRY_ADDRESS) throw new Error('Link registry address not found')
- process.env.LINK_TOKEN_ADDRESS = '0x326C977E6efc84E512bB9C30f76E30c160eD06FB'
- process.env.SSV_NETWORK_ADDRESS = '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3'
- process.env.SSV_NETWORK_VIEWS_ADDRESS = '0x8dB45282d7C4559fd093C26f677B3837a5598914'
- process.env.SSV_TOKEN_ADDRESS = '0x3a9f01091C446bdE031E39ea8354647AFef091E7'
- process.env.UNISWAP_V3_FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984'
- process.env.WETH_TOKEN_ADDRESS = '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'
+ if (process.env.USE_SECRETS !== 'false') {
+ await loadCredentials()
+ process.env.BIP39_SEED = process.env.BIP39_SEED || await getSecret('consensus-networks-bip39-seed') as string
+ } else {
+ process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
+ }
+
+ const networkKey = process.env.NETWORK?.toUpperCase() || process.env.FORK?.toUpperCase() || 'TESTNET'
+ if (process.env.NETWORK) {
+ process.env.ETHEREUM_RPC_URL = ETHEREUM_RPC_URL[networkKey]
+ process.env.MANAGER_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.MANAGER_ADDRESS
+ process.env.REGISTRY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.REGISTRY_ADDRESS
+ process.env.UPKEEP_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.UPKEEP_ADDRESS
+ process.env.VIEWS_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.VIEWS_ADDRESS
+ process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.FUNCTIONS_BILLING_REGISTRY_ADDRESS
+ }
+ process.env.KEEPER_REGISTRY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.KEEPER_REGISTRY_ADDRESS
+ process.env.LINK_TOKEN_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.LINK_TOKEN_ADDRESS
+ process.env.SSV_NETWORK_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_NETWORK_ADDRESS
+ process.env.SSV_VIEWS_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_VIEWS_ADDRESS
+ process.env.SSV_TOKEN_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SSV_TOKEN_ADDRESS
+ process.env.SWAP_FACTORY_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.SWAP_FACTORY_ADDRESS
+ process.env.WETH_TOKEN_ADDRESS = ETHEREUM_CONTRACTS[networkKey]?.WETH_TOKEN_ADDRESS
+ if (!process.env.ETHEREUM_RPC_URL) throw new Error(`No ethereum rpc url provided for ${networkKey}`)
+ if (!process.env.MANAGER_ADDRESS) throw new Error(`No manager address provided for ${networkKey}`)
+ if (!process.env.VIEWS_ADDRESS) throw new Error(`No views address provided for ${networkKey}`)
+ if (!process.env.REGISTRY_ADDRESS) throw new Error(`No registry address provided for ${networkKey}`)
+ if (!process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS) throw new Error(`No functions billing registry address provided for ${networkKey}`)
+ if (!process.env.KEEPER_REGISTRY_ADDRESS) throw new Error(`No keeper registry address provided for ${networkKey}`)
+ if (!process.env.LINK_TOKEN_ADDRESS) throw new Error(`No link token address provided for ${networkKey}`)
+ if (!process.env.SSV_NETWORK_ADDRESS) throw new Error(`No ssv network address provided for ${networkKey}`)
+ if (!process.env.SSV_VIEWS_ADDRESS) throw new Error(`No ssv views address provided for ${networkKey}`)
+ if (!process.env.SSV_TOKEN_ADDRESS) throw new Error(`No ssv token address provided for ${networkKey}`)
+ if (!process.env.SWAP_FACTORY_ADDRESS) throw new Error(`No uniswap v3 factory address provided for ${networkKey}`)
const dkg = await run(`which ${process.env.CLI_PATH}`) as string
if (!dkg || dkg.includes('not found')) {
@@ -33,6 +57,7 @@ void async function () {
const { message } = await ping.json()
if (message !== 'pong') throw new Error('Dkg service is not running')
+ process.env.USE_LOGS = process.env.USE_LOGS || 'false'
run('npx esno -r dotenv/config src/index.ts')
console.log('🔮 Oracle service started')
}()
\ No newline at end of file
diff --git a/services/oracle/scripts/generate.ts b/services/oracle/scripts/generate.ts
index 0e1566945..1829d61d0 100644
--- a/services/oracle/scripts/generate.ts
+++ b/services/oracle/scripts/generate.ts
@@ -1,9 +1,10 @@
import fs from 'fs'
import { ethers } from 'ethers'
-import { fetchRetry, run } from '@casimir/helpers'
-import { Validator } from '@casimir/types'
+import { fetchRetry } from '@casimir/fetch'
+import { run } from '@casimir/shell'
+import { /*Reshare, */Validator } from '@casimir/types'
import { Dkg } from '../src/providers/dkg'
-import { validatorStore } from '@casimir/data'
+import { /*reshareStore, */validatorStore } from '@casimir/data'
/**
* Generate validator keys for ethereum testing
@@ -20,21 +21,15 @@ void async function () {
process.env.BIP39_SEED = process.env.BIP39_SEED || 'inflict ball claim confirm cereal cost note dad mix donate traffic patient'
if (!process.env.MANAGER_ADDRESS) throw new Error('No manager address set')
if (!process.env.VIEWS_ADDRESS) throw new Error('No views address set')
- process.env.LINK_TOKEN_ADDRESS = '0x326C977E6efc84E512bB9C30f76E30c160eD06FB'
- process.env.SSV_NETWORK_ADDRESS = '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3'
- process.env.SSV_NETWORK_VIEWS_ADDRESS = '0x8dB45282d7C4559fd093C26f677B3837a5598914'
- process.env.SSV_TOKEN_ADDRESS = '0x3a9f01091C446bdE031E39ea8354647AFef091E7'
- process.env.UNISWAP_V3_FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984'
- process.env.WETH_TOKEN_ADDRESS = '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'
- const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [654, 655, 656, 657]
- if (preregisteredOperatorIds.length < 4) throw new Error('Not enough operator ids provided')
+ const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [200, 201, 202, 203, 156, 157, 158, 159]
+ if (preregisteredOperatorIds.length < 8) throw new Error('Not enough operator ids provided')
- const wallet = ethers.Wallet.fromMnemonic(process.env.BIP39_SEED, 'm/44\'/60\'/0\'/0/6')
- const daoOracleAddress = wallet.address
+ const accountPath = 'm/44\'/60\'/0\'/0/1'
+ const wallet = ethers.Wallet.fromMnemonic(process.env.BIP39_SEED, accountPath)
const validatorCount = 4
- if (!validatorStore[daoOracleAddress] || Object.keys(validatorStore[daoOracleAddress]).length < validatorCount) {
+ if (!validatorStore[wallet.address] || Object.keys(validatorStore[wallet.address]).length < validatorCount) {
const dkg = await run(`which ${process.env.CLI_PATH}`) as string
if (!dkg || dkg.includes('not found')) {
await run(`GOWORK=off make -C ${resourceDir}/rockx-dkg-cli build`)
@@ -47,15 +42,17 @@ void async function () {
let ownerNonce = 0
const newValidators: Validator[] = []
+ // const newReshares: Reshare[] = []
for (let i = 0; i < validatorCount; i++) {
+ const poolId = i + 1
const poolAddress = ethers.utils.getContractAddress({
from: process.env.MANAGER_ADDRESS,
nonce: managerNonce
})
- const selectedOperatorIds = preregisteredOperatorIds.slice(0, 4)
+ const selectedOperatorIds = preregisteredOperatorIds.slice(4)
const cli = new Dkg({
cliPath: process.env.CLI_PATH,
@@ -63,21 +60,38 @@ void async function () {
})
const validator = await cli.createValidator({
- poolId: i + 1,
+ poolId,
operatorIds: selectedOperatorIds,
ownerAddress: process.env.MANAGER_ADDRESS,
ownerNonce,
withdrawalAddress: poolAddress
})
-
newValidators.push(validator)
+ // for (let j = 0; j < 2; j++) {
+ // const oldOperatorIds = selectedOperatorIds.slice(1)
+ // const reshareOperatorIds = preregisteredOperatorIds.slice(5).concat(preregisteredOperatorIds[0])
+
+ // const reshare = await cli.reshareValidator({
+ // oldOperatorIds,
+ // operatorIds: reshareOperatorIds,
+ // ownerAddress: process.env.MANAGER_ADDRESS,
+ // ownerNonce,
+ // poolId,
+ // publicKey: validator.publicKey,
+ // withdrawalAddress: poolAddress
+ // })
+ // newReshares.push(reshare)
+ // }
+ // reshareStore[poolId] = newReshares
+
managerNonce++
ownerNonce++
}
- validatorStore[daoOracleAddress] = newValidators
+ validatorStore[wallet.address] = newValidators
fs.writeFileSync(`${outputPath}/validator.store.json`, JSON.stringify(validatorStore, null, 4))
+ // fs.writeFileSync(`${outputPath}/reshare.store.json`, JSON.stringify(reshareStore, null, 4))
}
}()
\ No newline at end of file
diff --git a/services/oracle/scripts/resources/rockx-dkg-cli b/services/oracle/scripts/resources/rockx-dkg-cli
index bed620f94..171973247 160000
--- a/services/oracle/scripts/resources/rockx-dkg-cli
+++ b/services/oracle/scripts/resources/rockx-dkg-cli
@@ -1 +1 @@
-Subproject commit bed620f94a2c28b860dafb102af161caae8d6488
+Subproject commit 171973247f89caae74003c484c3913ecfd33e62e
diff --git a/services/oracle/src/index.ts b/services/oracle/src/index.ts
index 23db96a02..bacb68871 100644
--- a/services/oracle/src/index.ts
+++ b/services/oracle/src/index.ts
@@ -1,42 +1,82 @@
import { getConfig } from './providers/config'
-import { getEventsIterable } from './providers/events'
+import { getEventsIterable } from '@casimir/events'
+import { getStartBlock, updateErrorLog, updateStartBlock } from '@casimir/logs'
import {
depositFunctionsBalanceHandler,
depositUpkeepBalanceHandler,
initiateDepositHandler,
- initiateResharesHandler,
+ reportResharesHandler,
// initiateExitsHandler,
// reportForcedExitsHandler,
reportCompletedExitsHandler
} from './providers/handlers'
+import { ethers } from 'ethers'
const config = getConfig()
-const handlers = {
- DepositRequested: initiateDepositHandler,
- ResharesRequested: initiateResharesHandler,
- /**
- * We don't need to handle these/they aren't ready:
- * ExitRequested: initiateExitsHandler,
- * ForcedExitReportsRequested: reportForcedExitsHandler,
- */
- CompletedExitReportsRequested: reportCompletedExitsHandler
+
+const contracts = {
+ CasimirManager: {
+ abi: config.managerAbi,
+ address: config.managerAddress,
+ events: {
+ DepositRequested: initiateDepositHandler,
+ ResharesRequested: reportResharesHandler,
+ // ExitRequested: initiateExitsHandler,
+ // ForcedExitReportsRequested: reportForcedExitsHandler,
+ CompletedExitReportsRequested: reportCompletedExitsHandler
+
+ }
+ }
+}
+
+const contractFilters = Object.values(contracts).map((contract) => {
+ return {
+ abi: contract.abi,
+ address: contract.address,
+ events: Object.keys(contract.events)
+ }
+})
+
+let startBlock
+if (process.env.USE_LOGS === 'true') {
+ startBlock = getStartBlock('.log/block.log')
+}
+
+const eventsIterable = getEventsIterable({
+ contractFilters,
+ ethereumUrl: config.ethereumUrl,
+ startBlock
+})
+
+const handlers: Record Promise> = {}
+for (const contractName in contracts) {
+ const contract = contracts[contractName as keyof typeof contracts]
+ for (const [event, handler] of Object.entries(contract.events)) {
+ handlers[event as keyof typeof handlers] = handler
+ }
}
void async function () {
- const eventsIterable = getEventsIterable({
- ethereumUrl: config.ethereumUrl,
- managerAddress: config.managerAddress,
- events: Object.keys(handlers)
- })
-
- for await (const event of eventsIterable) {
- const details = event?.[event.length - 1]
- const { args } = details
- const handler = handlers[details.event as keyof typeof handlers]
- if (!handler) throw new Error(`No handler found for event ${details.event}`)
- await depositFunctionsBalanceHandler()
- await depositUpkeepBalanceHandler()
- await handler({ args })
+ try {
+ for await (const event of eventsIterable) {
+ const details = event?.[event.length - 1] as ethers.Event
+ const input = details.args as ethers.utils.Result
+ const handler = handlers[details.event as keyof typeof handlers]
+ if (!handler) throw new Error(`No handler found for event ${details.event}`)
+ await depositFunctionsBalanceHandler()
+ await depositUpkeepBalanceHandler()
+ await handler(input)
+ if (process.env.USE_LOGS === 'true') {
+ updateStartBlock('.log/block.log', details.blockNumber)
+ }
+ }
+ } catch (error) {
+ if (process.env.USE_LOGS === 'true') {
+ updateErrorLog('.log/error.log', (error as Error).message)
+ } else {
+ console.log(error)
+ }
+ process.exit(1)
}
}()
diff --git a/services/oracle/src/interfaces/GetEventsIterableInput.ts b/services/oracle/src/interfaces/GetEventsIterableInput.ts
deleted file mode 100644
index 0fda967e0..000000000
--- a/services/oracle/src/interfaces/GetEventsIterableInput.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { ethers } from 'ethers'
-
-export interface GetEventsIterableInput {
- ethereumUrl?: string
- provider?: ethers.providers.JsonRpcProvider
- managerAddress: string
- events: string[]
-}
\ No newline at end of file
diff --git a/services/oracle/src/interfaces/HandlerInput.ts b/services/oracle/src/interfaces/HandlerInput.ts
deleted file mode 100644
index 386633ad4..000000000
--- a/services/oracle/src/interfaces/HandlerInput.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export interface HandlerInput {
- args: {
- poolId?: number
- operatorId?: number
- count?: number
- }
-}
\ No newline at end of file
diff --git a/services/oracle/src/interfaces/ReshareValidatorInput.ts b/services/oracle/src/interfaces/ReshareValidatorInput.ts
index 76d0347ac..d14016263 100644
--- a/services/oracle/src/interfaces/ReshareValidatorInput.ts
+++ b/services/oracle/src/interfaces/ReshareValidatorInput.ts
@@ -1,9 +1,9 @@
export interface ReshareValidatorInput {
- publicKey: string
- poolId: number
- operatorIds: number[]
oldOperatorIds: number[]
+ operatorIds: number[]
ownerAddress: string
ownerNonce: number
+ poolId: number
+ publicKey: string
withdrawalAddress: string
}
\ No newline at end of file
diff --git a/services/oracle/src/providers/config.ts b/services/oracle/src/providers/config.ts
index 7d0103f60..e0d379678 100644
--- a/services/oracle/src/providers/config.ts
+++ b/services/oracle/src/providers/config.ts
@@ -1,4 +1,5 @@
import { ethers } from 'ethers'
+import ICasimirManagerAbi from '@casimir/ethereum/build/abi/ICasimirManager.json'
export function getConfig() {
const cliPath = process.env.CLI_PATH
@@ -11,29 +12,29 @@ export function getConfig() {
const mnemonic = process.env.BIP39_SEED
if (!mnemonic) throw new Error('No mnemonic provided')
- const pathIndex = process.env.BIP39_PATH_INDEX
- const path = `m/44'/60'/0'/0/${pathIndex || 0}`
- const wallet = ethers.Wallet.fromMnemonic(mnemonic, path)
-
+ const accountPath = 'm/44\'/60\'/0\'/0/1'
+ const wallet = ethers.Wallet.fromMnemonic(mnemonic, accountPath)
+
+ const managerAbi = ICasimirManagerAbi
const managerAddress = process.env.MANAGER_ADDRESS
if (!managerAddress) throw new Error('No manager address provided')
- const viewsAddress = process.env.VIEWS_ADDRESS
- if (!viewsAddress) throw new Error('No views address provided')
const registryAddress = process.env.REGISTRY_ADDRESS
if (!registryAddress) throw new Error('No registry address provided')
+ const viewsAddress = process.env.VIEWS_ADDRESS
+ if (!viewsAddress) throw new Error('No views address provided')
const functionsBillingRegistryAddress = process.env.FUNCTIONS_BILLING_REGISTRY_ADDRESS
if (!functionsBillingRegistryAddress) throw new Error('No functions billing registry address provided')
- const linkRegistryAddress = process.env.LINK_REGISTRY_ADDRESS
- if (!linkRegistryAddress) throw new Error('No link registry address provided')
+ const keeperRegistryAddress = process.env.KEEPER_REGISTRY_ADDRESS
+ if (!keeperRegistryAddress) throw new Error('No link registry address provided')
const linkTokenAddress = process.env.LINK_TOKEN_ADDRESS
if (!linkTokenAddress) throw new Error('No link token address provided')
const ssvNetworkAddress = process.env.SSV_NETWORK_ADDRESS
if (!ssvNetworkAddress) throw new Error('No ssv network address provided')
- const ssvNetworkViewsAddress = process.env.SSV_NETWORK_VIEWS_ADDRESS
- if (!ssvNetworkViewsAddress) throw new Error('No ssv network views address provided')
const ssvTokenAddress = process.env.SSV_TOKEN_ADDRESS
if (!ssvTokenAddress) throw new Error('No ssv token address provided')
- const uniswapV3FactoryAddress = process.env.UNISWAP_V3_FACTORY_ADDRESS
+ const ssvViewsAddress = process.env.SSV_VIEWS_ADDRESS
+ if (!ssvViewsAddress) throw new Error('No ssv network views address provided')
+ const uniswapV3FactoryAddress = process.env.SWAP_FACTORY_ADDRESS
if (!uniswapV3FactoryAddress) throw new Error('No uniswap v3 factory address provided')
const wethTokenAddress = process.env.WETH_TOKEN_ADDRESS
if (!wethTokenAddress) throw new Error('No weth token address provided')
@@ -43,15 +44,16 @@ export function getConfig() {
messengerUrl,
ethereumUrl,
wallet,
+ managerAbi,
managerAddress,
- viewsAddress,
registryAddress,
+ viewsAddress,
functionsBillingRegistryAddress,
- linkRegistryAddress,
+ keeperRegistryAddress,
linkTokenAddress,
ssvNetworkAddress,
- ssvNetworkViewsAddress,
ssvTokenAddress,
+ ssvViewsAddress,
uniswapV3FactoryAddress,
wethTokenAddress
}
diff --git a/services/oracle/src/providers/dkg.ts b/services/oracle/src/providers/dkg.ts
index 0c3198a39..9b7671527 100644
--- a/services/oracle/src/providers/dkg.ts
+++ b/services/oracle/src/providers/dkg.ts
@@ -3,9 +3,9 @@ import { StartKeygenInput } from '../interfaces/StartKeygenInput'
import { DepositData } from '../interfaces/DepositData'
import { DkgOptions } from '../interfaces/DkgOptions'
import { StartReshareInput } from '../interfaces/StartReshareInput'
-import { getWithdrawalCredentials, run, runRetry } from '@casimir/helpers'
+import { run, runRetry } from '@casimir/shell'
import { CreateValidatorInput } from '../interfaces/CreateValidatorInput'
-import { Validator } from '@casimir/types'
+import { Reshare, Validator } from '@casimir/types'
import { ReshareValidatorInput } from '../interfaces/ReshareValidatorInput'
import { getOperatorUrls } from './registry'
import { GetSharesInput } from '../interfaces/GetSharesInput'
@@ -26,133 +26,125 @@ export class Dkg {
/**
* Create validator with operator key shares and deposit data
* @param {CreateValidatorInput} input - Input for creating a validator
+ * @param {number} retries - Number of retries
* @returns {Promise} Validator with operator key shares and deposit data
*/
- async createValidator(input: CreateValidatorInput): Promise {
- const operators = getOperatorUrls(input.operatorIds)
- const requestId = await this.startKeygen({
- operators,
- withdrawalAddress: input.withdrawalAddress
- })
-
- console.log(`Started request ${requestId} for pool ${input.poolId}`)
-
- await new Promise(resolve => setTimeout(resolve, 2500))
-
- const shares = await this.getShares({
- requestId,
- operators,
- ownerAddress: input.ownerAddress,
- ownerNonce: input.ownerNonce
- })
-
- const depositData = await this.getDepositData({
- requestId,
- withdrawalAddress: input.withdrawalAddress
- })
+ async createValidator(input: CreateValidatorInput, retries: number | undefined = 25): Promise {
+ try {
+ const operators = getOperatorUrls(input.operatorIds)
+ const requestId = await this.startKeygen({
+ operators,
+ withdrawalAddress: input.withdrawalAddress
+ })
+
+ console.log(`Started request ${requestId} for pool ${input.poolId}`)
+
+ await new Promise(resolve => setTimeout(resolve, 2500))
+
+ const shares = await this.getShares({
+ requestId,
+ operators,
+ ownerAddress: input.ownerAddress,
+ ownerNonce: input.ownerNonce
+ })
+
+ const depositData = await this.getDepositData({
+ requestId,
+ withdrawalAddress: input.withdrawalAddress
+ })
+
+ const validator: Validator = {
+ depositDataRoot: depositData.depositDataRoot,
+ publicKey: depositData.publicKey,
+ operatorIds: input.operatorIds,
+ shares,
+ signature: depositData.signature,
+ withdrawalCredentials: depositData.withdrawalCredentials
+ }
- const validator: Validator = {
- depositDataRoot: depositData.depositDataRoot,
- publicKey: depositData.publicKey,
- operatorIds: input.operatorIds,
- shares,
- signature: depositData.signature,
- withdrawalCredentials: depositData.withdrawalCredentials
+ return validator
+ } catch (error) {
+ if (retries === 0) {
+ throw error
+ }
+ await new Promise(resolve => setTimeout(resolve, 2500))
+ console.log(`Retrying create validator request ${retries} more times`)
+ return await this.createValidator(input, retries - 1)
}
-
- return validator
}
/**
- * Reshare validator for new operator key shares and deposit data
+ * Reshare validator for new operator key IDs and key shares
* @param {ReshareValidatorInput} input - Input for resharing a validator
- * @returns {Promise} Validator with operator key shares and deposit data
- */
- async reshareValidator(input: ReshareValidatorInput): Promise {
- const operators = getOperatorUrls(input.operatorIds)
- const oldOperators = getOperatorUrls(input.oldOperatorIds)
- const requestId = await this.startReshare({
- operators,
- publicKey: input.publicKey,
- oldOperators
- })
-
- console.log(`Started request ${requestId} for pool ${input.poolId}`)
-
- await new Promise(resolve => setTimeout(resolve, 2500))
-
- const shares = await this.getShares({
- requestId,
- operators,
- ownerAddress: input.ownerAddress,
- ownerNonce: input.ownerNonce
- })
-
- const depositData = await this.getDepositData({
- requestId,
- withdrawalAddress: input.withdrawalAddress
- })
-
- const validator: Validator = {
- depositDataRoot: depositData.depositDataRoot,
- publicKey: input.publicKey,
- operatorIds: input.operatorIds,
- shares,
- signature: depositData.signature,
- withdrawalCredentials: depositData.withdrawalCredentials
- }
-
- return validator
- }
-
- /**
- * Start a keygen request
- * @param {StartKeygenInput} input - Keygen input
* @param {number} retries - Number of retries
- * @returns {Promise} Ceremony ID
+ * @returns {Promise} New operator IDs and key shares for a validator
*/
- async startKeygen(input: StartKeygenInput, retries: number | undefined = 25): Promise {
+ async reshareValidator(input: ReshareValidatorInput, retries: number | undefined = 25): Promise {
try {
- const operatorFlags = Object.entries(input.operators).map(([id, url]) => `--operator ${id}=${url}`).join(' ')
- const thresholdFlag = `--threshold ${Object.keys(input.operators).length - 1}`
- const withdrawalCredentialsFlag = `--withdrawal-credentials ${getWithdrawalCredentials(input.withdrawalAddress)}`
- const forkVersionFlag = '--fork-version prater'
- const command = `${this.cliPath} keygen ${operatorFlags} ${thresholdFlag} ${withdrawalCredentialsFlag} ${forkVersionFlag}`
- const request = await run(`${command}`) as string
- return request.trim().split(' ').pop() as string
+ const operators = getOperatorUrls(input.operatorIds)
+ const oldOperators = getOperatorUrls(input.oldOperatorIds)
+ const requestId = await this.startReshare({
+ operators,
+ publicKey: input.publicKey,
+ oldOperators: oldOperators
+ })
+
+ console.log(`Started request ${requestId} for pool ${input.poolId}`)
+
+ await new Promise(resolve => setTimeout(resolve, 2500))
+
+ const shares = await this.getShares({
+ requestId,
+ operators,
+ ownerAddress: input.ownerAddress,
+ ownerNonce: input.ownerNonce
+ })
+
+ return {
+ operatorIds: input.operatorIds,
+ oldOperatorIds: input.oldOperatorIds,
+ poolId: input.poolId,
+ publicKey: input.publicKey,
+ shares
+ }
} catch (error) {
if (retries === 0) {
throw error
}
await new Promise(resolve => setTimeout(resolve, 2500))
- console.log(`Retrying keygen request ${retries} more times`)
- return await this.startKeygen(input, retries - 1)
+ console.log(`Retrying reshare validator request ${retries} more times`)
+ return await this.reshareValidator(input, retries - 1)
}
}
+ /**
+ * Start a keygen request
+ * @param {StartKeygenInput} input - Keygen input
+ * @returns {Promise} Ceremony ID
+ */
+ async startKeygen(input: StartKeygenInput): Promise {
+ const operatorFlags = Object.entries(input.operators).map(([id, url]) => `--operator ${id}=${url}`).join(' ')
+ const thresholdFlag = `--threshold ${Object.keys(input.operators).length - 1}`
+ const withdrawalCredentialsFlag = `--withdrawal-credentials ${'01' + '0'.repeat(22) + input.withdrawalAddress.split('0x')[1]}`
+ const forkVersionFlag = '--fork-version prater'
+ const command = `${this.cliPath} keygen ${operatorFlags} ${thresholdFlag} ${withdrawalCredentialsFlag} ${forkVersionFlag}`
+ const request = await run(`${command}`) as string
+ return request.trim().split(' ').pop() as string
+ }
+
/**
* Start a reshare request
* @param {StartReshareInput} input - Operator IDs, public key, and old operator IDs
- * @param {number} retries - Number of retries
* @returns {Promise} Ceremony ID
*/
- async startReshare(input: StartReshareInput, retries: number | undefined = 25): Promise {
- try {
- const operatorFlags = Object.entries(input.operators).map(([id, url]) => `--operator ${id}=${url}`).join(' ')
- const thresholdFlag = `--threshold ${Object.keys(input.operators).length - 1}`
- const publicKeyFlag = `--validator-public-key ${input.publicKey}`
- const oldOperatorFlags = Object.entries(input.oldOperators).map(([id, url]) => `--old-operator ${id}=${url}`).join(' ')
- const command = `${this.cliPath} reshare ${operatorFlags} ${thresholdFlag} ${publicKeyFlag} ${oldOperatorFlags}`
- const request = await runRetry(`${command}`) as string
- return request.trim().split(' ').pop() as string
- } catch (error) {
- if (retries === 0) {
- throw error
- }
- await new Promise(resolve => setTimeout(resolve, 2500))
- console.log(`Retrying reshare request ${retries} more times`)
- return await this.startReshare(input, retries - 1)
- }
+ async startReshare(input: StartReshareInput): Promise {
+ const operatorFlags = Object.entries(input.operators).map(([id, url]) => `--operator ${id}=${url}`).join(' ')
+ const thresholdFlag = `--threshold ${Object.keys(input.operators).length - 1}`
+ const publicKeyFlag = `--validator-pk ${input.publicKey.split('0x')[1]}`
+ const oldOperatorFlags = Object.entries(input.oldOperators).map(([id, url]) => `--old-operator ${id}=${url}`).join(' ')
+ const command = `${this.cliPath} resharing ${operatorFlags} ${thresholdFlag} ${publicKeyFlag} ${oldOperatorFlags}`
+ const request = await runRetry(`${command}`) as string
+ return request.trim().split(' ').pop() as string
}
/**
@@ -160,26 +152,17 @@ export class Dkg {
* @param {GetSharesInput} input - Request ID, operator IDs, owner address, and owner nonce
* @returns {Promise} Combined shares
*/
- async getShares(input: GetSharesInput, retries: number | undefined = 25): Promise {
- try {
- const requestIdFlag = `--request-id ${input.requestId}`
- const operatorFlags = Object.entries(input.operators).map(([id, url]) => `--operator ${id}=${url}`).join(' ')
- const ownerAddressFlag = `--owner-address ${input.ownerAddress}`
- const ownerNonceFlag = `--owner-nonce ${input.ownerNonce}`
- const command = `${this.cliPath} get-keyshares ${requestIdFlag} ${operatorFlags} ${ownerAddressFlag} ${ownerNonceFlag}`
- const download = await runRetry(`${command}`) as string
- const file = download.trim().split(' ').pop() as string
- const json = JSON.parse(fs.readFileSync(`${file}`, 'utf8'))
- fs.rmSync(file)
- return json.payload.readable.shares
- } catch (error) {
- if (retries === 0) {
- throw error
- }
- await new Promise(resolve => setTimeout(resolve, 2500))
- console.log(`Retrying get shares request ${retries} more times`)
- return await this.getShares(input, retries - 1)
- }
+ async getShares(input: GetSharesInput): Promise {
+ const requestIdFlag = `--request-id ${input.requestId}`
+ const operatorFlags = Object.entries(input.operators).map(([id, url]) => `--operator ${id}=${url}`).join(' ')
+ const ownerAddressFlag = `--owner-address ${input.ownerAddress}`
+ const ownerNonceFlag = `--owner-nonce ${input.ownerNonce}`
+ const command = `${this.cliPath} get-keyshares ${requestIdFlag} ${operatorFlags} ${ownerAddressFlag} ${ownerNonceFlag}`
+ const download = await runRetry(`${command}`) as string
+ const file = download.trim().split(' ').pop() as string
+ const json = JSON.parse(fs.readFileSync(`${file}`, 'utf8'))
+ fs.rmSync(file)
+ return json.payload.readable.shares
}
/**
@@ -187,35 +170,26 @@ export class Dkg {
* @param {GetDepositDataInput} input - Ceremony ID and withdrawal address
* @returns {Promise} Deposit data
*/
- async getDepositData(input: GetDepositDataInput, retries: number | undefined = 25): Promise {
- try {
- const requestIdFlag = `--request-id ${input.requestId}`
- const withdrawalCredentialsFlag = `--withdrawal-credentials 01${'0'.repeat(22)}${input.withdrawalAddress.split('0x')[1]}`
- const forkVersionFlag = '--fork-version prater'
- const command = `${this.cliPath} generate-deposit-data ${requestIdFlag} ${withdrawalCredentialsFlag} ${forkVersionFlag}`
- const download = await runRetry(`${command}`) as string
- const file = download.trim().split(' ').pop() as string
- const jsonArray = JSON.parse(fs.readFileSync(file, 'utf8'))
- fs.rmSync(file)
- const {
- deposit_data_root: depositDataRoot,
- pubkey: publicKey,
- signature,
- withdrawal_credentials: withdrawalCredentials
- } = jsonArray[0]
- return {
- depositDataRoot: `0x${depositDataRoot}`,
- publicKey: `0x${publicKey}`,
- signature: `0x${signature}`,
- withdrawalCredentials: `0x${withdrawalCredentials}`
- }
- } catch (error) {
- if (retries === 0) {
- throw error
- }
- await new Promise(resolve => setTimeout(resolve, 2500))
- console.log(`Retrying get deposit data request ${retries} more times`)
- return await this.getDepositData(input, retries - 1)
+ async getDepositData(input: GetDepositDataInput): Promise {
+ const requestIdFlag = `--request-id ${input.requestId}`
+ const withdrawalCredentialsFlag = `--withdrawal-credentials 01${'0'.repeat(22)}${input.withdrawalAddress.split('0x')[1]}`
+ const forkVersionFlag = '--fork-version prater'
+ const command = `${this.cliPath} generate-deposit-data ${requestIdFlag} ${withdrawalCredentialsFlag} ${forkVersionFlag}`
+ const download = await runRetry(`${command}`) as string
+ const file = download.trim().split(' ').pop() as string
+ const jsonArray = JSON.parse(fs.readFileSync(file, 'utf8'))
+ fs.rmSync(file)
+ const {
+ deposit_data_root: depositDataRoot,
+ pubkey: publicKey,
+ signature,
+ withdrawal_credentials: withdrawalCredentials
+ } = jsonArray[0]
+ return {
+ depositDataRoot: `0x${depositDataRoot}`,
+ publicKey: `0x${publicKey}`,
+ signature: `0x${signature}`,
+ withdrawalCredentials: `0x${withdrawalCredentials}`
}
}
}
diff --git a/services/oracle/src/providers/events.ts b/services/oracle/src/providers/events.ts
deleted file mode 100644
index 32cd48abe..000000000
--- a/services/oracle/src/providers/events.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { ethers } from 'ethers'
-import { CasimirManager } from '@casimir/ethereum/build/@types'
-import ICasimirManagerAbi from '@casimir/ethereum/build/abi/ICasimirManager.json'
-import { GetEventsIterableInput } from '../interfaces/GetEventsIterableInput'
-
-export function getEventsIterable(input: GetEventsIterableInput) {
- const events = input.events
- let provider: ethers.providers.JsonRpcProvider
- if (input.provider) {
- provider = input.provider
- } else {
- provider = new ethers.providers.JsonRpcProvider(input.ethereumUrl)
- }
- const manager = new ethers.Contract(input.managerAddress, ICasimirManagerAbi, provider) as ethers.Contract & CasimirManager
-
- return (async function*() {
- for (const event of events) {
- const queue: any[][] = []
- const listener = (...args: any[]) => queue.push(args)
- manager.on(event, listener)
- while (true) {
- if (queue.length === 0) {
- await new Promise(resolve => {
- const waitListener = () => {
- manager.off(event, waitListener)
- resolve()
- }
- manager.on(event, waitListener)
- })
- } else {
- yield queue.shift()
- }
- }
- }
- })()
-}
\ No newline at end of file
diff --git a/services/oracle/src/providers/handlers.ts b/services/oracle/src/providers/handlers.ts
index ef83356f9..1a71d82a8 100644
--- a/services/oracle/src/providers/handlers.ts
+++ b/services/oracle/src/providers/handlers.ts
@@ -1,9 +1,8 @@
import { ethers } from 'ethers'
-import { HandlerInput } from '../interfaces/HandlerInput'
import { CasimirManager, CasimirRegistry, CasimirViews, IFunctionsBillingRegistry, IAutomationRegistry } from '@casimir/ethereum/build/@types'
-import ICasimirManagerAbi from '@casimir/ethereum/build/abi/ICasimirManager.json'
-import ICasimirViewsAbi from '@casimir/ethereum/build/abi/ICasimirViews.json'
-import ICasimirRegistryAbi from '@casimir/ethereum/build/abi/ICasimirRegistry.json'
+import CasimirManagerAbi from '@casimir/ethereum/build/abi/CasimirManager.json'
+import CasimirViewsAbi from '@casimir/ethereum/build/abi/CasimirViews.json'
+import CasimirRegistryAbi from '@casimir/ethereum/build/abi/CasimirRegistry.json'
import IFunctionsBillingRegistryAbi from '@casimir/ethereum/build/abi/IFunctionsBillingRegistry.json'
import IAutomationRegistryAbi from '@casimir/ethereum/build/abi/IAutomationRegistry.json'
import { Scanner } from '@casimir/ssv'
@@ -13,6 +12,7 @@ import { getConfig } from './config'
import { Dkg } from './dkg'
const config = getConfig()
+
const cli = new Dkg({
cliPath: config.cliPath,
messengerUrl: config.messengerUrl
@@ -21,7 +21,7 @@ const cli = new Dkg({
export async function depositFunctionsBalanceHandler() {
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
const signer = config.wallet.connect(provider)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, signer) as ethers.Contract & CasimirManager
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, signer) as ethers.Contract & CasimirManager
const functionsBillingRegistry = new ethers.Contract(config.functionsBillingRegistryAddress, IFunctionsBillingRegistryAbi, provider) as ethers.Contract & IFunctionsBillingRegistry
const minimumBalance = 0.2
@@ -35,7 +35,6 @@ export async function depositFunctionsBalanceHandler() {
return part.slice(0, 1)
}).join('.'))
}
- console.log('🤖 Functions balance', balance)
if (balance < minimumBalance) {
const uniswapFactory = new Factory({
@@ -64,21 +63,20 @@ export async function depositFunctionsBalanceHandler() {
export async function depositUpkeepBalanceHandler() {
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
const signer = config.wallet.connect(provider)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, signer) as ethers.Contract & CasimirManager
- const linkRegistry = new ethers.Contract(config.linkRegistryAddress, IAutomationRegistryAbi, provider) as ethers.Contract & IAutomationRegistry
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, signer) as ethers.Contract & CasimirManager
+ const keeperRegistry = new ethers.Contract(config.keeperRegistryAddress, IAutomationRegistryAbi, provider) as ethers.Contract & IAutomationRegistry
const minimumBalance = 0.2
const refundBalance = 5
const upkeepId = await manager.upkeepId()
let balance = 0
if (upkeepId.gt(0)) {
- const subscription = await linkRegistry.getUpkeep(upkeepId)
+ const subscription = await keeperRegistry.getUpkeep(upkeepId)
balance = Number(ethers.utils.formatEther(subscription.balance).split('.').map((part, index) => {
if (index === 0) return part
return part.slice(0, 1)
}).join('.'))
}
- console.log('🤖 Upkeep balance', balance)
if (balance < minimumBalance) {
const uniswapFactory = new Factory({
@@ -104,14 +102,15 @@ export async function depositUpkeepBalanceHandler() {
}
}
-export async function initiateDepositHandler(input: HandlerInput) {
- if (!input.args.poolId) throw new Error('No pool id provided')
+export async function initiateDepositHandler(input: ethers.utils.Result) {
+ const { poolId } = input
+ if (!poolId) throw new Error('No pool id provided')
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
const signer = config.wallet.connect(provider)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, signer) as ethers.Contract & CasimirManager
- const views = new ethers.Contract(config.viewsAddress, ICasimirViewsAbi, provider) as ethers.Contract & CasimirViews
- const registry = new ethers.Contract(config.registryAddress, ICasimirRegistryAbi, provider) as ethers.Contract & CasimirRegistry
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, signer) as ethers.Contract & CasimirManager
+ const views = new ethers.Contract(config.viewsAddress, CasimirViewsAbi, provider) as ethers.Contract & CasimirViews
+ const registry = new ethers.Contract(config.registryAddress, CasimirRegistryAbi, provider) as ethers.Contract & CasimirRegistry
const managerNonce = await provider.getTransactionCount(manager.address)
const poolAddress = ethers.utils.getContractAddress({
@@ -141,7 +140,7 @@ export async function initiateDepositHandler(input: HandlerInput) {
const scanner = new Scanner({
ethereumUrl: config.ethereumUrl,
ssvNetworkAddress: config.ssvNetworkAddress,
- ssvNetworkViewsAddress: config.ssvNetworkViewsAddress
+ ssvViewsAddress: config.ssvViewsAddress
})
const cluster = await scanner.getCluster({
@@ -154,7 +153,7 @@ export async function initiateDepositHandler(input: HandlerInput) {
const requiredFee = await scanner.getRequiredFee(selectedOperatorIds)
const validator = await cli.createValidator({
- poolId: input.args.poolId,
+ poolId,
operatorIds: selectedOperatorIds,
ownerAddress: manager.address,
ownerNonce,
@@ -199,14 +198,15 @@ export async function initiateDepositHandler(input: HandlerInput) {
await initiateDeposit.wait()
}
-export async function initiateResharesHandler(input: HandlerInput) {
- if (!input.args.operatorId) throw new Error('No operator id provided')
+export async function reportResharesHandler(input: ethers.utils.Result) {
+ const { operatorId } = input
+ if (!operatorId) throw new Error('No operator id provided')
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
const signer = config.wallet.connect(provider)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, signer) as ethers.Contract & CasimirManager
- const views = new ethers.Contract(config.viewsAddress, ICasimirViewsAbi, provider) as ethers.Contract & CasimirViews
- const registry = new ethers.Contract(config.registryAddress, ICasimirRegistryAbi, provider) as ethers.Contract & CasimirRegistry
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, signer) as ethers.Contract & CasimirManager
+ const views = new ethers.Contract(config.viewsAddress, CasimirViewsAbi, provider) as ethers.Contract & CasimirViews
+ const registry = new ethers.Contract(config.registryAddress, CasimirRegistryAbi, provider) as ethers.Contract & CasimirRegistry
const poolIds = [
...await manager.getPendingPoolIds(),
@@ -214,9 +214,9 @@ export async function initiateResharesHandler(input: HandlerInput) {
]
for (const poolId of poolIds) {
- const poolDetails = await views.getPoolDetails(poolId)
+ const poolDetails = await views.getPool(poolId)
const oldOperatorIds = poolDetails.operatorIds.map(id => id.toNumber())
- if (oldOperatorIds.includes(input.args.operatorId)) {
+ if (oldOperatorIds.includes(operatorId)) {
const poolAddress = await manager.getPoolAddress(poolId)
const operatorCount = (await registry.getOperatorIds()).length
@@ -237,16 +237,16 @@ export async function initiateResharesHandler(input: HandlerInput) {
const newOperatorId = smallestOperators.find((operator) => !oldOperatorIds.includes(operator.id.toNumber()))?.id.toNumber()
- if (newOperatorId && poolDetails.reshares.toNumber() > 1) {
- const newOperatorIds = oldOperatorIds.map((operatorId) => {
- if (operatorId === input.args.operatorId) return newOperatorId
- return operatorId
+ if (newOperatorId && poolDetails.reshares.toNumber() < 2) {
+ const operatorIds = oldOperatorIds.map((id) => {
+ if (id === operatorId) return newOperatorId
+ return id
})
const scanner = new Scanner({
ethereumUrl: config.ethereumUrl,
ssvNetworkAddress: config.ssvNetworkAddress,
- ssvNetworkViewsAddress: config.ssvNetworkViewsAddress
+ ssvViewsAddress: config.ssvViewsAddress
})
const oldCluster = await scanner.getCluster({
@@ -255,29 +255,24 @@ export async function initiateResharesHandler(input: HandlerInput) {
})
const cluster = await scanner.getCluster({
- operatorIds: newOperatorIds,
+ operatorIds,
ownerAddress: manager.address
})
const ownerNonce = await scanner.getNonce(manager.address)
- const requiredFee = await scanner.getRequiredFee(newOperatorIds)
+ const requiredFee = await scanner.getRequiredFee(operatorIds)
- const validator = await cli.reshareValidator({
+ const reshare = await cli.reshareValidator({
publicKey: poolDetails.publicKey,
poolId,
oldOperatorIds,
- operatorIds: newOperatorIds,
+ operatorIds,
ownerAddress: manager.address,
ownerNonce,
withdrawalAddress: poolAddress
})
- const {
- operatorIds,
- shares
- } = validator
-
const uniswapFactory = new Factory({
ethereumUrl: config.ethereumUrl,
uniswapV3FactoryAddress: config.uniswapV3FactoryAddress
@@ -297,8 +292,8 @@ export async function initiateResharesHandler(input: HandlerInput) {
operatorIds,
oldOperatorIds,
newOperatorId,
- input.args.operatorId,
- shares,
+ operatorId,
+ reshare.shares,
cluster,
oldCluster,
feeAmount,
@@ -313,33 +308,35 @@ export async function initiateResharesHandler(input: HandlerInput) {
}
}
-export async function initiateExitsHandler(input: HandlerInput) {
- if (!input.args.poolId) throw new Error('No pool id provided')
+export async function initiateExitsHandler(input: ethers.utils.Result) {
+ const { poolId } = input
+ if (!poolId) throw new Error('No pool id provided')
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, provider) as ethers.Contract & CasimirManager
- const views = new ethers.Contract(config.viewsAddress, ICasimirViewsAbi, provider) as ethers.Contract & CasimirViews
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, provider) as ethers.Contract & CasimirManager
+ const views = new ethers.Contract(config.viewsAddress, CasimirViewsAbi, provider) as ethers.Contract & CasimirViews
// Get pool to exit
- const poolDetails = await views.getPoolDetails(input.args.poolId)
+ const poolDetails = await views.getPool(poolId)
// Get operators to sign exit
}
-export async function reportForcedExitsHandler(input: HandlerInput) {
- if (!input.args.count) throw new Error('No count provided')
+export async function reportForcedExitsHandler(input: ethers.utils.Result) {
+ const { count } = input
+ if (!count) throw new Error('No count provided')
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
const signer = config.wallet.connect(provider)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, signer) as ethers.Contract & CasimirManager
- const views = new ethers.Contract(config.viewsAddress, ICasimirViewsAbi, provider) as ethers.Contract & CasimirViews
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, signer) as ethers.Contract & CasimirManager
+ const views = new ethers.Contract(config.viewsAddress, CasimirViewsAbi, provider) as ethers.Contract & CasimirViews
const stakedPoolIds = await manager.getStakedPoolIds()
let poolIndex = 0
- let remaining = input.args.count
+ let remaining = count
while (remaining > 0) {
const poolId = stakedPoolIds[poolIndex]
- const poolDetails = await views.getPoolDetails(poolId)
+ const poolDetails = await views.getPool(poolId)
if (poolDetails.status === PoolStatus.ACTIVE) {
remaining--
const reportForcedExit = await manager.reportForcedExit(
@@ -351,13 +348,14 @@ export async function reportForcedExitsHandler(input: HandlerInput) {
}
}
-export async function reportCompletedExitsHandler(input: HandlerInput) {
- if (!input.args.count) throw new Error('No count provided')
+export async function reportCompletedExitsHandler(input: ethers.utils.Result) {
+ const { count } = input
+ if (!count) throw new Error('No count provided')
const provider = new ethers.providers.JsonRpcProvider(config.ethereumUrl)
const signer = config.wallet.connect(provider)
- const manager = new ethers.Contract(config.managerAddress, ICasimirManagerAbi, signer) as ethers.Contract & CasimirManager
- const views = new ethers.Contract(config.viewsAddress, ICasimirViewsAbi, provider) as ethers.Contract & CasimirViews
+ const manager = new ethers.Contract(config.managerAddress, CasimirManagerAbi, signer) as ethers.Contract & CasimirManager
+ const views = new ethers.Contract(config.viewsAddress, CasimirViewsAbi, provider) as ethers.Contract & CasimirViews
/**
* In production, we get the completed exit order from the Beacon API (sorting by withdrawn epoch)
@@ -366,11 +364,11 @@ export async function reportCompletedExitsHandler(input: HandlerInput) {
* Here, we're just grabbing the next exiting pool for each completed exit
*/
const stakedPoolIds = await manager.getStakedPoolIds()
- let remaining = input.args.count
+ let remaining = count
let poolIndex = 0
while (remaining > 0) {
const poolId = stakedPoolIds[poolIndex]
- const poolDetails = await views.getPoolDetails(poolId)
+ const poolDetails = await views.getPool(poolId)
if (poolDetails.status === PoolStatus.EXITING_FORCED || poolDetails.status === PoolStatus.EXITING_REQUESTED) {
remaining--
@@ -389,7 +387,7 @@ export async function reportCompletedExitsHandler(input: HandlerInput) {
const scanner = new Scanner({
ethereumUrl: config.ethereumUrl,
ssvNetworkAddress: config.ssvNetworkAddress,
- ssvNetworkViewsAddress: config.ssvNetworkViewsAddress
+ ssvViewsAddress: config.ssvViewsAddress
})
const cluster = await scanner.getCluster({
diff --git a/services/users/scripts/clean.ts b/services/users/scripts/clean.ts
index 9d3d34efe..ce20544b1 100644
--- a/services/users/scripts/clean.ts
+++ b/services/users/scripts/clean.ts
@@ -1,4 +1,4 @@
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
/**
* Clean up users resources
diff --git a/services/users/scripts/db.ts b/services/users/scripts/db.ts
index 4a6c85e7a..30d500a04 100644
--- a/services/users/scripts/db.ts
+++ b/services/users/scripts/db.ts
@@ -1,6 +1,6 @@
import fs from 'fs'
import os from 'os'
-import { run } from '@casimir/helpers'
+import { run } from '@casimir/shell'
import { getSecret, loadCredentials } from '@casimir/aws'
import { JsonSchema, Schema, accountSchema, nonceSchema, operatorSchema, userSchema, userAccountSchema } from '@casimir/data'
diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts
index 4852acbf6..45a430c9a 100644
--- a/services/users/src/providers/db.ts
+++ b/services/users/src/providers/db.ts
@@ -1,5 +1,5 @@
import { Postgres } from './postgres'
-import { camelCase } from '@casimir/helpers'
+import { camelCase } from '@casimir/format'
import { Account, OperatorAddedSuccess, RemoveAccountOptions, User, UserAddedSuccess, UserWithAccountsAndOperators } from '@casimir/types'
import useEthers from './ethers'