diff --git a/apps/web/src/composables/contracts.ts b/apps/web/src/composables/contracts.ts index a6644361a..db72817e8 100644 --- a/apps/web/src/composables/contracts.ts +++ b/apps/web/src/composables/contracts.ts @@ -10,7 +10,7 @@ import usePrice from '@/composables/price' import useTrezor from '@/composables/trezor' import useUsers from '@/composables/users' import useWalletConnect from './walletConnect' -import { Account, BreakdownAmount, BreakdownString, ContractEventsByAddress, Pool, ProviderString, UserWithAccounts } from '@casimir/types' +import { Account, BreakdownAmount, BreakdownString, ContractEventsByAddress, Pool, ProviderString, UserWithAccountsAndOperators } from '@casimir/types' const currentStaked = ref({ usd: '$0.00', @@ -72,7 +72,7 @@ export default function useContracts() { async function getCurrentStaked(): Promise { const provider = new ethers.providers.JsonRpcProvider(ethereumUrl) - const addresses = (user.value as UserWithAccounts).accounts.map((account: Account) => account.address) as string[] + const addresses = (user.value as UserWithAccountsAndOperators).accounts.map((account: Account) => account.address) as string[] try { const promises = addresses.map((address) => manager.connect(provider).getUserStake(address)) const settledPromises = await Promise.allSettled(promises) as Array> @@ -193,7 +193,7 @@ export default function useContracts() { async function getAllTimeStakingRewards() : Promise { try { /* Get User's Current Stake */ - const addresses = (user.value as UserWithAccounts).accounts.map((account: Account) => account.address) as string[] + const addresses = (user.value as UserWithAccountsAndOperators).accounts.map((account: Account) => account.address) as string[] const currentUserStakePromises = [] as Array> addresses.forEach(address => currentUserStakePromises.push(manager.connect(provider).getUserStake(address))) const settledCurrentUserStakePromises = await Promise.allSettled(currentUserStakePromises) as Array> @@ -234,7 +234,7 @@ export default function useContracts() { async function getTotalWalletBalance() : Promise { const promises = [] as Array> - const addresses = (user.value as UserWithAccounts).accounts.map((account: Account) => account.address) as string[] + const addresses = (user.value as UserWithAccountsAndOperators).accounts.map((account: Account) => account.address) as string[] addresses.forEach((address) => { promises.push(getEthersBalance(address)) }) const totalWalletBalance = (await Promise.all(promises)).reduce((acc, curr) => acc + curr, 0) const totalWalletBalanceUSD = totalWalletBalance * (await getCurrentPrice({ coin: 'ETH', currency: 'USD' })) diff --git a/apps/web/src/composables/ethers.ts b/apps/web/src/composables/ethers.ts index 4a45742d1..5c0f9f30c 100644 --- a/apps/web/src/composables/ethers.ts +++ b/apps/web/src/composables/ethers.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers' import { EthersProvider } from '@casimir/types' -import { Account, TransactionRequest, UserWithAccounts } from '@casimir/types' +import { Account, TransactionRequest, UserWithAccountsAndOperators } from '@casimir/types' import { GasEstimate, LoginCredentials, MessageRequest, ProviderString } from '@casimir/types' import useAuth from '@/composables/auth' import useContracts from '@/composables/contracts' @@ -35,7 +35,7 @@ export default function useEthers() { 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 addresses = (user.value as UserWithAccountsAndOperators).accounts.map((account: Account) => account.address) as string[] const block = await provider.getBlockWithTransactions(blockNumber) const transactions = block.transactions transactions.map(async (tx) => { diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index 040d4b46e..58b92aa11 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -1,5 +1,5 @@ import { ref, readonly } from 'vue' -import { Account, AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccounts, ApiResponse, UserAnalyticsData } from '@casimir/types' +import { Account, AddAccountOptions, ProviderString, RemoveAccountOptions, UserWithAccountsAndOperators, ApiResponse, UserAnalyticsData } from '@casimir/types' import useEnvironment from '@/composables/environment' import useEthers from './ethers' import * as Session from 'supertokens-web-js/recipe/session' @@ -10,7 +10,7 @@ const { usersUrl } = useEnvironment() // 0xd557a5745d4560B24D36A68b52351ffF9c86A212 const session = ref(false) -const user = ref(undefined) +const user = ref(undefined) const userAnalytics = ref({ oneMonth: { labels: [], @@ -236,12 +236,17 @@ export default function useUsers() { 'Content-Type': 'application/json' } } - const response = await fetch(`${usersUrl}/analytics`, requestOptions) - const { error, message, data } = await response.json() + // TODO: Re-enable this when athena is ready + // const response = await fetch(`${usersUrl}/analytics`, requestOptions) + // const { error, message, data } = await response.json() + const error = false + const message = 'User analytics found' + const data = txData.value + if (error) throw new Error(message) // TODO: Pass data from above when the API / data is ready - setRawAnalytics(txData.value) + setRawAnalytics(data) computeUserAnalytics() return { error, message, data } } catch (error: any) { @@ -297,8 +302,8 @@ export default function useUsers() { return { error: false, message: `Account removed from user: ${userAccount}`, data: userAccount } } - function setUser(newUser?: UserWithAccounts) { - user.value = newUser as UserWithAccounts + function setUser(newUser?: UserWithAccountsAndOperators) { + user.value = newUser as UserWithAccountsAndOperators userAddresses.value = newUser?.accounts.map(account => account.address) as Array } diff --git a/common/data/src/index.ts b/common/data/src/index.ts index c9f76e55a..74fc835e6 100644 --- a/common/data/src/index.ts +++ b/common/data/src/index.ts @@ -1,11 +1,12 @@ import accountSchema from './schemas/account.schema.json' -import nonceSchema from './schemas/nonce.schema.json' -import userSchema from './schemas/user.schema.json' -import eventSchema from './schemas/event.schema.json' +import accountStore from './mock/account.store.json' import actionSchema from './schemas/action.schema.json' -import userAccountSchema from './schemas/user_account.schema.json' +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 accountStore from './mock/account.store.json' +import userAccountSchema from './schemas/user_account.schema.json' +import userSchema from './schemas/user.schema.json' import userStore from './mock/user.store.json' import { Postgres } from '../../../services/users/src/providers/postgres' import { JsonType, GlueType, PostgresType, Schema } from './providers/schema' @@ -13,14 +14,15 @@ import { JsonSchema } from './interfaces/JsonSchema' export { accountSchema, + accountStore, + actionSchema, + eventSchema, nonceSchema, - userSchema, + operatorSchema, + operatorStore, userAccountSchema, - eventSchema, - actionSchema, - accountStore, + userSchema, userStore, - operatorStore, Postgres, Schema } diff --git a/common/data/src/schemas/operator.schema.json b/common/data/src/schemas/operator.schema.json new file mode 100644 index 000000000..df4f3d2f0 --- /dev/null +++ b/common/data/src/schemas/operator.schema.json @@ -0,0 +1,35 @@ +{ + "$id": "https://casimir.co/operator.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Operator", + "type": "object", + "properties": { + "account_id": { + "type": "integer", + "description": "The ID of the account the operator belongs to (FK)" + }, + "id": { + "type": "serial", + "description": "The operator ID (PK)" + }, + "user_id": { + "type": "integer", + "description": "The ID of the user who is an operator (FK)" + }, + "created_at": { + "type": "string", + "description": "The operator creation date in ISO 8601 format" + }, + "updated_at": { + "type": "string", + "description": "The operator last update date in ISO 8601 format" + } + }, + "required": [ + "account_id", + "id", + "user_id", + "created_at", + "updated_at" + ] +} diff --git a/common/types/src/index.ts b/common/types/src/index.ts index f1b0be969..4f68c287b 100644 --- a/common/types/src/index.ts +++ b/common/types/src/index.ts @@ -1,5 +1,5 @@ import { Account } from './interfaces/Account' -import { AccountWithStakingInfo } from './interfaces/AccountWithStakingInfo' +import { AccountWithStakingAndOperatorInfo } from './interfaces/AccountWithStakingAndOperatorInfo' import { AddAccountOptions } from './interfaces/AddAccountOptions' import { AnalyticsData } from './interfaces/AnalyticsData' import { ApiResponse } from './interfaces/ApiResponse' @@ -22,6 +22,7 @@ import { GasEstimate } from './interfaces/GasEstimate' import { LoginCredentials } from './interfaces/LoginCredentials' import { MessageRequest } from './interfaces/MessageRequest' import { Operator } from './interfaces/Operator' +import { OperatorAddedSuccess } from './interfaces/OperatorAddedSuccess' import { Pool } from './interfaces/Pool' import { PoolStatus } from './interfaces/PoolStatus' import { ProviderString } from './interfaces/ProviderString' @@ -29,13 +30,13 @@ import { TransactionRequest } from './interfaces/TransactionRequest' import { RemoveAccountOptions } from './interfaces/RemoveAccountOptions' import { User } from './interfaces/User' import { UserAddedSuccess } from './interfaces/UserAddedSuccess' -import { UserWithAccounts } from './interfaces/UserWithAccounts' +import { UserWithAccountsAndOperators } from './interfaces/UserWithAccountsAndOperators' import { UserAnalyticsData } from './interfaces/UserAnalyticsData' import { Validator } from './interfaces/Validator' export type { Account, - AccountWithStakingInfo, + AccountWithStakingAndOperatorInfo, ApiResponse, AddAccountOptions, AnalyticsData, @@ -57,7 +58,8 @@ export type { GasEstimate, LoginCredentials, MessageRequest, - Operator, + Operator, + OperatorAddedSuccess, Pool, ProviderString, TransactionRequest, @@ -65,7 +67,7 @@ export type { User, UserAddedSuccess, UserAnalyticsData, - UserWithAccounts, + UserWithAccountsAndOperators, Validator, } diff --git a/common/types/src/interfaces/AccountWithStakingInfo.ts b/common/types/src/interfaces/AccountWithStakingAndOperatorInfo.ts similarity index 75% rename from common/types/src/interfaces/AccountWithStakingInfo.ts rename to common/types/src/interfaces/AccountWithStakingAndOperatorInfo.ts index 3b6837c59..573a45f44 100644 --- a/common/types/src/interfaces/AccountWithStakingInfo.ts +++ b/common/types/src/interfaces/AccountWithStakingAndOperatorInfo.ts @@ -1,6 +1,6 @@ -import { Account, Pool } from '@casimir/types' +import { Account, Operator, Pool } from '@casimir/types' -export interface AccountWithStakingInfo extends Account { +export interface AccountWithStakingAndOperatorInfo extends Account { /** The user's current staking pools and details (this interface/logic is in the web app wallet composable, but it will be moved to the processor, see https://github.com/consensusnetworks/casimir/blob/master/apps/web/src/composables/wallet.ts#L146) */ pools?: Pool[] /** The total amount of stake rewards available to withdraw (ignore for now, see note on Account.pools) */ @@ -9,4 +9,6 @@ export interface AccountWithStakingInfo extends Account { roi?: number /** The total amount currently staked (ignore for now, see note on Account.pools) */ stake?: string + /** Operators associated with a given account address */ + operators?: Operator[] } \ No newline at end of file diff --git a/common/types/src/interfaces/Operator.ts b/common/types/src/interfaces/Operator.ts index a5e80728f..194984c3c 100644 --- a/common/types/src/interfaces/Operator.ts +++ b/common/types/src/interfaces/Operator.ts @@ -1,31 +1,7 @@ export interface Operator { + accountId: number id: number - id_str: string - declared_fee: number - previous_fee: number - fee: number // Todo check if this is bigint - name: string - public_key: string - owner_address: string - address: string - location: string - setup_provider: string - eth1_node_client: string - eth2_node_client: string - description: string - website_url: string - twitter_url: string - linkedin_url: string - logo: string - type: string - performance: { - '24h': number - '30d': number - }, - is_active: number - is_valid: boolean - is_deleted: boolean - status: string // Todo check for enum (i.e., 'Active'...) - validators_count: number - url: string // Todo check if this is usable in DKG + userId: number + createdAt: string + updatedAt: string } \ No newline at end of file diff --git a/common/types/src/interfaces/OperatorAddedSuccess.ts b/common/types/src/interfaces/OperatorAddedSuccess.ts new file mode 100644 index 000000000..4ee2c4fcd --- /dev/null +++ b/common/types/src/interfaces/OperatorAddedSuccess.ts @@ -0,0 +1,7 @@ +export interface OperatorAddedSuccess { + id: number + account_id: number + created_at: string + updated_at: string + user_id: number +} \ No newline at end of file diff --git a/common/types/src/interfaces/OperatorDetails.ts b/common/types/src/interfaces/OperatorDetails.ts new file mode 100644 index 000000000..27635aa3e --- /dev/null +++ b/common/types/src/interfaces/OperatorDetails.ts @@ -0,0 +1,30 @@ +export interface OperatorDetails { + id_str: string + declared_fee: number + previous_fee: number + fee: number // Todo check if this is bigint + name: string + public_key: string + owner_address: string + address: string + location: string + setup_provider: string + eth1_node_client: string + eth2_node_client: string + description: string + website_url: string + twitter_url: string + linkedin_url: string + logo: string + type: string + performance: { + '24h': number + '30d': number + }, + is_active: number + is_valid: boolean + is_deleted: boolean + status: string // Todo check for enum (i.e., 'Active'...) + validators_count: number + url: string // Todo check if this is usable in DKG +} \ No newline at end of file diff --git a/common/types/src/interfaces/UserWithAccounts.ts b/common/types/src/interfaces/UserWithAccounts.ts deleted file mode 100644 index 40edb01cd..000000000 --- a/common/types/src/interfaces/UserWithAccounts.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AccountWithStakingInfo, User } from '@casimir/types' - -export interface UserWithAccounts extends User { - /** An array of the user's accounts */ - accounts: AccountWithStakingInfo[] -} \ No newline at end of file diff --git a/common/types/src/interfaces/UserWithAccountsAndOperators.ts b/common/types/src/interfaces/UserWithAccountsAndOperators.ts new file mode 100644 index 000000000..21facf67a --- /dev/null +++ b/common/types/src/interfaces/UserWithAccountsAndOperators.ts @@ -0,0 +1,8 @@ +import { AccountWithStakingAndOperatorInfo, Operator, User } from '@casimir/types' + +export interface UserWithAccountsAndOperators extends User { + /** An array of the user's accounts */ + accounts: AccountWithStakingAndOperatorInfo[] + /** An array of the user's operators */ + operators?: Operator[] +} \ No newline at end of file