From 90250e8a499cd73a95decd0d241049a210bf3197 Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:02:49 -0400 Subject: [PATCH 1/8] migration script --- migrations/4_merge_nonces_into_vaults.sh | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 migrations/4_merge_nonces_into_vaults.sh diff --git a/migrations/4_merge_nonces_into_vaults.sh b/migrations/4_merge_nonces_into_vaults.sh new file mode 100644 index 0000000..5196a87 --- /dev/null +++ b/migrations/4_merge_nonces_into_vaults.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +# This script merges the nonces table into the vaults table by: +# 1) Adding a NOT NULL DEFAULT 0 nonce column to vaults +# 2) Enforcing non-empty controllers array via a CHECK constraint +# 3) Backfilling nonce values from the legacy nonces table + +APP_NAME="" + +# Function to display usage +usage() { + echo "Usage: $0 --app-name oya-api" + exit 1 +} + +# Parse command-line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --app-name) APP_NAME="$2"; shift ;; + *) echo "Unknown parameter passed: $1"; usage; exit 1 ;; + esac + shift +done + +# Verify required arguments +if [ -z "$APP_NAME" ]; then + usage +fi + +echo "Merging nonces into vaults (app: $APP_NAME)..." +heroku pg:psql --app "$APP_NAME" DATABASE_URL < 0); + END IF; +END +\$\$; + +-- 3) Backfill nonce from legacy nonces table if present +DO +\$\$ +BEGIN + IF EXISTS ( + SELECT 1 + FROM information_schema.tables + WHERE table_schema = 'public' AND table_name = 'nonces' + ) THEN + UPDATE vaults v + SET nonce = n.nonce + FROM nonces n + WHERE v.vault = n.vault; + END IF; +END +\$\$; +EOF + +echo "Merge complete: vaults.nonce added, controllers non-empty enforced, nonces backfilled." + + From a0c54095f2f261b6acdb59e62099814123cfe60d Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:04:21 -0400 Subject: [PATCH 2/8] update controllers and remove nonces from required tables --- src/config/dbSettings.ts | 1 - src/controllers.ts | 17 ++++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/config/dbSettings.ts b/src/config/dbSettings.ts index a8b7826..bc336b4 100644 --- a/src/config/dbSettings.ts +++ b/src/config/dbSettings.ts @@ -36,7 +36,6 @@ export const REQUIRED_TABLES = [ 'bundles', 'cids', 'balances', - 'nonces', 'proposers', 'vaults', 'deposits', diff --git a/src/controllers.ts b/src/controllers.ts index 9ffad8a..53eb2c1 100644 --- a/src/controllers.ts +++ b/src/controllers.ts @@ -295,7 +295,7 @@ export const getVaultNonce = async (req: Request, res: Response) => { const { vault } = req.params try { const result = await pool.query( - 'SELECT nonce FROM nonces WHERE LOWER(vault) = LOWER($1)', + 'SELECT nonce FROM vaults WHERE LOWER(vault) = LOWER($1)', [vault] ) logger.info('Getting vault nonce:', result.rows) @@ -320,14 +320,13 @@ export const setVaultNonce = async (req: Request, res: Response) => { try { const result = await pool.query( - `INSERT INTO nonces (vault, nonce) - VALUES (LOWER($1), $2) - ON CONFLICT (LOWER(vault)) - DO UPDATE SET nonce = EXCLUDED.nonce - RETURNING *`, + `UPDATE vaults SET nonce = $2 WHERE LOWER(vault) = LOWER($1) RETURNING vault, nonce`, [vault, nonce] ) - res.status(201).json(result.rows[0]) + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Vault not found' }) + } + res.status(200).json(result.rows[0]) } catch (err) { logger.error(err) res.status(500).json({ error: 'Internal Server Error' }) @@ -397,9 +396,9 @@ export const getMetrics = async (req: Request, res: Response) => { const latestCIDNonce = latestCIDResult.rows.length > 0 ? latestCIDResult.rows[0].nonce : null - // Get unique vault count + // Get vault count const vaultCountResult = await pool.query( - 'SELECT COUNT(DISTINCT vault) FROM nonces' + 'SELECT COUNT(*) FROM vaults' ) const totalVaults = parseInt(vaultCountResult.rows[0].count) From c71443a2ffeb8d62d18efe0714d6bfeb3096998b Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:06:13 -0400 Subject: [PATCH 3/8] update proposer to use vaults table for nonce updates --- src/controllers.ts | 4 +--- src/proposer.ts | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/controllers.ts b/src/controllers.ts index 53eb2c1..36eed11 100644 --- a/src/controllers.ts +++ b/src/controllers.ts @@ -397,9 +397,7 @@ export const getMetrics = async (req: Request, res: Response) => { latestCIDResult.rows.length > 0 ? latestCIDResult.rows[0].nonce : null // Get vault count - const vaultCountResult = await pool.query( - 'SELECT COUNT(*) FROM vaults' - ) + const vaultCountResult = await pool.query('SELECT COUNT(*) FROM vaults') const totalVaults = parseInt(vaultCountResult.rows[0].count) // Get latest bundle nonce diff --git a/src/proposer.ts b/src/proposer.ts index 45f98c3..d8df1c5 100644 --- a/src/proposer.ts +++ b/src/proposer.ts @@ -449,9 +449,9 @@ async function getLatestNonce(): Promise { * Returns 0 if no nonce is found for the vault. */ async function getVaultNonce(vaultId: number | string): Promise { - const result = await pool.query('SELECT nonce FROM nonces WHERE vault = $1', [ - String(vaultId), - ]) + const result = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [ + String(vaultId), + ]) if (result.rows.length === 0) { return 0 } @@ -667,14 +667,14 @@ async function saveBundleData( if (Array.isArray(bundleData.bundle)) { for (const execution of bundleData.bundle) { const vaultNonce = execution.intention.nonce - const vault = execution.from - await pool.query( - `INSERT INTO nonces (vault, nonce) - VALUES ($1, $2) - ON CONFLICT (vault) - DO UPDATE SET nonce = EXCLUDED.nonce`, - [String(vault), vaultNonce] - ) + const vault = execution.from + const updateResult = await pool.query( + `UPDATE vaults SET nonce = $2 WHERE vault = $1`, + [String(vault), vaultNonce] + ) + if (updateResult.rowCount === 0) { + logger.warn(`Nonce update skipped: vault ${String(vault)} does not exist`) + } } } } From 17922a74416def5317ae57491ded7ebcbfb62387 Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:08:02 -0400 Subject: [PATCH 4/8] enforce that controllers cannot be empty --- src/controllers.ts | 8 ++++++++ src/proposer.ts | 24 +++++++++++++----------- src/utils/vaults.ts | 22 +++++++++++++++++++--- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/controllers.ts b/src/controllers.ts index 36eed11..1544112 100644 --- a/src/controllers.ts +++ b/src/controllers.ts @@ -753,6 +753,14 @@ export const removeControllerFromVault = async ( if (inner instanceof Error && inner.message === 'Vault not found') { return res.status(404).json({ error: 'Vault not found' }) } + if ( + inner instanceof Error && + inner.message === 'Controllers cannot be empty' + ) { + return res + .status(400) + .json({ error: 'Cannot remove the last controller from a vault' }) + } throw inner } } catch (error) { diff --git a/src/proposer.ts b/src/proposer.ts index d8df1c5..bc33367 100644 --- a/src/proposer.ts +++ b/src/proposer.ts @@ -449,9 +449,9 @@ async function getLatestNonce(): Promise { * Returns 0 if no nonce is found for the vault. */ async function getVaultNonce(vaultId: number | string): Promise { - const result = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [ - String(vaultId), - ]) + const result = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [ + String(vaultId), + ]) if (result.rows.length === 0) { return 0 } @@ -667,14 +667,16 @@ async function saveBundleData( if (Array.isArray(bundleData.bundle)) { for (const execution of bundleData.bundle) { const vaultNonce = execution.intention.nonce - const vault = execution.from - const updateResult = await pool.query( - `UPDATE vaults SET nonce = $2 WHERE vault = $1`, - [String(vault), vaultNonce] - ) - if (updateResult.rowCount === 0) { - logger.warn(`Nonce update skipped: vault ${String(vault)} does not exist`) - } + const vault = execution.from + const updateResult = await pool.query( + `UPDATE vaults SET nonce = $2 WHERE vault = $1`, + [String(vault), vaultNonce] + ) + if (updateResult.rowCount === 0) { + logger.warn( + `Nonce update skipped: vault ${String(vault)} does not exist` + ) + } } } } diff --git a/src/utils/vaults.ts b/src/utils/vaults.ts index f10441e..60058a2 100644 --- a/src/utils/vaults.ts +++ b/src/utils/vaults.ts @@ -25,7 +25,10 @@ export async function updateVaultControllers( vaultId: number, controllers: string[] ): Promise { - const lowercasedControllers = controllers.map((c) => c.toLowerCase()) + if (!Array.isArray(controllers) || controllers.length === 0) { + throw new Error('Controllers cannot be empty') + } + const lowercasedControllers = controllers.map((c) => c.toLowerCase()) try { const result = await pool.query( `UPDATE vaults SET controllers = $2 WHERE vault = $1`, @@ -174,7 +177,7 @@ export async function removeControllerFromVault( ): Promise { const lower = controller.toLowerCase() try { - const result = await pool.query( + const result = await pool.query( `UPDATE vaults SET controllers = array_remove(controllers, LOWER($2)) WHERE vault = $1 @@ -184,7 +187,20 @@ export async function removeControllerFromVault( if (result.rows.length === 0) { throw new Error('Vault not found') } - return (result.rows[0].controllers as string[]).map((c) => c.toLowerCase()) + const updated = (result.rows[0].controllers as string[]).map((c) => + c.toLowerCase() + ) + if (updated.length === 0) { + // Revert removal to satisfy invariant and report an error + await pool.query( + `UPDATE vaults + SET controllers = ARRAY[LOWER($2)] || controllers + WHERE vault = $1`, + [String(vaultId), lower] + ) + throw new Error('Controllers cannot be empty') + } + return updated } catch (error) { logger.error( `Failed to remove controller ${controller} from vault ${vaultId}:`, From fcb27a416e77c3716dea7da5a0d7f2d63d172bc1 Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:10:08 -0400 Subject: [PATCH 5/8] remove nonces table from db setup --- scripts/setup-db.js | 3 +-- scripts/setup-test-db.js | 3 +-- scripts/shared/db-setup.js | 35 +++++++++++------------------------ src/utils/vaults.ts | 34 +++++++++++++++++----------------- test/helpers/testServer.ts | 6 +++--- 5 files changed, 33 insertions(+), 48 deletions(-) diff --git a/scripts/setup-db.js b/scripts/setup-db.js index 5063cf5..bc65b8a 100755 --- a/scripts/setup-db.js +++ b/scripts/setup-db.js @@ -50,9 +50,8 @@ ${chalk.yellow('Tables Created:')} - bundles : Stores bundle data with IPFS CIDs - cids : Tracks submitted CIDs - balances : Manages vault token balances - - nonces : Tracks vault nonces - proposers : Records block proposers - - vaults : Maps vault IDs to controllers and rules + - vaults : Maps vault IDs to controllers and rules; stores nonce ${chalk.red('Warning:')} Using --drop-existing will DELETE ALL EXISTING DATA! `) diff --git a/scripts/setup-test-db.js b/scripts/setup-test-db.js index 0db94cb..fbdb770 100755 --- a/scripts/setup-test-db.js +++ b/scripts/setup-test-db.js @@ -51,9 +51,8 @@ ${chalk.yellow('Tables Created:')} - bundles : Stores bundle data with IPFS CIDs - cids : Tracks submitted CIDs - balances : Manages vault token balances - - nonces : Tracks vault nonces - proposers : Records block proposers - - vaults : Maps vault IDs to controllers and rules + - vaults : Maps vault IDs to controllers and rules; stores nonce ${chalk.red('Warning:')} Using --drop-existing will DELETE ALL EXISTING DATA! `) diff --git a/scripts/shared/db-setup.js b/scripts/shared/db-setup.js index 1a00208..433383a 100644 --- a/scripts/shared/db-setup.js +++ b/scripts/shared/db-setup.js @@ -51,15 +51,6 @@ CREATE TABLE IF NOT EXISTS balances ( UNIQUE (vault, token) ); --- Create the nonces table (tracks vault nonces) -CREATE TABLE IF NOT EXISTS nonces ( - id SERIAL PRIMARY KEY, - vault TEXT NOT NULL, - nonce INTEGER NOT NULL, - timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, - UNIQUE (vault) -); - -- Create the proposers table (records block proposers) CREATE TABLE IF NOT EXISTS proposers ( id SERIAL PRIMARY KEY, @@ -71,6 +62,7 @@ CREATE TABLE IF NOT EXISTS proposers ( CREATE TABLE IF NOT EXISTS vaults ( vault TEXT PRIMARY KEY, controllers TEXT[] NOT NULL, + nonce INTEGER NOT NULL DEFAULT 0, rules TEXT, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP ); @@ -103,7 +95,6 @@ CREATE TABLE IF NOT EXISTS deposit_assignment_events ( */ export const createIndexesSql = ` -- Create case-insensitive unique indexes for vault/token lookups -CREATE UNIQUE INDEX IF NOT EXISTS unique_lower_vault_nonces ON nonces (LOWER(vault)); CREATE UNIQUE INDEX IF NOT EXISTS unique_lower_vault_token_balances ON balances (LOWER(vault), LOWER(token)); -- Create indexes for Filecoin tracking @@ -133,7 +124,6 @@ DROP TABLE IF EXISTS deposits CASCADE; DROP TABLE IF EXISTS bundles CASCADE; DROP TABLE IF EXISTS cids CASCADE; DROP TABLE IF EXISTS balances CASCADE; -DROP TABLE IF EXISTS nonces CASCADE; DROP TABLE IF EXISTS proposers CASCADE; DROP TABLE IF EXISTS vaults CASCADE; ` @@ -178,8 +168,8 @@ export async function setupDatabase(options) { console.log(chalk.red('⚠️ Dropping existing tables...')) if (!forceDropConfirm) { - console.log(chalk.red('\n⚠️ WARNING: This will DELETE ALL DATA in the following tables:')) - console.log(chalk.red(' - bundles, cids, balances, nonces, proposers')) + console.log(chalk.red('\n⚠️ WARNING: This will DELETE ALL DATA in the following tables:')) + console.log(chalk.red(' - bundles, cids, balances, proposers, vaults, deposits, deposit_assignment_events')) console.log(chalk.yellow('\nTo confirm, set FORCE_DROP=true or remove --drop-existing flag')) await pool.end() process.exit(1) @@ -201,11 +191,11 @@ export async function setupDatabase(options) { // Verify tables were created console.log(chalk.yellow('\nVerifying database schema...')) - const result = await pool.query(` + const result = await pool.query(` SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' - AND table_name IN ('bundles', 'cids', 'balances', 'nonces', 'proposers', 'vaults', 'deposits', 'deposit_assignment_events') + AND table_name IN ('bundles', 'cids', 'balances', 'proposers', 'vaults', 'deposits', 'deposit_assignment_events') ORDER BY table_name `) @@ -216,15 +206,12 @@ export async function setupDatabase(options) { }) // Check if we need to update existing data to lowercase - const balancesCount = await pool.query('SELECT COUNT(*) FROM balances') - const noncesCount = await pool.query('SELECT COUNT(*) FROM nonces') - - if (parseInt(balancesCount.rows[0].count) > 0 || parseInt(noncesCount.rows[0].count) > 0) { - console.log(chalk.yellow('\nUpdating existing data to lowercase...')) - await pool.query('UPDATE nonces SET vault = LOWER(vault)') - await pool.query('UPDATE balances SET vault = LOWER(vault), token = LOWER(token)') - console.log(chalk.green('✓ Existing data updated')) - } + const balancesCount = await pool.query('SELECT COUNT(*) FROM balances') + if (parseInt(balancesCount.rows[0].count) > 0) { + console.log(chalk.yellow('\nUpdating existing data to lowercase...')) + await pool.query('UPDATE balances SET vault = LOWER(vault), token = LOWER(token)') + console.log(chalk.green('✓ Existing data updated')) + } console.log(chalk.green(`\n✅ ${environment} database is ready for use!\n`)) diff --git a/src/utils/vaults.ts b/src/utils/vaults.ts index 60058a2..fe79e01 100644 --- a/src/utils/vaults.ts +++ b/src/utils/vaults.ts @@ -25,10 +25,10 @@ export async function updateVaultControllers( vaultId: number, controllers: string[] ): Promise { - if (!Array.isArray(controllers) || controllers.length === 0) { - throw new Error('Controllers cannot be empty') - } - const lowercasedControllers = controllers.map((c) => c.toLowerCase()) + if (!Array.isArray(controllers) || controllers.length === 0) { + throw new Error('Controllers cannot be empty') + } + const lowercasedControllers = controllers.map((c) => c.toLowerCase()) try { const result = await pool.query( `UPDATE vaults SET controllers = $2 WHERE vault = $1`, @@ -177,7 +177,7 @@ export async function removeControllerFromVault( ): Promise { const lower = controller.toLowerCase() try { - const result = await pool.query( + const result = await pool.query( `UPDATE vaults SET controllers = array_remove(controllers, LOWER($2)) WHERE vault = $1 @@ -187,20 +187,20 @@ export async function removeControllerFromVault( if (result.rows.length === 0) { throw new Error('Vault not found') } - const updated = (result.rows[0].controllers as string[]).map((c) => - c.toLowerCase() - ) - if (updated.length === 0) { - // Revert removal to satisfy invariant and report an error - await pool.query( - `UPDATE vaults + const updated = (result.rows[0].controllers as string[]).map((c) => + c.toLowerCase() + ) + if (updated.length === 0) { + // Revert removal to satisfy invariant and report an error + await pool.query( + `UPDATE vaults SET controllers = ARRAY[LOWER($2)] || controllers WHERE vault = $1`, - [String(vaultId), lower] - ) - throw new Error('Controllers cannot be empty') - } - return updated + [String(vaultId), lower] + ) + throw new Error('Controllers cannot be empty') + } + return updated } catch (error) { logger.error( `Failed to remove controller ${controller} from vault ${vaultId}:`, diff --git a/test/helpers/testServer.ts b/test/helpers/testServer.ts index 71d7391..43ba05e 100644 --- a/test/helpers/testServer.ts +++ b/test/helpers/testServer.ts @@ -72,9 +72,9 @@ export async function clearTestDatabase(pool: Pool): Promise { const client = await pool.connect() try { // Clear application tables - await client.query( - 'TRUNCATE TABLE bundles, cids, balances, nonces, proposers, vaults CASCADE' - ) + await client.query( + 'TRUNCATE TABLE bundles, cids, balances, proposers, vaults CASCADE' + ) } finally { client.release() } From ac4ca2c159420044119471b6639cbc8c989fc7b6 Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:13:55 -0400 Subject: [PATCH 6/8] update migrations to remove nonces table and delete existing table --- migrations/1_start.sh | 21 +-------------------- migrations/4_merge_nonces_into_vaults.sh | 5 ++++- test/helpers/testServer.ts | 6 +++--- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/migrations/1_start.sh b/migrations/1_start.sh index f36ccd8..e3b4d0a 100644 --- a/migrations/1_start.sh +++ b/migrations/1_start.sh @@ -28,7 +28,6 @@ heroku pg:psql --app "$APP_NAME" DATABASE_URL < { const client = await pool.connect() try { // Clear application tables - await client.query( - 'TRUNCATE TABLE bundles, cids, balances, proposers, vaults CASCADE' - ) + await client.query( + 'TRUNCATE TABLE bundles, cids, balances, proposers, vaults CASCADE' + ) } finally { client.release() } From 74e31460b10d9187104ceb142b30c7d95a7e1a4f Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:16:20 -0400 Subject: [PATCH 7/8] update vaults db test --- test/integration/vaults.db.test.ts | 40 +++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/test/integration/vaults.db.test.ts b/test/integration/vaults.db.test.ts index fa2a836..f8c3c3f 100644 --- a/test/integration/vaults.db.test.ts +++ b/test/integration/vaults.db.test.ts @@ -13,13 +13,13 @@ import { } from 'bun:test' import { pool } from '../../src/db.js' import { - createVaultRow, - addControllerToVault, - removeControllerFromVault, - setRulesForVault, - getRulesForVault, - getControllersForVault, - getVaultsForController, + createVaultRow, + addControllerToVault, + removeControllerFromVault, + setRulesForVault, + getRulesForVault, + getControllersForVault, + getVaultsForController, } from '../../src/utils/vaults.js' const TEST_VAULT_1 = 5001 @@ -73,11 +73,27 @@ describe('Vault utils (DB)', () => { ) }) - test('removeControllerFromVault: update-only', async () => { - await createVaultRow(TEST_VAULT_1, CTRL_1, null) - const removed = await removeControllerFromVault(TEST_VAULT_1, CTRL_1) - expect(removed).toEqual([]) - }) + test('removeControllerFromVault: cannot remove last controller', async () => { + await createVaultRow(TEST_VAULT_1, CTRL_1, null) + let threw = false + try { + await removeControllerFromVault(TEST_VAULT_1, CTRL_1) + } catch (e) { + threw = e instanceof Error && e.message === 'Controllers cannot be empty' + } + expect(threw).toBe(true) + const controllers = await getControllersForVault(TEST_VAULT_1) + expect(controllers).toEqual([CTRL_1.toLowerCase()]) + }) + + test('vault nonce defaults to 0 and can be updated', async () => { + await createVaultRow(TEST_VAULT_1, CTRL_1, null) + const initial = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [String(TEST_VAULT_1)]) + expect(initial.rows[0].nonce).toBe(0) + await pool.query('UPDATE vaults SET nonce = $2 WHERE vault = $1', [String(TEST_VAULT_1), 7]) + const updated = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [String(TEST_VAULT_1)]) + expect(updated.rows[0].nonce).toBe(7) + }) test('setRulesForVault and getRulesForVault: update-only', async () => { await createVaultRow(TEST_VAULT_1, CTRL_1, null) From d21b2319758c9d003603dc963c67b2b7c5b715dc Mon Sep 17 00:00:00 2001 From: Damian Kuthoore Date: Wed, 29 Oct 2025 18:19:32 -0400 Subject: [PATCH 8/8] formatting fix --- test/integration/vaults.db.test.ts | 63 +++++++++++++++++------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/test/integration/vaults.db.test.ts b/test/integration/vaults.db.test.ts index f8c3c3f..c71e8eb 100644 --- a/test/integration/vaults.db.test.ts +++ b/test/integration/vaults.db.test.ts @@ -13,13 +13,13 @@ import { } from 'bun:test' import { pool } from '../../src/db.js' import { - createVaultRow, - addControllerToVault, - removeControllerFromVault, - setRulesForVault, - getRulesForVault, - getControllersForVault, - getVaultsForController, + createVaultRow, + addControllerToVault, + removeControllerFromVault, + setRulesForVault, + getRulesForVault, + getControllersForVault, + getVaultsForController, } from '../../src/utils/vaults.js' const TEST_VAULT_1 = 5001 @@ -73,27 +73,36 @@ describe('Vault utils (DB)', () => { ) }) - test('removeControllerFromVault: cannot remove last controller', async () => { - await createVaultRow(TEST_VAULT_1, CTRL_1, null) - let threw = false - try { - await removeControllerFromVault(TEST_VAULT_1, CTRL_1) - } catch (e) { - threw = e instanceof Error && e.message === 'Controllers cannot be empty' - } - expect(threw).toBe(true) - const controllers = await getControllersForVault(TEST_VAULT_1) - expect(controllers).toEqual([CTRL_1.toLowerCase()]) - }) + test('removeControllerFromVault: cannot remove last controller', async () => { + await createVaultRow(TEST_VAULT_1, CTRL_1, null) + let threw = false + try { + await removeControllerFromVault(TEST_VAULT_1, CTRL_1) + } catch (e) { + threw = e instanceof Error && e.message === 'Controllers cannot be empty' + } + expect(threw).toBe(true) + const controllers = await getControllersForVault(TEST_VAULT_1) + expect(controllers).toEqual([CTRL_1.toLowerCase()]) + }) - test('vault nonce defaults to 0 and can be updated', async () => { - await createVaultRow(TEST_VAULT_1, CTRL_1, null) - const initial = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [String(TEST_VAULT_1)]) - expect(initial.rows[0].nonce).toBe(0) - await pool.query('UPDATE vaults SET nonce = $2 WHERE vault = $1', [String(TEST_VAULT_1), 7]) - const updated = await pool.query('SELECT nonce FROM vaults WHERE vault = $1', [String(TEST_VAULT_1)]) - expect(updated.rows[0].nonce).toBe(7) - }) + test('vault nonce defaults to 0 and can be updated', async () => { + await createVaultRow(TEST_VAULT_1, CTRL_1, null) + const initial = await pool.query( + 'SELECT nonce FROM vaults WHERE vault = $1', + [String(TEST_VAULT_1)] + ) + expect(initial.rows[0].nonce).toBe(0) + await pool.query('UPDATE vaults SET nonce = $2 WHERE vault = $1', [ + String(TEST_VAULT_1), + 7, + ]) + const updated = await pool.query( + 'SELECT nonce FROM vaults WHERE vault = $1', + [String(TEST_VAULT_1)] + ) + expect(updated.rows[0].nonce).toBe(7) + }) test('setRulesForVault and getRulesForVault: update-only', async () => { await createVaultRow(TEST_VAULT_1, CTRL_1, null)