From 85aaa9706a1df3d434a55597115a4c57fc4d12f8 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 18 Apr 2023 22:36:29 -0700 Subject: [PATCH 1/6] Update schema to: - handle multiple users w/ same address - change primary address --- common/data/src/index.ts | 2 ++ common/data/src/interfaces/JsonSchema.ts | 2 ++ common/data/src/providers/schema.ts | 13 ++++++--- common/data/src/schemas/account.schema.json | 22 +++++++++++---- common/data/src/schemas/user.schema.json | 11 ++++++-- .../src/schemas/users_accounts.schema.json | 27 +++++++++++++++++++ 6 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 common/data/src/schemas/users_accounts.schema.json diff --git a/common/data/src/index.ts b/common/data/src/index.ts index bc2fe88c7..e1712983b 100644 --- a/common/data/src/index.ts +++ b/common/data/src/index.ts @@ -3,6 +3,7 @@ import nonceSchema from './schemas/nonce.schema.json' import userSchema from './schemas/user.schema.json' import eventSchema from './schemas/event.schema.json' import aggSchema from './schemas/agg.schema.json' +import usersAccountsSchema from './schemas/users_accounts.schema.json' import operatorStore from './mock/operator.store.json' import validatorStore from './mock/validator.store.json' import accountStore from './mock/account.store.json' @@ -15,6 +16,7 @@ export { accountSchema, nonceSchema, userSchema, + usersAccountsSchema, eventSchema, aggSchema, accountStore, diff --git a/common/data/src/interfaces/JsonSchema.ts b/common/data/src/interfaces/JsonSchema.ts index 19e970cc3..5fd31a1cc 100644 --- a/common/data/src/interfaces/JsonSchema.ts +++ b/common/data/src/interfaces/JsonSchema.ts @@ -9,4 +9,6 @@ export interface JsonSchema { description: string } }, + uniqueFields?: string[], + composite_key?: string } \ No newline at end of file diff --git a/common/data/src/providers/schema.ts b/common/data/src/providers/schema.ts index a7bf38bff..39c5387c0 100644 --- a/common/data/src/providers/schema.ts +++ b/common/data/src/providers/schema.ts @@ -61,6 +61,8 @@ export class Schema { * ``` */ getPostgresTable(): string { + const compositeKey = this.jsonSchema.composite_key + const uniqueFields = this.jsonSchema.uniqueFields || [] const columns = Object.keys(this.jsonSchema.properties).map((name: string) => { const property = this.jsonSchema.properties[name] let type = { @@ -70,7 +72,8 @@ export class Schema { boolean: 'BOOLEAN', object: 'JSON', array: 'JSON', - null: 'VARCHAR' + null: 'VARCHAR', + serial: 'SERIAL' }[property.type as JsonType] as PostgresType if (name.endsWith('_at')) type = 'TIMESTAMP' @@ -80,14 +83,18 @@ export class Schema { const comment = property.description if (comment.includes('PK')) column += ' PRIMARY KEY' - + return column }) + /** Check for composite key property and add the primary key if so */ + if (compositeKey) columns.push(`PRIMARY KEY (${compositeKey})`) + /** Make table name plural of schema objects (todo: check edge-cases) */ const tableName = this.getTitle().toLowerCase() + 's' - return `CREATE TABLE ${tableName} (\n\t${columns.join(',\n\t')}\n);` + const queryString = uniqueFields.length > 0 ? `CREATE TABLE ${tableName} (\n\t${columns.join(',\n\t')}, \n\tUNIQUE (${uniqueFields.join(', ')}));` : `CREATE TABLE ${tableName} (\n\t${columns.join(',\n\t')}\n);` + return queryString } /** diff --git a/common/data/src/schemas/account.schema.json b/common/data/src/schemas/account.schema.json index 19b98fce2..3364753e0 100644 --- a/common/data/src/schemas/account.schema.json +++ b/common/data/src/schemas/account.schema.json @@ -6,7 +6,7 @@ "properties": { "address": { "type": "string", - "description": "The account address (PK)" + "description": "The account address" }, "balance": { "type": "number", @@ -20,9 +20,9 @@ "type": "string", "description": "The account creation date in ISO 8601 format" }, - "owner_address": { - "type": "string", - "description": "The account owner address" + "id": { + "type": "serial", + "description": "The account ID (PK)" }, "snapshots": { "type": "array", @@ -49,15 +49,27 @@ "type": "string", "description": "The account last update date in ISO 8601 format" }, + "user_id": { + "type": "integer", + "description": "The account user ID (FK)" + }, "wallet_provider": { "type": "string", "description": "The account wallet provider" } }, + "uniqueFields": [ + "address", + "user_id", + "wallet_provider" + ], "required": [ + "id", "address", + "created_at", "currency", - "owner_address", + "updated_at", + "user_id", "wallet_provider" ] } \ No newline at end of file diff --git a/common/data/src/schemas/user.schema.json b/common/data/src/schemas/user.schema.json index 0dab447c3..8e334be8e 100644 --- a/common/data/src/schemas/user.schema.json +++ b/common/data/src/schemas/user.schema.json @@ -6,18 +6,25 @@ "properties": { "address": { "type": "string", - "description": "The user address (PK)" + "description": "The user address used to sign in" }, "created_at": { "type": "string", "description": "The account creation date in ISO 8601 format" }, + "id": { + "type": "serial", + "description": "The user ID (PK)" + }, "updated_at": { "type": "string", "description": "The account last update date in ISO 8601 format" } }, "required": [ - "address" + "address", + "created_at", + "id", + "updated_at" ] } \ No newline at end of file diff --git a/common/data/src/schemas/users_accounts.schema.json b/common/data/src/schemas/users_accounts.schema.json new file mode 100644 index 000000000..d557ad662 --- /dev/null +++ b/common/data/src/schemas/users_accounts.schema.json @@ -0,0 +1,27 @@ +{ + "$id": "https://casimir.co/users_accounts.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "User_Account", + "type": "object", + "properties": { + "account_id": { + "type": "integer", + "description": "The unique identifier for an account (pk part 2) and the FK to the account table" + }, + "created_at": { + "type": "string", + "description": "The date and time the user_account was created" + }, + "user_id": { + "type": "integer", + "description": "The unique identifier for a user (pk part 1) and the FK to the user table" + } + }, + "composite_key": "user_id, account_id", + "required": [ + "account_id", + "created_at", + "user_id" + ] + } + \ No newline at end of file From 6477fc61d7c0e05cf038abd13ce009cc74462ea8 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 18 Apr 2023 22:38:29 -0700 Subject: [PATCH 2/6] Update postgres & dev scripts to handle new user_accounts table --- common/data/scripts/postgres.ts | 7 ++++--- scripts/local/dev.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/common/data/scripts/postgres.ts b/common/data/scripts/postgres.ts index 73009c2fb..ec624d5ec 100644 --- a/common/data/scripts/postgres.ts +++ b/common/data/scripts/postgres.ts @@ -1,7 +1,7 @@ import minimist from 'minimist' import fs from 'fs' import { run } from '@casimir/helpers' -import { JsonSchema, Schema, accountSchema, nonceSchema, userSchema } from '@casimir/data' +import { JsonSchema, Schema, accountSchema, nonceSchema, userSchema, usersAccountsSchema } from '@casimir/data' /** Resource path from package caller */ const resourcePath = './scripts' @@ -10,7 +10,8 @@ const resourcePath = './scripts' const tableSchemas = { accounts: accountSchema, nonces: nonceSchema, - users: userSchema + users: userSchema, + users_accounts: usersAccountsSchema } /** @@ -25,7 +26,7 @@ void async function () { const argv = minimist(process.argv.slice(2)) /** Default to all tables */ - const tables = argv.tables ? argv.tables.split(',') : ['accounts', 'nonces', 'users'] + const tables = argv.tables ? argv.tables.split(',') : ['accounts', 'nonces', 'users', 'users_accounts'] let sqlSchema = '-- Generated by @casimir/data/scripts/postgres.ts\n\n' for (const table of tables) { const tableSchema = tableSchemas[table] as JsonSchema diff --git a/scripts/local/dev.ts b/scripts/local/dev.ts index 36ab30cca..623b2b11a 100644 --- a/scripts/local/dev.ts +++ b/scripts/local/dev.ts @@ -19,7 +19,7 @@ void async function () { web: { chains: ['ethereum'], services: ['users'], - tables: ['accounts', 'nonces', 'users'] + tables: ['accounts', 'nonces', 'users', 'users_accounts'], } } From c222ef4864582efb54b134549da654475b0499eb Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 18 Apr 2023 22:51:42 -0700 Subject: [PATCH 3/6] Implement backend functionality to handle users accounts with updated schema --- services/users/src/providers/db.ts | 54 ++++++++++++++++++++++++++---- services/users/src/routes/auth.ts | 6 ++-- services/users/src/routes/user.ts | 18 ++++------ 3 files changed, 58 insertions(+), 20 deletions(-) diff --git a/services/users/src/providers/db.ts b/services/users/src/providers/db.ts index 427668ede..48373209a 100644 --- a/services/users/src/providers/db.ts +++ b/services/users/src/providers/db.ts @@ -21,11 +21,14 @@ export default function useDB() { */ async function addAccount(account: Account, createdAt?: string) : Promise { if (!createdAt) createdAt = new Date().toISOString() - const { address, currency, ownerAddress, walletProvider } = account - const text = 'INSERT INTO accounts (address, currency, owner_address, wallet_provider, created_at) VALUES ($1, $2, $3, $4, $5) RETURNING *;' - const params = [address, currency, ownerAddress, walletProvider, createdAt] + const { address, currency, userId, walletProvider } = account + const text = 'INSERT INTO accounts (address, currency, user_id, wallet_provider, created_at) VALUES ($1, $2, $3, $4, $5) RETURNING *;' + const params = [address, currency, userId, walletProvider, createdAt] const rows = await postgres.query(text, params) - return rows[0] as Account + const accountAdded = rows[0] + const accountId = accountAdded.id + await addUserAccount(parseInt(userId), accountId) + return accountAdded as Account } /** @@ -40,6 +43,7 @@ export default function useDB() { const params = [address, createdAt, updatedAt] const rows = await postgres.query(text, params) const addedUser = rows[0] + account.userId = addedUser.id const accountAdded = await addAccount(account, createdAt) addedUser.accounts = [accountAdded] @@ -47,13 +51,27 @@ export default function useDB() { return formatResult(addedUser) } + /** + * Add a user account. + * @param user_id - The user's id + * @param account_id - The account's id + * @returns The new user account + */ + async function addUserAccount(user_id: number, account_id: number) { + const createdAt = new Date().toISOString() + const text = 'INSERT INTO user_accounts (user_id, account_id, created_at) VALUES ($1, $2, $3) RETURNING *;' + const params = [user_id, account_id, createdAt] + const rows = await postgres.query(text, params) + return rows[0] + } + /** * Get a user by address. * @param address - The user's address * @returns The user if found, otherwise undefined */ async function getUser(address: string) { - const text = 'SELECT u.*, json_agg(a.*) AS accounts FROM users u JOIN accounts a ON u.address = a.owner_address WHERE u.address = $1 GROUP BY u.address' + const text = 'SELECT u.*, json_agg(a.*) AS accounts FROM users u JOIN user_accounts ua ON u.id = ua.user_id JOIN accounts a ON ua.account_id = a.id WHERE u.address = $1 GROUP BY u.id' const params = [address] const rows = await postgres.query(text, params) const user = rows[0] @@ -75,6 +93,30 @@ export default function useDB() { return rows[0] as Account } + /** + * Update user's address based on userId. + * @param userId - The user's id + * @param address - The user's new address + * @returns A promise that resolves when the user's address is updated + * @throws Error if the user is not found + * @throws Error if the user's address is not updated + */ + async function updateUserAddress(userId: number, address: string): Promise { + try { + const updated_at = new Date().toISOString() + const text = 'UPDATE users SET address = $1, updated_at = $2 WHERE id = $3 RETURNING *;' + const params = [address, updated_at, userId] + const rows = await postgres.query(text, params) + const user = rows[0] + if (!user) throw new Error('User not found.') + if (user.address !== address) throw new Error('User address not updated.') + return user + } catch (error) { + console.error('There was an error updating the user address in updateUserAddress.', error) + throw error + } + } + /** * Add or update nonce for an address. * @param address - The address @@ -122,7 +164,7 @@ export default function useDB() { } } - return { addAccount, addUser, getUser, removeAccount, upsertNonce } + return { addAccount, addUser, getUser, removeAccount, updateUserAddress, upsertNonce } } /** diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index 61c63de19..0a81e9e85 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -34,7 +34,7 @@ router.post('/login', async (req: express.Request, res: express.Response) => { if (!user) { // signup console.log('SIGNING UP!') const now = new Date().toISOString() - const newUser = { + const newUser = { address, createdAt: now, updatedAt: now, @@ -42,11 +42,11 @@ router.post('/login', async (req: express.Request, res: express.Response) => { const account = { address, currency, - ownerAddress: address, walletProvider: provider, } as Account + const addUserResult = await addUser(newUser, account) - + if (addUserResult?.address !== address) { res.setHeader('Content-Type', 'application/json') res.status(500) diff --git a/services/users/src/routes/user.ts b/services/users/src/routes/user.ts index fb7d0dc20..c0a013992 100644 --- a/services/users/src/routes/user.ts +++ b/services/users/src/routes/user.ts @@ -4,7 +4,7 @@ import { SessionRequest } from 'supertokens-node/framework/express' import useDB from '../providers/db' const router = express.Router() -const { addAccount, getUser, removeAccount } = useDB() +const { addAccount, getUser, updateUserAddress, removeAccount } = useDB() router.get('/', verifySession(), async (req: SessionRequest, res: express.Response) => { const address = req.session?.getUserId() as string @@ -103,16 +103,13 @@ router.post('/remove-sub-account', verifySession(), async (req: SessionRequest, }) // TODO: Think through handling changing primary address with SuperTokens Sessions. -router.put('/update-primary-account', async (req: express.Request, res: express.Response) => { - let { primaryAddress, updatedProvider, updatedAddress } = req.body - primaryAddress = primaryAddress.toLowerCase() - updatedProvider = updatedProvider.toLowerCase() +router.put('/update-primary-account', verifySession(), async (req: SessionRequest, res: express.Response) => { + const { userId } = req.body + let { updatedAddress } = req.body updatedAddress = updatedAddress.toLowerCase() - // TODO: Invoke updatePrimaryAccount function from here - - // eslint-disable-next-line no-constant-condition - if (false) { + const user = await updateUserAddress(userId, updatedAddress) + if (!user) { res.setHeader('Content-Type', 'application/json') res.status(200) res.json({ @@ -120,14 +117,13 @@ router.put('/update-primary-account', async (req: express.Request, res: express. error: true, data: null }) - return } else { res.setHeader('Content-Type', 'application/json') res.status(200) res.json({ message: 'Primary account updated', error: false, - data: {} + data: user }) } }) From 4b1b6a10986171bc66995e05e044747b3ff45dcc Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 18 Apr 2023 22:52:43 -0700 Subject: [PATCH 4/6] Update types and extended types correlating to postgres schema --- common/types/src/index.ts | 2 ++ common/types/src/interfaces/Account.ts | 24 +++++++++---------- .../src/interfaces/AccountWithStakingInfo.ts | 12 ++++++++++ common/types/src/interfaces/User.ts | 4 ++-- .../types/src/interfaces/UserWithAccounts.ts | 8 ++++--- 5 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 common/types/src/interfaces/AccountWithStakingInfo.ts diff --git a/common/types/src/index.ts b/common/types/src/index.ts index 9ec414c04..504089bf6 100644 --- a/common/types/src/index.ts +++ b/common/types/src/index.ts @@ -1,4 +1,5 @@ import { Account } from './interfaces/Account' +import { AccountWithStakingInfo } from './interfaces/AccountWithStakingInfo' import { AddAccountOptions } from './interfaces/AddAccountOptions' import { BalanceSnapshot } from './interfaces/BalanceSnapshot' import { ContractArgs } from './interfaces/ContractArgs' @@ -18,6 +19,7 @@ import { Validator } from './interfaces/Validator' export type { Account, + AccountWithStakingInfo, AddAccountOptions, BalanceSnapshot, ContractArgs, diff --git a/common/types/src/interfaces/Account.ts b/common/types/src/interfaces/Account.ts index 0aa5eda72..05bba098b 100644 --- a/common/types/src/interfaces/Account.ts +++ b/common/types/src/interfaces/Account.ts @@ -1,24 +1,22 @@ import { BalanceSnapshot, Currency, Pool, ProviderString } from '@casimir/types' export interface Account { - /** Unique ID (only keeping the latest of each distinct address/currency pair per User to avoid double counting) */ + /** The address of the current account */ address: string /** The current balance */ balance?: string - /** Daily balance snapshots */ - balanceSnapshots?: BalanceSnapshot[] /** See Currency below */ currency: Currency - /** 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) */ - rewards?: string - /** Return on investment rate (see https://github.com/consensusnetworks/casimir/issues/168#issuecomment-1314420917) */ - roi?: number - /** The total amount currently staked (ignore for now, see note on Account.pools) */ - stake?: string + /** ISO Timestamp of when user was created */ + createdAt: string + /** The unique account id */ + id: number + /** The account snapshots */ + snapshots?: BalanceSnapshot[] + /** The account transactions */ + // transactions?: Transaction[] + /** The user id associated with the account */ + userId: string /** The wallet provider which helps us show user breakdown and connect when signing or sending TXs */ walletProvider: ProviderString - /** The verified user owner address (only optional for compat, should be req) */ - ownerAddress?: string } \ No newline at end of file diff --git a/common/types/src/interfaces/AccountWithStakingInfo.ts b/common/types/src/interfaces/AccountWithStakingInfo.ts new file mode 100644 index 000000000..3b6837c59 --- /dev/null +++ b/common/types/src/interfaces/AccountWithStakingInfo.ts @@ -0,0 +1,12 @@ +import { Account, Pool } from '@casimir/types' + +export interface AccountWithStakingInfo 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) */ + rewards?: string + /** Return on investment rate (see https://github.com/consensusnetworks/casimir/issues/168#issuecomment-1314420917) */ + roi?: number + /** The total amount currently staked (ignore for now, see note on Account.pools) */ + stake?: string +} \ No newline at end of file diff --git a/common/types/src/interfaces/User.ts b/common/types/src/interfaces/User.ts index d0692f1f2..d03a61591 100644 --- a/common/types/src/interfaces/User.ts +++ b/common/types/src/interfaces/User.ts @@ -1,10 +1,10 @@ -import { Account } from '@casimir/types' - export interface User { /** Unique ID (and essential for auth verification) */ address: string /** ISO Timestamp of when user was created */ createdAt: string + /** Unique user ID (and essential for auth verification) */ + id: number /* ISO Timestamp of when user was last updated */ updatedAt?: string } \ No newline at end of file diff --git a/common/types/src/interfaces/UserWithAccounts.ts b/common/types/src/interfaces/UserWithAccounts.ts index 7527f3eea..61f6ff50b 100644 --- a/common/types/src/interfaces/UserWithAccounts.ts +++ b/common/types/src/interfaces/UserWithAccounts.ts @@ -1,12 +1,14 @@ -import { Account } from '@casimir/types' +import { AccountWithStakingInfo } from '@casimir/types' export interface UserWithAccounts { - /** Unique ID (and essential for auth verification) */ + /** Unique address for the user (can be updated) */ address: string /** An array of the user's accounts */ - accounts: Account[] + accounts: AccountWithStakingInfo[] /** ISO Timestamp of when user was created */ createdAt: string + /** Unique user ID (and essential for auth verification) */ + id: number /* ISO Timestamp of when user was last updated */ updatedAt?: string } \ No newline at end of file From 21b293e718d3cd5c4296b43cb0c13320f71d2909 Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Tue, 18 Apr 2023 22:53:14 -0700 Subject: [PATCH 5/6] Add front-end composable code to manage user accounts --- apps/web/src/composables/users.ts | 72 ++---------------------------- apps/web/src/composables/wallet.ts | 12 ++--- 2 files changed, 10 insertions(+), 74 deletions(-) diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index f2f0addc5..4971b75db 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -11,71 +11,6 @@ const { usersBaseURL, ethereumURL } = useEnvironment() // 0xd557a5745d4560B24D36A68b52351ffF9c86A212 const session = ref(false) const user = ref() -// const user = ref( -// { -// address: '0xd557a5745d4560B24D36A68b52351ffF9c86A212'.toLowerCase(), -// accounts: [ -// { -// address: '0xd557a5745d4560B24D36A68b52351ffF9c86A212'.toLowerCase(), -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'MetaMask' -// }, -// { -// address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(), -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'CoinbaseWallet' -// }, -// { -// address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(), -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'CoinbaseWallet' -// }, -// { -// address: '0x1dc336d94890b10e1a47b6e34cdee1009ee7b942'.toLowerCase(), -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'CoinbaseWallet' -// }, -// { -// address: '0x8222Ef172A2117D1C4739E35234E097630D94376'.toLowerCase(), -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'Ledger' -// }, -// { -// address: '0x8222Ef172A2117D1C4739E35234E097630D94377'.toLowerCase(), // Fake address -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'Trezor' -// }, -// { -// address: '0x8222Ef172A2117D1C4739E35234E097630D94378'.toLowerCase(), // Fake address -// currency: 'ETH', -// balance: '1000000000000000000', -// balanceSnapshots: [{ date: '2023-02-06', balance: '1000000000000000000' }, { date: '2023-02-05', balance: '100000000000000000' }], -// roi: 0.25, -// walletProvider: 'WalletConnect' -// }, -// ], -// nonce: '1234567890', -// pools: [] -// } -// ) const { casimirManager, getPools } = useSSV() export default function useUsers () { @@ -190,15 +125,16 @@ export default function useUsers () { }) } - async function updatePrimaryAddress(primaryAddress: string, updatedProvider: ProviderString, updatedAddress: string) { + async function updatePrimaryAddress(updatedAddress: string) { + const userId = user?.value?.id const requestOptions = { method: 'PUT', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ primaryAddress, updatedProvider, updatedAddress }) + body: JSON.stringify({ userId, updatedAddress }) } - return await fetch(`${usersBaseURL}/users/update-primary-account`, requestOptions) + return await fetch(`${usersBaseURL}/user/update-primary-account`, requestOptions) } return { diff --git a/apps/web/src/composables/wallet.ts b/apps/web/src/composables/wallet.ts index 24783054f..5008187ab 100644 --- a/apps/web/src/composables/wallet.ts +++ b/apps/web/src/composables/wallet.ts @@ -107,6 +107,7 @@ export default function useWallet() { // If account doesn't exist, add account using users api console.log('adding sub account') const account = { + userId: user?.value?.id, address: connectedAddress.toLowerCase() as string, currency: connectedCurrency, ownerAddress: user?.value?.address.toLowerCase() as string, @@ -206,13 +207,12 @@ export default function useWallet() { } } - // TODO: What is this used for? // Do we need balance of active address only? // Or do we need balance of all addresses in accounts associated with user? // Is this calculated on front end or back end or both? async function getUserBalance() { if (ethersProviderList.includes(selectedProvider.value)){ - const walletBalance = await getEthersBalance(selectedProvider.value, selectedAddress.value) + const walletBalance = await getEthersBalance(selectedAddress.value) console.log('walletBalance in wei in wallet.ts :>> ', walletBalance) return walletBalance } else { @@ -312,14 +312,14 @@ export default function useWallet() { async function setPrimaryWalletAccount() { if (!user?.value?.address) { alert('Please login first') - } - return alert('Not yet implemented for this wallet provider') - if (ethersProviderList.includes(selectedProvider.value)) { - const result = await updatePrimaryAddress(primaryAddress.value, selectedProvider.value, selectedAddress.value) + } else if (ethersProviderList.includes(selectedProvider.value)) { + const result = await updatePrimaryAddress(selectedAddress.value) const { data } = await result.json() if (data) { primaryAddress.value = data.address } + } else { + return alert('Not yet implemented for this wallet provider') } } From 2eaa6e10bf7ae6d6ce2fc90de81ab49bc122996d Mon Sep 17 00:00:00 2001 From: Christopher Cali Date: Thu, 20 Apr 2023 08:25:27 -0700 Subject: [PATCH 6/6] Fix naming convention of tables (with Shane) --- common/data/scripts/postgres.ts | 6 +++--- common/data/src/index.ts | 4 ++-- common/data/src/providers/schema.ts | 5 +++-- ...{users_accounts.schema.json => user_account.schema.json} | 4 ++-- scripts/local/dev.ts | 2 +- services/users/src/routes/auth.ts | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) rename common/data/src/schemas/{users_accounts.schema.json => user_account.schema.json} (89%) diff --git a/common/data/scripts/postgres.ts b/common/data/scripts/postgres.ts index ec624d5ec..be7496916 100644 --- a/common/data/scripts/postgres.ts +++ b/common/data/scripts/postgres.ts @@ -1,7 +1,7 @@ import minimist from 'minimist' import fs from 'fs' import { run } from '@casimir/helpers' -import { JsonSchema, Schema, accountSchema, nonceSchema, userSchema, usersAccountsSchema } from '@casimir/data' +import { JsonSchema, Schema, accountSchema, nonceSchema, userSchema, userAccountSchema } from '@casimir/data' /** Resource path from package caller */ const resourcePath = './scripts' @@ -11,7 +11,7 @@ const tableSchemas = { accounts: accountSchema, nonces: nonceSchema, users: userSchema, - users_accounts: usersAccountsSchema + user_accounts: userAccountSchema } /** @@ -26,7 +26,7 @@ void async function () { const argv = minimist(process.argv.slice(2)) /** Default to all tables */ - const tables = argv.tables ? argv.tables.split(',') : ['accounts', 'nonces', 'users', 'users_accounts'] + const tables = argv.tables ? argv.tables.split(',') : ['accounts', 'nonces', 'users', 'user_accounts'] let sqlSchema = '-- Generated by @casimir/data/scripts/postgres.ts\n\n' for (const table of tables) { const tableSchema = tableSchemas[table] as JsonSchema diff --git a/common/data/src/index.ts b/common/data/src/index.ts index e1712983b..96332ff68 100644 --- a/common/data/src/index.ts +++ b/common/data/src/index.ts @@ -3,7 +3,7 @@ import nonceSchema from './schemas/nonce.schema.json' import userSchema from './schemas/user.schema.json' import eventSchema from './schemas/event.schema.json' import aggSchema from './schemas/agg.schema.json' -import usersAccountsSchema from './schemas/users_accounts.schema.json' +import userAccountSchema from './schemas/user_account.schema.json' import operatorStore from './mock/operator.store.json' import validatorStore from './mock/validator.store.json' import accountStore from './mock/account.store.json' @@ -16,7 +16,7 @@ export { accountSchema, nonceSchema, userSchema, - usersAccountsSchema, + userAccountSchema, eventSchema, aggSchema, accountStore, diff --git a/common/data/src/providers/schema.ts b/common/data/src/providers/schema.ts index 39c5387c0..3dfe359f0 100644 --- a/common/data/src/providers/schema.ts +++ b/common/data/src/providers/schema.ts @@ -1,5 +1,6 @@ import * as glue from '@aws-cdk/aws-glue-alpha' import { JsonSchema } from '../interfaces/JsonSchema' +import { snakeCase } from '@casimir/helpers' export type JsonType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null' export type GlueType = glue.Type @@ -91,7 +92,7 @@ export class Schema { if (compositeKey) columns.push(`PRIMARY KEY (${compositeKey})`) /** Make table name plural of schema objects (todo: check edge-cases) */ - const tableName = this.getTitle().toLowerCase() + 's' + const tableName = this.getTitle() const queryString = uniqueFields.length > 0 ? `CREATE TABLE ${tableName} (\n\t${columns.join(',\n\t')}, \n\tUNIQUE (${uniqueFields.join(', ')}));` : `CREATE TABLE ${tableName} (\n\t${columns.join(',\n\t')}\n);` return queryString @@ -101,6 +102,6 @@ export class Schema { * Get the title of the JSON schema object. */ getTitle(): string { - return this.jsonSchema.title + return snakeCase(this.jsonSchema.title) + 's' } } \ No newline at end of file diff --git a/common/data/src/schemas/users_accounts.schema.json b/common/data/src/schemas/user_account.schema.json similarity index 89% rename from common/data/src/schemas/users_accounts.schema.json rename to common/data/src/schemas/user_account.schema.json index d557ad662..286842b65 100644 --- a/common/data/src/schemas/users_accounts.schema.json +++ b/common/data/src/schemas/user_account.schema.json @@ -1,7 +1,7 @@ { - "$id": "https://casimir.co/users_accounts.schema.json", + "$id": "https://casimir.co/user_account.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", - "title": "User_Account", + "title": "User Account", "type": "object", "properties": { "account_id": { diff --git a/scripts/local/dev.ts b/scripts/local/dev.ts index 623b2b11a..e37b5e522 100644 --- a/scripts/local/dev.ts +++ b/scripts/local/dev.ts @@ -19,7 +19,7 @@ void async function () { web: { chains: ['ethereum'], services: ['users'], - tables: ['accounts', 'nonces', 'users', 'users_accounts'], + tables: ['accounts', 'nonces', 'users', 'user_accounts'], } } diff --git a/services/users/src/routes/auth.ts b/services/users/src/routes/auth.ts index 0a81e9e85..469ae6eae 100644 --- a/services/users/src/routes/auth.ts +++ b/services/users/src/routes/auth.ts @@ -2,7 +2,7 @@ import express from 'express' import useDB from '../providers/db' import Session from 'supertokens-node/recipe/session' import useEthers from '../providers/ethers' -import { Account, LoginCredentials } from '@casimir/types' +import { Account, LoginCredentials, User } from '@casimir/types' const { verifyMessage } = useEthers() const { getUser, upsertNonce, addUser } = useDB() @@ -38,7 +38,7 @@ router.post('/login', async (req: express.Request, res: express.Response) => { address, createdAt: now, updatedAt: now, - } + } as User const account = { address, currency,