tapimo 0.12.0 → 0.13.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 +5561 -5026
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +38 -3
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +2 -0
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +17 -0
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +123 -74
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +80 -0
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +54 -0
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +15 -15
- package/dist/admin/apps/earn-vaults.js +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +81 -81
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +151 -151
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/Zones.d.ts +16 -16
- package/dist/apps/Zones.js +4 -4
- package/dist/apps/data/App.js +18 -18
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/ZoneSelection.d.ts +8 -8
- package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
- package/dist/apps/data/ZoneSelection.js +1 -1
- package/dist/apps/data/ZoneSelection.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +588 -584
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +1561 -1239
- package/dist/apps/data/routes/activities.js.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 +43 -16
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +44 -44
- package/dist/apps/data/routes/blocks.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.js +21 -11
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +3 -3
- package/dist/apps/data/routes/earn.d.ts +18 -18
- package/dist/apps/data/routes/earn.js +13 -13
- package/dist/apps/data/routes/exchanges.d.ts +145 -145
- package/dist/apps/data/routes/fee-amm.d.ts +2 -2
- package/dist/apps/data/routes/receipts.d.ts +155 -55
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +28 -10
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +13 -13
- package/dist/apps/data/routes/tokens.d.ts +98 -98
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +51 -20
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +7 -2
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +37 -17
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +1 -1
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +18 -12
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +1 -1
- package/dist/apps/data/routes/valuation.d.ts.map +1 -1
- package/dist/apps/data/routes/valuation.js +12 -7
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +3 -3
- package/dist/apps/data/routes/webhooks.d.ts +11 -11
- package/dist/apps/data/routes/zones.d.ts +14 -14
- package/dist/apps/data/routes/zones.js +1 -1
- package/dist/apps/funding/App.d.ts +11 -0
- package/dist/apps/funding/App.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.js +16 -11
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/funding/routes/transfers.d.ts +60 -48
- package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
- package/dist/apps/funding/routes/transfers.js +27 -19
- package/dist/apps/funding/routes/transfers.js.map +1 -1
- package/dist/apps/management/App.d.ts +4487 -3963
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +710 -159
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +236 -4
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +6 -6
- package/dist/apps/management/routes/invite-links.d.ts +42 -42
- package/dist/apps/management/routes/members.d.ts +30 -30
- package/dist/apps/management/routes/projects.d.ts +40 -40
- package/dist/apps/management/routes/usage.d.ts +24 -24
- package/dist/apps/management/routes/verified-token-requests.d.ts +1 -1
- package/dist/apps/management/routes/webhooks.d.ts +55 -55
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +12 -1
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +3 -2
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +5 -2
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/fundingCatalog.d.ts +4 -2
- package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
- package/dist/db/tables/fundingCatalog.js +5 -1
- package/dist/db/tables/fundingCatalog.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +9 -0
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/internal/Auth.d.ts +3 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +6 -3
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EarnVaults.d.ts +3 -3
- package/dist/internal/EarnVaults.js +3 -3
- package/dist/internal/Fetch.d.ts +23 -0
- package/dist/internal/Fetch.d.ts.map +1 -0
- package/dist/internal/Fetch.js +26 -0
- package/dist/internal/Fetch.js.map +1 -0
- package/dist/internal/Log.d.ts +3 -1
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +16 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +5 -3
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +13 -3
- package/dist/internal/OpenApi.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 +6 -3
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +8 -2
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Store.d.ts +16 -3
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +82 -16
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +7 -2
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Timeout.d.ts +36 -0
- package/dist/internal/Timeout.d.ts.map +1 -0
- package/dist/internal/Timeout.js +37 -0
- package/dist/internal/Timeout.js.map +1 -0
- package/dist/internal/Timing.d.ts +9 -0
- package/dist/internal/Timing.d.ts.map +1 -1
- package/dist/internal/Timing.js +7 -0
- package/dist/internal/Timing.js.map +1 -1
- package/dist/internal/WebhookDestination.d.ts.map +1 -1
- package/dist/internal/WebhookDestination.js +3 -0
- package/dist/internal/WebhookDestination.js.map +1 -1
- package/dist/internal/funding/Action.d.ts +9 -0
- package/dist/internal/funding/Action.d.ts.map +1 -1
- package/dist/internal/funding/Action.js +16 -8
- package/dist/internal/funding/Action.js.map +1 -1
- package/dist/internal/funding/Catalog.d.ts +9 -2
- package/dist/internal/funding/Catalog.d.ts.map +1 -1
- package/dist/internal/funding/Catalog.js +19 -8
- package/dist/internal/funding/Catalog.js.map +1 -1
- package/dist/internal/funding/Provider.d.ts +68 -13
- package/dist/internal/funding/Provider.d.ts.map +1 -1
- package/dist/internal/funding/Provider.js +29 -8
- package/dist/internal/funding/Provider.js.map +1 -1
- package/dist/internal/funding/Transfer.d.ts +13 -12
- package/dist/internal/funding/Transfer.d.ts.map +1 -1
- package/dist/internal/funding/Transfer.js +23 -21
- package/dist/internal/funding/Transfer.js.map +1 -1
- package/dist/internal/funding/providers/stargate.d.ts +28 -9
- package/dist/internal/funding/providers/stargate.d.ts.map +1 -1
- package/dist/internal/funding/providers/stargate.js +251 -117
- package/dist/internal/funding/providers/stargate.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 +2 -2
- package/src/App.test.ts +100 -0
- package/src/App.ts +42 -3
- package/src/Client.test-d.ts +46 -0
- package/src/Scope.test.ts +20 -0
- package/src/Scope.ts +16 -0
- package/src/admin/apps/api-keys.test.ts +75 -0
- package/src/admin/apps/api-keys.ts +64 -0
- package/src/admin/apps/earn-vaults.test.ts +1 -1
- package/src/admin/apps/earn-vaults.ts +1 -1
- package/src/admin/ui/src/lib/api-keys.ts +19 -0
- package/src/admin/ui/src/routes/api-keys.tsx +89 -2
- package/src/admin/ui.generated.ts +189 -151
- package/src/apps/Zones.test.ts +4 -4
- package/src/apps/Zones.ts +4 -4
- package/src/apps/composition.test.ts +1 -1
- package/src/apps/data/App.test.ts +41 -0
- package/src/apps/data/App.ts +18 -18
- package/src/apps/data/ZoneSelection.test.ts +2 -2
- package/src/apps/data/ZoneSelection.ts +8 -8
- package/src/apps/data/routes/activities.test.ts +1526 -12
- package/src/apps/data/routes/activities.ts +1774 -1356
- package/src/apps/data/routes/balances.ts +133 -97
- package/src/apps/data/routes/blocks.test.ts +533 -0
- package/src/apps/data/routes/blocks.ts +35 -16
- package/src/apps/data/routes/earn.test.ts +4 -2
- package/src/apps/data/routes/earn.ts +13 -13
- package/src/apps/data/routes/earn.zone-access.test.ts +6 -6
- package/src/apps/data/routes/receipts.ts +47 -16
- package/src/apps/data/routes/tokens.test.ts +578 -0
- package/src/apps/data/routes/tokens.ts +283 -225
- package/src/apps/data/routes/transactions.ts +68 -29
- package/src/apps/data/routes/transfers.test.ts +421 -0
- package/src/apps/data/routes/transfers.ts +45 -27
- package/src/apps/data/routes/valuation.ts +94 -78
- package/src/apps/data/routes/zones.test.ts +2 -2
- package/src/apps/data/routes/zones.ts +1 -1
- package/src/apps/funding/routes/deposit-addresses.test.ts +25 -3
- package/src/apps/funding/routes/deposit-addresses.ts +17 -12
- package/src/apps/funding/routes/quotes.test.ts +5 -9
- package/src/apps/funding/routes/transfers.test.ts +395 -8
- package/src/apps/funding/routes/transfers.ts +76 -59
- package/src/apps/management/routes/api-keys.test.ts +220 -0
- package/src/apps/management/routes/api-keys.ts +280 -3
- package/src/db/Db.ts +13 -1
- package/src/db/Schema.ts +5 -2
- package/src/db/tables/earnVaults.test.ts +9 -9
- package/src/db/tables/fundingCatalog.test.ts +16 -2
- package/src/db/tables/fundingCatalog.ts +9 -3
- package/src/handlers/internal/utils.test.ts +53 -0
- package/src/handlers/internal/utils.ts +15 -0
- package/src/internal/Auth.ts +12 -4
- package/src/internal/EarnVaults.capabilities.test.ts +2 -2
- package/src/internal/EarnVaults.test.ts +1 -1
- package/src/internal/EarnVaults.ts +3 -3
- package/src/internal/Fetch.test.ts +46 -0
- package/src/internal/Fetch.ts +56 -0
- package/src/internal/Log.test.ts +21 -0
- package/src/internal/Log.ts +20 -5
- package/src/internal/OpenApi.ts +14 -4
- package/src/internal/Response.ts +1 -1
- package/src/internal/Schema.test.ts +2 -0
- package/src/internal/Schema.ts +12 -2
- package/src/internal/Store.test.ts +178 -0
- package/src/internal/Store.ts +104 -18
- package/src/internal/Tidx.test.ts +2 -1
- package/src/internal/Tidx.ts +7 -2
- package/src/internal/Timeout.test.ts +35 -0
- package/src/internal/Timeout.ts +73 -0
- package/src/internal/Timing.ts +16 -0
- package/src/internal/WebhookDestination.ts +3 -0
- package/src/internal/funding/Action.test.ts +41 -1
- package/src/internal/funding/Action.ts +69 -41
- package/src/internal/funding/Catalog.test.ts +34 -0
- package/src/internal/funding/Catalog.ts +28 -11
- package/src/internal/funding/Provider.test.ts +73 -0
- package/src/internal/funding/Provider.ts +82 -28
- package/src/internal/funding/Transfer.ts +133 -110
- package/src/internal/funding/providers/index.test.ts +4 -167
- package/src/internal/funding/providers/relay.test.ts +2 -2
- package/src/internal/funding/providers/stargate.test.ts +163 -0
- package/src/internal/funding/providers/stargate.ts +359 -134
- package/src/internal/index.test.ts +1 -0
- package/src/internal/index.ts +1 -0
|
@@ -1,59 +1,56 @@
|
|
|
1
|
-
import { Address } from 'ox'
|
|
1
|
+
import { AbiFunction, Address, Hex, RpcTransport } from 'ox'
|
|
2
|
+
import { createClient, custom, fallback, publicActions } from 'viem'
|
|
2
3
|
import * as z from 'zod/mini'
|
|
3
4
|
|
|
5
|
+
import * as Action from '../Action.js'
|
|
6
|
+
import type * as Catalog from '../Catalog.js'
|
|
4
7
|
import * as FundingProvider from '../Provider.js'
|
|
5
8
|
|
|
6
|
-
const
|
|
9
|
+
const approve = AbiFunction.from('function approve(address spender, uint256 amount)')
|
|
7
10
|
const defaultFetch: FundingProvider.Fetch = (input, init) => globalThis.fetch(input, init)
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
estimated: z.nullable(DecimalString),
|
|
23
|
-
}),
|
|
24
|
-
),
|
|
25
|
-
expiresAt: z.optional(z.iso.datetime()),
|
|
26
|
-
id: z.string().check(z.minLength(1)),
|
|
27
|
-
routeSteps: z
|
|
28
|
-
.array(
|
|
29
|
-
z.object({
|
|
30
|
-
srcChainKey: z.string(),
|
|
31
|
-
type: z.string(),
|
|
32
|
-
}),
|
|
33
|
-
)
|
|
34
|
-
.check(z.minLength(1)),
|
|
35
|
-
srcAmount: IntegerString,
|
|
36
|
-
})
|
|
11
|
+
const destinationChainId = 'eip155:4217'
|
|
12
|
+
const destinationEid = 30_410
|
|
13
|
+
const destinationToken = '0x20C000000000000000000000b9537d11c60E8b50'
|
|
14
|
+
const quoteOft = AbiFunction.from(
|
|
15
|
+
'function quoteOFT((uint32 dstEid, bytes32 to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd) sendParam) view returns ((uint256 minAmountLD, uint256 maxAmountLD) limit, (int256 feeAmountLD, string description)[] oftFeeDetails, (uint256 amountSentLD, uint256 amountReceivedLD) receipt)',
|
|
16
|
+
)
|
|
17
|
+
const quoteSend = AbiFunction.from(
|
|
18
|
+
'function quoteSend((uint32 dstEid, bytes32 to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd) sendParam, bool payInLzToken) view returns ((uint256 nativeFee, uint256 lzTokenFee) fee)',
|
|
19
|
+
)
|
|
20
|
+
const sendToken = AbiFunction.from(
|
|
21
|
+
'function sendToken((uint32 dstEid, bytes32 to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd) sendParam, (uint256 nativeFee, uint256 lzTokenFee) fee, address refundAddress) payable returns ((bytes32 guid, uint64 nonce, (uint256 nativeFee, uint256 lzTokenFee) fee) msgReceipt, (uint256 amountSentLD, uint256 amountReceivedLD) oftReceipt, (uint72 ticketId, bytes passengerBytes) ticket)',
|
|
22
|
+
)
|
|
23
|
+
const quoteTtlMs = 60_000
|
|
24
|
+
const zeroAddress = '0x0000000000000000000000000000000000000000'
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
const configuration = z
|
|
27
|
+
.strictObject({
|
|
28
|
+
poolAddress: z
|
|
29
|
+
.string()
|
|
30
|
+
.check(
|
|
31
|
+
z.regex(/^0x[0-9a-fA-F]{40}$/),
|
|
32
|
+
z.describe('Stargate pool contract on the source chain.'),
|
|
33
|
+
),
|
|
41
34
|
})
|
|
35
|
+
.check(z.describe('Stargate configuration for one funding route.'))
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
})
|
|
37
|
+
type Deployment = {
|
|
38
|
+
pool: Address.Address
|
|
39
|
+
sourceToken: Address.Address
|
|
47
40
|
}
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
type SendParam = {
|
|
43
|
+
amountLD: bigint
|
|
44
|
+
composeMsg: Hex.Hex
|
|
45
|
+
dstEid: number
|
|
46
|
+
extraOptions: Hex.Hex
|
|
47
|
+
minAmountLD: bigint
|
|
48
|
+
oftCmd: Hex.Hex
|
|
49
|
+
to: Hex.Hex
|
|
50
|
+
}
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
/** Creates a direct Stargate V2 OFT funding provider. */
|
|
53
|
+
export function stargate(options: stargate.Options = {}) {
|
|
57
54
|
const fetch = options.fetch ?? defaultFetch
|
|
58
55
|
const now = options.now ?? (() => new Date())
|
|
59
56
|
|
|
@@ -61,124 +58,352 @@ export function stargate(options: stargate.Options) {
|
|
|
61
58
|
id: 'stargate',
|
|
62
59
|
name: 'Stargate',
|
|
63
60
|
async getQuote({ candidate, route }, signal) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
options: { amountType: 'EXACT_SRC_AMOUNT' },
|
|
71
|
-
srcChainKey: route.source.chain.slug,
|
|
72
|
-
srcTokenAddress: candidate.sourceToken.address,
|
|
73
|
-
srcWalletAddress: options.userAddress,
|
|
74
|
-
},
|
|
75
|
-
fetch,
|
|
76
|
-
headers: { 'user-agent': 'tempo-api', 'x-api-key': options.apiKey },
|
|
77
|
-
method: 'POST',
|
|
78
|
-
signal,
|
|
61
|
+
const deployment = resolveDeployment({
|
|
62
|
+
configuration: candidate.configuration,
|
|
63
|
+
destinationChainId: route.destination.chain.id,
|
|
64
|
+
destinationTokenAddress: route.destination.address,
|
|
65
|
+
sourceChainId: route.source.chain.id,
|
|
66
|
+
sourceTokenAddress: route.source.address,
|
|
79
67
|
})
|
|
80
|
-
const parsed = schema.Quotes.safeParse(response)
|
|
81
|
-
if (!parsed.success || parsed.data.error) throw new FundingProvider.ProviderPayloadError()
|
|
82
|
-
|
|
83
68
|
const sampledAt = now()
|
|
84
|
-
|
|
69
|
+
if (!deployment) return unavailable({ message: 'ROUTE_NOT_CONFIGURED', now: sampledAt })
|
|
70
|
+
|
|
71
|
+
const sendParam = createSendParam({
|
|
85
72
|
amount: candidate.sourceAmount.amount,
|
|
86
|
-
|
|
87
|
-
|
|
73
|
+
recipient: zeroAddress,
|
|
74
|
+
})
|
|
75
|
+
const [limit, feeDetails, receipt] = await client({ fetch, route, signal }).readContract({
|
|
76
|
+
abi: [quoteOft],
|
|
77
|
+
address: deployment.pool,
|
|
78
|
+
args: [sendParam],
|
|
79
|
+
functionName: 'quoteOFT',
|
|
88
80
|
})
|
|
89
|
-
if (!
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
message: 'NO_STARGATE_ROUTE',
|
|
93
|
-
now: sampledAt,
|
|
94
|
-
source: 'providerQuote',
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
const estimated = estimatedSeconds(selected.quote.duration?.estimated)
|
|
81
|
+
if (!isExactQuote({ amount: candidate.sourceAmount.amount, feeDetails, limit, receipt }))
|
|
82
|
+
return unavailable({ message: 'NO_EXACT_ROUTE', now: sampledAt })
|
|
83
|
+
|
|
98
84
|
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
quality: {
|
|
103
|
-
...(estimated === undefined ? {} : { estimatedSeconds: estimated }),
|
|
104
|
-
liquiditySource: 'providerQuote',
|
|
105
|
-
sourceDetail: sourceDetails[selected.type],
|
|
106
|
-
tier: 'liquid',
|
|
107
|
-
},
|
|
85
|
+
destinationAmountMin: receipt.amountReceivedLD.toString(),
|
|
86
|
+
destinationAmount: receipt.amountReceivedLD.toString(),
|
|
87
|
+
quality: quality(),
|
|
108
88
|
sampledAt: sampledAt.toISOString(),
|
|
109
89
|
status: 'available',
|
|
110
90
|
}
|
|
111
91
|
},
|
|
92
|
+
async prepareTransfer({ candidate, method, mode, recipient, sender }, signal) {
|
|
93
|
+
if (
|
|
94
|
+
method !== 'transaction' ||
|
|
95
|
+
mode !== 'exactSource' ||
|
|
96
|
+
!Address.validate(recipient, { strict: false }) ||
|
|
97
|
+
!Address.validate(sender, { strict: false })
|
|
98
|
+
)
|
|
99
|
+
throw new FundingProvider.ProviderConfigurationError()
|
|
100
|
+
|
|
101
|
+
const deployment = resolveDeployment({
|
|
102
|
+
configuration: candidate.configuration,
|
|
103
|
+
destinationChainId: candidate.destinationChain.id,
|
|
104
|
+
destinationTokenAddress: candidate.destinationToken.address,
|
|
105
|
+
sourceChainId: candidate.sourceChain.id,
|
|
106
|
+
sourceTokenAddress: candidate.sourceToken.address,
|
|
107
|
+
})
|
|
108
|
+
if (!deployment) throw new FundingProvider.ProviderUnavailableError()
|
|
109
|
+
const sendParam = createSendParam({ amount: candidate.sourceAmount.amount, recipient })
|
|
110
|
+
const rpc = client({ fetch, route: candidate.route, signal })
|
|
111
|
+
const [[limit, feeDetails, receipt], messagingFee] = await Promise.all([
|
|
112
|
+
rpc.readContract({
|
|
113
|
+
abi: [quoteOft],
|
|
114
|
+
address: deployment.pool,
|
|
115
|
+
args: [sendParam],
|
|
116
|
+
functionName: 'quoteOFT',
|
|
117
|
+
}),
|
|
118
|
+
rpc.readContract({
|
|
119
|
+
abi: [quoteSend],
|
|
120
|
+
account: sender as Address.Address,
|
|
121
|
+
address: deployment.pool,
|
|
122
|
+
args: [sendParam, false],
|
|
123
|
+
functionName: 'quoteSend',
|
|
124
|
+
}),
|
|
125
|
+
])
|
|
126
|
+
if (!isExactQuote({ amount: candidate.sourceAmount.amount, feeDetails, limit, receipt }))
|
|
127
|
+
throw new FundingProvider.ProviderUnavailableError()
|
|
128
|
+
if (messagingFee.lzTokenFee !== 0n) throw new FundingProvider.ProviderPayloadError()
|
|
129
|
+
|
|
130
|
+
const action = {
|
|
131
|
+
calls: [
|
|
132
|
+
{
|
|
133
|
+
data: AbiFunction.encodeData(approve, [
|
|
134
|
+
deployment.pool,
|
|
135
|
+
BigInt(candidate.sourceAmount.amount),
|
|
136
|
+
]),
|
|
137
|
+
to: deployment.sourceToken,
|
|
138
|
+
value: '0x0',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
data: AbiFunction.encodeData(sendToken, [sendParam, messagingFee, sender]),
|
|
142
|
+
to: deployment.pool,
|
|
143
|
+
value: Hex.fromNumber(messagingFee.nativeFee),
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
type: 'evm:calls' as const,
|
|
147
|
+
}
|
|
148
|
+
validateAction({
|
|
149
|
+
action,
|
|
150
|
+
configuration: candidate.configuration,
|
|
151
|
+
destinationTokenAddress: candidate.destinationToken.address,
|
|
152
|
+
recipient,
|
|
153
|
+
sender,
|
|
154
|
+
sourceAmount: candidate.sourceAmount.amount,
|
|
155
|
+
sourceChainId: candidate.sourceChain.id,
|
|
156
|
+
sourceTokenAddress: candidate.sourceToken.address,
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const sampledAt = now()
|
|
160
|
+
return {
|
|
161
|
+
action,
|
|
162
|
+
destinationAmountMin: receipt.amountReceivedLD.toString(),
|
|
163
|
+
destinationAmount: receipt.amountReceivedLD.toString(),
|
|
164
|
+
expiresAt: new Date(sampledAt.getTime() + quoteTtlMs).toISOString(),
|
|
165
|
+
fees:
|
|
166
|
+
messagingFee.nativeFee === 0n
|
|
167
|
+
? []
|
|
168
|
+
: [
|
|
169
|
+
{
|
|
170
|
+
amount: messagingFee.nativeFee.toString(),
|
|
171
|
+
side: 'source' as const,
|
|
172
|
+
token: nativeToken(candidate.sourceChain.id),
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
quality: quality(),
|
|
176
|
+
sampledAt: sampledAt.toISOString(),
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
validateTransferAction({ action, candidate, recipient, sender }) {
|
|
180
|
+
return {
|
|
181
|
+
nativeValues: validateAction({
|
|
182
|
+
action,
|
|
183
|
+
configuration: candidate.configuration,
|
|
184
|
+
destinationTokenAddress: candidate.destinationToken.address,
|
|
185
|
+
recipient,
|
|
186
|
+
sender,
|
|
187
|
+
sourceAmount: candidate.sourceAmount.amount,
|
|
188
|
+
sourceChainId: candidate.sourceChain.id,
|
|
189
|
+
sourceTokenAddress: candidate.sourceToken.address,
|
|
190
|
+
}),
|
|
191
|
+
}
|
|
192
|
+
},
|
|
112
193
|
})
|
|
113
194
|
}
|
|
114
195
|
|
|
115
196
|
export declare namespace stargate {
|
|
116
197
|
/** Stargate provider options. */
|
|
117
198
|
type Options = {
|
|
118
|
-
/**
|
|
119
|
-
apiKey: string
|
|
120
|
-
/** Override for tests or LayerZero test environments. */
|
|
121
|
-
baseUrl?: string | undefined
|
|
122
|
-
/** Fetch implementation override for tests. */
|
|
199
|
+
/** Fetch implementation override for chain RPC requests. */
|
|
123
200
|
fetch?: FundingProvider.Fetch | undefined
|
|
124
201
|
/** Clock override for deterministic tests. */
|
|
125
202
|
now?: (() => Date) | undefined
|
|
126
|
-
/** Quote wallet address used as the LayerZero sender and recipient. */
|
|
127
|
-
userAddress: string
|
|
128
203
|
}
|
|
129
204
|
}
|
|
130
205
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (!type) return []
|
|
142
|
-
if (
|
|
143
|
-
quote.expiresAt !== undefined &&
|
|
144
|
-
new Date(quote.expiresAt).getTime() <= options.now.getTime()
|
|
145
|
-
)
|
|
146
|
-
return []
|
|
147
|
-
if (
|
|
148
|
-
quote.srcAmount !== options.amount ||
|
|
149
|
-
BigInt(quote.dstAmount) <= 0n ||
|
|
150
|
-
BigInt(quote.dstAmountMin) <= 0n ||
|
|
151
|
-
BigInt(quote.dstAmountMin) > BigInt(quote.dstAmount)
|
|
152
|
-
)
|
|
153
|
-
throw new FundingProvider.ProviderPayloadError()
|
|
154
|
-
return [{ quote, type }]
|
|
206
|
+
/** Validates one direct Stargate action and returns its exact native-value allowance. */
|
|
207
|
+
export function validateAction(options: validateAction.Options): readonly Action.NativeValue[] {
|
|
208
|
+
try {
|
|
209
|
+
const action = Action.schema.EvmCalls.parse(options.action)
|
|
210
|
+
const deployment = resolveDeployment({
|
|
211
|
+
configuration: options.configuration,
|
|
212
|
+
destinationChainId,
|
|
213
|
+
destinationTokenAddress: options.destinationTokenAddress,
|
|
214
|
+
sourceChainId: options.sourceChainId,
|
|
215
|
+
sourceTokenAddress: options.sourceTokenAddress,
|
|
155
216
|
})
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
217
|
+
if (!deployment || action.calls.length !== 2) throw new FundingProvider.ProviderPayloadError()
|
|
218
|
+
const [approval, execution] = action.calls
|
|
219
|
+
if (
|
|
220
|
+
!Address.isEqual(approval!.to as Address.Address, deployment.sourceToken) ||
|
|
221
|
+
BigInt(approval!.value) !== 0n ||
|
|
222
|
+
!Address.isEqual(execution!.to as Address.Address, deployment.pool)
|
|
223
|
+
)
|
|
224
|
+
throw new FundingProvider.ProviderPayloadError()
|
|
225
|
+
|
|
226
|
+
const [spender, approvalAmount] = AbiFunction.decodeData(approve, approval!.data as Hex.Hex)
|
|
227
|
+
const [sendParam, messagingFee, refundAddress] = AbiFunction.decodeData(
|
|
228
|
+
sendToken,
|
|
229
|
+
execution!.data as Hex.Hex,
|
|
230
|
+
)
|
|
231
|
+
const nativeValue = BigInt(execution!.value)
|
|
232
|
+
if (
|
|
233
|
+
!Address.isEqual(spender, deployment.pool) ||
|
|
234
|
+
approvalAmount !== BigInt(options.sourceAmount) ||
|
|
235
|
+
sendParam.amountLD !== BigInt(options.sourceAmount) ||
|
|
236
|
+
sendParam.composeMsg !== '0x' ||
|
|
237
|
+
sendParam.dstEid !== destinationEid ||
|
|
238
|
+
sendParam.extraOptions !== '0x' ||
|
|
239
|
+
sendParam.minAmountLD !== BigInt(options.sourceAmount) ||
|
|
240
|
+
sendParam.oftCmd !== '0x' ||
|
|
241
|
+
!Hex.isEqual(sendParam.to, recipientBytes32(options.recipient)) ||
|
|
242
|
+
messagingFee.lzTokenFee !== 0n ||
|
|
243
|
+
messagingFee.nativeFee !== nativeValue ||
|
|
244
|
+
!Address.isEqual(refundAddress, options.sender as Address.Address)
|
|
245
|
+
)
|
|
246
|
+
throw new FundingProvider.ProviderPayloadError()
|
|
247
|
+
return [{ to: execution!.to, value: execution!.value }]
|
|
248
|
+
} catch (cause) {
|
|
249
|
+
if (cause instanceof FundingProvider.ProviderPayloadError) throw cause
|
|
250
|
+
throw new FundingProvider.ProviderPayloadError()
|
|
251
|
+
}
|
|
162
252
|
}
|
|
163
253
|
|
|
164
|
-
declare namespace
|
|
254
|
+
export declare namespace validateAction {
|
|
255
|
+
/** Expected route terms for one Stargate action. */
|
|
256
|
+
type Options = {
|
|
257
|
+
/** Prepared Stargate action. */
|
|
258
|
+
action: Action.EvmCalls
|
|
259
|
+
/** Stargate configuration for the selected route. */
|
|
260
|
+
configuration?: Catalog.Configuration | undefined
|
|
261
|
+
/** Curated Tempo destination token. */
|
|
262
|
+
destinationTokenAddress: string
|
|
263
|
+
/** Tempo beneficiary. */
|
|
264
|
+
recipient: string
|
|
265
|
+
/** Source account and LayerZero refund recipient. */
|
|
266
|
+
sender: string
|
|
267
|
+
/** Exact source amount in base units. */
|
|
268
|
+
sourceAmount: string
|
|
269
|
+
/** Source chain CAIP-2 id. */
|
|
270
|
+
sourceChainId: string
|
|
271
|
+
/** Curated source token. */
|
|
272
|
+
sourceTokenAddress: string
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function client(options: client.Options) {
|
|
277
|
+
if (options.route.source.chain.rpcUrls.length === 0)
|
|
278
|
+
throw new FundingProvider.ProviderConfigurationError()
|
|
279
|
+
return createClient({
|
|
280
|
+
transport: fallback(
|
|
281
|
+
options.route.source.chain.rpcUrls.map((url) =>
|
|
282
|
+
custom(
|
|
283
|
+
RpcTransport.fromHttp(url, {
|
|
284
|
+
fetchFn: (input, init) => options.fetch(input, { ...init, signal: options.signal }),
|
|
285
|
+
}),
|
|
286
|
+
{ retryCount: 0 },
|
|
287
|
+
),
|
|
288
|
+
),
|
|
289
|
+
),
|
|
290
|
+
}).extend(publicActions)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
declare namespace client {
|
|
294
|
+
type Options = {
|
|
295
|
+
fetch: FundingProvider.Fetch
|
|
296
|
+
route: FundingProvider.QuoteCandidate['route']
|
|
297
|
+
signal: AbortSignal
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function createSendParam(options: createSendParam.Options): SendParam {
|
|
302
|
+
const amount = BigInt(options.amount)
|
|
303
|
+
return {
|
|
304
|
+
amountLD: amount,
|
|
305
|
+
composeMsg: '0x',
|
|
306
|
+
dstEid: destinationEid,
|
|
307
|
+
extraOptions: '0x',
|
|
308
|
+
minAmountLD: amount,
|
|
309
|
+
oftCmd: '0x',
|
|
310
|
+
to: recipientBytes32(options.recipient),
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
declare namespace createSendParam {
|
|
165
315
|
type Options = {
|
|
166
316
|
amount: string
|
|
167
|
-
|
|
168
|
-
|
|
317
|
+
recipient: string
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function isExactQuote(options: isExactQuote.Options) {
|
|
322
|
+
const amount = BigInt(options.amount)
|
|
323
|
+
return (
|
|
324
|
+
amount >= options.limit.minAmountLD &&
|
|
325
|
+
amount <= options.limit.maxAmountLD &&
|
|
326
|
+
options.feeDetails.every((fee) => fee.feeAmountLD >= 0n) &&
|
|
327
|
+
options.receipt.amountSentLD === amount &&
|
|
328
|
+
options.receipt.amountReceivedLD === amount
|
|
329
|
+
)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
declare namespace isExactQuote {
|
|
333
|
+
type Options = {
|
|
334
|
+
amount: string
|
|
335
|
+
feeDetails: readonly { feeAmountLD: bigint }[]
|
|
336
|
+
limit: { maxAmountLD: bigint; minAmountLD: bigint }
|
|
337
|
+
receipt: { amountReceivedLD: bigint; amountSentLD: bigint }
|
|
169
338
|
}
|
|
170
339
|
}
|
|
171
340
|
|
|
172
|
-
function
|
|
173
|
-
return
|
|
341
|
+
function nativeToken(sourceChainId: string) {
|
|
342
|
+
return {
|
|
343
|
+
address: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
|
344
|
+
currency: 'ETH',
|
|
345
|
+
decimals: 18,
|
|
346
|
+
name: 'Ether',
|
|
347
|
+
standard: 'native',
|
|
348
|
+
symbol: 'ETH',
|
|
349
|
+
tokenKey: `${sourceChainId}/slip44:60`,
|
|
350
|
+
verified: true,
|
|
351
|
+
}
|
|
174
352
|
}
|
|
175
353
|
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
354
|
+
function quality() {
|
|
355
|
+
return {
|
|
356
|
+
liquiditySource: 'onchain',
|
|
357
|
+
sourceDetail: 'stargate:oft-v2:taxi',
|
|
358
|
+
tier: 'liquid' as const,
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function recipientBytes32(recipient: string) {
|
|
363
|
+
if (!Address.validate(recipient, { strict: false }))
|
|
364
|
+
throw new FundingProvider.ProviderConfigurationError()
|
|
365
|
+
return Hex.padLeft(recipient as Hex.Hex, 32)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function resolveDeployment(options: resolveDeployment.Options): Deployment | undefined {
|
|
369
|
+
const parsed = configuration.safeParse(options.configuration)
|
|
370
|
+
if (
|
|
371
|
+
!parsed.success ||
|
|
372
|
+
options.destinationChainId !== destinationChainId ||
|
|
373
|
+
!options.sourceChainId.startsWith('eip155:') ||
|
|
374
|
+
!Address.validate(options.destinationTokenAddress, { strict: false }) ||
|
|
375
|
+
!Address.validate(options.sourceTokenAddress, { strict: false }) ||
|
|
376
|
+
!Address.isEqual(options.destinationTokenAddress as Address.Address, destinationToken)
|
|
377
|
+
)
|
|
378
|
+
return undefined
|
|
379
|
+
return {
|
|
380
|
+
pool: Address.checksum(parsed.data.poolAddress),
|
|
381
|
+
sourceToken: Address.checksum(options.sourceTokenAddress),
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
declare namespace resolveDeployment {
|
|
386
|
+
type Options = {
|
|
387
|
+
configuration?: Catalog.Configuration | undefined
|
|
388
|
+
destinationChainId: string
|
|
389
|
+
destinationTokenAddress: string
|
|
390
|
+
sourceChainId: string
|
|
391
|
+
sourceTokenAddress: string
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function unavailable(options: unavailable.Options) {
|
|
396
|
+
return FundingProvider.unavailableResult({
|
|
397
|
+
detail: 'stargate:oft-v2',
|
|
398
|
+
message: options.message,
|
|
399
|
+
now: options.now,
|
|
400
|
+
source: 'onchain',
|
|
401
|
+
})
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
declare namespace unavailable {
|
|
405
|
+
type Options = {
|
|
406
|
+
message: string
|
|
407
|
+
now: Date
|
|
408
|
+
}
|
|
184
409
|
}
|
package/src/internal/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * as EarnVaults from './EarnVaults.js'
|
|
|
7
7
|
export * as Errors from './Errors.js'
|
|
8
8
|
export * as Exchange from './exchange/index.js'
|
|
9
9
|
export * as Fees from './Fees.js'
|
|
10
|
+
export * as Fetch from './Fetch.js'
|
|
10
11
|
export * as Funding from './funding/index.js'
|
|
11
12
|
export * as Id from './Id.js'
|
|
12
13
|
export * as Idempotency from './Idempotency.js'
|