From 787508af2f67410b4bcee7a824ed40c38de4acf6 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Fri, 14 Jul 2023 13:09:37 -0400 Subject: [PATCH] Reset analytics data and stop listening to blocks on logout --- apps/web/src/composables/ethers.ts | 42 +++++----- apps/web/src/composables/users.ts | 80 ++++++++++--------- apps/web/src/composables/wallet.ts | 12 +-- .../overview/components/BreakdownChart.vue | 7 +- .../src/pages/overview/components/Staking.vue | 15 +++- common/types/src/index.ts | 2 + .../types/src/interfaces/UserAnalyticsData.ts | 18 +++++ services/oracle/keyshares-1689345097.json | 1 + services/oracle/keyshares-1689347414.json | 1 + 9 files changed, 113 insertions(+), 65 deletions(-) create mode 100644 common/types/src/interfaces/UserAnalyticsData.ts create mode 100644 services/oracle/keyshares-1689345097.json create mode 100644 services/oracle/keyshares-1689347414.json diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index e83f363cd..4a45742d1 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -14,6 +14,7 @@ declare const window: ethereumWindow const { createSiweMessage, signInWithEthereum } = useAuth() const { ethereumUrl } = useEnvironment() +const provider = new ethers.providers.JsonRpcProvider(ethereumUrl) export default function useEthers() { const ethersProviderList = ['BraveWallet', 'CoinbaseWallet', 'MetaMask', 'OkxWallet', 'TrustWallet'] @@ -30,6 +31,23 @@ export default function useEthers() { } } + async function blockListener (blockNumber: number) { + const { manager, refreshBreakdown } = useContracts() + const { user } = useUsers() + console.log('blockNumber :>> ', blockNumber) + const addresses = (user.value as UserWithAccounts).accounts.map((account: Account) => account.address) as string[] + const block = await provider.getBlockWithTransactions(blockNumber) + const transactions = block.transactions + transactions.map(async (tx) => { + if (addresses.includes(tx.from.toLowerCase())) { + console.log('tx :>> ', tx) + const response = manager.interface.parseTransaction({ data: tx.data }) + console.log('response :>> ', response) + await refreshBreakdown() + } + }) + } + /** * Estimate gas fee using EIP 1559 methodology * @returns string in ETH @@ -112,7 +130,6 @@ export default function useEthers() { } async function getEthersBalance(address: string) : Promise { - const provider = new ethers.providers.JsonRpcProvider(ethereumUrl) const balance = await provider.getBalance(address) return parseFloat(ethers.utils.formatEther(balance)) } @@ -152,23 +169,7 @@ export default function useEthers() { } async function listenForTransactions() { - const { manager, refreshBreakdown } = useContracts() - const { user } = useUsers() - const provider = new ethers.providers.JsonRpcProvider(ethereumUrl) - provider.on('block', async (blockNumber: number) => { - console.log('blockNumber :>> ', blockNumber) - const addresses = (user.value as UserWithAccounts).accounts.map((account: Account) => account.address) as string[] - const block = await provider.getBlockWithTransactions(blockNumber) - const transactions = block.transactions - transactions.map(async (tx) => { - if (addresses.includes(tx.from.toLowerCase())) { - console.log('tx :>> ', tx) - const response = manager.interface.parseTransaction({ data: tx.data }) - console.log('response :>> ', response) - await refreshBreakdown() - } - }) - }) + provider.on('block', blockListener as ethers.providers.Listener) await new Promise(() => { // Wait indefinitely using a Promise that never resolves }) @@ -232,6 +233,10 @@ export default function useEthers() { return signature } + function stopListeningForTransactions() { + provider.off('block', blockListener as ethers.providers.Listener) + } + async function switchEthersNetwork (providerString: ProviderString, chainId: string) { const provider = getBrowserProvider(providerString) const currentChainId = await provider.networkVersion @@ -275,6 +280,7 @@ export default function useEthers() { requestEthersAccount, sendEthersTransaction, signEthersMessage, + stopListeningForTransactions, switchEthersNetwork } } diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index dfa0e8956..dcd8f9ffc 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -1,18 +1,14 @@ import { ref, readonly } from 'vue' -import { Account, AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, ApiResponse } from '@casimir/types' +import { Account, AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, ApiResponse, UserAnalyticsData } from '@casimir/types' import useEnvironment from '@/composables/environment' import useEthers from './ethers' import * as Session from 'supertokens-web-js/recipe/session' import useTxData from '../mockData/mock_transaction_data' const { txData } = useTxData() - const { usersUrl } = useEnvironment() -// 0xd557a5745d4560B24D36A68b52351ffF9c86A212 -const session = ref(false) -const user = ref(null) -const userAnalytics = ref({ +const userAnalyticsInit = { oneMonth: { labels: [], data: [] @@ -29,7 +25,12 @@ const userAnalytics = ref({ labels: [], data: [] } -}) +} + +// 0xd557a5745d4560B24D36A68b52351ffF9c86A212 +const session = ref(false) +const user = ref(undefined) +const userAnalytics = ref(userAnalyticsInit) const rawUserAnalytics = ref(null) const userAddresses = ref>([]) @@ -119,8 +120,8 @@ export default function useUsers() { } } - function setUserAnalytics() { - const result = userAnalytics.value + function computeUserAnalytics() { + // const result = userAnalytics.value const sortedTransactions = rawUserAnalytics.value.sort((a: any, b: any) => { new Date(a.receivedAt).getTime() - new Date(b.receivedAt).getTime() }) @@ -140,58 +141,58 @@ export default function useUsers() { sortedTransactions.forEach((tx: any) => { const { receivedAt, walletAddress, walletBalance } = tx /* Historical */ - if (!result.historical.data.find((obj: any) => obj.walletAddress === walletAddress)) { - result.historical.data.push({ walletAddress, walletBalance: Array(12).fill(0) }) + if (!userAnalytics.value.historical.data.find((obj: any) => obj.walletAddress === walletAddress)) { + userAnalytics.value.historical.data.push({ walletAddress, walletBalance: Array(12).fill(0) }) // Determine which interval the receivedAt falls into const intervalIndex = Math.floor((new Date(receivedAt).getTime() - earliest) / historicalInterval) // Set the value of the intervalIndex to the walletBalance - result.historical.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.historical.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } else { // Determine which interval the receivedAt falls into const intervalIndex = Math.floor((new Date(receivedAt).getTime() - earliest) / historicalInterval) // Set the value of the intervalIndex to the walletBalance - result.historical.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.historical.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } /* One Year */ if (new Date(receivedAt).getTime() > oneYear) { - if (!result.oneYear.data.find((obj: any) => obj.walletAddress === walletAddress)) { - result.oneYear.data.push({ walletAddress, walletBalance: Array(12).fill(0) }) + if (!userAnalytics.value.oneYear.data.find((obj: any) => obj.walletAddress === walletAddress)) { + userAnalytics.value.oneYear.data.push({ walletAddress, walletBalance: Array(12).fill(0) }) const monthsAgo = (new Date().getFullYear() - new Date(receivedAt).getFullYear()) * 12 + (new Date().getMonth() - new Date(receivedAt).getMonth()) const intervalIndex = 11 - monthsAgo - result.oneYear.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.oneYear.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } else { const monthsAgo = (new Date().getFullYear() - new Date(receivedAt).getFullYear()) * 12 + (new Date().getMonth() - new Date(receivedAt).getMonth()) const intervalIndex = 11 - monthsAgo - result.oneYear.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.oneYear.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } } /* Six Months */ if (new Date(receivedAt).getTime() > sixMonths) { - if (!result.sixMonth.data.find((obj: any) => obj.walletAddress === walletAddress)) { - result.sixMonth.data.push({ walletAddress, walletBalance: Array(6).fill(0) }) + if (!userAnalytics.value.sixMonth.data.find((obj: any) => obj.walletAddress === walletAddress)) { + userAnalytics.value.sixMonth.data.push({ walletAddress, walletBalance: Array(6).fill(0) }) const monthsAgo = (new Date().getFullYear() - new Date(receivedAt).getFullYear()) * 12 + (new Date().getMonth() - new Date(receivedAt).getMonth()) const intervalIndex = 5 - monthsAgo - result.sixMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.sixMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } else { const monthsAgo = (new Date().getFullYear() - new Date(receivedAt).getFullYear()) * 12 + (new Date().getMonth() - new Date(receivedAt).getMonth()) const intervalIndex = 5 - monthsAgo - result.sixMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.sixMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } } /* One Month */ if (new Date(receivedAt).getTime() > oneMonth) { - if (!result.oneMonth.data.find((obj: any) => obj.walletAddress === walletAddress)) { - result.oneMonth.data.push({ walletAddress, walletBalance: Array(30).fill(0) }) + if (!userAnalytics.value.oneMonth.data.find((obj: any) => obj.walletAddress === walletAddress)) { + userAnalytics.value.oneMonth.data.push({ walletAddress, walletBalance: Array(30).fill(0) }) const daysAgo = Math.floor((new Date().getTime() - new Date(receivedAt).getTime()) / 86400000) const intervalIndex = 29 - daysAgo - result.oneMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.oneMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } else { const daysAgo = Math.floor((new Date().getTime() - new Date(receivedAt).getTime()) / 86400000) const intervalIndex = 29 - daysAgo - result.oneMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance + userAnalytics.value.oneMonth.data.find((obj: any) => obj.walletAddress === walletAddress).walletBalance[intervalIndex] = walletBalance } } }) @@ -200,7 +201,7 @@ export default function useUsers() { // Set the historical labels array to the interval labels let previousMonth: any = null - result.historical.labels = Array(12).fill(0).map((_, i) => { + userAnalytics.value.historical.labels = Array(12).fill(0).map((_, i) => { const date = new Date(earliest + (historicalInterval * i)) const currentMonth = date.getMonth() if (!previousMonth) { @@ -216,26 +217,26 @@ export default function useUsers() { }) // Set the oneYear labels array to the interval labels - result.oneYear.labels = Array(12).fill(0).map((_, i) => { + userAnalytics.value.oneYear.labels = Array(12).fill(0).map((_, i) => { const date = new Date (new Date().setDate(1)) const monthIndex = new Date(date.setMonth(date.getMonth() - (11 - i))) return `${months[monthIndex.getMonth()]} ${monthIndex.getFullYear()}` }) // Set the sixMonth labels array to the interval labels - result.sixMonth.labels = Array(6).fill(0).map((_, i) => { + userAnalytics.value.sixMonth.labels = Array(6).fill(0).map((_, i) => { const date = new Date (new Date().setDate(1)) const monthIndex = new Date(date.setMonth(date.getMonth() - (5 - i))) return `${months[monthIndex.getMonth()]} ${monthIndex.getFullYear()}` }) // Set the oneMonth labels array to the interval labels - result.oneMonth.labels = [] + userAnalytics.value.oneMonth.labels = [] for (let i = 30; i > 0; i--) { const date = new Date().getTime() - ((i - 1) * 86400000) - result.oneMonth.labels.push(`${new Date(date).getMonth() + 1}/${new Date(date).getDate()}`) + userAnalytics.value.oneMonth.labels.push(`${new Date(date).getMonth() + 1}/${new Date(date).getDate()}`) } - userAnalytics.value = result + // userAnalytics.value = result } async function getUserAnalytics() { @@ -250,11 +251,9 @@ export default function useUsers() { const { error, message, data } = await response.json() if (error) throw new Error(message) - // TODO: Swap this when the API / data is ready - // rawUserAnalytics.value = data - rawUserAnalytics.value = txData.value - - setUserAnalytics() + // TODO: Pass data from above when the API / data is ready + setRawAnalytics(txData.value) + computeUserAnalytics() return { error, message, data } } catch (error: any) { throw new Error(error.message || 'Error getting user analytics') @@ -314,6 +313,14 @@ export default function useUsers() { userAddresses.value = newUser?.accounts.map(account => account.address) as Array } + function setUserAnalytics(data: UserAnalyticsData = userAnalyticsInit) { + userAnalytics.value = data + } + + function setRawAnalytics(data: UserAnalyticsData = userAnalyticsInit) { + rawUserAnalytics.value = data + } + async function setUserAccountBalances() { try { if (user?.value?.accounts) { @@ -372,6 +379,7 @@ export default function useUsers() { removeAccount, setUser, setUserAccountBalances, + setUserAnalytics, updatePrimaryAddress, updateUserAgreement } diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 3af25b1d4..0538199b4 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -37,11 +37,11 @@ const toAddress = ref('0x728474D29c2F81eb17a669a7582A2C17f1042b57') export default function useWallet() { const { listenForContractEvents, refreshBreakdown } = useContracts() - const { estimateEIP1559GasFee, ethersProviderList, getEthersAddressWithBalance, getEthersBalance, sendEthersTransaction, signEthersMessage, listenForTransactions, loginWithEthers, getEthersBrowserProviderSelectedCurrency, switchEthersNetwork } = useEthers() + const { estimateEIP1559GasFee, ethersProviderList, getEthersAddressWithBalance, getEthersBalance, sendEthersTransaction, signEthersMessage, listenForTransactions, loginWithEthers, getEthersBrowserProviderSelectedCurrency, stopListeningForTransactions, switchEthersNetwork } = useEthers() const { getLedgerAddress, loginWithLedger, sendLedgerTransaction, signLedgerMessage } = useLedger() // const { solanaProviderList, sendSolanaTransaction, signSolanaMessage } = useSolana() const { getTrezorAddress, loginWithTrezor, sendTrezorTransaction, signTrezorMessage } = useTrezor() - const { addAccount, getUser, checkIfSecondaryAddress, checkIfPrimaryUserExists, removeAccount, setUser, setUserAccountBalances, updatePrimaryAddress, user } = useUsers() + const { addAccount, getUser, checkIfSecondaryAddress, checkIfPrimaryUserExists, removeAccount, setUser, setUserAnalytics, setUserAccountBalances, updatePrimaryAddress, user } = useUsers() const { getWalletConnectAddress, loginWithWalletConnect, sendWalletConnectTransaction, signWalletConnectMessage } = useWalletConnect() function getColdStorageAddress(provider: ProviderString, currency: Currency = 'ETH') { @@ -173,17 +173,17 @@ export default function useWallet() { } async function logout() { - console.log('clicked log out') loadingUserWallets.value = true await Session.signOut() + stopListeningForTransactions() + setUser(undefined) setSelectedAddress('') setSelectedProvider('') setSelectedCurrency('') - setUser(undefined) setPrimaryAddress('') - loadingUserWallets.value = false + setUserAnalytics() + // loadingUserWallets.value = false console.log('user.value :>> ', user.value) - // router.push('/auth') } async function removeConnectedAccount() { diff --git a/apps/web/src/pages/overview/components/BreakdownChart.vue b/apps/web/src/pages/overview/components/BreakdownChart.vue index 452c64bbf..acd0e73a8 100644 --- a/apps/web/src/pages/overview/components/BreakdownChart.vue +++ b/apps/web/src/pages/overview/components/BreakdownChart.vue @@ -7,7 +7,7 @@ import useUsers from '@/composables/users' import { ProviderString } from '@casimir/types' const { currentStaked, refreshBreakdown, stakingRewards, totalWalletBalance } = useContracts() -const { user, getUserAnalytics, userAnalytics } = useUsers() +const { user, getUserAnalytics, setUserAnalytics, userAnalytics } = useUsers() const chardId = ref('cross_provider_chart') const selectedTimeframe = ref('historical') @@ -54,6 +54,7 @@ const formatLegendLabel = (address: string) => { } const setChartData = () => { + console.log('setting chart data in BreakdownChart.vue') let labels let data = [] switch (selectedTimeframe.value) { @@ -101,6 +102,8 @@ onMounted(async () => { await getUserAnalytics() setChartData() await refreshBreakdown() + } else { + setUserAnalytics() } }) @@ -108,6 +111,8 @@ watch(user, async () => { if (user.value?.id) { await getUserAnalytics() setChartData() + } else { + setUserAnalytics() } }) diff --git a/apps/web/src/pages/overview/components/Staking.vue b/apps/web/src/pages/overview/components/Staking.vue index d39bf4a32..5183fd991 100644 --- a/apps/web/src/pages/overview/components/Staking.vue +++ b/apps/web/src/pages/overview/components/Staking.vue @@ -140,10 +140,17 @@ watch(formattedAmountToStake, async () => { }) watch(user, async () => { - aggregateAddressesByProvider() - termsOfServiceCheckbox.value = user.value?.agreedToTermsOfService as boolean - address_balance.value = (Math.round( await getEthersBalance(user.value?.address as string) * 100) / 100 ) + ' ETH' - selectedWallet.value = user.value?.address as string + if (user.value?.id) { + aggregateAddressesByProvider() + termsOfServiceCheckbox.value = user.value?.agreedToTermsOfService as boolean + address_balance.value = (Math.round( await getEthersBalance(user.value?.address as string) * 100) / 100 ) + ' ETH' + selectedWallet.value = user.value?.address as string + } else { + selectedProvider.value = '' + selectedWallet.value = null + formattedAmountToStake.value = '' + address_balance.value = null + } }) onMounted(async () => { diff --git a/common/types/src/index.ts b/common/types/src/index.ts index 6841997cd..b739fc617 100644 --- a/common/types/src/index.ts +++ b/common/types/src/index.ts @@ -28,6 +28,7 @@ import { RemoveAccountOptions } from './interfaces/RemoveAccountOptions' import { User } from './interfaces/User' import { UserAddedSuccess } from './interfaces/UserAddedSuccess' import { UserWithAccounts } from './interfaces/UserWithAccounts' +import { UserAnalyticsData } from './interfaces/UserAnalyticsData' import { Validator } from './interfaces/Validator' export type { @@ -60,6 +61,7 @@ export type { RemoveAccountOptions, User, UserAddedSuccess, + UserAnalyticsData, UserWithAccounts, Validator, } diff --git a/common/types/src/interfaces/UserAnalyticsData.ts b/common/types/src/interfaces/UserAnalyticsData.ts new file mode 100644 index 000000000..d4d34674c --- /dev/null +++ b/common/types/src/interfaces/UserAnalyticsData.ts @@ -0,0 +1,18 @@ +export interface UserAnalyticsData { + oneMonth: { + labels: string[]; + data: number[]; + } + sixMonth: { + labels: string[] + data: number[] + } + oneYear: { + labels: string[] + data: number[] + } + historical: { + labels: string[] + data: number[] + } +} \ No newline at end of file diff --git a/services/oracle/keyshares-1689345097.json b/services/oracle/keyshares-1689345097.json new file mode 100644 index 000000000..2ffa5011c --- /dev/null +++ b/services/oracle/keyshares-1689345097.json @@ -0,0 +1 @@ +{"version":"v3","data":{"publicKey":"0xa720bbf37b9dc26eab1071895b1acfa05f3c617a88a337904714625f424d89ce2bd6f92a833d9fa686c7a84c22ec1a26","operators":[{"id":1,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVg2MUFXY001QUNLaGN5MTlUaEIKby9HMWlhN1ByOVUralJ5aWY5ZjAyRG9sd091V2ZLLzdSVUlhOEhEbHBvQlVERDkwRTVQUGdJSy9sTXB4RytXbwpwQ2N5bTBpWk9UT0JzNDE5bEh3TzA4bXFja1JsZEg5WExmbmY2UThqWFR5Ym1yYzdWNmwyNVprcTl4U0owbHR1CndmTnVTSzNCZnFtNkQxOUY0aTVCbmVaSWhjRVJTYlFLWDFxbWNqYnZFL2cyQko4TzhaZUgrd0RzTHJiNnZXQVIKY3BYWG1uelE3Vlp6ZklHTGVLVU1CTTh6SW0rcXI4RGZ4SEhSeVU1QTE3cFU4cy9MNUp5RXE1RGJjc2Q2dHlnbQp5UE9BYUNzWldVREI3UGhLOHpUWU9WYi9MM1lnSTU4bjFXek5IM0s5cmFreUppTmUxTE9GVVZzQTFDUnhtQ2YzCmlRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},{"id":2,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeUtVWTVEUmZZREljengzcjhVY0UKTlpFMFdIQXFuV2FIRjZYRlUydVdObjVOVE94Zkt4ZmZaLzkyeVE1citQVkJPRmQrcHhILzI2QXJVT3dNL1lBRQpRbDZ0VzBtc1FqdUtIU1Q4aUtvTDRTNUt0aDNoeTBqeFRHR1ZZaWdjWG1vRURjd2YxaG8wdWRxRmlEN3dFWXN1CmZHa2E2U1ZQNnBab1NMaU9HZFRKUWVzVDI5WEVCdDZnblhMaFB1MER2K0xsQUJJQ1pqWEFTZWtpSFVKUHRjYlgKRjZFL0lScGpkWHVNSmUyOXZDcmZudXhWWk93a1ptdzJXdGljYlNDOVJpSFRYWUQ1dnVGakZXRHNZMERHUDhzOAoyc1haVHdsNWl4dEhlUWM2N1lLRFN6YU1MNnY1VUVZblhUTzZzNHFVSWVnTXJwZjd3S0xGVWxqRTMwbnNIaVBUCjBRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},{"id":3,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNWVUNUwwV0h6ZTdyTWZPb2xtVHMKdWtIQ2E4K3dtbUw2OTFJQ1RpREE1UkJ1TkxqSVQ2WkE0YzMxcVRIY3FBVHl5eVkwLzk3R3lKZ2doYnlFR2RoZQovalh6aWVTOXJ2RytJVGF1QjhMVlhkekxGYVQxWEZWeFlnN2x2TlB4OURPL1ZoRkhkWWxnT3I2d0RtV3FjRGo3ClhWUWFOWEFtRng3NjVQNTlXNXZzVGRXVWFHRWxXSm93SkZKdnc2UlRISkZ1TVhjSzZVaWJ0cUZMSmJwOW5kdUgKQjlLSzNWcmYrZmtJOWRBZ2txRDFHOElxQ0tKMVl3bjUyeGxxbTRCNitOOGZUZE1MS1JucWpFZmRzV1dwMFVzMQpLTW9vSXcyc3BoaXAzUFpNYnJaaU0wNjJ2ZUo0U3ovYjBObWdPTnhTd0JJTnNxcG54QjhFUVQxSTNjNklqNXhhCm5RSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},{"id":4,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdXZleUpUMURwM21mQ3FRTUora2YKZHdhV0d1bkRURUFaWmNTOHdtUTJBcjU1bE5venl5cHRwb1lGSTgxaW1RSmpwdVV0akR2am15RDRQSmt1SzFXRQovZG9TSzFraWlTSEYvZFBaeE5ZT2swMlRiTGIvTXBjMG12VE1nZmRsVDBoTlVOWDZIMnJzZzNlc2NEOStENEdDCmxtZGpCdmdxUDQydXdDbFlQUVhuN3Z6OWlOOEpXdEFtd1JkQ25USkZ6M2tYSEFPVGMyMjJGYXp4ZGJVNEVPYkIKVmJNejd2UXRmMWtNSGtacEh5UXNpL3F0WmhQaThtTlNQTWpMTDBtcmc4Ly9xVjIyeEVPNENmSHFKZkZOWEhKVwpEbU85M2h2QXE2dDFZOGN5UVZkSGZ2WEp5VzRxR29MY25HZzV1S2ZSYWVCSSt1aXFSeExOL2dtTnA2RzdpZVNkCkl3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"}],"shares":{"publicKeys":["0xa153c6e12c646d10c65cd6614608e16fa7ec77ef7e8d019db5e3b3aea55672d7394c3aa902f27ad314e1a8a8f212505d","0x995c7c8185b4ebb920e71cdb9160d05acb2137b80c90e4b8850c091ece769648cc865f846878342353d474c54f474b76","0x95f4bbdc88adce53a2a3f350f5d3b9477f5e4986823123af0aa1868b68cfc8743fc5b482969bdd2c854d77f3e0362851","0x9226b7a84925215adcdf0965262dcd035203bf5eebf7bdcfdab9c2dfb47f48e22c040afa75327916a40bfed12154b759"],"encryptedKeys":["8e4ccb98bedf2c5cbb1844f079878bf29f16938296484e2e97a559a63a374484f11b894a4b2ed251663d2ac78f54de4108a3b525dab27fbd75a437503d5399e6b7bf655cb8360d49c01910c8a602832ac395cdc4b7c9820fe88e0f775a6c56f9d67fcad4787f395ee6c2464a8326faaddb832a7b4160d2110ff6cd410e12db13bdb47352083dde9c7a821ae978591129dea464cbcb1f7497ad50400ef4d904bbea3176b5f3de9455984e5f34b3fecea8c1a540993c05c12a34fac67514702a74bb82b82e29434c731e519368415a18942bb1a041b4d79e99f946ffb938885d019efab140479de81932386a847d28d2919cd841b87a9f24b9061fe5cf49aca3cb","7120941e0c29a055c5cbf420d13112bbb063e7d8af9d4a581d53051ed86749a3008b239d53866ea720ad95c410be307b0b62a1c0dd98db5bb7d6df0b90dafb978c2f3dd38c804d030b7dfc99fe234b4fdaa99996ca9f1883142be5c141c68bfdc861a14c78274132c94bdecb3e0599dc5e018932a6af1b4bdd6ff23f6ea43fd8f44dfdab938996eb4e781316dec409d081b1eb4be6dfc960b05cbc4a794d68004c8e9fb03a4da4149298d052c7e27f4fc6318843fdc8e364425756c3f307311b5bf86ae2edb87f8436f8812731feb6fed7da6521469fe708631941865cf7e6e03cc7d91c55459baa5eaba2b74a5061a461887c7b46e8687fff5c4f593cf38e55","706c693e6bac22c83595be24f3b30e7558714c8ba82fe234d3deb73a6d5404779019c10cc529af121e0ab43a282b2793975dccd6eb8163138dbc97eb12f6de55fe1262a3ca6f948f6214a64d909e1672f180b4eae7bd1e567f924720db38d6bdbaa9989b5173d4c25a6fd845b3c1b2ce7d9e270379dadef10676920ed7804f77d23417e6cfeed64860b029367882b369a8a24ffba956face577219cbd660bcbea70b754ed03570f9b4a197b03c6d8affe57ae868c74027d4991ec9c5c9c6aa355c0f12b368e5db670cbc4248313c5931174e020dd37717a38cd0dcaef77aa58cc07a52f50058d8e54db51792d1d7440fb1975b75fb2fd9c60d28d05d31d86ee6","00199ca82ec747ad4a07fb27b8ff12fa127d8c80864f5c761768b5bee6ebbea83e4bff631c86bb71ef716b95e9ee0896b1af332a6ef0a491d3d8d30ef0339443a1401956b0012f7a23d1c52615662787a708115dc3666ba2a041f9354e609e7c32da186a7cbc3efc3bdef81198ab150110f4d46fcea6852eb8d2e28c53dbd555ec41120d286bc1c21446ca322deb789118f2da860ee9f79f2bf3320761a530ba87d9f1687633c58ef24f2c310ebd3b3a454d0ca0d54a2f949aa6f25587505055fcd32797942b1f71d5ea4fb898351246929310951b7ebe041cec2edadf0d1700161e410bf38e20ae33fea904e47bc699d31288cf752b5ae3a4be98b610910656"]}},"payload":{"readable":{"publicKey":"0xa720bbf37b9dc26eab1071895b1acfa05f3c617a88a337904714625f424d89ce2bd6f92a833d9fa686c7a84c22ec1a26","operatorIds":[1,2,3,4],"shares":"0x00c0a153c6e12c646d10c65cd6614608e16fa7ec77ef7e8d019db5e3b3aea55672d7394c3aa902f27ad314e1a8a8f212505d995c7c8185b4ebb920e71cdb9160d05acb2137b80c90e4b8850c091ece769648cc865f846878342353d474c54f474b7695f4bbdc88adce53a2a3f350f5d3b9477f5e4986823123af0aa1868b68cfc8743fc5b482969bdd2c854d77f3e03628519226b7a84925215adcdf0965262dcd035203bf5eebf7bdcfdab9c2dfb47f48e22c040afa75327916a40bfed12154b759f1ee1c71bf7c6de75fd9ce5c6dbd7ce387f4efdf3bf1b7f6f5fd7af77f36f7ae3ce1ed9ef7b6b9e7d6baddadfbe38f387f5d5bf3de1ae1bd9e776e75ebadddd9a73bf1fe7875ee35d3c6b76f9db975a6f6edf6ddef96b8dfbe74ddde77f7d7ba6fb6dfeb9e5c6fcdfad1de3d734d7dd7473c6bad36f37d9a737f7971d7386fb73df36d1f7bcf1ed1fefbe5ae9ce7a7fd77aedf71a778efcedfdfde5e7ba736e3ae1af37dba7da69d75bf37d9aedbe35eb4776d75d1f7fa71de35d1ed7675bd776dd6f8ef7e76d3cddd75ef5cedaf36d5a7bdefce7dd75dbd75e6b8eb871b71bd5fef8f7b69de74e34d1e7f877dd386db79adf5efa6f97f775ef78e79f7ce1ee5fdf86f77de71e6bc7356b9e34f7dddcd39735d9adf87da73aef9d78ef4d9aef86dbf366fcd9edbde37e1cef7d5ee75f77ebce35e5ad7cf78d9b6f56b4e356f877bf5ef7d7fde3a7df6fddfcf3ce5dd35f5e7da6f5e34e3bf5d7bcd7ddf6dfce9af38edddbc776f75f5c77ce356fcedaf5fdb86fdd3ad5f7b971fe3d69c6b771bef5db4f78d5ed1cdbd6b4e7973971b7f8db4775df5d766db6f4eb77bb77c69ff5de1ae7cd5de77d39d5e77cebbe3d6b7d34f1bdb7f5de77f3ae9e6bbdb469df79738d746dedf4edbd1beb66b573475df7c75be5b6fb77a75fd1bf7475a7dbf7bf1cd9fddd777f1cf34e1dd37d1bedd7dcf7d7dedb7e1be1f75a6bdf7df7a71af5fd7cf37d78d9b7b9735e3573af1b7dd73ceb56b5e1cefcdbbe35df673de1b75e71bdded39f7d75ce5ed35f3ddf66ba69fd5be1b75de9f7f6ddfe9e6b8ddf77c7f8e1d7dd69bf77f3df7a79be1eefcd77d7a75e738d3d774f356f579be1b7ba75f73deb46f4e5c6dce1aefde1debcd34e1cf1ef5f6f4ddae1d6b8d78f76f7c774e7673b7b6edfe1f73adf5f3ce377dd73c7b7eb8e36e7be7a7377f7d3bdf5d5be5b7fce9a7b679d6fcedff38dfa7fcf35dbbdf57de6fa7de77b75aeb9db5e3af5f7bbd3ceb7d7de35f3ae5c7fb7ba7b4ddc73b77dd5ce79e39f5b69ae5e69b6b66fbe1ae74eb56b8eb5f3cedcedbe3a7bcebcedf7dfe5ce1fe7dddc7f7f1ee79ef4e9cebdddee9b69cdb673cdf9f796dedb87f76f7d1eef9e7cef5e1cf1b6bcd9f7b6df877775e6fbddae9de78d38efbf74d7d735d1c739dbd69fd76d5ed1a6f8ddadbcd9bdbbf77f7be5d71c77a79bf35eb7d77f1d6dcf7b79bd767fa75ee797ded76eb66b771ae9ff78f1feb6d786bae1df74f5ed7aef67f5f346f879a7bb6ddd5ee7aedff76e3bdb475bdfc77a6dd6da6bdf7cf5be75ef7778736e5ae9f77ce396f77356f671eeddf5edbbd37efd75a75e7f5d3aefaf76d1e77bf34e1fefb776df8d7b7ba71f79e77ae3ceb46f4dbddfaefcf366f7ebd6bc6b6e1f7db6bde7a7da71ee7bef6d7d71b77aeb46dc6de6bbd1bef9e1e774df9ef47fd6f86b5f7b6f4ddce9df1a7df7b9eda7bcebc73be34dbb778f7dd5e73d73973d73a69adf9e5cd1fd766f7ebc7b975bebbd1c6dce36e3cdf5ddce7ddf5d7be1ed36d1d777efbd7b6b7f1c77475c69e7fbeda6b9f1c734edae767f9d34e7c77c7b9e1d6f9d7bf7677577be38d1f6f5f7be5bef97dbd9f77d73ad1ddbc774e5ddf577ce9e7bad34d7df5c6bcd9e73be3b69de1ad3b7dbdbb6fc7dfd767dad76eddf1cf34f3ae1fe5cefad7bebc6f96de7ba79b6de6bcddee1b7dfeb7d5cf3a6dbef579fef5e9bf797bd79ed3cf7a6f569fdf7d9ae9e7f46b8f7577777c777d1e7f4df7f78e376b5e34d7de7a6f4d35d9fedadb7775739dbad79ebadbbf3b6bbd3cd75e5d737ebae9b6b66b4e357fddf9e1eeb4f5eedcdf675ad7ce9aedc6dcdde7dcddb75e7fcd75f7c69bd79d35d747f8778e9f71e6baf39d9e6fc7767b6f1ce7775b779e7979ce35d76d1ddbce9b735736d78e3a71adf6d9d79befcf75d7c7f675af3ad1e7bd7fbf5fd9b7f7df6d3beb56b9df46daf3b77d7f5ebcefadf7739f1e7f6e1fd9cdf5d1e6ddddbddae39e1dd1c6b4779e1ad9ff78f5a6ba7f6e79f3be74e74e797dc777dbbf7bf78d9bd5fef577979ae1f6fcf7cdf9d76e3af76f77d74f79d5bede6ded38d5c79cd9e75a75fd1dd7bd34d7ad5ee35d1b7f7f1edb469edf77de6bdd387b8edb73af7d777d76f3c71fef9d9be5a7b76b86def7c6fad74f75d3ae7a","amount":"Amount of SSV tokens to be deposited to your validator's cluster balance (mandatory only for 1st validator in a cluster)","cluster":"The latest cluster snapshot data, obtained using the cluster-scanner tool. If this is the cluster's 1st validator then use - {0,0,0,0,0,false}"}},"createdAt":"2023-07-14T14:31:37.445622Z"} diff --git a/services/oracle/keyshares-1689347414.json b/services/oracle/keyshares-1689347414.json new file mode 100644 index 000000000..0d880205d --- /dev/null +++ b/services/oracle/keyshares-1689347414.json @@ -0,0 +1 @@ +{"version":"v3","data":{"publicKey":"0x95e4bb599d45322ad42f3ec77ae4b8aebec14abc09cc4fbf5e95f21ccd5a54d363a8fe6a3045bd574a13b8394cc9eddf","operators":[{"id":3,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNWVUNUwwV0h6ZTdyTWZPb2xtVHMKdWtIQ2E4K3dtbUw2OTFJQ1RpREE1UkJ1TkxqSVQ2WkE0YzMxcVRIY3FBVHl5eVkwLzk3R3lKZ2doYnlFR2RoZQovalh6aWVTOXJ2RytJVGF1QjhMVlhkekxGYVQxWEZWeFlnN2x2TlB4OURPL1ZoRkhkWWxnT3I2d0RtV3FjRGo3ClhWUWFOWEFtRng3NjVQNTlXNXZzVGRXVWFHRWxXSm93SkZKdnc2UlRISkZ1TVhjSzZVaWJ0cUZMSmJwOW5kdUgKQjlLSzNWcmYrZmtJOWRBZ2txRDFHOElxQ0tKMVl3bjUyeGxxbTRCNitOOGZUZE1MS1JucWpFZmRzV1dwMFVzMQpLTW9vSXcyc3BoaXAzUFpNYnJaaU0wNjJ2ZUo0U3ovYjBObWdPTnhTd0JJTnNxcG54QjhFUVQxSTNjNklqNXhhCm5RSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},{"id":4,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdXZleUpUMURwM21mQ3FRTUora2YKZHdhV0d1bkRURUFaWmNTOHdtUTJBcjU1bE5venl5cHRwb1lGSTgxaW1RSmpwdVV0akR2am15RDRQSmt1SzFXRQovZG9TSzFraWlTSEYvZFBaeE5ZT2swMlRiTGIvTXBjMG12VE1nZmRsVDBoTlVOWDZIMnJzZzNlc2NEOStENEdDCmxtZGpCdmdxUDQydXdDbFlQUVhuN3Z6OWlOOEpXdEFtd1JkQ25USkZ6M2tYSEFPVGMyMjJGYXp4ZGJVNEVPYkIKVmJNejd2UXRmMWtNSGtacEh5UXNpL3F0WmhQaThtTlNQTWpMTDBtcmc4Ly9xVjIyeEVPNENmSHFKZkZOWEhKVwpEbU85M2h2QXE2dDFZOGN5UVZkSGZ2WEp5VzRxR29MY25HZzV1S2ZSYWVCSSt1aXFSeExOL2dtTnA2RzdpZVNkCkl3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},{"id":1,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMVg2MUFXY001QUNLaGN5MTlUaEIKby9HMWlhN1ByOVUralJ5aWY5ZjAyRG9sd091V2ZLLzdSVUlhOEhEbHBvQlVERDkwRTVQUGdJSy9sTXB4RytXbwpwQ2N5bTBpWk9UT0JzNDE5bEh3TzA4bXFja1JsZEg5WExmbmY2UThqWFR5Ym1yYzdWNmwyNVprcTl4U0owbHR1CndmTnVTSzNCZnFtNkQxOUY0aTVCbmVaSWhjRVJTYlFLWDFxbWNqYnZFL2cyQko4TzhaZUgrd0RzTHJiNnZXQVIKY3BYWG1uelE3Vlp6ZklHTGVLVU1CTTh6SW0rcXI4RGZ4SEhSeVU1QTE3cFU4cy9MNUp5RXE1RGJjc2Q2dHlnbQp5UE9BYUNzWldVREI3UGhLOHpUWU9WYi9MM1lnSTU4bjFXek5IM0s5cmFreUppTmUxTE9GVVZzQTFDUnhtQ2YzCmlRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},{"id":2,"publicKey":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeUtVWTVEUmZZREljengzcjhVY0UKTlpFMFdIQXFuV2FIRjZYRlUydVdObjVOVE94Zkt4ZmZaLzkyeVE1citQVkJPRmQrcHhILzI2QXJVT3dNL1lBRQpRbDZ0VzBtc1FqdUtIU1Q4aUtvTDRTNUt0aDNoeTBqeFRHR1ZZaWdjWG1vRURjd2YxaG8wdWRxRmlEN3dFWXN1CmZHa2E2U1ZQNnBab1NMaU9HZFRKUWVzVDI5WEVCdDZnblhMaFB1MER2K0xsQUJJQ1pqWEFTZWtpSFVKUHRjYlgKRjZFL0lScGpkWHVNSmUyOXZDcmZudXhWWk93a1ptdzJXdGljYlNDOVJpSFRYWUQ1dnVGakZXRHNZMERHUDhzOAoyc1haVHdsNWl4dEhlUWM2N1lLRFN6YU1MNnY1VUVZblhUTzZzNHFVSWVnTXJwZjd3S0xGVWxqRTMwbnNIaVBUCjBRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"}],"shares":{"publicKeys":["0x8daeb029cd5c02e3de317df72ea375c96adb100e7091c9ec2266688c40c1aebaf3b4c3e50ba0a32f9b3bfb1e6a45c267","0x9714e38ebc269126e8d6ce1554c7bbe96ceb3044a8a4a26001c1c19b97aaec2c2e696273674c3bacb22fd195dd856859","0xa9293be0a78ba001a833300d4d5305baa1d9159679f6c9c79e0b9e852061a3d9c867d87d034f22e9f6d8158a25bdbb19","0x8a9983dbe21e5bbb8b6c96a72e4c7cba4562c18cb9c4abaff2ccd4c9ecc8808b095a4bd776bb33e66bf48e989618191d"],"encryptedKeys":["92830efbde96927dbdc7974828e5c912c1b94e90489a892b0c1a59721b897a3f77aa8d495396c743f1b83d9a190450730bc5b8c85380e185cab799beceaa8431085cd17dc5d0a52d45250e1990f993728b214b60b4600b5581c96bc0868b5a79b1fea4fba73bfb13e0cbb007f8db9e49de027669027169d53a7c0aaa071278533819c535652a5b26798f61f77000e9f18b5e7dfd6fc1d02984f8835e31c6a56f01a79ff1d0cc890ee246d0a3e3266f0d535cc6273a9d5feb7f73439a17db81735d59d3cc2201faf87294989c3fdcf9e48b366b3382efc7409445ad306bd24b3a7d58af4fa819c3c6326c48282f522f0f4c5af66eff004fadb0d9301f99caa4ba","447850bc913f78d18a8f32bbb3a62b954fd105bc1ac3663fabbc8ad0d57614e8957ff0be43731b79424149d6b9fe3130b91952b1625553cd1cbeb5a586bf0f541d1fdaa587c080ded5da4fbbe6bdb990e27f9b8e3178e21d5f3dfdeac5d308e9a0b4416dcd3514cb73eee1c45f62bbdc943fb36dddc8f7a1b9792ad553e30a4acacfba13fcc85a37f21c8274200d526a2987f992a592f9dc2f9b8380185fd7cb07928b92cefd6b19dc9f7d8fd4fd8ddc2d05033f3844bc0685914783cad359ca6d84a9d4fb0ce84e9a2cd117dc54303c20ba19644f8d1953d3ff0ae720f93ffb3349fa60ba19787acd66b19eda720ecd772567d63db778eeaa0f74ea3045c7d4","551605f0701e2b50d4afffbed1ff49d6f7ff85d58bc9cbedb26ba547fb8210522e7ce2f707d9b01de62adfe000bd3c1c7c44f55bd6c678638c50b1c8fbf045afa0b086c1ab797ab0794f3047e49d5e584055abed16b7d746c66cb5ce30d342ff68b05949715fb38c9b422b4320969d40f1e9cc1ed3e80bddbe02a749fb367bcb871edb81f15164490437591395f9dc3f149c3c6ac7e7f63d0cfa7220e77f0ce21071c5ee270110da38a00383ca7c0b6fc26d7fb9832277b6292c77095661ccad4ce2dbd1542ac590f8bcb72b1bedd972d76560943d8fe3bf550b9317840c5776c95531d2c7198e5a24fe3b4481bd5d22e0e862cb9c6c0826ac628d1349d2e1b7","31dfca1af4a0b6170c7636ac04bbe4be2a4475532bca2efa5d3b78be28a76a9357f40f357ddc294b1a842e188cab8b0820b4ec59e7c963102ef9405e7ba0396a4541c94e9321688dfea9562a9586895e391aa85cfe4abdd3dd39aa497c3e93f3ebae6d34eb8b117372e5f42bcf82436f6b189f9431770629469aa2b604dd1691f1cc3b59159f48c2f5df14279f4fc5592de59e379106ae991e06a8bcb183c3ab38a9a47d4fd1c358260c89effbeea6517a6bd7d0b1c48bbd5abdb1a315ef8811dd49ea5038c3ef9edb291d5fd756cdbd07ed254dd4587a91b3f79e19aeba0f0467115016a0daeeaca28676a18e205d33ee1221ee62cca11a250c5b72a2c5a51c"]}},"payload":{"readable":{"publicKey":"0x95e4bb599d45322ad42f3ec77ae4b8aebec14abc09cc4fbf5e95f21ccd5a54d363a8fe6a3045bd574a13b8394cc9eddf","operatorIds":[3,4,1,2],"shares":"0x00c08daeb029cd5c02e3de317df72ea375c96adb100e7091c9ec2266688c40c1aebaf3b4c3e50ba0a32f9b3bfb1e6a45c2679714e38ebc269126e8d6ce1554c7bbe96ceb3044a8a4a26001c1c19b97aaec2c2e696273674c3bacb22fd195dd856859a9293be0a78ba001a833300d4d5305baa1d9159679f6c9c79e0b9e852061a3d9c867d87d034f22e9f6d8158a25bdbb198a9983dbe21e5bbb8b6c96a72e4c7cba4562c18cb9c4abaff2ccd4c9ecc8808b095a4bd776bb33e66bf48e989618191df76f37d1e7db75ef7af76edd6dd73bf7be3cdbc7b973dd767356fde1ef74e3cf5af3dd9bd1cd5ae7def6d5bf3dedaddfefb69af1de3de77f7a73be377f56fcdddf5ad7dd38e74ef7d1b7396fc73ce77f347b5f3971a6fbf7d6de71e69af38df5d3ce5c775edd7397746b9d9de39db9d1ed7df747fdf77ef6f1bdb5e1beb46f8eb4d1be79f3573de9b734f3af1be5aefd6f57de6b87db6bbddb7dbd777b471b6f4d3b7fc75bf5ee3d75ed36efaebdd36ef5ebd779ddaedcd1a69ad3bd76efce77dfcd7d739df9eb9d9ae5bdbaefdf1feb57fbef4d347bd7f5f1be5eedd7dde9f735774dbdf387fcf37e5edf573a6b9e9fd356bbf5f7f577471cf3dd1e7b6e3a7746b77b7dbae9fd1de77e5c73adbbddaf5de5f79bedfef7e37f5ad7b75bf35ef7e5de7d77771cdb6d357da7fcef6f78f7cf5cddf75c7fd7b8f1bdfae9bdf7f3679f73be34f78e3969ddf4e9b776e1bddaedde7c69fe1f6bcd7d73773adf6e9ce3cdbcd9fe76d9fd1fe1ce5a7fae9e7dfd34e1f69d6f477ddf4d5ff7d71a6b86dae38efce746dcf75ddfefc775f1af1fdf66db6f76bad9bf79e1f775d396dcd5a737ebaddf69b6dcf1a774779efad787bcf79edf7f46dee37ef7d5befde36e35e3d77a6fd7dedf5df46fdd7de766f5eb6e79e7771dd5c6de6f96b9f3a6dfd1fe78d5dd5f75a6b9f3b734f3475e77975ae1f6db7ba6dd6fdf747b6edff5bf1edf5efc7b6d5de5fddd7dd79a739777d3c7bd6b46f8e35e9d71ddf9d7871bef779e7b5738e5feb66db75cf78ddf6f7e9d75d73c7fb6b56fdefdd9a779e777b7d1ae1a71a71f6dad777dc73ce5adfb7f6d5cf36ef8db4d1de76e9adbdf3b7fdf766b9f767fd75cd9ff5bf37f34d7ce5f77b71bd3bf76f1bf7671e7dde9bd7d75cf5feddf1f7787ddf1d75cd9dd39d37ddfdfce386dcd3af39f75e3bf3771a777e7d71ae9df386bd7787dbd1c7bce1ef5ad9c775d7b75ce78df4ddcdb46dad7deb8e1ff1dd7de777777dfd1a7bbdb47fdddf7dbdf7e3d7daeb46dad7defceda71deba6f5f5e75aef6d1e71defbdb9ebb77addd6fbefc79e69ad1fef879adf4e3973b778e79d7ad397f4ef4d5ed9be7477869f7df6de7757dfe3d77a7fb7dff39779f1b73d71b79d6f6e9b6b9e3b7dbf36d74e76d9eedc7b67fbd3b77d6f4d5d7bad9a75f7b4d346ddddcd5cedce387f9e5b77a73aefceb7f1ce746f573c7db7f4e3969f6b46f4f3a73569befdeda6f4efde1fdf4e3b7b8f5de5ee7ce34e7969b79dd7a6fb77be3a73ae9c6f971edf4777e367dfebc6f4e7de3def5e5f6f7f1cf5be36d9be37db4f7af5de347f57bd71cd5e7777bcd1b75d6ded366bbe3d7dbdfaedb71bf3bd5e75bf357f5e75eb8e3dd38dfbe7dd77f797fd75cddfd78f5cddce9a73b7bb7fadddd1c7daef6db47bbedfd1c7b6d74ef573979edbbd35d7475adfc6b4d37f3771aedcd1be9f736e9dedf6fdf37db6efb6fadbdd9cefbd3de7aeb571c69de1c7b675b775e78d9a739f747fc6dc6fbd9bd5b79d77def677beb9eb4f78dddf1f7b76dfe79d1bf77d7bf38d1ce7befa73de79df577673bd7df1ee5adb87deddbe38f356dde5ddb67b47bceb671bf5ce9cd3cdba69ceb6f1dd77e3d7767b56fbdf575f71ad5a7f86b46fad7bd1cefadfa69cd386db7b86ded9ae38ef9e77d9b71ad9e7dae5dddbefc6dedbc6bbe9af77e7b7f8d1fdf9edd75cdbde1bd5af38d9ed7cf1c69bf1bd3cdb46f879ce7d7bb73deb7d74d9e7fde34e5eedb6b4dfde9ae39e3573de1ef77db5ebcf1d7de6bde7ad9af79f3af3de5edfdd5a6bce5c7dee1a6dd77775ddfd69ae3dedcddef777f779b69ee9ddf879bf1bd75ef7ef67b97f8d9b71ff36e37e9fe9bd7cf5ff78df5efbd3adbde3af5a6b66fad3875dd7af757f571cddbe7dd79f5fe3c7367f975fd78dbbf5fe1f739e7dd9d7b9f5edfbf75d3a69ef7dd5ed3a6bc6dc6f5f3773769bdfc6bd6b8edde1f775737e7cdbad1cf3d79f7db79e6bae75edae9b77b7746f5738f1b6dde5a6dd6f56b7d7979ff3cd7575de3d79ae74dfc73779ff5e75bdbdd5de5f77be7a71d6ddd3b79ddb9e1d778e7cedaf756f77fbf5ed7d69e6dad1fd38ebbd75e74d7a6b475a79e69c6b6f3aefa6b5f1edb4e5ddf779ed76db579eeb671c6b5d5adb9d1ce5bef66b67396b9d5c","amount":"Amount of SSV tokens to be deposited to your validator's cluster balance (mandatory only for 1st validator in a cluster)","cluster":"The latest cluster snapshot data, obtained using the cluster-scanner tool. If this is the cluster's 1st validator then use - {0,0,0,0,0,false}"}},"createdAt":"2023-07-14T15:10:14.886591Z"}