@gibs/bridge-sdk 1.13.0 → 1.17.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 +244 -18
- package/abis/package.json +6 -0
- package/bridge-limits/package.json +6 -0
- package/chain-info/package.json +6 -0
- package/chain-names/package.json +6 -0
- package/chains/package.json +6 -0
- package/claims/package.json +6 -0
- package/config/package.json +6 -0
- package/consolidated-quote/package.json +6 -0
- package/destination-calldata/package.json +6 -0
- package/dist/chain-info.d.ts +1 -1
- package/dist/chain-info.js +11 -12
- package/dist/chains.d.ts +25 -0
- package/dist/chains.js +55 -20
- package/dist/cjs/abis.d.ts +1 -0
- package/dist/cjs/abis.js +19 -0
- package/dist/cjs/bridge-limits.d.ts +103 -0
- package/dist/cjs/bridge-limits.js +89 -0
- package/dist/cjs/chain-info.d.ts +169 -0
- package/dist/cjs/chain-info.js +452 -0
- package/dist/cjs/chain-names.d.ts +160 -0
- package/dist/cjs/chain-names.js +207 -0
- package/dist/cjs/chains.d.ts +90 -0
- package/dist/cjs/chains.js +357 -0
- package/dist/cjs/claims.d.ts +198 -0
- package/dist/cjs/claims.js +182 -0
- package/dist/cjs/config.d.ts +240 -0
- package/dist/cjs/config.js +537 -0
- package/dist/cjs/consolidated-quote.d.ts +648 -0
- package/dist/cjs/consolidated-quote.js +1048 -0
- package/dist/cjs/destination-calldata.d.ts +118 -0
- package/dist/cjs/destination-calldata.js +156 -0
- package/dist/cjs/ecosystems.d.ts +217 -0
- package/dist/cjs/ecosystems.js +298 -0
- package/dist/cjs/execution.d.ts +346 -0
- package/dist/cjs/execution.js +468 -0
- package/dist/cjs/fee-type.d.ts +10 -0
- package/dist/cjs/fee-type.js +10 -0
- package/dist/cjs/hyperliquid-execution.d.ts +152 -0
- package/dist/cjs/hyperliquid-execution.js +175 -0
- package/dist/cjs/image-links.d.ts +117 -0
- package/dist/cjs/image-links.js +153 -0
- package/dist/cjs/index.d.ts +23 -0
- package/dist/cjs/index.js +39 -0
- package/dist/cjs/lifi-execution-guard.d.ts +210 -0
- package/dist/cjs/lifi-execution-guard.js +409 -0
- package/dist/cjs/near-intents-conformance.d.ts +85 -0
- package/dist/cjs/near-intents-conformance.js +337 -0
- package/dist/cjs/near-intents-route.d.ts +47 -0
- package/dist/cjs/near-intents-route.js +303 -0
- package/dist/cjs/near-intents.d.ts +524 -0
- package/dist/cjs/near-intents.js +1071 -0
- package/dist/cjs/origin-deposit.d.ts +326 -0
- package/dist/cjs/origin-deposit.js +82 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/pre-quote.d.ts +198 -0
- package/dist/cjs/pre-quote.js +180 -0
- package/dist/cjs/prices.d.ts +107 -0
- package/dist/cjs/prices.js +172 -0
- package/dist/cjs/providers.d.ts +238 -0
- package/dist/cjs/providers.js +171 -0
- package/dist/cjs/quote-fees.d.ts +102 -0
- package/dist/cjs/quote-fees.js +201 -0
- package/dist/cjs/referral.d.ts +85 -0
- package/dist/cjs/referral.js +85 -0
- package/dist/cjs/relay-currencies.d.ts +47 -0
- package/dist/cjs/relay-currencies.js +95 -0
- package/dist/cjs/relay-depository.d.ts +2 -0
- package/dist/cjs/relay-depository.js +85 -0
- package/dist/cjs/relay-quote.d.ts +301 -0
- package/dist/cjs/relay-quote.js +996 -0
- package/dist/cjs/route-steps.d.ts +138 -0
- package/dist/cjs/route-steps.js +310 -0
- package/dist/cjs/routing/amounts.d.ts +80 -0
- package/dist/cjs/routing/amounts.js +126 -0
- package/dist/cjs/routing/candidate-route.d.ts +43 -0
- package/dist/cjs/routing/candidate-route.js +50 -0
- package/dist/cjs/routing/candidate.d.ts +237 -0
- package/dist/cjs/routing/candidate.js +100 -0
- package/dist/cjs/routing/carriers/ask-answer.d.ts +77 -0
- package/dist/cjs/routing/carriers/ask-answer.js +2 -0
- package/dist/cjs/routing/carriers/omnibridge.d.ts +137 -0
- package/dist/cjs/routing/carriers/omnibridge.js +459 -0
- package/dist/cjs/routing/carriers/pulsex-paths.d.ts +80 -0
- package/dist/cjs/routing/carriers/pulsex-paths.js +97 -0
- package/dist/cjs/routing/carriers/pulsex-split.d.ts +175 -0
- package/dist/cjs/routing/carriers/pulsex-split.js +193 -0
- package/dist/cjs/routing/carriers/pulsex.d.ts +159 -0
- package/dist/cjs/routing/carriers/pulsex.js +565 -0
- package/dist/cjs/routing/carriers/wrap.d.ts +25 -0
- package/dist/cjs/routing/carriers/wrap.js +119 -0
- package/dist/cjs/routing/composed-route-quality.d.ts +125 -0
- package/dist/cjs/routing/composed-route-quality.js +144 -0
- package/dist/cjs/routing/entry-chain-anchor.d.ts +88 -0
- package/dist/cjs/routing/entry-chain-anchor.js +59 -0
- package/dist/cjs/routing/format.d.ts +31 -0
- package/dist/cjs/routing/format.js +64 -0
- package/dist/cjs/routing/index.d.ts +38 -0
- package/dist/cjs/routing/index.js +134 -0
- package/dist/cjs/routing/producers.d.ts +770 -0
- package/dist/cjs/routing/producers.js +1617 -0
- package/dist/cjs/routing/providers.d.ts +31 -0
- package/dist/cjs/routing/providers.js +48 -0
- package/dist/cjs/routing/route-data.d.ts +355 -0
- package/dist/cjs/routing/route-data.js +2 -0
- package/dist/cjs/routing/search/compose.d.ts +168 -0
- package/dist/cjs/routing/search/compose.js +104 -0
- package/dist/cjs/routing/search/graph.d.ts +668 -0
- package/dist/cjs/routing/search/graph.js +461 -0
- package/dist/cjs/routing/search/plan-route-data.d.ts +269 -0
- package/dist/cjs/routing/search/plan-route-data.js +848 -0
- package/dist/cjs/routing/search/score.d.ts +356 -0
- package/dist/cjs/routing/search/score.js +445 -0
- package/dist/cjs/routing/swap-transactions.d.ts +91 -0
- package/dist/cjs/routing/swap-transactions.js +131 -0
- package/dist/cjs/routing/usd-value.d.ts +17 -0
- package/dist/cjs/routing/usd-value.js +29 -0
- package/dist/cjs/settings.d.ts +785 -0
- package/dist/cjs/settings.js +1074 -0
- package/dist/cjs/ton-connect.d.ts +98 -0
- package/dist/cjs/ton-connect.js +206 -0
- package/dist/cjs/ton-execution.d.ts +7 -0
- package/dist/cjs/ton-execution.js +23 -0
- package/dist/cjs/ton.d.ts +37 -0
- package/dist/cjs/ton.js +83 -0
- package/dist/cjs/tron-execution.d.ts +146 -0
- package/dist/cjs/tron-execution.js +248 -0
- package/dist/cjs/types.d.ts +51 -0
- package/dist/cjs/types.js +2 -0
- package/dist/claims.d.ts +198 -0
- package/dist/claims.js +140 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +39 -5
- package/dist/consolidated-quote.d.ts +109 -15
- package/dist/consolidated-quote.js +310 -52
- package/dist/execution.d.ts +346 -0
- package/dist/execution.js +428 -0
- package/dist/hyperliquid-execution.js +2 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/lifi-execution-guard.d.ts +13 -2
- package/dist/lifi-execution-guard.js +4 -0
- package/dist/near-intents.js +2 -3
- package/dist/pre-quote.d.ts +6 -6
- package/dist/pre-quote.js +10 -14
- package/dist/providers.d.ts +17 -0
- package/dist/providers.js +6 -0
- package/dist/referral.d.ts +12 -4
- package/dist/referral.js +12 -4
- package/dist/relay-depository.d.ts +2 -0
- package/dist/relay-depository.js +82 -0
- package/dist/relay-quote.js +2 -3
- package/dist/routing/candidate.d.ts +3 -3
- package/dist/routing/candidate.js +3 -3
- package/dist/routing/carriers/ask-answer.d.ts +19 -0
- package/dist/routing/carriers/omnibridge.js +23 -21
- package/dist/routing/carriers/pulsex-paths.d.ts +80 -0
- package/dist/routing/carriers/pulsex-paths.js +92 -0
- package/dist/routing/carriers/pulsex-split.d.ts +175 -0
- package/dist/routing/carriers/pulsex-split.js +185 -0
- package/dist/routing/carriers/pulsex.d.ts +69 -21
- package/dist/routing/carriers/pulsex.js +184 -65
- package/dist/routing/composed-route-quality.d.ts +28 -6
- package/dist/routing/composed-route-quality.js +36 -5
- package/dist/routing/entry-chain-anchor.d.ts +1 -1
- package/dist/routing/entry-chain-anchor.js +1 -1
- package/dist/routing/index.d.ts +7 -3
- package/dist/routing/index.js +7 -3
- package/dist/routing/producers.js +1 -1
- package/dist/routing/providers.d.ts +5 -0
- package/dist/routing/providers.js +5 -0
- package/dist/routing/search/graph.d.ts +29 -0
- package/dist/routing/search/plan-route-data.d.ts +25 -0
- package/dist/routing/search/plan-route-data.js +43 -7
- package/dist/routing/search/score.d.ts +33 -1
- package/dist/routing/search/score.js +41 -6
- package/dist/routing/swap-transactions.d.ts +91 -0
- package/dist/routing/swap-transactions.js +125 -0
- package/dist/settings.d.ts +94 -1
- package/dist/settings.js +95 -3
- package/dist/ton-connect.d.ts +98 -0
- package/dist/ton-connect.js +200 -0
- package/dist/ton-execution.d.ts +4 -114
- package/dist/ton-execution.js +4 -244
- package/dist/ton.d.ts +37 -0
- package/dist/ton.js +65 -0
- package/docs/examples/example-a-ether-to-pulse.ts +300 -0
- package/docs/examples/example-b-token-pulsechain-to-ethereum.ts +270 -0
- package/docs/examples/shared.ts +261 -0
- package/docs/examples/tsconfig.json +18 -0
- package/docs/integration-guide.md +617 -0
- package/ecosystems/package.json +6 -0
- package/execution/package.json +6 -0
- package/fee-type/package.json +6 -0
- package/hyperliquid-execution/package.json +6 -0
- package/image-links/package.json +6 -0
- package/lifi-execution-guard/package.json +6 -0
- package/llms.txt +234 -0
- package/near-intents/package.json +6 -0
- package/near-intents-route/package.json +6 -0
- package/origin-deposit/package.json +6 -0
- package/package.json +818 -10
- package/pre-quote/package.json +6 -0
- package/prices/package.json +6 -0
- package/providers/package.json +6 -0
- package/quote-fees/package.json +6 -0
- package/referral/package.json +6 -0
- package/relay-currencies/package.json +6 -0
- package/relay-quote/package.json +6 -0
- package/route-steps/package.json +6 -0
- package/routing/package.json +6 -0
- package/settings/package.json +6 -0
- package/ton/package.json +6 -0
- package/ton-connect/package.json +6 -0
- package/ton-execution/package.json +6 -0
- package/tron-execution/package.json +6 -0
- package/types/package.json +6 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readBroadcastResponse = exports.readTriggerSmartContractResponse = exports.tronErrorMessage = exports.buildTriggerSmartContractRequest = exports.isSameTronAccount = exports.normalizeTronHexAddress = exports.maximumTronFeeLimitSun = exports.defaultTronFeeLimitSun = exports.tronTriggerSmartContractPath = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Executing a deposit on Tron, as pure data.
|
|
6
|
+
*
|
|
7
|
+
* Relay does not return a broadcastable Tron transaction. It returns the
|
|
8
|
+
* *parameters* of a `TriggerSmartContract` call — owner, contract, call value
|
|
9
|
+
* and calldata — and nothing else. A Tron transaction additionally needs a
|
|
10
|
+
* reference block, an expiration and a fee limit, none of which Relay supplies.
|
|
11
|
+
* Those are produced by asking a full node to build the transaction, which is
|
|
12
|
+
* what {@link buildTriggerSmartContractRequest} constructs the body for. The
|
|
13
|
+
* node answers with an UNSIGNED transaction; the wallet signs it and a second
|
|
14
|
+
* call broadcasts it.
|
|
15
|
+
*
|
|
16
|
+
* Three details of that exchange lose money or mislead if handled naively:
|
|
17
|
+
*
|
|
18
|
+
* **The `visible` flag defaults to true.** A node reads addresses as base58
|
|
19
|
+
* unless told otherwise, but Relay returns them as hex with Tron's `41` prefix.
|
|
20
|
+
* Omitting the flag therefore hands base58-parsing a hex string. The request
|
|
21
|
+
* built here always states `visible: false` rather than relying on a default
|
|
22
|
+
* that is the opposite of what the payload contains.
|
|
23
|
+
*
|
|
24
|
+
* **`fee_limit` is required and Relay omits it.** It caps the energy the caller
|
|
25
|
+
* will pay for. Set too low, the call runs out of energy, reverts, and the
|
|
26
|
+
* energy already burned is NOT refunded — the deposit fails and costs the user
|
|
27
|
+
* anyway.
|
|
28
|
+
*
|
|
29
|
+
* **A rejected call still answers HTTP 200**, with the reason hex-encoded in
|
|
30
|
+
* `result.message`. Reading the status code alone reports a failed deposit as a
|
|
31
|
+
* success, and printing the message unmodified shows the user a wall of hex.
|
|
32
|
+
* {@link tronErrorMessage} decodes it.
|
|
33
|
+
*
|
|
34
|
+
* Kept free of transport and of clock reads so it is fully testable: nothing
|
|
35
|
+
* here signs, fetches, or calls `Date.now`. The caller performs the requests.
|
|
36
|
+
*/
|
|
37
|
+
/** Path of the full-node endpoint that builds an unsigned contract call. */
|
|
38
|
+
exports.tronTriggerSmartContractPath = '/wallet/triggersmartcontract';
|
|
39
|
+
/**
|
|
40
|
+
* The fee limit used when a caller states none, in sun (1 TRX = 1,000,000 sun).
|
|
41
|
+
*
|
|
42
|
+
* Thirty TRX, matching Relay's own wallet adapter, which is the only reference
|
|
43
|
+
* implementation of this deposit path. It is an upper bound rather than a
|
|
44
|
+
* charge: unused energy is not taken, so the cost of setting it generously is
|
|
45
|
+
* only that the wallet shows a larger worst case.
|
|
46
|
+
*/
|
|
47
|
+
exports.defaultTronFeeLimitSun = 30_000_000;
|
|
48
|
+
/**
|
|
49
|
+
* The largest fee limit a node accepts, in sun — 15,000 TRX. Documented as a
|
|
50
|
+
* hard protocol cap, so a request above it is rejected outright rather than
|
|
51
|
+
* clamped.
|
|
52
|
+
*/
|
|
53
|
+
exports.maximumTronFeeLimitSun = 15_000_000_000;
|
|
54
|
+
/**
|
|
55
|
+
* Tron's `41` address prefix, the hex form's equivalent of the base58 `T`.
|
|
56
|
+
*/
|
|
57
|
+
const tronHexAddressPrefix = '41';
|
|
58
|
+
/** A hex address is the prefix byte plus a twenty-byte account identifier. */
|
|
59
|
+
const tronHexAddressLength = 42;
|
|
60
|
+
/**
|
|
61
|
+
* Normalizes a Tron hex address for comparison.
|
|
62
|
+
*
|
|
63
|
+
* Wallets and quotes disagree on casing, and Relay's payload is not guaranteed
|
|
64
|
+
* to match what a wallet reports even when both name the same account.
|
|
65
|
+
*
|
|
66
|
+
* @param value - an address in Tron's `41`-prefixed hex form, in any casing,
|
|
67
|
+
* optionally written with a `0x` prefix
|
|
68
|
+
* @returns the lowercase `41` form, or null when the value is not that form
|
|
69
|
+
*/
|
|
70
|
+
const normalizeTronHexAddress = (value) => {
|
|
71
|
+
const withoutPrefix = value.trim().replace(/^0x/i, '').toLowerCase();
|
|
72
|
+
if (withoutPrefix.length !== tronHexAddressLength) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!withoutPrefix.startsWith(tronHexAddressPrefix)) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return /^[0-9a-f]+$/.test(withoutPrefix) ? withoutPrefix : null;
|
|
79
|
+
};
|
|
80
|
+
exports.normalizeTronHexAddress = normalizeTronHexAddress;
|
|
81
|
+
/**
|
|
82
|
+
* Whether two Tron hex addresses name the same account.
|
|
83
|
+
*
|
|
84
|
+
* Used to check a deposit's owner against the connected wallet before signing.
|
|
85
|
+
* A mismatch means the quote was built for a different account, and signing it
|
|
86
|
+
* would spend from an account the user did not choose — or simply fail after
|
|
87
|
+
* the user has already approved.
|
|
88
|
+
*
|
|
89
|
+
* @param left - an address in Tron's `41`-prefixed hex form
|
|
90
|
+
* @param right - an address in the same form
|
|
91
|
+
* @returns true only when both parse and name the same account
|
|
92
|
+
*/
|
|
93
|
+
const isSameTronAccount = (left, right) => {
|
|
94
|
+
const normalizedLeft = (0, exports.normalizeTronHexAddress)(left);
|
|
95
|
+
const normalizedRight = (0, exports.normalizeTronHexAddress)(right);
|
|
96
|
+
return normalizedLeft !== null && normalizedLeft === normalizedRight;
|
|
97
|
+
};
|
|
98
|
+
exports.isSameTronAccount = isSameTronAccount;
|
|
99
|
+
/**
|
|
100
|
+
* Strips the `0x` prefix Tron calldata never carries.
|
|
101
|
+
*
|
|
102
|
+
* Relay documents this field as bare hex, but its own adapter strips the prefix
|
|
103
|
+
* defensively, and a prefixed value is parsed by a node as calldata beginning
|
|
104
|
+
* with the bytes `0x` rather than being rejected — a silently wrong call.
|
|
105
|
+
*/
|
|
106
|
+
const bareHex = (value) => value.replace(/^0x/i, '').toLowerCase();
|
|
107
|
+
/**
|
|
108
|
+
* Whether a numeric amount survives the trip through JSON as an exact integer.
|
|
109
|
+
*
|
|
110
|
+
* Sun amounts are 64-bit on the wire but JSON carries them as doubles, so a
|
|
111
|
+
* large enough value would be silently rounded — into a different amount of
|
|
112
|
+
* money than the one that was quoted.
|
|
113
|
+
*/
|
|
114
|
+
const isExactInteger = (value) => value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER);
|
|
115
|
+
/**
|
|
116
|
+
* Builds the body that asks a full node to construct the unsigned deposit.
|
|
117
|
+
*
|
|
118
|
+
* @param deposit - the parsed origin deposit
|
|
119
|
+
* @param options.feeLimitSun - the energy spending cap in sun; defaults to
|
|
120
|
+
* {@link defaultTronFeeLimitSun}
|
|
121
|
+
* @returns the request body, or null when the deposit names an address that is
|
|
122
|
+
* not Tron hex, carries a call value that cannot be represented exactly, or
|
|
123
|
+
* the fee limit is outside what a node accepts — never a body that would be
|
|
124
|
+
* built against a default `visible` the payload contradicts
|
|
125
|
+
*/
|
|
126
|
+
const buildTriggerSmartContractRequest = (deposit, { feeLimitSun = exports.defaultTronFeeLimitSun } = {}) => {
|
|
127
|
+
const ownerAddress = (0, exports.normalizeTronHexAddress)(deposit.ownerAddress);
|
|
128
|
+
const contractAddress = (0, exports.normalizeTronHexAddress)(deposit.contractAddress);
|
|
129
|
+
if (ownerAddress === null || contractAddress === null) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
if (!isExactInteger(deposit.callValue)) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
if (!Number.isInteger(feeLimitSun) || feeLimitSun <= 0 || feeLimitSun > exports.maximumTronFeeLimitSun) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
owner_address: ownerAddress,
|
|
140
|
+
contract_address: contractAddress,
|
|
141
|
+
data: bareHex(deposit.data),
|
|
142
|
+
call_value: Number(deposit.callValue),
|
|
143
|
+
fee_limit: feeLimitSun,
|
|
144
|
+
visible: false,
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
exports.buildTriggerSmartContractRequest = buildTriggerSmartContractRequest;
|
|
148
|
+
/**
|
|
149
|
+
* Decodes a node's hex-encoded failure message.
|
|
150
|
+
*
|
|
151
|
+
* A node reports why it refused a call in `result.message`, hex-encoded — the
|
|
152
|
+
* bytes `4e6f20636f6e7472616374…` rather than "No contract or not a valid smart
|
|
153
|
+
* contract". Broadcast failures report plain text in the same field, so both
|
|
154
|
+
* are handled and a value that is not hex is passed through unchanged.
|
|
155
|
+
*/
|
|
156
|
+
const decodeTronMessage = (value) => {
|
|
157
|
+
const trimmed = value.trim();
|
|
158
|
+
if (trimmed.length === 0 || trimmed.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(trimmed)) {
|
|
159
|
+
return trimmed;
|
|
160
|
+
}
|
|
161
|
+
let decoded = '';
|
|
162
|
+
for (let index = 0; index < trimmed.length; index += 2) {
|
|
163
|
+
decoded += String.fromCharCode(Number.parseInt(trimmed.slice(index, index + 2), 16));
|
|
164
|
+
}
|
|
165
|
+
// A hex string that decodes to control characters was a number, not a
|
|
166
|
+
// message — return the original rather than a string of unprintable bytes.
|
|
167
|
+
return /^[\x20-\x7e]*$/.test(decoded) ? decoded : trimmed;
|
|
168
|
+
};
|
|
169
|
+
const asRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
170
|
+
? value
|
|
171
|
+
: null;
|
|
172
|
+
/**
|
|
173
|
+
* Extracts a node's failure reason from either endpoint's response.
|
|
174
|
+
*
|
|
175
|
+
* @param payload - the parsed response body
|
|
176
|
+
* @returns the decoded message, or null when the response reports no failure
|
|
177
|
+
*/
|
|
178
|
+
const tronErrorMessage = (payload) => {
|
|
179
|
+
const body = asRecord(payload);
|
|
180
|
+
if (body === null) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
// The build endpoint nests its outcome under `result`; the broadcast endpoint
|
|
184
|
+
// reports at the top level.
|
|
185
|
+
const nested = asRecord(body.result);
|
|
186
|
+
const message = nested?.message ?? body.message;
|
|
187
|
+
if (typeof message !== 'string') {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const decoded = decodeTronMessage(message);
|
|
191
|
+
return decoded.length === 0 ? null : decoded;
|
|
192
|
+
};
|
|
193
|
+
exports.tronErrorMessage = tronErrorMessage;
|
|
194
|
+
/**
|
|
195
|
+
* Reads the unsigned transaction out of a build response.
|
|
196
|
+
*
|
|
197
|
+
* The response carries the transaction at the top level alongside a `result`
|
|
198
|
+
* object stating whether the build succeeded, so the presence of a `txID` is
|
|
199
|
+
* not on its own evidence of success.
|
|
200
|
+
*
|
|
201
|
+
* @param payload - the parsed `/wallet/triggersmartcontract` response
|
|
202
|
+
* @returns the unsigned transaction to hand a wallet, or null when the node
|
|
203
|
+
* refused the call
|
|
204
|
+
*/
|
|
205
|
+
const readTriggerSmartContractResponse = (payload) => {
|
|
206
|
+
const body = asRecord(payload);
|
|
207
|
+
if (body === null) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const outcome = asRecord(body.result);
|
|
211
|
+
if (outcome === null || outcome.result !== true) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const transaction = asRecord(body.transaction);
|
|
215
|
+
if (transaction === null || typeof transaction.txID !== 'string') {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
return transaction;
|
|
219
|
+
};
|
|
220
|
+
exports.readTriggerSmartContractResponse = readTriggerSmartContractResponse;
|
|
221
|
+
/**
|
|
222
|
+
* Reads the transaction identifier out of a broadcast response.
|
|
223
|
+
*
|
|
224
|
+
* GOTCHA: a rejected broadcast answers HTTP 200, and `result` is OMITTED rather
|
|
225
|
+
* than set to false. Testing `result === false` therefore never fires, and
|
|
226
|
+
* trusting the status code records a deposit that never entered a block. Only
|
|
227
|
+
* an explicit `result: true` is accepted here.
|
|
228
|
+
*
|
|
229
|
+
* The identifier is read from `txid` where a node reports it, falling back to
|
|
230
|
+
* the echoed transaction's `txID`. The two spellings differ by casing and by
|
|
231
|
+
* position: a node answers `txid`, while a wallet library that echoes the
|
|
232
|
+
* transaction it broadcast carries `txID` inside it. Accepting only the first
|
|
233
|
+
* would report an accepted broadcast as a failure whenever the caller is one of
|
|
234
|
+
* those libraries.
|
|
235
|
+
*
|
|
236
|
+
* @param payload - the parsed `/wallet/broadcasttransaction` response
|
|
237
|
+
* @returns the transaction identifier, or null when the broadcast was refused
|
|
238
|
+
*/
|
|
239
|
+
const readBroadcastResponse = (payload) => {
|
|
240
|
+
const body = asRecord(payload);
|
|
241
|
+
if (body === null || body.result !== true) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const echoed = asRecord(body.transaction);
|
|
245
|
+
const identifier = body.txid ?? echoed?.txID;
|
|
246
|
+
return typeof identifier === 'string' && identifier.length > 0 ? identifier : null;
|
|
247
|
+
};
|
|
248
|
+
exports.readBroadcastResponse = readBroadcastResponse;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Chain, Hex } from 'viem';
|
|
2
|
+
import type { Chains, Provider } from './config.js';
|
|
3
|
+
export type { RouteStep, RouteStepKind } from './route-steps.js';
|
|
4
|
+
/** The per network bridge link */
|
|
5
|
+
export type PerNetworkBridgeLink = {
|
|
6
|
+
tokenAddress: Hex;
|
|
7
|
+
};
|
|
8
|
+
/** The extensions for a token */
|
|
9
|
+
export type Extensions = {
|
|
10
|
+
wrapped?: {
|
|
11
|
+
address: Hex;
|
|
12
|
+
};
|
|
13
|
+
bridgeInfo?: Record<number, PerNetworkBridgeLink>;
|
|
14
|
+
};
|
|
15
|
+
/** The metadata for a token */
|
|
16
|
+
export type TokenMetadata = {
|
|
17
|
+
name: string;
|
|
18
|
+
symbol: string;
|
|
19
|
+
decimals: number;
|
|
20
|
+
};
|
|
21
|
+
/** The token for a given asset */
|
|
22
|
+
export type Token = TokenMetadata & {
|
|
23
|
+
address: string;
|
|
24
|
+
chainId: number;
|
|
25
|
+
logoURI: string | null;
|
|
26
|
+
extensions?: Extensions;
|
|
27
|
+
/**
|
|
28
|
+
* Spot USD price as a decimal string, when a price source provides one inline
|
|
29
|
+
* (e.g. the LI.FI `/tokens` response). Absent/null for tokens from sources
|
|
30
|
+
* that carry no price (e.g. the dapp image lists).
|
|
31
|
+
*/
|
|
32
|
+
priceUSD?: string | null;
|
|
33
|
+
};
|
|
34
|
+
/** The token out for a given asset */
|
|
35
|
+
export type TokenOut = Omit<Token, 'address'> & {
|
|
36
|
+
address: string | null;
|
|
37
|
+
};
|
|
38
|
+
/** The token list for a given asset */
|
|
39
|
+
export type TokenList = {
|
|
40
|
+
tokens: Token[];
|
|
41
|
+
};
|
|
42
|
+
/** The bridge key for a given provider, from chain, and to chain */
|
|
43
|
+
export type BridgeKey = [Provider, Chains, Chains];
|
|
44
|
+
/** The visual chain for a given chain */
|
|
45
|
+
export type VisualChain = Chain & {
|
|
46
|
+
chainId: Chains;
|
|
47
|
+
logoURI: string;
|
|
48
|
+
alt: string;
|
|
49
|
+
};
|
|
50
|
+
/** The metadata for a chain */
|
|
51
|
+
export type ChainsMetadata = Record<Chains, VisualChain>;
|
package/dist/claims.d.ts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { type Hex } from 'viem';
|
|
2
|
+
import type { PlannedTx } from './execution.js';
|
|
3
|
+
/**
|
|
4
|
+
* MANUAL CLAIMS. A home-to-foreign crossing (PulseChain to Ethereum, for
|
|
5
|
+
* example) ends with a release on the destination chain. When nobody delivers
|
|
6
|
+
* it, the reader claims it by hand: they send the validators' signatures and
|
|
7
|
+
* the encoded message to the destination bridge. This module builds that
|
|
8
|
+
* transaction from the bridge indexer's `UserRequest` record.
|
|
9
|
+
*
|
|
10
|
+
* THE INDEXER ASSUMPTION. The indexer collects the signatures in
|
|
11
|
+
* `handleSignedFor` (`packages/indexer/src/index.ts`, the handler for
|
|
12
|
+
* `HomeAMB:SignedForUserRequest` and `HomeAMB:SignedForAffirmation`). It does
|
|
13
|
+
* not read the signature from the event. It decodes the TRANSACTION's own
|
|
14
|
+
* input as `submitSignature(bytes signature, bytes message)`. That works only
|
|
15
|
+
* when a validator sends `submitSignature` straight to the home bridge from
|
|
16
|
+
* its own account.
|
|
17
|
+
*
|
|
18
|
+
* When a validator signs some other way (through a multisig wallet, a proxy,
|
|
19
|
+
* a batching contract, or any call whose top-level input is not
|
|
20
|
+
* `submitSignature`), the decode fails and the handler drops that signature.
|
|
21
|
+
* It still counts it: `confirmedSignatures` goes up by one, but `signatures`
|
|
22
|
+
* stays one short. `finishedSigning` does NOT stay false. The separate
|
|
23
|
+
* `HomeAMB:CollectedSignatures` event sets it to true regardless. So the
|
|
24
|
+
* record says "signed" while it holds too few signatures, and a claim built
|
|
25
|
+
* from it reverts on the destination bridge, which checks the count against
|
|
26
|
+
* its required-signature threshold. {@link buildClaimTransaction} refuses
|
|
27
|
+
* that record with `signatures-incomplete` rather than build a claim that
|
|
28
|
+
* cannot succeed.
|
|
29
|
+
*/
|
|
30
|
+
/** A signature split into the three parts the destination bridge reads, each as hex without a `0x` prefix. */
|
|
31
|
+
export type SignatureParts = {
|
|
32
|
+
readonly v: string;
|
|
33
|
+
readonly r: string;
|
|
34
|
+
readonly s: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Splits one 65-byte validator signature into its `v`, `r` and `s` parts.
|
|
38
|
+
*
|
|
39
|
+
* @param rawSignature - the signature as the indexer stores it, with or without a `0x` prefix
|
|
40
|
+
* @returns the three parts, hex without prefixes
|
|
41
|
+
*/
|
|
42
|
+
export declare const signatureToVRS: (rawSignature: string) => SignatureParts;
|
|
43
|
+
/**
|
|
44
|
+
* Packs signatures in the layout the bridge's `executeSignatures` reads: one
|
|
45
|
+
* count byte, then every `v`, then every `r`, then every `s`.
|
|
46
|
+
*
|
|
47
|
+
* @param signatures - the split signatures, in the order the validators signed
|
|
48
|
+
* @returns the packed signatures as one hex string
|
|
49
|
+
*/
|
|
50
|
+
export declare const packSignatures: (signatures: readonly SignatureParts[]) => Hex;
|
|
51
|
+
/**
|
|
52
|
+
* The calldata for a release that pays no delivery tip: a direct call to the
|
|
53
|
+
* destination bridge.
|
|
54
|
+
*
|
|
55
|
+
* @param options.encodedData - the bridge message, `UserRequest.encodedData`
|
|
56
|
+
* @param options.encodedSignatures - the output of {@link packSignatures}
|
|
57
|
+
* @returns the calldata for `safeExecuteSignaturesWithAutoGasLimit`
|
|
58
|
+
*/
|
|
59
|
+
export declare const encodeReleaseWithoutTipData: ({ encodedData, encodedSignatures, }: {
|
|
60
|
+
encodedData: Hex;
|
|
61
|
+
encodedSignatures: Hex;
|
|
62
|
+
}) => Hex;
|
|
63
|
+
/**
|
|
64
|
+
* The calldata for a release sent through the pathway's destination output
|
|
65
|
+
* router, the path a fee-director (delivery) request uses.
|
|
66
|
+
*
|
|
67
|
+
* @param options.validator - the pathway's validator contract
|
|
68
|
+
* @param options.encodedData - the bridge message, `UserRequest.encodedData`
|
|
69
|
+
* @param options.encodedSignatures - the output of {@link packSignatures}
|
|
70
|
+
* @returns the calldata for the router's `safeExecuteSignaturesWithAutoGasLimit`
|
|
71
|
+
*/
|
|
72
|
+
export declare const encodeReleaseToRouterData: ({ validator, encodedData, encodedSignatures, }: {
|
|
73
|
+
validator: Hex;
|
|
74
|
+
encodedData: Hex;
|
|
75
|
+
encodedSignatures: Hex;
|
|
76
|
+
}) => Hex;
|
|
77
|
+
/**
|
|
78
|
+
* Where a claim is sent.
|
|
79
|
+
*
|
|
80
|
+
* - `direct` sends it to the destination bridge and pays no delivery tip.
|
|
81
|
+
* - `router` sends it through the pathway's destination output router, which
|
|
82
|
+
* pays the tip a fee-director request carries. Read both addresses from the
|
|
83
|
+
* pathway (`pathway(bridgeKey)`'s `destinationRouter` and `validator`).
|
|
84
|
+
*/
|
|
85
|
+
export type ClaimRoute = {
|
|
86
|
+
readonly kind: 'direct';
|
|
87
|
+
} | {
|
|
88
|
+
readonly kind: 'router';
|
|
89
|
+
readonly destinationRouter: Hex;
|
|
90
|
+
readonly validator: Hex;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* The one place a claim's target and calldata come from. The interface's
|
|
94
|
+
* release hook and {@link buildClaimTransaction} both call it.
|
|
95
|
+
*
|
|
96
|
+
* @param options.encodedData - the bridge message
|
|
97
|
+
* @param options.signatures - the raw validator signatures, in signing order
|
|
98
|
+
* @param options.destinationAmbAddress - the destination bridge, used by the `direct` route
|
|
99
|
+
* @param options.via - which contract receives the claim
|
|
100
|
+
* @returns the target contract and the calldata
|
|
101
|
+
*/
|
|
102
|
+
export declare const claimCall: ({ encodedData, signatures, destinationAmbAddress, via, }: {
|
|
103
|
+
readonly encodedData: Hex;
|
|
104
|
+
readonly signatures: readonly string[];
|
|
105
|
+
readonly destinationAmbAddress: Hex;
|
|
106
|
+
readonly via: ClaimRoute;
|
|
107
|
+
}) => {
|
|
108
|
+
readonly to: Hex;
|
|
109
|
+
readonly data: Hex;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* The bridge indexer's `UserRequest` fields a claim reads. The names match the
|
|
113
|
+
* indexer's GraphQL type, so a caller passes the record it fetched as it is.
|
|
114
|
+
* The indexer sends its big-integer scalars as decimal strings, so the counts
|
|
115
|
+
* and the chain id accept a string as well.
|
|
116
|
+
*/
|
|
117
|
+
export type ClaimableUserRequest = {
|
|
118
|
+
/** `'signature'` for a home-to-foreign request. Only those are claimed by hand. */
|
|
119
|
+
readonly type: string;
|
|
120
|
+
readonly encodedData: string;
|
|
121
|
+
/** The JSON list of raw validator signatures, or null on a request type that collects none. */
|
|
122
|
+
readonly signatures?: unknown;
|
|
123
|
+
/** How many `SignedFor` events the indexer counted for this request. */
|
|
124
|
+
readonly confirmedSignatures: bigint | number | string;
|
|
125
|
+
/**
|
|
126
|
+
* The bridge's required-signature threshold in force for this request, as
|
|
127
|
+
* the indexer links it. When absent, the builder demands every counted
|
|
128
|
+
* signature, which is stricter than the bridge.
|
|
129
|
+
*/
|
|
130
|
+
readonly requiredSignatures?: {
|
|
131
|
+
readonly value: bigint | number | string;
|
|
132
|
+
} | null;
|
|
133
|
+
readonly destinationAmbAddress: string;
|
|
134
|
+
readonly destinationChainId: bigint | number | string;
|
|
135
|
+
/** True once the indexer saw `CollectedSignatures` (or the delivery itself). */
|
|
136
|
+
readonly finishedSigning: boolean;
|
|
137
|
+
/** True once the release executed on the destination chain. */
|
|
138
|
+
readonly delivered: boolean;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Why a request cannot be claimed. Each case names a different action for the
|
|
142
|
+
* reader:
|
|
143
|
+
*
|
|
144
|
+
* - `wrong-type` — not a signature request. An affirmation request is
|
|
145
|
+
* executed by the validators themselves; there is nothing to claim.
|
|
146
|
+
* - `already-delivered` — the release already executed. A claim would revert.
|
|
147
|
+
* - `not-signed-yet` — the validators have not finished signing. Wait.
|
|
148
|
+
* - `signatures-incomplete` — the indexer stored fewer signatures than the
|
|
149
|
+
* bridge needs (the threshold, or every counted signature when the request
|
|
150
|
+
* carries no threshold). See this module's note on the `submitSignature`
|
|
151
|
+
* assumption. Waiting does not fix this one.
|
|
152
|
+
* - `malformed-request` — a field is not the shape the indexer documents.
|
|
153
|
+
*/
|
|
154
|
+
export type ClaimRefusal = {
|
|
155
|
+
readonly reason: 'wrong-type';
|
|
156
|
+
readonly type: string;
|
|
157
|
+
} | {
|
|
158
|
+
readonly reason: 'already-delivered';
|
|
159
|
+
} | {
|
|
160
|
+
readonly reason: 'not-signed-yet';
|
|
161
|
+
} | {
|
|
162
|
+
readonly reason: 'signatures-incomplete';
|
|
163
|
+
readonly stored: number;
|
|
164
|
+
readonly needed: number;
|
|
165
|
+
} | {
|
|
166
|
+
readonly reason: 'malformed-request';
|
|
167
|
+
readonly field: string;
|
|
168
|
+
};
|
|
169
|
+
/** A claim transaction, or the typed reason none can be built. */
|
|
170
|
+
export type ClaimPlan = {
|
|
171
|
+
readonly kind: 'claim';
|
|
172
|
+
readonly transaction: PlannedTx;
|
|
173
|
+
} | {
|
|
174
|
+
readonly kind: 'refused';
|
|
175
|
+
readonly refusal: ClaimRefusal;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Builds the manual-claim transaction for one bridge request, or refuses with
|
|
179
|
+
* a typed reason.
|
|
180
|
+
*
|
|
181
|
+
* The checks run in this order: request type, delivery, signing, then the
|
|
182
|
+
* stored signature count. A delivered request is refused before the signing
|
|
183
|
+
* check, because delivery also sets `finishedSigning`.
|
|
184
|
+
*
|
|
185
|
+
* ASSUMPTION: the signatures are only complete when every validator sent
|
|
186
|
+
* `submitSignature` directly to the home bridge. The indexer drops a
|
|
187
|
+
* signature sent any other way; see this module's head note. This builder
|
|
188
|
+
* catches the drop by comparing the stored list with the required-signature
|
|
189
|
+
* threshold, or with `confirmedSignatures` when the record carries no threshold.
|
|
190
|
+
*
|
|
191
|
+
* @param options.request - the indexer's `UserRequest` record
|
|
192
|
+
* @param options.via - the claim target; see {@link ClaimRoute}
|
|
193
|
+
* @returns a `claim` plan whose transaction runs on the destination chain, or a refusal
|
|
194
|
+
*/
|
|
195
|
+
export declare const buildClaimTransaction: ({ request, via, }: {
|
|
196
|
+
readonly request: ClaimableUserRequest;
|
|
197
|
+
readonly via: ClaimRoute;
|
|
198
|
+
}) => ClaimPlan;
|
package/dist/claims.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { encodeFunctionData, isHex, numberToHex } from 'viem';
|
|
2
|
+
import * as abis from './abis.js';
|
|
3
|
+
const strip0x = (input) => input.replace(/^0x/, '');
|
|
4
|
+
/**
|
|
5
|
+
* Splits one 65-byte validator signature into its `v`, `r` and `s` parts.
|
|
6
|
+
*
|
|
7
|
+
* @param rawSignature - the signature as the indexer stores it, with or without a `0x` prefix
|
|
8
|
+
* @returns the three parts, hex without prefixes
|
|
9
|
+
*/
|
|
10
|
+
export const signatureToVRS = (rawSignature) => {
|
|
11
|
+
const signature = strip0x(rawSignature);
|
|
12
|
+
const word = 32;
|
|
13
|
+
const word2 = word * 2;
|
|
14
|
+
const word4 = word2 * 2;
|
|
15
|
+
const r = signature.slice(0, word2);
|
|
16
|
+
const s = signature.slice(word2, word4);
|
|
17
|
+
const v = signature.slice(word4);
|
|
18
|
+
return { v, r, s };
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Packs signatures in the layout the bridge's `executeSignatures` reads: one
|
|
22
|
+
* count byte, then every `v`, then every `r`, then every `s`.
|
|
23
|
+
*
|
|
24
|
+
* @param signatures - the split signatures, in the order the validators signed
|
|
25
|
+
* @returns the packed signatures as one hex string
|
|
26
|
+
*/
|
|
27
|
+
export const packSignatures = (signatures) => {
|
|
28
|
+
const length = strip0x(numberToHex(signatures.length));
|
|
29
|
+
const countByte = length.length === 1 ? `0${length}` : length;
|
|
30
|
+
const v = signatures.map((signature) => signature.v).join('');
|
|
31
|
+
const r = signatures.map((signature) => signature.r).join('');
|
|
32
|
+
const s = signatures.map((signature) => signature.s).join('');
|
|
33
|
+
return `0x${countByte}${v}${r}${s}`;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The calldata for a release that pays no delivery tip: a direct call to the
|
|
37
|
+
* destination bridge.
|
|
38
|
+
*
|
|
39
|
+
* @param options.encodedData - the bridge message, `UserRequest.encodedData`
|
|
40
|
+
* @param options.encodedSignatures - the output of {@link packSignatures}
|
|
41
|
+
* @returns the calldata for `safeExecuteSignaturesWithAutoGasLimit`
|
|
42
|
+
*/
|
|
43
|
+
export const encodeReleaseWithoutTipData = ({ encodedData, encodedSignatures, }) => encodeFunctionData({
|
|
44
|
+
abi: abis.relayTokensDirect,
|
|
45
|
+
functionName: 'safeExecuteSignaturesWithAutoGasLimit',
|
|
46
|
+
args: [encodedData, encodedSignatures],
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* The calldata for a release sent through the pathway's destination output
|
|
50
|
+
* router, the path a fee-director (delivery) request uses.
|
|
51
|
+
*
|
|
52
|
+
* @param options.validator - the pathway's validator contract
|
|
53
|
+
* @param options.encodedData - the bridge message, `UserRequest.encodedData`
|
|
54
|
+
* @param options.encodedSignatures - the output of {@link packSignatures}
|
|
55
|
+
* @returns the calldata for the router's `safeExecuteSignaturesWithAutoGasLimit`
|
|
56
|
+
*/
|
|
57
|
+
export const encodeReleaseToRouterData = ({ validator, encodedData, encodedSignatures, }) => encodeFunctionData({
|
|
58
|
+
abi: abis.outputRouter,
|
|
59
|
+
functionName: 'safeExecuteSignaturesWithAutoGasLimit',
|
|
60
|
+
args: [validator, encodedData, encodedSignatures],
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* The one place a claim's target and calldata come from. The interface's
|
|
64
|
+
* release hook and {@link buildClaimTransaction} both call it.
|
|
65
|
+
*
|
|
66
|
+
* @param options.encodedData - the bridge message
|
|
67
|
+
* @param options.signatures - the raw validator signatures, in signing order
|
|
68
|
+
* @param options.destinationAmbAddress - the destination bridge, used by the `direct` route
|
|
69
|
+
* @param options.via - which contract receives the claim
|
|
70
|
+
* @returns the target contract and the calldata
|
|
71
|
+
*/
|
|
72
|
+
export const claimCall = ({ encodedData, signatures, destinationAmbAddress, via, }) => {
|
|
73
|
+
const encodedSignatures = packSignatures(signatures.map(signatureToVRS));
|
|
74
|
+
if (via.kind === 'router') {
|
|
75
|
+
return {
|
|
76
|
+
to: via.destinationRouter,
|
|
77
|
+
data: encodeReleaseToRouterData({ validator: via.validator, encodedData, encodedSignatures }),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { to: destinationAmbAddress, data: encodeReleaseWithoutTipData({ encodedData, encodedSignatures }) };
|
|
81
|
+
};
|
|
82
|
+
const isSignatureList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === 'string' && isHex(entry));
|
|
83
|
+
const refused = (refusal) => ({ kind: 'refused', refusal });
|
|
84
|
+
/**
|
|
85
|
+
* Builds the manual-claim transaction for one bridge request, or refuses with
|
|
86
|
+
* a typed reason.
|
|
87
|
+
*
|
|
88
|
+
* The checks run in this order: request type, delivery, signing, then the
|
|
89
|
+
* stored signature count. A delivered request is refused before the signing
|
|
90
|
+
* check, because delivery also sets `finishedSigning`.
|
|
91
|
+
*
|
|
92
|
+
* ASSUMPTION: the signatures are only complete when every validator sent
|
|
93
|
+
* `submitSignature` directly to the home bridge. The indexer drops a
|
|
94
|
+
* signature sent any other way; see this module's head note. This builder
|
|
95
|
+
* catches the drop by comparing the stored list with the required-signature
|
|
96
|
+
* threshold, or with `confirmedSignatures` when the record carries no threshold.
|
|
97
|
+
*
|
|
98
|
+
* @param options.request - the indexer's `UserRequest` record
|
|
99
|
+
* @param options.via - the claim target; see {@link ClaimRoute}
|
|
100
|
+
* @returns a `claim` plan whose transaction runs on the destination chain, or a refusal
|
|
101
|
+
*/
|
|
102
|
+
export const buildClaimTransaction = ({ request, via, }) => {
|
|
103
|
+
if (request.type !== 'signature')
|
|
104
|
+
return refused({ reason: 'wrong-type', type: request.type });
|
|
105
|
+
if (request.delivered)
|
|
106
|
+
return refused({ reason: 'already-delivered' });
|
|
107
|
+
if (!request.finishedSigning)
|
|
108
|
+
return refused({ reason: 'not-signed-yet' });
|
|
109
|
+
if (!isSignatureList(request.signatures))
|
|
110
|
+
return refused({ reason: 'malformed-request', field: 'signatures' });
|
|
111
|
+
if (!isHex(request.encodedData))
|
|
112
|
+
return refused({ reason: 'malformed-request', field: 'encodedData' });
|
|
113
|
+
if (!isHex(request.destinationAmbAddress)) {
|
|
114
|
+
return refused({ reason: 'malformed-request', field: 'destinationAmbAddress' });
|
|
115
|
+
}
|
|
116
|
+
const needed = Number(request.requiredSignatures?.value ?? request.confirmedSignatures);
|
|
117
|
+
const stored = request.signatures.length;
|
|
118
|
+
if (stored < needed)
|
|
119
|
+
return refused({ reason: 'signatures-incomplete', stored, needed });
|
|
120
|
+
const { to, data } = claimCall({
|
|
121
|
+
encodedData: request.encodedData,
|
|
122
|
+
signatures: request.signatures,
|
|
123
|
+
destinationAmbAddress: request.destinationAmbAddress,
|
|
124
|
+
via,
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
kind: 'claim',
|
|
128
|
+
transaction: {
|
|
129
|
+
chainId: Number(request.destinationChainId),
|
|
130
|
+
kind: 'claim',
|
|
131
|
+
to,
|
|
132
|
+
data,
|
|
133
|
+
value: 0n,
|
|
134
|
+
// The calldata itself asks the bridge to pick its own gas limit
|
|
135
|
+
// (`safeExecuteSignaturesWithAutoGasLimit`); the wallet estimates the rest.
|
|
136
|
+
gasLimit: null,
|
|
137
|
+
waitForReceipt: false,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
};
|
package/dist/config.d.ts
CHANGED
|
@@ -33,6 +33,30 @@ export declare const Providers: {
|
|
|
33
33
|
export type Provider = (typeof Providers)[keyof typeof Providers];
|
|
34
34
|
/** A map of chains to native asset out addresses */
|
|
35
35
|
export declare const nativeAssetOut: Record<Chains, Hex>;
|
|
36
|
+
/**
|
|
37
|
+
* Four PulseChain mainnet tokens that no other constant in this package
|
|
38
|
+
* names. The PulseX carrier routes swaps through them
|
|
39
|
+
* (`routing/carriers/pulsex-paths.ts`), and the interface builds its
|
|
40
|
+
* PulseChain hub nodes from the two stablecoins.
|
|
41
|
+
*
|
|
42
|
+
* Each address was already in the repository before it moved here: USDC and
|
|
43
|
+
* USDT from the interface's `HUB_STABLECOIN_ADDRESSES`
|
|
44
|
+
* (`packages/ui/src/lib/state/useRouteSearch.ts`), PLSX and HEX from
|
|
45
|
+
* `scripts/route-parity-corpus.ts`. Each one was read on chain again on
|
|
46
|
+
* 2026-10-06 (`symbol()`, `decimals()`): PLSX 18, HEX 8, USDC 6, USDT 6.
|
|
47
|
+
* `getAddress` checksums them at load, so a mistyped character fails the
|
|
48
|
+
* build rather than silently matching nothing.
|
|
49
|
+
*/
|
|
50
|
+
export declare const pulsechainTokenAddresses: Readonly<{
|
|
51
|
+
/** PulseX, the exchange's own token. */
|
|
52
|
+
PLSX: `0x${string}`;
|
|
53
|
+
/** HEX. */
|
|
54
|
+
HEX: `0x${string}`;
|
|
55
|
+
/** USD Coin, bridged from Ethereum. */
|
|
56
|
+
USDC: `0x${string}`;
|
|
57
|
+
/** Tether USD, bridged from Ethereum. */
|
|
58
|
+
USDT: `0x${string}`;
|
|
59
|
+
}>;
|
|
36
60
|
/** A map of chains to deprecated native asset out addresses */
|
|
37
61
|
export declare const deprecatedNativeAssetOut: Partial<Record<Chains, Set<Hex>>>;
|
|
38
62
|
/** A map of chains to uni v2 router addresses */
|