import type * as Db from '../../db/Db.js' import * as RoutesTransferTransactions from '../../db/tables/routesTransferTransactions.js' import * as Organizations from '../../db/tables/organizations.js' import * as Projects from '../../db/tables/projects.js' import * as Deposit from '../../internal/routes/Deposit.js' import * as DepositAddress from '../../internal/routes/DepositAddress.js' import * as Transfer from '../../internal/routes/Transfer.js' import * as TestAdmin from '../../../test/Admin.js' import * as TestApp from '../../../test/App.js' import * as TestRoutes from '../../../test/Routes.js' import * as AdminRoutes from './routes.js' describe('GET /routes/summary', () => { test('counts each active resource in one lifecycle bucket', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) await seedTransfer(db, organization.id, project.id) await seedDeposit(db, organization.id, project.id) const response = await client.routes.summary.$get({ query: {} }) const body = await TestApp.json(response, AdminRoutes.schema.getRoutesSummary.Response) expect(response.status).toBe(200) expect(body).toMatchObject({ actionRequired: 0, inProgress: 2, resources: { depositAddresses: { actionRequired: 0, inProgress: 0 }, deposits: { actionRequired: 0, inProgress: 1 }, transfers: { actionRequired: 0, inProgress: 1 }, }, }) }) test('applies the transaction method without counting deposit-address resources', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) await seedTransfer(db, organization.id, project.id) await seedDeposit(db, organization.id, project.id) const response = await client.routes.summary.$get({ query: { method: 'transaction' }, }) const body = await TestApp.json(response, AdminRoutes.schema.getRoutesSummary.Response) expect(body.inProgress).toBe(1) expect(body.resources.deposits.inProgress).toBe(0) }) }) describe('GET /routes/transfers', () => { test('searches transaction references and includes attribution', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { record, transactionRef } = await seedTransfer(db, organization.id, project.id) const response = await client.routes.transfers.$get({ query: { query: transactionRef } }) const body = await TestApp.json(response, AdminRoutes.schema.listRoutesTransfers.Response) expect(body.data).toHaveLength(1) expect(body.data[0]).toMatchObject({ id: record.id, organization: { id: organization.id, name: organization.name }, project: { id: project.id, name: project.name }, status: 'processing', }) }) test('applies the in-progress preset across active statuses', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { record } = await seedTransfer(db, organization.id, project.id) await Transfer.create(db, { apiKeyId: 'key_admin_routes', environment: 'production', id: Transfer.generateId(new Date('2026-08-26T00:00:02.000Z')), orgId: organization.id, projectId: project.id, providerState: { secret: 'hidden' }, snapshot: TestRoutes.transferSnapshot({ provider: { id: 'stargate', name: 'Stargate' }, }), }) const response = await client.routes.transfers.$get({ query: { inProgress: 'true' }, }) const body = await TestApp.json(response, AdminRoutes.schema.listRoutesTransfers.Response) expect(body.data.map(({ id }) => id)).toEqual([record.id]) }) test('filters by multiple lifecycle statuses', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { record } = await seedTransfer(db, organization.id, project.id) const awaiting = await Transfer.create(db, { apiKeyId: 'key_admin_routes', environment: 'production', id: Transfer.generateId(new Date('2026-08-26T00:00:02.000Z')), orgId: organization.id, projectId: project.id, providerState: { secret: 'hidden' }, snapshot: TestRoutes.transferSnapshot({ provider: { id: 'stargate', name: 'Stargate' }, }), }) const response = await client.routes.transfers.$get({ query: { status: 'awaiting-source,processing' }, }) const body = await TestApp.json(response, AdminRoutes.schema.listRoutesTransfers.Response) expect(body.data.map(({ id }) => id).sort()).toEqual([awaiting.id, record.id].sort()) }) }) describe('GET /routes/transfers/:id', () => { test('returns lifecycle events and safe transaction references', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { record, transactionRef } = await seedTransfer(db, organization.id, project.id) const response = await client.routes.transfers[':id'].$get({ param: { id: record.id }, }) const body = await TestApp.json(response, AdminRoutes.schema.getRoutesTransfer.Response) expect(body.events.map(({ status }) => status)).toEqual(['awaiting-source', 'processing']) expect(body.transactions).toEqual([ { chainId: 'eip155:8453', createdAt: '2026-08-26T00:00:01.000Z', role: 'source', transactionRef, }, ]) expect(body).not.toHaveProperty('providerState') }) }) describe('GET /routes/deposit-addresses', () => { test('searches deposit addresses and exposes safe polling state', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address } = await seedDeposit(db, organization.id, project.id) const response = await client.routes['deposit-addresses'].$get({ query: { query: address.address }, }) const body = await TestApp.json( response, AdminRoutes.schema.listRoutesDepositAddresses.Response, ) expect(body.data[0]).toMatchObject({ consecutivePollFailures: 0, id: address.id, providerRequestIds: ['provider_address_request'], }) expect(body.data[0]).not.toHaveProperty('providerState') }) test('applies the needs-attention preset', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address } = await seedDeposit(db, organization.id, project.id) await DepositAddress.transition(db, { expectedVersion: address.version, id: address.id, status: 'action-required', }) const response = await client.routes['deposit-addresses'].$get({ query: { needsAttention: 'true' }, }) const body = await TestApp.json( response, AdminRoutes.schema.listRoutesDepositAddresses.Response, ) expect(body.data.map(({ id }) => id)).toEqual([address.id]) }) test('filters terminal deactivated addresses', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address } = await seedDeposit(db, organization.id, project.id) await DepositAddress.transition(db, { expectedVersion: address.version, id: address.id, status: 'deactivated', }) const response = await client.routes['deposit-addresses'].$get({ query: { status: 'deactivated' }, }) const body = await TestApp.json( response, AdminRoutes.schema.listRoutesDepositAddresses.Response, ) expect(body.data.map(({ id, status }) => ({ id, status }))).toEqual([ { id: address.id, status: 'deactivated' }, ]) }) }) describe('GET /routes/deposit-addresses/:id', () => { test('returns an address created before the route ID rename', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address } = await seedDeposit(db, organization.id, project.id, { addressId: 'fda_001785792000000_2ZPE2gvateYEQ0dQslgvkhjx', }) const response = await client.routes['deposit-addresses'][':id'].$get({ param: { id: address.id }, }) const body = await TestApp.json(response, AdminRoutes.schema.getRoutesDepositAddress.Response) expect(body.id).toBe(address.id) }) test('returns 404 for an unknown address', async () => { const { client } = TestAdmin.setup() const response = await client.routes['deposit-addresses'][':id'].$get({ param: { id: 'rda_unknown' }, }) expect(response.status).toBe(404) }) }) describe('GET /routes/deposits', () => { test('searches source transactions and omits raw private state', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { deposit, transactionRef } = await seedDeposit(db, organization.id, project.id) const response = await client.routes.deposits.$get({ query: { query: transactionRef } }) const body = await TestApp.json(response, AdminRoutes.schema.listRoutesDeposits.Response) expect(body.data[0]).toMatchObject({ id: deposit.id, retryAttempts: 2, status: 'bridging', }) expect(body.data[0]).not.toHaveProperty('providerState') expect(body.data[0]).not.toHaveProperty('retryState') expect(body.data[0]).not.toHaveProperty('settlementTransaction') }) test('returns provider and Tempo subsidies with token details', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { deposit } = await seedDeposit(db, organization.id, project.id, { subsidies: true, }) const response = await client.routes.deposits.$get({ query: { query: deposit.id } }) const body = await TestApp.json(response, AdminRoutes.schema.listRoutesDeposits.Response) expect(body.data[0]?.subsidies).toEqual([ { amount: { baseUnits: '23838', currency: 'USD', decimals: 6, formatted: '0.023838' }, provider: 'relay', token: deposit.snapshot.sourceToken, }, { amount: { baseUnits: '2', currency: 'USD', decimals: 6, formatted: '0.000002' }, provider: 'tempo', token: deposit.snapshot.destinationToken, }, ]) }) test('lists resources created before the route ID rename', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address, deposit } = await seedDeposit(db, organization.id, project.id, { addressId: 'fda_001785792000001_2ZPE2gvateYEQ0dQslgvkhjx', depositId: 'fdp_001785792060001_2ZPE2gvateYEQ0dQslgvkhjx', }) const addressResponse = await client.routes['deposit-addresses'].$get({ query: { query: address.address }, }) const addressBody = await TestApp.json( addressResponse, AdminRoutes.schema.listRoutesDepositAddresses.Response, ) const depositResponse = await client.routes.deposits.$get({ query: { depositAddressId: address.id }, }) const depositBody = await TestApp.json( depositResponse, AdminRoutes.schema.listRoutesDeposits.Response, ) expect(addressBody.data.map(({ id }) => id)).toEqual([address.id]) expect(depositBody.data.map(({ id }) => id)).toEqual([deposit.id]) }) }) describe('GET /routes/deposits/:id', () => { test('returns the associated deposit address', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address, deposit } = await seedDeposit(db, organization.id, project.id) const response = await client.routes.deposits[':id'].$get({ param: { id: deposit.id }, }) const body = await TestApp.json(response, AdminRoutes.schema.getRoutesDeposit.Response) expect(body.depositAddress.id).toBe(address.id) }) test('returns a deposit created before the route ID rename', async () => { const { client, db } = TestAdmin.setup() const { organization, project } = await seedAttribution(db) const { address, deposit } = await seedDeposit(db, organization.id, project.id, { addressId: 'fda_001785792000002_2ZPE2gvateYEQ0dQslgvkhjx', depositId: 'fdp_001785792060002_2ZPE2gvateYEQ0dQslgvkhjx', }) const response = await client.routes.deposits[':id'].$get({ param: { id: deposit.id }, }) const body = await TestApp.json(response, AdminRoutes.schema.getRoutesDeposit.Response) expect(body.depositAddress.id).toBe(address.id) expect(body.id).toBe(deposit.id) }) }) async function seedAttribution(db: Db.Db) { const organization = await Organizations.create(db, { id: 'org_admin_routes', name: 'Acme', }) const project = await Projects.create(db, { name: 'Checkout', orgId: organization.id }) return { organization, project } } async function seedTransfer(db: Db.Db, orgId: string, projectId: string) { const record = await Transfer.create(db, { apiKeyId: 'key_admin_routes', environment: 'production', id: Transfer.generateId(new Date('2026-08-26T00:00:00.000Z')), orgId, projectId, providerState: { secret: 'hidden' }, snapshot: TestRoutes.transferSnapshot({ provider: { id: 'stargate', name: 'Stargate' }, }), }) await Transfer.transition(db, { expectedVersion: record.version, id: record.id, status: 'processing', }) const transactionRef = `0x${'ab'.repeat(32)}` await RoutesTransferTransactions.insert(db, { chainId: 'eip155:8453', createdAt: '2026-08-26T00:00:01.000Z', role: 'source', transactionRef, transferId: record.id, }) return { record, transactionRef } } async function seedDeposit( db: Db.Db, orgId: string, projectId: string, options: seedDeposit.Options = {}, ) { const address = await DepositAddress.create(db, { deliveryStrategy: 'tempo', environment: 'production', id: options.addressId ?? DepositAddress.generateId(new Date('2026-08-26T00:01:00.000Z')), now: new Date('2026-08-26T00:01:00.000Z'), orgId, projectId, providerOutputToken: TestRoutes.providerOutputToken(), providerRequestIds: ['provider_address_request'], providerState: { secret: 'hidden' }, snapshot: TestRoutes.depositAddressSnapshot(), }) const transactionRef = 'cd'.repeat(32) const deposit = await Deposit.create(db, { id: options.depositId, now: new Date('2026-08-26T00:02:00.000Z'), providerRequestId: 'provider_deposit_request', providerState: { secret: 'hidden' }, ...(options.subsidies ? { providerSubsidy: { amount: { baseUnits: '23838', currency: 'USD', decimals: 6, formatted: '0.023838', }, provider: 'relay', token: address.snapshot.sourceToken, }, } : {}), providerTransactionHashes: ['provider_transaction'], retryState: { attempts: 2, secret: 'hidden' }, settlementTransaction: 'signed-transaction-bytes', snapshot: TestRoutes.depositSnapshot(address.id, { sourceTransactionHashes: [transactionRef], }), sourceTransactionHash: transactionRef, sourceTransferIndex: 0, ...(options.subsidies ? { settlementTransactionHash: `0x${'ef'.repeat(32)}`, subsidyAmount: { baseUnits: '2', currency: 'USD', decimals: 6, formatted: '0.000002', }, } : {}), }) await Deposit.transition(db, { expectedVersion: deposit.version, id: deposit.id, status: 'bridging', }) return { address, deposit, transactionRef } } declare namespace seedDeposit { /** Legacy IDs used to seed records created before the route rename. */ type Options = { /** Legacy deposit-address id override. */ addressId?: string | undefined /** Legacy deposit id override. */ depositId?: string | undefined /** Whether the deposit includes provider and Tempo subsidies. */ subsidies?: boolean | undefined } }