diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index ff3fd038c..6a6c51f63 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -11,7 +11,7 @@ jobs: # Skip any pushes from the act CLI # Comment out for testing - if: ${{ github.actor != "nektos/act" }} + if: ${{ github.actor != 'nektos/act' }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 57882d047..bf62ea8ec 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -32,7 +32,7 @@ jobs: aws-region: ${{ env.AWS_REGION }} - name: Install and build all package dependencies - run: npm ci + run: npm ci --omit=optional - name: Test cdk deployment run: npm run test:cdk \ No newline at end of file diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 581886f0e..c61cf9b7d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -15,7 +15,7 @@ jobs: # Skip any pushes with commit flag "(skip deploy)" # Comment out for testing - if: ${{ !contains(github.event.head_commit.message, "(skip deploy)") }} + if: ${{ !contains(github.event.head_commit.message, '(skip deploy)') }} steps: - name: Checkout the repo with submodules @@ -40,7 +40,7 @@ jobs: curl -sSf https://atlasgo.sh | sh - name: Install and build all package dependencies - run: npm ci + run: npm ci --omit=optional - name: Deploy cdk infrastructure run: npm run deploy:cdk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 17c9b8359..c52cddc50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,7 @@ jobs: # curl -sSf https://atlasgo.sh | sh - name: Install and build all package dependencies - run: npm ci + run: npm ci --omit=optional - name: Deploy CDK infrastructure run: npm run deploy:cdk diff --git a/.github/workflows/sandbox.yml b/.github/workflows/sandbox.yml index 9c8c19c24..230e4ec11 100644 --- a/.github/workflows/sandbox.yml +++ b/.github/workflows/sandbox.yml @@ -18,7 +18,7 @@ jobs: # Skip any pushes with commit flag "(skip deploy)" # Comment out for testing - if: ${{ !contains(github.event.head_commit.message, "(skip deploy)") }} + if: ${{ !contains(github.event.head_commit.message, '(skip deploy)') }} steps: - name: Checkout the repo with submodules @@ -43,7 +43,7 @@ jobs: curl -sSf https://atlasgo.sh | sh - name: Install and build all package dependencies - run: npm ci + run: npm ci --omit=optional env: PUBLIC_STAGE: ${{ env.STAGE }} diff --git a/.gitignore b/.gitignore index a3534697a..e56a3be5b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ cdk-outputs.json services/crawler/.env -.out \ No newline at end of file +.out +dist +build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 43db9b3e7..73fd8aaa9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = services/oracle/lib/dkg url = https://github.com/consensusnetworks/ssv-dkg.git branch = update/makefile +[submodule "contracts/ethereum/lib/eigenlayer-contracts"] + path = contracts/ethereum/lib/eigenlayer-contracts + url = https://github.com/Layr-Labs/eigenlayer-contracts.git diff --git a/.vscode/settings.json b/.vscode/settings.json index dd8391181..ddb47ce1d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,5 +19,10 @@ "[json]": { "editor.defaultFormatter": "vscode.json-language-features" }, - "volar.inlayHints.eventArgumentInInlineHandlers": false + "volar.inlayHints.eventArgumentInInlineHandlers": false, + "deno.enable": true, + "deno.enablePaths": [ + "./services/functions/request/scripts", + "./services/functions/request/src" + ] } \ No newline at end of file diff --git a/README.md b/README.md index d82d5cdf6..68248c76a 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,9 @@ Configure the following prerequisite global dependency versions: > 🚩 **Using NVM**: Install [NVM](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating) and run `nvm install --lts && nvm alias default lts/*` to set the default version to the latest LTS. You will need to rerun this command whenever the latest LTS changes. -5. [AWS CLI (v2.x)](https://aws.amazon.com/cli). +5. [Deno (v1.39.x)](https://docs.deno.com/runtime/manual/getting_started/installation). + +6. [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`. diff --git a/apps/app/package.json b/apps/app/package.json index 7154ebdd8..50e3869f9 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -9,14 +9,14 @@ "preview": "vite preview" }, "dependencies": { - "vue": "^3.3.8" + "vue": "^3.3.13" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^4.5.2", "rollup-plugin-polyfill-node": "^0.13.0", - "typescript": "^5.2.2", - "vite": "^5.0.0", - "vue-tsc": "^1.8.22" + "typescript": "^5.3.3", + "vite": "^5.0.10", + "vue-tsc": "^1.8.25" } } diff --git a/apps/docs/.vitepress/config.mts b/apps/docs/.vitepress/config.mts index 562659828..3c66b8327 100644 --- a/apps/docs/.vitepress/config.mts +++ b/apps/docs/.vitepress/config.mts @@ -25,7 +25,7 @@ export default withMermaid({ items: [ { text: 'What is Casimir?', link: '/introduction/what-is-casimir' }, { text: 'Architecture', link: '/introduction/architecture' }, - { text: 'Staking Strategies', link: '/introduction/staking-strategies' }, + { text: 'Stake Configs', link: '/introduction/stake-configs' }, { text: 'User Accounts', link: '/introduction/user-accounts' } ] }, diff --git a/apps/docs/package.json b/apps/docs/package.json index 59089cdf6..f83a6bbde 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -9,7 +9,7 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { - "@types/node": "^17.0.38", + "@types/node": "^20.10.5", "dotenv": "^16.3.1", "esno": "0.17.0", "markdown-it-mathjax3": "^4.3.2", diff --git a/apps/docs/src/guide/staking.md b/apps/docs/src/guide/staking.md index b0213202f..815e4d362 100644 --- a/apps/docs/src/guide/staking.md +++ b/apps/docs/src/guide/staking.md @@ -17,20 +17,15 @@ Let: - $F_t$ be the total fee percentage, which is a sum of the required ETH, LINK, and SSV fees. - $D$ be the amount of ETH deposited by the user. - $E$ be the amount of ETH to be allocated for the contract's operations. -- $F_a$ be the ETH amount to be swapped for LINK and SSV to facilitate the contract's functions. Given the 5% fee, the ETH to be allocated for the contract's operations is calculated as: $E = D \times \frac{100}{100 + F_t}$ -The amount to be converted to LINK and SSV is: -$F_a = D - E$ - Where: - $F_t$ typically equals 5%. - $D$ is the amount of ETH the user wants to deposit. - $E$ represents the actual ETH amount that will be added to the contract after deducting the fee. -- $F_a$ is the remaining ETH that will be used to acquire LINK and SSV. ## Stake Balances @@ -57,4 +52,26 @@ Where: ## Stake Withdrawals -You can request a withdrawal of any amount of your stake at any time. If the requested amount is available in the manager's withdrawable balance (prepooled balance plus withdrawn balance), the withdrawal is fulfilled immediately. Otherwise, the withdrawal is added to the pending withdrawals queue and fulfilled when the requested amount is available (usually within 1-4 days, depending on the amount). \ No newline at end of file +You can request a withdrawal of any amount of your stake at any time. If the requested amount is available in the manager's withdrawable balance (prepooled balance plus withdrawn balance), the withdrawal is fulfilled immediately. Otherwise, the withdrawal is added to the pending withdrawals queue and fulfilled when the requested amount is available (usually within 1-4 days, depending on the amount). + +## Stake Events + +When your stake balance changes, the manager contract emits: + +- A [stake deposited](#stake-deposited) event when you deposit ETH to the manager contract. +- A [stake rebalanced](#stake-rebalanced) event when your stake balance is updated due to a change in the total reward-to-stake ratio sum after a new report. +- A [withdrawal requested](#withdrawal-requested) event when you request a withdrawal of your stake. + +### Stake Deposited + +The `StakeDeposited` event is emitted when you deposit ETH to the manager contract. + +```solidity +event StakeDeposited(address sender, uint256 amount) +``` + +The event's parameters are: + +- `sender`: Address of the staker who deposited ETH. +- `amount`: Amount of ETH deposited after fees. + diff --git a/apps/docs/src/introduction/stake-configs.md b/apps/docs/src/introduction/stake-configs.md new file mode 100644 index 000000000..d97e45340 --- /dev/null +++ b/apps/docs/src/introduction/stake-configs.md @@ -0,0 +1,7 @@ +::: warning +This page is incomplete. +::: + +# Stake Configs + +The simple stake config provides secure and reliable native ETH rewards from an open registry of performant SSV operators. Casimir will deploy additonal stake configs with different registry requirements and opt-in features for stakers and operators. Our simple restake config will allow stakers and operators to participate in creating and managing native EigenLayer pods with less (or more) than 32 ETH. \ No newline at end of file diff --git a/apps/docs/src/introduction/staking-strategies.md b/apps/docs/src/introduction/staking-strategies.md deleted file mode 100644 index 3ba8a6b08..000000000 --- a/apps/docs/src/introduction/staking-strategies.md +++ /dev/null @@ -1,11 +0,0 @@ -::: warning -This page is incomplete. -::: - -# Staking Strategies - -The base Casimir staking strategy provides a default configuration for secure and reliable native ETH rewards. Casimir also provides opt-in features by offering alternative staking strategies for stakers and operators to choose when depositing stake or collateral, respectively. The first of these opt-in features is EigenLayer restaking, which allows stakers and operators to participate in creating and managing native EigenPods with less (or more) than 32 ETH. - -## Base Strategy - -## EigenLayer Strategy \ No newline at end of file diff --git a/apps/mvp/package.json b/apps/mvp/package.json index 602b27e98..ab2f440c2 100644 --- a/apps/mvp/package.json +++ b/apps/mvp/package.json @@ -19,24 +19,23 @@ "d3": "^7.8.1", "ethers": "^5.7.2", "feather-icons": "^4.29.0", - "sass": "^1.69.1", + "sass": "^1.69.5", "supertokens-web-js": "^0.5.0", "util": "^0.12.5", - "vue": "^3.2.25", + "vue": "^3.3.13", "vue-feather": "^2.0.0", - "vue-router": "^4.0.15", - "web3": "^1.8.1", - "xlsx": "^0.18.5" + "vue-router": "^4.2.5", + "web3": "^4.3.0" }, "devDependencies": { - "@rollup/plugin-node-resolve": "^15.1.0", - "@vitejs/plugin-vue": "^4.2.3", - "autoprefixer": "^10.4.14", - "postcss": "^8.4.27", - "rollup-plugin-polyfill-node": "^0.12.0", - "tailwindcss": "^3.3.3", - "typescript": "^5.1.6", - "vite": "^4.4.7", - "vue-tsc": "^1.8.7" + "@rollup/plugin-node-resolve": "^15.2.3", + "@vitejs/plugin-vue": "^4.5.2", + "autoprefixer": "^10.4.16", + "postcss": "^8.4.32", + "rollup-plugin-polyfill-node": "^0.13.0", + "tailwindcss": "^3.4.0", + "typescript": "^5.3.3", + "vite": "^5.0.10", + "vue-tsc": "^1.8.25" } } diff --git a/apps/mvp/src/composables/breakdownMetrics.ts b/apps/mvp/src/composables/breakdownMetrics.ts index 93b91ccdb..25f9bf544 100644 --- a/apps/mvp/src/composables/breakdownMetrics.ts +++ b/apps/mvp/src/composables/breakdownMetrics.ts @@ -104,7 +104,7 @@ export default function useBreakdownMetrics() { const addresses = (user.value as UserWithAccountsAndOperators).accounts.map((account: Account) => account.address) as string[] const currentUserStakePromises = [] as Array> addresses.forEach(address => currentUserStakePromises.push((baseManager as CasimirManager).getUserStake(address))) - addresses.forEach(address => currentUserStakePromises.push((eigenManager as CasimirManager).getUserStake(address))) + // addresses.forEach(address => currentUserStakePromises.push((eigenManager as CasimirManager).getUserStake(address))) const settledCurrentUserStakePromises = await Promise.allSettled(currentUserStakePromises) as Array> const currentUserStake = settledCurrentUserStakePromises.filter(result => result.status === "fulfilled").map(result => result.value) const currentUserStakeSum = currentUserStake.reduce((acc, curr) => acc.add(curr), ethers.BigNumber.from(0)) @@ -113,33 +113,28 @@ export default function useBreakdownMetrics() { /* Get User's All Time Deposits and Withdrawals */ const userEventTotalsPromises = [] as Array> addresses.forEach(address => {userEventTotalsPromises.push(getContractEventsTotalsByAddress(address, baseManager))}) - addresses.forEach(address => {userEventTotalsPromises.push(getContractEventsTotalsByAddress(address, eigenManager))}) + // addresses.forEach(address => {userEventTotalsPromises.push(getContractEventsTotalsByAddress(address, eigenManager))}) const userEventTotals = await Promise.all(userEventTotalsPromises) as Array const userEventTotalsSum = userEventTotals.reduce((acc, curr) => { - const { StakeDeposited, WithdrawalInitiated, WithdrawalRequested, WithdrawalFulfilled } = curr + const { StakeDeposited/*, WithdrawalRequested*/, WithdrawalFulfilled } = curr return { StakeDeposited: acc.StakeDeposited + (StakeDeposited || 0), - WithdrawalInitiated: acc.WithdrawalInitiated + (WithdrawalInitiated || 0), - WithdrawalRequested: acc.WithdrawalRequested + (WithdrawalRequested || 0), + // WithdrawalRequested: acc.WithdrawalRequested + (WithdrawalRequested || 0), WithdrawalFulfilled: acc.WithdrawalFulfilled + (WithdrawalFulfilled || 0) } }, { - StakeDeposited: 0, - WithdrawalInitiated: 0, - WithdrawalRequested: 0, + StakeDeposited: 0, + // WithdrawalRequested: 0, WithdrawalFulfilled: 0 - } as { StakeDeposited: number; WithdrawalInitiated: number, WithdrawalRequested: number, WithdrawalFulfilled: number }) - + } as { StakeDeposited: number/*, WithdrawalRequested: number*/, WithdrawalFulfilled: number }) const stakedDepositedETH = userEventTotalsSum.StakeDeposited - const withdrawalInitiatedETH = userEventTotalsSum.WithdrawalInitiated - const withdrawalRequestedETH = userEventTotalsSum.WithdrawalRequested + // const withdrawalRequestedETH = userEventTotalsSum.WithdrawalRequested const withdrawalFulfilledETH = userEventTotalsSum.WithdrawalFulfilled - /* Get User's All Time Rewards */ - const currentUserStakeMinusEvents = - currentUserStakeETH - stakedDepositedETH + ((withdrawalInitiatedETH) + (withdrawalRequestedETH) + (withdrawalFulfilledETH)) + const currentUserStakeMinusEvents = currentUserStakeETH - (stakedDepositedETH - withdrawalFulfilledETH) + return { eth: `${formatEthersCasimir(currentUserStakeMinusEvents)} ETH`, usd: `$${formatEthersCasimir(currentUserStakeMinusEvents * (await getCurrentPrice({ coin: "ETH", currency: "USD" })))}` @@ -158,8 +153,7 @@ export default function useBreakdownMetrics() { const eventList = [ "StakeDeposited", "StakeRebalanced", - "WithdrawalInitiated", - "WithdrawalRequested", + // "WithdrawalRequested", "WithdrawalFulfilled" ] const eventFilters = eventList.map(event => { @@ -190,8 +184,7 @@ export default function useBreakdownMetrics() { return { StakeDeposited: 0, StakeRebalanced: 0, - WithdrawalInitiated: 0, - WithdrawalRequested: 0, + // WithdrawalRequested: 0, WithdrawalFulfilled: 0 } } @@ -222,7 +215,7 @@ export default function useBreakdownMetrics() { } catch (error) { console.log("Error occurred while fetching stake:", error) return { - eth: "0ETH", + eth: "0 ETH", usd: "$0.00" } } @@ -281,9 +274,11 @@ export default function useBreakdownMetrics() { listeningForContractEvents.value = true try { (baseManager as CasimirManager).on("StakeDeposited", stakeDepositedListener); - (baseManager as CasimirManager).on("WithdrawalInitiated", withdrawalInitiatedListener); + (baseManager as CasimirManager).on("StakeRebalanced", stakeRebalancedListener); + (baseManager as CasimirManager).on("WithdrawalFulfilled", withdrawalFulfilledListener); (eigenManager as CasimirManager).on("StakeDeposited", stakeDepositedListener); - (eigenManager as CasimirManager).on("WithdrawalInitiated", withdrawalInitiatedListener) + (eigenManager as CasimirManager).on("StakeRebalanced", stakeRebalancedListener); + (eigenManager as CasimirManager).on("WithdrawalFulfilled", withdrawalFulfilledListener) } catch (err) { console.log(`There was an error in listenForStakeWithdrawEvents: ${err}`) } @@ -305,15 +300,15 @@ export default function useBreakdownMetrics() { if (!breakdownMetricsComposableInitialized.value) return (baseManager as CasimirManager).removeListener("StakeDeposited", stakeDepositedListener); (baseManager as CasimirManager).removeListener("StakeRebalanced", stakeRebalancedListener); - (baseManager as CasimirManager).removeListener("WithdrawalInitiated", withdrawalInitiatedListener); + (baseManager as CasimirManager).removeListener("WithdrawalFulfilled", withdrawalFulfilledListener); (eigenManager as CasimirManager).removeListener("StakeDeposited", stakeDepositedListener); (eigenManager as CasimirManager).removeListener("StakeRebalanced", stakeRebalancedListener); - (eigenManager as CasimirManager).removeListener("WithdrawalInitiated", withdrawalInitiatedListener) + (eigenManager as CasimirManager).removeListener("WithdrawalFulfilled", withdrawalFulfilledListener) } const stakeDepositedListener = async () => await refreshBreakdown() const stakeRebalancedListener = async () => await refreshBreakdown() - const withdrawalInitiatedListener = async () => await refreshBreakdown() + const withdrawalFulfilledListener = async () => await refreshBreakdown() return { currentStaked: readonly(currentStaked), diff --git a/apps/mvp/src/composables/files.ts b/apps/mvp/src/composables/files.ts deleted file mode 100644 index 7f65df9c6..000000000 --- a/apps/mvp/src/composables/files.ts +++ /dev/null @@ -1,69 +0,0 @@ -import * as XLSX from "xlsx" - -export default function useFiles() { - function exportFile(checkedItems: any, filteredData: any) { - const jsonData = checkedItems.value.length > 0 ? checkedItems.value : filteredData.value - - const isMac = navigator.userAgent.indexOf("Mac") !== -1 - const fileExtension = isMac ? "csv" : "xlsx" - - if (fileExtension === "csv") { - const csvContent = convertJsonToCsv(jsonData) - downloadFile(csvContent, "operator_performance.csv", "text/csv") - } else { - const excelBuffer = convertJsonToExcelBuffer(jsonData) - downloadFile(excelBuffer, "operator_performance.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") - } - } - - return { - exportFile - } -} - -function downloadFile (content: any, filename: string, mimeType: any) { - const blob = new Blob([content], { type: mimeType }) - const url = URL.createObjectURL(blob) - const link = document.createElement("a") - link.href = url - link.download = filename - link.click() - - // Cleanup - URL.revokeObjectURL(url) -} - -function convertJsonToExcelBuffer (jsonData: unknown[]) { - const worksheet = XLSX.utils.json_to_sheet(jsonData) - const workbook = XLSX.utils.book_new() - XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1") - const excelBuffer = XLSX.write(workbook, { type: "array", bookType: "xlsx" }) - - return excelBuffer -} - -function convertJsonToCsv (jsonData: any[]) { - const separator = "," - const csvRows = [] - - if (!Array.isArray(jsonData)) { - return "" - } - - if (jsonData.length === 0) { - return "" - } - - const keys = Object.keys(jsonData[0]) - - // Add headers - csvRows.push(keys.join(separator)) - - // Convert JSON data to CSV rows - jsonData.forEach(obj => { - const values = keys.map(key => obj[key]) - csvRows.push(values.join(separator)) - }) - - return csvRows.join("\n") -} \ No newline at end of file diff --git a/apps/mvp/src/mockData/mock_transaction_data.ts b/apps/mvp/src/mockData/mock_transaction_data.ts index cc1f252c8..2d179d6fb 100644 --- a/apps/mvp/src/mockData/mock_transaction_data.ts +++ b/apps/mvp/src/mockData/mock_transaction_data.ts @@ -18,7 +18,7 @@ export default function useTxData () { } function generateRandomDate() { - // Generate a random date within the last two years + // Generate a random date within the last two years const startDate = new Date() startDate.setFullYear(startDate.getFullYear() - 2) const endDate = new Date() diff --git a/apps/mvp/src/pages/operators/Operator.vue b/apps/mvp/src/pages/operators/Operator.vue index 4d807d0bf..48e3538db 100644 --- a/apps/mvp/src/pages/operators/Operator.vue +++ b/apps/mvp/src/pages/operators/Operator.vue @@ -70,10 +70,10 @@ const selectedHeader = ref("walletProvider") const selectedOrientation = ref("ascending") const operatorTableHeaders = ref( [ - // { - // title: '', - // value: 'blank_column' - // }, + // { + // title: '', + // value: 'blank_column' + // }, { title: "Operator ID", value: "id" @@ -94,14 +94,14 @@ const operatorTableHeaders = ref( title: "Node URL", value: "nodeURL" }, - // { - // title: '', - // value: 'deactivate' - // }, - // { - // title: '', - // value: 'withdraw_collateral' - // }, + // { + // title: '', + // value: 'deactivate' + // }, + // { + // title: '', + // value: 'withdraw_collateral' + // }, ] ) diff --git a/apps/mvp/src/pages/overview/components/BreakdownTable.vue b/apps/mvp/src/pages/overview/components/BreakdownTable.vue index af05c3167..f7fbd068f 100644 --- a/apps/mvp/src/pages/overview/components/BreakdownTable.vue +++ b/apps/mvp/src/pages/overview/components/BreakdownTable.vue @@ -1,6 +1,5 @@