@gibs/bridge-sdk 1.12.0 → 1.13.1
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/LICENSE +15 -0
- package/README.md +234 -432
- package/dist/abis.d.ts +1 -0
- package/dist/bridge-limits.d.ts +103 -0
- package/dist/bridge-limits.js +84 -0
- package/dist/chain-info.d.ts +169 -0
- package/dist/chain-info.js +410 -0
- package/dist/chain-names.d.ts +160 -0
- package/dist/chain-names.js +200 -0
- package/dist/chains.d.ts +65 -0
- package/dist/chains.js +284 -0
- package/dist/config.d.ts +216 -0
- package/dist/config.js +493 -0
- package/dist/consolidated-quote.d.ts +554 -0
- package/dist/consolidated-quote.js +773 -0
- package/dist/destination-calldata.d.ts +118 -0
- package/dist/destination-calldata.js +152 -0
- package/dist/ecosystems.d.ts +217 -0
- package/dist/ecosystems.js +288 -0
- package/dist/fee-type.d.ts +10 -0
- package/dist/fee-type.js +9 -0
- package/dist/hyperliquid-execution.d.ts +152 -0
- package/dist/hyperliquid-execution.js +168 -0
- package/dist/image-links.d.ts +117 -0
- package/dist/image-links.js +142 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/lifi-execution-guard.d.ts +199 -0
- package/dist/lifi-execution-guard.js +400 -0
- package/dist/near-intents-conformance.d.ts +85 -0
- package/dist/near-intents-conformance.js +329 -0
- package/dist/near-intents-route.d.ts +47 -0
- package/dist/near-intents-route.js +265 -0
- package/dist/near-intents.d.ts +524 -0
- package/dist/near-intents.js +1055 -0
- package/dist/origin-deposit.d.ts +326 -0
- package/dist/origin-deposit.js +68 -0
- package/dist/pre-quote.d.ts +198 -0
- package/dist/pre-quote.js +175 -0
- package/dist/prices.d.ts +107 -0
- package/dist/prices.js +162 -0
- package/dist/providers.d.ts +221 -0
- package/dist/providers.js +157 -0
- package/dist/quote-fees.d.ts +102 -0
- package/dist/quote-fees.js +195 -0
- package/dist/referral.d.ts +77 -0
- package/dist/referral.js +72 -0
- package/dist/relay-currencies.d.ts +47 -0
- package/dist/relay-currencies.js +89 -0
- package/dist/relay-quote.d.ts +301 -0
- package/dist/relay-quote.js +983 -0
- package/dist/route-steps.d.ts +138 -0
- package/dist/route-steps.js +305 -0
- package/dist/routing/amounts.d.ts +80 -0
- package/dist/routing/amounts.js +120 -0
- package/dist/routing/candidate-route.d.ts +43 -0
- package/dist/routing/candidate-route.js +45 -0
- package/dist/routing/candidate.d.ts +237 -0
- package/dist/routing/candidate.js +96 -0
- package/dist/routing/carriers/ask-answer.d.ts +60 -0
- package/dist/routing/carriers/ask-answer.js +1 -0
- package/dist/routing/carriers/omnibridge.d.ts +137 -0
- package/dist/routing/carriers/omnibridge.js +419 -0
- package/dist/routing/carriers/pulsex.d.ts +149 -0
- package/dist/routing/carriers/pulsex.js +453 -0
- package/dist/routing/carriers/wrap.d.ts +25 -0
- package/dist/routing/carriers/wrap.js +115 -0
- package/dist/routing/composed-route-quality.d.ts +103 -0
- package/dist/routing/composed-route-quality.js +108 -0
- package/dist/routing/entry-chain-anchor.d.ts +88 -0
- package/dist/routing/entry-chain-anchor.js +55 -0
- package/dist/routing/format.d.ts +31 -0
- package/dist/routing/format.js +58 -0
- package/dist/routing/index.d.ts +34 -0
- package/dist/routing/index.js +42 -0
- package/dist/routing/producers.d.ts +770 -0
- package/dist/routing/producers.js +1564 -0
- package/dist/routing/providers.d.ts +26 -0
- package/dist/routing/providers.js +38 -0
- package/dist/routing/route-data.d.ts +355 -0
- package/dist/routing/route-data.js +1 -0
- package/dist/routing/search/compose.d.ts +168 -0
- package/dist/routing/search/compose.js +98 -0
- package/dist/routing/search/graph.d.ts +653 -0
- package/dist/routing/search/graph.js +445 -0
- package/dist/routing/search/plan-route-data.d.ts +244 -0
- package/dist/routing/search/plan-route-data.js +767 -0
- package/dist/routing/search/score.d.ts +353 -0
- package/dist/routing/search/score.js +427 -0
- package/dist/routing/usd-value.d.ts +17 -0
- package/dist/routing/usd-value.js +25 -0
- package/dist/settings.d.ts +692 -0
- package/dist/settings.js +909 -0
- package/dist/ton-execution.d.ts +117 -0
- package/dist/ton-execution.js +247 -0
- package/dist/tron-execution.d.ts +146 -0
- package/dist/tron-execution.js +239 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +1 -0
- package/llms.txt +169 -0
- package/package.json +204 -23
- package/src/chain-info.test.ts +0 -968
- package/src/chain-info.ts +0 -498
- package/src/chains.test.ts +0 -123
- package/src/chains.ts +0 -88
- package/src/config.test.ts +0 -679
- package/src/config.ts +0 -500
- package/src/fee-type.test.ts +0 -45
- package/src/fee-type.ts +0 -14
- package/src/image-links.test.ts +0 -160
- package/src/image-links.ts +0 -65
- package/src/index.ts +0 -8
- package/src/settings.test.ts +0 -2754
- package/src/settings.ts +0 -875
- package/src/types.ts +0 -48
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -13
- /package/{src/abis.ts → dist/abis.js} +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executing a deposit on Tron, as pure data.
|
|
3
|
+
*
|
|
4
|
+
* Relay does not return a broadcastable Tron transaction. It returns the
|
|
5
|
+
* *parameters* of a `TriggerSmartContract` call — owner, contract, call value
|
|
6
|
+
* and calldata — and nothing else. A Tron transaction additionally needs a
|
|
7
|
+
* reference block, an expiration and a fee limit, none of which Relay supplies.
|
|
8
|
+
* Those are produced by asking a full node to build the transaction, which is
|
|
9
|
+
* what {@link buildTriggerSmartContractRequest} constructs the body for. The
|
|
10
|
+
* node answers with an UNSIGNED transaction; the wallet signs it and a second
|
|
11
|
+
* call broadcasts it.
|
|
12
|
+
*
|
|
13
|
+
* Three details of that exchange lose money or mislead if handled naively:
|
|
14
|
+
*
|
|
15
|
+
* **The `visible` flag defaults to true.** A node reads addresses as base58
|
|
16
|
+
* unless told otherwise, but Relay returns them as hex with Tron's `41` prefix.
|
|
17
|
+
* Omitting the flag therefore hands base58-parsing a hex string. The request
|
|
18
|
+
* built here always states `visible: false` rather than relying on a default
|
|
19
|
+
* that is the opposite of what the payload contains.
|
|
20
|
+
*
|
|
21
|
+
* **`fee_limit` is required and Relay omits it.** It caps the energy the caller
|
|
22
|
+
* will pay for. Set too low, the call runs out of energy, reverts, and the
|
|
23
|
+
* energy already burned is NOT refunded — the deposit fails and costs the user
|
|
24
|
+
* anyway.
|
|
25
|
+
*
|
|
26
|
+
* **A rejected call still answers HTTP 200**, with the reason hex-encoded in
|
|
27
|
+
* `result.message`. Reading the status code alone reports a failed deposit as a
|
|
28
|
+
* success, and printing the message unmodified shows the user a wall of hex.
|
|
29
|
+
* {@link tronErrorMessage} decodes it.
|
|
30
|
+
*
|
|
31
|
+
* Kept free of transport and of clock reads so it is fully testable: nothing
|
|
32
|
+
* here signs, fetches, or calls `Date.now`. The caller performs the requests.
|
|
33
|
+
*/
|
|
34
|
+
/** Path of the full-node endpoint that builds an unsigned contract call. */
|
|
35
|
+
export const tronTriggerSmartContractPath = '/wallet/triggersmartcontract';
|
|
36
|
+
/**
|
|
37
|
+
* The fee limit used when a caller states none, in sun (1 TRX = 1,000,000 sun).
|
|
38
|
+
*
|
|
39
|
+
* Thirty TRX, matching Relay's own wallet adapter, which is the only reference
|
|
40
|
+
* implementation of this deposit path. It is an upper bound rather than a
|
|
41
|
+
* charge: unused energy is not taken, so the cost of setting it generously is
|
|
42
|
+
* only that the wallet shows a larger worst case.
|
|
43
|
+
*/
|
|
44
|
+
export const defaultTronFeeLimitSun = 30_000_000;
|
|
45
|
+
/**
|
|
46
|
+
* The largest fee limit a node accepts, in sun — 15,000 TRX. Documented as a
|
|
47
|
+
* hard protocol cap, so a request above it is rejected outright rather than
|
|
48
|
+
* clamped.
|
|
49
|
+
*/
|
|
50
|
+
export const maximumTronFeeLimitSun = 15_000_000_000;
|
|
51
|
+
/**
|
|
52
|
+
* Tron's `41` address prefix, the hex form's equivalent of the base58 `T`.
|
|
53
|
+
*/
|
|
54
|
+
const tronHexAddressPrefix = '41';
|
|
55
|
+
/** A hex address is the prefix byte plus a twenty-byte account identifier. */
|
|
56
|
+
const tronHexAddressLength = 42;
|
|
57
|
+
/**
|
|
58
|
+
* Normalizes a Tron hex address for comparison.
|
|
59
|
+
*
|
|
60
|
+
* Wallets and quotes disagree on casing, and Relay's payload is not guaranteed
|
|
61
|
+
* to match what a wallet reports even when both name the same account.
|
|
62
|
+
*
|
|
63
|
+
* @param value - an address in Tron's `41`-prefixed hex form, in any casing,
|
|
64
|
+
* optionally written with a `0x` prefix
|
|
65
|
+
* @returns the lowercase `41` form, or null when the value is not that form
|
|
66
|
+
*/
|
|
67
|
+
export const normalizeTronHexAddress = (value) => {
|
|
68
|
+
const withoutPrefix = value.trim().replace(/^0x/i, '').toLowerCase();
|
|
69
|
+
if (withoutPrefix.length !== tronHexAddressLength) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (!withoutPrefix.startsWith(tronHexAddressPrefix)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return /^[0-9a-f]+$/.test(withoutPrefix) ? withoutPrefix : null;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Whether two Tron hex addresses name the same account.
|
|
79
|
+
*
|
|
80
|
+
* Used to check a deposit's owner against the connected wallet before signing.
|
|
81
|
+
* A mismatch means the quote was built for a different account, and signing it
|
|
82
|
+
* would spend from an account the user did not choose — or simply fail after
|
|
83
|
+
* the user has already approved.
|
|
84
|
+
*
|
|
85
|
+
* @param left - an address in Tron's `41`-prefixed hex form
|
|
86
|
+
* @param right - an address in the same form
|
|
87
|
+
* @returns true only when both parse and name the same account
|
|
88
|
+
*/
|
|
89
|
+
export const isSameTronAccount = (left, right) => {
|
|
90
|
+
const normalizedLeft = normalizeTronHexAddress(left);
|
|
91
|
+
const normalizedRight = normalizeTronHexAddress(right);
|
|
92
|
+
return normalizedLeft !== null && normalizedLeft === normalizedRight;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Strips the `0x` prefix Tron calldata never carries.
|
|
96
|
+
*
|
|
97
|
+
* Relay documents this field as bare hex, but its own adapter strips the prefix
|
|
98
|
+
* defensively, and a prefixed value is parsed by a node as calldata beginning
|
|
99
|
+
* with the bytes `0x` rather than being rejected — a silently wrong call.
|
|
100
|
+
*/
|
|
101
|
+
const bareHex = (value) => value.replace(/^0x/i, '').toLowerCase();
|
|
102
|
+
/**
|
|
103
|
+
* Whether a numeric amount survives the trip through JSON as an exact integer.
|
|
104
|
+
*
|
|
105
|
+
* Sun amounts are 64-bit on the wire but JSON carries them as doubles, so a
|
|
106
|
+
* large enough value would be silently rounded — into a different amount of
|
|
107
|
+
* money than the one that was quoted.
|
|
108
|
+
*/
|
|
109
|
+
const isExactInteger = (value) => value >= 0n && value <= BigInt(Number.MAX_SAFE_INTEGER);
|
|
110
|
+
/**
|
|
111
|
+
* Builds the body that asks a full node to construct the unsigned deposit.
|
|
112
|
+
*
|
|
113
|
+
* @param deposit - the parsed origin deposit
|
|
114
|
+
* @param options.feeLimitSun - the energy spending cap in sun; defaults to
|
|
115
|
+
* {@link defaultTronFeeLimitSun}
|
|
116
|
+
* @returns the request body, or null when the deposit names an address that is
|
|
117
|
+
* not Tron hex, carries a call value that cannot be represented exactly, or
|
|
118
|
+
* the fee limit is outside what a node accepts — never a body that would be
|
|
119
|
+
* built against a default `visible` the payload contradicts
|
|
120
|
+
*/
|
|
121
|
+
export const buildTriggerSmartContractRequest = (deposit, { feeLimitSun = defaultTronFeeLimitSun } = {}) => {
|
|
122
|
+
const ownerAddress = normalizeTronHexAddress(deposit.ownerAddress);
|
|
123
|
+
const contractAddress = normalizeTronHexAddress(deposit.contractAddress);
|
|
124
|
+
if (ownerAddress === null || contractAddress === null) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
if (!isExactInteger(deposit.callValue)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
if (!Number.isInteger(feeLimitSun) || feeLimitSun <= 0 || feeLimitSun > maximumTronFeeLimitSun) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
owner_address: ownerAddress,
|
|
135
|
+
contract_address: contractAddress,
|
|
136
|
+
data: bareHex(deposit.data),
|
|
137
|
+
call_value: Number(deposit.callValue),
|
|
138
|
+
fee_limit: feeLimitSun,
|
|
139
|
+
visible: false,
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Decodes a node's hex-encoded failure message.
|
|
144
|
+
*
|
|
145
|
+
* A node reports why it refused a call in `result.message`, hex-encoded — the
|
|
146
|
+
* bytes `4e6f20636f6e7472616374…` rather than "No contract or not a valid smart
|
|
147
|
+
* contract". Broadcast failures report plain text in the same field, so both
|
|
148
|
+
* are handled and a value that is not hex is passed through unchanged.
|
|
149
|
+
*/
|
|
150
|
+
const decodeTronMessage = (value) => {
|
|
151
|
+
const trimmed = value.trim();
|
|
152
|
+
if (trimmed.length === 0 || trimmed.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(trimmed)) {
|
|
153
|
+
return trimmed;
|
|
154
|
+
}
|
|
155
|
+
let decoded = '';
|
|
156
|
+
for (let index = 0; index < trimmed.length; index += 2) {
|
|
157
|
+
decoded += String.fromCharCode(Number.parseInt(trimmed.slice(index, index + 2), 16));
|
|
158
|
+
}
|
|
159
|
+
// A hex string that decodes to control characters was a number, not a
|
|
160
|
+
// message — return the original rather than a string of unprintable bytes.
|
|
161
|
+
return /^[\x20-\x7e]*$/.test(decoded) ? decoded : trimmed;
|
|
162
|
+
};
|
|
163
|
+
const asRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
164
|
+
? value
|
|
165
|
+
: null;
|
|
166
|
+
/**
|
|
167
|
+
* Extracts a node's failure reason from either endpoint's response.
|
|
168
|
+
*
|
|
169
|
+
* @param payload - the parsed response body
|
|
170
|
+
* @returns the decoded message, or null when the response reports no failure
|
|
171
|
+
*/
|
|
172
|
+
export const tronErrorMessage = (payload) => {
|
|
173
|
+
const body = asRecord(payload);
|
|
174
|
+
if (body === null) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
// The build endpoint nests its outcome under `result`; the broadcast endpoint
|
|
178
|
+
// reports at the top level.
|
|
179
|
+
const nested = asRecord(body.result);
|
|
180
|
+
const message = nested?.message ?? body.message;
|
|
181
|
+
if (typeof message !== 'string') {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const decoded = decodeTronMessage(message);
|
|
185
|
+
return decoded.length === 0 ? null : decoded;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Reads the unsigned transaction out of a build response.
|
|
189
|
+
*
|
|
190
|
+
* The response carries the transaction at the top level alongside a `result`
|
|
191
|
+
* object stating whether the build succeeded, so the presence of a `txID` is
|
|
192
|
+
* not on its own evidence of success.
|
|
193
|
+
*
|
|
194
|
+
* @param payload - the parsed `/wallet/triggersmartcontract` response
|
|
195
|
+
* @returns the unsigned transaction to hand a wallet, or null when the node
|
|
196
|
+
* refused the call
|
|
197
|
+
*/
|
|
198
|
+
export const readTriggerSmartContractResponse = (payload) => {
|
|
199
|
+
const body = asRecord(payload);
|
|
200
|
+
if (body === null) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const outcome = asRecord(body.result);
|
|
204
|
+
if (outcome === null || outcome.result !== true) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const transaction = asRecord(body.transaction);
|
|
208
|
+
if (transaction === null || typeof transaction.txID !== 'string') {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
return transaction;
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Reads the transaction identifier out of a broadcast response.
|
|
215
|
+
*
|
|
216
|
+
* GOTCHA: a rejected broadcast answers HTTP 200, and `result` is OMITTED rather
|
|
217
|
+
* than set to false. Testing `result === false` therefore never fires, and
|
|
218
|
+
* trusting the status code records a deposit that never entered a block. Only
|
|
219
|
+
* an explicit `result: true` is accepted here.
|
|
220
|
+
*
|
|
221
|
+
* The identifier is read from `txid` where a node reports it, falling back to
|
|
222
|
+
* the echoed transaction's `txID`. The two spellings differ by casing and by
|
|
223
|
+
* position: a node answers `txid`, while a wallet library that echoes the
|
|
224
|
+
* transaction it broadcast carries `txID` inside it. Accepting only the first
|
|
225
|
+
* would report an accepted broadcast as a failure whenever the caller is one of
|
|
226
|
+
* those libraries.
|
|
227
|
+
*
|
|
228
|
+
* @param payload - the parsed `/wallet/broadcasttransaction` response
|
|
229
|
+
* @returns the transaction identifier, or null when the broadcast was refused
|
|
230
|
+
*/
|
|
231
|
+
export const readBroadcastResponse = (payload) => {
|
|
232
|
+
const body = asRecord(payload);
|
|
233
|
+
if (body === null || body.result !== true) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const echoed = asRecord(body.transaction);
|
|
237
|
+
const identifier = body.txid ?? echoed?.txID;
|
|
238
|
+
return typeof identifier === 'string' && identifier.length > 0 ? identifier : null;
|
|
239
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -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/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/llms.txt
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# @gibs/bridge-sdk
|
|
2
|
+
|
|
3
|
+
> A TypeScript library that prices and builds transfers across the Gibs
|
|
4
|
+
> Finance omnibridges (PulseChain with Ethereum, PulseChain with BNB Smart
|
|
5
|
+
> Chain). It also builds the requests for the aggregator routes (LI.FI,
|
|
6
|
+
> Relay, NEAR Intents) that reach those bridges from other chains. It does
|
|
7
|
+
> not sign or send anything. You bring a viem client and a wallet.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
- Run `npm install @gibs/bridge-sdk viem`.
|
|
12
|
+
- The package is ESM only. Use `import`, not `require`.
|
|
13
|
+
- It needs Node 20 or later (`engines.node` is `>=20`).
|
|
14
|
+
- viem is a peer dependency. The range is `>=2.37.0 <3`.
|
|
15
|
+
- Version note: 1.12.0 and older on npm are broken. 1.13.0 is the first usable version.
|
|
16
|
+
- In a browser, `@gibs/bridge-sdk/ton-execution` needs a global `Buffer`. No other entry point does.
|
|
17
|
+
|
|
18
|
+
## Entry points
|
|
19
|
+
|
|
20
|
+
Import from the narrowest subpath. The root `@gibs/bridge-sdk` exports everything.
|
|
21
|
+
|
|
22
|
+
- `@gibs/bridge-sdk/config`: chains, providers, pathways, native-asset tables.
|
|
23
|
+
- `@gibs/bridge-sdk/types`: shared types such as `BridgeKey` and `Token`.
|
|
24
|
+
- `@gibs/bridge-sdk/chains`: viem chain objects with logos and RPC URLs.
|
|
25
|
+
- `@gibs/bridge-sdk/chain-info`: on-chain reads (token mappings, fees, minimum amounts).
|
|
26
|
+
- `@gibs/bridge-sdk/settings`: fee and amount arithmetic.
|
|
27
|
+
- `@gibs/bridge-sdk/consolidated-quote`: LI.FI request builders and parsers.
|
|
28
|
+
- `@gibs/bridge-sdk/relay-quote`: Relay request builders and parsers.
|
|
29
|
+
- `@gibs/bridge-sdk/near-intents`: NEAR Intents requests and parsers.
|
|
30
|
+
- `@gibs/bridge-sdk/pre-quote`: price checks before a binding quote.
|
|
31
|
+
- `@gibs/bridge-sdk/routing`: route search across carriers.
|
|
32
|
+
- `@gibs/bridge-sdk/image-links`: image URLs from gib.show.
|
|
33
|
+
- `@gibs/bridge-sdk/abis`: contract ABIs.
|
|
34
|
+
|
|
35
|
+
## Chains and pathways
|
|
36
|
+
|
|
37
|
+
A chain is a hex id from the `Chains` enum. A route is a `BridgeKey`:
|
|
38
|
+
`[provider, fromChain, toChain]`. `pathway` returns the contract addresses
|
|
39
|
+
for a key, or `undefined` when no pathway exists.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { Chains, Providers, pathway } from '@gibs/bridge-sdk/config'
|
|
43
|
+
import type { BridgeKey } from '@gibs/bridge-sdk/types'
|
|
44
|
+
|
|
45
|
+
const bridgeKey: BridgeKey = [Providers.PULSECHAIN, Chains.ETH, Chains.PLS]
|
|
46
|
+
const route = pathway(bridgeKey, true) // true: mainnet only
|
|
47
|
+
if (route) {
|
|
48
|
+
route.from // the mediator on Ethereum, where funds enter
|
|
49
|
+
route.feeManager // 'to': the PulseChain mediator owns the fee manager
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Fees: direction and units
|
|
54
|
+
|
|
55
|
+
These rules must hold in every integration.
|
|
56
|
+
|
|
57
|
+
- PulseChain is the home side of both omnibridges.
|
|
58
|
+
- Foreign to home (`feeF2H`) means entering PulseChain.
|
|
59
|
+
- Home to foreign (`feeH2F`) means leaving PulseChain.
|
|
60
|
+
- Use the fee for your direction. Do not use one fee for both.
|
|
61
|
+
- Bridge fees are a rate per `1e18`. `1e18` is one hundred percent.
|
|
62
|
+
- Aggregator referral fees are basis points. `10_000n` is one hundred percent.
|
|
63
|
+
- LI.FI takes its fee as a decimal fraction (`0.001` is a tenth of a percent).
|
|
64
|
+
- Fees are on-chain settings. Read them. Do not hard-code them.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { loadBridgeFees } from '@gibs/bridge-sdk/chain-info'
|
|
68
|
+
import { Chains, pathway, Providers } from '@gibs/bridge-sdk/config'
|
|
69
|
+
import { amountAfterBridgeFee, bridgeCost } from '@gibs/bridge-sdk/settings'
|
|
70
|
+
import type { PublicClient } from 'viem'
|
|
71
|
+
|
|
72
|
+
declare const ethereumClient: PublicClient
|
|
73
|
+
declare const pulsechainClient: PublicClient
|
|
74
|
+
|
|
75
|
+
const route = pathway([Providers.PULSECHAIN, Chains.ETH, Chains.PLS], true)
|
|
76
|
+
if (route) {
|
|
77
|
+
const { feeF2H } = await loadBridgeFees({
|
|
78
|
+
pathway: route,
|
|
79
|
+
fromChainClient: ethereumClient,
|
|
80
|
+
toChainClient: pulsechainClient,
|
|
81
|
+
})
|
|
82
|
+
const amountToBridge = 1_000_000n
|
|
83
|
+
const cost = bridgeCost({ amountToBridge, bridgeFee: feeF2H })
|
|
84
|
+
const received = amountAfterBridgeFee({ amountToBridge, bridgeCost: cost })
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`loadBridgeFees` reads the default rate. It does not read per-token rates.
|
|
89
|
+
|
|
90
|
+
## Tokens that are not bridged yet
|
|
91
|
+
|
|
92
|
+
`tokenBridgeInfo` asks both mediators how a token maps across the bridge.
|
|
93
|
+
A `null` `assetOutAddress` is a normal answer. The token gets an address on
|
|
94
|
+
the far side when its first transfer arrives. Always check for `null`.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { tokenBridgeInfo } from '@gibs/bridge-sdk/chain-info'
|
|
98
|
+
import { Chains, Providers } from '@gibs/bridge-sdk/config'
|
|
99
|
+
import type { Token } from '@gibs/bridge-sdk/types'
|
|
100
|
+
import type { PublicClient } from 'viem'
|
|
101
|
+
|
|
102
|
+
declare const assetIn: Token
|
|
103
|
+
declare const ethereumClient: PublicClient
|
|
104
|
+
declare const pulsechainClient: PublicClient
|
|
105
|
+
|
|
106
|
+
const info = await tokenBridgeInfo({
|
|
107
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
108
|
+
assetIn,
|
|
109
|
+
isProd: true,
|
|
110
|
+
fromChainClient: ethereumClient,
|
|
111
|
+
toChainClient: pulsechainClient,
|
|
112
|
+
})
|
|
113
|
+
if (info && info.assetOutAddress === null) {
|
|
114
|
+
// Not bridged yet. Do not treat this as an error.
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Aggregator identity: pass your own
|
|
119
|
+
|
|
120
|
+
The package ships no API key. Pass your own.
|
|
121
|
+
|
|
122
|
+
- Relay: pass your own `apiKey` to `relayRequestHeaders`. Name your own `relayReferrer`. The package sends no referrer by default, because Relay rejects a referrer without a key.
|
|
123
|
+
- LI.FI: set your own `lifiIntegrator`. A positive `lifiFee` without your own integrator throws.
|
|
124
|
+
- NEAR Intents: no key is needed. Pass your own `userAgent` if you want one.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import {
|
|
128
|
+
buildLifiContractCallsRequest,
|
|
129
|
+
type ConsolidatedQuoteRequest,
|
|
130
|
+
} from '@gibs/bridge-sdk/consolidated-quote'
|
|
131
|
+
import { nearIntentsRequestHeaders } from '@gibs/bridge-sdk/near-intents'
|
|
132
|
+
import { buildRelayQuoteRequest, relayQuoteUrl, relayRequestHeaders } from '@gibs/bridge-sdk/relay-quote'
|
|
133
|
+
|
|
134
|
+
declare const baseRequest: ConsolidatedQuoteRequest
|
|
135
|
+
declare const myRelayApiKey: string
|
|
136
|
+
|
|
137
|
+
const request: ConsolidatedQuoteRequest = {
|
|
138
|
+
...baseRequest,
|
|
139
|
+
lifiIntegrator: 'your-app.example',
|
|
140
|
+
lifiFee: 0.001,
|
|
141
|
+
relayReferrer: 'your-app.example',
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const lifiBody = buildLifiContractCallsRequest(request)
|
|
145
|
+
const relayBody = buildRelayQuoteRequest(request)
|
|
146
|
+
if (relayBody) {
|
|
147
|
+
await fetch(relayQuoteUrl, {
|
|
148
|
+
method: 'POST',
|
|
149
|
+
body: JSON.stringify(relayBody),
|
|
150
|
+
headers: relayRequestHeaders(myRelayApiKey),
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const nearHeaders = nearIntentsRequestHeaders(undefined, { userAgent: 'your-app/1.0' })
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Nulls and throws
|
|
158
|
+
|
|
159
|
+
- A question the package cannot answer returns `null`, `undefined` or `false`.
|
|
160
|
+
- A caller mistake or a failed chain read throws.
|
|
161
|
+
- Every request builder returns `null` for a request its provider cannot express.
|
|
162
|
+
- Every response parser returns `null` for an unexpected response shape.
|
|
163
|
+
- Check each return value before you use it.
|
|
164
|
+
|
|
165
|
+
## Links
|
|
166
|
+
|
|
167
|
+
- [README](https://github.com/gibsfinance/bridge/blob/staging/packages/bridge-sdk/README.md): the full guide.
|
|
168
|
+
- [Gibs Finance llms.txt](https://next.gibs.finance/llms.txt): the whole platform.
|
|
169
|
+
- [@gibs/quotes](https://github.com/gibsfinance/bridge/blob/staging/packages/quotes/llms.txt): live multi-provider quotes.
|