tapimo 0.4.4 → 0.5.0
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/App.d.ts +7403 -6127
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +4 -0
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +18 -1
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +24 -3
- package/dist/Scope.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +115 -115
- package/dist/apps/data/App.d.ts +1838 -1534
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +135 -44
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/{FundingRouteProviders.d.ts → FundingQuoteProviders.d.ts} +7 -7
- package/dist/apps/data/{FundingRouteProviders.d.ts.map → FundingQuoteProviders.d.ts.map} +1 -1
- package/dist/apps/data/{FundingRouteProviders.js → FundingQuoteProviders.js} +36 -91
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -1
- package/dist/apps/data/index.js +1 -1
- package/dist/apps/data/routes/activities.d.ts +242 -242
- package/dist/apps/data/routes/addresses.d.ts +227 -227
- package/dist/apps/data/routes/balances.d.ts +12 -12
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +67 -149
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +125 -126
- package/dist/apps/data/routes/blocks.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.js +3 -5
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +55 -54
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
- package/dist/apps/data/routes/coingecko.js +3 -8
- package/dist/apps/data/routes/coingecko.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +207 -388
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +143 -221
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +86 -16
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +33 -33
- package/dist/apps/data/routes/transactions.d.ts +281 -281
- package/dist/apps/data/routes/transfers.d.ts +58 -58
- package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
- package/dist/apps/data/routes/webhooks.d.ts +340 -0
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +13 -1
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/management/App.d.ts +1090 -108
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +4 -0
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +118 -118
- package/dist/apps/management/routes/api-keys.js +2 -2
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +207 -207
- package/dist/apps/management/routes/invite-links.d.ts +1100 -0
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -0
- package/dist/apps/management/routes/invite-links.js +411 -0
- package/dist/apps/management/routes/invite-links.js.map +1 -0
- package/dist/apps/management/routes/me.d.ts +17 -17
- package/dist/apps/management/routes/members.d.ts +71 -71
- package/dist/apps/management/routes/orgs.d.ts +12 -12
- package/dist/apps/management/routes/projects.d.ts +70 -70
- package/dist/apps/management/routes/scopes.d.ts +11 -11
- package/dist/apps/management/routes/scopes.d.ts.map +1 -1
- package/dist/apps/management/routes/scopes.js +2 -2
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +75 -75
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +42 -4
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +3 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +57 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +31 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +31 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +42 -0
- package/dist/db/tables/inviteLinks.d.ts.map +1 -0
- package/dist/db/tables/inviteLinks.js +148 -0
- package/dist/db/tables/inviteLinks.js.map +1 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +2 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +13 -3
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +9 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +130 -10
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +3 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +17 -2
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/{FundingRoutes.d.ts → FundingQuotes.d.ts} +185 -428
- package/dist/internal/FundingQuotes.d.ts.map +1 -0
- package/dist/internal/{FundingRoutes.js → FundingQuotes.js} +93 -218
- package/dist/internal/FundingQuotes.js.map +1 -0
- package/dist/internal/Viem.d.ts +3 -1
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +11 -2
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal/index.js +1 -1
- package/package.json +1 -1
- package/src/ApiKeys.test.ts +23 -0
- package/src/App.test-d.ts +2 -0
- package/src/App.ts +6 -0
- package/src/Client.test-d.ts +20 -11
- package/src/Scope.test.ts +1 -0
- package/src/Scope.ts +30 -4
- package/src/apps/data/App.test.ts +354 -0
- package/src/apps/data/App.ts +159 -52
- package/src/apps/data/FundingQuoteProviders.test.ts +151 -0
- package/src/apps/data/{FundingRouteProviders.ts → FundingQuoteProviders.ts} +40 -101
- package/src/apps/data/index.ts +1 -1
- package/src/apps/data/routes/balances.test.ts +64 -18
- package/src/apps/data/routes/balances.ts +76 -177
- package/src/apps/data/routes/blocks.ts +3 -5
- package/src/apps/data/routes/coingecko.ts +3 -8
- package/src/apps/data/routes/funding.test.ts +151 -206
- package/src/apps/data/routes/funding.ts +156 -291
- package/src/apps/data/routes/indexer.test.ts +97 -1
- package/src/apps/data/routes/rpc.test.ts +219 -0
- package/src/apps/data/routes/rpc.ts +92 -17
- package/src/apps/data/routes/webhooks.test.ts +21 -0
- package/src/apps/data/routes/webhooks.ts +13 -1
- package/src/apps/index.ts +1 -1
- package/src/apps/management/App.ts +4 -0
- package/src/apps/management/routes/api-keys.test.ts +47 -3
- package/src/apps/management/routes/api-keys.ts +2 -2
- package/src/apps/management/routes/invite-links.test.ts +385 -0
- package/src/apps/management/routes/invite-links.ts +570 -0
- package/src/apps/management/routes/scopes.test.ts +3 -2
- package/src/apps/management/routes/scopes.ts +4 -2
- package/src/apps/relay/App.test.ts +324 -4
- package/src/apps/relay/App.ts +40 -4
- package/src/db/Db.ts +65 -0
- package/src/db/Schema.ts +39 -0
- package/src/db/tables/inviteLinks.ts +187 -0
- package/src/db/tables/organizations.ts +2 -0
- package/src/handlers/relay.ts +16 -4
- package/src/internal/Auth.test.ts +132 -22
- package/src/internal/Auth.ts +171 -14
- package/src/internal/EdgeCache.test.ts +24 -3
- package/src/internal/EdgeCache.ts +18 -2
- package/src/internal/FundingQuotes.test.ts +174 -0
- package/src/internal/{FundingRoutes.ts → FundingQuotes.ts} +153 -312
- package/src/internal/Viem.ts +14 -5
- package/src/internal/index.test.ts +1 -1
- package/src/internal/index.ts +1 -1
- package/dist/apps/data/FundingRouteProviders.js.map +0 -1
- package/dist/internal/FundingRoutes.d.ts.map +0 -1
- package/dist/internal/FundingRoutes.js.map +0 -1
- package/src/apps/data/FundingRouteProviders.test.ts +0 -225
- package/src/internal/FundingRoutes.test.ts +0 -213
|
@@ -1,279 +1,224 @@
|
|
|
1
1
|
import { Schema } from 'tapimo'
|
|
2
2
|
|
|
3
|
+
import type * as FundingQuotes from '../../../internal/FundingQuotes.js'
|
|
3
4
|
import * as TestApp from '../../../../test/App.js'
|
|
4
5
|
import * as Funding from './funding.js'
|
|
5
6
|
|
|
6
|
-
describe('GET /funding/
|
|
7
|
-
test('returns
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
query: {
|
|
11
|
-
destinationToken: 'USDC.e',
|
|
12
|
-
sourceAmount: '1000000',
|
|
13
|
-
sourceChain: 'base',
|
|
14
|
-
sourceToken: 'USDC',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
TestApp.auth,
|
|
18
|
-
)
|
|
7
|
+
describe('GET /funding/quotes', () => {
|
|
8
|
+
test('returns successful live quotes with output amounts', async () => {
|
|
9
|
+
const app = TestApp.create({ funding: { adapters: { relay: relayAdapter() } } })
|
|
10
|
+
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
19
11
|
expect(response.status).toBe(200)
|
|
20
|
-
|
|
12
|
+
expect(response.headers.get('cache-control')).toBe('no-store')
|
|
13
|
+
const body = await TestApp.json(response, Funding.schema.quoteFunding.Response)
|
|
21
14
|
|
|
22
|
-
expect(body.data
|
|
15
|
+
expect(body.data).toHaveLength(1)
|
|
23
16
|
expect(body.data[0]).toMatchObject({
|
|
24
|
-
destinationChain: { id: 'eip155:4217', name: 'Tempo' },
|
|
25
|
-
destinationToken: { symbol: 'USDC.e' },
|
|
26
17
|
id: 'base-usdc-tempo-usdce-relay',
|
|
27
|
-
|
|
18
|
+
provider: { id: 'relay' },
|
|
19
|
+
quality: { liquiditySource: 'providerQuote', tier: 'liquid' },
|
|
20
|
+
quote: {
|
|
21
|
+
inputAmount: '1000000',
|
|
22
|
+
outputAmount: '990000',
|
|
23
|
+
outputAmountFormatted: '0.99',
|
|
24
|
+
},
|
|
28
25
|
sourceAmount: { amount: '1000000', formatted: '1' },
|
|
29
|
-
sourceChain: { id: 'eip155:8453', name: 'Base' },
|
|
30
|
-
sourceToken: { symbol: 'USDC' },
|
|
31
|
-
status: 'unknown',
|
|
32
26
|
})
|
|
33
27
|
})
|
|
34
28
|
|
|
35
|
-
test('
|
|
29
|
+
test('queries only the requested provider', async () => {
|
|
30
|
+
let calls = 0
|
|
36
31
|
const app = TestApp.create({
|
|
37
|
-
|
|
32
|
+
funding: {
|
|
38
33
|
adapters: {
|
|
39
|
-
relay: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
expect(input.cache.bypass).toBe(true)
|
|
43
|
-
expect(input.include).toEqual(['quotes'])
|
|
44
|
-
expect(input.route.id).toBe('base-usdc-tempo-usdce-relay')
|
|
45
|
-
expect(input.sourceAmount.amount).toBe('1000000')
|
|
46
|
-
expect(input.sourceChain.id).toBe('eip155:8453')
|
|
47
|
-
expect(input.sourceToken.symbol).toBe('USDC')
|
|
48
|
-
return {
|
|
49
|
-
expiresAt: '2026-01-01T00:00:30Z',
|
|
50
|
-
limits: {
|
|
51
|
-
instantSourceAmount: '1000000000',
|
|
52
|
-
maxSourceAmount: '100000000000',
|
|
53
|
-
minSourceAmount: '500000',
|
|
54
|
-
},
|
|
55
|
-
minimumOutputAmount: '980000',
|
|
56
|
-
outputAmount: '990000',
|
|
57
|
-
outputAmountFormatted: '0.99',
|
|
58
|
-
quality: {
|
|
59
|
-
availableVolumeUsd: '1000.00',
|
|
60
|
-
estimatedSeconds: 4,
|
|
61
|
-
feeBps: 12,
|
|
62
|
-
historicalVolumeUsd24h: '100000.00',
|
|
63
|
-
instantVolumeUsd: '1000.00',
|
|
64
|
-
liquiditySource: 'providerQuote',
|
|
65
|
-
score: 91,
|
|
66
|
-
sourceDetail: 'providerEndpoint',
|
|
67
|
-
tier: 'liquid',
|
|
68
|
-
},
|
|
69
|
-
sampledAt: '2026-01-01T00:00:00Z',
|
|
70
|
-
status: 'available',
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
},
|
|
34
|
+
relay: relayAdapter(() => {
|
|
35
|
+
calls += 1
|
|
36
|
+
}),
|
|
74
37
|
},
|
|
75
38
|
},
|
|
76
39
|
})
|
|
40
|
+
const response = await app.request(quoteUrl({ ...baseUsdcQuery, provider: 'relay' }), {
|
|
41
|
+
headers: TestApp.auth.headers,
|
|
42
|
+
})
|
|
77
43
|
|
|
78
|
-
const response = await app.request(
|
|
79
|
-
'/v1/funding/routes?sourceChain=base&sourceToken=USDC&sourceAmount=1000000&provider=relay&include=quotes',
|
|
80
|
-
{ headers: { ...TestApp.auth.headers, 'Cache-Control': 'no-cache' } },
|
|
81
|
-
)
|
|
82
44
|
expect(response.status).toBe(200)
|
|
83
|
-
|
|
45
|
+
expect(calls).toBe(1)
|
|
46
|
+
})
|
|
84
47
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
id: 'base-usdc-tempo-usdce-relay',
|
|
89
|
-
quality: {
|
|
90
|
-
availableVolumeUsd: '1000.00',
|
|
91
|
-
liquiditySource: 'providerQuote',
|
|
92
|
-
sourceDetail: 'providerEndpoint',
|
|
93
|
-
tier: 'liquid',
|
|
94
|
-
},
|
|
95
|
-
quote: {
|
|
96
|
-
expiresAt: '2026-01-01T00:00:30Z',
|
|
97
|
-
inputAmount: '1000000',
|
|
98
|
-
limits: {
|
|
99
|
-
instantSourceAmount: '1000000000',
|
|
100
|
-
maxSourceAmount: '100000000000',
|
|
101
|
-
minSourceAmount: '500000',
|
|
102
|
-
},
|
|
103
|
-
minimumOutputAmount: '980000',
|
|
104
|
-
outputAmount: '990000',
|
|
105
|
-
outputAmountFormatted: '0.99',
|
|
106
|
-
sampledAt: '2026-01-01T00:00:00Z',
|
|
107
|
-
},
|
|
108
|
-
status: 'available',
|
|
48
|
+
test('returns an empty list when no provider is configured', async () => {
|
|
49
|
+
const response = await TestApp.create().request(quoteUrl(), {
|
|
50
|
+
headers: TestApp.auth.headers,
|
|
109
51
|
})
|
|
52
|
+
expect(response.status).toBe(200)
|
|
53
|
+
const body = await TestApp.json(response, Funding.schema.quoteFunding.Response)
|
|
54
|
+
expect(body.data).toEqual([])
|
|
110
55
|
})
|
|
111
56
|
|
|
112
|
-
test('
|
|
113
|
-
const
|
|
114
|
-
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
57
|
+
test('returns an empty list when the provider reports no quote', async () => {
|
|
58
|
+
const app = TestApp.create({
|
|
59
|
+
funding: {
|
|
60
|
+
adapters: {
|
|
61
|
+
relay: {
|
|
62
|
+
async probeQuote() {
|
|
63
|
+
return { sampledAt: '2026-01-01T00:00:00Z', status: 'unavailable' }
|
|
64
|
+
},
|
|
65
|
+
},
|
|
121
66
|
},
|
|
122
67
|
},
|
|
123
|
-
TestApp.auth,
|
|
124
|
-
)
|
|
125
|
-
expect(response.status).toBe(200)
|
|
126
|
-
const body = await TestApp.json(response, Funding.schema.listFundingRoutes.Response)
|
|
127
|
-
|
|
128
|
-
expect(body.data).toHaveLength(1)
|
|
129
|
-
expect(body.data[0]?.sourceAmount).toMatchObject({
|
|
130
|
-
amount: '1250000',
|
|
131
|
-
formatted: '1.25',
|
|
132
68
|
})
|
|
69
|
+
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
70
|
+
expect(response.status).toBe(200)
|
|
71
|
+
const body = await TestApp.json(response, Funding.schema.quoteFunding.Response)
|
|
72
|
+
expect(body.data).toEqual([])
|
|
133
73
|
})
|
|
134
74
|
|
|
135
|
-
test('
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
TestApp.auth,
|
|
146
|
-
)
|
|
147
|
-
expect(exactResponse.status).toBe(200)
|
|
148
|
-
const exactBody = await TestApp.json(exactResponse, Funding.schema.listFundingRoutes.Response)
|
|
149
|
-
expect(exactBody.data.map((route) => route.provider.id)).toEqual(['bridge'])
|
|
150
|
-
|
|
151
|
-
const lowercasedSolanaResponse = await TestApp.client().v1.funding.routes.$get(
|
|
152
|
-
{
|
|
153
|
-
query: {
|
|
154
|
-
sourceAmount: '1000000',
|
|
155
|
-
sourceChain: 'solana',
|
|
156
|
-
sourceToken: solanaMint.toLowerCase(),
|
|
75
|
+
test('returns 502 when every matching provider fails', async () => {
|
|
76
|
+
const app = TestApp.create({
|
|
77
|
+
funding: {
|
|
78
|
+
adapters: {
|
|
79
|
+
relay: {
|
|
80
|
+
async probeQuote() {
|
|
81
|
+
throw new Error('upstream unavailable')
|
|
82
|
+
},
|
|
83
|
+
},
|
|
157
84
|
},
|
|
158
85
|
},
|
|
159
|
-
|
|
160
|
-
)
|
|
161
|
-
expect(
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
)
|
|
166
|
-
expect(lowercasedSolanaBody.data).toEqual([])
|
|
86
|
+
})
|
|
87
|
+
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
88
|
+
expect(response.status).toBe(502)
|
|
89
|
+
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
90
|
+
expect(body.error.code).toBe('upstream_error')
|
|
91
|
+
})
|
|
167
92
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
93
|
+
test('rejects successful provider results without output amounts', async () => {
|
|
94
|
+
const app = TestApp.create({
|
|
95
|
+
funding: {
|
|
96
|
+
adapters: {
|
|
97
|
+
relay: {
|
|
98
|
+
async probeQuote() {
|
|
99
|
+
return { sampledAt: '2026-01-01T00:00:00Z', status: 'available' }
|
|
100
|
+
},
|
|
101
|
+
},
|
|
174
102
|
},
|
|
175
103
|
},
|
|
176
|
-
|
|
177
|
-
)
|
|
178
|
-
expect(
|
|
179
|
-
const lowercasedTronBody = await TestApp.json(
|
|
180
|
-
lowercasedTronResponse,
|
|
181
|
-
Funding.schema.listFundingRoutes.Response,
|
|
182
|
-
)
|
|
183
|
-
expect(lowercasedTronBody.data).toEqual([])
|
|
104
|
+
})
|
|
105
|
+
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
106
|
+
expect(response.status).toBe(502)
|
|
184
107
|
})
|
|
185
108
|
|
|
186
|
-
test('
|
|
187
|
-
const response = await TestApp.
|
|
188
|
-
{
|
|
189
|
-
|
|
190
|
-
sourceAmount: '1.234567890',
|
|
191
|
-
sourceAmountUnits: 'decimal',
|
|
192
|
-
sourceChain: 'base',
|
|
193
|
-
sourceToken: 'DAI',
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
TestApp.auth,
|
|
109
|
+
test('rejects invalid query parameters', async () => {
|
|
110
|
+
const response = await TestApp.create().request(
|
|
111
|
+
quoteUrl({ sourceAmount: '1000000', sourceChain: 'base' }),
|
|
112
|
+
{ headers: TestApp.auth.headers },
|
|
197
113
|
)
|
|
198
|
-
expect(response.status).toBe(
|
|
199
|
-
const body = await TestApp.json(response,
|
|
200
|
-
expect(body.
|
|
114
|
+
expect(response.status).toBe(400)
|
|
115
|
+
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
116
|
+
expect(body.error.code).toBe('query_invalid')
|
|
201
117
|
})
|
|
202
118
|
|
|
203
|
-
test('rejects
|
|
204
|
-
const response = await TestApp.
|
|
205
|
-
{
|
|
206
|
-
|
|
207
|
-
sourceAmount: '1.0000001',
|
|
208
|
-
sourceAmountUnits: 'decimal',
|
|
209
|
-
sourceChain: 'base',
|
|
210
|
-
sourceToken: 'USDC',
|
|
211
|
-
},
|
|
212
|
-
},
|
|
213
|
-
TestApp.auth,
|
|
119
|
+
test('rejects unsupported providers', async () => {
|
|
120
|
+
const response = await TestApp.create().request(
|
|
121
|
+
quoteUrl({ ...baseUsdcQuery, provider: 'bridge' }),
|
|
122
|
+
{ headers: TestApp.auth.headers },
|
|
214
123
|
)
|
|
215
124
|
expect(response.status).toBe(400)
|
|
216
125
|
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
217
126
|
expect(body.error.code).toBe('query_invalid')
|
|
218
127
|
})
|
|
219
128
|
|
|
220
|
-
test('rejects
|
|
129
|
+
test('rejects source chains without a live quote adapter', async () => {
|
|
221
130
|
const response = await TestApp.create().request(
|
|
222
|
-
|
|
131
|
+
quoteUrl({ ...baseUsdcQuery, sourceChain: 'solana' }),
|
|
223
132
|
{ headers: TestApp.auth.headers },
|
|
224
133
|
)
|
|
225
134
|
expect(response.status).toBe(400)
|
|
226
135
|
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
227
136
|
expect(body.error.code).toBe('query_invalid')
|
|
228
137
|
})
|
|
138
|
+
|
|
139
|
+
test('does not expose the removed routes endpoint', async () => {
|
|
140
|
+
const response = await TestApp.create().request(
|
|
141
|
+
'/v1/funding/routes?sourceChain=base&sourceToken=USDC&sourceAmount=1000000',
|
|
142
|
+
{ headers: TestApp.auth.headers },
|
|
143
|
+
)
|
|
144
|
+
expect(response.status).toBe(404)
|
|
145
|
+
})
|
|
229
146
|
})
|
|
230
147
|
|
|
231
148
|
describe('GET /funding/chains', () => {
|
|
232
|
-
test('lists
|
|
149
|
+
test('lists only inputs supported by quote providers', async () => {
|
|
233
150
|
const response = await TestApp.client().v1.funding.chains.$get(undefined, TestApp.auth)
|
|
234
151
|
expect(response.status).toBe(200)
|
|
235
152
|
const body = await TestApp.json(response, Funding.schema.listFundingChains.Response)
|
|
236
153
|
|
|
237
|
-
expect(body.data.map((chain) => chain.id)).toEqual([
|
|
238
|
-
|
|
239
|
-
'
|
|
240
|
-
'eip155:56',
|
|
241
|
-
'solana:mainnet',
|
|
242
|
-
'tron:mainnet',
|
|
243
|
-
])
|
|
244
|
-
expect(body.data.find((chain) => chain.id === 'solana:mainnet')?.tokens).toEqual(
|
|
245
|
-
expect.arrayContaining([expect.objectContaining({ symbol: 'USDC', standard: 'SPL' })]),
|
|
154
|
+
expect(body.data.map((chain) => chain.id)).toEqual(['eip155:1', 'eip155:8453', 'eip155:56'])
|
|
155
|
+
expect(body.data.flatMap((chain) => chain.tokens.map((token) => token.symbol))).toEqual(
|
|
156
|
+
expect.arrayContaining(['USDC', 'USDT']),
|
|
246
157
|
)
|
|
247
158
|
})
|
|
248
159
|
})
|
|
249
160
|
|
|
250
|
-
describe('GET /providers', () => {
|
|
251
|
-
test('lists providers
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
TestApp.auth,
|
|
255
|
-
)
|
|
161
|
+
describe('GET /funding/providers', () => {
|
|
162
|
+
test('lists quote providers and their configuration status', async () => {
|
|
163
|
+
const app = TestApp.create({ funding: { adapters: { relay: relayAdapter() } } })
|
|
164
|
+
const response = await app.request('/v1/funding/providers', {
|
|
165
|
+
headers: TestApp.auth.headers,
|
|
166
|
+
})
|
|
256
167
|
expect(response.status).toBe(200)
|
|
257
168
|
const body = await TestApp.json(response, Funding.schema.listProviders.Response)
|
|
258
169
|
|
|
259
|
-
expect(body.data
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
'planned',
|
|
170
|
+
expect(body.data).toEqual([
|
|
171
|
+
{
|
|
172
|
+
id: 'relay',
|
|
173
|
+
kind: 'solverNetwork',
|
|
174
|
+
name: 'Relay',
|
|
175
|
+
requiresApiKey: false,
|
|
176
|
+
status: 'configured',
|
|
177
|
+
},
|
|
268
178
|
])
|
|
269
179
|
})
|
|
270
180
|
|
|
271
|
-
test('
|
|
272
|
-
const response = await TestApp.create().request('/v1/providers
|
|
181
|
+
test('does not expose the removed generic provider endpoint', async () => {
|
|
182
|
+
const response = await TestApp.create().request('/v1/providers', {
|
|
273
183
|
headers: TestApp.auth.headers,
|
|
274
184
|
})
|
|
275
|
-
expect(response.status).toBe(
|
|
276
|
-
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
277
|
-
expect(body.error.code).toBe('query_invalid')
|
|
185
|
+
expect(response.status).toBe(404)
|
|
278
186
|
})
|
|
279
187
|
})
|
|
188
|
+
|
|
189
|
+
const baseUsdcQuery = {
|
|
190
|
+
sourceAmount: '1000000',
|
|
191
|
+
sourceChain: 'base',
|
|
192
|
+
sourceToken: 'USDC',
|
|
193
|
+
} as const
|
|
194
|
+
|
|
195
|
+
type QuoteQuery = Record<string, string>
|
|
196
|
+
|
|
197
|
+
function quoteUrl(query: QuoteQuery = baseUsdcQuery) {
|
|
198
|
+
return `/v1/funding/quotes?${new URLSearchParams(
|
|
199
|
+
Object.entries(query).map(([key, value]) => [key, String(value)]),
|
|
200
|
+
)}`
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function relayAdapter(onProbe: () => void = () => {}): FundingQuotes.ProviderAdapter {
|
|
204
|
+
return {
|
|
205
|
+
async probeQuote(input, signal) {
|
|
206
|
+
onProbe()
|
|
207
|
+
expect(signal.aborted).toBe(false)
|
|
208
|
+
expect(input.candidate.id).toBe('base-usdc-tempo-usdce-relay')
|
|
209
|
+
return {
|
|
210
|
+
minimumOutputAmount: '980000',
|
|
211
|
+
outputAmount: '990000',
|
|
212
|
+
outputAmountFormatted: '0.99',
|
|
213
|
+
quality: {
|
|
214
|
+
estimatedSeconds: 4,
|
|
215
|
+
liquiditySource: 'providerQuote',
|
|
216
|
+
sourceDetail: 'relay:quote-v2',
|
|
217
|
+
tier: 'liquid',
|
|
218
|
+
},
|
|
219
|
+
sampledAt: '2026-01-01T00:00:00Z',
|
|
220
|
+
status: 'available',
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
}
|