tapimo 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ApiKey.d.ts +2 -1
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKeys.d.ts +4 -2
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +26 -1
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +6007 -5003
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +1 -0
- package/dist/App.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -1
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +6 -6
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +91 -84
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +22 -13
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +6 -0
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +4 -2
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +69 -69
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +232 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +4 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +2 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/Zones.d.ts +4266 -82
- package/dist/apps/Zones.d.ts.map +1 -1
- package/dist/apps/Zones.js +27 -8
- package/dist/apps/Zones.js.map +1 -1
- package/dist/apps/data/App.d.ts +3467 -2696
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +2 -0
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +2999 -100
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +340 -2
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +514 -0
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +26 -26
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +7 -3
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +4 -4
- package/dist/apps/data/routes/earn.d.ts +75 -75
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +65 -36
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +124 -120
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +115 -77
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +24 -24
- package/dist/apps/data/routes/indexer.d.ts +2 -1
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +3 -2
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +4 -3
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +15 -14
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +5 -1
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +12 -12
- package/dist/apps/data/routes/tokens.d.ts +1 -1
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +4 -3
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +25 -7
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +37 -37
- package/dist/apps/data/routes/webhooks.d.ts +71 -1
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +177 -23
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.js +1 -1
- package/dist/apps/data/routes/zones.js.map +1 -1
- package/dist/apps/funding/App.d.ts +322 -89
- package/dist/apps/funding/App.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts +375 -45
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.js +208 -12
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/funding/routes/transfers.d.ts +32 -32
- package/dist/apps/funding/routes/transfers.js +1 -1
- package/dist/apps/funding/routes/transfers.js.map +1 -1
- package/dist/apps/management/App.d.ts +418 -418
- package/dist/apps/management/routes/api-keys.d.ts +50 -50
- package/dist/apps/management/routes/billing.d.ts +72 -72
- package/dist/apps/management/routes/billing.js +1 -1
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +8 -8
- package/dist/apps/management/routes/faucet.js +2 -2
- package/dist/apps/management/routes/faucet.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +42 -42
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +14 -14
- package/dist/apps/management/routes/projects.d.ts +40 -40
- package/dist/apps/management/routes/usage.d.ts +8 -8
- package/dist/apps/management/routes/webhooks.d.ts +49 -49
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +4 -1
- package/dist/apps/mcp.js.map +1 -1
- package/dist/db/Db.d.ts +2 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +90 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +19 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +24 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/fundingDepositAddresses.d.ts +20 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
- package/dist/db/tables/fundingDepositAddresses.js +17 -0
- package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
- package/dist/db/tables/fundingDeposits.d.ts +41 -0
- package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
- package/dist/db/tables/fundingDeposits.js +69 -0
- package/dist/db/tables/fundingDeposits.js.map +1 -1
- package/dist/db/tables/webhookQueueEvents.d.ts +122 -0
- package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -0
- package/dist/db/tables/webhookQueueEvents.js +160 -0
- package/dist/db/tables/webhookQueueEvents.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +2 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +10 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/Auth.d.ts +3 -26
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +6 -37
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Credential.d.ts +27 -0
- package/dist/internal/Credential.d.ts.map +1 -0
- package/dist/internal/Credential.js +34 -0
- package/dist/internal/Credential.js.map +1 -0
- package/dist/internal/EarnRates.js +11 -7
- package/dist/internal/EarnRates.js.map +1 -1
- package/dist/internal/Log.d.ts +8 -0
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +4 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts +51 -0
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +54 -2
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +4 -6
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +15 -14
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Store.d.ts +2 -1
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +57 -18
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts +4 -3
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +2 -2
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Value.d.ts +2 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +25 -0
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/Viem.d.ts +4 -3
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +3 -2
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/WebhookTransfer.d.ts +20 -0
- package/dist/internal/WebhookTransfer.d.ts.map +1 -1
- package/dist/internal/WebhookTransfer.js +7 -4
- package/dist/internal/WebhookTransfer.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +141 -0
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +139 -10
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/funding/providers/relay.d.ts +3 -4
- package/dist/internal/funding/providers/relay.d.ts.map +1 -1
- package/dist/internal/funding/providers/relay.js +59 -8
- package/dist/internal/funding/providers/relay.js.map +1 -1
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -0
- package/dist/internal/index.js.map +1 -1
- package/package.json +3 -3
- package/src/ApiKeys.test.ts +20 -0
- package/src/ApiKeys.ts +28 -1
- package/src/App.test.ts +40 -8
- package/src/App.ts +1 -0
- package/src/Client.test-d.ts +34 -1
- package/src/Webhooks.ts +20 -18
- package/src/admin/apps/api-keys.test.ts +9 -0
- package/src/admin/apps/api-keys.ts +15 -0
- package/src/admin/ui/src/lib/query-client.ts +3 -2
- package/src/admin/ui/src/routes/api-keys.tsx +31 -9
- package/src/admin/ui.generated.ts +69 -69
- package/src/analytics/Analytics.test.ts +42 -0
- package/src/analytics/Analytics.ts +232 -0
- package/src/analytics/tables/requestEvents.ts +6 -0
- package/src/apps/Zones.test.ts +20 -3
- package/src/apps/Zones.ts +28 -8
- package/src/apps/composition.test.ts +2 -0
- package/src/apps/data/App.test.ts +2 -2
- package/src/apps/data/App.ts +2 -0
- package/src/apps/data/routes/activities.bench.ts +41 -0
- package/src/apps/data/routes/activities.test.ts +103 -2
- package/src/apps/data/routes/activities.ts +401 -2
- package/src/apps/data/routes/balances.bench.ts +21 -0
- package/src/apps/data/routes/balances.ts +7 -3
- package/src/apps/data/routes/blocks.bench.ts +34 -0
- package/src/apps/data/routes/coingecko.bench.ts +53 -0
- package/src/apps/data/routes/earn.bench.ts +71 -0
- package/src/apps/data/routes/earn.ts +66 -36
- package/src/apps/data/routes/exchanges.bench.ts +85 -0
- package/src/apps/data/routes/exchanges.test.ts +8 -3
- package/src/apps/data/routes/exchanges.ts +134 -82
- package/src/apps/data/routes/fee-amm.bench.ts +13 -0
- package/src/apps/data/routes/indexer.bench.ts +8 -0
- package/src/apps/data/routes/indexer.test.ts +2 -1
- package/src/apps/data/routes/indexer.ts +3 -2
- package/src/apps/data/routes/receipts.bench.ts +39 -0
- package/src/apps/data/routes/receipts.ts +16 -14
- package/src/apps/data/routes/rpc.bench.ts +14 -0
- package/src/apps/data/routes/rpc.test.ts +27 -0
- package/src/apps/data/routes/rpc.ts +5 -1
- package/src/apps/data/routes/tokenlist.bench.ts +3 -0
- package/src/apps/data/routes/tokens.bench.ts +76 -0
- package/src/apps/data/routes/tokens.ts +3 -2
- package/src/apps/data/routes/transactions.bench.ts +48 -0
- package/src/apps/data/routes/transfers.bench.ts +28 -0
- package/src/apps/data/routes/transfers.ts +36 -10
- package/src/apps/data/routes/valuation.bench.ts +14 -0
- package/src/apps/data/routes/verified-tokens.bench.ts +8 -0
- package/src/apps/data/routes/webhooks.bench.ts +26 -0
- package/src/apps/data/routes/webhooks.scan.test.ts +326 -0
- package/src/apps/data/routes/webhooks.test.ts +53 -6
- package/src/apps/data/routes/webhooks.ts +252 -24
- package/src/apps/data/routes/zones.bench.ts +32 -0
- package/src/apps/data/routes/zones.test.ts +1 -1
- package/src/apps/data/routes/zones.ts +1 -1
- package/src/apps/funding/routes/chains.test.ts +1 -1
- package/src/apps/funding/routes/deposit-addresses.test.ts +217 -3
- package/src/apps/funding/routes/deposit-addresses.ts +255 -19
- package/src/apps/funding/routes/providers.test.ts +1 -1
- package/src/apps/funding/routes/quotes.test.ts +1 -1
- package/src/apps/funding/routes/transfers.test.ts +20 -8
- package/src/apps/funding/routes/transfers.ts +1 -1
- package/src/apps/management/routes/billing.ts +1 -1
- package/src/apps/management/routes/faucet.ts +2 -2
- package/src/apps/management/routes/me.test.ts +31 -0
- package/src/apps/mcp.ts +4 -1
- package/src/db/Db.ts +117 -0
- package/src/db/Schema.ts +32 -0
- package/src/db/tables/fundingDepositAddresses.test.ts +28 -0
- package/src/db/tables/fundingDepositAddresses.ts +39 -0
- package/src/db/tables/fundingDeposits.test.ts +82 -0
- package/src/db/tables/fundingDeposits.ts +130 -0
- package/src/db/tables/webhookQueueEvents.ts +285 -0
- package/src/db/tables/webhookSubscriptions.ts +15 -0
- package/src/internal/Auth.test.ts +61 -98
- package/src/internal/Auth.ts +9 -63
- package/src/internal/Credential.test.ts +51 -0
- package/src/internal/Credential.ts +58 -0
- package/src/internal/EarnRates.ts +13 -7
- package/src/internal/EarnVaults.test.ts +2 -2
- package/src/internal/Log.test.ts +3 -1
- package/src/internal/Log.ts +14 -0
- package/src/internal/MetricSink.test.ts +108 -2
- package/src/internal/MetricSink.ts +112 -2
- package/src/internal/RateLimit.test.ts +23 -18
- package/src/internal/RateLimit.ts +23 -15
- package/src/internal/Store.test.ts +99 -13
- package/src/internal/Store.ts +52 -17
- package/src/internal/Tidx.test.ts +4 -4
- package/src/internal/Tidx.ts +5 -4
- package/src/internal/Value.test.ts +25 -0
- package/src/internal/Value.ts +29 -0
- package/src/internal/Viem.test.ts +4 -0
- package/src/internal/Viem.ts +6 -4
- package/src/internal/WebhookTransfer.test.ts +89 -0
- package/src/internal/WebhookTransfer.ts +11 -7
- package/src/internal/Webhooks.test.ts +488 -0
- package/src/internal/Webhooks.ts +291 -10
- package/src/internal/funding/Provider.test.ts +1 -1
- package/src/internal/funding/providers/index.test.ts +73 -3
- package/src/internal/funding/providers/relay.test.ts +1 -5
- package/src/internal/funding/providers/relay.ts +56 -12
- package/src/internal/index.test.ts +1 -0
- package/src/internal/index.ts +1 -0
|
@@ -45,7 +45,7 @@ const providers = [
|
|
|
45
45
|
integratorId: '0xdead',
|
|
46
46
|
userAddress: '0x1111111111111111111111111111111111111111',
|
|
47
47
|
}),
|
|
48
|
-
Relay.relay({
|
|
48
|
+
Relay.relay({ userAddresses: TestFunding.relayQuoteUsers }),
|
|
49
49
|
Rhino.rhino(),
|
|
50
50
|
Squid.squid({
|
|
51
51
|
integratorId: 'squid-integrator-id',
|
|
@@ -966,6 +966,67 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
|
|
|
966
966
|
})
|
|
967
967
|
})
|
|
968
968
|
|
|
969
|
+
describe('GET /funding/deposit-addresses', () => {
|
|
970
|
+
test('pages organization addresses and narrows project-attributed keys', async () => {
|
|
971
|
+
const app = transfersApp()
|
|
972
|
+
const first = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
|
|
973
|
+
const second = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
|
|
974
|
+
const third = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
|
|
975
|
+
const project = await seedDepositAddress({
|
|
976
|
+
orgId: fundingAddressListReader.orgId,
|
|
977
|
+
projectId: fundingAddressListProjectReader.projectId,
|
|
978
|
+
})
|
|
979
|
+
const sibling = await seedDepositAddress({
|
|
980
|
+
orgId: fundingAddressListReader.orgId,
|
|
981
|
+
projectId: 'prj_funding_address_list_sibling',
|
|
982
|
+
})
|
|
983
|
+
const sixth = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
|
|
984
|
+
await seedDepositAddress({ orgId: fundingForeign.orgId })
|
|
985
|
+
await seedDepositAddress({
|
|
986
|
+
environment: 'sandbox',
|
|
987
|
+
orgId: fundingAddressListReader.orgId,
|
|
988
|
+
})
|
|
989
|
+
|
|
990
|
+
const path = '/v1/funding/deposit-addresses'
|
|
991
|
+
expect((await app.request(path)).status).toBe(401)
|
|
992
|
+
expect((await app.request(path, as(TestApp.key))).status).toBe(403)
|
|
993
|
+
|
|
994
|
+
const response = await app.request(`${path}?limit=5`, as(fundingAddressListReader))
|
|
995
|
+
expect(response.status).toBe(200)
|
|
996
|
+
expect({
|
|
997
|
+
cacheControl: response.headers.get('cache-control'),
|
|
998
|
+
etag: response.headers.get('etag'),
|
|
999
|
+
vary: response.headers.get('vary'),
|
|
1000
|
+
}).toEqual({
|
|
1001
|
+
cacheControl: 'no-store',
|
|
1002
|
+
etag: null,
|
|
1003
|
+
vary: 'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
|
|
1004
|
+
})
|
|
1005
|
+
const body = await TestApp.json(response, Funding.schema.listFundingDepositAddresses.Response)
|
|
1006
|
+
expect(body.data.map((address) => address.id)).toEqual([
|
|
1007
|
+
sixth.id,
|
|
1008
|
+
sibling.id,
|
|
1009
|
+
project.id,
|
|
1010
|
+
third.id,
|
|
1011
|
+
second.id,
|
|
1012
|
+
])
|
|
1013
|
+
expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
|
|
1014
|
+
|
|
1015
|
+
const next = await TestApp.json(
|
|
1016
|
+
await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(fundingAddressListReader)),
|
|
1017
|
+
Funding.schema.listFundingDepositAddresses.Response,
|
|
1018
|
+
)
|
|
1019
|
+
expect(next.data.map((address) => address.id)).toEqual([first.id])
|
|
1020
|
+
expect(next.nextCursor).toBeNull()
|
|
1021
|
+
|
|
1022
|
+
const projectBody = await TestApp.json(
|
|
1023
|
+
await app.request(path, as(fundingAddressListProjectReader)),
|
|
1024
|
+
Funding.schema.listFundingDepositAddresses.Response,
|
|
1025
|
+
)
|
|
1026
|
+
expect(projectBody.data.map((address) => address.id)).toEqual([project.id])
|
|
1027
|
+
})
|
|
1028
|
+
})
|
|
1029
|
+
|
|
969
1030
|
describe('GET /funding/deposit-addresses/:id', () => {
|
|
970
1031
|
test('requires funding:read and returns the owned address', async () => {
|
|
971
1032
|
const app = transfersApp()
|
|
@@ -1329,6 +1390,63 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1329
1390
|
})
|
|
1330
1391
|
})
|
|
1331
1392
|
|
|
1393
|
+
describe('GET /funding/deposits', () => {
|
|
1394
|
+
test('pages organization deposits and narrows project-attributed keys', async () => {
|
|
1395
|
+
const app = transfersApp()
|
|
1396
|
+
const firstAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
|
|
1397
|
+
const secondAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
|
|
1398
|
+
const thirdAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
|
|
1399
|
+
const projectAddress = await seedDepositAddress({
|
|
1400
|
+
orgId: fundingDepositListReader.orgId,
|
|
1401
|
+
projectId: fundingDepositListProjectReader.projectId,
|
|
1402
|
+
})
|
|
1403
|
+
const siblingAddress = await seedDepositAddress({
|
|
1404
|
+
orgId: fundingDepositListReader.orgId,
|
|
1405
|
+
projectId: 'prj_funding_deposit_list_sibling',
|
|
1406
|
+
})
|
|
1407
|
+
const sixthAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
|
|
1408
|
+
const first = await seedDeposit(firstAddress)
|
|
1409
|
+
const second = await seedDeposit(secondAddress)
|
|
1410
|
+
const third = await seedDeposit(thirdAddress)
|
|
1411
|
+
const project = await seedDeposit(projectAddress)
|
|
1412
|
+
const sibling = await seedDeposit(siblingAddress)
|
|
1413
|
+
const sixth = await seedDeposit(sixthAddress)
|
|
1414
|
+
const foreignAddress = await seedDepositAddress({ orgId: fundingForeign.orgId })
|
|
1415
|
+
await seedDeposit(foreignAddress)
|
|
1416
|
+
const sandboxAddress = await seedDepositAddress({
|
|
1417
|
+
environment: 'sandbox',
|
|
1418
|
+
orgId: fundingDepositListReader.orgId,
|
|
1419
|
+
})
|
|
1420
|
+
await seedDeposit(sandboxAddress)
|
|
1421
|
+
|
|
1422
|
+
const path = '/v1/funding/deposits'
|
|
1423
|
+
const response = await app.request(`${path}?limit=5`, as(fundingDepositListReader))
|
|
1424
|
+
expect(response.status).toBe(200)
|
|
1425
|
+
const body = await TestApp.json(response, Funding.schema.listFundingDeposits.Response)
|
|
1426
|
+
expect(body.data.map((deposit) => deposit.id)).toEqual([
|
|
1427
|
+
sixth.id,
|
|
1428
|
+
sibling.id,
|
|
1429
|
+
project.id,
|
|
1430
|
+
third.id,
|
|
1431
|
+
second.id,
|
|
1432
|
+
])
|
|
1433
|
+
expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
|
|
1434
|
+
|
|
1435
|
+
const next = await TestApp.json(
|
|
1436
|
+
await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(fundingDepositListReader)),
|
|
1437
|
+
Funding.schema.listFundingDeposits.Response,
|
|
1438
|
+
)
|
|
1439
|
+
expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
|
|
1440
|
+
expect(next.nextCursor).toBeNull()
|
|
1441
|
+
|
|
1442
|
+
const projectBody = await TestApp.json(
|
|
1443
|
+
await app.request(path, as(fundingDepositListProjectReader)),
|
|
1444
|
+
Funding.schema.listFundingDeposits.Response,
|
|
1445
|
+
)
|
|
1446
|
+
expect(projectBody.data.map((deposit) => deposit.id)).toEqual([project.id])
|
|
1447
|
+
})
|
|
1448
|
+
})
|
|
1449
|
+
|
|
1332
1450
|
describe('GET /funding/deposits?recipient', () => {
|
|
1333
1451
|
test('requires funding:read and pages recipient deposits across addresses', async () => {
|
|
1334
1452
|
const app = transfersApp()
|
|
@@ -1336,7 +1454,6 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1336
1454
|
const path = `/v1/funding/deposits?recipient=${recipient.toLowerCase()}`
|
|
1337
1455
|
expect((await app.request(path)).status).toBe(401)
|
|
1338
1456
|
expect((await app.request(path, as(TestApp.key))).status).toBe(403)
|
|
1339
|
-
expect((await app.request('/v1/funding/deposits', as(fundingReader))).status).toBe(400)
|
|
1340
1457
|
expect(
|
|
1341
1458
|
(await app.request('/v1/funding/deposits?depositAddress=', as(fundingReader))).status,
|
|
1342
1459
|
).toBe(400)
|
|
@@ -1347,7 +1464,7 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1347
1464
|
as(fundingReader),
|
|
1348
1465
|
)
|
|
1349
1466
|
).status,
|
|
1350
|
-
).toBe(
|
|
1467
|
+
).toBe(200)
|
|
1351
1468
|
|
|
1352
1469
|
const firstAddress = await seedDepositAddress({
|
|
1353
1470
|
snapshot: TestFunding.depositAddressSnapshot({
|
|
@@ -1438,6 +1555,61 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1438
1555
|
})
|
|
1439
1556
|
})
|
|
1440
1557
|
|
|
1558
|
+
describe('GET /funding/deposits?filters', () => {
|
|
1559
|
+
test('AND-combines canonical aliases and includes the matching count', async () => {
|
|
1560
|
+
const app = transfersApp()
|
|
1561
|
+
const snapshot = TestFunding.depositAddressSnapshot({
|
|
1562
|
+
address: 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE',
|
|
1563
|
+
})
|
|
1564
|
+
const address = await seedDepositAddress({
|
|
1565
|
+
orgId: fundingDepositFilterReader.orgId,
|
|
1566
|
+
snapshot,
|
|
1567
|
+
})
|
|
1568
|
+
const deposit = await seedDeposit(address)
|
|
1569
|
+
const unrelatedAddress = await seedDepositAddress({
|
|
1570
|
+
orgId: fundingDepositFilterReader.orgId,
|
|
1571
|
+
snapshot: TestFunding.depositAddressSnapshot({
|
|
1572
|
+
provider: { id: 'relay_unrelated', name: 'Relay' },
|
|
1573
|
+
recipient: `0x${'22'.repeat(20)}`,
|
|
1574
|
+
}),
|
|
1575
|
+
})
|
|
1576
|
+
await seedDeposit(unrelatedAddress)
|
|
1577
|
+
const query = new URLSearchParams({
|
|
1578
|
+
depositAddress: snapshot.address,
|
|
1579
|
+
destinationToken: 'usdt0',
|
|
1580
|
+
include: 'totalCount',
|
|
1581
|
+
provider: 'relay',
|
|
1582
|
+
recipient: snapshot.recipient.toLowerCase(),
|
|
1583
|
+
sourceChain: 'tron',
|
|
1584
|
+
sourceToken: 'usdt',
|
|
1585
|
+
status: 'detected',
|
|
1586
|
+
})
|
|
1587
|
+
|
|
1588
|
+
const body = await TestApp.json(
|
|
1589
|
+
await app.request(`/v1/funding/deposits?${query}`, as(fundingDepositFilterReader)),
|
|
1590
|
+
Funding.schema.listFundingDeposits.Response,
|
|
1591
|
+
)
|
|
1592
|
+
expect(body).toEqual({
|
|
1593
|
+
data: [FundingDeposit.toPublic(deposit)],
|
|
1594
|
+
meta: { totalCount: 1, totalCountCapped: false },
|
|
1595
|
+
nextCursor: null,
|
|
1596
|
+
})
|
|
1597
|
+
|
|
1598
|
+
const empty = await TestApp.json(
|
|
1599
|
+
await app.request(
|
|
1600
|
+
'/v1/funding/deposits?sourceToken=unknown&include=totalCount',
|
|
1601
|
+
as(fundingDepositFilterReader),
|
|
1602
|
+
),
|
|
1603
|
+
Funding.schema.listFundingDeposits.Response,
|
|
1604
|
+
)
|
|
1605
|
+
expect(empty).toEqual({
|
|
1606
|
+
data: [],
|
|
1607
|
+
meta: { totalCount: 0, totalCountCapped: false },
|
|
1608
|
+
nextCursor: null,
|
|
1609
|
+
})
|
|
1610
|
+
})
|
|
1611
|
+
})
|
|
1612
|
+
|
|
1441
1613
|
describe('GET /funding/deposits/:id', () => {
|
|
1442
1614
|
test('returns the owned deposit without private reconciliation state', async () => {
|
|
1443
1615
|
const app = transfersApp()
|
|
@@ -1544,6 +1716,43 @@ const fundingReader = {
|
|
|
1544
1716
|
token: 'secret_funding_reader',
|
|
1545
1717
|
} satisfies TestApp.kvStore.Key
|
|
1546
1718
|
|
|
1719
|
+
const fundingAddressListReader = {
|
|
1720
|
+
id: 'key_funding_address_list',
|
|
1721
|
+
orgId: 'org_funding_address_list',
|
|
1722
|
+
scopes: ['funding:read'],
|
|
1723
|
+
token: 'secret_funding_address_list',
|
|
1724
|
+
} satisfies TestApp.kvStore.Key
|
|
1725
|
+
|
|
1726
|
+
const fundingAddressListProjectReader = {
|
|
1727
|
+
id: 'key_funding_address_list_project',
|
|
1728
|
+
orgId: fundingAddressListReader.orgId,
|
|
1729
|
+
projectId: 'prj_funding_address_list',
|
|
1730
|
+
scopes: ['funding:read'],
|
|
1731
|
+
token: 'secret_funding_address_list_project',
|
|
1732
|
+
} satisfies TestApp.kvStore.Key
|
|
1733
|
+
|
|
1734
|
+
const fundingDepositListReader = {
|
|
1735
|
+
id: 'key_funding_deposit_list',
|
|
1736
|
+
orgId: 'org_funding_deposit_list',
|
|
1737
|
+
scopes: ['funding:read'],
|
|
1738
|
+
token: 'secret_funding_deposit_list',
|
|
1739
|
+
} satisfies TestApp.kvStore.Key
|
|
1740
|
+
|
|
1741
|
+
const fundingDepositFilterReader = {
|
|
1742
|
+
id: 'key_funding_deposit_filter',
|
|
1743
|
+
orgId: 'org_funding_deposit_filter',
|
|
1744
|
+
scopes: ['funding:read'],
|
|
1745
|
+
token: 'secret_funding_deposit_filter',
|
|
1746
|
+
} satisfies TestApp.kvStore.Key
|
|
1747
|
+
|
|
1748
|
+
const fundingDepositListProjectReader = {
|
|
1749
|
+
id: 'key_funding_deposit_list_project',
|
|
1750
|
+
orgId: fundingDepositListReader.orgId,
|
|
1751
|
+
projectId: 'prj_funding_deposit_list',
|
|
1752
|
+
scopes: ['funding:read'],
|
|
1753
|
+
token: 'secret_funding_deposit_list_project',
|
|
1754
|
+
} satisfies TestApp.kvStore.Key
|
|
1755
|
+
|
|
1547
1756
|
const fundingProjectReader = {
|
|
1548
1757
|
id: 'key_funding_project',
|
|
1549
1758
|
orgId: 'org_funding',
|
|
@@ -1589,6 +1798,11 @@ function transfersApp(options: TestApp.create.Options = {}) {
|
|
|
1589
1798
|
auth: {
|
|
1590
1799
|
keys: [
|
|
1591
1800
|
TestApp.key,
|
|
1801
|
+
fundingAddressListProjectReader,
|
|
1802
|
+
fundingAddressListReader,
|
|
1803
|
+
fundingDepositFilterReader,
|
|
1804
|
+
fundingDepositListProjectReader,
|
|
1805
|
+
fundingDepositListReader,
|
|
1592
1806
|
fundingForeign,
|
|
1593
1807
|
fundingForeignWriter,
|
|
1594
1808
|
fundingProjectReader,
|
|
@@ -126,6 +126,27 @@ export namespace schema {
|
|
|
126
126
|
export const Response = DepositAddress
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/** Schemas for the listFundingDepositAddresses operation. */
|
|
130
|
+
export namespace listFundingDepositAddresses {
|
|
131
|
+
/** Query parameters for listing funding deposit addresses. */
|
|
132
|
+
export const Query = z
|
|
133
|
+
.object({
|
|
134
|
+
cursor: Schema.Cursor,
|
|
135
|
+
limit: Schema.Limit,
|
|
136
|
+
})
|
|
137
|
+
.check(z.describe('Paging parameters for listing funding deposit addresses.'))
|
|
138
|
+
|
|
139
|
+
/** One page of reusable funding deposit addresses. */
|
|
140
|
+
export const Response = z
|
|
141
|
+
.object({
|
|
142
|
+
data: z
|
|
143
|
+
.array(DepositAddress)
|
|
144
|
+
.check(z.describe('Funding deposit addresses on this page, newest first.')),
|
|
145
|
+
nextCursor: Schema.NextCursor,
|
|
146
|
+
})
|
|
147
|
+
.check(z.describe('A page of reusable funding deposit addresses.'))
|
|
148
|
+
}
|
|
149
|
+
|
|
129
150
|
/** Schemas for the reconcileFundingDepositAddress operation. */
|
|
130
151
|
export namespace reconcileFundingDepositAddress {
|
|
131
152
|
/** Path parameters for reconciling a funding deposit address. */
|
|
@@ -144,32 +165,49 @@ export namespace schema {
|
|
|
144
165
|
z.meta({ examples: ['TJRabPrwbZy45sbavfcjinPJC18kjpRTv8'] }),
|
|
145
166
|
),
|
|
146
167
|
cursor: Schema.Cursor,
|
|
168
|
+
destinationToken: z
|
|
169
|
+
.optional(z.string().check(z.minLength(1)))
|
|
170
|
+
.check(
|
|
171
|
+
z.describe('Destination token symbol, contract address, or token key.'),
|
|
172
|
+
z.meta({ examples: ['usdt0'] }),
|
|
173
|
+
),
|
|
174
|
+
include: Schema.totalCountInclude,
|
|
147
175
|
limit: Schema.Limit,
|
|
176
|
+
provider: z
|
|
177
|
+
.optional(z.string().check(z.minLength(1)))
|
|
178
|
+
.check(z.describe('Funding provider id.'), z.meta({ examples: ['relay'] })),
|
|
148
179
|
recipient: z
|
|
149
180
|
.optional(Schema.Address)
|
|
150
181
|
.check(
|
|
151
182
|
z.describe('Tempo account that received the deposits.'),
|
|
152
183
|
z.meta({ examples: [`0x${'11'.repeat(20)}`] }),
|
|
153
184
|
),
|
|
185
|
+
sourceChain: z
|
|
186
|
+
.optional(z.string().check(z.minLength(1)))
|
|
187
|
+
.check(
|
|
188
|
+
z.describe('Source chain CAIP-2 id, slug, or alias.'),
|
|
189
|
+
z.meta({ examples: ['tron'] }),
|
|
190
|
+
),
|
|
191
|
+
sourceToken: z
|
|
192
|
+
.optional(z.string().check(z.minLength(1)))
|
|
193
|
+
.check(
|
|
194
|
+
z.describe('Source token symbol, contract address, or token key.'),
|
|
195
|
+
z.meta({ examples: ['usdt'] }),
|
|
196
|
+
),
|
|
197
|
+
status: z.optional(FundingDeposit.schema.Status),
|
|
154
198
|
})
|
|
155
|
-
.check(
|
|
156
|
-
z.refine(
|
|
157
|
-
(query) => (query.depositAddress === undefined) !== (query.recipient === undefined),
|
|
158
|
-
{
|
|
159
|
-
error: 'Pass exactly one of `depositAddress` or `recipient`.',
|
|
160
|
-
path: ['depositAddress'],
|
|
161
|
-
},
|
|
162
|
-
),
|
|
163
|
-
z.describe('Exactly one deposit filter and optional paging parameters.'),
|
|
164
|
-
)
|
|
199
|
+
.check(z.describe('Optional deposit filters and paging parameters.'))
|
|
165
200
|
|
|
166
201
|
/** One page of detected deposits. */
|
|
167
202
|
export const Response = z
|
|
168
203
|
.object({
|
|
169
204
|
data: z.array(Deposit).check(z.describe('Detected deposits on this page, newest first.')),
|
|
205
|
+
meta: z
|
|
206
|
+
.optional(Schema.CountMeta)
|
|
207
|
+
.check(z.describe('Extra response metadata requested with `include`.')),
|
|
170
208
|
nextCursor: Schema.NextCursor,
|
|
171
209
|
})
|
|
172
|
-
.check(z.describe('A page of funding deposits
|
|
210
|
+
.check(z.describe('A page of visible funding deposits.'))
|
|
173
211
|
}
|
|
174
212
|
|
|
175
213
|
/** Schemas for the getFundingDeposit operation. */
|
|
@@ -276,9 +314,114 @@ const fundingDepositExample = {
|
|
|
276
314
|
|
|
277
315
|
const fundingDepositsExample = {
|
|
278
316
|
data: [fundingDepositExample],
|
|
317
|
+
meta: { totalCount: 1, totalCountCapped: false },
|
|
279
318
|
nextCursor: null,
|
|
280
319
|
} satisfies z.output<typeof schema.listFundingDeposits.Response>
|
|
281
320
|
|
|
321
|
+
const fundingDepositAddressesExample = {
|
|
322
|
+
data: [fundingDepositAddressExample],
|
|
323
|
+
nextCursor: null,
|
|
324
|
+
} satisfies z.output<typeof schema.listFundingDepositAddresses.Response>
|
|
325
|
+
|
|
326
|
+
function resolveDepositFilters(options: resolveDepositFilters.Options): FundingDeposits.Filters {
|
|
327
|
+
const { catalog, parameters } = options
|
|
328
|
+
return {
|
|
329
|
+
...(parameters.depositAddress === undefined
|
|
330
|
+
? {}
|
|
331
|
+
: { depositAddress: parameters.depositAddress }),
|
|
332
|
+
...(parameters.destinationToken === undefined
|
|
333
|
+
? {}
|
|
334
|
+
: {
|
|
335
|
+
destinationTokenKeys: resolveTokenKeys({
|
|
336
|
+
catalog,
|
|
337
|
+
input: parameters.destinationToken,
|
|
338
|
+
side: 'destination',
|
|
339
|
+
}),
|
|
340
|
+
}),
|
|
341
|
+
...(parameters.provider === undefined
|
|
342
|
+
? {}
|
|
343
|
+
: { providerId: parameters.provider.trim().toLowerCase() }),
|
|
344
|
+
...(parameters.recipient === undefined ? {} : { recipient: parameters.recipient }),
|
|
345
|
+
...(parameters.sourceChain === undefined
|
|
346
|
+
? {}
|
|
347
|
+
: { sourceChainIds: resolveChainIds(catalog, parameters.sourceChain) }),
|
|
348
|
+
...(parameters.sourceToken === undefined
|
|
349
|
+
? {}
|
|
350
|
+
: {
|
|
351
|
+
sourceTokenKeys: resolveTokenKeys({
|
|
352
|
+
catalog,
|
|
353
|
+
input: parameters.sourceToken,
|
|
354
|
+
side: 'source',
|
|
355
|
+
}),
|
|
356
|
+
}),
|
|
357
|
+
...(parameters.status === undefined ? {} : { status: parameters.status }),
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
declare namespace resolveDepositFilters {
|
|
362
|
+
type Options = {
|
|
363
|
+
catalog?: FundingCatalog.Snapshot | undefined
|
|
364
|
+
parameters: z.output<typeof schema.listFundingDeposits.Query>
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function resolveChainIds(catalog: FundingCatalog.Snapshot | undefined, input: string): string[] {
|
|
369
|
+
const trimmed = input.trim()
|
|
370
|
+
const chain = catalog?.chainsByKey.get(trimmed.toLowerCase())
|
|
371
|
+
if (chain) return [chain.id]
|
|
372
|
+
return /^[a-z][a-z0-9-]*:.+$/i.test(trimmed) ? [trimmed] : []
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function resolveTokenKeys(options: resolveTokenKeys.Options): string[] {
|
|
376
|
+
const trimmed = options.input.trim()
|
|
377
|
+
const normalized = trimmed.toLowerCase()
|
|
378
|
+
const keys =
|
|
379
|
+
options.catalog?.routes
|
|
380
|
+
.map((entry) => entry.route[options.side])
|
|
381
|
+
.filter((token) => matchesToken(token, trimmed, normalized))
|
|
382
|
+
.map(tokenKey) ?? []
|
|
383
|
+
if (keys.length) return [...new Set(keys)]
|
|
384
|
+
if (!/^[a-z][a-z0-9-]*:.+\/(?:erc20|trc20|token):.+$/i.test(trimmed)) return []
|
|
385
|
+
return [/\/erc20:/i.test(trimmed) ? normalized : trimmed]
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
declare namespace resolveTokenKeys {
|
|
389
|
+
type Options = {
|
|
390
|
+
catalog?: FundingCatalog.Snapshot | undefined
|
|
391
|
+
input: string
|
|
392
|
+
side: 'destination' | 'source'
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
type ResolvedToken = FundingCatalog.Snapshot['routes'][number]['route']['source']
|
|
397
|
+
|
|
398
|
+
function matchesToken(token: ResolvedToken, trimmed: string, normalized: string): boolean {
|
|
399
|
+
return (
|
|
400
|
+
token.slug === normalized ||
|
|
401
|
+
token.symbol.toLowerCase() === normalized ||
|
|
402
|
+
matchesTokenIdentifier(token, token.address, trimmed, normalized) ||
|
|
403
|
+
matchesTokenIdentifier(token, tokenKey(token), trimmed, normalized)
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function matchesTokenIdentifier(
|
|
408
|
+
token: ResolvedToken,
|
|
409
|
+
candidate: string,
|
|
410
|
+
trimmed: string,
|
|
411
|
+
normalized: string,
|
|
412
|
+
): boolean {
|
|
413
|
+
return token.chain.kind === 'evm' ? candidate.toLowerCase() === normalized : candidate === trimmed
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function tokenKey(token: ResolvedToken): string {
|
|
417
|
+
const namespace = (() => {
|
|
418
|
+
if (token.chain.kind === 'solana') return 'token'
|
|
419
|
+
if (token.chain.kind === 'tron') return 'trc20'
|
|
420
|
+
return 'erc20'
|
|
421
|
+
})()
|
|
422
|
+
return `${token.chain.id}/${namespace}:${token.address}`
|
|
423
|
+
}
|
|
424
|
+
|
|
282
425
|
const reconcileFundingDepositAddressResponses = (() => {
|
|
283
426
|
const responses = OpenApi.responses({
|
|
284
427
|
errors: {
|
|
@@ -646,6 +789,72 @@ export function depositAddresses(options: depositAddresses.Options = {}) {
|
|
|
646
789
|
}
|
|
647
790
|
},
|
|
648
791
|
)
|
|
792
|
+
.get(
|
|
793
|
+
'/v1/funding/deposit-addresses',
|
|
794
|
+
Auth.policy({ apiKey: { scopes: ['funding:read'] } }),
|
|
795
|
+
OpenApi.validate('query', schema.listFundingDepositAddresses.Query, {
|
|
796
|
+
code: 'query_invalid',
|
|
797
|
+
message: 'Check the query parameters and try again.',
|
|
798
|
+
}),
|
|
799
|
+
OpenApi.describeRoute({
|
|
800
|
+
description: 'Lists reusable funding deposit addresses, newest first.',
|
|
801
|
+
operationId: 'listFundingDepositAddresses',
|
|
802
|
+
responses: OpenApi.responses({
|
|
803
|
+
errors: {
|
|
804
|
+
400: { codes: ['query_invalid'] },
|
|
805
|
+
},
|
|
806
|
+
success: {
|
|
807
|
+
description: 'A page of reusable funding deposit addresses.',
|
|
808
|
+
example: fundingDepositAddressesExample,
|
|
809
|
+
schema: schema.listFundingDepositAddresses.Response,
|
|
810
|
+
},
|
|
811
|
+
}),
|
|
812
|
+
summary: 'List deposit addresses',
|
|
813
|
+
tags: ['Deposit Addresses'],
|
|
814
|
+
}),
|
|
815
|
+
async (c) => {
|
|
816
|
+
if (Auth.narrowAccess) return Auth.accessError(c)
|
|
817
|
+
if (OpenApi.narrowValidation)
|
|
818
|
+
return OpenApi.validationError(c, {
|
|
819
|
+
code: 'query_invalid',
|
|
820
|
+
message: 'Check the query parameters and try again.',
|
|
821
|
+
})
|
|
822
|
+
|
|
823
|
+
const owner = Access.owner(c)
|
|
824
|
+
if (!owner) return Access.unauthorized(c)
|
|
825
|
+
|
|
826
|
+
const db = Db.get(c.get('db'))
|
|
827
|
+
const { cursor, limit } = c.req.valid('query')
|
|
828
|
+
const decoded = cursor ? Cursor.decode(cursor, ['timestamp', 'id']) : undefined
|
|
829
|
+
try {
|
|
830
|
+
const rows = await FundingDepositAddresses.list(db, {
|
|
831
|
+
...(decoded
|
|
832
|
+
? { cursor: { createdAt: String(decoded[0]), id: String(decoded[1]) } }
|
|
833
|
+
: {}),
|
|
834
|
+
limit: limit + 1,
|
|
835
|
+
owner,
|
|
836
|
+
})
|
|
837
|
+
const page = Cursor.paginate({
|
|
838
|
+
key: (record) => [record.createdAt, record.id],
|
|
839
|
+
limit,
|
|
840
|
+
rows,
|
|
841
|
+
})
|
|
842
|
+
const data = page.rows.map(FundingDepositAddress.toPublic)
|
|
843
|
+
|
|
844
|
+
c.header('Cache-Control', Cache.policies.noStore)
|
|
845
|
+
c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key')
|
|
846
|
+
return c.json(
|
|
847
|
+
Response.validated(schema.listFundingDepositAddresses.Response, {
|
|
848
|
+
data,
|
|
849
|
+
nextCursor: page.nextCursor,
|
|
850
|
+
}),
|
|
851
|
+
200,
|
|
852
|
+
)
|
|
853
|
+
} catch (cause) {
|
|
854
|
+
return Response.upstream(c, cause)
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
)
|
|
649
858
|
.get(
|
|
650
859
|
'/v1/funding/deposit-addresses/:id{fda_[A-Za-z0-9_-]+}',
|
|
651
860
|
Auth.policy({ apiKey: { scopes: ['funding:read'] } }),
|
|
@@ -712,7 +921,7 @@ export function depositAddresses(options: depositAddresses.Options = {}) {
|
|
|
712
921
|
.post(
|
|
713
922
|
'/v1/funding/deposit-addresses/:id{fda_[A-Za-z0-9_-]+}/reconcile',
|
|
714
923
|
Auth.policy({
|
|
715
|
-
apiKey: { rateLimit: {
|
|
924
|
+
apiKey: { rateLimit: { limit: 10, period: 'minute' }, scopes: ['funding:write'] },
|
|
716
925
|
}),
|
|
717
926
|
OpenApi.validate('param', schema.reconcileFundingDepositAddress.Params, {
|
|
718
927
|
code: 'param_invalid',
|
|
@@ -782,14 +991,14 @@ export function depositAddresses(options: depositAddresses.Options = {}) {
|
|
|
782
991
|
message: 'Check the query parameters and try again.',
|
|
783
992
|
}),
|
|
784
993
|
OpenApi.describeRoute({
|
|
785
|
-
description: 'Lists deposits
|
|
994
|
+
description: 'Lists visible deposits, optionally filtered, newest first.',
|
|
786
995
|
operationId: 'listFundingDeposits',
|
|
787
996
|
responses: OpenApi.responses({
|
|
788
997
|
errors: {
|
|
789
998
|
400: { codes: ['query_invalid'] },
|
|
790
999
|
},
|
|
791
1000
|
success: {
|
|
792
|
-
description: 'A page of funding deposits
|
|
1001
|
+
description: 'A page of visible funding deposits.',
|
|
793
1002
|
example: fundingDepositsExample,
|
|
794
1003
|
schema: schema.listFundingDeposits.Response,
|
|
795
1004
|
},
|
|
@@ -809,32 +1018,59 @@ export function depositAddresses(options: depositAddresses.Options = {}) {
|
|
|
809
1018
|
if (!owner) return Access.unauthorized(c)
|
|
810
1019
|
|
|
811
1020
|
const db = Db.get(c.get('db'))
|
|
812
|
-
const
|
|
1021
|
+
const parameters = c.req.valid('query')
|
|
1022
|
+
const { cursor, include, limit } = parameters
|
|
813
1023
|
const decoded = cursor ? Cursor.decode(cursor, ['timestamp', 'id']) : undefined
|
|
814
1024
|
try {
|
|
1025
|
+
const catalog =
|
|
1026
|
+
parameters.destinationToken !== undefined ||
|
|
1027
|
+
parameters.sourceChain !== undefined ||
|
|
1028
|
+
parameters.sourceToken !== undefined
|
|
1029
|
+
? await FundingCatalog.snapshot(c)
|
|
1030
|
+
: undefined
|
|
1031
|
+
const filters = resolveDepositFilters({ catalog, parameters })
|
|
1032
|
+
// Counts are best-effort and share every ownership and filter predicate
|
|
1033
|
+
// with the page query. A failure omits `meta` rather than failing the page.
|
|
1034
|
+
const countPromise = include.includes('totalCount')
|
|
1035
|
+
? FundingDeposits.count(db, {
|
|
1036
|
+
...filters,
|
|
1037
|
+
cap: Schema.countCap,
|
|
1038
|
+
owner,
|
|
1039
|
+
}).catch(() => {
|
|
1040
|
+
c.set('fundingDepositCountFailed', true)
|
|
1041
|
+
return undefined
|
|
1042
|
+
})
|
|
1043
|
+
: undefined
|
|
815
1044
|
const paging = {
|
|
1045
|
+
...filters,
|
|
816
1046
|
...(decoded
|
|
817
1047
|
? { cursor: { createdAt: String(decoded[0]), id: String(decoded[1]) } }
|
|
818
1048
|
: {}),
|
|
819
1049
|
limit: limit + 1,
|
|
820
1050
|
owner,
|
|
821
1051
|
}
|
|
822
|
-
const rows =
|
|
823
|
-
depositAddress === undefined
|
|
824
|
-
? await FundingDeposits.listByRecipient(db, { ...paging, recipient: recipient! })
|
|
825
|
-
: await FundingDeposits.listByDepositAddress(db, { ...paging, depositAddress })
|
|
1052
|
+
const rows = await FundingDeposits.list(db, paging)
|
|
826
1053
|
const page = Cursor.paginate({
|
|
827
1054
|
key: (record) => [record.createdAt, record.id],
|
|
828
1055
|
limit,
|
|
829
1056
|
rows,
|
|
830
1057
|
})
|
|
831
1058
|
const data = page.rows.map(FundingDeposit.toPublic)
|
|
1059
|
+
const count = await countPromise
|
|
832
1060
|
|
|
833
1061
|
c.header('Cache-Control', Cache.policies.noStore)
|
|
834
1062
|
c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key')
|
|
835
1063
|
return c.json(
|
|
836
1064
|
Response.validated(schema.listFundingDeposits.Response, {
|
|
837
1065
|
data,
|
|
1066
|
+
...(count === undefined
|
|
1067
|
+
? {}
|
|
1068
|
+
: {
|
|
1069
|
+
meta: {
|
|
1070
|
+
totalCount: Math.min(count, Schema.countCap),
|
|
1071
|
+
totalCountCapped: count > Schema.countCap,
|
|
1072
|
+
},
|
|
1073
|
+
}),
|
|
838
1074
|
nextCursor: page.nextCursor,
|
|
839
1075
|
}),
|
|
840
1076
|
200,
|
|
@@ -28,7 +28,7 @@ const providers = [
|
|
|
28
28
|
integratorId: '0xdead',
|
|
29
29
|
userAddress: '0x1111111111111111111111111111111111111111',
|
|
30
30
|
}),
|
|
31
|
-
Relay.relay({
|
|
31
|
+
Relay.relay({ userAddresses: TestFunding.relayQuoteUsers }),
|
|
32
32
|
Rhino.rhino(),
|
|
33
33
|
Squid.squid({
|
|
34
34
|
integratorId: 'squid-integrator-id',
|
|
@@ -28,7 +28,7 @@ const providers = [
|
|
|
28
28
|
integratorId: '0xdead',
|
|
29
29
|
userAddress: '0x1111111111111111111111111111111111111111',
|
|
30
30
|
}),
|
|
31
|
-
Relay.relay({
|
|
31
|
+
Relay.relay({ userAddresses: TestFunding.relayQuoteUsers }),
|
|
32
32
|
Rhino.rhino(),
|
|
33
33
|
Squid.squid({
|
|
34
34
|
integratorId: 'squid-integrator-id',
|