@defuse-protocol/intents-sdk 0.14.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 +732 -0
- package/dist/index.cjs +2069 -0
- package/dist/index.d.cts +488 -0
- package/dist/index.d.ts +488 -0
- package/dist/index.js +2055 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2055 @@
|
|
|
1
|
+
// src/sdk.ts
|
|
2
|
+
import {
|
|
3
|
+
assert as assert11,
|
|
4
|
+
PUBLIC_NEAR_RPC_URLS,
|
|
5
|
+
RETRY_CONFIGS as RETRY_CONFIGS2,
|
|
6
|
+
configsByEnvironment as configsByEnvironment7,
|
|
7
|
+
nearFailoverRpcProvider,
|
|
8
|
+
solverRelay as solverRelay5
|
|
9
|
+
} from "@defuse-protocol/internal-utils";
|
|
10
|
+
import hotOmniSdk from "@hot-labs/omni-sdk";
|
|
11
|
+
import { stringify } from "viem";
|
|
12
|
+
|
|
13
|
+
// src/bridges/aurora-engine-bridge/aurora-engine-bridge.ts
|
|
14
|
+
import {
|
|
15
|
+
assert as assert2,
|
|
16
|
+
configsByEnvironment,
|
|
17
|
+
getNearNep141MinStorageBalance,
|
|
18
|
+
getNearNep141StorageBalance,
|
|
19
|
+
solverRelay,
|
|
20
|
+
utils as utils2
|
|
21
|
+
} from "@defuse-protocol/internal-utils";
|
|
22
|
+
|
|
23
|
+
// src/constants/route-enum.ts
|
|
24
|
+
var RouteEnum = {
|
|
25
|
+
HotBridge: "hot_bridge",
|
|
26
|
+
PoaBridge: "poa_bridge",
|
|
27
|
+
NearWithdrawal: "near_withdrawal",
|
|
28
|
+
VirtualChain: "virtual_chain",
|
|
29
|
+
InternalTransfer: "internal_transfer"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/bridges/aurora-engine-bridge/aurora-engine-bridge-constants.ts
|
|
33
|
+
var NEAR_NATIVE_ASSET_ID = "nep141:wrap.near";
|
|
34
|
+
|
|
35
|
+
// src/bridges/aurora-engine-bridge/aurora-engine-bridge-utils.ts
|
|
36
|
+
import { assert, utils } from "@defuse-protocol/internal-utils";
|
|
37
|
+
import { getAddress } from "viem";
|
|
38
|
+
function createWithdrawIntentPrimitive(params) {
|
|
39
|
+
const { contractId: tokenAccountId, standard } = utils.parseDefuseAssetId(
|
|
40
|
+
params.assetId
|
|
41
|
+
);
|
|
42
|
+
assert(standard === "nep141", "Only NEP-141 is supported");
|
|
43
|
+
if (params.proxyTokenContractId == null) {
|
|
44
|
+
return {
|
|
45
|
+
intent: "ft_withdraw",
|
|
46
|
+
token: tokenAccountId,
|
|
47
|
+
receiver_id: params.auroraEngineContractId,
|
|
48
|
+
amount: params.amount.toString(),
|
|
49
|
+
msg: makeAuroraEngineDepositMsg(params.destinationAddress),
|
|
50
|
+
storage_deposit: params.storageDeposit > 0n ? params.storageDeposit.toString() : null
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
intent: "ft_withdraw",
|
|
55
|
+
token: tokenAccountId,
|
|
56
|
+
receiver_id: params.proxyTokenContractId,
|
|
57
|
+
amount: params.amount.toString(),
|
|
58
|
+
msg: `${params.auroraEngineContractId}:${makeAuroraEngineDepositMsg(params.destinationAddress)}`,
|
|
59
|
+
storage_deposit: params.storageDeposit > 0n ? params.storageDeposit.toString() : null
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function makeAuroraEngineDepositMsg(recipientAddress) {
|
|
63
|
+
const parsedRecipientAddress = getAddress(recipientAddress);
|
|
64
|
+
return parsedRecipientAddress.slice(2).toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
function withdrawalParamsInvariant(params) {
|
|
67
|
+
assert(params.routeConfig != null, "Bridge config is required");
|
|
68
|
+
assert(
|
|
69
|
+
params.routeConfig.route === RouteEnum.VirtualChain,
|
|
70
|
+
"Bridge is not aurora_engine"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/bridges/aurora-engine-bridge/aurora-engine-bridge.ts
|
|
75
|
+
var AuroraEngineBridge = class {
|
|
76
|
+
constructor({
|
|
77
|
+
env,
|
|
78
|
+
nearProvider
|
|
79
|
+
}) {
|
|
80
|
+
this.env = env;
|
|
81
|
+
this.nearProvider = nearProvider;
|
|
82
|
+
}
|
|
83
|
+
is(routeConfig) {
|
|
84
|
+
return routeConfig.route === RouteEnum.VirtualChain;
|
|
85
|
+
}
|
|
86
|
+
supports(params) {
|
|
87
|
+
if ("routeConfig" in params && params.routeConfig != null) {
|
|
88
|
+
return this.is(params.routeConfig);
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
parseAssetId() {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
createWithdrawalIntents(args) {
|
|
96
|
+
withdrawalParamsInvariant(args.withdrawalParams);
|
|
97
|
+
const intents = [];
|
|
98
|
+
if (args.feeEstimation.quote != null) {
|
|
99
|
+
intents.push({
|
|
100
|
+
intent: "token_diff",
|
|
101
|
+
diff: {
|
|
102
|
+
[args.feeEstimation.quote.defuse_asset_identifier_in]: `-${args.feeEstimation.quote.amount_in}`,
|
|
103
|
+
[args.feeEstimation.quote.defuse_asset_identifier_out]: args.feeEstimation.quote.amount_out
|
|
104
|
+
},
|
|
105
|
+
referral: args.referral
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const intent = createWithdrawIntentPrimitive({
|
|
109
|
+
assetId: args.withdrawalParams.assetId,
|
|
110
|
+
auroraEngineContractId: args.withdrawalParams.routeConfig.auroraEngineContractId,
|
|
111
|
+
proxyTokenContractId: args.withdrawalParams.routeConfig.proxyTokenContractId,
|
|
112
|
+
destinationAddress: args.withdrawalParams.destinationAddress,
|
|
113
|
+
amount: args.withdrawalParams.amount,
|
|
114
|
+
storageDeposit: args.feeEstimation.quote ? BigInt(args.feeEstimation.quote.amount_out) : args.feeEstimation.amount
|
|
115
|
+
});
|
|
116
|
+
intents.push(intent);
|
|
117
|
+
return Promise.resolve(intents);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Aurora Engine bridge doesn't have withdrawal restrictions.
|
|
121
|
+
*/
|
|
122
|
+
async validateWithdrawal(_args) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
async estimateWithdrawalFee(args) {
|
|
126
|
+
withdrawalParamsInvariant(args.withdrawalParams);
|
|
127
|
+
const { contractId: tokenAccountId, standard } = utils2.parseDefuseAssetId(
|
|
128
|
+
args.withdrawalParams.assetId
|
|
129
|
+
);
|
|
130
|
+
assert2(standard === "nep141", "Only NEP-141 is supported");
|
|
131
|
+
const [minStorageBalance, userStorageBalance] = await Promise.all([
|
|
132
|
+
getNearNep141MinStorageBalance({
|
|
133
|
+
contractId: tokenAccountId,
|
|
134
|
+
nearProvider: this.nearProvider
|
|
135
|
+
}),
|
|
136
|
+
getNearNep141StorageBalance({
|
|
137
|
+
contractId: tokenAccountId,
|
|
138
|
+
accountId: args.withdrawalParams.routeConfig.auroraEngineContractId,
|
|
139
|
+
nearProvider: this.nearProvider
|
|
140
|
+
})
|
|
141
|
+
]);
|
|
142
|
+
if (minStorageBalance <= userStorageBalance) {
|
|
143
|
+
return {
|
|
144
|
+
amount: 0n,
|
|
145
|
+
quote: null
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const feeAssetId = NEAR_NATIVE_ASSET_ID;
|
|
149
|
+
const feeAmount = minStorageBalance - userStorageBalance;
|
|
150
|
+
const feeQuote = args.withdrawalParams.assetId === feeAssetId ? null : await solverRelay.getQuote({
|
|
151
|
+
quoteParams: {
|
|
152
|
+
defuse_asset_identifier_in: args.withdrawalParams.assetId,
|
|
153
|
+
defuse_asset_identifier_out: feeAssetId,
|
|
154
|
+
exact_amount_out: feeAmount.toString(),
|
|
155
|
+
wait_ms: args.quoteOptions?.waitMs
|
|
156
|
+
},
|
|
157
|
+
config: {
|
|
158
|
+
baseURL: configsByEnvironment[this.env].solverRelayBaseURL,
|
|
159
|
+
logBalanceSufficient: false,
|
|
160
|
+
logger: args.logger
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
amount: feeQuote ? BigInt(feeQuote.amount_in) : feeAmount,
|
|
165
|
+
quote: feeQuote
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async waitForWithdrawalCompletion(_args) {
|
|
169
|
+
return { hash: null };
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/bridges/direct-bridge/direct-bridge.ts
|
|
174
|
+
import {
|
|
175
|
+
assert as assert5,
|
|
176
|
+
configsByEnvironment as configsByEnvironment2,
|
|
177
|
+
getNearNep141MinStorageBalance as getNearNep141MinStorageBalance2,
|
|
178
|
+
getNearNep141StorageBalance as getNearNep141StorageBalance2,
|
|
179
|
+
solverRelay as solverRelay2,
|
|
180
|
+
utils as utils4
|
|
181
|
+
} from "@defuse-protocol/internal-utils";
|
|
182
|
+
|
|
183
|
+
// src/constants/bridge-name-enum.ts
|
|
184
|
+
var BridgeNameEnum = {
|
|
185
|
+
Hot: "hot",
|
|
186
|
+
Poa: "poa",
|
|
187
|
+
None: null
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// src/lib/caip2.ts
|
|
191
|
+
import { assert as assert3 } from "@defuse-protocol/internal-utils";
|
|
192
|
+
var Chains = {
|
|
193
|
+
Bitcoin: "bip122:000000000019d6689c085ae165831e93",
|
|
194
|
+
Ethereum: "eip155:1",
|
|
195
|
+
Base: "eip155:8453",
|
|
196
|
+
Arbitrum: "eip155:42161",
|
|
197
|
+
BNB: "eip155:56",
|
|
198
|
+
Polygon: "eip155:137",
|
|
199
|
+
Near: "near:mainnet",
|
|
200
|
+
Solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
201
|
+
Tron: "tron:27Lqcw",
|
|
202
|
+
Gnosis: "eip155:100",
|
|
203
|
+
XRPL: "xrpl:0",
|
|
204
|
+
Dogecoin: "bip122:1a91e3dace36e2be3bf030a65679fe82",
|
|
205
|
+
Zcash: "zcash:0",
|
|
206
|
+
Berachain: "eip155:80085",
|
|
207
|
+
TON: "tvm:-239",
|
|
208
|
+
Optimism: "eip155:10",
|
|
209
|
+
Avalanche: "eip155:43114",
|
|
210
|
+
Sui: "sui:mainnet",
|
|
211
|
+
Aptos: "aptos:mainnet",
|
|
212
|
+
Stellar: "stellar:pubnet",
|
|
213
|
+
Cardano: "cip34:1-764824073"
|
|
214
|
+
};
|
|
215
|
+
function getEIP155ChainId(chain) {
|
|
216
|
+
assert3(chain.startsWith("eip155:"), "Chain is not an EIP-155 chain");
|
|
217
|
+
const chainIdStr = chain.slice(7);
|
|
218
|
+
assert3(chainIdStr.length > 0, "Chain is not an EIP-155 chain");
|
|
219
|
+
const chainId = Number(chainIdStr);
|
|
220
|
+
assert3(!Number.isNaN(chainId), "Chain is not an EIP-155 chain");
|
|
221
|
+
return chainId;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/bridges/direct-bridge/direct-bridge-constants.ts
|
|
225
|
+
var NEAR_NATIVE_ASSET_ID2 = "nep141:wrap.near";
|
|
226
|
+
|
|
227
|
+
// src/bridges/direct-bridge/direct-bridge-utils.ts
|
|
228
|
+
import { assert as assert4, utils as utils3 } from "@defuse-protocol/internal-utils";
|
|
229
|
+
function createWithdrawIntentPrimitive2(params) {
|
|
230
|
+
if (params.assetId === NEAR_NATIVE_ASSET_ID2 && // Ensure `msg` is not passed, because `native_withdraw` intent doesn't support `msg`
|
|
231
|
+
params.msg === void 0) {
|
|
232
|
+
return {
|
|
233
|
+
intent: "native_withdraw",
|
|
234
|
+
receiver_id: params.destinationAddress,
|
|
235
|
+
amount: params.amount.toString()
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const { contractId: tokenAccountId, standard } = utils3.parseDefuseAssetId(
|
|
239
|
+
params.assetId
|
|
240
|
+
);
|
|
241
|
+
assert4(standard === "nep141", "Only NEP-141 is supported");
|
|
242
|
+
return {
|
|
243
|
+
intent: "ft_withdraw",
|
|
244
|
+
token: tokenAccountId,
|
|
245
|
+
receiver_id: params.destinationAddress,
|
|
246
|
+
amount: params.amount.toString(),
|
|
247
|
+
storage_deposit: params.storageDeposit > 0n ? params.storageDeposit.toString() : null,
|
|
248
|
+
msg: params.msg
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function withdrawalParamsInvariant2(params) {
|
|
252
|
+
assert4(
|
|
253
|
+
!params.routeConfig ? true : params.routeConfig.route === RouteEnum.NearWithdrawal,
|
|
254
|
+
"Bridge is not direct"
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/bridges/direct-bridge/direct-bridge.ts
|
|
259
|
+
var DirectBridge = class {
|
|
260
|
+
constructor({
|
|
261
|
+
env,
|
|
262
|
+
nearProvider
|
|
263
|
+
}) {
|
|
264
|
+
this.env = env;
|
|
265
|
+
this.nearProvider = nearProvider;
|
|
266
|
+
}
|
|
267
|
+
is(routeConfig) {
|
|
268
|
+
return routeConfig.route === RouteEnum.NearWithdrawal;
|
|
269
|
+
}
|
|
270
|
+
supports(params) {
|
|
271
|
+
let result = true;
|
|
272
|
+
if ("routeConfig" in params && params.routeConfig != null) {
|
|
273
|
+
result && (result = this.is(params.routeConfig));
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
return result && this.parseAssetId(params.assetId) != null;
|
|
277
|
+
} catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
parseAssetId(assetId) {
|
|
282
|
+
const parsed = utils4.parseDefuseAssetId(assetId);
|
|
283
|
+
if (parsed.standard === "nep141") {
|
|
284
|
+
return Object.assign(parsed, {
|
|
285
|
+
blockchain: Chains.Near,
|
|
286
|
+
bridgeName: BridgeNameEnum.None,
|
|
287
|
+
address: parsed.contractId
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
createWithdrawalIntents(args) {
|
|
293
|
+
withdrawalParamsInvariant2(args.withdrawalParams);
|
|
294
|
+
const intents = [];
|
|
295
|
+
if (args.feeEstimation.quote != null) {
|
|
296
|
+
intents.push({
|
|
297
|
+
intent: "token_diff",
|
|
298
|
+
diff: {
|
|
299
|
+
[args.feeEstimation.quote.defuse_asset_identifier_in]: `-${args.feeEstimation.quote.amount_in}`,
|
|
300
|
+
[args.feeEstimation.quote.defuse_asset_identifier_out]: args.feeEstimation.quote.amount_out
|
|
301
|
+
},
|
|
302
|
+
referral: args.referral
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
const intent = createWithdrawIntentPrimitive2({
|
|
306
|
+
assetId: args.withdrawalParams.assetId,
|
|
307
|
+
destinationAddress: args.withdrawalParams.destinationAddress,
|
|
308
|
+
amount: args.withdrawalParams.amount,
|
|
309
|
+
storageDeposit: args.feeEstimation.quote ? BigInt(args.feeEstimation.quote.amount_out) : args.feeEstimation.amount,
|
|
310
|
+
msg: args.withdrawalParams.routeConfig?.msg
|
|
311
|
+
});
|
|
312
|
+
intents.push(intent);
|
|
313
|
+
return Promise.resolve(intents);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Direct bridge doesn't have withdrawal restrictions.
|
|
317
|
+
*/
|
|
318
|
+
async validateWithdrawal(_args) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
async estimateWithdrawalFee(args) {
|
|
322
|
+
withdrawalParamsInvariant2(args.withdrawalParams);
|
|
323
|
+
const { contractId: tokenAccountId, standard } = utils4.parseDefuseAssetId(
|
|
324
|
+
args.withdrawalParams.assetId
|
|
325
|
+
);
|
|
326
|
+
assert5(standard === "nep141", "Only NEP-141 is supported");
|
|
327
|
+
if (
|
|
328
|
+
// We don't directly withdraw `wrap.near`, we unwrap it first, so it doesn't require storage
|
|
329
|
+
args.withdrawalParams.assetId === NEAR_NATIVE_ASSET_ID2 && // Ensure `msg` is not passed, because `native_withdraw` intent doesn't support `msg`
|
|
330
|
+
args.withdrawalParams.routeConfig?.msg === void 0
|
|
331
|
+
)
|
|
332
|
+
return {
|
|
333
|
+
amount: 0n,
|
|
334
|
+
quote: null
|
|
335
|
+
};
|
|
336
|
+
const [minStorageBalance, userStorageBalance] = await Promise.all([
|
|
337
|
+
getNearNep141MinStorageBalance2({
|
|
338
|
+
contractId: tokenAccountId,
|
|
339
|
+
nearProvider: this.nearProvider
|
|
340
|
+
}),
|
|
341
|
+
getNearNep141StorageBalance2({
|
|
342
|
+
contractId: tokenAccountId,
|
|
343
|
+
accountId: args.withdrawalParams.destinationAddress,
|
|
344
|
+
nearProvider: this.nearProvider
|
|
345
|
+
})
|
|
346
|
+
]);
|
|
347
|
+
if (minStorageBalance <= userStorageBalance) {
|
|
348
|
+
return {
|
|
349
|
+
amount: 0n,
|
|
350
|
+
quote: null
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const feeAssetId = NEAR_NATIVE_ASSET_ID2;
|
|
354
|
+
const feeAmount = minStorageBalance - userStorageBalance;
|
|
355
|
+
const feeQuote = args.withdrawalParams.assetId === feeAssetId ? null : await solverRelay2.getQuote({
|
|
356
|
+
quoteParams: {
|
|
357
|
+
defuse_asset_identifier_in: args.withdrawalParams.assetId,
|
|
358
|
+
defuse_asset_identifier_out: feeAssetId,
|
|
359
|
+
exact_amount_out: feeAmount.toString(),
|
|
360
|
+
wait_ms: args.quoteOptions?.waitMs
|
|
361
|
+
},
|
|
362
|
+
config: {
|
|
363
|
+
baseURL: configsByEnvironment2[this.env].solverRelayBaseURL,
|
|
364
|
+
logBalanceSufficient: false,
|
|
365
|
+
logger: args.logger
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
return {
|
|
369
|
+
amount: feeQuote ? BigInt(feeQuote.amount_in) : feeAmount,
|
|
370
|
+
quote: feeQuote
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
async waitForWithdrawalCompletion(args) {
|
|
374
|
+
return { hash: args.tx.hash };
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// src/bridges/hot-bridge/hot-bridge.ts
|
|
379
|
+
import {
|
|
380
|
+
assert as assert7,
|
|
381
|
+
RETRY_CONFIGS,
|
|
382
|
+
configsByEnvironment as configsByEnvironment3,
|
|
383
|
+
utils as internalUtils,
|
|
384
|
+
solverRelay as solverRelay3
|
|
385
|
+
} from "@defuse-protocol/internal-utils";
|
|
386
|
+
import { utils as utils5 } from "@hot-labs/omni-sdk";
|
|
387
|
+
import { retry } from "@lifeomic/attempt";
|
|
388
|
+
|
|
389
|
+
// src/classes/errors.ts
|
|
390
|
+
import { BaseError } from "@defuse-protocol/internal-utils";
|
|
391
|
+
var FeeExceedsAmountError = class extends BaseError {
|
|
392
|
+
constructor(feeEstimation, amount) {
|
|
393
|
+
super("Amount too small to pay fee.", {
|
|
394
|
+
metaMessages: [
|
|
395
|
+
`Required fee: ${feeEstimation.amount}`,
|
|
396
|
+
`Withdrawal amount: ${amount}`
|
|
397
|
+
],
|
|
398
|
+
name: "FeeExceedsAmountError"
|
|
399
|
+
});
|
|
400
|
+
this.feeEstimation = feeEstimation;
|
|
401
|
+
this.amount = amount;
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var MinWithdrawalAmountError = class extends BaseError {
|
|
405
|
+
constructor(minAmount, requestedAmount, assetId) {
|
|
406
|
+
super("Withdrawal amount is below minimum required by the bridge.", {
|
|
407
|
+
metaMessages: [
|
|
408
|
+
`Asset ID: ${assetId}`,
|
|
409
|
+
`Minimum amount: ${minAmount}`,
|
|
410
|
+
`Requested amount: ${requestedAmount}`
|
|
411
|
+
],
|
|
412
|
+
name: "MinWithdrawalAmountError"
|
|
413
|
+
});
|
|
414
|
+
this.minAmount = minAmount;
|
|
415
|
+
this.requestedAmount = requestedAmount;
|
|
416
|
+
this.assetId = assetId;
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
var UnsupportedDestinationMemoError = class extends BaseError {
|
|
420
|
+
constructor(blockchain, assetId) {
|
|
421
|
+
super("Destination memo is not supported for this blockchain.", {
|
|
422
|
+
details: "Destination memo is only supported for XRP Ledger withdrawals.",
|
|
423
|
+
metaMessages: [`Blockchain: ${blockchain}`, `Asset ID: ${assetId}`],
|
|
424
|
+
name: "UnsupportedDestinationMemoError"
|
|
425
|
+
});
|
|
426
|
+
this.blockchain = blockchain;
|
|
427
|
+
this.assetId = assetId;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
var TrustlineNotFoundError = class extends BaseError {
|
|
431
|
+
constructor(destinationAddress, assetId, blockchain, tokenAddress) {
|
|
432
|
+
super("Destination address does not have a trustline for this asset.", {
|
|
433
|
+
details: "The destination address must establish a trustline before receiving this asset.",
|
|
434
|
+
metaMessages: [
|
|
435
|
+
`Blockchain: ${blockchain}`,
|
|
436
|
+
`Asset ID: ${assetId}`,
|
|
437
|
+
`Destination address: ${destinationAddress}`,
|
|
438
|
+
`Token address: ${tokenAddress}`
|
|
439
|
+
],
|
|
440
|
+
name: "TrustlineNotFoundError"
|
|
441
|
+
});
|
|
442
|
+
this.destinationAddress = destinationAddress;
|
|
443
|
+
this.assetId = assetId;
|
|
444
|
+
this.blockchain = blockchain;
|
|
445
|
+
this.tokenAddress = tokenAddress;
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// src/bridges/hot-bridge/error.ts
|
|
450
|
+
import { BaseError as BaseError2 } from "@defuse-protocol/internal-utils";
|
|
451
|
+
var HotWithdrawalPendingError = class extends BaseError2 {
|
|
452
|
+
constructor(txHash, index) {
|
|
453
|
+
super("Withdrawal is still pending.", {
|
|
454
|
+
metaMessages: [`TxHash: ${txHash}`, `Index: ${index}`],
|
|
455
|
+
name: "HotWithdrawalPendingError"
|
|
456
|
+
});
|
|
457
|
+
this.txHash = txHash;
|
|
458
|
+
this.index = index;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
var HotWithdrawalNotFoundError = class extends BaseError2 {
|
|
462
|
+
constructor(txHash, index) {
|
|
463
|
+
super("Withdrawal with given index is not found.", {
|
|
464
|
+
metaMessages: [`TxHash: ${txHash}`, `Index: ${index}`],
|
|
465
|
+
name: "HotWithdrawalNotFoundError"
|
|
466
|
+
});
|
|
467
|
+
this.txHash = txHash;
|
|
468
|
+
this.index = index;
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
var HotWithdrawalCancelledError = class extends BaseError2 {
|
|
472
|
+
constructor(txHash, index) {
|
|
473
|
+
super("Gasless withdrawal was canceled.", {
|
|
474
|
+
metaMessages: [`TxHash: ${txHash}`, `Index: ${index}`],
|
|
475
|
+
name: "HotWithdrawalCancelledError"
|
|
476
|
+
});
|
|
477
|
+
this.txHash = txHash;
|
|
478
|
+
this.index = index;
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// src/bridges/hot-bridge/hot-bridge-constants.ts
|
|
483
|
+
var HotWithdrawStatus = {
|
|
484
|
+
Completed: "COMPLETED",
|
|
485
|
+
Canceled: "CANCELED"
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// src/bridges/hot-bridge/hot-bridge-utils.ts
|
|
489
|
+
import { assert as assert6 } from "@defuse-protocol/internal-utils";
|
|
490
|
+
import { Network } from "@hot-labs/omni-sdk";
|
|
491
|
+
|
|
492
|
+
// src/bridges/hot-bridge/hot-bridge-chains.ts
|
|
493
|
+
var HotBridgeChains = [
|
|
494
|
+
Chains.Polygon,
|
|
495
|
+
Chains.BNB,
|
|
496
|
+
Chains.TON,
|
|
497
|
+
Chains.Optimism,
|
|
498
|
+
Chains.Avalanche,
|
|
499
|
+
Chains.Stellar
|
|
500
|
+
];
|
|
501
|
+
var HotBridgeEVMChains = HotBridgeChains.filter((a) => a.startsWith("eip155:"));
|
|
502
|
+
|
|
503
|
+
// src/bridges/hot-bridge/hot-bridge-utils.ts
|
|
504
|
+
var nativeTokenMapping = {
|
|
505
|
+
[Chains.BNB]: "nep245:v2_1.omni.hot.tg:56_11111111111111111111",
|
|
506
|
+
[Chains.Polygon]: "nep245:v2_1.omni.hot.tg:137_11111111111111111111",
|
|
507
|
+
[Chains.TON]: "nep245:v2_1.omni.hot.tg:1117_",
|
|
508
|
+
[Chains.Optimism]: "nep245:v2_1.omni.hot.tg:10_11111111111111111111",
|
|
509
|
+
[Chains.Avalanche]: "nep245:v2_1.omni.hot.tg:43114_11111111111111111111",
|
|
510
|
+
[Chains.Stellar]: "nep245:v2_1.omni.hot.tg:1100_111bzQBB5v7AhLyPMDwS8uJgQV24KaAPXtwyVWu2KXbbfQU6NXRCz"
|
|
511
|
+
};
|
|
512
|
+
var caip2NetworkIdMapping = {
|
|
513
|
+
[Chains.BNB]: Network.Bnb,
|
|
514
|
+
[Chains.Polygon]: Network.Polygon,
|
|
515
|
+
[Chains.TON]: Network.Ton,
|
|
516
|
+
[Chains.Optimism]: Network.Optimism,
|
|
517
|
+
[Chains.Avalanche]: Network.Avalanche,
|
|
518
|
+
[Chains.Stellar]: Network.Stellar
|
|
519
|
+
};
|
|
520
|
+
var networkIdCAIP2Mapping = Object.fromEntries(
|
|
521
|
+
Object.entries(caip2NetworkIdMapping).map(([k, v]) => [v, k])
|
|
522
|
+
);
|
|
523
|
+
function getFeeAssetIdForChain(caip2) {
|
|
524
|
+
return nativeTokenMapping[caip2];
|
|
525
|
+
}
|
|
526
|
+
function toHotNetworkId(caip2) {
|
|
527
|
+
hotBlockchainInvariant(caip2);
|
|
528
|
+
return caip2NetworkIdMapping[caip2];
|
|
529
|
+
}
|
|
530
|
+
function hotNetworkIdToCAIP2(network) {
|
|
531
|
+
if (networkIdCAIP2Mapping[network] != null) {
|
|
532
|
+
return networkIdCAIP2Mapping[network];
|
|
533
|
+
}
|
|
534
|
+
throw new Error(`Unsupported HOT Bridge chain = ${network}`);
|
|
535
|
+
}
|
|
536
|
+
function formatTxHash(txHash, caip2) {
|
|
537
|
+
if (caip2.startsWith("eip155:")) {
|
|
538
|
+
return `0x${txHash}`;
|
|
539
|
+
}
|
|
540
|
+
return txHash;
|
|
541
|
+
}
|
|
542
|
+
function hotBlockchainInvariant(blockchain) {
|
|
543
|
+
assert6(
|
|
544
|
+
HotBridgeChains.includes(blockchain),
|
|
545
|
+
`${blockchain} is not a valid HOT Bridge blockchain. Supported values: ${HotBridgeChains.join()}`
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// src/bridges/hot-bridge/hot-bridge.ts
|
|
550
|
+
var HotBridge = class {
|
|
551
|
+
constructor({ env, hotSdk }) {
|
|
552
|
+
this.env = env;
|
|
553
|
+
this.hotSdk = hotSdk;
|
|
554
|
+
}
|
|
555
|
+
is(routeConfig) {
|
|
556
|
+
return routeConfig.route === RouteEnum.HotBridge;
|
|
557
|
+
}
|
|
558
|
+
supports(params) {
|
|
559
|
+
let result = true;
|
|
560
|
+
if ("routeConfig" in params && params.routeConfig != null) {
|
|
561
|
+
result && (result = this.is(params.routeConfig));
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
return result && this.parseAssetId(params.assetId) != null;
|
|
565
|
+
} catch {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
parseAssetId(assetId) {
|
|
570
|
+
const parsed = internalUtils.parseDefuseAssetId(assetId);
|
|
571
|
+
if (parsed.contractId === utils5.OMNI_HOT_V2) {
|
|
572
|
+
assert7(
|
|
573
|
+
parsed.standard === "nep245",
|
|
574
|
+
"NEP-245 is supported only for HOT bridge"
|
|
575
|
+
);
|
|
576
|
+
const [chainId, address] = utils5.fromOmni(parsed.tokenId).split(":");
|
|
577
|
+
assert7(chainId != null, "Chain ID is not found");
|
|
578
|
+
assert7(address != null, "Address is not found");
|
|
579
|
+
return Object.assign(
|
|
580
|
+
parsed,
|
|
581
|
+
{
|
|
582
|
+
blockchain: hotNetworkIdToCAIP2(chainId),
|
|
583
|
+
bridgeName: BridgeNameEnum.Hot
|
|
584
|
+
},
|
|
585
|
+
address === "native" ? { native: true } : { address }
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
async createWithdrawalIntents(args) {
|
|
591
|
+
const assetInfo = this.parseAssetId(args.withdrawalParams.assetId);
|
|
592
|
+
assert7(assetInfo != null, "Asset is not supported");
|
|
593
|
+
if (args.withdrawalParams.destinationMemo != null && args.withdrawalParams.destinationMemo !== "") {
|
|
594
|
+
throw new UnsupportedDestinationMemoError(
|
|
595
|
+
assetInfo.blockchain,
|
|
596
|
+
args.withdrawalParams.assetId
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
const intents = [];
|
|
600
|
+
let feeAmount;
|
|
601
|
+
if (args.feeEstimation.quote == null) {
|
|
602
|
+
feeAmount = args.feeEstimation.amount;
|
|
603
|
+
} else {
|
|
604
|
+
feeAmount = BigInt(args.feeEstimation.quote.amount_out);
|
|
605
|
+
intents.push({
|
|
606
|
+
intent: "token_diff",
|
|
607
|
+
diff: {
|
|
608
|
+
[args.feeEstimation.quote.defuse_asset_identifier_in]: `-${args.feeEstimation.quote.amount_in}`,
|
|
609
|
+
[args.feeEstimation.quote.defuse_asset_identifier_out]: args.feeEstimation.quote.amount_out
|
|
610
|
+
},
|
|
611
|
+
referral: args.referral
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
const isNative = "native" in assetInfo;
|
|
615
|
+
const amount = args.withdrawalParams.amount + (isNative ? feeAmount : 0n);
|
|
616
|
+
const intent = await this.hotSdk.buildGaslessWithdrawIntent({
|
|
617
|
+
feeToken: "native",
|
|
618
|
+
feeAmount,
|
|
619
|
+
chain: toHotNetworkId(assetInfo.blockchain),
|
|
620
|
+
token: isNative ? "native" : assetInfo.address,
|
|
621
|
+
amount,
|
|
622
|
+
receiver: args.withdrawalParams.destinationAddress,
|
|
623
|
+
intentAccount: ""
|
|
624
|
+
// it is not used inside the function
|
|
625
|
+
});
|
|
626
|
+
assert7(intent.amounts[0] === amount.toString(), "Amount is not correct");
|
|
627
|
+
if (intent.amounts.length === 2) {
|
|
628
|
+
assert7(
|
|
629
|
+
intent.amounts[1] === feeAmount.toString(),
|
|
630
|
+
"Amount is not correct"
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
intents.push(intent);
|
|
634
|
+
return intents;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Hot bridge validates trustlines for Stellar addresses.
|
|
638
|
+
* For Stellar chains, checks if the destination address has the required trustline.
|
|
639
|
+
* @throws {TrustlineNotFoundError} If Stellar destination address lacks required trustline
|
|
640
|
+
*/
|
|
641
|
+
async validateWithdrawal(args) {
|
|
642
|
+
const assetInfo = this.parseAssetId(args.assetId);
|
|
643
|
+
assert7(assetInfo != null, "Asset is not supported");
|
|
644
|
+
hotBlockchainInvariant(assetInfo.blockchain);
|
|
645
|
+
if (assetInfo.blockchain === Chains.Stellar) {
|
|
646
|
+
const token = "native" in assetInfo ? "native" : assetInfo.address;
|
|
647
|
+
const hasTrustline = await this.hotSdk.stellar.isTrustlineExists(
|
|
648
|
+
args.destinationAddress,
|
|
649
|
+
token
|
|
650
|
+
);
|
|
651
|
+
if (!hasTrustline) {
|
|
652
|
+
throw new TrustlineNotFoundError(
|
|
653
|
+
args.destinationAddress,
|
|
654
|
+
args.assetId,
|
|
655
|
+
assetInfo.blockchain,
|
|
656
|
+
token
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async estimateWithdrawalFee(args) {
|
|
662
|
+
const assetInfo = this.parseAssetId(args.withdrawalParams.assetId);
|
|
663
|
+
assert7(assetInfo != null, "Asset is not supported");
|
|
664
|
+
hotBlockchainInvariant(assetInfo.blockchain);
|
|
665
|
+
const { gasPrice: feeAmount } = await this.hotSdk.getGaslessWithdrawFee(
|
|
666
|
+
toHotNetworkId(assetInfo.blockchain),
|
|
667
|
+
args.withdrawalParams.destinationAddress
|
|
668
|
+
);
|
|
669
|
+
const feeAssetId = getFeeAssetIdForChain(assetInfo.blockchain);
|
|
670
|
+
const feeQuote = args.withdrawalParams.assetId === feeAssetId || feeAmount === 0n ? null : await solverRelay3.getQuote({
|
|
671
|
+
quoteParams: {
|
|
672
|
+
defuse_asset_identifier_in: args.withdrawalParams.assetId,
|
|
673
|
+
defuse_asset_identifier_out: feeAssetId,
|
|
674
|
+
exact_amount_out: feeAmount.toString(),
|
|
675
|
+
wait_ms: args.quoteOptions?.waitMs
|
|
676
|
+
},
|
|
677
|
+
config: {
|
|
678
|
+
baseURL: configsByEnvironment3[this.env].solverRelayBaseURL,
|
|
679
|
+
logBalanceSufficient: false,
|
|
680
|
+
logger: args.logger
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
return {
|
|
684
|
+
amount: feeQuote ? BigInt(feeQuote.amount_in) : feeAmount,
|
|
685
|
+
quote: feeQuote
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
async waitForWithdrawalCompletion(args) {
|
|
689
|
+
const nonces = await this.hotSdk.near.parseWithdrawalNonces(
|
|
690
|
+
args.tx.hash,
|
|
691
|
+
args.tx.accountId
|
|
692
|
+
);
|
|
693
|
+
const nonce = nonces[args.index];
|
|
694
|
+
if (nonce == null) {
|
|
695
|
+
throw new HotWithdrawalNotFoundError(args.tx.hash, args.index);
|
|
696
|
+
}
|
|
697
|
+
return retry(
|
|
698
|
+
async () => {
|
|
699
|
+
if (args.signal?.aborted) {
|
|
700
|
+
throw args.signal.reason;
|
|
701
|
+
}
|
|
702
|
+
const status = await this.hotSdk.getGaslessWithdrawStatus(
|
|
703
|
+
nonce.toString()
|
|
704
|
+
);
|
|
705
|
+
if (status === HotWithdrawStatus.Canceled) {
|
|
706
|
+
throw new HotWithdrawalCancelledError(args.tx.hash, args.index);
|
|
707
|
+
}
|
|
708
|
+
if (status === HotWithdrawStatus.Completed) {
|
|
709
|
+
return { hash: null };
|
|
710
|
+
}
|
|
711
|
+
if (typeof status === "string") {
|
|
712
|
+
return {
|
|
713
|
+
hash: "chain" in args.routeConfig ? formatTxHash(status, args.routeConfig.chain) : status
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
throw new HotWithdrawalPendingError(args.tx.hash, args.index);
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
...args.retryOptions ?? RETRY_CONFIGS.TWO_MINS_GRADUAL,
|
|
720
|
+
handleError: (err, ctx) => {
|
|
721
|
+
if (err instanceof HotWithdrawalCancelledError || err === args.signal?.reason) {
|
|
722
|
+
ctx.abort();
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
// src/bridges/intents-bridge/intents-bridge.ts
|
|
731
|
+
var IntentsBridge = class {
|
|
732
|
+
is(routeConfig) {
|
|
733
|
+
return routeConfig.route === RouteEnum.InternalTransfer;
|
|
734
|
+
}
|
|
735
|
+
supports(params) {
|
|
736
|
+
if ("routeConfig" in params && params.routeConfig != null) {
|
|
737
|
+
return this.is(params.routeConfig);
|
|
738
|
+
}
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
parseAssetId() {
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
createWithdrawalIntents(args) {
|
|
745
|
+
const intents = [
|
|
746
|
+
{
|
|
747
|
+
intent: "transfer",
|
|
748
|
+
receiver_id: args.withdrawalParams.destinationAddress,
|
|
749
|
+
tokens: {
|
|
750
|
+
[args.withdrawalParams.assetId]: args.withdrawalParams.amount.toString()
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
];
|
|
754
|
+
return Promise.resolve(intents);
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Intents bridge doesn't have withdrawal restrictions.
|
|
758
|
+
*/
|
|
759
|
+
async validateWithdrawal(_args) {
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
async estimateWithdrawalFee() {
|
|
763
|
+
return {
|
|
764
|
+
amount: 0n,
|
|
765
|
+
quote: null
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
async waitForWithdrawalCompletion(args) {
|
|
769
|
+
return { hash: args.tx.hash };
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// src/bridges/poa-bridge/poa-bridge.ts
|
|
774
|
+
import {
|
|
775
|
+
assert as assert8,
|
|
776
|
+
configsByEnvironment as configsByEnvironment4,
|
|
777
|
+
poaBridge,
|
|
778
|
+
utils as utils7
|
|
779
|
+
} from "@defuse-protocol/internal-utils";
|
|
780
|
+
import TTLCache from "@isaacs/ttlcache";
|
|
781
|
+
|
|
782
|
+
// src/bridges/poa-bridge/poa-bridge-utils.ts
|
|
783
|
+
import { utils as utils6 } from "@defuse-protocol/internal-utils";
|
|
784
|
+
function createWithdrawIntentPrimitive3(params) {
|
|
785
|
+
const { contractId: tokenAccountId } = utils6.parseDefuseAssetId(
|
|
786
|
+
params.assetId
|
|
787
|
+
);
|
|
788
|
+
return {
|
|
789
|
+
intent: "ft_withdraw",
|
|
790
|
+
token: tokenAccountId,
|
|
791
|
+
receiver_id: tokenAccountId,
|
|
792
|
+
amount: params.amount.toString(),
|
|
793
|
+
memo: createWithdrawMemo({
|
|
794
|
+
receiverAddress: params.destinationAddress,
|
|
795
|
+
xrpMemo: params.destinationMemo
|
|
796
|
+
})
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
function createWithdrawMemo({
|
|
800
|
+
receiverAddress,
|
|
801
|
+
xrpMemo
|
|
802
|
+
}) {
|
|
803
|
+
const memo = ["WITHDRAW_TO", receiverAddress];
|
|
804
|
+
if (xrpMemo != null && xrpMemo !== "") {
|
|
805
|
+
memo.push(xrpMemo);
|
|
806
|
+
}
|
|
807
|
+
return memo.join(":");
|
|
808
|
+
}
|
|
809
|
+
var caip2Mapping = {
|
|
810
|
+
[Chains.Ethereum]: "eth:1",
|
|
811
|
+
[Chains.Base]: "eth:8453",
|
|
812
|
+
[Chains.Arbitrum]: "eth:42161",
|
|
813
|
+
[Chains.Bitcoin]: "btc:mainnet",
|
|
814
|
+
[Chains.Solana]: "sol:mainnet",
|
|
815
|
+
[Chains.Dogecoin]: "doge:mainnet",
|
|
816
|
+
[Chains.XRPL]: "xrp:mainnet",
|
|
817
|
+
[Chains.Zcash]: "zec:mainnet",
|
|
818
|
+
[Chains.Gnosis]: "eth:100",
|
|
819
|
+
[Chains.Berachain]: "eth:80094",
|
|
820
|
+
[Chains.Tron]: "tron:mainnet",
|
|
821
|
+
[Chains.Sui]: "sui:mainnet",
|
|
822
|
+
[Chains.Aptos]: "aptos:mainnet",
|
|
823
|
+
[Chains.Cardano]: "cardano:mainnet"
|
|
824
|
+
};
|
|
825
|
+
function toPoaNetwork(caip2) {
|
|
826
|
+
if (caip2Mapping[caip2] == null) {
|
|
827
|
+
throw new Error(`Unsupported POA Bridge chain = ${caip2}`);
|
|
828
|
+
}
|
|
829
|
+
return caip2Mapping[caip2];
|
|
830
|
+
}
|
|
831
|
+
var tokenPrefixMapping = {
|
|
832
|
+
eth: Chains.Ethereum,
|
|
833
|
+
base: Chains.Base,
|
|
834
|
+
arb: Chains.Arbitrum,
|
|
835
|
+
btc: Chains.Bitcoin,
|
|
836
|
+
sol: Chains.Solana,
|
|
837
|
+
doge: Chains.Dogecoin,
|
|
838
|
+
xrp: Chains.XRPL,
|
|
839
|
+
zec: Chains.Zcash,
|
|
840
|
+
gnosis: Chains.Gnosis,
|
|
841
|
+
bera: Chains.Berachain,
|
|
842
|
+
tron: Chains.Tron,
|
|
843
|
+
sui: Chains.Sui,
|
|
844
|
+
aptos: Chains.Aptos,
|
|
845
|
+
cardano: Chains.Cardano
|
|
846
|
+
};
|
|
847
|
+
function contractIdToCaip2(contractId) {
|
|
848
|
+
for (const [prefix, caip2] of Object.entries(tokenPrefixMapping)) {
|
|
849
|
+
if (contractId.startsWith(`${prefix}.`) || contractId.startsWith(`${prefix}-`)) {
|
|
850
|
+
return caip2;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
throw new Error(`Unsupported POA Bridge contractId = ${contractId}`);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/bridges/poa-bridge/poa-bridge.ts
|
|
857
|
+
var PoaBridge = class {
|
|
858
|
+
constructor({ env }) {
|
|
859
|
+
// TTL cache for supported tokens with 30-second TTL
|
|
860
|
+
this.supportedTokensCache = new TTLCache({ ttl: 30 * 1e3 });
|
|
861
|
+
this.env = env;
|
|
862
|
+
}
|
|
863
|
+
is(routeConfig) {
|
|
864
|
+
return routeConfig.route === RouteEnum.PoaBridge;
|
|
865
|
+
}
|
|
866
|
+
supports(params) {
|
|
867
|
+
let result = true;
|
|
868
|
+
if ("routeConfig" in params && params.routeConfig != null) {
|
|
869
|
+
result && (result = this.is(params.routeConfig));
|
|
870
|
+
}
|
|
871
|
+
try {
|
|
872
|
+
return result && this.parseAssetId(params.assetId) != null;
|
|
873
|
+
} catch {
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
parseAssetId(assetId) {
|
|
878
|
+
const parsed = utils7.parseDefuseAssetId(assetId);
|
|
879
|
+
if (parsed.contractId.endsWith(
|
|
880
|
+
`.${configsByEnvironment4[this.env].poaTokenFactoryContractID}`
|
|
881
|
+
)) {
|
|
882
|
+
return Object.assign(parsed, {
|
|
883
|
+
blockchain: contractIdToCaip2(parsed.contractId),
|
|
884
|
+
bridgeName: BridgeNameEnum.Poa,
|
|
885
|
+
address: ""
|
|
886
|
+
// todo: derive address (or native)
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
createWithdrawalIntents(args) {
|
|
892
|
+
const intent = createWithdrawIntentPrimitive3({
|
|
893
|
+
...args.withdrawalParams,
|
|
894
|
+
amount: args.withdrawalParams.amount + args.feeEstimation.amount,
|
|
895
|
+
destinationMemo: args.withdrawalParams.destinationMemo
|
|
896
|
+
});
|
|
897
|
+
return Promise.resolve([intent]);
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Validates minimum withdrawal amount for POA bridge tokens.
|
|
901
|
+
* Checks the bridge's supported tokens API to ensure the withdrawal amount
|
|
902
|
+
* meets the minimum required amount for the specific token and blockchain.
|
|
903
|
+
* @throws {MinWithdrawalAmountError} If the amount is below the minimum required
|
|
904
|
+
*/
|
|
905
|
+
async validateWithdrawal(args) {
|
|
906
|
+
const assetInfo = this.parseAssetId(args.assetId);
|
|
907
|
+
assert8(assetInfo != null, "Asset is not supported");
|
|
908
|
+
const { tokens } = await this.getCachedSupportedTokens(
|
|
909
|
+
[toPoaNetwork(assetInfo.blockchain)],
|
|
910
|
+
args.logger
|
|
911
|
+
);
|
|
912
|
+
const tokenInfo = tokens.find(
|
|
913
|
+
(token) => token.intents_token_id === args.assetId
|
|
914
|
+
);
|
|
915
|
+
if (tokenInfo != null) {
|
|
916
|
+
const minWithdrawalAmount = BigInt(tokenInfo.min_withdrawal_amount);
|
|
917
|
+
if (args.amount < minWithdrawalAmount) {
|
|
918
|
+
throw new MinWithdrawalAmountError(
|
|
919
|
+
minWithdrawalAmount,
|
|
920
|
+
args.amount,
|
|
921
|
+
args.assetId
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
async estimateWithdrawalFee(args) {
|
|
927
|
+
const assetInfo = this.parseAssetId(args.withdrawalParams.assetId);
|
|
928
|
+
assert8(assetInfo != null, "Asset is not supported");
|
|
929
|
+
const estimation = await poaBridge.httpClient.getWithdrawalEstimate(
|
|
930
|
+
{
|
|
931
|
+
token: utils7.getTokenAccountId(args.withdrawalParams.assetId),
|
|
932
|
+
address: args.withdrawalParams.destinationAddress,
|
|
933
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
934
|
+
chain: toPoaNetwork(assetInfo.blockchain)
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
baseURL: configsByEnvironment4[this.env].poaBridgeBaseURL,
|
|
938
|
+
logger: args.logger
|
|
939
|
+
}
|
|
940
|
+
);
|
|
941
|
+
return {
|
|
942
|
+
amount: BigInt(estimation.withdrawalFee),
|
|
943
|
+
quote: null
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
async waitForWithdrawalCompletion(args) {
|
|
947
|
+
const withdrawalStatus = await poaBridge.waitForWithdrawalCompletion({
|
|
948
|
+
txHash: args.tx.hash,
|
|
949
|
+
index: args.index,
|
|
950
|
+
signal: args.signal ?? new AbortController().signal,
|
|
951
|
+
retryOptions: args.retryOptions,
|
|
952
|
+
baseURL: configsByEnvironment4[this.env].poaBridgeBaseURL,
|
|
953
|
+
logger: args.logger
|
|
954
|
+
});
|
|
955
|
+
return { hash: withdrawalStatus.destinationTxHash };
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Gets supported tokens with caching to avoid frequent API calls.
|
|
959
|
+
* Cache expires after 30 seconds using TTL cache.
|
|
960
|
+
*/
|
|
961
|
+
async getCachedSupportedTokens(chains, logger) {
|
|
962
|
+
const cacheKey = chains.sort().join(",");
|
|
963
|
+
const cached = this.supportedTokensCache.get(cacheKey);
|
|
964
|
+
if (cached != null) {
|
|
965
|
+
return cached;
|
|
966
|
+
}
|
|
967
|
+
const data = await poaBridge.httpClient.getSupportedTokens(
|
|
968
|
+
{ chains },
|
|
969
|
+
{
|
|
970
|
+
baseURL: configsByEnvironment4[this.env].poaBridgeBaseURL,
|
|
971
|
+
logger
|
|
972
|
+
}
|
|
973
|
+
);
|
|
974
|
+
this.supportedTokensCache.set(cacheKey, data);
|
|
975
|
+
return data;
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
// src/constants/public-rpc-urls.ts
|
|
980
|
+
var PUBLIC_EVM_RPC_URLS = {
|
|
981
|
+
[Chains.BNB]: ["https://bsc-rpc.publicnode.com"],
|
|
982
|
+
[Chains.Polygon]: ["https://polygon-bor-rpc.publicnode.com"],
|
|
983
|
+
[Chains.Optimism]: ["https://optimism-rpc.publicnode.com"],
|
|
984
|
+
[Chains.Avalanche]: ["https://avalanche-c-chain-rpc.publicnode.com"]
|
|
985
|
+
};
|
|
986
|
+
var PUBLIC_STELLAR_RPC_URLS = {
|
|
987
|
+
soroban: ["https://mainnet.sorobanrpc.com"],
|
|
988
|
+
horizon: ["https://horizon.stellar.org"]
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
// src/intents/intent-executer-impl/intent-executer.ts
|
|
992
|
+
import {
|
|
993
|
+
configsByEnvironment as configsByEnvironment5
|
|
994
|
+
} from "@defuse-protocol/internal-utils";
|
|
995
|
+
|
|
996
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_u64.js
|
|
997
|
+
var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
998
|
+
var _32n = /* @__PURE__ */ BigInt(32);
|
|
999
|
+
function fromBig(n, le = false) {
|
|
1000
|
+
if (le)
|
|
1001
|
+
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
1002
|
+
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
|
1003
|
+
}
|
|
1004
|
+
function split(lst, le = false) {
|
|
1005
|
+
const len = lst.length;
|
|
1006
|
+
let Ah = new Uint32Array(len);
|
|
1007
|
+
let Al = new Uint32Array(len);
|
|
1008
|
+
for (let i = 0; i < len; i++) {
|
|
1009
|
+
const { h, l } = fromBig(lst[i], le);
|
|
1010
|
+
[Ah[i], Al[i]] = [h, l];
|
|
1011
|
+
}
|
|
1012
|
+
return [Ah, Al];
|
|
1013
|
+
}
|
|
1014
|
+
var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
|
|
1015
|
+
var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
|
|
1016
|
+
var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
|
|
1017
|
+
var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
|
|
1018
|
+
|
|
1019
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/utils.js
|
|
1020
|
+
function isBytes(a) {
|
|
1021
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
1022
|
+
}
|
|
1023
|
+
function anumber(n) {
|
|
1024
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
1025
|
+
throw new Error("positive integer expected, got " + n);
|
|
1026
|
+
}
|
|
1027
|
+
function abytes(b, ...lengths) {
|
|
1028
|
+
if (!isBytes(b))
|
|
1029
|
+
throw new Error("Uint8Array expected");
|
|
1030
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
1031
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
1032
|
+
}
|
|
1033
|
+
function aexists(instance, checkFinished = true) {
|
|
1034
|
+
if (instance.destroyed)
|
|
1035
|
+
throw new Error("Hash instance has been destroyed");
|
|
1036
|
+
if (checkFinished && instance.finished)
|
|
1037
|
+
throw new Error("Hash#digest() has already been called");
|
|
1038
|
+
}
|
|
1039
|
+
function aoutput(out, instance) {
|
|
1040
|
+
abytes(out);
|
|
1041
|
+
const min = instance.outputLen;
|
|
1042
|
+
if (out.length < min) {
|
|
1043
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
function u32(arr) {
|
|
1047
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
1048
|
+
}
|
|
1049
|
+
function clean(...arrays) {
|
|
1050
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
1051
|
+
arrays[i].fill(0);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
1055
|
+
function byteSwap(word) {
|
|
1056
|
+
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
1057
|
+
}
|
|
1058
|
+
function byteSwap32(arr) {
|
|
1059
|
+
for (let i = 0; i < arr.length; i++) {
|
|
1060
|
+
arr[i] = byteSwap(arr[i]);
|
|
1061
|
+
}
|
|
1062
|
+
return arr;
|
|
1063
|
+
}
|
|
1064
|
+
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
1065
|
+
function utf8ToBytes(str) {
|
|
1066
|
+
if (typeof str !== "string")
|
|
1067
|
+
throw new Error("string expected");
|
|
1068
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
1069
|
+
}
|
|
1070
|
+
function toBytes(data) {
|
|
1071
|
+
if (typeof data === "string")
|
|
1072
|
+
data = utf8ToBytes(data);
|
|
1073
|
+
abytes(data);
|
|
1074
|
+
return data;
|
|
1075
|
+
}
|
|
1076
|
+
var Hash = class {
|
|
1077
|
+
};
|
|
1078
|
+
function createHasher(hashCons) {
|
|
1079
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
1080
|
+
const tmp = hashCons();
|
|
1081
|
+
hashC.outputLen = tmp.outputLen;
|
|
1082
|
+
hashC.blockLen = tmp.blockLen;
|
|
1083
|
+
hashC.create = () => hashCons();
|
|
1084
|
+
return hashC;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha3.js
|
|
1088
|
+
var _0n = BigInt(0);
|
|
1089
|
+
var _1n = BigInt(1);
|
|
1090
|
+
var _2n = BigInt(2);
|
|
1091
|
+
var _7n = BigInt(7);
|
|
1092
|
+
var _256n = BigInt(256);
|
|
1093
|
+
var _0x71n = BigInt(113);
|
|
1094
|
+
var SHA3_PI = [];
|
|
1095
|
+
var SHA3_ROTL = [];
|
|
1096
|
+
var _SHA3_IOTA = [];
|
|
1097
|
+
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
|
1098
|
+
[x, y] = [y, (2 * x + 3 * y) % 5];
|
|
1099
|
+
SHA3_PI.push(2 * (5 * y + x));
|
|
1100
|
+
SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
|
|
1101
|
+
let t = _0n;
|
|
1102
|
+
for (let j = 0; j < 7; j++) {
|
|
1103
|
+
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
|
|
1104
|
+
if (R & _2n)
|
|
1105
|
+
t ^= _1n << (_1n << /* @__PURE__ */ BigInt(j)) - _1n;
|
|
1106
|
+
}
|
|
1107
|
+
_SHA3_IOTA.push(t);
|
|
1108
|
+
}
|
|
1109
|
+
var IOTAS = split(_SHA3_IOTA, true);
|
|
1110
|
+
var SHA3_IOTA_H = IOTAS[0];
|
|
1111
|
+
var SHA3_IOTA_L = IOTAS[1];
|
|
1112
|
+
var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
|
|
1113
|
+
var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
|
|
1114
|
+
function keccakP(s, rounds = 24) {
|
|
1115
|
+
const B = new Uint32Array(5 * 2);
|
|
1116
|
+
for (let round = 24 - rounds; round < 24; round++) {
|
|
1117
|
+
for (let x = 0; x < 10; x++)
|
|
1118
|
+
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
|
1119
|
+
for (let x = 0; x < 10; x += 2) {
|
|
1120
|
+
const idx1 = (x + 8) % 10;
|
|
1121
|
+
const idx0 = (x + 2) % 10;
|
|
1122
|
+
const B0 = B[idx0];
|
|
1123
|
+
const B1 = B[idx0 + 1];
|
|
1124
|
+
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
|
1125
|
+
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
|
1126
|
+
for (let y = 0; y < 50; y += 10) {
|
|
1127
|
+
s[x + y] ^= Th;
|
|
1128
|
+
s[x + y + 1] ^= Tl;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
let curH = s[2];
|
|
1132
|
+
let curL = s[3];
|
|
1133
|
+
for (let t = 0; t < 24; t++) {
|
|
1134
|
+
const shift = SHA3_ROTL[t];
|
|
1135
|
+
const Th = rotlH(curH, curL, shift);
|
|
1136
|
+
const Tl = rotlL(curH, curL, shift);
|
|
1137
|
+
const PI = SHA3_PI[t];
|
|
1138
|
+
curH = s[PI];
|
|
1139
|
+
curL = s[PI + 1];
|
|
1140
|
+
s[PI] = Th;
|
|
1141
|
+
s[PI + 1] = Tl;
|
|
1142
|
+
}
|
|
1143
|
+
for (let y = 0; y < 50; y += 10) {
|
|
1144
|
+
for (let x = 0; x < 10; x++)
|
|
1145
|
+
B[x] = s[y + x];
|
|
1146
|
+
for (let x = 0; x < 10; x++)
|
|
1147
|
+
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
|
1148
|
+
}
|
|
1149
|
+
s[0] ^= SHA3_IOTA_H[round];
|
|
1150
|
+
s[1] ^= SHA3_IOTA_L[round];
|
|
1151
|
+
}
|
|
1152
|
+
clean(B);
|
|
1153
|
+
}
|
|
1154
|
+
var Keccak = class _Keccak extends Hash {
|
|
1155
|
+
// NOTE: we accept arguments in bytes instead of bits here.
|
|
1156
|
+
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
|
1157
|
+
super();
|
|
1158
|
+
this.pos = 0;
|
|
1159
|
+
this.posOut = 0;
|
|
1160
|
+
this.finished = false;
|
|
1161
|
+
this.destroyed = false;
|
|
1162
|
+
this.enableXOF = false;
|
|
1163
|
+
this.blockLen = blockLen;
|
|
1164
|
+
this.suffix = suffix;
|
|
1165
|
+
this.outputLen = outputLen;
|
|
1166
|
+
this.enableXOF = enableXOF;
|
|
1167
|
+
this.rounds = rounds;
|
|
1168
|
+
anumber(outputLen);
|
|
1169
|
+
if (!(0 < blockLen && blockLen < 200))
|
|
1170
|
+
throw new Error("only keccak-f1600 function is supported");
|
|
1171
|
+
this.state = new Uint8Array(200);
|
|
1172
|
+
this.state32 = u32(this.state);
|
|
1173
|
+
}
|
|
1174
|
+
clone() {
|
|
1175
|
+
return this._cloneInto();
|
|
1176
|
+
}
|
|
1177
|
+
keccak() {
|
|
1178
|
+
swap32IfBE(this.state32);
|
|
1179
|
+
keccakP(this.state32, this.rounds);
|
|
1180
|
+
swap32IfBE(this.state32);
|
|
1181
|
+
this.posOut = 0;
|
|
1182
|
+
this.pos = 0;
|
|
1183
|
+
}
|
|
1184
|
+
update(data) {
|
|
1185
|
+
aexists(this);
|
|
1186
|
+
data = toBytes(data);
|
|
1187
|
+
abytes(data);
|
|
1188
|
+
const { blockLen, state } = this;
|
|
1189
|
+
const len = data.length;
|
|
1190
|
+
for (let pos = 0; pos < len; ) {
|
|
1191
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
1192
|
+
for (let i = 0; i < take; i++)
|
|
1193
|
+
state[this.pos++] ^= data[pos++];
|
|
1194
|
+
if (this.pos === blockLen)
|
|
1195
|
+
this.keccak();
|
|
1196
|
+
}
|
|
1197
|
+
return this;
|
|
1198
|
+
}
|
|
1199
|
+
finish() {
|
|
1200
|
+
if (this.finished)
|
|
1201
|
+
return;
|
|
1202
|
+
this.finished = true;
|
|
1203
|
+
const { state, suffix, pos, blockLen } = this;
|
|
1204
|
+
state[pos] ^= suffix;
|
|
1205
|
+
if ((suffix & 128) !== 0 && pos === blockLen - 1)
|
|
1206
|
+
this.keccak();
|
|
1207
|
+
state[blockLen - 1] ^= 128;
|
|
1208
|
+
this.keccak();
|
|
1209
|
+
}
|
|
1210
|
+
writeInto(out) {
|
|
1211
|
+
aexists(this, false);
|
|
1212
|
+
abytes(out);
|
|
1213
|
+
this.finish();
|
|
1214
|
+
const bufferOut = this.state;
|
|
1215
|
+
const { blockLen } = this;
|
|
1216
|
+
for (let pos = 0, len = out.length; pos < len; ) {
|
|
1217
|
+
if (this.posOut >= blockLen)
|
|
1218
|
+
this.keccak();
|
|
1219
|
+
const take = Math.min(blockLen - this.posOut, len - pos);
|
|
1220
|
+
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
|
1221
|
+
this.posOut += take;
|
|
1222
|
+
pos += take;
|
|
1223
|
+
}
|
|
1224
|
+
return out;
|
|
1225
|
+
}
|
|
1226
|
+
xofInto(out) {
|
|
1227
|
+
if (!this.enableXOF)
|
|
1228
|
+
throw new Error("XOF is not possible for this instance");
|
|
1229
|
+
return this.writeInto(out);
|
|
1230
|
+
}
|
|
1231
|
+
xof(bytes) {
|
|
1232
|
+
anumber(bytes);
|
|
1233
|
+
return this.xofInto(new Uint8Array(bytes));
|
|
1234
|
+
}
|
|
1235
|
+
digestInto(out) {
|
|
1236
|
+
aoutput(out, this);
|
|
1237
|
+
if (this.finished)
|
|
1238
|
+
throw new Error("digest() was already called");
|
|
1239
|
+
this.writeInto(out);
|
|
1240
|
+
this.destroy();
|
|
1241
|
+
return out;
|
|
1242
|
+
}
|
|
1243
|
+
digest() {
|
|
1244
|
+
return this.digestInto(new Uint8Array(this.outputLen));
|
|
1245
|
+
}
|
|
1246
|
+
destroy() {
|
|
1247
|
+
this.destroyed = true;
|
|
1248
|
+
clean(this.state);
|
|
1249
|
+
}
|
|
1250
|
+
_cloneInto(to) {
|
|
1251
|
+
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
|
1252
|
+
to || (to = new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
|
|
1253
|
+
to.state32.set(this.state32);
|
|
1254
|
+
to.pos = this.pos;
|
|
1255
|
+
to.posOut = this.posOut;
|
|
1256
|
+
to.finished = this.finished;
|
|
1257
|
+
to.rounds = rounds;
|
|
1258
|
+
to.suffix = suffix;
|
|
1259
|
+
to.outputLen = outputLen;
|
|
1260
|
+
to.enableXOF = enableXOF;
|
|
1261
|
+
to.destroyed = this.destroyed;
|
|
1262
|
+
return to;
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
1265
|
+
var gen = (suffix, blockLen, outputLen) => createHasher(() => new Keccak(blockLen, suffix, outputLen));
|
|
1266
|
+
var keccak_256 = /* @__PURE__ */ (() => gen(1, 136, 256 / 8))();
|
|
1267
|
+
|
|
1268
|
+
// src/intents/intent-hash.ts
|
|
1269
|
+
import { base58, base64 } from "@scure/base";
|
|
1270
|
+
|
|
1271
|
+
// src/lib/nep413.ts
|
|
1272
|
+
import { BorshSchema, borshSerialize } from "borsher";
|
|
1273
|
+
var nep413PayloadSchema = BorshSchema.Struct({
|
|
1274
|
+
message: BorshSchema.String,
|
|
1275
|
+
nonce: BorshSchema.Array(BorshSchema.u8, 32),
|
|
1276
|
+
recipient: BorshSchema.String,
|
|
1277
|
+
callback_url: BorshSchema.Option(BorshSchema.String)
|
|
1278
|
+
});
|
|
1279
|
+
async function hashNEP413Message({
|
|
1280
|
+
message,
|
|
1281
|
+
recipient,
|
|
1282
|
+
nonce,
|
|
1283
|
+
callback_url
|
|
1284
|
+
}) {
|
|
1285
|
+
const payload = {
|
|
1286
|
+
message,
|
|
1287
|
+
nonce: Array.from(nonce),
|
|
1288
|
+
recipient,
|
|
1289
|
+
callback_url
|
|
1290
|
+
};
|
|
1291
|
+
const payloadSerialized = borshSerialize(nep413PayloadSchema, payload);
|
|
1292
|
+
const baseInt = 2 ** 31 + 413;
|
|
1293
|
+
const baseIntSerialized = borshSerialize(BorshSchema.u32, baseInt);
|
|
1294
|
+
const combinedData = new Uint8Array(
|
|
1295
|
+
baseIntSerialized.length + payloadSerialized.length
|
|
1296
|
+
);
|
|
1297
|
+
combinedData.set(baseIntSerialized);
|
|
1298
|
+
combinedData.set(payloadSerialized, baseIntSerialized.length);
|
|
1299
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", combinedData);
|
|
1300
|
+
return new Uint8Array(hashBuffer);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// src/intents/intent-hash.ts
|
|
1304
|
+
async function computeIntentHash(multiPayload) {
|
|
1305
|
+
const hashBytes = await computeIntentHashBytes(multiPayload);
|
|
1306
|
+
return base58.encode(hashBytes);
|
|
1307
|
+
}
|
|
1308
|
+
async function computeIntentHashBytes(multiPayload) {
|
|
1309
|
+
switch (multiPayload.standard) {
|
|
1310
|
+
case "nep413":
|
|
1311
|
+
return computeNep413Hash(
|
|
1312
|
+
multiPayload
|
|
1313
|
+
);
|
|
1314
|
+
case "erc191":
|
|
1315
|
+
return computeErc191Hash(
|
|
1316
|
+
multiPayload
|
|
1317
|
+
);
|
|
1318
|
+
default:
|
|
1319
|
+
throw new Error(
|
|
1320
|
+
`Standard is not yet supported: ${multiPayload.standard}`
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
async function computeNep413Hash(multiPayload) {
|
|
1325
|
+
const payload = multiPayload.payload;
|
|
1326
|
+
return hashNEP413Message({
|
|
1327
|
+
message: payload.message,
|
|
1328
|
+
recipient: payload.recipient,
|
|
1329
|
+
nonce: Array.from(base64.decode(payload.nonce)),
|
|
1330
|
+
callback_url: payload.callbackUrl
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
function computeErc191Hash(multiPayload) {
|
|
1334
|
+
const message = multiPayload.payload;
|
|
1335
|
+
const prefix = "Ethereum Signed Message:\n";
|
|
1336
|
+
const messageWithPrefix = prefix + message.length.toString() + message;
|
|
1337
|
+
return keccak_256(new TextEncoder().encode(messageWithPrefix));
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// src/intents/intent-payload-factory.ts
|
|
1341
|
+
import { base64 as base642 } from "@scure/base";
|
|
1342
|
+
function defaultIntentPayloadFactory({
|
|
1343
|
+
intents,
|
|
1344
|
+
verifying_contract,
|
|
1345
|
+
...params
|
|
1346
|
+
}) {
|
|
1347
|
+
params = Object.fromEntries(
|
|
1348
|
+
Object.entries(params).filter(([, value]) => value !== void 0)
|
|
1349
|
+
);
|
|
1350
|
+
return {
|
|
1351
|
+
verifying_contract,
|
|
1352
|
+
deadline: new Date(Date.now() + 60 * 1e3).toISOString(),
|
|
1353
|
+
nonce: base642.encode(crypto.getRandomValues(new Uint8Array(32))),
|
|
1354
|
+
intents: intents == null ? [] : intents,
|
|
1355
|
+
signer_id: void 0,
|
|
1356
|
+
// or you can specify intent user id
|
|
1357
|
+
...params
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// src/intents/intent-executer-impl/intent-executer.ts
|
|
1362
|
+
var IntentExecuter = class {
|
|
1363
|
+
constructor(args) {
|
|
1364
|
+
this.env = args.env;
|
|
1365
|
+
this.logger = args.logger;
|
|
1366
|
+
this.intentPayloadFactory = args.intentPayloadFactory;
|
|
1367
|
+
this.intentRelayer = args.intentRelayer;
|
|
1368
|
+
this.intentSigner = args.intentSigner;
|
|
1369
|
+
this.onBeforePublishIntent = args.onBeforePublishIntent;
|
|
1370
|
+
}
|
|
1371
|
+
async signAndSendIntent({
|
|
1372
|
+
relayParams: relayParamsFactory,
|
|
1373
|
+
...intentParams
|
|
1374
|
+
}) {
|
|
1375
|
+
const verifyingContract = configsByEnvironment5[this.env].contractID;
|
|
1376
|
+
let intentPayload = defaultIntentPayloadFactory({
|
|
1377
|
+
verifying_contract: verifyingContract,
|
|
1378
|
+
...intentParams
|
|
1379
|
+
});
|
|
1380
|
+
if (this.intentPayloadFactory) {
|
|
1381
|
+
intentPayload = await mergeIntentPayloads(
|
|
1382
|
+
intentPayload,
|
|
1383
|
+
this.intentPayloadFactory
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
const multiPayload = await this.intentSigner.signIntent(intentPayload);
|
|
1387
|
+
const relayParams = relayParamsFactory ? await relayParamsFactory() : {};
|
|
1388
|
+
if (this.onBeforePublishIntent) {
|
|
1389
|
+
const intentHash = await computeIntentHash(multiPayload);
|
|
1390
|
+
await this.onBeforePublishIntent({
|
|
1391
|
+
intentHash,
|
|
1392
|
+
intentPayload,
|
|
1393
|
+
multiPayload,
|
|
1394
|
+
relayParams
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
const ticket = await this.intentRelayer.publishIntent(
|
|
1398
|
+
{
|
|
1399
|
+
multiPayload,
|
|
1400
|
+
...relayParams
|
|
1401
|
+
},
|
|
1402
|
+
{ logger: this.logger }
|
|
1403
|
+
);
|
|
1404
|
+
return { ticket };
|
|
1405
|
+
}
|
|
1406
|
+
async waitForSettlement(ticket) {
|
|
1407
|
+
return this.intentRelayer.waitForSettlement(ticket, {
|
|
1408
|
+
logger: this.logger
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
async function mergeIntentPayloads(basePayload, intentPayloadFactory) {
|
|
1413
|
+
const customPayload = await intentPayloadFactory(basePayload);
|
|
1414
|
+
const customPayloadIntents = customPayload.intents ?? [];
|
|
1415
|
+
return {
|
|
1416
|
+
...basePayload,
|
|
1417
|
+
...customPayload,
|
|
1418
|
+
intents: Array.from(
|
|
1419
|
+
/* @__PURE__ */ new Set([...customPayloadIntents, ...basePayload.intents])
|
|
1420
|
+
)
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
// src/intents/intent-relayer-impl/intent-relayer-public.ts
|
|
1425
|
+
import {
|
|
1426
|
+
configsByEnvironment as configsByEnvironment6,
|
|
1427
|
+
solverRelay as solverRelay4
|
|
1428
|
+
} from "@defuse-protocol/internal-utils";
|
|
1429
|
+
var IntentRelayerPublic = class {
|
|
1430
|
+
constructor({ env }) {
|
|
1431
|
+
this.env = env;
|
|
1432
|
+
}
|
|
1433
|
+
async publishIntent({
|
|
1434
|
+
multiPayload,
|
|
1435
|
+
quoteHashes
|
|
1436
|
+
}, ctx = {}) {
|
|
1437
|
+
return (await this.publishIntents(
|
|
1438
|
+
{
|
|
1439
|
+
multiPayloads: [multiPayload],
|
|
1440
|
+
quoteHashes: quoteHashes ?? []
|
|
1441
|
+
},
|
|
1442
|
+
ctx
|
|
1443
|
+
))[0];
|
|
1444
|
+
}
|
|
1445
|
+
// как прокидывать доп. параметры, например, quoteHashes (или специфичные параметры для каждого релея?)
|
|
1446
|
+
async publishIntents({
|
|
1447
|
+
multiPayloads,
|
|
1448
|
+
quoteHashes
|
|
1449
|
+
}, ctx = {}) {
|
|
1450
|
+
const a = await solverRelay4.publishIntents(
|
|
1451
|
+
{
|
|
1452
|
+
quote_hashes: quoteHashes,
|
|
1453
|
+
signed_datas: multiPayloads
|
|
1454
|
+
},
|
|
1455
|
+
{
|
|
1456
|
+
baseURL: configsByEnvironment6[this.env].solverRelayBaseURL,
|
|
1457
|
+
logger: ctx.logger
|
|
1458
|
+
}
|
|
1459
|
+
);
|
|
1460
|
+
if (a.isOk()) {
|
|
1461
|
+
return a.unwrap();
|
|
1462
|
+
}
|
|
1463
|
+
throw a.unwrapErr();
|
|
1464
|
+
}
|
|
1465
|
+
async waitForSettlement(ticket, ctx = {}) {
|
|
1466
|
+
const result = await solverRelay4.waitForIntentSettlement({
|
|
1467
|
+
intentHash: ticket,
|
|
1468
|
+
signal: new AbortController().signal,
|
|
1469
|
+
baseURL: configsByEnvironment6[this.env].solverRelayBaseURL,
|
|
1470
|
+
logger: ctx.logger
|
|
1471
|
+
});
|
|
1472
|
+
return {
|
|
1473
|
+
tx: {
|
|
1474
|
+
hash: result.txHash,
|
|
1475
|
+
// Usually relayer's account id is the verifying contract (`intents.near`),
|
|
1476
|
+
// but it is not set in stone and may change in the future.
|
|
1477
|
+
accountId: configsByEnvironment6[this.env].contractID
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
// src/intents/intent-signer-impl/intent-signer-noop.ts
|
|
1484
|
+
var noopIntentSigner = {
|
|
1485
|
+
signIntent() {
|
|
1486
|
+
throw new Error("Not implemented");
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
|
|
1490
|
+
// src/lib/array.ts
|
|
1491
|
+
import { assert as assert9 } from "@defuse-protocol/internal-utils";
|
|
1492
|
+
function zip(arr1, arr2) {
|
|
1493
|
+
assert9(arr1.length === arr2.length, "Arrays must have the same length");
|
|
1494
|
+
return arr1.map((v, i) => [v, arr2[i]]);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
// src/lib/configure-rpc-config.ts
|
|
1498
|
+
import { assert as assert10 } from "@defuse-protocol/internal-utils";
|
|
1499
|
+
|
|
1500
|
+
// src/lib/object.ts
|
|
1501
|
+
function pick(obj, keys) {
|
|
1502
|
+
const result = {};
|
|
1503
|
+
for (const key of keys) {
|
|
1504
|
+
if (key in obj) {
|
|
1505
|
+
result[key] = obj[key];
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return result;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// src/lib/configure-rpc-config.ts
|
|
1512
|
+
function configureEvmRpcUrls(defaultRpcUrls, userRpcUrls, supportedChains) {
|
|
1513
|
+
const evmRpcUrls = Object.fromEntries(
|
|
1514
|
+
Object.entries(
|
|
1515
|
+
pick(
|
|
1516
|
+
Object.assign({}, defaultRpcUrls, userRpcUrls ?? {}),
|
|
1517
|
+
supportedChains
|
|
1518
|
+
)
|
|
1519
|
+
).map(([caip2, urls]) => [getEIP155ChainId(caip2), urls])
|
|
1520
|
+
);
|
|
1521
|
+
for (const [chainId, urls] of Object.entries(evmRpcUrls)) {
|
|
1522
|
+
assert10(
|
|
1523
|
+
urls.length > 0,
|
|
1524
|
+
`EVM RPC URLs for chain ${chainId} are not provided`
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
return evmRpcUrls;
|
|
1528
|
+
}
|
|
1529
|
+
function configureStellarRpcUrls(defaultRpcUrls, userRpcUrls) {
|
|
1530
|
+
const stellarRpcUrls = Object.assign(
|
|
1531
|
+
{},
|
|
1532
|
+
defaultRpcUrls,
|
|
1533
|
+
userRpcUrls?.[Chains.Stellar] ?? {}
|
|
1534
|
+
);
|
|
1535
|
+
for (const [key, value] of Object.entries(stellarRpcUrls)) {
|
|
1536
|
+
assert10(value.length > 0, `Stellar RPC URL for ${key} is not provided`);
|
|
1537
|
+
}
|
|
1538
|
+
return stellarRpcUrls;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// src/lib/route-config-factory.ts
|
|
1542
|
+
function createInternalTransferRoute() {
|
|
1543
|
+
return { route: RouteEnum.InternalTransfer };
|
|
1544
|
+
}
|
|
1545
|
+
function createNearWithdrawalRoute(msg) {
|
|
1546
|
+
return { route: RouteEnum.NearWithdrawal, msg };
|
|
1547
|
+
}
|
|
1548
|
+
function createVirtualChainRoute(auroraEngineContractId, proxyTokenContractId) {
|
|
1549
|
+
return {
|
|
1550
|
+
route: RouteEnum.VirtualChain,
|
|
1551
|
+
auroraEngineContractId,
|
|
1552
|
+
proxyTokenContractId
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
function createPoaBridgeRoute(chain) {
|
|
1556
|
+
return {
|
|
1557
|
+
route: RouteEnum.PoaBridge,
|
|
1558
|
+
chain
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
function createHotBridgeRoute(chain) {
|
|
1562
|
+
return {
|
|
1563
|
+
route: RouteEnum.HotBridge,
|
|
1564
|
+
chain
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
function createDefaultRoute() {
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// src/lib/route-config.ts
|
|
1571
|
+
function determineRouteConfig(sdk, withdrawalParams) {
|
|
1572
|
+
if (withdrawalParams.routeConfig != null) {
|
|
1573
|
+
return withdrawalParams.routeConfig;
|
|
1574
|
+
}
|
|
1575
|
+
const parseAssetId = sdk.parseAssetId(withdrawalParams.assetId);
|
|
1576
|
+
const bridgeName = parseAssetId.bridgeName;
|
|
1577
|
+
switch (bridgeName) {
|
|
1578
|
+
case BridgeNameEnum.Hot:
|
|
1579
|
+
return {
|
|
1580
|
+
route: RouteEnum.HotBridge,
|
|
1581
|
+
chain: parseAssetId.blockchain
|
|
1582
|
+
};
|
|
1583
|
+
case BridgeNameEnum.Poa:
|
|
1584
|
+
return {
|
|
1585
|
+
route: RouteEnum.PoaBridge,
|
|
1586
|
+
chain: parseAssetId.blockchain
|
|
1587
|
+
};
|
|
1588
|
+
case BridgeNameEnum.None:
|
|
1589
|
+
return createNearWithdrawalRoute();
|
|
1590
|
+
default:
|
|
1591
|
+
bridgeName;
|
|
1592
|
+
throw new Error(`Unexpected bridge = ${bridgeName}`);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
// src/sdk.ts
|
|
1597
|
+
var IntentsSDK = class {
|
|
1598
|
+
constructor(args) {
|
|
1599
|
+
this.env = args.env ?? "production";
|
|
1600
|
+
this.referral = args.referral;
|
|
1601
|
+
const nearRpcUrls = args.rpc?.[Chains.Near] ?? PUBLIC_NEAR_RPC_URLS;
|
|
1602
|
+
assert11(nearRpcUrls.length > 0, "NEAR RPC URLs are not provided");
|
|
1603
|
+
const nearProvider = nearFailoverRpcProvider({ urls: nearRpcUrls });
|
|
1604
|
+
const stellarRpcUrls = configureStellarRpcUrls(
|
|
1605
|
+
PUBLIC_STELLAR_RPC_URLS,
|
|
1606
|
+
args.rpc
|
|
1607
|
+
);
|
|
1608
|
+
const evmRpcUrls = configureEvmRpcUrls(
|
|
1609
|
+
PUBLIC_EVM_RPC_URLS,
|
|
1610
|
+
args.rpc,
|
|
1611
|
+
HotBridgeEVMChains
|
|
1612
|
+
);
|
|
1613
|
+
this.bridges = [
|
|
1614
|
+
new IntentsBridge(),
|
|
1615
|
+
new AuroraEngineBridge({
|
|
1616
|
+
env: this.env,
|
|
1617
|
+
nearProvider
|
|
1618
|
+
}),
|
|
1619
|
+
new PoaBridge({ env: this.env }),
|
|
1620
|
+
new HotBridge({
|
|
1621
|
+
env: this.env,
|
|
1622
|
+
hotSdk: new hotOmniSdk.HotBridge({
|
|
1623
|
+
logger: console,
|
|
1624
|
+
evmRpc: evmRpcUrls,
|
|
1625
|
+
// 1. HotBridge from omni-sdk does not support FailoverProvider.
|
|
1626
|
+
// 2. omni-sdk has near-api-js@5.0.1, and it uses `instanceof` which doesn't work when multiple versions of packages are installed
|
|
1627
|
+
nearRpc: nearRpcUrls,
|
|
1628
|
+
stellarRpc: stellarRpcUrls.soroban,
|
|
1629
|
+
stellarHorizonRpc: stellarRpcUrls.horizon,
|
|
1630
|
+
async executeNearTransaction() {
|
|
1631
|
+
throw new Error("not implemented");
|
|
1632
|
+
}
|
|
1633
|
+
})
|
|
1634
|
+
}),
|
|
1635
|
+
new DirectBridge({
|
|
1636
|
+
env: this.env,
|
|
1637
|
+
nearProvider
|
|
1638
|
+
})
|
|
1639
|
+
];
|
|
1640
|
+
this.intentRelayer = new IntentRelayerPublic({ env: this.env });
|
|
1641
|
+
this.intentSigner = args.intentSigner;
|
|
1642
|
+
}
|
|
1643
|
+
setIntentSigner(signer) {
|
|
1644
|
+
this.intentSigner = signer;
|
|
1645
|
+
}
|
|
1646
|
+
async createWithdrawalIntents(args) {
|
|
1647
|
+
for (const bridge of this.bridges) {
|
|
1648
|
+
if (bridge.supports(args.withdrawalParams)) {
|
|
1649
|
+
const actualAmount = args.withdrawalParams.feeInclusive ? args.withdrawalParams.amount - args.feeEstimation.amount : args.withdrawalParams.amount;
|
|
1650
|
+
await bridge.validateWithdrawal({
|
|
1651
|
+
assetId: args.withdrawalParams.assetId,
|
|
1652
|
+
amount: actualAmount,
|
|
1653
|
+
destinationAddress: args.withdrawalParams.destinationAddress,
|
|
1654
|
+
logger: args.logger
|
|
1655
|
+
});
|
|
1656
|
+
return bridge.createWithdrawalIntents({
|
|
1657
|
+
withdrawalParams: {
|
|
1658
|
+
...args.withdrawalParams,
|
|
1659
|
+
amount: actualAmount
|
|
1660
|
+
},
|
|
1661
|
+
feeEstimation: args.feeEstimation,
|
|
1662
|
+
referral: args.referral ?? this.referral
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
throw new Error(
|
|
1667
|
+
`Cannot determine bridge for withdrawal = ${stringify(args.withdrawalParams)}`
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
estimateWithdrawalFee(args) {
|
|
1671
|
+
if (!Array.isArray(args.withdrawalParams)) {
|
|
1672
|
+
return this._estimateWithdrawalFee({
|
|
1673
|
+
...args,
|
|
1674
|
+
withdrawalParams: args.withdrawalParams
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
return Promise.all(
|
|
1678
|
+
args.withdrawalParams.map(
|
|
1679
|
+
(withdrawalParams) => this._estimateWithdrawalFee({
|
|
1680
|
+
...args,
|
|
1681
|
+
withdrawalParams
|
|
1682
|
+
})
|
|
1683
|
+
)
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
async _estimateWithdrawalFee(args) {
|
|
1687
|
+
for (const bridge of this.bridges) {
|
|
1688
|
+
if (bridge.supports(args.withdrawalParams)) {
|
|
1689
|
+
const fee = await bridge.estimateWithdrawalFee({
|
|
1690
|
+
withdrawalParams: args.withdrawalParams,
|
|
1691
|
+
quoteOptions: args.quoteOptions,
|
|
1692
|
+
logger: args.logger
|
|
1693
|
+
});
|
|
1694
|
+
if (args.withdrawalParams.feeInclusive) {
|
|
1695
|
+
if (args.withdrawalParams.amount <= fee.amount) {
|
|
1696
|
+
throw new FeeExceedsAmountError(fee, args.withdrawalParams.amount);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
return fee;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
throw new Error(
|
|
1703
|
+
`Cannot determine bridge for withdrawal = ${stringify(args.withdrawalParams)}`
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
getWithdrawalsIdentifiers({
|
|
1707
|
+
withdrawalParams,
|
|
1708
|
+
intentTx
|
|
1709
|
+
}) {
|
|
1710
|
+
const indexes = new Map(
|
|
1711
|
+
zip(
|
|
1712
|
+
withdrawalParams.map((w) => {
|
|
1713
|
+
const routeConfig = determineRouteConfig(this, w);
|
|
1714
|
+
return routeConfig.route;
|
|
1715
|
+
}),
|
|
1716
|
+
Array(withdrawalParams.length).fill(0)
|
|
1717
|
+
)
|
|
1718
|
+
);
|
|
1719
|
+
return withdrawalParams.map((w) => {
|
|
1720
|
+
const routeConfig = determineRouteConfig(this, w);
|
|
1721
|
+
const route = routeConfig.route;
|
|
1722
|
+
const index = indexes.get(route);
|
|
1723
|
+
assert11(index != null, "Index is not found for route");
|
|
1724
|
+
indexes.set(route, index + 1);
|
|
1725
|
+
return {
|
|
1726
|
+
routeConfig,
|
|
1727
|
+
index,
|
|
1728
|
+
tx: intentTx
|
|
1729
|
+
};
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
async waitForWithdrawalCompletion(args) {
|
|
1733
|
+
const wids = this.getWithdrawalsIdentifiers({
|
|
1734
|
+
withdrawalParams: Array.isArray(args.withdrawalParams) ? args.withdrawalParams : [args.withdrawalParams],
|
|
1735
|
+
intentTx: args.intentTx
|
|
1736
|
+
});
|
|
1737
|
+
const result = await Promise.all(
|
|
1738
|
+
wids.map((wid) => {
|
|
1739
|
+
for (const bridge of this.bridges) {
|
|
1740
|
+
if (bridge.is(wid.routeConfig)) {
|
|
1741
|
+
return bridge.waitForWithdrawalCompletion({
|
|
1742
|
+
tx: args.intentTx,
|
|
1743
|
+
index: wid.index,
|
|
1744
|
+
routeConfig: wid.routeConfig,
|
|
1745
|
+
signal: args.signal,
|
|
1746
|
+
retryOptions: args.retryOptions,
|
|
1747
|
+
logger: args.logger
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
throw new Error(`Unsupported route = ${stringify(wid.routeConfig)}`);
|
|
1752
|
+
})
|
|
1753
|
+
);
|
|
1754
|
+
if (Array.isArray(args.withdrawalParams)) {
|
|
1755
|
+
return result;
|
|
1756
|
+
}
|
|
1757
|
+
assert11(result.length === 1, "Unexpected result length");
|
|
1758
|
+
return result[0];
|
|
1759
|
+
}
|
|
1760
|
+
parseAssetId(assetId) {
|
|
1761
|
+
for (const bridge of this.bridges) {
|
|
1762
|
+
const parsed = bridge.parseAssetId(assetId);
|
|
1763
|
+
if (parsed != null) {
|
|
1764
|
+
return parsed;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
throw new Error(`Cannot determine bridge for assetId = ${assetId}`);
|
|
1768
|
+
}
|
|
1769
|
+
async signAndSendIntent(args) {
|
|
1770
|
+
const intentSigner = args.signer ?? this.intentSigner;
|
|
1771
|
+
assert11(intentSigner != null, "Intent signer is not provided");
|
|
1772
|
+
const intentExecuter = new IntentExecuter({
|
|
1773
|
+
env: this.env,
|
|
1774
|
+
logger: args.logger,
|
|
1775
|
+
intentSigner,
|
|
1776
|
+
intentRelayer: this.intentRelayer,
|
|
1777
|
+
intentPayloadFactory: args.payload,
|
|
1778
|
+
onBeforePublishIntent: args.onBeforePublishIntent
|
|
1779
|
+
});
|
|
1780
|
+
const { ticket } = await intentExecuter.signAndSendIntent({
|
|
1781
|
+
intents: args.intents,
|
|
1782
|
+
relayParams: args.relayParams
|
|
1783
|
+
});
|
|
1784
|
+
return { intentHash: ticket };
|
|
1785
|
+
}
|
|
1786
|
+
async signAndSendWithdrawalIntent(args) {
|
|
1787
|
+
let withdrawalParamsArray;
|
|
1788
|
+
let feeEstimations;
|
|
1789
|
+
if (isBatchMode(args)) {
|
|
1790
|
+
withdrawalParamsArray = args.withdrawalParams;
|
|
1791
|
+
feeEstimations = args.feeEstimation;
|
|
1792
|
+
} else {
|
|
1793
|
+
withdrawalParamsArray = [args.withdrawalParams];
|
|
1794
|
+
feeEstimations = [args.feeEstimation];
|
|
1795
|
+
}
|
|
1796
|
+
const intentsP = zip(withdrawalParamsArray, feeEstimations).map(
|
|
1797
|
+
([withdrawalParams, feeEstimation]) => {
|
|
1798
|
+
return this.createWithdrawalIntents({
|
|
1799
|
+
withdrawalParams,
|
|
1800
|
+
feeEstimation,
|
|
1801
|
+
referral: args.referral ?? this.referral,
|
|
1802
|
+
logger: args.logger
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
);
|
|
1806
|
+
const intents = (await Promise.all(intentsP)).flat();
|
|
1807
|
+
const relayParamsFn = async () => {
|
|
1808
|
+
const relayParams = args.intent?.relayParams != null ? await args.intent?.relayParams() : { quoteHashes: void 0 };
|
|
1809
|
+
const quoteHashes = relayParams.quoteHashes ?? [];
|
|
1810
|
+
for (const fee of feeEstimations) {
|
|
1811
|
+
if (fee.quote != null) {
|
|
1812
|
+
quoteHashes.push(fee.quote.quote_hash);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return { ...relayParams, quoteHashes };
|
|
1816
|
+
};
|
|
1817
|
+
return this.signAndSendIntent({
|
|
1818
|
+
intents,
|
|
1819
|
+
signer: args.intent?.signer,
|
|
1820
|
+
onBeforePublishIntent: args.intent?.onBeforePublishIntent,
|
|
1821
|
+
relayParams: relayParamsFn,
|
|
1822
|
+
payload: args.intent?.payload,
|
|
1823
|
+
logger: args.logger
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
async waitForIntentSettlement(args) {
|
|
1827
|
+
const intentExecuter = new IntentExecuter({
|
|
1828
|
+
env: this.env,
|
|
1829
|
+
logger: args.logger,
|
|
1830
|
+
intentSigner: noopIntentSigner,
|
|
1831
|
+
intentRelayer: this.intentRelayer
|
|
1832
|
+
});
|
|
1833
|
+
const { tx } = await intentExecuter.waitForSettlement(args.intentHash);
|
|
1834
|
+
return tx;
|
|
1835
|
+
}
|
|
1836
|
+
async getIntentStatus({
|
|
1837
|
+
intentHash,
|
|
1838
|
+
logger
|
|
1839
|
+
}) {
|
|
1840
|
+
return solverRelay5.getStatus(
|
|
1841
|
+
{
|
|
1842
|
+
intent_hash: intentHash
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
baseURL: configsByEnvironment7[this.env].solverRelayBaseURL,
|
|
1846
|
+
logger
|
|
1847
|
+
}
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
async processWithdrawal(args) {
|
|
1851
|
+
const withdrawalParams = Array.isArray(args.withdrawalParams) ? args.withdrawalParams : [args.withdrawalParams];
|
|
1852
|
+
const feeEstimation = await (() => {
|
|
1853
|
+
if (args.feeEstimation != null) {
|
|
1854
|
+
return Array.isArray(args.feeEstimation) ? args.feeEstimation : [args.feeEstimation];
|
|
1855
|
+
}
|
|
1856
|
+
return this.estimateWithdrawalFee({
|
|
1857
|
+
withdrawalParams,
|
|
1858
|
+
logger: args.logger
|
|
1859
|
+
});
|
|
1860
|
+
})();
|
|
1861
|
+
const { intentHash } = await this.signAndSendWithdrawalIntent({
|
|
1862
|
+
withdrawalParams,
|
|
1863
|
+
feeEstimation,
|
|
1864
|
+
referral: args.referral,
|
|
1865
|
+
intent: args.intent,
|
|
1866
|
+
logger: args.logger
|
|
1867
|
+
});
|
|
1868
|
+
const intentTx = await this.waitForIntentSettlement({
|
|
1869
|
+
intentHash,
|
|
1870
|
+
logger: args.logger
|
|
1871
|
+
});
|
|
1872
|
+
const destinationTx = await this.waitForWithdrawalCompletion({
|
|
1873
|
+
withdrawalParams,
|
|
1874
|
+
intentTx,
|
|
1875
|
+
logger: args.logger,
|
|
1876
|
+
retryOptions: RETRY_CONFIGS2.FIVE_MINS_STEADY
|
|
1877
|
+
});
|
|
1878
|
+
if (!Array.isArray(args.withdrawalParams)) {
|
|
1879
|
+
return {
|
|
1880
|
+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
1881
|
+
feeEstimation: feeEstimation[0],
|
|
1882
|
+
intentHash,
|
|
1883
|
+
intentTx,
|
|
1884
|
+
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
1885
|
+
destinationTx: destinationTx[0]
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1888
|
+
return {
|
|
1889
|
+
feeEstimation,
|
|
1890
|
+
intentHash,
|
|
1891
|
+
intentTx,
|
|
1892
|
+
destinationTx
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
function isBatchMode(args) {
|
|
1897
|
+
return Array.isArray(args.withdrawalParams);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
// src/intents/intent-signer-impl/intent-signer-near-keypair.ts
|
|
1901
|
+
import { base64 as base644 } from "@scure/base";
|
|
1902
|
+
|
|
1903
|
+
// src/intents/intent-signer-impl/intent-signer-nep413.ts
|
|
1904
|
+
import { base58 as base582, base64 as base643 } from "@scure/base";
|
|
1905
|
+
var IntentSignerNEP413 = class {
|
|
1906
|
+
constructor({ signMessage, accountId }) {
|
|
1907
|
+
this.signMessage = signMessage;
|
|
1908
|
+
this.accountId = accountId;
|
|
1909
|
+
}
|
|
1910
|
+
async signIntent(intent) {
|
|
1911
|
+
const nep413Payload = {
|
|
1912
|
+
recipient: intent.verifying_contract,
|
|
1913
|
+
nonce: Array.from(base643.decode(intent.nonce)),
|
|
1914
|
+
message: JSON.stringify({
|
|
1915
|
+
deadline: intent.deadline,
|
|
1916
|
+
intents: intent.intents,
|
|
1917
|
+
signer_id: intent.signer_id ?? this.accountId
|
|
1918
|
+
})
|
|
1919
|
+
};
|
|
1920
|
+
const nep413Hash = await hashNEP413Message(nep413Payload);
|
|
1921
|
+
const { publicKey, signature } = await this.signMessage(
|
|
1922
|
+
nep413Payload,
|
|
1923
|
+
nep413Hash
|
|
1924
|
+
);
|
|
1925
|
+
const signatureFormatted = signature.startsWith("ed25519:") ? signature : `ed25519:${base582.encode(base643.decode(signature))}`;
|
|
1926
|
+
return {
|
|
1927
|
+
standard: "nep413",
|
|
1928
|
+
payload: {
|
|
1929
|
+
...nep413Payload,
|
|
1930
|
+
nonce: intent.nonce
|
|
1931
|
+
},
|
|
1932
|
+
public_key: publicKey,
|
|
1933
|
+
signature: signatureFormatted
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
|
|
1938
|
+
// src/intents/intent-signer-impl/intent-signer-near-keypair.ts
|
|
1939
|
+
var IntentSignerNearKeypair = class extends IntentSignerNEP413 {
|
|
1940
|
+
constructor({ keypair, accountId }) {
|
|
1941
|
+
super({
|
|
1942
|
+
signMessage: (_nep413Payload, nep413Hash) => {
|
|
1943
|
+
const { publicKey, signature } = keypair.sign(nep413Hash);
|
|
1944
|
+
return {
|
|
1945
|
+
publicKey: publicKey.toString(),
|
|
1946
|
+
signature: base644.encode(signature)
|
|
1947
|
+
};
|
|
1948
|
+
},
|
|
1949
|
+
accountId
|
|
1950
|
+
});
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
|
|
1954
|
+
// src/intents/intent-signer-impl/intent-signer-viem.ts
|
|
1955
|
+
import { utils as utils8 } from "@defuse-protocol/internal-utils";
|
|
1956
|
+
var IntentSignerViem = class {
|
|
1957
|
+
constructor(account) {
|
|
1958
|
+
this.account = account;
|
|
1959
|
+
}
|
|
1960
|
+
async signIntent(intent) {
|
|
1961
|
+
const payload = JSON.stringify({
|
|
1962
|
+
signer_id: intent.signer_id ?? utils8.authHandleToIntentsUserId({
|
|
1963
|
+
identifier: this.account.address,
|
|
1964
|
+
method: "evm"
|
|
1965
|
+
}),
|
|
1966
|
+
verifying_contract: intent.verifying_contract,
|
|
1967
|
+
deadline: intent.deadline,
|
|
1968
|
+
nonce: intent.nonce,
|
|
1969
|
+
intents: intent.intents
|
|
1970
|
+
});
|
|
1971
|
+
const signature = await this.account.signMessage?.({
|
|
1972
|
+
message: payload
|
|
1973
|
+
});
|
|
1974
|
+
if (signature == null) {
|
|
1975
|
+
throw new Error("No signature is returned");
|
|
1976
|
+
}
|
|
1977
|
+
return {
|
|
1978
|
+
standard: "erc191",
|
|
1979
|
+
payload,
|
|
1980
|
+
signature: utils8.transformERC191Signature(signature)
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
|
|
1985
|
+
// src/intents/intent-signer-impl/factories.ts
|
|
1986
|
+
function createIntentSignerNEP413(config) {
|
|
1987
|
+
return new IntentSignerNEP413(config);
|
|
1988
|
+
}
|
|
1989
|
+
function createIntentSignerNearKeyPair(config) {
|
|
1990
|
+
return new IntentSignerNearKeypair(config);
|
|
1991
|
+
}
|
|
1992
|
+
function createIntentSignerViem(config) {
|
|
1993
|
+
return new IntentSignerViem(config);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
// index.ts
|
|
1997
|
+
import {
|
|
1998
|
+
BaseError as BaseError3
|
|
1999
|
+
} from "@defuse-protocol/internal-utils";
|
|
2000
|
+
import {
|
|
2001
|
+
PoaWithdrawalInvariantError,
|
|
2002
|
+
PoaWithdrawalNotFoundError,
|
|
2003
|
+
PoaWithdrawalPendingError
|
|
2004
|
+
} from "@defuse-protocol/internal-utils";
|
|
2005
|
+
import {
|
|
2006
|
+
HttpRequestError,
|
|
2007
|
+
RpcRequestError,
|
|
2008
|
+
TimeoutError
|
|
2009
|
+
} from "@defuse-protocol/internal-utils";
|
|
2010
|
+
import {
|
|
2011
|
+
AssertionError
|
|
2012
|
+
} from "@defuse-protocol/internal-utils";
|
|
2013
|
+
import {
|
|
2014
|
+
QuoteError,
|
|
2015
|
+
IntentSettlementError,
|
|
2016
|
+
RelayPublishError
|
|
2017
|
+
} from "@defuse-protocol/internal-utils";
|
|
2018
|
+
export {
|
|
2019
|
+
AssertionError,
|
|
2020
|
+
BaseError3 as BaseError,
|
|
2021
|
+
BridgeNameEnum,
|
|
2022
|
+
Chains,
|
|
2023
|
+
FeeExceedsAmountError,
|
|
2024
|
+
HotWithdrawalCancelledError,
|
|
2025
|
+
HotWithdrawalNotFoundError,
|
|
2026
|
+
HotWithdrawalPendingError,
|
|
2027
|
+
HttpRequestError,
|
|
2028
|
+
IntentSettlementError,
|
|
2029
|
+
IntentsSDK,
|
|
2030
|
+
MinWithdrawalAmountError,
|
|
2031
|
+
PoaWithdrawalInvariantError,
|
|
2032
|
+
PoaWithdrawalNotFoundError,
|
|
2033
|
+
PoaWithdrawalPendingError,
|
|
2034
|
+
QuoteError,
|
|
2035
|
+
RelayPublishError,
|
|
2036
|
+
RouteEnum,
|
|
2037
|
+
RpcRequestError,
|
|
2038
|
+
TimeoutError,
|
|
2039
|
+
TrustlineNotFoundError,
|
|
2040
|
+
UnsupportedDestinationMemoError,
|
|
2041
|
+
createDefaultRoute,
|
|
2042
|
+
createHotBridgeRoute,
|
|
2043
|
+
createIntentSignerNEP413,
|
|
2044
|
+
createIntentSignerNearKeyPair,
|
|
2045
|
+
createIntentSignerViem,
|
|
2046
|
+
createInternalTransferRoute,
|
|
2047
|
+
createNearWithdrawalRoute,
|
|
2048
|
+
createPoaBridgeRoute,
|
|
2049
|
+
createVirtualChainRoute
|
|
2050
|
+
};
|
|
2051
|
+
/*! Bundled license information:
|
|
2052
|
+
|
|
2053
|
+
@noble/hashes/esm/utils.js:
|
|
2054
|
+
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
2055
|
+
*/
|