tapimo 0.2.0 → 0.3.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/README.md +31 -3
- package/dist/ApiKey.d.ts +1 -0
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +5 -2
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +28 -1
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +34 -1
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +7167 -4507
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +8 -0
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +11 -2
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +14 -3
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +128 -118
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +7 -0
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/scopes.d.ts +8 -0
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/apps/scopes.js +3 -0
- package/dist/admin/apps/scopes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +57 -57
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +13 -13
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +151 -0
- package/dist/analytics/Analytics.d.ts.map +1 -0
- package/dist/analytics/Analytics.js +212 -0
- package/dist/analytics/Analytics.js.map +1 -0
- package/dist/analytics/tables/requestEvents.d.ts +215 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -0
- package/dist/analytics/tables/requestEvents.js +264 -0
- package/dist/analytics/tables/requestEvents.js.map +1 -0
- package/dist/apps/data/App.d.ts +1024 -624
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +36 -0
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +45 -45
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/exchanges.d.ts +455 -455
- package/dist/apps/data/routes/fee-amm.d.ts +101 -101
- package/dist/apps/data/routes/funding.d.ts +765 -0
- package/dist/apps/data/routes/funding.d.ts.map +1 -0
- package/dist/apps/data/routes/funding.js +383 -0
- package/dist/apps/data/routes/funding.js.map +1 -0
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +2 -8
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +29 -36
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +29 -1
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +36 -36
- package/dist/apps/data/routes/transfers.d.ts +56 -56
- package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
- package/dist/apps/data/routes/webhooks.d.ts +45 -45
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +8 -8
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/docs/App.d.ts +4 -2
- package/dist/apps/docs/App.d.ts.map +1 -1
- package/dist/apps/docs/App.js +27 -95
- package/dist/apps/docs/App.js.map +1 -1
- package/dist/apps/docs/reference.d.ts +21 -0
- package/dist/apps/docs/reference.d.ts.map +1 -0
- package/dist/apps/docs/reference.js +112 -0
- package/dist/apps/docs/reference.js.map +1 -0
- package/dist/apps/index.d.ts +1 -0
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -0
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/mcp.d.ts +76 -0
- package/dist/apps/mcp.d.ts.map +1 -0
- package/dist/apps/mcp.js +188 -0
- package/dist/apps/mcp.js.map +1 -0
- package/dist/apps/platform/App.d.ts +3005 -728
- package/dist/apps/platform/App.d.ts.map +1 -1
- package/dist/apps/platform/App.js +13 -3
- package/dist/apps/platform/App.js.map +1 -1
- package/dist/apps/platform/Billing.d.ts +279 -0
- package/dist/apps/platform/Billing.d.ts.map +1 -0
- package/dist/apps/platform/Billing.js +477 -0
- package/dist/apps/platform/Billing.js.map +1 -0
- package/dist/apps/platform/index.d.ts +1 -0
- package/dist/apps/platform/index.d.ts.map +1 -1
- package/dist/apps/platform/index.js +1 -0
- package/dist/apps/platform/index.js.map +1 -1
- package/dist/apps/platform/routes/api-keys.d.ts +341 -49
- package/dist/apps/platform/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/platform/routes/api-keys.js +115 -13
- package/dist/apps/platform/routes/api-keys.js.map +1 -1
- package/dist/apps/platform/routes/billing.d.ts +1520 -0
- package/dist/apps/platform/routes/billing.d.ts.map +1 -0
- package/dist/apps/platform/routes/billing.js +795 -0
- package/dist/apps/platform/routes/billing.js.map +1 -0
- package/dist/apps/platform/routes/invitations.d.ts +201 -83
- package/dist/apps/platform/routes/invitations.d.ts.map +1 -1
- package/dist/apps/platform/routes/invitations.js +58 -0
- package/dist/apps/platform/routes/invitations.js.map +1 -1
- package/dist/apps/platform/routes/me.d.ts +17 -17
- package/dist/apps/platform/routes/orgs.d.ts +50 -36
- package/dist/apps/platform/routes/orgs.d.ts.map +1 -1
- package/dist/apps/platform/routes/orgs.js +14 -3
- package/dist/apps/platform/routes/orgs.js.map +1 -1
- package/dist/apps/platform/routes/projects.d.ts +97 -97
- package/dist/apps/platform/routes/scopes.d.ts +107 -0
- package/dist/apps/platform/routes/scopes.d.ts.map +1 -0
- package/dist/apps/platform/routes/scopes.js +66 -0
- package/dist/apps/platform/routes/scopes.js.map +1 -0
- package/dist/apps/platform/routes/usage.d.ts +588 -0
- package/dist/apps/platform/routes/usage.d.ts.map +1 -0
- package/dist/apps/platform/routes/usage.js +391 -0
- package/dist/apps/platform/routes/usage.js.map +1 -0
- package/dist/apps/relay/App.d.ts +4 -1
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +118 -10
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +2 -1
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/cli/Cli.d.ts +8 -1
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +11 -3
- package/dist/cli/Cli.js.map +1 -1
- package/dist/cli/commands/admin.d.ts +4 -0
- package/dist/cli/commands/admin.d.ts.map +1 -1
- package/dist/cli/commands/admin.js +80 -1
- package/dist/cli/commands/admin.js.map +1 -1
- package/dist/db/Db.d.ts +7 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +126 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +79 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +88 -2
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/billingSettings.d.ts +55 -0
- package/dist/db/tables/billingSettings.d.ts.map +1 -0
- package/dist/db/tables/billingSettings.js +70 -0
- package/dist/db/tables/billingSettings.js.map +1 -0
- package/dist/db/tables/invitations.js +2 -2
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +6 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +10 -4
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.js +2 -2
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +121 -0
- package/dist/db/tables/requestUsage.d.ts.map +1 -0
- package/dist/db/tables/requestUsage.js +150 -0
- package/dist/db/tables/requestUsage.js.map +1 -0
- package/dist/db/tables/sponsoredTransactions.d.ts +119 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +155 -2
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/stripeCustomers.d.ts +81 -0
- package/dist/db/tables/stripeCustomers.d.ts.map +1 -0
- package/dist/db/tables/stripeCustomers.js +120 -0
- package/dist/db/tables/stripeCustomers.js.map +1 -0
- package/dist/db/tables/users.js +2 -2
- package/dist/db/tables/users.js.map +1 -1
- package/dist/handlers/internal/sponsorship.d.ts +5 -2
- package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
- package/dist/handlers/internal/sponsorship.js +19 -5
- package/dist/handlers/internal/sponsorship.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts +10 -3
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +14 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/Auth.d.ts +18 -4
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +148 -76
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +4 -1
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +10 -0
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +39 -8
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/Fees.d.ts +27 -0
- package/dist/internal/Fees.d.ts.map +1 -0
- package/dist/internal/Fees.js +48 -0
- package/dist/internal/Fees.js.map +1 -0
- package/dist/internal/FundingRoutes.d.ts +183 -0
- package/dist/internal/FundingRoutes.d.ts.map +1 -0
- package/dist/internal/FundingRoutes.js +490 -0
- package/dist/internal/FundingRoutes.js.map +1 -0
- package/dist/internal/Id.d.ts +15 -0
- package/dist/internal/Id.d.ts.map +1 -0
- package/dist/internal/Id.js +22 -0
- package/dist/internal/Id.js.map +1 -0
- package/dist/internal/Log.d.ts +2 -0
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +3 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +10 -1
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +8 -1
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +25 -0
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +51 -0
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Response.d.ts +1 -1
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Schema.d.ts +8 -0
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +7 -0
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +3 -3
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +4 -3
- package/src/ApiKey.ts +9 -2
- package/src/ApiKeys.test.ts +51 -0
- package/src/ApiKeys.ts +50 -1
- package/src/App.test.ts +33 -86718
- package/src/App.ts +18 -0
- package/src/Client.test-d.ts +351 -0
- package/src/Scope.ts +16 -3
- package/src/admin/apps/scopes.test.ts +6 -0
- package/src/admin/apps/scopes.ts +3 -0
- package/src/admin/ui/src/components/Page.tsx +2 -3
- package/src/admin/ui/src/routes/__root.tsx +2 -2
- package/src/admin/ui/src/routes/api-keys.tsx +2 -2
- package/src/admin/ui.generated.ts +13 -13
- package/src/analytics/Analytics.test.ts +527 -0
- package/src/analytics/Analytics.ts +318 -0
- package/src/analytics/tables/requestEvents.ts +523 -0
- package/src/apps/data/App.test.ts +72 -0
- package/src/apps/data/App.ts +35 -0
- package/src/apps/data/routes/funding.test.ts +214 -0
- package/src/apps/data/routes/funding.ts +584 -0
- package/src/apps/data/routes/receipts.ts +2 -9
- package/src/apps/data/routes/rpc.test.ts +78 -2
- package/src/apps/data/routes/rpc.ts +31 -1
- package/src/apps/data/routes/webhooks.test.ts +1 -1
- package/src/apps/data/routes/webhooks.ts +11 -8
- package/src/apps/docs/App.ts +29 -100
- package/src/apps/docs/reference.ts +132 -0
- package/src/apps/index.ts +1 -0
- package/src/apps/mcp.test.ts +206 -0
- package/src/apps/mcp.ts +250 -0
- package/src/apps/platform/App.ts +43 -4
- package/src/apps/platform/Billing.test.ts +530 -0
- package/src/apps/platform/Billing.ts +682 -0
- package/src/apps/platform/index.ts +1 -0
- package/src/apps/platform/routes/api-keys.test.ts +172 -9
- package/src/apps/platform/routes/api-keys.ts +136 -20
- package/src/apps/platform/routes/billing.test.ts +1100 -0
- package/src/apps/platform/routes/billing.ts +966 -0
- package/src/apps/platform/routes/invitations.test.ts +55 -7
- package/src/apps/platform/routes/invitations.ts +68 -0
- package/src/apps/platform/routes/me.test.ts +230 -0
- package/src/apps/platform/routes/orgs.ts +26 -4
- package/src/apps/platform/routes/scopes.test.ts +29 -0
- package/src/apps/platform/routes/scopes.ts +85 -0
- package/src/apps/platform/routes/usage.test.ts +422 -0
- package/src/apps/platform/routes/usage.ts +527 -0
- package/src/apps/relay/App.test.ts +457 -8
- package/src/apps/relay/App.ts +120 -12
- package/src/apps/relay/Sponsorships.test.ts +1 -1
- package/src/apps/relay/Sponsorships.ts +2 -1
- package/src/cli/Cli.test.ts +25 -2
- package/src/cli/Cli.ts +17 -2
- package/src/cli/commands/admin.test.ts +83 -0
- package/src/cli/commands/admin.ts +89 -1
- package/src/db/Db.ts +137 -0
- package/src/db/Schema.ts +104 -2
- package/src/db/tables/billingSettings.test.ts +87 -0
- package/src/db/tables/billingSettings.ts +108 -0
- package/src/db/tables/invitations.ts +2 -2
- package/src/db/tables/organizations.test.ts +1 -1
- package/src/db/tables/organizations.ts +15 -5
- package/src/db/tables/projects.ts +2 -2
- package/src/db/tables/requestUsage.ts +231 -0
- package/src/db/tables/sponsoredTransactions.test.ts +108 -1
- package/src/db/tables/sponsoredTransactions.ts +230 -2
- package/src/db/tables/stripeCustomers.test.ts +109 -0
- package/src/db/tables/stripeCustomers.ts +162 -0
- package/src/db/tables/users.ts +2 -2
- package/src/handlers/internal/sponsorship.ts +34 -7
- package/src/handlers/internal/utils.ts +19 -7
- package/src/index.ts +1 -0
- package/src/internal/Auth.test.ts +175 -25
- package/src/internal/Auth.ts +175 -86
- package/src/internal/Cache.ts +5 -1
- package/src/internal/EdgeCache.test.ts +27 -4
- package/src/internal/EdgeCache.ts +47 -9
- package/src/internal/Fees.test.ts +32 -0
- package/src/internal/Fees.ts +51 -0
- package/src/internal/FundingRoutes.ts +583 -0
- package/src/internal/Id.test.ts +17 -0
- package/src/internal/Id.ts +24 -0
- package/src/internal/Log.test.ts +1 -0
- package/src/internal/Log.ts +5 -0
- package/src/internal/OpenApi.ts +12 -1
- package/src/internal/RateLimit.test.ts +84 -0
- package/src/internal/RateLimit.ts +70 -0
- package/src/internal/Response.ts +1 -1
- package/src/internal/Schema.ts +8 -0
- package/src/internal/Webhooks.test.ts +3 -3
- package/src/internal/Webhooks.ts +3 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Hex } from 'ox'
|
|
2
|
+
|
|
3
|
+
// Tempo gas prices (`maxFeePerGas`, `effectiveGasPrice`, block base fee) are
|
|
4
|
+
// denominated in attodollars (10^-18 USD) per gas, while fee-token balances
|
|
5
|
+
// use 6 decimals (microdollars, 10^-6 USD). The charged fee is
|
|
6
|
+
// `ceil(gas × gasPrice / 10^12)`, mirroring `calc_gas_balance_spending` in
|
|
7
|
+
// tempoxyz/tempo.
|
|
8
|
+
|
|
9
|
+
/** Attodollar exponent gas prices use (10^-18 USD per gas), fixed by the fee spec. */
|
|
10
|
+
const attoDecimals = 18
|
|
11
|
+
|
|
12
|
+
/** Fee-token decimals: TIP-20 fixes 6 (1 token unit = 1 microdollar). */
|
|
13
|
+
export const tokenDecimals = 6
|
|
14
|
+
|
|
15
|
+
/** Scaling between attodollar gas math and fee-token units, derived from the exponents. */
|
|
16
|
+
export const scalingFactor = 10n ** BigInt(attoDecimals - tokenDecimals)
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fee in fee-token base units for a gas amount priced in attodollars per gas
|
|
20
|
+
* (ceiling division). Works for actual fees (`gasUsed × effectiveGasPrice`)
|
|
21
|
+
* and signed caps (`gas × maxFeePerGas`) alike.
|
|
22
|
+
*
|
|
23
|
+
* @param gas - Gas amount.
|
|
24
|
+
* @param gasPrice - Price in attodollars per gas.
|
|
25
|
+
* @returns The fee in fee-token base units.
|
|
26
|
+
*/
|
|
27
|
+
export function fromGas(gas: bigint, gasPrice: bigint): bigint {
|
|
28
|
+
return (gas * gasPrice + scalingFactor - 1n) / scalingFactor
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Signed fee cap of a candidate transaction in fee-token base units:
|
|
33
|
+
* `gas × maxFeePerGas` (attodollars) scaled through {@link fromGas}. Undefined
|
|
34
|
+
* when either field is missing or unparseable, so callers can fail closed.
|
|
35
|
+
*
|
|
36
|
+
* @param request - Transaction-shaped fee fields.
|
|
37
|
+
* @returns The cap in base units, or undefined.
|
|
38
|
+
*/
|
|
39
|
+
export function maxOf(request: { gas?: unknown; maxFeePerGas?: unknown }): bigint | undefined {
|
|
40
|
+
const gas = toBigInt(request.gas)
|
|
41
|
+
const maxFeePerGas = toBigInt(request.maxFeePerGas)
|
|
42
|
+
if (gas === undefined || maxFeePerGas === undefined) return undefined
|
|
43
|
+
return fromGas(gas, maxFeePerGas)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Fee fields arrive as bigints (raw envelopes) or hex quantities (fills). */
|
|
47
|
+
function toBigInt(value: unknown): bigint | undefined {
|
|
48
|
+
if (typeof value === 'bigint') return value
|
|
49
|
+
if (typeof value === 'string' && Hex.validate(value)) return Hex.toBigInt(value)
|
|
50
|
+
return undefined
|
|
51
|
+
}
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
/** Tempo mainnet as a CAIP-2 chain reference. */
|
|
2
|
+
const destinationChain = {
|
|
3
|
+
addressFormat: 'evm',
|
|
4
|
+
id: 'eip155:4217',
|
|
5
|
+
kind: 'evm',
|
|
6
|
+
name: 'Tempo',
|
|
7
|
+
} as const
|
|
8
|
+
|
|
9
|
+
/** Tempo token used when the caller omits `destinationToken`. */
|
|
10
|
+
const defaultDestinationToken = 'usdce'
|
|
11
|
+
|
|
12
|
+
/** Source chains accepted by the funding route inventory. */
|
|
13
|
+
const sourceChains = [
|
|
14
|
+
{
|
|
15
|
+
addressFormat: 'evm',
|
|
16
|
+
aliases: ['ethereum', 'eth', 'eip155:1'],
|
|
17
|
+
id: 'eip155:1',
|
|
18
|
+
kind: 'evm',
|
|
19
|
+
name: 'Ethereum',
|
|
20
|
+
providerIds: {
|
|
21
|
+
across: '1',
|
|
22
|
+
bridge: 'ethereum',
|
|
23
|
+
bungee: '1',
|
|
24
|
+
lifi: '1',
|
|
25
|
+
relay: '1',
|
|
26
|
+
},
|
|
27
|
+
slug: 'ethereum',
|
|
28
|
+
tokens: [
|
|
29
|
+
{
|
|
30
|
+
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
31
|
+
coingeckoId: 'usd-coin',
|
|
32
|
+
decimals: 6,
|
|
33
|
+
name: 'USD Coin',
|
|
34
|
+
standard: 'ERC-20',
|
|
35
|
+
symbol: 'USDC',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
39
|
+
coingeckoId: 'tether',
|
|
40
|
+
decimals: 6,
|
|
41
|
+
name: 'Tether USD',
|
|
42
|
+
standard: 'ERC-20',
|
|
43
|
+
symbol: 'USDT',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
address: '0x6c3ea9036406852006290770bedfcaba0e23a0e8',
|
|
47
|
+
coingeckoId: 'paypal-usd',
|
|
48
|
+
decimals: 6,
|
|
49
|
+
name: 'PayPal USD',
|
|
50
|
+
standard: 'ERC-20',
|
|
51
|
+
symbol: 'PYUSD',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
address: '0x1abaea1f7c830bd89acc67ec4af516284b1bc33c',
|
|
55
|
+
coingeckoId: 'euro-coin',
|
|
56
|
+
decimals: 6,
|
|
57
|
+
name: 'Euro Coin',
|
|
58
|
+
standard: 'ERC-20',
|
|
59
|
+
symbol: 'EURC',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
|
63
|
+
coingeckoId: 'dai',
|
|
64
|
+
decimals: 18,
|
|
65
|
+
name: 'Dai Stablecoin',
|
|
66
|
+
standard: 'ERC-20',
|
|
67
|
+
symbol: 'DAI',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
addressFormat: 'evm',
|
|
73
|
+
aliases: ['base', 'eip155:8453'],
|
|
74
|
+
id: 'eip155:8453',
|
|
75
|
+
kind: 'evm',
|
|
76
|
+
name: 'Base',
|
|
77
|
+
providerIds: {
|
|
78
|
+
across: '8453',
|
|
79
|
+
bridge: 'base',
|
|
80
|
+
bungee: '8453',
|
|
81
|
+
lifi: '8453',
|
|
82
|
+
relay: '8453',
|
|
83
|
+
},
|
|
84
|
+
slug: 'base',
|
|
85
|
+
tokens: [
|
|
86
|
+
{
|
|
87
|
+
address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
88
|
+
coingeckoId: 'usd-coin',
|
|
89
|
+
decimals: 6,
|
|
90
|
+
name: 'USD Coin',
|
|
91
|
+
standard: 'ERC-20',
|
|
92
|
+
symbol: 'USDC',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
address: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
|
|
96
|
+
coingeckoId: 'tether',
|
|
97
|
+
decimals: 6,
|
|
98
|
+
name: 'Tether USD',
|
|
99
|
+
standard: 'ERC-20',
|
|
100
|
+
symbol: 'USDT',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
address: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
104
|
+
coingeckoId: 'euro-coin',
|
|
105
|
+
decimals: 6,
|
|
106
|
+
name: 'Euro Coin',
|
|
107
|
+
standard: 'ERC-20',
|
|
108
|
+
symbol: 'EURC',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
addressFormat: 'evm',
|
|
114
|
+
aliases: ['bnb', 'bsc', 'eip155:56'],
|
|
115
|
+
id: 'eip155:56',
|
|
116
|
+
kind: 'evm',
|
|
117
|
+
name: 'BNB Smart Chain',
|
|
118
|
+
providerIds: {
|
|
119
|
+
across: '56',
|
|
120
|
+
bungee: '56',
|
|
121
|
+
lifi: '56',
|
|
122
|
+
relay: '56',
|
|
123
|
+
},
|
|
124
|
+
slug: 'bnb',
|
|
125
|
+
tokens: [
|
|
126
|
+
{
|
|
127
|
+
address: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d',
|
|
128
|
+
coingeckoId: 'usd-coin',
|
|
129
|
+
decimals: 18,
|
|
130
|
+
name: 'Binance-Peg USD Coin',
|
|
131
|
+
standard: 'BEP-20',
|
|
132
|
+
symbol: 'USDC',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
address: '0x55d398326f99059ff775485246999027b3197955',
|
|
136
|
+
coingeckoId: 'tether',
|
|
137
|
+
decimals: 18,
|
|
138
|
+
name: 'Tether USD',
|
|
139
|
+
standard: 'BEP-20',
|
|
140
|
+
symbol: 'USDT',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
addressFormat: 'solana',
|
|
146
|
+
aliases: ['solana', 'solana:mainnet'],
|
|
147
|
+
id: 'solana:mainnet',
|
|
148
|
+
kind: 'solana',
|
|
149
|
+
name: 'Solana',
|
|
150
|
+
providerIds: {
|
|
151
|
+
bridge: 'solana',
|
|
152
|
+
relay: 'solana',
|
|
153
|
+
},
|
|
154
|
+
slug: 'solana',
|
|
155
|
+
tokens: [
|
|
156
|
+
{
|
|
157
|
+
address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
158
|
+
coingeckoId: 'usd-coin',
|
|
159
|
+
decimals: 6,
|
|
160
|
+
name: 'USD Coin',
|
|
161
|
+
standard: 'SPL',
|
|
162
|
+
symbol: 'USDC',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
address: 'Es9vMFrzaCERmJfrF4H2FYD4KCo3LwC1uix9YEaQ8t1v',
|
|
166
|
+
coingeckoId: 'tether',
|
|
167
|
+
decimals: 6,
|
|
168
|
+
name: 'Tether USD',
|
|
169
|
+
standard: 'SPL',
|
|
170
|
+
symbol: 'USDT',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
addressFormat: 'tron',
|
|
176
|
+
aliases: ['tron', 'tron:mainnet'],
|
|
177
|
+
id: 'tron:mainnet',
|
|
178
|
+
kind: 'tron',
|
|
179
|
+
name: 'Tron',
|
|
180
|
+
providerIds: {
|
|
181
|
+
bridge: 'tron',
|
|
182
|
+
relay: 'tron',
|
|
183
|
+
},
|
|
184
|
+
slug: 'tron',
|
|
185
|
+
tokens: [
|
|
186
|
+
{
|
|
187
|
+
address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
|
|
188
|
+
coingeckoId: 'tether',
|
|
189
|
+
decimals: 6,
|
|
190
|
+
name: 'Tether USD',
|
|
191
|
+
standard: 'TRC-20',
|
|
192
|
+
symbol: 'USDT',
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
] as const
|
|
197
|
+
|
|
198
|
+
/** Tempo destination tokens supported by the initial funding route inventory. */
|
|
199
|
+
const destinationTokens = [
|
|
200
|
+
{
|
|
201
|
+
address: '0x20c0000000000000000000000000000000000000',
|
|
202
|
+
decimals: 6,
|
|
203
|
+
name: 'pathUSD',
|
|
204
|
+
slug: 'pathusd',
|
|
205
|
+
standard: 'TIP-20',
|
|
206
|
+
symbol: 'pathUSD',
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
address: '0x20c000000000000000000000b9537d11c60e8b50',
|
|
210
|
+
decimals: 6,
|
|
211
|
+
name: 'Bridged USDC (Stargate)',
|
|
212
|
+
slug: 'usdce',
|
|
213
|
+
standard: 'TIP-20',
|
|
214
|
+
symbol: 'USDC.e',
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
address: '0x20c0000000000000000000001621e21f71cf12fb',
|
|
218
|
+
decimals: 6,
|
|
219
|
+
name: 'Bridged EURC',
|
|
220
|
+
slug: 'eurce',
|
|
221
|
+
standard: 'TIP-20',
|
|
222
|
+
symbol: 'EURC.e',
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
address: '0x20c00000000000000000000014f22ca97301eb73',
|
|
226
|
+
decimals: 6,
|
|
227
|
+
name: 'USDT0',
|
|
228
|
+
slug: 'usdt0',
|
|
229
|
+
standard: 'TIP-20',
|
|
230
|
+
symbol: 'USDT0',
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
address: '0x20c0000000000000000000003554d28269e0f3c2',
|
|
234
|
+
decimals: 6,
|
|
235
|
+
name: 'frxUSD',
|
|
236
|
+
slug: 'frxusd',
|
|
237
|
+
standard: 'TIP-20',
|
|
238
|
+
symbol: 'frxUSD',
|
|
239
|
+
},
|
|
240
|
+
] as const
|
|
241
|
+
|
|
242
|
+
/** Providers exposed by the generic provider catalog. */
|
|
243
|
+
const providers = [
|
|
244
|
+
{
|
|
245
|
+
capabilities: ['fundingRoutes'],
|
|
246
|
+
id: 'across',
|
|
247
|
+
kind: 'intentBridge',
|
|
248
|
+
name: 'Across',
|
|
249
|
+
requiresApiKey: true,
|
|
250
|
+
status: 'inventoryOnly',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
capabilities: ['fundingRoutes'],
|
|
254
|
+
id: 'relay',
|
|
255
|
+
kind: 'solverNetwork',
|
|
256
|
+
name: 'Relay',
|
|
257
|
+
requiresApiKey: false,
|
|
258
|
+
status: 'inventoryOnly',
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
capabilities: ['fundingRoutes'],
|
|
262
|
+
id: 'bridge',
|
|
263
|
+
kind: 'enterpriseTransfer',
|
|
264
|
+
name: 'Bridge.xyz',
|
|
265
|
+
requiresApiKey: true,
|
|
266
|
+
status: 'inventoryOnly',
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
capabilities: ['fundingRoutes'],
|
|
270
|
+
id: 'bungee',
|
|
271
|
+
kind: 'aggregator',
|
|
272
|
+
name: 'Bungee',
|
|
273
|
+
requiresApiKey: false,
|
|
274
|
+
status: 'inventoryOnly',
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
capabilities: ['fundingRoutes'],
|
|
278
|
+
id: 'lifi',
|
|
279
|
+
kind: 'aggregator',
|
|
280
|
+
name: 'LI.FI',
|
|
281
|
+
requiresApiKey: true,
|
|
282
|
+
status: 'planned',
|
|
283
|
+
},
|
|
284
|
+
] as const
|
|
285
|
+
|
|
286
|
+
type TokenInput = (typeof sourceChains)[number]['tokens'][number]
|
|
287
|
+
type DestinationTokenInput = (typeof destinationTokens)[number]
|
|
288
|
+
type ProviderInput = (typeof providers)[number]
|
|
289
|
+
type SourceChainInput = (typeof sourceChains)[number]
|
|
290
|
+
|
|
291
|
+
/** Static provider support rows used until live quote adapters are configured. */
|
|
292
|
+
const inventory: readonly InventoryEntry[] = [
|
|
293
|
+
{ destinationToken: 'usdce', provider: 'across', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC'] }, // prettier-ignore
|
|
294
|
+
{ destinationToken: 'usdce', provider: 'relay', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC', 'USDT'] }, // prettier-ignore
|
|
295
|
+
{ destinationToken: 'usdce', provider: 'bridge', sourceChains: ['ethereum', 'base', 'solana'], sourceTokens: ['USDC'] }, // prettier-ignore
|
|
296
|
+
{ destinationToken: 'usdce', provider: 'bridge', sourceChains: ['ethereum', 'solana', 'tron'], sourceTokens: ['USDT'] }, // prettier-ignore
|
|
297
|
+
{ destinationToken: 'usdce', provider: 'bungee', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC'] }, // prettier-ignore
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
type InventoryEntry = {
|
|
301
|
+
destinationToken: string
|
|
302
|
+
provider: ProviderInput['id']
|
|
303
|
+
sourceChains: readonly string[]
|
|
304
|
+
sourceTokens: readonly string[]
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Lists normalized chains and source tokens that can fund Tempo. */
|
|
308
|
+
export function listChains() {
|
|
309
|
+
return sourceChains.map((chain) => ({
|
|
310
|
+
...formatChain(chain),
|
|
311
|
+
tokens: chain.tokens.map((token) => formatSourceToken(chain, token)),
|
|
312
|
+
}))
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** Lists providers, optionally filtered by one provider capability. */
|
|
316
|
+
export function listProviders(options: listProviders.Options = {}) {
|
|
317
|
+
return providers
|
|
318
|
+
.filter((provider) =>
|
|
319
|
+
options.capability === undefined ? true : provider.capabilities.includes(options.capability),
|
|
320
|
+
)
|
|
321
|
+
.map(formatProvider)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export declare namespace listProviders {
|
|
325
|
+
/** Options for listing providers. */
|
|
326
|
+
type Options = {
|
|
327
|
+
/** Provider capability to require. */
|
|
328
|
+
capability?: Capability | undefined
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Lists static funding route candidates for a normalized caller request. */
|
|
333
|
+
export function listRoutes(options: listRoutes.Options) {
|
|
334
|
+
const sourceChain = resolveSourceChain(options.sourceChain)
|
|
335
|
+
const sourceToken = resolveSourceToken(sourceChain, options.sourceToken)
|
|
336
|
+
const destinationToken = resolveDestinationToken(options.destinationToken)
|
|
337
|
+
const provider = options.provider ? resolveProvider(options.provider) : undefined
|
|
338
|
+
|
|
339
|
+
if (!sourceToken) {
|
|
340
|
+
validateSourceAmountSyntax(options.sourceAmount, options.sourceAmountUnits)
|
|
341
|
+
return []
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const sourceAmount = resolveSourceAmount({
|
|
345
|
+
amount: options.sourceAmount,
|
|
346
|
+
token: sourceToken,
|
|
347
|
+
units: options.sourceAmountUnits,
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
return inventory
|
|
351
|
+
.filter((entry) => entry.sourceChains.includes(sourceChain.slug))
|
|
352
|
+
.filter((entry) => entry.sourceTokens.includes(sourceToken.symbol))
|
|
353
|
+
.filter((entry) => entry.destinationToken === destinationToken.slug)
|
|
354
|
+
.filter((entry) => provider === undefined || entry.provider === provider.id)
|
|
355
|
+
.slice(0, options.limit)
|
|
356
|
+
.map((entry) => {
|
|
357
|
+
const entryProvider = providers.find((candidate) => candidate.id === entry.provider)!
|
|
358
|
+
return {
|
|
359
|
+
destinationChain,
|
|
360
|
+
destinationToken: formatDestinationToken(destinationToken),
|
|
361
|
+
id: [
|
|
362
|
+
sourceChain.slug,
|
|
363
|
+
sourceToken.symbol.toLowerCase(),
|
|
364
|
+
'tempo',
|
|
365
|
+
destinationToken.slug,
|
|
366
|
+
entryProvider.id,
|
|
367
|
+
].join('-'),
|
|
368
|
+
provider: formatProviderRef(entryProvider),
|
|
369
|
+
quality: {
|
|
370
|
+
availableVolumeUsd: null,
|
|
371
|
+
estimatedSeconds: null,
|
|
372
|
+
feeBps: null,
|
|
373
|
+
historicalVolumeUsd24h: null,
|
|
374
|
+
instantVolumeUsd: null,
|
|
375
|
+
liquiditySource: 'staticInventory',
|
|
376
|
+
score: null,
|
|
377
|
+
tier: 'unknown' as const,
|
|
378
|
+
},
|
|
379
|
+
sourceAmount,
|
|
380
|
+
sourceChain: formatChain(sourceChain),
|
|
381
|
+
sourceToken: formatSourceToken(sourceChain, sourceToken),
|
|
382
|
+
status: 'unknown' as const,
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export declare namespace listRoutes {
|
|
388
|
+
/** Options for listing funding routes. */
|
|
389
|
+
type Options = {
|
|
390
|
+
/** Optional Tempo destination token symbol, address, or token key. */
|
|
391
|
+
destinationToken?: string | undefined
|
|
392
|
+
/** Maximum number of route candidates to return. */
|
|
393
|
+
limit: number
|
|
394
|
+
/** Optional provider id filter. */
|
|
395
|
+
provider?: string | undefined
|
|
396
|
+
/** Source amount as supplied by the caller. */
|
|
397
|
+
sourceAmount: string
|
|
398
|
+
/** Unit used by {@link sourceAmount}. */
|
|
399
|
+
sourceAmountUnits: SourceAmountUnits
|
|
400
|
+
/** Chain alias or CAIP-2 source chain id. */
|
|
401
|
+
sourceChain: string
|
|
402
|
+
/** Source token symbol, contract address, mint, or Tempo token key. */
|
|
403
|
+
sourceToken: string
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/** Provider capability identifiers accepted by the generic provider catalog. */
|
|
408
|
+
export type Capability = 'fundingRoutes'
|
|
409
|
+
|
|
410
|
+
/** Source amount unit accepted by the funding route request. */
|
|
411
|
+
export type SourceAmountUnits = 'baseUnits' | 'decimal'
|
|
412
|
+
|
|
413
|
+
function tokenKey(chain: { id: string }, token: TokenInput | DestinationTokenInput) {
|
|
414
|
+
const standard =
|
|
415
|
+
token.standard === 'SPL' ? 'spl' : token.standard === 'TRC-20' ? 'trc20' : 'erc20'
|
|
416
|
+
return `${chain.id}/${standard}:${token.address}`
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function decimalFromBaseUnits(baseUnits: string, decimals: number) {
|
|
420
|
+
const padded = baseUnits.padStart(decimals + 1, '0')
|
|
421
|
+
const whole = decimals === 0 ? padded : padded.slice(0, -decimals)
|
|
422
|
+
const fraction = decimals === 0 ? '' : padded.slice(-decimals).replace(/0+$/, '')
|
|
423
|
+
return fraction ? `${whole}.${fraction}` : whole
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function formatChain(chain: SourceChainInput) {
|
|
427
|
+
const { addressFormat, id, kind, name, providerIds } = chain
|
|
428
|
+
return { addressFormat, id, kind, name, providerIds }
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function formatDestinationToken(token: DestinationTokenInput) {
|
|
432
|
+
return {
|
|
433
|
+
address: token.address,
|
|
434
|
+
decimals: token.decimals,
|
|
435
|
+
metadata: {},
|
|
436
|
+
name: token.name,
|
|
437
|
+
standard: token.standard,
|
|
438
|
+
symbol: token.symbol,
|
|
439
|
+
tokenKey: tokenKey(destinationChain, token),
|
|
440
|
+
verified: true,
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function formatProvider(provider: ProviderInput) {
|
|
445
|
+
const { id, kind, name, requiresApiKey, status } = provider
|
|
446
|
+
return { capabilities: [...provider.capabilities], id, kind, name, requiresApiKey, status }
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function formatProviderRef(provider: ProviderInput) {
|
|
450
|
+
const { id, kind, name, requiresApiKey } = provider
|
|
451
|
+
return { id, kind, name, requiresApiKey }
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function formatSourceToken(chain: SourceChainInput, token: TokenInput) {
|
|
455
|
+
return {
|
|
456
|
+
address: token.address,
|
|
457
|
+
decimals: token.decimals,
|
|
458
|
+
metadata: { coingeckoId: token.coingeckoId },
|
|
459
|
+
name: token.name,
|
|
460
|
+
standard: token.standard,
|
|
461
|
+
symbol: token.symbol,
|
|
462
|
+
tokenKey: tokenKey(chain, token),
|
|
463
|
+
verified: true,
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function normalizeInput(value: string) {
|
|
468
|
+
return value.trim().toLowerCase()
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function parseBaseUnits(value: string) {
|
|
472
|
+
if (!/^\d+$/.test(value) || BigInt(value) <= 0n) throw new InvalidAmountError()
|
|
473
|
+
return BigInt(value).toString()
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function parseDecimalUnits(value: string, decimals: number) {
|
|
477
|
+
if (!/^\d+(\.\d+)?$/.test(value)) throw new InvalidAmountError()
|
|
478
|
+
const [whole, fraction = ''] = value.split('.')
|
|
479
|
+
if (fraction.length > decimals) throw new InvalidAmountError()
|
|
480
|
+
const baseUnits = BigInt(`${whole}${fraction.padEnd(decimals, '0')}`)
|
|
481
|
+
if (baseUnits <= 0n) throw new InvalidAmountError()
|
|
482
|
+
return baseUnits.toString()
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function resolveDestinationToken(input: string | undefined) {
|
|
486
|
+
if (input === undefined) return destinationTokens.find((token) => token.slug === defaultDestinationToken)! // prettier-ignore
|
|
487
|
+
const normalized = normalizeInput(input)
|
|
488
|
+
const token = destinationTokens.find(
|
|
489
|
+
(candidate) =>
|
|
490
|
+
candidate.slug === normalized ||
|
|
491
|
+
candidate.symbol.toLowerCase() === normalized ||
|
|
492
|
+
candidate.address === normalized ||
|
|
493
|
+
tokenKey(destinationChain, candidate).toLowerCase() === normalized,
|
|
494
|
+
)
|
|
495
|
+
if (!token) throw new UnsupportedDestinationTokenError()
|
|
496
|
+
return token
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function resolveProvider(input: string) {
|
|
500
|
+
const provider = providers.find((candidate) => candidate.id === normalizeInput(input))
|
|
501
|
+
if (!provider) throw new UnsupportedProviderError()
|
|
502
|
+
return provider
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function resolveSourceAmount(options: resolveSourceAmount.Options) {
|
|
506
|
+
const amount =
|
|
507
|
+
options.units === 'baseUnits'
|
|
508
|
+
? parseBaseUnits(options.amount)
|
|
509
|
+
: parseDecimalUnits(options.amount, options.token.decimals)
|
|
510
|
+
return {
|
|
511
|
+
amount,
|
|
512
|
+
formatted: decimalFromBaseUnits(amount, options.token.decimals),
|
|
513
|
+
usd: null,
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
declare namespace resolveSourceAmount {
|
|
518
|
+
type Options = {
|
|
519
|
+
amount: string
|
|
520
|
+
token: TokenInput
|
|
521
|
+
units: SourceAmountUnits
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function resolveSourceToken(chain: SourceChainInput, input: string) {
|
|
526
|
+
const trimmed = input.trim()
|
|
527
|
+
const normalized = trimmed.toLowerCase()
|
|
528
|
+
return chain.tokens.find(
|
|
529
|
+
(token) =>
|
|
530
|
+
token.symbol.toLowerCase() === normalized ||
|
|
531
|
+
matchesTokenIdentifier(chain, token.address, trimmed, normalized) ||
|
|
532
|
+
matchesTokenIdentifier(chain, tokenKey(chain, token), trimmed, normalized),
|
|
533
|
+
)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function matchesTokenIdentifier(
|
|
537
|
+
chain: SourceChainInput,
|
|
538
|
+
candidate: string,
|
|
539
|
+
trimmed: string,
|
|
540
|
+
normalized: string,
|
|
541
|
+
) {
|
|
542
|
+
return chain.kind === 'evm' ? candidate.toLowerCase() === normalized : candidate === trimmed
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function resolveSourceChain(input: string) {
|
|
546
|
+
const normalized = normalizeInput(input)
|
|
547
|
+
const chain = sourceChains.find(
|
|
548
|
+
(candidate) =>
|
|
549
|
+
candidate.id === normalized || (candidate.aliases as readonly string[]).includes(normalized),
|
|
550
|
+
)
|
|
551
|
+
if (!chain) throw new UnsupportedSourceChainError()
|
|
552
|
+
return chain
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function validateSourceAmountSyntax(value: string, units: SourceAmountUnits) {
|
|
556
|
+
if (units === 'baseUnits') {
|
|
557
|
+
parseBaseUnits(value)
|
|
558
|
+
return
|
|
559
|
+
}
|
|
560
|
+
if (!/^\d+(\.\d+)?$/.test(value)) throw new InvalidAmountError()
|
|
561
|
+
const [whole, fraction = ''] = value.split('.')
|
|
562
|
+
if (BigInt(`${whole}${fraction}`) <= 0n) throw new InvalidAmountError()
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Error thrown when the caller supplies an unsupported destination token. */
|
|
566
|
+
export class UnsupportedDestinationTokenError extends Error {
|
|
567
|
+
override name = 'FundingRoutes.UnsupportedDestinationTokenError'
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/** Error thrown when the caller supplies an invalid source amount. */
|
|
571
|
+
export class InvalidAmountError extends Error {
|
|
572
|
+
override name = 'FundingRoutes.InvalidAmountError'
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/** Error thrown when the caller filters to an unknown provider. */
|
|
576
|
+
export class UnsupportedProviderError extends Error {
|
|
577
|
+
override name = 'FundingRoutes.UnsupportedProviderError'
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/** Error thrown when the caller supplies an unsupported source chain. */
|
|
581
|
+
export class UnsupportedSourceChainError extends Error {
|
|
582
|
+
override name = 'FundingRoutes.UnsupportedSourceChainError'
|
|
583
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as Id from './Id.js'
|
|
2
|
+
|
|
3
|
+
describe('generate', () => {
|
|
4
|
+
test('produces a prefixed 24-char base62 id', () => {
|
|
5
|
+
expect(Id.generate('usr')).toMatch(/^usr_[0-9A-Za-z]{24}$/)
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('never emits `_` or `-` in the random segment', () => {
|
|
9
|
+
for (let i = 0; i < 100; i++) expect(Id.generate('org').slice(4)).toMatch(/^[0-9A-Za-z]{24}$/)
|
|
10
|
+
})
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('random', () => {
|
|
14
|
+
test('produces a 24-char base62 segment', () => {
|
|
15
|
+
expect(Id.random()).toMatch(/^[0-9A-Za-z]{24}$/)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { customAlphabet } from 'nanoid'
|
|
2
|
+
|
|
3
|
+
/** Base62 alphabet: `_` and `-` excluded so the prefix separator stays unambiguous. */
|
|
4
|
+
const segment = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 24)
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generates a prefixed resource id (`{prefix}_{24 base62 chars}`, ~143 bits).
|
|
8
|
+
*
|
|
9
|
+
* @param prefix - The resource-type prefix (e.g. `usr`, `org`).
|
|
10
|
+
* @returns The generated id.
|
|
11
|
+
*/
|
|
12
|
+
export function generate(prefix: string): string {
|
|
13
|
+
return `${prefix}_${random()}`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generates the random segment of an id (24 base62 chars) without a prefix,
|
|
18
|
+
* for ids composing extra parts (e.g. `wh_{timestamp}_{random}`).
|
|
19
|
+
*
|
|
20
|
+
* @returns The generated segment.
|
|
21
|
+
*/
|
|
22
|
+
export function random(): string {
|
|
23
|
+
return segment()
|
|
24
|
+
}
|
package/src/internal/Log.test.ts
CHANGED
package/src/internal/Log.ts
CHANGED
|
@@ -47,6 +47,8 @@ export type Entry = {
|
|
|
47
47
|
| {
|
|
48
48
|
/** Attributed super admin identity for super admin callers. */
|
|
49
49
|
actor?: string | undefined
|
|
50
|
+
/** Whether the owning org's billing was active for API-key callers; drives request-metered billing. */
|
|
51
|
+
billingActive?: boolean | undefined
|
|
50
52
|
/** Key environment for API-key callers. */
|
|
51
53
|
environment?: ApiKey.ApiKey['environment'] | undefined
|
|
52
54
|
/** Principal id: the API key id, the public quota identity, the user id, or `super_admin`. */
|
|
@@ -151,6 +153,9 @@ export function middleware<environment extends Environment = Environment>(
|
|
|
151
153
|
: {
|
|
152
154
|
principal: {
|
|
153
155
|
...(principal.type === 'super_admin' ? { actor: principal.actor } : {}),
|
|
156
|
+
...(principal.type === 'api_key'
|
|
157
|
+
? { billingActive: principal.apiKey.billingActive === true }
|
|
158
|
+
: {}),
|
|
154
159
|
...(principal.type === 'api_key' ? { environment: principal.environment } : {}),
|
|
155
160
|
id: principal.id,
|
|
156
161
|
...(principal.type === 'api_key' ? { orgId: principal.orgId } : {}),
|