@hyperbridge/sdk 2.8.13 → 2.8.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.ts +839 -911
- package/dist/browser/index.js +1435 -2081
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +1455 -2099
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +492 -180
- package/dist/node/index.d.ts +492 -180
- package/dist/node/index.js +1435 -2081
- package/dist/node/index.js.map +1 -1
- package/dist/node/{intents-helpers-fntBuoYM.d.cts → intents-helpers-BHl2If1T.d.cts} +909 -2967
- package/dist/node/{intents-helpers-fntBuoYM.d.ts → intents-helpers-BHl2If1T.d.ts} +909 -2967
- package/dist/node/intents-helpers.cjs +371 -1215
- package/dist/node/intents-helpers.cjs.map +1 -1
- package/dist/node/intents-helpers.d.cts +1 -3
- package/dist/node/intents-helpers.d.ts +1 -3
- package/dist/node/intents-helpers.js +373 -1200
- package/dist/node/intents-helpers.js.map +1 -1
- package/package.json +1 -1
package/dist/node/index.cjs
CHANGED
|
@@ -6,14 +6,14 @@ var util$1 = require('util');
|
|
|
6
6
|
var consola = require('consola');
|
|
7
7
|
var viem = require('viem');
|
|
8
8
|
var chains$1 = require('viem/chains');
|
|
9
|
-
var
|
|
9
|
+
var utilCrypto = require('@polkadot/util-crypto');
|
|
10
10
|
var lodashEs = require('lodash-es');
|
|
11
11
|
var tsPattern = require('ts-pattern');
|
|
12
12
|
var api = require('@polkadot/api');
|
|
13
13
|
var scaleTs = require('scale-ts');
|
|
14
|
-
var utilCrypto = require('@polkadot/util-crypto');
|
|
15
14
|
var util = require('@polkadot/util');
|
|
16
15
|
var PQueue = require('p-queue');
|
|
16
|
+
var tronweb = require('tronweb');
|
|
17
17
|
var stdEnv = require('std-env');
|
|
18
18
|
var mergeRace = require('@async-generator/merge-race');
|
|
19
19
|
var graphqlRequest = require('graphql-request');
|
|
@@ -280,6 +280,7 @@ var OrderStatus = /* @__PURE__ */ ((OrderStatus2) => {
|
|
|
280
280
|
OrderStatus2["FILLED"] = "FILLED";
|
|
281
281
|
OrderStatus2["REDEEMED"] = "REDEEMED";
|
|
282
282
|
OrderStatus2["REFUNDED"] = "REFUNDED";
|
|
283
|
+
OrderStatus2["CANCELLED"] = "CANCELLED";
|
|
283
284
|
return OrderStatus2;
|
|
284
285
|
})(OrderStatus || {});
|
|
285
286
|
var TeleportStatus = /* @__PURE__ */ ((TeleportStatus2) => {
|
|
@@ -294,6 +295,8 @@ var RequestKind = /* @__PURE__ */ ((RequestKind2) => {
|
|
|
294
295
|
RequestKind2[RequestKind2["UpdateParams"] = 2] = "UpdateParams";
|
|
295
296
|
RequestKind2[RequestKind2["SweepDust"] = 3] = "SweepDust";
|
|
296
297
|
RequestKind2[RequestKind2["RefundEscrow"] = 4] = "RefundEscrow";
|
|
298
|
+
RequestKind2[RequestKind2["Execute"] = 5] = "Execute";
|
|
299
|
+
RequestKind2[RequestKind2["RedeemEscrowPartial"] = 6] = "RedeemEscrowPartial";
|
|
297
300
|
return RequestKind2;
|
|
298
301
|
})(RequestKind || {});
|
|
299
302
|
var IntentOrderStatus = Object.freeze({
|
|
@@ -306,6 +309,7 @@ var IntentOrderStatus = Object.freeze({
|
|
|
306
309
|
BID_SELECTED: "BID_SELECTED",
|
|
307
310
|
FILLED: "FILLED",
|
|
308
311
|
PARTIAL_FILL: "PARTIAL_FILL",
|
|
312
|
+
CANCELLED: "CANCELLED",
|
|
309
313
|
EXPIRED: "EXPIRED",
|
|
310
314
|
FAILED: "FAILED"
|
|
311
315
|
});
|
|
@@ -2488,7 +2492,12 @@ var ABI2 = [
|
|
|
2488
2492
|
];
|
|
2489
2493
|
var handlerV2_default = { ABI: ABI2 };
|
|
2490
2494
|
function tronAddress(base58) {
|
|
2491
|
-
|
|
2495
|
+
const decoded = utilCrypto.base58Decode(base58);
|
|
2496
|
+
if (decoded.length !== 25 || decoded[0] !== 65) {
|
|
2497
|
+
throw new Error(`Not a Tron base58 address: ${base58}`);
|
|
2498
|
+
}
|
|
2499
|
+
const hex = Array.from(decoded.slice(1, 21), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2500
|
+
return `0x${hex}`;
|
|
2492
2501
|
}
|
|
2493
2502
|
var Chains = /* @__PURE__ */ ((Chains2) => {
|
|
2494
2503
|
Chains2["BSC_CHAPEL"] = "EVM-97";
|
|
@@ -2575,11 +2584,13 @@ var chainConfigs = {
|
|
|
2575
2584
|
WETH: "0xae13d989dac2f0debff460ac112a837c89baa7cd",
|
|
2576
2585
|
DAI: "0x1938165569a5463327fb206be06d8d9253aa06b7",
|
|
2577
2586
|
USDC: "0xA801da100bF16D07F668F4A49E1f71fc54D05177",
|
|
2578
|
-
USDT: "0xc043f483373072f7f27420d6e7d7ad269c018e18"
|
|
2587
|
+
USDT: "0xc043f483373072f7f27420d6e7d7ad269c018e18",
|
|
2588
|
+
cNGN: "0x2bbbd701cfc25d37f18127e51df0933566d5778a"
|
|
2579
2589
|
},
|
|
2580
2590
|
tokenDecimals: {
|
|
2581
2591
|
USDC: 18,
|
|
2582
|
-
USDT: 18
|
|
2592
|
+
USDT: 18,
|
|
2593
|
+
cNGN: 6
|
|
2583
2594
|
},
|
|
2584
2595
|
tokenStorageSlots: {
|
|
2585
2596
|
USDC: { balanceSlot: 1, allowanceSlot: 2 },
|
|
@@ -2596,7 +2607,7 @@ var chainConfigs = {
|
|
|
2596
2607
|
UniswapV3Quoter: "0x0000000000000000000000000000000000000000",
|
|
2597
2608
|
UniswapV4Quoter: "0x0000000000000000000000000000000000000000",
|
|
2598
2609
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2599
|
-
SolverAccount: "
|
|
2610
|
+
SolverAccount: "0x153DB990FE3b761B54ad71D0f1A0987dF11740DB"
|
|
2600
2611
|
},
|
|
2601
2612
|
rpcEnvKey: "BSC_CHAPEL",
|
|
2602
2613
|
defaultRpcUrl: "https://bnb-testnet.api.onfinality.io/public",
|
|
@@ -2722,7 +2733,7 @@ var chainConfigs = {
|
|
|
2722
2733
|
},
|
|
2723
2734
|
addresses: {
|
|
2724
2735
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2725
|
-
SolverAccount: "
|
|
2736
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
2726
2737
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2727
2738
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2728
2739
|
UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
|
|
@@ -2789,7 +2800,7 @@ var chainConfigs = {
|
|
|
2789
2800
|
},
|
|
2790
2801
|
addresses: {
|
|
2791
2802
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2792
|
-
SolverAccount: "
|
|
2803
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
2793
2804
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2794
2805
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2795
2806
|
UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
|
|
@@ -2850,7 +2861,7 @@ var chainConfigs = {
|
|
|
2850
2861
|
},
|
|
2851
2862
|
addresses: {
|
|
2852
2863
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2853
|
-
SolverAccount: "
|
|
2864
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
2854
2865
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2855
2866
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2856
2867
|
UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
|
|
@@ -2924,7 +2935,7 @@ var chainConfigs = {
|
|
|
2924
2935
|
},
|
|
2925
2936
|
addresses: {
|
|
2926
2937
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2927
|
-
SolverAccount: "
|
|
2938
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
2928
2939
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2929
2940
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2930
2941
|
UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
|
|
@@ -2949,7 +2960,6 @@ var chainConfigs = {
|
|
|
2949
2960
|
consensusStateId: "ETH0",
|
|
2950
2961
|
coingeckoId: "base",
|
|
2951
2962
|
layerZeroEid: 30184,
|
|
2952
|
-
uniswapV4Pools: [{ tokens: ["USDC", "cNGN"], fee: 1500, tickSpacing: 30 }],
|
|
2953
2963
|
erc4626Vaults: [
|
|
2954
2964
|
{ label: "Aave stataUSDC", address: "0xC768c589647798a6EE01A91FdE98EF2ed046DBD6", asset: "USDC" },
|
|
2955
2965
|
{ label: "Yield Bearing cNGN", address: "0xa82A3531021317240Fb32E67f9c7bC091F737D3b", asset: "cNGN" }
|
|
@@ -2999,7 +3009,7 @@ var chainConfigs = {
|
|
|
2999
3009
|
},
|
|
3000
3010
|
addresses: {
|
|
3001
3011
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3002
|
-
SolverAccount: "
|
|
3012
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
3003
3013
|
TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
|
|
3004
3014
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3005
3015
|
UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
|
|
@@ -3074,11 +3084,13 @@ var chainConfigs = {
|
|
|
3074
3084
|
//wmatic, change it to wpol
|
|
3075
3085
|
DAI: "0x0000000000000000000000000000000000000000",
|
|
3076
3086
|
USDC: "0xBE97E73126D66188d72fbF99029126D0340a7f18",
|
|
3077
|
-
USDT: "0x0000000000000000000000000000000000000000"
|
|
3087
|
+
USDT: "0x0000000000000000000000000000000000000000",
|
|
3088
|
+
cNGN: "0xe4ff5d2ae65c10f530c000215029919961e8a758"
|
|
3078
3089
|
},
|
|
3079
3090
|
tokenDecimals: {
|
|
3080
3091
|
USDC: 18,
|
|
3081
|
-
USDT: 18
|
|
3092
|
+
USDT: 18,
|
|
3093
|
+
cNGN: 6
|
|
3082
3094
|
},
|
|
3083
3095
|
tokenStorageSlots: {
|
|
3084
3096
|
USDT: { balanceSlot: 0, allowanceSlot: 1 },
|
|
@@ -3091,7 +3103,7 @@ var chainConfigs = {
|
|
|
3091
3103
|
Calldispatcher: "0x876F1891982E260026630c233A4897160A281Fb8",
|
|
3092
3104
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
3093
3105
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
3094
|
-
SolverAccount: "
|
|
3106
|
+
SolverAccount: "0x153DB990FE3b761B54ad71D0f1A0987dF11740DB"
|
|
3095
3107
|
},
|
|
3096
3108
|
rpcEnvKey: "POLYGON_AMOY",
|
|
3097
3109
|
defaultRpcUrl: "https://rpc-amoy.polygon.technology",
|
|
@@ -3115,7 +3127,7 @@ var chainConfigs = {
|
|
|
3115
3127
|
},
|
|
3116
3128
|
addresses: {
|
|
3117
3129
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3118
|
-
SolverAccount: "
|
|
3130
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
3119
3131
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
3120
3132
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3121
3133
|
UniswapRouter02: "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2",
|
|
@@ -3150,7 +3162,7 @@ var chainConfigs = {
|
|
|
3150
3162
|
},
|
|
3151
3163
|
addresses: {
|
|
3152
3164
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3153
|
-
SolverAccount: "
|
|
3165
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
3154
3166
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
3155
3167
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3156
3168
|
UniswapRouter02: "0xB2e26652e4BAd1e56055A051f922E06760cA0BFE",
|
|
@@ -3306,7 +3318,7 @@ var chainConfigs = {
|
|
|
3306
3318
|
},
|
|
3307
3319
|
addresses: {
|
|
3308
3320
|
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3309
|
-
SolverAccount: "
|
|
3321
|
+
SolverAccount: "0xd5535d4DeB17F050e52B6efda2fDe00435f39279",
|
|
3310
3322
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3311
3323
|
Calldispatcher: "0xE2C7e576E26E0bE7aC97c6fE925bcDAbD87c4bEd"
|
|
3312
3324
|
},
|
|
@@ -3353,7 +3365,12 @@ var ABI3 = [
|
|
|
3353
3365
|
type: "constructor",
|
|
3354
3366
|
inputs: [
|
|
3355
3367
|
{
|
|
3356
|
-
name: "
|
|
3368
|
+
name: "intrinsic",
|
|
3369
|
+
type: "address",
|
|
3370
|
+
internalType: "address"
|
|
3371
|
+
},
|
|
3372
|
+
{
|
|
3373
|
+
name: "extrinsic",
|
|
3357
3374
|
type: "address",
|
|
3358
3375
|
internalType: "address"
|
|
3359
3376
|
}
|
|
@@ -3452,8 +3469,8 @@ var ABI3 = [
|
|
|
3452
3469
|
},
|
|
3453
3470
|
{
|
|
3454
3471
|
name: "",
|
|
3455
|
-
type: "
|
|
3456
|
-
internalType: "
|
|
3472
|
+
type: "uint256",
|
|
3473
|
+
internalType: "uint256"
|
|
3457
3474
|
}
|
|
3458
3475
|
],
|
|
3459
3476
|
outputs: [
|
|
@@ -3467,20 +3484,31 @@ var ABI3 = [
|
|
|
3467
3484
|
},
|
|
3468
3485
|
{
|
|
3469
3486
|
type: "function",
|
|
3470
|
-
name: "
|
|
3471
|
-
inputs: [
|
|
3487
|
+
name: "_partialFills",
|
|
3488
|
+
inputs: [
|
|
3489
|
+
{
|
|
3490
|
+
name: "",
|
|
3491
|
+
type: "bytes32",
|
|
3492
|
+
internalType: "bytes32"
|
|
3493
|
+
},
|
|
3494
|
+
{
|
|
3495
|
+
name: "",
|
|
3496
|
+
type: "uint256",
|
|
3497
|
+
internalType: "uint256"
|
|
3498
|
+
}
|
|
3499
|
+
],
|
|
3472
3500
|
outputs: [
|
|
3473
3501
|
{
|
|
3474
3502
|
name: "",
|
|
3475
|
-
type: "
|
|
3476
|
-
internalType: "
|
|
3503
|
+
type: "uint256",
|
|
3504
|
+
internalType: "uint256"
|
|
3477
3505
|
}
|
|
3478
3506
|
],
|
|
3479
3507
|
stateMutability: "view"
|
|
3480
3508
|
},
|
|
3481
3509
|
{
|
|
3482
3510
|
type: "function",
|
|
3483
|
-
name: "
|
|
3511
|
+
name: "_protocolFees",
|
|
3484
3512
|
inputs: [
|
|
3485
3513
|
{
|
|
3486
3514
|
name: "",
|
|
@@ -3489,19 +3517,31 @@ var ABI3 = [
|
|
|
3489
3517
|
},
|
|
3490
3518
|
{
|
|
3491
3519
|
name: "",
|
|
3492
|
-
type: "
|
|
3493
|
-
internalType: "
|
|
3520
|
+
type: "uint256",
|
|
3521
|
+
internalType: "uint256"
|
|
3494
3522
|
}
|
|
3495
3523
|
],
|
|
3496
3524
|
outputs: [
|
|
3497
3525
|
{
|
|
3498
|
-
name: "",
|
|
3526
|
+
name: "amount",
|
|
3527
|
+
type: "uint256",
|
|
3528
|
+
internalType: "uint256"
|
|
3529
|
+
},
|
|
3530
|
+
{
|
|
3531
|
+
name: "committed",
|
|
3499
3532
|
type: "uint256",
|
|
3500
3533
|
internalType: "uint256"
|
|
3501
3534
|
}
|
|
3502
3535
|
],
|
|
3503
3536
|
stateMutability: "view"
|
|
3504
3537
|
},
|
|
3538
|
+
{
|
|
3539
|
+
type: "function",
|
|
3540
|
+
name: "acceptOwnership",
|
|
3541
|
+
inputs: [],
|
|
3542
|
+
outputs: [],
|
|
3543
|
+
stateMutability: "nonpayable"
|
|
3544
|
+
},
|
|
3505
3545
|
{
|
|
3506
3546
|
type: "function",
|
|
3507
3547
|
name: "calculateCommitmentSlotHash",
|
|
@@ -3711,6 +3751,19 @@ var ABI3 = [
|
|
|
3711
3751
|
],
|
|
3712
3752
|
stateMutability: "view"
|
|
3713
3753
|
},
|
|
3754
|
+
{
|
|
3755
|
+
type: "function",
|
|
3756
|
+
name: "extrinsicModule",
|
|
3757
|
+
inputs: [],
|
|
3758
|
+
outputs: [
|
|
3759
|
+
{
|
|
3760
|
+
name: "",
|
|
3761
|
+
type: "address",
|
|
3762
|
+
internalType: "address"
|
|
3763
|
+
}
|
|
3764
|
+
],
|
|
3765
|
+
stateMutability: "view"
|
|
3766
|
+
},
|
|
3714
3767
|
{
|
|
3715
3768
|
type: "function",
|
|
3716
3769
|
name: "fillOrder",
|
|
@@ -3873,6 +3926,23 @@ var ABI3 = [
|
|
|
3873
3926
|
internalType: "uint256"
|
|
3874
3927
|
}
|
|
3875
3928
|
]
|
|
3929
|
+
},
|
|
3930
|
+
{
|
|
3931
|
+
name: "inputs",
|
|
3932
|
+
type: "tuple[]",
|
|
3933
|
+
internalType: "struct TokenInfo[]",
|
|
3934
|
+
components: [
|
|
3935
|
+
{
|
|
3936
|
+
name: "token",
|
|
3937
|
+
type: "bytes32",
|
|
3938
|
+
internalType: "bytes32"
|
|
3939
|
+
},
|
|
3940
|
+
{
|
|
3941
|
+
name: "amount",
|
|
3942
|
+
type: "uint256",
|
|
3943
|
+
internalType: "uint256"
|
|
3944
|
+
}
|
|
3945
|
+
]
|
|
3876
3946
|
}
|
|
3877
3947
|
]
|
|
3878
3948
|
}
|
|
@@ -3898,51 +3968,63 @@ var ABI3 = [
|
|
|
3898
3968
|
name: "initialize",
|
|
3899
3969
|
inputs: [
|
|
3900
3970
|
{
|
|
3901
|
-
name: "
|
|
3971
|
+
name: "init",
|
|
3902
3972
|
type: "tuple",
|
|
3903
|
-
internalType: "struct
|
|
3973
|
+
internalType: "struct InitParams",
|
|
3904
3974
|
components: [
|
|
3905
3975
|
{
|
|
3906
|
-
name: "
|
|
3907
|
-
type: "
|
|
3908
|
-
internalType: "
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3976
|
+
name: "params",
|
|
3977
|
+
type: "tuple",
|
|
3978
|
+
internalType: "struct Params",
|
|
3979
|
+
components: [
|
|
3980
|
+
{
|
|
3981
|
+
name: "host",
|
|
3982
|
+
type: "address",
|
|
3983
|
+
internalType: "address"
|
|
3984
|
+
},
|
|
3985
|
+
{
|
|
3986
|
+
name: "dispatcher",
|
|
3987
|
+
type: "address",
|
|
3988
|
+
internalType: "address"
|
|
3989
|
+
},
|
|
3990
|
+
{
|
|
3991
|
+
name: "solverSelection",
|
|
3992
|
+
type: "bool",
|
|
3993
|
+
internalType: "bool"
|
|
3994
|
+
},
|
|
3995
|
+
{
|
|
3996
|
+
name: "surplusShareBps",
|
|
3997
|
+
type: "uint256",
|
|
3998
|
+
internalType: "uint256"
|
|
3999
|
+
},
|
|
4000
|
+
{
|
|
4001
|
+
name: "protocolFeeBps",
|
|
4002
|
+
type: "uint256",
|
|
4003
|
+
internalType: "uint256"
|
|
4004
|
+
},
|
|
4005
|
+
{
|
|
4006
|
+
name: "priceOracle",
|
|
4007
|
+
type: "address",
|
|
4008
|
+
internalType: "address"
|
|
4009
|
+
}
|
|
4010
|
+
]
|
|
3919
4011
|
},
|
|
3920
4012
|
{
|
|
3921
|
-
name: "
|
|
3922
|
-
type: "
|
|
3923
|
-
internalType: "
|
|
4013
|
+
name: "peerChains",
|
|
4014
|
+
type: "bytes[]",
|
|
4015
|
+
internalType: "bytes[]"
|
|
3924
4016
|
},
|
|
3925
4017
|
{
|
|
3926
|
-
name: "
|
|
3927
|
-
type: "
|
|
3928
|
-
internalType: "
|
|
4018
|
+
name: "relayer",
|
|
4019
|
+
type: "address",
|
|
4020
|
+
internalType: "address"
|
|
3929
4021
|
},
|
|
3930
4022
|
{
|
|
3931
|
-
name: "
|
|
4023
|
+
name: "owner",
|
|
3932
4024
|
type: "address",
|
|
3933
4025
|
internalType: "address"
|
|
3934
4026
|
}
|
|
3935
4027
|
]
|
|
3936
|
-
},
|
|
3937
|
-
{
|
|
3938
|
-
name: "peerChains",
|
|
3939
|
-
type: "bytes[]",
|
|
3940
|
-
internalType: "bytes[]"
|
|
3941
|
-
},
|
|
3942
|
-
{
|
|
3943
|
-
name: "relayer",
|
|
3944
|
-
type: "address",
|
|
3945
|
-
internalType: "address"
|
|
3946
4028
|
}
|
|
3947
4029
|
],
|
|
3948
4030
|
outputs: [],
|
|
@@ -3967,12 +4049,25 @@ var ABI3 = [
|
|
|
3967
4049
|
],
|
|
3968
4050
|
stateMutability: "view"
|
|
3969
4051
|
},
|
|
4052
|
+
{
|
|
4053
|
+
type: "function",
|
|
4054
|
+
name: "intrinsicModule",
|
|
4055
|
+
inputs: [],
|
|
4056
|
+
outputs: [
|
|
4057
|
+
{
|
|
4058
|
+
name: "",
|
|
4059
|
+
type: "address",
|
|
4060
|
+
internalType: "address"
|
|
4061
|
+
}
|
|
4062
|
+
],
|
|
4063
|
+
stateMutability: "view"
|
|
4064
|
+
},
|
|
3970
4065
|
{
|
|
3971
4066
|
type: "function",
|
|
3972
4067
|
name: "migrate",
|
|
3973
4068
|
inputs: [
|
|
3974
4069
|
{
|
|
3975
|
-
name: "
|
|
4070
|
+
name: "owner_",
|
|
3976
4071
|
type: "address",
|
|
3977
4072
|
internalType: "address"
|
|
3978
4073
|
}
|
|
@@ -4047,7 +4142,7 @@ var ABI3 = [
|
|
|
4047
4142
|
name: "onGetResponse",
|
|
4048
4143
|
inputs: [
|
|
4049
4144
|
{
|
|
4050
|
-
name: "
|
|
4145
|
+
name: "",
|
|
4051
4146
|
type: "tuple",
|
|
4052
4147
|
internalType: "struct IncomingGetResponse",
|
|
4053
4148
|
components: [
|
|
@@ -4262,6 +4357,19 @@ var ABI3 = [
|
|
|
4262
4357
|
outputs: [],
|
|
4263
4358
|
stateMutability: "nonpayable"
|
|
4264
4359
|
},
|
|
4360
|
+
{
|
|
4361
|
+
type: "function",
|
|
4362
|
+
name: "owner",
|
|
4363
|
+
inputs: [],
|
|
4364
|
+
outputs: [
|
|
4365
|
+
{
|
|
4366
|
+
name: "",
|
|
4367
|
+
type: "address",
|
|
4368
|
+
internalType: "address"
|
|
4369
|
+
}
|
|
4370
|
+
],
|
|
4371
|
+
stateMutability: "view"
|
|
4372
|
+
},
|
|
4265
4373
|
{
|
|
4266
4374
|
type: "function",
|
|
4267
4375
|
name: "params",
|
|
@@ -4307,6 +4415,39 @@ var ABI3 = [
|
|
|
4307
4415
|
],
|
|
4308
4416
|
stateMutability: "view"
|
|
4309
4417
|
},
|
|
4418
|
+
{
|
|
4419
|
+
type: "function",
|
|
4420
|
+
name: "pause",
|
|
4421
|
+
inputs: [],
|
|
4422
|
+
outputs: [],
|
|
4423
|
+
stateMutability: "nonpayable"
|
|
4424
|
+
},
|
|
4425
|
+
{
|
|
4426
|
+
type: "function",
|
|
4427
|
+
name: "paused",
|
|
4428
|
+
inputs: [],
|
|
4429
|
+
outputs: [
|
|
4430
|
+
{
|
|
4431
|
+
name: "",
|
|
4432
|
+
type: "bool",
|
|
4433
|
+
internalType: "bool"
|
|
4434
|
+
}
|
|
4435
|
+
],
|
|
4436
|
+
stateMutability: "view"
|
|
4437
|
+
},
|
|
4438
|
+
{
|
|
4439
|
+
type: "function",
|
|
4440
|
+
name: "pendingOwner",
|
|
4441
|
+
inputs: [],
|
|
4442
|
+
outputs: [
|
|
4443
|
+
{
|
|
4444
|
+
name: "",
|
|
4445
|
+
type: "address",
|
|
4446
|
+
internalType: "address"
|
|
4447
|
+
}
|
|
4448
|
+
],
|
|
4449
|
+
stateMutability: "view"
|
|
4450
|
+
},
|
|
4310
4451
|
{
|
|
4311
4452
|
type: "function",
|
|
4312
4453
|
name: "placeOrder",
|
|
@@ -4562,6 +4703,13 @@ var ABI3 = [
|
|
|
4562
4703
|
],
|
|
4563
4704
|
stateMutability: "view"
|
|
4564
4705
|
},
|
|
4706
|
+
{
|
|
4707
|
+
type: "function",
|
|
4708
|
+
name: "renounceOwnership",
|
|
4709
|
+
inputs: [],
|
|
4710
|
+
outputs: [],
|
|
4711
|
+
stateMutability: "nonpayable"
|
|
4712
|
+
},
|
|
4565
4713
|
{
|
|
4566
4714
|
type: "function",
|
|
4567
4715
|
name: "select",
|
|
@@ -4600,10 +4748,10 @@ var ABI3 = [
|
|
|
4600
4748
|
},
|
|
4601
4749
|
{
|
|
4602
4750
|
type: "function",
|
|
4603
|
-
name: "
|
|
4751
|
+
name: "transferOwnership",
|
|
4604
4752
|
inputs: [
|
|
4605
4753
|
{
|
|
4606
|
-
name: "
|
|
4754
|
+
name: "newOwner",
|
|
4607
4755
|
type: "address",
|
|
4608
4756
|
internalType: "address"
|
|
4609
4757
|
}
|
|
@@ -4613,19 +4761,8 @@ var ABI3 = [
|
|
|
4613
4761
|
},
|
|
4614
4762
|
{
|
|
4615
4763
|
type: "function",
|
|
4616
|
-
name: "
|
|
4617
|
-
inputs: [
|
|
4618
|
-
{
|
|
4619
|
-
name: "newImplementation",
|
|
4620
|
-
type: "address",
|
|
4621
|
-
internalType: "address"
|
|
4622
|
-
},
|
|
4623
|
-
{
|
|
4624
|
-
name: "data",
|
|
4625
|
-
type: "bytes",
|
|
4626
|
-
internalType: "bytes"
|
|
4627
|
-
}
|
|
4628
|
-
],
|
|
4764
|
+
name: "unpause",
|
|
4765
|
+
inputs: [],
|
|
4629
4766
|
outputs: [],
|
|
4630
4767
|
stateMutability: "nonpayable"
|
|
4631
4768
|
},
|
|
@@ -4771,6 +4908,12 @@ var ABI3 = [
|
|
|
4771
4908
|
indexed: true,
|
|
4772
4909
|
internalType: "bytes32"
|
|
4773
4910
|
},
|
|
4911
|
+
{
|
|
4912
|
+
name: "solver",
|
|
4913
|
+
type: "address",
|
|
4914
|
+
indexed: false,
|
|
4915
|
+
internalType: "address"
|
|
4916
|
+
},
|
|
4774
4917
|
{
|
|
4775
4918
|
name: "tokens",
|
|
4776
4919
|
type: "tuple[]",
|
|
@@ -5008,37 +5151,75 @@ var ABI3 = [
|
|
|
5008
5151
|
},
|
|
5009
5152
|
{
|
|
5010
5153
|
type: "event",
|
|
5011
|
-
name: "
|
|
5154
|
+
name: "OwnershipTransferStarted",
|
|
5012
5155
|
inputs: [
|
|
5013
5156
|
{
|
|
5014
|
-
name: "
|
|
5015
|
-
type: "
|
|
5016
|
-
indexed:
|
|
5017
|
-
internalType: "
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5157
|
+
name: "previousOwner",
|
|
5158
|
+
type: "address",
|
|
5159
|
+
indexed: true,
|
|
5160
|
+
internalType: "address"
|
|
5161
|
+
},
|
|
5162
|
+
{
|
|
5163
|
+
name: "newOwner",
|
|
5164
|
+
type: "address",
|
|
5165
|
+
indexed: true,
|
|
5166
|
+
internalType: "address"
|
|
5167
|
+
}
|
|
5168
|
+
],
|
|
5169
|
+
anonymous: false
|
|
5170
|
+
},
|
|
5171
|
+
{
|
|
5172
|
+
type: "event",
|
|
5173
|
+
name: "OwnershipTransferred",
|
|
5174
|
+
inputs: [
|
|
5175
|
+
{
|
|
5176
|
+
name: "previousOwner",
|
|
5177
|
+
type: "address",
|
|
5178
|
+
indexed: true,
|
|
5179
|
+
internalType: "address"
|
|
5180
|
+
},
|
|
5181
|
+
{
|
|
5182
|
+
name: "newOwner",
|
|
5183
|
+
type: "address",
|
|
5184
|
+
indexed: true,
|
|
5185
|
+
internalType: "address"
|
|
5186
|
+
}
|
|
5187
|
+
],
|
|
5188
|
+
anonymous: false
|
|
5189
|
+
},
|
|
5190
|
+
{
|
|
5191
|
+
type: "event",
|
|
5192
|
+
name: "ParamsUpdated",
|
|
5193
|
+
inputs: [
|
|
5194
|
+
{
|
|
5195
|
+
name: "previous",
|
|
5196
|
+
type: "tuple",
|
|
5197
|
+
indexed: false,
|
|
5198
|
+
internalType: "struct Params",
|
|
5199
|
+
components: [
|
|
5200
|
+
{
|
|
5201
|
+
name: "host",
|
|
5202
|
+
type: "address",
|
|
5203
|
+
internalType: "address"
|
|
5204
|
+
},
|
|
5205
|
+
{
|
|
5206
|
+
name: "dispatcher",
|
|
5207
|
+
type: "address",
|
|
5208
|
+
internalType: "address"
|
|
5209
|
+
},
|
|
5210
|
+
{
|
|
5211
|
+
name: "solverSelection",
|
|
5212
|
+
type: "bool",
|
|
5213
|
+
internalType: "bool"
|
|
5214
|
+
},
|
|
5215
|
+
{
|
|
5216
|
+
name: "surplusShareBps",
|
|
5217
|
+
type: "uint256",
|
|
5218
|
+
internalType: "uint256"
|
|
5219
|
+
},
|
|
5220
|
+
{
|
|
5221
|
+
name: "protocolFeeBps",
|
|
5222
|
+
type: "uint256",
|
|
5042
5223
|
internalType: "uint256"
|
|
5043
5224
|
},
|
|
5044
5225
|
{
|
|
@@ -5146,46 +5327,73 @@ var ABI3 = [
|
|
|
5146
5327
|
},
|
|
5147
5328
|
{
|
|
5148
5329
|
type: "event",
|
|
5149
|
-
name: "
|
|
5330
|
+
name: "Paused",
|
|
5150
5331
|
inputs: [
|
|
5151
5332
|
{
|
|
5152
|
-
name: "
|
|
5333
|
+
name: "account",
|
|
5153
5334
|
type: "address",
|
|
5154
5335
|
indexed: false,
|
|
5155
5336
|
internalType: "address"
|
|
5337
|
+
}
|
|
5338
|
+
],
|
|
5339
|
+
anonymous: false
|
|
5340
|
+
},
|
|
5341
|
+
{
|
|
5342
|
+
type: "event",
|
|
5343
|
+
name: "ProtocolFeeRefunded",
|
|
5344
|
+
inputs: [
|
|
5345
|
+
{
|
|
5346
|
+
name: "commitment",
|
|
5347
|
+
type: "bytes32",
|
|
5348
|
+
indexed: true,
|
|
5349
|
+
internalType: "bytes32"
|
|
5156
5350
|
},
|
|
5157
5351
|
{
|
|
5158
|
-
name: "
|
|
5352
|
+
name: "token",
|
|
5159
5353
|
type: "address",
|
|
5160
|
-
indexed:
|
|
5354
|
+
indexed: true,
|
|
5161
5355
|
internalType: "address"
|
|
5356
|
+
},
|
|
5357
|
+
{
|
|
5358
|
+
name: "amount",
|
|
5359
|
+
type: "uint256",
|
|
5360
|
+
indexed: false,
|
|
5361
|
+
internalType: "uint256"
|
|
5162
5362
|
}
|
|
5163
5363
|
],
|
|
5164
5364
|
anonymous: false
|
|
5165
5365
|
},
|
|
5166
5366
|
{
|
|
5167
5367
|
type: "event",
|
|
5168
|
-
name: "
|
|
5368
|
+
name: "RelayerUpdated",
|
|
5169
5369
|
inputs: [
|
|
5170
5370
|
{
|
|
5171
|
-
name: "
|
|
5371
|
+
name: "previous",
|
|
5172
5372
|
type: "address",
|
|
5173
|
-
indexed:
|
|
5373
|
+
indexed: false,
|
|
5374
|
+
internalType: "address"
|
|
5375
|
+
},
|
|
5376
|
+
{
|
|
5377
|
+
name: "current",
|
|
5378
|
+
type: "address",
|
|
5379
|
+
indexed: false,
|
|
5174
5380
|
internalType: "address"
|
|
5175
5381
|
}
|
|
5176
5382
|
],
|
|
5177
5383
|
anonymous: false
|
|
5178
5384
|
},
|
|
5179
5385
|
{
|
|
5180
|
-
type: "
|
|
5181
|
-
name: "
|
|
5386
|
+
type: "event",
|
|
5387
|
+
name: "Unpaused",
|
|
5182
5388
|
inputs: [
|
|
5183
5389
|
{
|
|
5184
|
-
name: "
|
|
5390
|
+
name: "account",
|
|
5185
5391
|
type: "address",
|
|
5392
|
+
indexed: false,
|
|
5186
5393
|
internalType: "address"
|
|
5187
5394
|
}
|
|
5188
|
-
]
|
|
5395
|
+
],
|
|
5396
|
+
anonymous: false
|
|
5189
5397
|
},
|
|
5190
5398
|
{
|
|
5191
5399
|
type: "error",
|
|
@@ -5221,28 +5429,17 @@ var ABI3 = [
|
|
|
5221
5429
|
},
|
|
5222
5430
|
{
|
|
5223
5431
|
type: "error",
|
|
5224
|
-
name: "
|
|
5225
|
-
inputs: [
|
|
5226
|
-
{
|
|
5227
|
-
name: "implementation",
|
|
5228
|
-
type: "address",
|
|
5229
|
-
internalType: "address"
|
|
5230
|
-
}
|
|
5231
|
-
]
|
|
5232
|
-
},
|
|
5233
|
-
{
|
|
5234
|
-
type: "error",
|
|
5235
|
-
name: "ERC1967NonPayable",
|
|
5432
|
+
name: "EnforcedPause",
|
|
5236
5433
|
inputs: []
|
|
5237
5434
|
},
|
|
5238
5435
|
{
|
|
5239
5436
|
type: "error",
|
|
5240
|
-
name: "
|
|
5437
|
+
name: "ExpectedPause",
|
|
5241
5438
|
inputs: []
|
|
5242
5439
|
},
|
|
5243
5440
|
{
|
|
5244
5441
|
type: "error",
|
|
5245
|
-
name: "
|
|
5442
|
+
name: "Expired",
|
|
5246
5443
|
inputs: []
|
|
5247
5444
|
},
|
|
5248
5445
|
{
|
|
@@ -5285,11 +5482,43 @@ var ABI3 = [
|
|
|
5285
5482
|
name: "NotInitializing",
|
|
5286
5483
|
inputs: []
|
|
5287
5484
|
},
|
|
5485
|
+
{
|
|
5486
|
+
type: "error",
|
|
5487
|
+
name: "OwnableInvalidOwner",
|
|
5488
|
+
inputs: [
|
|
5489
|
+
{
|
|
5490
|
+
name: "owner",
|
|
5491
|
+
type: "address",
|
|
5492
|
+
internalType: "address"
|
|
5493
|
+
}
|
|
5494
|
+
]
|
|
5495
|
+
},
|
|
5496
|
+
{
|
|
5497
|
+
type: "error",
|
|
5498
|
+
name: "OwnableUnauthorizedAccount",
|
|
5499
|
+
inputs: [
|
|
5500
|
+
{
|
|
5501
|
+
name: "account",
|
|
5502
|
+
type: "address",
|
|
5503
|
+
internalType: "address"
|
|
5504
|
+
}
|
|
5505
|
+
]
|
|
5506
|
+
},
|
|
5288
5507
|
{
|
|
5289
5508
|
type: "error",
|
|
5290
5509
|
name: "PartialFillNotAllowed",
|
|
5291
5510
|
inputs: []
|
|
5292
5511
|
},
|
|
5512
|
+
{
|
|
5513
|
+
type: "error",
|
|
5514
|
+
name: "RateBelowOrder",
|
|
5515
|
+
inputs: []
|
|
5516
|
+
},
|
|
5517
|
+
{
|
|
5518
|
+
type: "error",
|
|
5519
|
+
name: "RateFillTooSmall",
|
|
5520
|
+
inputs: []
|
|
5521
|
+
},
|
|
5293
5522
|
{
|
|
5294
5523
|
type: "error",
|
|
5295
5524
|
name: "ReentrancyGuardReentrantCall",
|
|
@@ -5517,9 +5746,6 @@ var ChainConfigService = class {
|
|
|
5517
5746
|
getUniswapV4StateViewAddress(chain) {
|
|
5518
5747
|
return this.getConfig(chain)?.addresses.UniswapV4StateView ?? "0x";
|
|
5519
5748
|
}
|
|
5520
|
-
getUniswapV4PoolConfigs(chain) {
|
|
5521
|
-
return this.getConfig(chain)?.uniswapV4Pools ?? [];
|
|
5522
|
-
}
|
|
5523
5749
|
getPermit2Address(chain) {
|
|
5524
5750
|
return this.getConfig(chain)?.addresses.Permit2 ?? "0x";
|
|
5525
5751
|
}
|
|
@@ -8256,9 +8482,7 @@ Failed HTTP Request: ${JSON.stringify(
|
|
|
8256
8482
|
};
|
|
8257
8483
|
|
|
8258
8484
|
// src/chains/intentsCoprocessor.ts
|
|
8259
|
-
var SYSTEM_EVENTS_KEY = util.u8aToHex(util.u8aConcat(utilCrypto.xxhashAsU8a("System", 128), utilCrypto.xxhashAsU8a("Events", 128)));
|
|
8260
8485
|
var OFFCHAIN_BID_PREFIX = new TextEncoder().encode("intents::bid::");
|
|
8261
|
-
var OFFCHAIN_PHANTOM_PREFIX = new TextEncoder().encode("intents::phantom::order::");
|
|
8262
8486
|
var HYPERBRIDGE_TYPES_BUNDLE = {
|
|
8263
8487
|
spec: {
|
|
8264
8488
|
nexus: { hasher: utilCrypto.keccakAsU8a },
|
|
@@ -8268,11 +8492,7 @@ var HYPERBRIDGE_TYPES_BUNDLE = {
|
|
|
8268
8492
|
var BASE_TIP = 1000000000n;
|
|
8269
8493
|
var HTTP_CONNECT_TIMEOUT_MS = 2e4;
|
|
8270
8494
|
var INCLUSION_TIMEOUT_MS = 2e4;
|
|
8271
|
-
var PHANTOM_POLL_INTERVAL_MS = 15e3;
|
|
8272
|
-
var GARGANTUA_PHANTOM_POLL_INTERVAL_MS = 6e3;
|
|
8273
8495
|
var DEFAULT_RPC_MAX_RPS = 8;
|
|
8274
|
-
var DEFAULT_MAX_BLOCKS_PER_POLL = 10;
|
|
8275
|
-
var MAX_RATE_LIMIT_BACKOFF_TICKS = 8;
|
|
8276
8496
|
var rpcLimiters = /* @__PURE__ */ new Map();
|
|
8277
8497
|
function limiterFor(httpUrl) {
|
|
8278
8498
|
const key = new URL(httpUrl).origin;
|
|
@@ -8288,45 +8508,6 @@ function configuredRpcMaxRps() {
|
|
|
8288
8508
|
const parsed = raw === void 0 ? Number.NaN : Number(raw);
|
|
8289
8509
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_RPC_MAX_RPS;
|
|
8290
8510
|
}
|
|
8291
|
-
function isRateLimited(err) {
|
|
8292
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
8293
|
-
return message.includes("[429]") || /too many requests/i.test(message);
|
|
8294
|
-
}
|
|
8295
|
-
function isMethodUnavailable(err) {
|
|
8296
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
8297
|
-
const code = err?.code;
|
|
8298
|
-
return code === -32601 || /method not found|unsafe to be called externally/i.test(message);
|
|
8299
|
-
}
|
|
8300
|
-
var EventDecodeError = class extends Error {
|
|
8301
|
-
};
|
|
8302
|
-
function phantomOrdersFrom(records) {
|
|
8303
|
-
if (records == null || typeof records[Symbol.iterator] !== "function") {
|
|
8304
|
-
throw new EventDecodeError(`Expected a decoded event vector, got ${typeof records}`);
|
|
8305
|
-
}
|
|
8306
|
-
const orders = [];
|
|
8307
|
-
for (const record of records) {
|
|
8308
|
-
if (typeof record !== "object" || record === null || !("event" in record)) {
|
|
8309
|
-
throw new EventDecodeError(
|
|
8310
|
-
"system.events did not decode to event records \u2014 the storage entry's metadata was probably not carried through, leaving the value as raw bytes"
|
|
8311
|
-
);
|
|
8312
|
-
}
|
|
8313
|
-
const { event } = record;
|
|
8314
|
-
if (event.section !== "intentsCoprocessor" || event.method !== "PhantomOrderRegistered") continue;
|
|
8315
|
-
const [commitment, chain, createdAt, legs] = event.data;
|
|
8316
|
-
orders.push({
|
|
8317
|
-
commitment: commitment.toHex(),
|
|
8318
|
-
chain: new TextDecoder().decode(util.hexToU8a(chain.toHex())),
|
|
8319
|
-
createdAt: createdAt.toNumber(),
|
|
8320
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8321
|
-
legs: legs.map((leg) => ({
|
|
8322
|
-
tokenA: leg.tokenA.toHex(),
|
|
8323
|
-
tokenB: leg.tokenB.toHex(),
|
|
8324
|
-
standardAmount: BigInt(leg.standardAmount.toString())
|
|
8325
|
-
}))
|
|
8326
|
-
});
|
|
8327
|
-
}
|
|
8328
|
-
return orders;
|
|
8329
|
-
}
|
|
8330
8511
|
function rejectAfter(ms, message) {
|
|
8331
8512
|
return new Promise((_resolve, reject) => {
|
|
8332
8513
|
const timer = setTimeout(() => reject(new Error(message)), ms);
|
|
@@ -8398,19 +8579,16 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8398
8579
|
ownsConnection;
|
|
8399
8580
|
/** Cached result of whether the node exposes intents_* RPC methods */
|
|
8400
8581
|
hasIntentsRpc = null;
|
|
8401
|
-
/** The pallet's phantom timings, read once. Cleared on failure so the read retries. */
|
|
8402
|
-
phantomTimingsRead = null;
|
|
8403
8582
|
/** The HTTP-backed api, connected on first use. Cleared after a failed attempt so it retries. */
|
|
8404
8583
|
httpApi = null;
|
|
8405
|
-
/** Last runtime version read from the node, for {@link confirmedRuntimeVersion} to compare against. */
|
|
8406
|
-
lastRuntimeVersion;
|
|
8407
|
-
/** Set once the node refuses `state_queryStorage`, so the poll stops asking for it. */
|
|
8408
|
-
rangeQueryUnavailable = false;
|
|
8409
8584
|
// Serialises every extrinsic submission on this instance's substrate account. All submit/retract
|
|
8410
|
-
// methods funnel through signAndSendExtrinsic
|
|
8411
|
-
//
|
|
8412
|
-
//
|
|
8585
|
+
// methods funnel through signAndSendExtrinsic; fired in parallel (bids for orders on different
|
|
8586
|
+
// chains, or several bids on one order) they would grab the same nonce and all but one would
|
|
8587
|
+
// fail. Concurrency 1 sequences them, and {@link nextNonce} keeps consecutive submissions off
|
|
8588
|
+
// each other's nonce even while the first is still in the pool.
|
|
8413
8589
|
submissionQueue = new PQueue__default.default({ concurrency: 1 });
|
|
8590
|
+
/** The highest nonce this instance has put into the pool, so the next submission clears it. */
|
|
8591
|
+
lastPooledNonce;
|
|
8414
8592
|
/**
|
|
8415
8593
|
* Creates and connects an IntentsCoprocessor to a Hyperbridge node.
|
|
8416
8594
|
* This creates and manages its own API connection.
|
|
@@ -8472,10 +8650,10 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8472
8650
|
* The HTTP api is always created here, so it is always ours to close.
|
|
8473
8651
|
*/
|
|
8474
8652
|
async disconnect() {
|
|
8475
|
-
const
|
|
8653
|
+
const http3 = this.httpApi;
|
|
8476
8654
|
this.httpApi = null;
|
|
8477
|
-
if (
|
|
8478
|
-
await
|
|
8655
|
+
if (http3) {
|
|
8656
|
+
await http3.then((api) => api.disconnect()).catch(() => {
|
|
8479
8657
|
});
|
|
8480
8658
|
}
|
|
8481
8659
|
if (this.ownsConnection) {
|
|
@@ -8489,9 +8667,8 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8489
8667
|
*
|
|
8490
8668
|
* The connection attempt is bounded on both sides. `isReadyOrError` rejects on a failed
|
|
8491
8669
|
* handshake, where plain `isReady` would simply never resolve, and the timeout covers an
|
|
8492
|
-
* endpoint that accepts the request and then goes quiet
|
|
8493
|
-
*
|
|
8494
|
-
* failed attempt is not cached, so the next call tries again.
|
|
8670
|
+
* endpoint that accepts the request and then goes quiet, so a caller awaiting it never hangs
|
|
8671
|
+
* silently. A failed attempt is not cached, so the next call tries again.
|
|
8495
8672
|
*/
|
|
8496
8673
|
async http() {
|
|
8497
8674
|
if (!this.httpApi) {
|
|
@@ -8500,11 +8677,9 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8500
8677
|
// Response cache off (third argument, capacity 0). polkadot-js caches every request that
|
|
8501
8678
|
// names a block hash — `chain_getHeader(hash)`, `state_getRuntimeVersion(hash)`, storage
|
|
8502
8679
|
// reads at a hash — by storing the request promise itself, a rejected one included, for a
|
|
8503
|
-
// 30s TTL that every hit refreshes.
|
|
8504
|
-
//
|
|
8505
|
-
//
|
|
8506
|
-
// saw a second request. The cache bought nothing here anyway: the poll reads each block
|
|
8507
|
-
// once, and `api.at(hash)` reuses registries at the api layer regardless.
|
|
8680
|
+
// 30s TTL that every hit refreshes. A caller retrying a failed read with identical
|
|
8681
|
+
// parameters would get the same rejection replayed from memory for as long as it kept
|
|
8682
|
+
// retrying inside the TTL, and the node would never see a second request.
|
|
8508
8683
|
// Concurrent calls are coalesced into one JSON-RPC batch request, and every request
|
|
8509
8684
|
// to this endpoint is paced by a bucket shared with any other coprocessor in this
|
|
8510
8685
|
// process pointed at the same host — the limit is the server's, and it counts
|
|
@@ -8579,7 +8754,12 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8579
8754
|
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
8580
8755
|
}
|
|
8581
8756
|
}
|
|
8582
|
-
return await this.sendExtrinsicWithRetries(
|
|
8757
|
+
return await this.sendExtrinsicWithRetries(
|
|
8758
|
+
build(this.api),
|
|
8759
|
+
maxRetries,
|
|
8760
|
+
timeoutMs,
|
|
8761
|
+
await this.nextNonce(this.api)
|
|
8762
|
+
);
|
|
8583
8763
|
});
|
|
8584
8764
|
return result ?? { success: false, error: "Submission queue returned no result" };
|
|
8585
8765
|
}
|
|
@@ -8598,7 +8778,10 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8598
8778
|
*/
|
|
8599
8779
|
async sendViaHttp(api, build) {
|
|
8600
8780
|
try {
|
|
8601
|
-
const
|
|
8781
|
+
const nonce = await this.nextNonce(api);
|
|
8782
|
+
const options = nonce === void 0 ? { tip: BASE_TIP } : { tip: BASE_TIP, nonce };
|
|
8783
|
+
const hash = await build(api).signAndSend(this.getKeyPair(), options);
|
|
8784
|
+
if (nonce !== void 0) this.lastPooledNonce = nonce;
|
|
8602
8785
|
return { success: false, pending: true, extrinsicHash: hash.toHex() };
|
|
8603
8786
|
} catch (err) {
|
|
8604
8787
|
return this.classifySubmissionError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -8611,7 +8794,7 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8611
8794
|
* Two kinds of failure are retried, and the difference is the nonce.
|
|
8612
8795
|
*
|
|
8613
8796
|
* An attempt that verifiably went nowhere (rejected before the pool, dropped, invalid) leaves
|
|
8614
|
-
* the account nonce free, so the next attempt simply re-signs with the
|
|
8797
|
+
* the account nonce free, so the next attempt simply re-signs with the pool-aware nonce.
|
|
8615
8798
|
*
|
|
8616
8799
|
* An attempt that reached the pool and was still there when the watch timed out (`stalled`) is
|
|
8617
8800
|
* retried as a *replacement*: the same nonce it was signed with, and double the tip. Substrate's
|
|
@@ -8630,16 +8813,19 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8630
8813
|
* copy is in flight and its outcome is unknown here, so the `pending` result goes back to the
|
|
8631
8814
|
* caller to confirm later.
|
|
8632
8815
|
*/
|
|
8633
|
-
async sendExtrinsicWithRetries(extrinsic, maxRetries, timeoutMs) {
|
|
8816
|
+
async sendExtrinsicWithRetries(extrinsic, maxRetries, timeoutMs, initialNonce) {
|
|
8634
8817
|
const keyPair = this.getKeyPair();
|
|
8635
8818
|
let attempt = 0;
|
|
8636
|
-
let nonce;
|
|
8819
|
+
let nonce = initialNonce;
|
|
8637
8820
|
let stalled;
|
|
8638
8821
|
while (attempt < maxRetries) {
|
|
8639
8822
|
const currentTip = BASE_TIP * BigInt(2 ** attempt);
|
|
8640
8823
|
attempt++;
|
|
8641
8824
|
try {
|
|
8642
8825
|
const result = await this.sendWithTimeout(extrinsic, keyPair, currentTip, timeoutMs, nonce);
|
|
8826
|
+
if (nonce !== void 0 && (result.success || result.pending || result.stalled)) {
|
|
8827
|
+
this.lastPooledNonce = Math.max(nonce, this.lastPooledNonce ?? nonce);
|
|
8828
|
+
}
|
|
8643
8829
|
if (result.success || result.error?.includes("Dispatch error")) {
|
|
8644
8830
|
return result;
|
|
8645
8831
|
}
|
|
@@ -8699,6 +8885,35 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8699
8885
|
* replacement rather than a second extrinsic queued behind the first. Left undefined on the
|
|
8700
8886
|
* first attempt, where the api's auto-nonce is correct.
|
|
8701
8887
|
*/
|
|
8888
|
+
/**
|
|
8889
|
+
* The nonce the next submission signs with, or undefined when the node cannot be asked.
|
|
8890
|
+
*
|
|
8891
|
+
* Submissions are serialised, but a watch gives up while its extrinsic is still in the pool
|
|
8892
|
+
* (`stalled`, reported as `pending`), and a pooled extrinsic does not advance the account's
|
|
8893
|
+
* on-chain nonce. An extrinsic signed against on-chain state would then take the nonce of the
|
|
8894
|
+
* one ahead of it and bounce off it (1013/1014) instead of queueing behind it.
|
|
8895
|
+
*
|
|
8896
|
+
* `system_accountNextIndex` is the only pool-aware source here. `signAndSend`'s own `nonce: -1`
|
|
8897
|
+
* is not: on a runtime carrying `AccountNonceApi`, which Hyperbridge does, polkadot-js reads the
|
|
8898
|
+
* nonce through that runtime call and never sees the pool.
|
|
8899
|
+
*
|
|
8900
|
+
* The RPC covers the ready queue, so anything of this instance's that has left it — retried,
|
|
8901
|
+
* queued as future, or simply not counted yet — is covered by `lastPooledNonce` instead, which
|
|
8902
|
+
* is the highest nonce this instance has put into the pool. The two are combined rather than
|
|
8903
|
+
* trusted separately, so a burst never reuses a nonce and a restart still picks up the chain's.
|
|
8904
|
+
*/
|
|
8905
|
+
async nextNonce(api) {
|
|
8906
|
+
try {
|
|
8907
|
+
const accountNextIndex = api.rpc?.system?.accountNextIndex;
|
|
8908
|
+
if (!accountNextIndex) return void 0;
|
|
8909
|
+
const next = await accountNextIndex(this.getKeyPair().address);
|
|
8910
|
+
const fromPool = Number(next.toString());
|
|
8911
|
+
if (!Number.isFinite(fromPool)) return void 0;
|
|
8912
|
+
return this.lastPooledNonce === void 0 ? fromPool : Math.max(fromPool, this.lastPooledNonce + 1);
|
|
8913
|
+
} catch {
|
|
8914
|
+
return void 0;
|
|
8915
|
+
}
|
|
8916
|
+
}
|
|
8702
8917
|
async sendWithTimeout(extrinsic, keyPair, tip, timeoutMs, nonce) {
|
|
8703
8918
|
return new Promise((resolve) => {
|
|
8704
8919
|
let resolved = false;
|
|
@@ -8741,25 +8956,10 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8741
8956
|
} else if (result.status.isInBlock || result.status.isFinalized) {
|
|
8742
8957
|
resolved = true;
|
|
8743
8958
|
clearTimeout(timeoutId);
|
|
8744
|
-
const interrupted = result.events.find(
|
|
8745
|
-
({ event }) => event.section === "utility" && event.method === "BatchInterrupted"
|
|
8746
|
-
);
|
|
8747
|
-
if (interrupted) {
|
|
8748
|
-
const [indexCodec, dispatchError] = interrupted.event.data;
|
|
8749
|
-
if (Number(indexCodec.toString()) === 0) {
|
|
8750
|
-
resolve({
|
|
8751
|
-
success: false,
|
|
8752
|
-
error: `Dispatch error: ${this.describeDispatchError(dispatchError)}`
|
|
8753
|
-
});
|
|
8754
|
-
return;
|
|
8755
|
-
}
|
|
8756
|
-
}
|
|
8757
8959
|
resolve({
|
|
8758
8960
|
success: true,
|
|
8759
8961
|
blockHash: (result.status.isInBlock ? result.status.asInBlock : result.status.asFinalized).toHex(),
|
|
8760
|
-
extrinsicHash: extrinsic.hash.toHex()
|
|
8761
|
-
// Carried so a batch caller can attribute each item's outcome.
|
|
8762
|
-
events: result.events
|
|
8962
|
+
extrinsicHash: extrinsic.hash.toHex()
|
|
8763
8963
|
});
|
|
8764
8964
|
}
|
|
8765
8965
|
}).then((unsub) => {
|
|
@@ -8780,13 +8980,19 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8780
8980
|
/**
|
|
8781
8981
|
* Submits a bid to Hyperbridge's pallet-intents
|
|
8782
8982
|
*
|
|
8983
|
+
* A filler can hold several bids on one order, one per price it offers, and `bid` tells them
|
|
8984
|
+
* apart: submitting again under an identifier the filler already holds replaces that bid alone.
|
|
8985
|
+
* By convention it is `keccak256` of the UserOp's `callData`, which is also what gives each bid
|
|
8986
|
+
* its own nonce key on the `SolverAccount` (see `CryptoUtils.bidId`).
|
|
8987
|
+
*
|
|
8783
8988
|
* @param commitment - The order commitment hash (bytes32)
|
|
8784
8989
|
* @param userOp - The encoded PackedUserOperation as hex string
|
|
8990
|
+
* @param bid - Identifies this bid among the filler's bids on the order (bytes32)
|
|
8785
8991
|
* @returns BidSubmissionResult with success status and block/extrinsic hash
|
|
8786
8992
|
*/
|
|
8787
|
-
async submitBid(commitment, userOp) {
|
|
8993
|
+
async submitBid(commitment, userOp, bid) {
|
|
8788
8994
|
try {
|
|
8789
|
-
return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.placeBid(commitment, userOp));
|
|
8995
|
+
return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.placeBid(commitment, bid, userOp));
|
|
8790
8996
|
} catch (error) {
|
|
8791
8997
|
return {
|
|
8792
8998
|
success: false,
|
|
@@ -8800,46 +9006,12 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8800
9006
|
* Use this to remove unused quotes and claim back deposited BRIDGE tokens.
|
|
8801
9007
|
*
|
|
8802
9008
|
* @param commitment - The order commitment hash (bytes32)
|
|
9009
|
+
* @param bid - Which of the filler's bids on the order to retract (bytes32)
|
|
8803
9010
|
* @returns BidSubmissionResult with success status and block/extrinsic hash
|
|
8804
9011
|
*/
|
|
8805
|
-
async retractBid(commitment) {
|
|
8806
|
-
try {
|
|
8807
|
-
return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.retractBid(commitment));
|
|
8808
|
-
} catch (error) {
|
|
8809
|
-
return {
|
|
8810
|
-
success: false,
|
|
8811
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
8812
|
-
};
|
|
8813
|
-
}
|
|
8814
|
-
}
|
|
8815
|
-
/**
|
|
8816
|
-
* Places a new bid and retracts a previous one in a single transaction via utility.batch.
|
|
8817
|
-
*
|
|
8818
|
-
* The new bid is the primary operation, so `placeBid` MUST run first. `utility.batch` is
|
|
8819
|
-
* non-atomic: a failing call interrupts the batch (via a BatchInterrupted event) without
|
|
8820
|
-
* reverting the calls that already succeeded. Placing first guarantees the new bid lands even
|
|
8821
|
-
* when the retraction then fails — which it routinely does, because a previous commitment's bid
|
|
8822
|
-
* may already be gone (or was itself never placed), making `retractBid` return `BidNotFound`.
|
|
8823
|
-
*
|
|
8824
|
-
* Ordering retraction first (the previous behaviour) caused a self-sustaining cascade: a
|
|
8825
|
-
* `BidNotFound` on the leading retract skipped the trailing `placeBid`, so the current bid never
|
|
8826
|
-
* landed, so the *next* interval's retract of that never-placed commitment also failed, and so
|
|
8827
|
-
* on — silently, because the batch extrinsic itself reports success. The deposit reclaim is
|
|
8828
|
-
* best-effort; landing the bid is not.
|
|
8829
|
-
*
|
|
8830
|
-
* @param retractCommitment - The order commitment of the bid to retract (bytes32)
|
|
8831
|
-
* @param bidCommitment - The order commitment of the new bid (bytes32)
|
|
8832
|
-
* @param userOp - The encoded PackedUserOperation as hex string
|
|
8833
|
-
* @returns BidSubmissionResult with success status and block/extrinsic hash
|
|
8834
|
-
*/
|
|
8835
|
-
async submitBidWithRetraction(retractCommitment, bidCommitment, userOp) {
|
|
9012
|
+
async retractBid(commitment, bid) {
|
|
8836
9013
|
try {
|
|
8837
|
-
return await this.signAndSendExtrinsic(
|
|
8838
|
-
(api) => api.tx.utility.batch([
|
|
8839
|
-
api.tx.intentsCoprocessor.placeBid(bidCommitment, userOp),
|
|
8840
|
-
api.tx.intentsCoprocessor.retractBid(retractCommitment)
|
|
8841
|
-
])
|
|
8842
|
-
);
|
|
9014
|
+
return await this.signAndSendExtrinsic((api) => api.tx.intentsCoprocessor.retractBid(commitment, bid));
|
|
8843
9015
|
} catch (error) {
|
|
8844
9016
|
return {
|
|
8845
9017
|
success: false,
|
|
@@ -8847,89 +9019,6 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8847
9019
|
};
|
|
8848
9020
|
}
|
|
8849
9021
|
}
|
|
8850
|
-
/**
|
|
8851
|
-
* Places every phantom bid of one interval in a single extrinsic, retracting each chain's
|
|
8852
|
-
* previous bid alongside it.
|
|
8853
|
-
*
|
|
8854
|
-
* The pallet registers one phantom order per configured chain in the same block, so this is the
|
|
8855
|
-
* whole interval's set. Submitting them one at a time costs a block per chain: submissions are
|
|
8856
|
-
* serialised on the account nonce and each waits for inclusion, so the last chain's bid is many
|
|
8857
|
-
* blocks behind the first, against a bid window measured in tens of blocks. Batched, every bid
|
|
8858
|
-
* lands in the same block.
|
|
8859
|
-
*
|
|
8860
|
-
* Uses `utility.force_batch`, not `utility.batch`. `batch` stops at the first failing call, so
|
|
8861
|
-
* one rejected bid — a closed window, a duplicate, an insufficient deposit — would silently
|
|
8862
|
-
* drop every bid after it. `force_batch` runs them all and reports each outcome. It needs no
|
|
8863
|
-
* special origin: any signed account may call it, exactly like `batch`.
|
|
8864
|
-
*
|
|
8865
|
-
* @param bids - The bids to place; an empty list is a no-op
|
|
8866
|
-
* @returns Per-bid outcomes, in the order given
|
|
8867
|
-
*/
|
|
8868
|
-
async submitPhantomBids(bids) {
|
|
8869
|
-
if (bids.length === 0) return { bids: [] };
|
|
8870
|
-
const placeIndexByBid = [];
|
|
8871
|
-
let callCount = 0;
|
|
8872
|
-
for (const bid of bids) {
|
|
8873
|
-
placeIndexByBid.push(callCount);
|
|
8874
|
-
callCount += bid.retractCommitment ? 2 : 1;
|
|
8875
|
-
}
|
|
8876
|
-
const outcome = await this.signAndSendExtrinsic(
|
|
8877
|
-
(api) => api.tx.utility.forceBatch(
|
|
8878
|
-
bids.flatMap((bid) => {
|
|
8879
|
-
const calls = [api.tx.intentsCoprocessor.placeBid(bid.commitment, bid.userOp)];
|
|
8880
|
-
if (bid.retractCommitment) {
|
|
8881
|
-
calls.push(api.tx.intentsCoprocessor.retractBid(bid.retractCommitment));
|
|
8882
|
-
}
|
|
8883
|
-
return calls;
|
|
8884
|
-
})
|
|
8885
|
-
)
|
|
8886
|
-
);
|
|
8887
|
-
if (!outcome.success) {
|
|
8888
|
-
return {
|
|
8889
|
-
bids: bids.map((bid) => ({ commitment: bid.commitment, success: false, error: outcome.error })),
|
|
8890
|
-
pending: outcome.pending,
|
|
8891
|
-
extrinsicHash: outcome.extrinsicHash,
|
|
8892
|
-
error: outcome.error
|
|
8893
|
-
};
|
|
8894
|
-
}
|
|
8895
|
-
const items = this.readForceBatchItems(outcome.events ?? [], callCount);
|
|
8896
|
-
return {
|
|
8897
|
-
bids: bids.map((bid, index) => {
|
|
8898
|
-
const error = items.errors[placeIndexByBid[index]];
|
|
8899
|
-
return { commitment: bid.commitment, success: !error, error };
|
|
8900
|
-
}),
|
|
8901
|
-
blockHash: outcome.blockHash,
|
|
8902
|
-
extrinsicHash: outcome.extrinsicHash,
|
|
8903
|
-
error: items.error
|
|
8904
|
-
};
|
|
8905
|
-
}
|
|
8906
|
-
/**
|
|
8907
|
-
* Reads one outcome per call out of a force_batch's events.
|
|
8908
|
-
*
|
|
8909
|
-
* `ItemFailed` carries no index — pallet-utility emits exactly one `ItemCompleted` or
|
|
8910
|
-
* `ItemFailed` per call, in call order, so the k-th item event belongs to call k.
|
|
8911
|
-
*
|
|
8912
|
-
* A count that does not match the calls submitted means the events are not the ones assumed
|
|
8913
|
-
* here, and every attribution after the discrepancy would be off by one. The bids are then
|
|
8914
|
-
* reported as placed: a bid wrongly recorded as landed is retracted next interval and the
|
|
8915
|
-
* retraction harmlessly fails with `BidNotFound`, whereas one wrongly recorded as failed is
|
|
8916
|
-
* never retracted at all and leaves its deposit reserved.
|
|
8917
|
-
*/
|
|
8918
|
-
readForceBatchItems(events, callCount) {
|
|
8919
|
-
const errors = [];
|
|
8920
|
-
for (const { event } of events) {
|
|
8921
|
-
if (event.section !== "utility") continue;
|
|
8922
|
-
if (event.method === "ItemCompleted") errors.push(void 0);
|
|
8923
|
-
else if (event.method === "ItemFailed") errors.push(this.describeDispatchError(event.data[0]));
|
|
8924
|
-
}
|
|
8925
|
-
if (errors.length !== callCount) {
|
|
8926
|
-
return {
|
|
8927
|
-
errors: new Array(callCount).fill(void 0),
|
|
8928
|
-
error: `force_batch reported ${errors.length} item events for ${callCount} calls; outcomes not attributed`
|
|
8929
|
-
};
|
|
8930
|
-
}
|
|
8931
|
-
return { errors };
|
|
8932
|
-
}
|
|
8933
9022
|
/** Renders a DispatchError as `pallet::Error`, falling back to its raw form. */
|
|
8934
9023
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8935
9024
|
describeDispatchError(dispatchError) {
|
|
@@ -8948,10 +9037,11 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8948
9037
|
*/
|
|
8949
9038
|
async getBidStorageEntries(commitment) {
|
|
8950
9039
|
const api = await this.http();
|
|
8951
|
-
const entries = await api.query.intentsCoprocessor.
|
|
9040
|
+
const entries = await api.query.intentsCoprocessor.orderBids.entries(commitment);
|
|
8952
9041
|
return entries.map(([storageKey, depositValue]) => ({
|
|
8953
9042
|
commitment,
|
|
8954
9043
|
filler: storageKey.args[1].toString(),
|
|
9044
|
+
bid: storageKey.args[2].toHex(),
|
|
8955
9045
|
deposit: BigInt(depositValue.toString())
|
|
8956
9046
|
}));
|
|
8957
9047
|
}
|
|
@@ -8983,7 +9073,7 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8983
9073
|
return result.map((entry) => {
|
|
8984
9074
|
const userOp = decodeUserOpScale(entry.user_op);
|
|
8985
9075
|
const filler = new api.Keyring({ type: "sr25519" }).encodeAddress(util.hexToU8a(entry.filler));
|
|
8986
|
-
return { filler, userOp, deposit: 0n };
|
|
9076
|
+
return { filler, bid: entry.bid, userOp, deposit: 0n };
|
|
8987
9077
|
});
|
|
8988
9078
|
}
|
|
8989
9079
|
/**
|
|
@@ -8992,19 +9082,20 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8992
9082
|
*/
|
|
8993
9083
|
async getBidsViaStorage(commitment) {
|
|
8994
9084
|
const api = await this.http();
|
|
8995
|
-
const entries = await api.query.intentsCoprocessor.
|
|
9085
|
+
const entries = await api.query.intentsCoprocessor.orderBids.entries(commitment);
|
|
8996
9086
|
if (entries.length === 0) return [];
|
|
8997
9087
|
const bidPromises = entries.map(async ([storageKey, depositValue]) => {
|
|
8998
9088
|
try {
|
|
8999
9089
|
const filler = storageKey.args[1].toString();
|
|
9090
|
+
const bid = storageKey.args[2].toHex();
|
|
9000
9091
|
const deposit = BigInt(depositValue.toString());
|
|
9001
|
-
const offchainKey = this.buildOffchainBidKey(commitment, filler);
|
|
9092
|
+
const offchainKey = this.buildOffchainBidKey(commitment, filler, bid);
|
|
9002
9093
|
const offchainKeyHex = util.u8aToHex(offchainKey);
|
|
9003
9094
|
const offchainResult = await api.rpc.offchain.localStorageGet("PERSISTENT", offchainKeyHex);
|
|
9004
9095
|
if (!offchainResult || offchainResult.isNone) return null;
|
|
9005
9096
|
const bidData = offchainResult.unwrap().toHex();
|
|
9006
9097
|
const decoded = this.decodeBid(bidData);
|
|
9007
|
-
return { filler: decoded.filler, userOp: decoded.userOp, deposit };
|
|
9098
|
+
return { filler: decoded.filler, bid, userOp: decoded.userOp, deposit };
|
|
9008
9099
|
} catch {
|
|
9009
9100
|
return null;
|
|
9010
9101
|
}
|
|
@@ -9020,418 +9111,38 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
9020
9111
|
const userOp = decodeUserOpScale(userOpHex);
|
|
9021
9112
|
return { filler, userOp };
|
|
9022
9113
|
}
|
|
9023
|
-
/** Builds offchain storage key: "intents::bid::" + commitment + filler */
|
|
9024
|
-
buildOffchainBidKey(commitment, filler) {
|
|
9025
|
-
return util.u8aConcat(OFFCHAIN_BID_PREFIX, util.hexToU8a(commitment), utilCrypto.decodeAddress(filler));
|
|
9114
|
+
/** Builds offchain storage key: "intents::bid::" + commitment + filler + bid */
|
|
9115
|
+
buildOffchainBidKey(commitment, filler, bid) {
|
|
9116
|
+
return util.u8aConcat(OFFCHAIN_BID_PREFIX, util.hexToU8a(commitment), utilCrypto.decodeAddress(filler), util.hexToU8a(bid));
|
|
9026
9117
|
}
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
* or the commitment has expired and been cleared).
|
|
9034
|
-
*/
|
|
9035
|
-
async fetchPhantomOrder(commitment) {
|
|
9036
|
-
const key = util.u8aConcat(OFFCHAIN_PHANTOM_PREFIX, util.hexToU8a(commitment));
|
|
9037
|
-
const api = await this.http();
|
|
9038
|
-
const result = await api.rpc.offchain.localStorageGet("PERSISTENT", util.u8aToHex(key));
|
|
9039
|
-
if (!result || result.isNone) return null;
|
|
9040
|
-
const rawHex = result.unwrap().toHex();
|
|
9041
|
-
if (rawHex === "0x" || rawHex === "0x00") return null;
|
|
9042
|
-
const placeOrderAbi = IntentGatewayV2_default.ABI.find((item) => item.type === "function" && item.name === "placeOrder");
|
|
9043
|
-
const orderType = placeOrderAbi?.inputs?.[0];
|
|
9044
|
-
if (!orderType) return null;
|
|
9045
|
-
const [decoded] = viem.decodeAbiParameters([orderType], rawHex);
|
|
9046
|
-
const d = decoded;
|
|
9047
|
-
const textDecoder = new TextDecoder();
|
|
9048
|
-
return {
|
|
9049
|
-
id: commitment,
|
|
9050
|
-
user: d.user,
|
|
9051
|
-
source: textDecoder.decode(viem.hexToBytes(d.source)),
|
|
9052
|
-
destination: textDecoder.decode(viem.hexToBytes(d.destination)),
|
|
9053
|
-
deadline: d.deadline,
|
|
9054
|
-
nonce: d.nonce,
|
|
9055
|
-
fees: d.fees,
|
|
9056
|
-
session: d.session,
|
|
9057
|
-
predispatch: {
|
|
9058
|
-
assets: d.predispatch.assets.map((a) => ({
|
|
9059
|
-
token: a.token,
|
|
9060
|
-
amount: a.amount
|
|
9061
|
-
})),
|
|
9062
|
-
call: d.predispatch.call
|
|
9063
|
-
},
|
|
9064
|
-
inputs: d.inputs.map((i) => ({
|
|
9065
|
-
token: i.token,
|
|
9066
|
-
amount: i.amount
|
|
9067
|
-
})),
|
|
9068
|
-
output: {
|
|
9069
|
-
beneficiary: d.output.beneficiary,
|
|
9070
|
-
assets: d.output.assets.map((a) => ({
|
|
9071
|
-
token: a.token,
|
|
9072
|
-
amount: a.amount
|
|
9073
|
-
})),
|
|
9074
|
-
call: d.output.call
|
|
9075
|
-
}
|
|
9076
|
-
};
|
|
9118
|
+
};
|
|
9119
|
+
var TronChain = class _TronChain {
|
|
9120
|
+
constructor(params, evm) {
|
|
9121
|
+
this.params = params;
|
|
9122
|
+
this.evm = evm;
|
|
9123
|
+
this.tronWebInstance = new tronweb.TronWeb({ fullHost: params.rpcUrl });
|
|
9077
9124
|
}
|
|
9125
|
+
params;
|
|
9126
|
+
evm;
|
|
9127
|
+
tronWebInstance;
|
|
9078
9128
|
/**
|
|
9079
|
-
*
|
|
9129
|
+
* Creates a `TronChain` instance from a fully-specified config object.
|
|
9080
9130
|
*
|
|
9081
|
-
*
|
|
9082
|
-
* poll goes to the trouble of establishing one. `api.at(hash)` has to work out which metadata to
|
|
9083
|
-
* decode the block against, and with nothing to go on it fetches the header and then the runtime
|
|
9084
|
-
* version at its parent — every block, forever. Its cheaper paths are a registry already pinned
|
|
9085
|
-
* to this exact hash (only ever the previous block's) or one matching a version the caller
|
|
9086
|
-
* names, so naming the version is the only way out. See `getBlockRegistry` in
|
|
9087
|
-
* `@polkadot/api/base/Init`; the `getUpgradeVersion` shortcut that would otherwise skip the
|
|
9088
|
-
* lookup only covers chains hardcoded in `@polkadot/types-known`, which Hyperbridge is not.
|
|
9131
|
+
* This is the only public way to construct a `TronChain` — the constructor is private.
|
|
9089
9132
|
*
|
|
9090
|
-
* @param
|
|
9091
|
-
*
|
|
9092
|
-
* wrong metadata, so this is for callers that have checked, not a place to pass a guess.
|
|
9133
|
+
* @param params - Tron chain configuration
|
|
9134
|
+
* @returns A `TronChain` instance
|
|
9093
9135
|
*/
|
|
9094
|
-
async
|
|
9095
|
-
const
|
|
9096
|
-
|
|
9097
|
-
return await this.getPhantomOrdersAtHash(blockHash.toHex(), knownVersion);
|
|
9136
|
+
static async fromParams(params) {
|
|
9137
|
+
const evm = await EvmChain.create(params.rpcUrl, params.bundlerUrl);
|
|
9138
|
+
return new _TronChain(params, evm);
|
|
9098
9139
|
}
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
* historic block hash, so it never triggers polkadot-js's per-hash registry resolution, and
|
|
9106
|
-
* concurrent calls cannot race each other's registry state.
|
|
9107
|
-
*/
|
|
9108
|
-
async getPhantomOrdersAtHash(blockHash, knownVersion) {
|
|
9109
|
-
const api = await this.http();
|
|
9110
|
-
const apiAt = await api.at(blockHash, knownVersion);
|
|
9111
|
-
return phantomOrdersFrom(await apiAt.query.system.events());
|
|
9112
|
-
}
|
|
9113
|
-
/**
|
|
9114
|
-
* Every block's phantom orders across a whole range, in one `state_queryStorage` call.
|
|
9115
|
-
*
|
|
9116
|
-
* This is the cheap path: the request cost of a scan stops depending on how many blocks it
|
|
9117
|
-
* covers. The events key is the only key queried, and both bounds are block hashes the caller
|
|
9118
|
-
* already holds.
|
|
9119
|
-
*
|
|
9120
|
-
* Two properties of the RPC shape the result.
|
|
9121
|
-
*
|
|
9122
|
-
* It returns *diffs*: `query_storage_unfiltered` in `sc-rpc` pushes a change set for a block only
|
|
9123
|
-
* when the value differs from the previous block in the range (`has_changed`, and the set is
|
|
9124
|
-
* dropped when empty), so a block whose events encode byte-for-byte identically to its
|
|
9125
|
-
* predecessor's is simply absent. That happens on a quiet chain, where consecutive blocks carry
|
|
9126
|
-
* nothing but the timestamp inherent's `ExtrinsicSuccess`. It is safe here because an absent
|
|
9127
|
-
* block provably carries no phantom orders: a `PhantomOrderRegistered` commitment is derived from
|
|
9128
|
-
* the block number (`phantom_order_commitment`), so a block that registered orders can never
|
|
9129
|
-
* encode identically to any other block. Absent therefore means "same as the previous block",
|
|
9130
|
-
* and the previous block having orders would contradict that.
|
|
9131
|
-
*
|
|
9132
|
-
* And it is gated by `--rpc-methods` (`check_if_safe` in `sc-rpc`), which answers a denied call
|
|
9133
|
-
* with `Method not found`. The node this reads from must already run unsafe RPC to serve
|
|
9134
|
-
* `offchain_localStorageGet` for the orders themselves, so this is normally available; the poll
|
|
9135
|
-
* falls back to reading block by block when it is not.
|
|
9136
|
-
*
|
|
9137
|
-
* @returns one entry per block the node reported a change for, in ascending block order.
|
|
9138
|
-
*/
|
|
9139
|
-
async getPhantomOrdersInRange(fromBlockHash, toBlockHash) {
|
|
9140
|
-
const api = await this.http();
|
|
9141
|
-
const changeSets = await api.rpc.state.queryStorage.raw(
|
|
9142
|
-
[SYSTEM_EVENTS_KEY],
|
|
9143
|
-
fromBlockHash,
|
|
9144
|
-
toBlockHash
|
|
9145
|
-
);
|
|
9146
|
-
return changeSets.map((changeSet) => {
|
|
9147
|
-
const value = changeSet?.changes?.find(([key]) => key === SYSTEM_EVENTS_KEY)?.[1];
|
|
9148
|
-
if (!value) return [];
|
|
9149
|
-
return phantomOrdersFrom(api.registry.createType("Vec<EventRecord>", value));
|
|
9150
|
-
});
|
|
9151
|
-
}
|
|
9152
|
-
/**
|
|
9153
|
-
* Polls for newly registered phantom orders, invoking the callback once per block that carries
|
|
9154
|
-
* any, with all of that block's orders.
|
|
9155
|
-
*
|
|
9156
|
-
* Per block rather than per order because that is how the pallet writes them: one order per
|
|
9157
|
-
* configured chain, all registered in the same `on_initialize`. Delivering them together lets a
|
|
9158
|
-
* caller bid on the whole interval in one extrinsic (see {@link submitPhantomBids}) instead of
|
|
9159
|
-
* one per chain.
|
|
9160
|
-
*
|
|
9161
|
-
* Each tick reads the current head and scans every block between the last one processed and that
|
|
9162
|
-
* head, so the block cursor — not the connection — determines what has been seen. This replaced a
|
|
9163
|
-
* system.events subscription, which was only as reliable as its socket: polkadot-js reconnects
|
|
9164
|
-
* the transport but does not reliably re-establish storage subscriptions, and anything emitted
|
|
9165
|
-
* while disconnected was lost silently. With a bid window measured in a handful of blocks, that
|
|
9166
|
-
* meant silently missed bids.
|
|
9167
|
-
*
|
|
9168
|
-
* Scanning a block range is gap-free rather than merely self-healing: an outage delays orders but
|
|
9169
|
-
* cannot drop them, because the cursor only advances past a block whose events were actually
|
|
9170
|
-
* read. Recovery replays the backlog.
|
|
9171
|
-
*
|
|
9172
|
-
* Every read here goes over HTTP, never the websocket. Polling is a sequence of independent
|
|
9173
|
-
* one-shot requests with no state to lose between them, which is exactly what a stateless
|
|
9174
|
-
* transport does well: a request either answers or fails loudly on this tick, instead of a
|
|
9175
|
-
* socket that looks alive while delivering nothing. It also means a websocket outage does not
|
|
9176
|
-
* pause phantom bidding at all — the two transports fail independently.
|
|
9177
|
-
*
|
|
9178
|
-
* What the cadence does *not* describe is the request rate, which is what rate limiters police.
|
|
9179
|
-
* A tick costs four requests whatever the range covers — the head, the runtime version, the two
|
|
9180
|
-
* bounding block hashes as one batched request, and one `state_queryStorage` for every block's
|
|
9181
|
-
* events — and they go out back-to-back, so an interval well under any per-second limit could
|
|
9182
|
-
* still arrive as a burst over it. Three things keep that in bounds: the provider coalesces
|
|
9183
|
-
* concurrent calls into one request and paces requests through the endpoint's token bucket (see
|
|
9184
|
-
* `http`), and `maxBlocksPerPoll` bounds the range. A 429 that gets through anyway backs the
|
|
9185
|
-
* poll off for a doubling number of ticks, so a limiter that is already shedding load is not
|
|
9186
|
-
* handed the next window's budget in rejections too.
|
|
9187
|
-
*
|
|
9188
|
-
* Where the node will not serve `state_queryStorage` the poll reads block by block instead, at
|
|
9189
|
-
* three requests plus one per block; see {@link scanRangeAtOnce}.
|
|
9190
|
-
*
|
|
9191
|
-
* Returns a function that stops polling.
|
|
9192
|
-
*/
|
|
9193
|
-
pollPhantomOrders(callback, options = {}) {
|
|
9194
|
-
const {
|
|
9195
|
-
intervalMs,
|
|
9196
|
-
maxBlocksPerPoll = DEFAULT_MAX_BLOCKS_PER_POLL,
|
|
9197
|
-
onError,
|
|
9198
|
-
onSkip
|
|
9199
|
-
} = options;
|
|
9200
|
-
let cursor = null;
|
|
9201
|
-
let inFlight = false;
|
|
9202
|
-
let stopped = false;
|
|
9203
|
-
let backoffTicks = 0;
|
|
9204
|
-
let backoffLength = 0;
|
|
9205
|
-
const tick = async () => {
|
|
9206
|
-
if (inFlight || stopped) return;
|
|
9207
|
-
if (backoffTicks > 0) {
|
|
9208
|
-
backoffTicks -= 1;
|
|
9209
|
-
return;
|
|
9210
|
-
}
|
|
9211
|
-
inFlight = true;
|
|
9212
|
-
try {
|
|
9213
|
-
const api = await this.http();
|
|
9214
|
-
const head = (await api.rpc.chain.getHeader()).number.toNumber();
|
|
9215
|
-
if (cursor === null) {
|
|
9216
|
-
cursor = Math.max(head - 1, -1);
|
|
9217
|
-
} else {
|
|
9218
|
-
const { bidWindowBlocks, intervalBlocks } = await this.phantomTimings();
|
|
9219
|
-
if (head - cursor > bidWindowBlocks + Math.max(intervalBlocks, bidWindowBlocks)) {
|
|
9220
|
-
const from = cursor + 1;
|
|
9221
|
-
cursor = Math.max(head - 1 - bidWindowBlocks, -1);
|
|
9222
|
-
onSkip?.({ from, to: cursor, head });
|
|
9223
|
-
}
|
|
9224
|
-
}
|
|
9225
|
-
if (head <= cursor) return;
|
|
9226
|
-
const knownVersion = await this.confirmedRuntimeVersion();
|
|
9227
|
-
const to = Math.min(head, cursor + maxBlocksPerPoll);
|
|
9228
|
-
const ranged = await this.scanRangeAtOnce(api, cursor + 1, to, knownVersion, onError);
|
|
9229
|
-
if (ranged) {
|
|
9230
|
-
for (const orders of ranged) {
|
|
9231
|
-
if (stopped) return;
|
|
9232
|
-
if (orders.length > 0) callback(orders);
|
|
9233
|
-
}
|
|
9234
|
-
cursor = to;
|
|
9235
|
-
backoffLength = 0;
|
|
9236
|
-
return;
|
|
9237
|
-
}
|
|
9238
|
-
const numbers = [];
|
|
9239
|
-
for (let blockNumber = cursor + 1; blockNumber <= to; blockNumber++) numbers.push(blockNumber);
|
|
9240
|
-
const hashes = await Promise.allSettled(
|
|
9241
|
-
numbers.map((blockNumber) => api.rpc.chain.getBlockHash(blockNumber))
|
|
9242
|
-
);
|
|
9243
|
-
for (let index = 0; index < numbers.length; index++) {
|
|
9244
|
-
if (stopped) return;
|
|
9245
|
-
const hash = hashes[index];
|
|
9246
|
-
if (hash.status === "rejected") throw hash.reason;
|
|
9247
|
-
const orders = await this.getPhantomOrdersAtHash(hash.value.toHex(), knownVersion);
|
|
9248
|
-
if (orders.length > 0) callback(orders);
|
|
9249
|
-
cursor = numbers[index];
|
|
9250
|
-
}
|
|
9251
|
-
backoffLength = 0;
|
|
9252
|
-
} catch (err) {
|
|
9253
|
-
if (isRateLimited(err)) {
|
|
9254
|
-
backoffLength = Math.min(backoffLength === 0 ? 1 : backoffLength * 2, MAX_RATE_LIMIT_BACKOFF_TICKS);
|
|
9255
|
-
backoffTicks = backoffLength;
|
|
9256
|
-
}
|
|
9257
|
-
onError?.(err);
|
|
9258
|
-
} finally {
|
|
9259
|
-
inFlight = false;
|
|
9260
|
-
}
|
|
9261
|
-
};
|
|
9262
|
-
void tick();
|
|
9263
|
-
let timer = null;
|
|
9264
|
-
const startTimer = (ms) => {
|
|
9265
|
-
if (stopped) return;
|
|
9266
|
-
timer = setInterval(() => void tick(), ms);
|
|
9267
|
-
};
|
|
9268
|
-
if (intervalMs !== void 0) startTimer(intervalMs);
|
|
9269
|
-
else void this.phantomPollIntervalMs().then(startTimer);
|
|
9270
|
-
return () => {
|
|
9271
|
-
stopped = true;
|
|
9272
|
-
if (timer) clearInterval(timer);
|
|
9273
|
-
};
|
|
9274
|
-
}
|
|
9275
|
-
/**
|
|
9276
|
-
* The Hyperbridge head, over HTTP like every other read here.
|
|
9277
|
-
*
|
|
9278
|
-
* Exposed for callers that have to know how old something is: a phantom order carries the block
|
|
9279
|
-
* it was registered at, and only against the head does that become "still biddable" or "long
|
|
9280
|
-
* expired".
|
|
9281
|
-
*/
|
|
9282
|
-
async latestBlockNumber() {
|
|
9283
|
-
const api = await this.http();
|
|
9284
|
-
return (await api.rpc.chain.getHeader()).number.toNumber();
|
|
9285
|
-
}
|
|
9286
|
-
/**
|
|
9287
|
-
* The pallet's phantom timings, read from chain state.
|
|
9288
|
-
*
|
|
9289
|
-
* Both are governance-settable and neither is derivable: on Nexus today the window is 15 while
|
|
9290
|
-
* the runtime constant behind it is 25, so anything hard-coded is wrong in one direction or the
|
|
9291
|
-
* other — too tight and live orders are dropped, too loose and bids are sent into a closed
|
|
9292
|
-
* window for the pallet to reject.
|
|
9293
|
-
*
|
|
9294
|
-
* Read once per instance and cached, because a governance change to either is rare and a read
|
|
9295
|
-
* per poll tick would be a request per tick forever. The cost is that a change is picked up on
|
|
9296
|
-
* the next restart rather than immediately. A failed read is not cached, so it retries.
|
|
9297
|
-
*/
|
|
9298
|
-
async phantomTimings() {
|
|
9299
|
-
if (!this.phantomTimingsRead) {
|
|
9300
|
-
this.phantomTimingsRead = this.readPhantomTimings().catch((err) => {
|
|
9301
|
-
this.phantomTimingsRead = null;
|
|
9302
|
-
throw err;
|
|
9303
|
-
});
|
|
9304
|
-
}
|
|
9305
|
-
return this.phantomTimingsRead;
|
|
9306
|
-
}
|
|
9307
|
-
async readPhantomTimings() {
|
|
9308
|
-
const api = await this.http();
|
|
9309
|
-
const [window, interval] = await Promise.all([
|
|
9310
|
-
api.query.intentsCoprocessor.phantomBidWindow(),
|
|
9311
|
-
api.query.intentsCoprocessor.phantomOrderInterval()
|
|
9312
|
-
]);
|
|
9313
|
-
const stored = Number(window.toString());
|
|
9314
|
-
return {
|
|
9315
|
-
bidWindowBlocks: stored === 0 ? Number(api.consts.intentsCoprocessor.phantomOrderBidWindowBlocks.toString()) : stored,
|
|
9316
|
-
intervalBlocks: Number(interval.toString())
|
|
9317
|
-
};
|
|
9318
|
-
}
|
|
9319
|
-
/**
|
|
9320
|
-
* A whole range of blocks in one `state_queryStorage` call, or `null` when that is not available
|
|
9321
|
-
* and the caller should read block by block.
|
|
9322
|
-
*
|
|
9323
|
-
* Two conditions have to hold, and both are about decoding rather than the range itself.
|
|
9324
|
-
*
|
|
9325
|
-
* The version must be confirmed for this tick — an upgrade inside the range means blocks decode
|
|
9326
|
-
* against different metadata, and one call cannot do that.
|
|
9327
|
-
*
|
|
9328
|
-
* And that confirmed version must still be the one the api's own registry was built for.
|
|
9329
|
-
* `state_queryStorage` declares no historic block hash, so rpc-core skips its registry swap and
|
|
9330
|
-
* decodes the reply against the default registry — fixed at connect, with no
|
|
9331
|
-
* `subscribeRuntimeVersion` on an HTTP api to refresh it. After an upgrade the two diverge, and
|
|
9332
|
-
* the per-block path takes over for good: `api.at(hash, version)` resolves, and builds, the right
|
|
9333
|
-
* registry. That costs a restart to get the cheap path back, which is the correct direction to
|
|
9334
|
-
* fail in.
|
|
9335
|
-
*/
|
|
9336
|
-
async scanRangeAtOnce(api, from, to, knownVersion, onError) {
|
|
9337
|
-
if (this.rangeQueryUnavailable || !knownVersion) return null;
|
|
9338
|
-
const registryVersion = api.runtimeVersion?.specVersion;
|
|
9339
|
-
if (!registryVersion || !knownVersion.specVersion.eq(registryVersion)) return null;
|
|
9340
|
-
const [fromHash, toHash] = from === to ? await Promise.all([api.rpc.chain.getBlockHash(from)]).then(([only]) => [only, only]) : await Promise.all([api.rpc.chain.getBlockHash(from), api.rpc.chain.getBlockHash(to)]);
|
|
9341
|
-
try {
|
|
9342
|
-
return await this.getPhantomOrdersInRange(fromHash.toHex(), toHash.toHex());
|
|
9343
|
-
} catch (err) {
|
|
9344
|
-
if (isMethodUnavailable(err)) {
|
|
9345
|
-
this.rangeQueryUnavailable = true;
|
|
9346
|
-
return null;
|
|
9347
|
-
}
|
|
9348
|
-
if (err instanceof EventDecodeError) {
|
|
9349
|
-
this.rangeQueryUnavailable = true;
|
|
9350
|
-
onError?.(err);
|
|
9351
|
-
return null;
|
|
9352
|
-
}
|
|
9353
|
-
throw err;
|
|
9354
|
-
}
|
|
9355
|
-
}
|
|
9356
|
-
/**
|
|
9357
|
-
* The runtime version this tick's blocks may be decoded against, or `undefined` when that cannot
|
|
9358
|
-
* be established and each block must resolve its own.
|
|
9359
|
-
*
|
|
9360
|
-
* Naming a version to `api.at` is what removes two of the four RPCs a block scan costs, and it
|
|
9361
|
-
* is only sound while the version is actually the block's. Getting that wrong is not a loud
|
|
9362
|
-
* failure: events decoded against the wrong metadata come back as a shape the scan does not
|
|
9363
|
-
* recognise, so the block reads as carrying no phantom orders and the cursor advances past it —
|
|
9364
|
-
* exactly the silent miss the block cursor exists to rule out.
|
|
9365
|
-
*
|
|
9366
|
-
* So the version is read fresh each tick and only used when it matches the previous reading.
|
|
9367
|
-
* `specVersion` only ever increases, and this read happens *after* the head read, so two equal
|
|
9368
|
-
* readings mean no upgrade landed anywhere in between — and therefore none in the range about to
|
|
9369
|
-
* be scanned. A reading that differs means an upgrade landed inside the range: that tick falls
|
|
9370
|
-
* back to per-block resolution, which is exact, and the version is used from the next tick on
|
|
9371
|
-
* once it has been seen twice.
|
|
9372
|
-
*
|
|
9373
|
-
* The gap this leaves is a backlog reaching back past an upgrade, whose oldest blocks predate
|
|
9374
|
-
* even the previous reading. Recovering from an outage that long means those bid windows closed
|
|
9375
|
-
* many upgrades ago, so nothing is lost that was still winnable.
|
|
9376
|
-
*
|
|
9377
|
-
* A version that cannot be read at all yields `undefined` rather than an error: the scan is
|
|
9378
|
-
* about to make the same request against the same endpoint and is the better place to report it.
|
|
9379
|
-
*/
|
|
9380
|
-
async confirmedRuntimeVersion() {
|
|
9381
|
-
let api;
|
|
9382
|
-
let current;
|
|
9383
|
-
try {
|
|
9384
|
-
api = await this.http();
|
|
9385
|
-
current = await api.rpc.state.getRuntimeVersion();
|
|
9386
|
-
} catch {
|
|
9387
|
-
return void 0;
|
|
9388
|
-
}
|
|
9389
|
-
const previous = this.lastRuntimeVersion ?? api.runtimeVersion;
|
|
9390
|
-
this.lastRuntimeVersion = current;
|
|
9391
|
-
if (!previous?.specVersion || !previous?.specName) return void 0;
|
|
9392
|
-
return current.specVersion.eq(previous.specVersion) && current.specName.eq(previous.specName) ? current : void 0;
|
|
9393
|
-
}
|
|
9394
|
-
/**
|
|
9395
|
-
* The poll cadence for the runtime this instance is connected to: Gargantua polls every block,
|
|
9396
|
-
* everything else every 15s. Falls back to the slower cadence if the runtime cannot be read,
|
|
9397
|
-
* since an unreachable node is the poll's problem to report, not the cadence lookup's.
|
|
9398
|
-
*/
|
|
9399
|
-
async phantomPollIntervalMs() {
|
|
9400
|
-
try {
|
|
9401
|
-
const specName = (await this.http()).runtimeVersion.specName.toString();
|
|
9402
|
-
return specName === "gargantua" ? GARGANTUA_PHANTOM_POLL_INTERVAL_MS : PHANTOM_POLL_INTERVAL_MS;
|
|
9403
|
-
} catch {
|
|
9404
|
-
return PHANTOM_POLL_INTERVAL_MS;
|
|
9405
|
-
}
|
|
9406
|
-
}
|
|
9407
|
-
};
|
|
9408
|
-
var TronChain = class _TronChain {
|
|
9409
|
-
constructor(params, evm) {
|
|
9410
|
-
this.params = params;
|
|
9411
|
-
this.evm = evm;
|
|
9412
|
-
this.tronWebInstance = new tronweb.TronWeb({ fullHost: params.rpcUrl });
|
|
9413
|
-
}
|
|
9414
|
-
params;
|
|
9415
|
-
evm;
|
|
9416
|
-
tronWebInstance;
|
|
9417
|
-
/**
|
|
9418
|
-
* Creates a `TronChain` instance from a fully-specified config object.
|
|
9419
|
-
*
|
|
9420
|
-
* This is the only public way to construct a `TronChain` — the constructor is private.
|
|
9421
|
-
*
|
|
9422
|
-
* @param params - Tron chain configuration
|
|
9423
|
-
* @returns A `TronChain` instance
|
|
9424
|
-
*/
|
|
9425
|
-
static async fromParams(params) {
|
|
9426
|
-
const evm = await EvmChain.create(params.rpcUrl, params.bundlerUrl);
|
|
9427
|
-
return new _TronChain(params, evm);
|
|
9428
|
-
}
|
|
9429
|
-
// -------------------------------------------------------------------------
|
|
9430
|
-
// Public accessors
|
|
9431
|
-
// -------------------------------------------------------------------------
|
|
9432
|
-
/** Underlying viem public client (delegated from the internal EvmChain) */
|
|
9433
|
-
get client() {
|
|
9434
|
-
return this.evm.client;
|
|
9140
|
+
// -------------------------------------------------------------------------
|
|
9141
|
+
// Public accessors
|
|
9142
|
+
// -------------------------------------------------------------------------
|
|
9143
|
+
/** Underlying viem public client (delegated from the internal EvmChain) */
|
|
9144
|
+
get client() {
|
|
9145
|
+
return this.evm.client;
|
|
9435
9146
|
}
|
|
9436
9147
|
/** Host contract address for this chain (delegated from the internal EvmChain) */
|
|
9437
9148
|
get host() {
|
|
@@ -10487,8 +10198,8 @@ var PharosChain = class _PharosChain {
|
|
|
10487
10198
|
};
|
|
10488
10199
|
async function generateRootWithProof(postRequest, treeSize) {
|
|
10489
10200
|
const { generate_root_with_proof: generate_root_with_proof2 } = await load_ckb_mmr();
|
|
10490
|
-
const { commitment: hash, encodePacked:
|
|
10491
|
-
const result = JSON.parse(generate_root_with_proof2(viem.hexToBytes(
|
|
10201
|
+
const { commitment: hash, encodePacked: encodePacked5 } = postRequestCommitment(postRequest);
|
|
10202
|
+
const result = JSON.parse(generate_root_with_proof2(viem.hexToBytes(encodePacked5), treeSize));
|
|
10492
10203
|
const { root, proof, mmr_size, keccak_hash_calldata } = result;
|
|
10493
10204
|
if (keccak_hash_calldata !== hash) {
|
|
10494
10205
|
console.log("keccak_hash", keccak_hash_calldata);
|
|
@@ -10705,7 +10416,8 @@ async function retryPromise(operation, retryConfig) {
|
|
|
10705
10416
|
return await operation();
|
|
10706
10417
|
} catch (error) {
|
|
10707
10418
|
if (shouldRetry && !shouldRetry(error)) throw error;
|
|
10708
|
-
|
|
10419
|
+
const detail = error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
10420
|
+
logger.trace(`Retrying(${i}) > ${logMessage}: ${detail.slice(0, 200)}`);
|
|
10709
10421
|
lastError = error;
|
|
10710
10422
|
if (i === retryConfig.maxRetries - 1) break;
|
|
10711
10423
|
await new Promise((resolve) => setTimeout(resolve, retryConfig.backoffMs * 2 ** i));
|
|
@@ -12751,92 +12463,6 @@ query OrderStatus($commitment: String!) {
|
|
|
12751
12463
|
}
|
|
12752
12464
|
}
|
|
12753
12465
|
}`;
|
|
12754
|
-
var LATEST_PHANTOM_ORDER_PRICE_SNAPSHOT = `
|
|
12755
|
-
query LatestPhantomOrderPriceSnapshot($tokenA: String!, $tokenB: String!) {
|
|
12756
|
-
phantomOrderPriceSnapshots(
|
|
12757
|
-
filter: {
|
|
12758
|
-
and: [
|
|
12759
|
-
{ tokenA: { equalTo: $tokenA } }
|
|
12760
|
-
{ tokenB: { equalTo: $tokenB } }
|
|
12761
|
-
{ medianPrice: { isNull: false } }
|
|
12762
|
-
]
|
|
12763
|
-
}
|
|
12764
|
-
orderBy: BLOCK_NUMBER_DESC
|
|
12765
|
-
first: 1
|
|
12766
|
-
) {
|
|
12767
|
-
nodes {
|
|
12768
|
-
commitment
|
|
12769
|
-
tokenA
|
|
12770
|
-
tokenB
|
|
12771
|
-
standardAmount
|
|
12772
|
-
blockNumber
|
|
12773
|
-
medianPrice
|
|
12774
|
-
lowestPrice
|
|
12775
|
-
highestPrice
|
|
12776
|
-
bidCount
|
|
12777
|
-
snapshotTime
|
|
12778
|
-
}
|
|
12779
|
-
}
|
|
12780
|
-
}`;
|
|
12781
|
-
var AVAILABLE_LIQUIDITY = `
|
|
12782
|
-
query AvailableLiquidity(
|
|
12783
|
-
$poolId: String!
|
|
12784
|
-
$sourceChain: String!
|
|
12785
|
-
$destinationChain: String!
|
|
12786
|
-
$direction: String!
|
|
12787
|
-
) {
|
|
12788
|
-
poolChainLiquidities(
|
|
12789
|
-
filter: {
|
|
12790
|
-
and: [
|
|
12791
|
-
{ poolId: { equalToInsensitive: $poolId } }
|
|
12792
|
-
{ chain: { equalTo: $destinationChain } }
|
|
12793
|
-
{ direction: { equalTo: $direction } }
|
|
12794
|
-
]
|
|
12795
|
-
}
|
|
12796
|
-
first: 1
|
|
12797
|
-
) {
|
|
12798
|
-
nodes {
|
|
12799
|
-
depth
|
|
12800
|
-
bidCount
|
|
12801
|
-
unrestrictedDepth
|
|
12802
|
-
unrestrictedBidCount
|
|
12803
|
-
lastUpdatedAt
|
|
12804
|
-
}
|
|
12805
|
-
}
|
|
12806
|
-
poolRoutes(
|
|
12807
|
-
filter: {
|
|
12808
|
-
and: [
|
|
12809
|
-
{ poolId: { equalToInsensitive: $poolId } }
|
|
12810
|
-
{ sourceChain: { equalTo: $sourceChain } }
|
|
12811
|
-
{ chain: { equalTo: $destinationChain } }
|
|
12812
|
-
{ direction: { equalTo: $direction } }
|
|
12813
|
-
]
|
|
12814
|
-
}
|
|
12815
|
-
first: 1
|
|
12816
|
-
) {
|
|
12817
|
-
nodes {
|
|
12818
|
-
depth
|
|
12819
|
-
bidCount
|
|
12820
|
-
lastUpdatedAt
|
|
12821
|
-
}
|
|
12822
|
-
}
|
|
12823
|
-
}`;
|
|
12824
|
-
var BUY_AND_SELL_RATES = `
|
|
12825
|
-
query GetLiquidityPoolRate($poolId: String!) {
|
|
12826
|
-
liquidityPools(
|
|
12827
|
-
first: 1
|
|
12828
|
-
filter: { id: { equalToInsensitive: $poolId } }
|
|
12829
|
-
) {
|
|
12830
|
-
nodes {
|
|
12831
|
-
id
|
|
12832
|
-
token0Symbol
|
|
12833
|
-
token1Symbol
|
|
12834
|
-
sellRate
|
|
12835
|
-
buyRate
|
|
12836
|
-
lastUpdatedAt
|
|
12837
|
-
}
|
|
12838
|
-
}
|
|
12839
|
-
}`;
|
|
12840
12466
|
var TOKEN_GATEWAY_ASSET_TELEPORTED_STATUS = `
|
|
12841
12467
|
query TokenGatewayAssetTeleportedStatus($commitment: String!) {
|
|
12842
12468
|
tokenGatewayAssetTeleportedV2s(
|
|
@@ -12898,29 +12524,6 @@ async function queryAssetTeleported(params) {
|
|
|
12898
12524
|
function queryGetRequest(params) {
|
|
12899
12525
|
return _queryGetRequestInternal(params);
|
|
12900
12526
|
}
|
|
12901
|
-
async function _queryLatestPhantomOrderPriceSnapshot(params) {
|
|
12902
|
-
const response = await params.queryClient.request(
|
|
12903
|
-
LATEST_PHANTOM_ORDER_PRICE_SNAPSHOT,
|
|
12904
|
-
{
|
|
12905
|
-
tokenA: params.tokenA.toLowerCase(),
|
|
12906
|
-
tokenB: params.tokenB.toLowerCase()
|
|
12907
|
-
}
|
|
12908
|
-
);
|
|
12909
|
-
const snapshot = response.phantomOrderPriceSnapshots.nodes[0];
|
|
12910
|
-
if (!snapshot?.medianPrice) return;
|
|
12911
|
-
return {
|
|
12912
|
-
commitment: snapshot.commitment,
|
|
12913
|
-
tokenA: snapshot.tokenA,
|
|
12914
|
-
tokenB: snapshot.tokenB,
|
|
12915
|
-
standardAmount: BigInt(snapshot.standardAmount),
|
|
12916
|
-
blockNumber: BigInt(snapshot.blockNumber),
|
|
12917
|
-
medianPrice: BigInt(snapshot.medianPrice),
|
|
12918
|
-
lowestPrice: snapshot.lowestPrice === null ? void 0 : BigInt(snapshot.lowestPrice),
|
|
12919
|
-
highestPrice: snapshot.highestPrice === null ? void 0 : BigInt(snapshot.highestPrice),
|
|
12920
|
-
bidCount: snapshot.bidCount,
|
|
12921
|
-
snapshotTime: new Date(snapshot.snapshotTime)
|
|
12922
|
-
};
|
|
12923
|
-
}
|
|
12924
12527
|
async function _queryTokenGatewayAssetTeleportedInternal(params) {
|
|
12925
12528
|
const { commitmentHash, queryClient: client, logger = DEFAULT_LOGGER } = params;
|
|
12926
12529
|
const response = await retryPromise(
|
|
@@ -16194,18 +15797,39 @@ var CryptoUtils = class _CryptoUtils {
|
|
|
16194
15797
|
}
|
|
16195
15798
|
/**
|
|
16196
15799
|
* Derives the ERC-4337 nonce key that binds a bid UserOperation to its
|
|
16197
|
-
* order
|
|
16198
|
-
* `keccak256(commitment ‖ sessionKey)`. `SolverAccount`
|
|
16199
|
-
* operations whose nonce key differs — this is what lets the
|
|
16200
|
-
* the plain userOpHash while staying committed to the order and
|
|
16201
|
-
* session key it bid against.
|
|
15800
|
+
* order, session key and calldata: the lower 192 bits of
|
|
15801
|
+
* `keccak256(commitment ‖ sessionKey ‖ keccak256(callData))`. `SolverAccount`
|
|
15802
|
+
* rejects bid operations whose nonce key differs — this is what lets the
|
|
15803
|
+
* solver sign the plain userOpHash while staying committed to the order and
|
|
15804
|
+
* to the session key it bid against.
|
|
15805
|
+
*
|
|
15806
|
+
* The calldata gives every bid its own key. A solver bidding several prices
|
|
15807
|
+
* on one order signs one op per price, and each is sequence 0 of its own key,
|
|
15808
|
+
* so they execute independently rather than in a sequence where one bid that
|
|
15809
|
+
* is never selected blocks the rest.
|
|
16202
15810
|
*
|
|
16203
15811
|
* @param commitment - The order commitment (`order.id`).
|
|
16204
15812
|
* @param sessionKey - The order's session key address (`order.session`).
|
|
15813
|
+
* @param callData - The UserOperation's `callData`.
|
|
16205
15814
|
* @returns The 192-bit nonce key as a bigint (pass to `EntryPoint.getNonce`).
|
|
16206
15815
|
*/
|
|
16207
|
-
static bidNonceKey(commitment, sessionKey) {
|
|
16208
|
-
return BigInt(
|
|
15816
|
+
static bidNonceKey(commitment, sessionKey, callData) {
|
|
15817
|
+
return BigInt(
|
|
15818
|
+
viem.keccak256(
|
|
15819
|
+
viem.encodePacked(["bytes32", "address", "bytes32"], [commitment, sessionKey, viem.keccak256(callData)])
|
|
15820
|
+
)
|
|
15821
|
+
) & (1n << 192n) - 1n;
|
|
15822
|
+
}
|
|
15823
|
+
/**
|
|
15824
|
+
* The identifier Hyperbridge files a bid under: `keccak256` of the UserOp's
|
|
15825
|
+
* `callData`. It is the same hash {@link bidNonceKey} takes, so a bid's
|
|
15826
|
+
* identifier and its nonce key both follow from the op itself, and one
|
|
15827
|
+
* solver's bids on one order are kept apart for the same reason on both sides.
|
|
15828
|
+
*
|
|
15829
|
+
* @param callData - The UserOperation's `callData`.
|
|
15830
|
+
*/
|
|
15831
|
+
static bidId(callData) {
|
|
15832
|
+
return viem.keccak256(callData);
|
|
16209
15833
|
}
|
|
16210
15834
|
/**
|
|
16211
15835
|
* Builds the EIP-712 typed-data payload whose digest is the EntryPoint v0.8
|
|
@@ -16764,9 +16388,98 @@ var OrderPlacer = class {
|
|
|
16764
16388
|
return { order: finalizedOrder, receipt };
|
|
16765
16389
|
}
|
|
16766
16390
|
};
|
|
16391
|
+
var TOKEN_KEYED_GATEWAY_ABI = viem.parseAbi([
|
|
16392
|
+
"function _orders(bytes32 commitment, address token) view returns (uint256)",
|
|
16393
|
+
"function _partialFills(bytes32 commitment, bytes32 token) view returns (uint256)"
|
|
16394
|
+
]);
|
|
16395
|
+
var keyingByClient = /* @__PURE__ */ new WeakMap();
|
|
16396
|
+
async function readLegEscrow(client, gateway, commitment, index, token) {
|
|
16397
|
+
return readKeyed(
|
|
16398
|
+
client,
|
|
16399
|
+
gateway,
|
|
16400
|
+
(keying) => keying === "leg" ? client.readContract({
|
|
16401
|
+
address: gateway,
|
|
16402
|
+
abi: ABI3,
|
|
16403
|
+
functionName: "_orders",
|
|
16404
|
+
args: [commitment, BigInt(index)]
|
|
16405
|
+
}) : client.readContract({
|
|
16406
|
+
address: gateway,
|
|
16407
|
+
abi: TOKEN_KEYED_GATEWAY_ABI,
|
|
16408
|
+
functionName: "_orders",
|
|
16409
|
+
args: [commitment, bytes32ToBytes20(token)]
|
|
16410
|
+
})
|
|
16411
|
+
);
|
|
16412
|
+
}
|
|
16413
|
+
async function readLegPartialFill(client, gateway, commitment, index, token) {
|
|
16414
|
+
return readKeyed(
|
|
16415
|
+
client,
|
|
16416
|
+
gateway,
|
|
16417
|
+
(keying) => keying === "leg" ? client.readContract({
|
|
16418
|
+
address: gateway,
|
|
16419
|
+
abi: ABI3,
|
|
16420
|
+
functionName: "_partialFills",
|
|
16421
|
+
args: [commitment, BigInt(index)]
|
|
16422
|
+
}) : client.readContract({
|
|
16423
|
+
address: gateway,
|
|
16424
|
+
abi: TOKEN_KEYED_GATEWAY_ABI,
|
|
16425
|
+
functionName: "_partialFills",
|
|
16426
|
+
args: [commitment, token]
|
|
16427
|
+
})
|
|
16428
|
+
);
|
|
16429
|
+
}
|
|
16430
|
+
async function readKeyed(client, gateway, read) {
|
|
16431
|
+
let known = keyingByClient.get(client);
|
|
16432
|
+
if (!known) {
|
|
16433
|
+
known = /* @__PURE__ */ new Map();
|
|
16434
|
+
keyingByClient.set(client, known);
|
|
16435
|
+
}
|
|
16436
|
+
const key = gateway.toLowerCase();
|
|
16437
|
+
const first = known.get(key) ?? "leg";
|
|
16438
|
+
try {
|
|
16439
|
+
const value = await read(first);
|
|
16440
|
+
known.set(key, first);
|
|
16441
|
+
return value;
|
|
16442
|
+
} catch (error) {
|
|
16443
|
+
if (!isRevert(error)) throw error;
|
|
16444
|
+
const second = first === "leg" ? "token" : "leg";
|
|
16445
|
+
try {
|
|
16446
|
+
const value = await read(second);
|
|
16447
|
+
known.set(key, second);
|
|
16448
|
+
return value;
|
|
16449
|
+
} catch (secondError) {
|
|
16450
|
+
throw isRevert(secondError) ? error : secondError;
|
|
16451
|
+
}
|
|
16452
|
+
}
|
|
16453
|
+
}
|
|
16454
|
+
function isRevert(error) {
|
|
16455
|
+
let current = error;
|
|
16456
|
+
while (current && typeof current === "object") {
|
|
16457
|
+
const item = current;
|
|
16458
|
+
if (item.name === "ContractFunctionZeroDataError") return true;
|
|
16459
|
+
if (item.code === 3) return true;
|
|
16460
|
+
if (!item.cause || typeof item.cause !== "object") {
|
|
16461
|
+
return /^(?:execution reverted\b|VM Exception while processing transaction:\s*revert\b|function selector was not recognized\b)/i.test(
|
|
16462
|
+
item.message ?? ""
|
|
16463
|
+
);
|
|
16464
|
+
}
|
|
16465
|
+
current = item.cause;
|
|
16466
|
+
}
|
|
16467
|
+
return false;
|
|
16468
|
+
}
|
|
16469
|
+
var PARTIAL_FILLS_SLOT = 11n;
|
|
16470
|
+
function partialFillSlot(commitment, index) {
|
|
16471
|
+
const inner = viem.keccak256(viem.encodePacked(["bytes32", "uint256"], [commitment, PARTIAL_FILLS_SLOT]));
|
|
16472
|
+
return viem.keccak256(viem.encodePacked(["uint256", "bytes32"], [BigInt(index), inner]));
|
|
16473
|
+
}
|
|
16767
16474
|
|
|
16768
16475
|
// src/protocols/intents/OrderExecutor.ts
|
|
16769
16476
|
var USED_USEROPS_STORAGE_KEY = (commitment) => `used-userops:${commitment.toLowerCase()}`;
|
|
16477
|
+
function remainingAfter(targets, filled) {
|
|
16478
|
+
return targets.map((target, index) => {
|
|
16479
|
+
const credited = filled[index]?.amount ?? 0n;
|
|
16480
|
+
return { token: target.token, amount: credited >= target.amount ? 0n : target.amount - credited };
|
|
16481
|
+
});
|
|
16482
|
+
}
|
|
16770
16483
|
var OrderExecutor = class {
|
|
16771
16484
|
constructor(ctx, bidManager) {
|
|
16772
16485
|
this.ctx = ctx;
|
|
@@ -16816,6 +16529,38 @@ var OrderExecutor = class {
|
|
|
16816
16529
|
JSON.stringify([...usedUserOps])
|
|
16817
16530
|
);
|
|
16818
16531
|
}
|
|
16532
|
+
/**
|
|
16533
|
+
* Reads the order's state on its destination chain into `totalFilledAssets`: the output credited
|
|
16534
|
+
* per leg from `_partialFills`, never below what is already counted, so a lagging RPC node cannot
|
|
16535
|
+
* take back a fill this executor has seen. Other solvers can fill the order too, so the chain, not
|
|
16536
|
+
* this executor's own fills, says how much is left.
|
|
16537
|
+
*
|
|
16538
|
+
* Returns the terminal update once `_filled` is set: `FILLED` when every leg is complete,
|
|
16539
|
+
* `CANCELLED` otherwise. `_filled` is read first because progress cannot change after it is set,
|
|
16540
|
+
* so a finalized order is never paired with progress from before its last fill.
|
|
16541
|
+
*/
|
|
16542
|
+
async syncWithDestination(order, commitment, targetAssets, totalFilledAssets) {
|
|
16543
|
+
const client = this.ctx.dest.client;
|
|
16544
|
+
const gateway = this.ctx.dest.configService.getIntentGatewayAddress(normalizeStateMachineId(order.destination));
|
|
16545
|
+
const finalizer = await client.readContract({
|
|
16546
|
+
address: gateway,
|
|
16547
|
+
abi: ABI3,
|
|
16548
|
+
functionName: "_filled",
|
|
16549
|
+
args: [commitment]
|
|
16550
|
+
});
|
|
16551
|
+
const filled = await Promise.all(
|
|
16552
|
+
order.output.assets.map(async (asset, index) => {
|
|
16553
|
+
const credited = await readLegPartialFill(client, gateway, commitment, index, asset.token);
|
|
16554
|
+
const counted = totalFilledAssets[index]?.amount ?? 0n;
|
|
16555
|
+
return { token: asset.token, amount: credited > counted ? credited : counted };
|
|
16556
|
+
})
|
|
16557
|
+
);
|
|
16558
|
+
const remainingAssets = remainingAfter(targetAssets, filled);
|
|
16559
|
+
if (/^0x0{40}$/i.test(finalizer)) return { totalFilledAssets: filled, remainingAssets };
|
|
16560
|
+
const progress = { commitment, totalFilledAssets: filled, remainingAssets };
|
|
16561
|
+
const final = remainingAssets.every((asset) => asset.amount === 0n) ? { status: "FILLED", selectedSolver: finalizer, ...progress } : { status: "CANCELLED", ...progress };
|
|
16562
|
+
return { totalFilledAssets: filled, remainingAssets, final };
|
|
16563
|
+
}
|
|
16819
16564
|
/**
|
|
16820
16565
|
* Creates a closure that computes the deduplication hash key for a
|
|
16821
16566
|
* UserOperation, pre-bound to the order's destination chain and entry point.
|
|
@@ -16874,12 +16619,12 @@ var OrderExecutor = class {
|
|
|
16874
16619
|
}
|
|
16875
16620
|
if (result.fillStatus === "partial") {
|
|
16876
16621
|
const filledAssets = result.filledAssets ?? [];
|
|
16877
|
-
totalFilledAssets = totalFilledAssets.map((a) => {
|
|
16878
|
-
const filled = filledAssets
|
|
16622
|
+
totalFilledAssets = totalFilledAssets.map((a, index) => {
|
|
16623
|
+
const filled = filledAssets[index];
|
|
16879
16624
|
return filled ? { token: a.token, amount: a.amount + filled.amount } : { ...a };
|
|
16880
16625
|
});
|
|
16881
|
-
remainingAssets = targetAssets.map((target) => {
|
|
16882
|
-
const filled = totalFilledAssets
|
|
16626
|
+
remainingAssets = targetAssets.map((target, index) => {
|
|
16627
|
+
const filled = totalFilledAssets[index];
|
|
16883
16628
|
const filledAmt = filled?.amount ?? 0n;
|
|
16884
16629
|
return {
|
|
16885
16630
|
token: target.token,
|
|
@@ -16945,8 +16690,27 @@ var OrderExecutor = class {
|
|
|
16945
16690
|
const usedUserOps = await this.loadUsedUserOps(commitment);
|
|
16946
16691
|
const userOpHashKey = this.createUserOpHasher(order);
|
|
16947
16692
|
const targetAssets = order.output.assets.map((a) => ({ token: a.token, amount: a.amount }));
|
|
16948
|
-
let
|
|
16949
|
-
|
|
16693
|
+
let initial;
|
|
16694
|
+
try {
|
|
16695
|
+
initial = await this.syncWithDestination(
|
|
16696
|
+
order,
|
|
16697
|
+
commitment,
|
|
16698
|
+
targetAssets,
|
|
16699
|
+
order.output.assets.map((a) => ({ token: a.token, amount: 0n }))
|
|
16700
|
+
);
|
|
16701
|
+
} catch (err) {
|
|
16702
|
+
yield {
|
|
16703
|
+
status: "FAILED",
|
|
16704
|
+
commitment,
|
|
16705
|
+
error: `Could not read the order on its destination chain: ${err instanceof Error ? err.message : String(err)}`
|
|
16706
|
+
};
|
|
16707
|
+
return;
|
|
16708
|
+
}
|
|
16709
|
+
if (initial.final) {
|
|
16710
|
+
yield initial.final;
|
|
16711
|
+
return;
|
|
16712
|
+
}
|
|
16713
|
+
const { totalFilledAssets, remainingAssets } = initial;
|
|
16950
16714
|
const executionStream = this.executionStream({
|
|
16951
16715
|
order,
|
|
16952
16716
|
sessionPrivateKey,
|
|
@@ -16978,7 +16742,7 @@ var OrderExecutor = class {
|
|
|
16978
16742
|
if (done) return;
|
|
16979
16743
|
const fed = yield value;
|
|
16980
16744
|
if (value.status === "BIDS_RECEIVED") input = fed;
|
|
16981
|
-
if (value.status === "EXPIRED" || value.status === "FILLED") return;
|
|
16745
|
+
if (value.status === "EXPIRED" || value.status === "FILLED" || value.status === "CANCELLED") return;
|
|
16982
16746
|
}
|
|
16983
16747
|
} finally {
|
|
16984
16748
|
console.log(`[OrderExecutor] Tearing down streams for commitment=${commitment}`);
|
|
@@ -17037,18 +16801,29 @@ var OrderExecutor = class {
|
|
|
17037
16801
|
}
|
|
17038
16802
|
while (true) {
|
|
17039
16803
|
let freshBids;
|
|
16804
|
+
let final;
|
|
17040
16805
|
try {
|
|
17041
|
-
|
|
17042
|
-
|
|
16806
|
+
;
|
|
16807
|
+
({ totalFilledAssets, remainingAssets, final } = await this.syncWithDestination(
|
|
16808
|
+
order,
|
|
16809
|
+
commitment,
|
|
16810
|
+
targetAssets,
|
|
16811
|
+
totalFilledAssets
|
|
16812
|
+
));
|
|
16813
|
+
freshBids = final ? [] : (await this.fetchBids({ commitment, solver, solverLockStartTime })).filter(isFreshBid);
|
|
17043
16814
|
} catch {
|
|
17044
16815
|
await sleep(pollIntervalMs);
|
|
17045
16816
|
continue;
|
|
17046
16817
|
}
|
|
16818
|
+
if (final) {
|
|
16819
|
+
yield final;
|
|
16820
|
+
return;
|
|
16821
|
+
}
|
|
17047
16822
|
if (freshBids.length === 0) {
|
|
17048
16823
|
await sleep(pollIntervalMs);
|
|
17049
16824
|
continue;
|
|
17050
16825
|
}
|
|
17051
|
-
const bids = this.bidManager.buildBids(order, freshBids, sessionPrivateKey);
|
|
16826
|
+
const bids = this.bidManager.buildBids(order, freshBids, sessionPrivateKey).filter((bid) => servesOpenLeg(bid, remainingAssets));
|
|
17052
16827
|
if (bids.length === 0) {
|
|
17053
16828
|
await sleep(pollIntervalMs);
|
|
17054
16829
|
continue;
|
|
@@ -17091,6 +16866,10 @@ var OrderExecutor = class {
|
|
|
17091
16866
|
}
|
|
17092
16867
|
}
|
|
17093
16868
|
};
|
|
16869
|
+
function servesOpenLeg(bid, remainingAssets) {
|
|
16870
|
+
if (bid.outputs.length !== remainingAssets.length) return true;
|
|
16871
|
+
return bid.outputs.some((output, leg) => output.amount > 0n && remainingAssets[leg].amount > 0n);
|
|
16872
|
+
}
|
|
17094
16873
|
var OrderCanceller = class _OrderCanceller {
|
|
17095
16874
|
/**
|
|
17096
16875
|
* @param ctx - Shared IntentsV2 context providing the source and destination
|
|
@@ -17129,8 +16908,9 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17129
16908
|
/**
|
|
17130
16909
|
* Quotes the native token cost of a source-initiated cross-chain cancellation.
|
|
17131
16910
|
*
|
|
17132
|
-
* Constructs
|
|
17133
|
-
* calls `quoteNative` on the source host to
|
|
16911
|
+
* Constructs the ISMP GET request the source gateway will dispatch, one
|
|
16912
|
+
* `_partialFills` key per leg, and calls `quoteNative` on the source host to
|
|
16913
|
+
* obtain the dispatch fee.
|
|
17134
16914
|
* Returns 0 for same-chain orders (no ISMP call needed).
|
|
17135
16915
|
*
|
|
17136
16916
|
* @param order - The order to quote.
|
|
@@ -17144,21 +16924,16 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17144
16924
|
}
|
|
17145
16925
|
const height = order.deadline + 1n;
|
|
17146
16926
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
17147
|
-
const
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
functionName: "calculateCommitmentSlotHash",
|
|
17151
|
-
args: [order.id]
|
|
17152
|
-
});
|
|
17153
|
-
const key = viem.concatHex([destIntentGateway, slotHash]);
|
|
17154
|
-
const context = encodeWithdrawalRequest(order, order.user);
|
|
16927
|
+
const commitment = this.orderId(order);
|
|
16928
|
+
const keys = order.inputs.map((_, index) => viem.concatHex([destIntentGateway, partialFillSlot(commitment, index)]));
|
|
16929
|
+
const context = cancelFromSourceContext(order, commitment);
|
|
17155
16930
|
const getRequest = {
|
|
17156
16931
|
source: sourceStateMachine,
|
|
17157
16932
|
dest: destStateMachine,
|
|
17158
16933
|
from: this.ctx.source.configService.getIntentGatewayAddress(destStateMachine),
|
|
17159
16934
|
nonce: await this.ctx.source.getHostNonce(),
|
|
17160
16935
|
height,
|
|
17161
|
-
keys
|
|
16936
|
+
keys,
|
|
17162
16937
|
timeoutTimestamp: 0n,
|
|
17163
16938
|
context
|
|
17164
16939
|
};
|
|
@@ -17183,10 +16958,13 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17183
16958
|
*
|
|
17184
16959
|
* @param order - The order to cancel.
|
|
17185
16960
|
* @param indexerClient - Indexer client used to stream ISMP request status
|
|
17186
|
-
* updates and query state-machine heights.
|
|
17187
|
-
*
|
|
16961
|
+
* updates and query state-machine heights. The direct same-chain route does
|
|
16962
|
+
* not access it.
|
|
16963
|
+
* @param options - Choose the initiation side. Defaults to source-side
|
|
16964
|
+
* cancellation. Same-chain orders always use the direct local route.
|
|
17188
16965
|
* @yields {@link CancelEvent} objects describing each stage of the
|
|
17189
|
-
* cancellation lifecycle.
|
|
16966
|
+
* cancellation lifecycle. The caller signs or broadcasts the yielded
|
|
16967
|
+
* transaction, so its signer may differ from `order.user` after expiry.
|
|
17190
16968
|
*/
|
|
17191
16969
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
17192
16970
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
@@ -17220,9 +16998,12 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17220
16998
|
* Async generator that cancels an order by initiating the cancel from the
|
|
17221
16999
|
* source chain.
|
|
17222
17000
|
*
|
|
17223
|
-
* **Same-chain path:** encodes a direct `cancelOrder` call
|
|
17224
|
-
* `AWAITING_CANCEL_TRANSACTION`,
|
|
17225
|
-
*
|
|
17001
|
+
* **Same-chain path:** encodes a direct `cancelOrder` call with zero cancel
|
|
17002
|
+
* options, yields `AWAITING_CANCEL_TRANSACTION`, accepts either a signed raw
|
|
17003
|
+
* transaction or an already-broadcast hash, and yields `CANCELLATION_COMPLETE`
|
|
17004
|
+
* after confirming the `EscrowRefunded` event. The contract authorizes the
|
|
17005
|
+
* order user through the deadline and any caller strictly after it; the SDK
|
|
17006
|
+
* preserves `order.user` in calldata so a third party cannot redirect escrow.
|
|
17226
17007
|
*
|
|
17227
17008
|
* **Cross-chain path:**
|
|
17228
17009
|
* 1. Fetches (or resumes from cache) a destination finalization proof.
|
|
@@ -17532,9 +17313,9 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17532
17313
|
}
|
|
17533
17314
|
}
|
|
17534
17315
|
/**
|
|
17535
|
-
* Polls for a finalized destination-chain state proof
|
|
17536
|
-
*
|
|
17537
|
-
*
|
|
17316
|
+
* Polls for a finalized destination-chain state proof of every leg's
|
|
17317
|
+
* `_partialFills` slot, i.e. how much of the order was filled before the
|
|
17318
|
+
* deadline.
|
|
17538
17319
|
*
|
|
17539
17320
|
* Waits until the latest Hyperbridge-tracked state-machine height exceeds
|
|
17540
17321
|
* `order.deadline` (or the last failed probe height) before attempting to
|
|
@@ -17563,14 +17344,9 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17563
17344
|
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
17564
17345
|
this.ctx.dest.config.stateMachineId
|
|
17565
17346
|
);
|
|
17566
|
-
const
|
|
17567
|
-
const
|
|
17568
|
-
|
|
17569
|
-
address: intentGatewayV2Address,
|
|
17570
|
-
functionName: "calculateCommitmentSlotHash",
|
|
17571
|
-
args: [orderId]
|
|
17572
|
-
});
|
|
17573
|
-
const proofHex = await this.ctx.dest.queryStateProof(latestHeight, [slotHash], intentGatewayV2Address);
|
|
17347
|
+
const commitment = this.orderId(order);
|
|
17348
|
+
const slots = order.inputs.map((_, index) => partialFillSlot(commitment, index));
|
|
17349
|
+
const proofHex = await this.ctx.dest.queryStateProof(latestHeight, slots, intentGatewayV2Address);
|
|
17574
17350
|
const proof = {
|
|
17575
17351
|
consensusStateId: this.ctx.dest.config.consensusStateId,
|
|
17576
17352
|
height: latestHeight,
|
|
@@ -17768,118 +17544,135 @@ var OrderCanceller = class _OrderCanceller {
|
|
|
17768
17544
|
return feeInDestFeeToken * 1005n / 1000n;
|
|
17769
17545
|
}
|
|
17770
17546
|
};
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
outputs: [],
|
|
17777
|
-
inputs: [
|
|
17778
|
-
ABI3.find((e) => e.type === "function" && e.name === "fillOrder").inputs[0],
|
|
17547
|
+
function cancelFromSourceContext(order, commitment) {
|
|
17548
|
+
return viem.encodeAbiParameters(
|
|
17549
|
+
[
|
|
17550
|
+
{ type: "bytes32" },
|
|
17551
|
+
{ type: "bytes32" },
|
|
17779
17552
|
{
|
|
17780
|
-
|
|
17781
|
-
type: "tuple",
|
|
17782
|
-
internalType: "struct FillOptions",
|
|
17553
|
+
type: "tuple[]",
|
|
17783
17554
|
components: [
|
|
17784
|
-
{ name: "
|
|
17785
|
-
{ name: "
|
|
17786
|
-
{
|
|
17787
|
-
name: "outputs",
|
|
17788
|
-
type: "tuple[]",
|
|
17789
|
-
internalType: "struct TokenInfo[]",
|
|
17790
|
-
components: [
|
|
17791
|
-
{ name: "token", type: "bytes32", internalType: "bytes32" },
|
|
17792
|
-
{ name: "amount", type: "uint256", internalType: "uint256" }
|
|
17793
|
-
]
|
|
17794
|
-
}
|
|
17555
|
+
{ name: "token", type: "bytes32" },
|
|
17556
|
+
{ name: "amount", type: "uint256" }
|
|
17795
17557
|
]
|
|
17796
|
-
}
|
|
17558
|
+
},
|
|
17559
|
+
{ type: "uint256[]" }
|
|
17560
|
+
],
|
|
17561
|
+
[
|
|
17562
|
+
commitment,
|
|
17563
|
+
bytes20ToBytes32(order.user),
|
|
17564
|
+
order.inputs.map((input) => ({ token: normalizeAddressForEvmBytes32(input.token), amount: input.amount })),
|
|
17565
|
+
order.output.assets.map((asset) => asset.amount)
|
|
17797
17566
|
]
|
|
17567
|
+
);
|
|
17568
|
+
}
|
|
17569
|
+
var FILL_ORDER_SELECTOR = "0x68ddf058";
|
|
17570
|
+
var SUPPORTED_INTENTS_VERSION = 3n;
|
|
17571
|
+
var CONTRACT_VERSION_ABI = [
|
|
17572
|
+
{
|
|
17573
|
+
type: "function",
|
|
17574
|
+
name: "version",
|
|
17575
|
+
stateMutability: "view",
|
|
17576
|
+
inputs: [],
|
|
17577
|
+
outputs: [{ name: "", type: "uint64" }]
|
|
17798
17578
|
}
|
|
17799
17579
|
];
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
var CHAINS_WITHOUT_VALID_UNTIL = /* @__PURE__ */ new Set([
|
|
17808
|
-
97,
|
|
17809
|
-
// BNB testnet
|
|
17810
|
-
10200,
|
|
17811
|
-
// Gnosis Chiado
|
|
17812
|
-
80002,
|
|
17813
|
-
// Polygon Amoy
|
|
17814
|
-
84532,
|
|
17815
|
-
// Base Sepolia
|
|
17816
|
-
421614,
|
|
17817
|
-
// Arbitrum Sepolia
|
|
17818
|
-
688689,
|
|
17819
|
-
// Pharos testnet
|
|
17820
|
-
11155111,
|
|
17821
|
-
// Sepolia
|
|
17822
|
-
11155420,
|
|
17823
|
-
// Optimism Sepolia
|
|
17824
|
-
420420417
|
|
17825
|
-
// Polkadot Hub Paseo
|
|
17826
|
-
]);
|
|
17827
|
-
var knownV2Gateways = /* @__PURE__ */ new Set();
|
|
17828
|
-
function resetFillOptionsVersionCache() {
|
|
17829
|
-
knownV2Gateways.clear();
|
|
17580
|
+
async function readContractVersion(client, address) {
|
|
17581
|
+
try {
|
|
17582
|
+
return await client.readContract({ address, abi: CONTRACT_VERSION_ABI, functionName: "version" });
|
|
17583
|
+
} catch (error) {
|
|
17584
|
+
if (isRevert(error)) return void 0;
|
|
17585
|
+
throw error;
|
|
17586
|
+
}
|
|
17830
17587
|
}
|
|
17831
|
-
async function
|
|
17832
|
-
|
|
17833
|
-
if (!slot || slot.length < 66) return gateway;
|
|
17834
|
-
const addr = `0x${slot.slice(-40)}`;
|
|
17835
|
-
return /^0x0{40}$/.test(addr) ? gateway : addr;
|
|
17588
|
+
async function supportsRateFills(client, gateway) {
|
|
17589
|
+
return await readContractVersion(client, gateway) === SUPPORTED_INTENTS_VERSION;
|
|
17836
17590
|
}
|
|
17837
|
-
async function
|
|
17838
|
-
const
|
|
17839
|
-
if (
|
|
17840
|
-
|
|
17841
|
-
|
|
17842
|
-
|
|
17843
|
-
if (LEGACY_FILL_OPTIONS_IMPLEMENTATIONS.has(implementation.toLowerCase())) return 1;
|
|
17844
|
-
knownV2Gateways.add(key);
|
|
17845
|
-
return 2;
|
|
17591
|
+
async function assertGatewayRelease(client, gateway) {
|
|
17592
|
+
const version = await readContractVersion(client, gateway);
|
|
17593
|
+
if (version === SUPPORTED_INTENTS_VERSION) return;
|
|
17594
|
+
throw new Error(
|
|
17595
|
+
version === void 0 ? `IntentGateway ${gateway} reports no version(); this SDK requires release ${SUPPORTED_INTENTS_VERSION}` : `IntentGateway ${gateway} reports release ${String(version)}; this SDK requires release ${SUPPORTED_INTENTS_VERSION}`
|
|
17596
|
+
);
|
|
17846
17597
|
}
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17852
|
-
|
|
17853
|
-
|
|
17854
|
-
|
|
17855
|
-
|
|
17856
|
-
|
|
17857
|
-
|
|
17858
|
-
|
|
17859
|
-
|
|
17860
|
-
|
|
17598
|
+
var CANONICAL_EVM_TOKEN = /^0x0{24}[0-9a-fA-F]{40}$/;
|
|
17599
|
+
function isCanonicalEvmToken(token) {
|
|
17600
|
+
return CANONICAL_EVM_TOKEN.test(token);
|
|
17601
|
+
}
|
|
17602
|
+
function validateFillQuotes(order, options) {
|
|
17603
|
+
const count = order.output.assets.length;
|
|
17604
|
+
if (!count || !Array.isArray(options.inputs) || options.inputs.length !== count || options.outputs.length !== count || order.inputs.length !== count) {
|
|
17605
|
+
throw new Error("Fill inputs and outputs must quote every order leg");
|
|
17606
|
+
}
|
|
17607
|
+
for (let i = 0; i < count; i++) {
|
|
17608
|
+
const input = options.inputs[i];
|
|
17609
|
+
const output = options.outputs[i];
|
|
17610
|
+
if (input.token.toLowerCase() !== order.inputs[i].token.toLowerCase() || output.token.toLowerCase() !== order.output.assets[i].token.toLowerCase() || !isCanonicalEvmToken(input.token) || !isCanonicalEvmToken(output.token)) {
|
|
17611
|
+
throw new Error("Fill quote tokens must match their order legs");
|
|
17612
|
+
}
|
|
17613
|
+
if (input.amount === 0n !== (output.amount === 0n)) {
|
|
17614
|
+
throw new Error("Fill quote input and output must both be zero or positive");
|
|
17615
|
+
}
|
|
17616
|
+
}
|
|
17617
|
+
}
|
|
17618
|
+
function encodeFillOrder(order, options) {
|
|
17619
|
+
validateFillQuotes(order, options);
|
|
17620
|
+
return viem.encodeFunctionData({
|
|
17621
|
+
abi: ABI3,
|
|
17622
|
+
functionName: "fillOrder",
|
|
17623
|
+
args: [order, options]
|
|
17624
|
+
});
|
|
17861
17625
|
}
|
|
17862
17626
|
function decodeFillOrder(data) {
|
|
17863
17627
|
try {
|
|
17864
17628
|
const decoded = viem.decodeFunctionData({ abi: ABI3, data });
|
|
17865
|
-
if (decoded.functionName
|
|
17866
|
-
|
|
17867
|
-
|
|
17629
|
+
if (decoded.functionName !== "fillOrder" || !decoded.args || decoded.args.length < 2) return null;
|
|
17630
|
+
const order = decoded.args[0];
|
|
17631
|
+
const options = decoded.args[1];
|
|
17632
|
+
validateFillQuotes(order, options);
|
|
17633
|
+
return { order, options };
|
|
17868
17634
|
} catch {
|
|
17635
|
+
return null;
|
|
17869
17636
|
}
|
|
17870
|
-
|
|
17871
|
-
|
|
17872
|
-
|
|
17873
|
-
|
|
17874
|
-
|
|
17875
|
-
|
|
17876
|
-
|
|
17637
|
+
}
|
|
17638
|
+
var ENTRY_POINT_EVENT_ABI = [
|
|
17639
|
+
{ type: "event", name: "BeforeExecution", inputs: [] },
|
|
17640
|
+
{
|
|
17641
|
+
type: "event",
|
|
17642
|
+
name: "UserOperationEvent",
|
|
17643
|
+
inputs: [
|
|
17644
|
+
{ name: "userOpHash", type: "bytes32", indexed: true },
|
|
17645
|
+
{ name: "sender", type: "address", indexed: true },
|
|
17646
|
+
{ name: "paymaster", type: "address", indexed: true },
|
|
17647
|
+
{ name: "nonce", type: "uint256", indexed: false },
|
|
17648
|
+
{ name: "success", type: "bool", indexed: false },
|
|
17649
|
+
{ name: "actualGasCost", type: "uint256", indexed: false },
|
|
17650
|
+
{ name: "actualGasUsed", type: "uint256", indexed: false }
|
|
17651
|
+
]
|
|
17877
17652
|
}
|
|
17878
|
-
|
|
17653
|
+
];
|
|
17654
|
+
function userOperationLogs(logs, entryPoint, userOpHash) {
|
|
17655
|
+
const [beforeExecution, userOperationEvent] = ENTRY_POINT_EVENT_ABI.map((event) => viem.toEventSelector(event));
|
|
17656
|
+
const isBoundary = (log) => log.address.toLowerCase() === entryPoint.toLowerCase() && (log.topics[0] === beforeExecution || log.topics[0] === userOperationEvent);
|
|
17657
|
+
const end = logs.findIndex(
|
|
17658
|
+
(log) => isBoundary(log) && log.topics[0] === userOperationEvent && log.topics[1]?.toLowerCase() === userOpHash.toLowerCase()
|
|
17659
|
+
);
|
|
17660
|
+
if (end === -1) throw new Error(`UserOperation ${userOpHash} is not in the transaction`);
|
|
17661
|
+
const { args } = viem.decodeEventLog({
|
|
17662
|
+
abi: ENTRY_POINT_EVENT_ABI,
|
|
17663
|
+
eventName: "UserOperationEvent",
|
|
17664
|
+
data: logs[end].data,
|
|
17665
|
+
topics: logs[end].topics
|
|
17666
|
+
});
|
|
17667
|
+
if (!args.success) throw new Error(`UserOperation ${userOpHash} reverted`);
|
|
17668
|
+
let start = end - 1;
|
|
17669
|
+
while (start >= 0 && !isBoundary(logs[start])) start--;
|
|
17670
|
+
return logs.slice(start + 1, end);
|
|
17879
17671
|
}
|
|
17880
17672
|
var BidImpl = class {
|
|
17881
17673
|
solverAddress;
|
|
17882
17674
|
outputs;
|
|
17675
|
+
inputs;
|
|
17883
17676
|
relayerFee;
|
|
17884
17677
|
nativeDispatchFee;
|
|
17885
17678
|
userOp;
|
|
@@ -17902,6 +17695,7 @@ var BidImpl = class {
|
|
|
17902
17695
|
this.sessionPrivateKey = params.sessionPrivateKey;
|
|
17903
17696
|
this.solverAddress = params.fillerBid.userOp.sender;
|
|
17904
17697
|
this.outputs = params.fillOptions.outputs;
|
|
17698
|
+
this.inputs = params.fillOptions.inputs;
|
|
17905
17699
|
this.relayerFee = params.fillOptions.relayerFee;
|
|
17906
17700
|
this.nativeDispatchFee = params.fillOptions.nativeDispatchFee;
|
|
17907
17701
|
this.userOp = params.fillerBid.userOp;
|
|
@@ -18034,31 +17828,28 @@ var BidImpl = class {
|
|
|
18034
17828
|
{ maxRetries: 5, backoffMs: 2e3, logMessage: "Fetching user operation receipt" }
|
|
18035
17829
|
);
|
|
18036
17830
|
txnHash = receipt.receipt.transactionHash;
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18040
|
-
|
|
18041
|
-
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
|
|
18046
|
-
|
|
18047
|
-
|
|
18048
|
-
|
|
18049
|
-
|
|
18050
|
-
|
|
18051
|
-
|
|
18052
|
-
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
|
|
18056
|
-
|
|
18057
|
-
|
|
18058
|
-
|
|
18059
|
-
}
|
|
18060
|
-
} catch {
|
|
18061
|
-
throw new Error("Failed to determine fill status from logs");
|
|
17831
|
+
const chainReceipt = await this.ctx.dest.client.waitForTransactionReceipt({
|
|
17832
|
+
hash: txnHash,
|
|
17833
|
+
confirmations: 1
|
|
17834
|
+
});
|
|
17835
|
+
const gateway = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
17836
|
+
normalizeStateMachineId(this.order.destination)
|
|
17837
|
+
);
|
|
17838
|
+
const fills = viem.parseEventLogs({
|
|
17839
|
+
abi: ABI3,
|
|
17840
|
+
logs: userOperationLogs(chainReceipt.logs, entryPointAddress, userOpHash),
|
|
17841
|
+
eventName: ["OrderFilled", "PartialFill"]
|
|
17842
|
+
}).filter(
|
|
17843
|
+
(event) => event.address.toLowerCase() === gateway.toLowerCase() && event.args.commitment.toLowerCase() === commitment.toLowerCase()
|
|
17844
|
+
);
|
|
17845
|
+
if (fills.some((event) => event.eventName === "OrderFilled")) {
|
|
17846
|
+
fillStatus = "full";
|
|
17847
|
+
} else if (fills.length > 0) {
|
|
17848
|
+
fillStatus = "partial";
|
|
17849
|
+
filledAssets = fills[0].args.outputs.map(({ token }, index) => ({
|
|
17850
|
+
token,
|
|
17851
|
+
amount: fills.reduce((sum, event) => sum + (event.args.outputs[index]?.amount ?? 0n), 0n)
|
|
17852
|
+
}));
|
|
18062
17853
|
}
|
|
18063
17854
|
} catch (err) {
|
|
18064
17855
|
throw new Error(`Failed to execute bid: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -18125,6 +17916,20 @@ var BidManager = class {
|
|
|
18125
17916
|
callData,
|
|
18126
17917
|
paymasterAndData = "0x"
|
|
18127
17918
|
} = options;
|
|
17919
|
+
const fills = (this.crypto.decodeERC7821Execute(callData) ?? []).filter(
|
|
17920
|
+
(call) => call.data.slice(0, 10).toLowerCase() === FILL_ORDER_SELECTOR
|
|
17921
|
+
);
|
|
17922
|
+
if (fills.length === 0) throw new Error("Bid calldata carries no fillOrder call");
|
|
17923
|
+
for (const call of fills) {
|
|
17924
|
+
if (!decodeFillOrder(call.data)) {
|
|
17925
|
+
throw new Error("Malformed fill quote; every leg requires inputs and outputs");
|
|
17926
|
+
}
|
|
17927
|
+
}
|
|
17928
|
+
const chain = normalizeStateMachineId(order.destination);
|
|
17929
|
+
const gateway = this.ctx.dest.configService.getIntentGatewayAddress(chain);
|
|
17930
|
+
if (!await supportsRateFills(this.ctx.dest.client, gateway)) {
|
|
17931
|
+
throw new Error("Fills are not supported by the destination gateway");
|
|
17932
|
+
}
|
|
18128
17933
|
const chainId = BigInt(
|
|
18129
17934
|
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
|
|
18130
17935
|
);
|
|
@@ -18142,10 +17947,10 @@ var BidManager = class {
|
|
|
18142
17947
|
signature: "0x"
|
|
18143
17948
|
};
|
|
18144
17949
|
const nonceKey = BigInt(nonce) >> 64n;
|
|
18145
|
-
const expectedKey = CryptoUtils.bidNonceKey(order.id, order.session);
|
|
17950
|
+
const expectedKey = CryptoUtils.bidNonceKey(order.id, order.session, callData);
|
|
18146
17951
|
if (nonceKey !== expectedKey) {
|
|
18147
17952
|
console.warn(
|
|
18148
|
-
`[BidManager] bid nonce key does not bind the order commitment
|
|
17953
|
+
`[BidManager] bid nonce key does not bind the order commitment, session key and calldata; on-chain validation will fail (order=${order.id})`
|
|
18149
17954
|
);
|
|
18150
17955
|
}
|
|
18151
17956
|
const solverSignature = await solverSigner.signTypedData(
|
|
@@ -18210,7 +18015,7 @@ var BidManager = class {
|
|
|
18210
18015
|
return this.selectAndExecuteBest(order, this.buildBids(order, bids, sessionPrivateKey));
|
|
18211
18016
|
}
|
|
18212
18017
|
/**
|
|
18213
|
-
* Autopilot bid selection: sorts the given bids by
|
|
18018
|
+
* Autopilot bid selection: sorts the given bids by rate, simulates
|
|
18214
18019
|
* each in order and attempts execution. Any bid that fails simulation or
|
|
18215
18020
|
* execution is skipped once so the next ranked bid can be attempted in the
|
|
18216
18021
|
* same round. For consumers that do not need custom selection logic.
|
|
@@ -18265,35 +18070,58 @@ var BidManager = class {
|
|
|
18265
18070
|
throw new Error("No bids passed simulation and execution");
|
|
18266
18071
|
}
|
|
18267
18072
|
/**
|
|
18268
|
-
* Sorts
|
|
18073
|
+
* Sorts bids by rate, best to worst, independently of how much each one fills.
|
|
18269
18074
|
*
|
|
18270
|
-
*
|
|
18271
|
-
*
|
|
18272
|
-
*
|
|
18273
|
-
*
|
|
18274
|
-
* - Mixed outputs: sort by DEX-quoted USD value descending, with a raw-amount
|
|
18275
|
-
* fallback if pricing fails.
|
|
18075
|
+
* A leg's rate is what the bid pays out for what it takes: `output / input` for
|
|
18076
|
+
* that leg. Every leg of an order trades the same pair, so a bid's rate is its
|
|
18077
|
+
* total output over its total input across the legs it quotes. Rates are
|
|
18078
|
+
* compared exactly, by cross-multiplication; equal rates keep arrival order.
|
|
18276
18079
|
*
|
|
18277
|
-
*
|
|
18080
|
+
* A bid is dropped when it does not quote the order's legs one for one, names
|
|
18081
|
+
* another token on a leg, quotes an input without an output (or the reverse),
|
|
18082
|
+
* quotes no leg at all, or quotes a leg below the rate the order requires.
|
|
18278
18083
|
*
|
|
18279
|
-
* @param order - The placed order
|
|
18084
|
+
* @param order - The placed order the bids compete to fill.
|
|
18280
18085
|
* @param bids - Executable bids to sort (from {@link buildBids}).
|
|
18281
|
-
* @returns
|
|
18086
|
+
* @returns The valid bids, best rate first, ready for simulation.
|
|
18282
18087
|
*/
|
|
18283
18088
|
async sortBids(order, bids) {
|
|
18284
|
-
const
|
|
18285
|
-
|
|
18286
|
-
|
|
18287
|
-
|
|
18288
|
-
|
|
18289
|
-
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
|
|
18293
|
-
|
|
18089
|
+
const legs = order.inputs.length;
|
|
18090
|
+
const ranked = [];
|
|
18091
|
+
for (const [index, bid] of bids.entries()) {
|
|
18092
|
+
if (bid.inputs.length !== legs || bid.outputs.length !== legs || order.output.assets.length !== legs) {
|
|
18093
|
+
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: does not quote the order's legs`);
|
|
18094
|
+
continue;
|
|
18095
|
+
}
|
|
18096
|
+
let input = 0n;
|
|
18097
|
+
let output = 0n;
|
|
18098
|
+
let reason = "";
|
|
18099
|
+
for (let leg = 0; leg < legs && !reason; leg++) {
|
|
18100
|
+
const take = bid.inputs[leg];
|
|
18101
|
+
const pay = bid.outputs[leg];
|
|
18102
|
+
const escrow = order.inputs[leg];
|
|
18103
|
+
const required = order.output.assets[leg];
|
|
18104
|
+
if (take.token.toLowerCase() !== escrow.token.toLowerCase()) reason = `input token mismatch on leg ${leg}`;
|
|
18105
|
+
else if (pay.token.toLowerCase() !== required.token.toLowerCase()) reason = `output token mismatch on leg ${leg}`;
|
|
18106
|
+
else if (take.amount < 0n || pay.amount < 0n || take.amount === 0n !== (pay.amount === 0n))
|
|
18107
|
+
reason = `no valid quote on leg ${leg}`;
|
|
18108
|
+
else if (pay.amount * escrow.amount < take.amount * required.amount) reason = `rate below the order on leg ${leg}`;
|
|
18109
|
+
input += take.amount;
|
|
18110
|
+
output += pay.amount;
|
|
18111
|
+
}
|
|
18112
|
+
if (!reason && input === 0n) reason = "quotes no leg";
|
|
18113
|
+
if (reason) {
|
|
18114
|
+
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: ${reason}`);
|
|
18115
|
+
continue;
|
|
18116
|
+
}
|
|
18117
|
+
ranked.push({ bid, input, output, index });
|
|
18294
18118
|
}
|
|
18295
|
-
|
|
18296
|
-
|
|
18119
|
+
ranked.sort((a, b) => {
|
|
18120
|
+
const left = a.output * b.input;
|
|
18121
|
+
const right = b.output * a.input;
|
|
18122
|
+
return left === right ? a.index - b.index : left > right ? -1 : 1;
|
|
18123
|
+
});
|
|
18124
|
+
return ranked.map(({ bid }) => bid);
|
|
18297
18125
|
}
|
|
18298
18126
|
/**
|
|
18299
18127
|
* Extracts the `FillOptions` struct from a single bid's ERC-7821
|
|
@@ -18316,150 +18144,6 @@ var BidManager = class {
|
|
|
18316
18144
|
}
|
|
18317
18145
|
return null;
|
|
18318
18146
|
}
|
|
18319
|
-
/**
|
|
18320
|
-
* Case A: single output token.
|
|
18321
|
-
* Filter bids by token match only, sort descending by amount.
|
|
18322
|
-
* Partial fill bids are allowed — the contract determines fill status.
|
|
18323
|
-
*/
|
|
18324
|
-
sortSingleOutput(bids, requiredAsset) {
|
|
18325
|
-
const requiredAmount = new Decimal2__default.default(requiredAsset.amount.toString());
|
|
18326
|
-
console.log(
|
|
18327
|
-
`[BidManager] sortSingleOutput: required token=${requiredAsset.token}, amount=${requiredAmount.toString()}`
|
|
18328
|
-
);
|
|
18329
|
-
const validBids = [];
|
|
18330
|
-
for (const bid of bids) {
|
|
18331
|
-
const bidOutput = bid.outputs[0];
|
|
18332
|
-
const bidAmount = new Decimal2__default.default(bidOutput.amount.toString());
|
|
18333
|
-
if (bidOutput.token.toLowerCase() !== requiredAsset.token.toLowerCase()) {
|
|
18334
|
-
console.warn(
|
|
18335
|
-
`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: token mismatch (bid=${bidOutput.token}, required=${requiredAsset.token})`
|
|
18336
|
-
);
|
|
18337
|
-
continue;
|
|
18338
|
-
}
|
|
18339
|
-
if (bidAmount.lt(requiredAmount)) {
|
|
18340
|
-
console.log(
|
|
18341
|
-
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidAmount.toString()}, required=${requiredAmount.toString()}, covers=${bidAmount.div(requiredAmount).mul(100).toFixed(2)}%)`
|
|
18342
|
-
);
|
|
18343
|
-
} else {
|
|
18344
|
-
console.log(
|
|
18345
|
-
`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: amount=${bidAmount.toString()} (surplus=${bidAmount.minus(requiredAmount).toString()})`
|
|
18346
|
-
);
|
|
18347
|
-
}
|
|
18348
|
-
validBids.push({ bid, amount: bidOutput.amount });
|
|
18349
|
-
}
|
|
18350
|
-
validBids.sort((a, b) => {
|
|
18351
|
-
const aAmt = new Decimal2__default.default(a.amount.toString());
|
|
18352
|
-
const bAmt = new Decimal2__default.default(b.amount.toString());
|
|
18353
|
-
return bAmt.comparedTo(aAmt);
|
|
18354
|
-
});
|
|
18355
|
-
return validBids.map(({ bid }) => bid);
|
|
18356
|
-
}
|
|
18357
|
-
/**
|
|
18358
|
-
* Case B: all outputs are USDC/USDT.
|
|
18359
|
-
* Sum normalised USD values (treating each stable as $1) and sort descending.
|
|
18360
|
-
* Partial fill bids are allowed.
|
|
18361
|
-
*/
|
|
18362
|
-
sortAllStables(bids, orderOutputs, chainId) {
|
|
18363
|
-
const requiredUsd = this.computeStablesUsdValue(orderOutputs, chainId);
|
|
18364
|
-
console.log(`[BidManager] sortAllStables: required USD value=${requiredUsd.toString()}`);
|
|
18365
|
-
const validBids = [];
|
|
18366
|
-
for (const bid of bids) {
|
|
18367
|
-
const bidUsd = this.computeStablesUsdValue(bid.outputs, chainId);
|
|
18368
|
-
if (bidUsd === null) {
|
|
18369
|
-
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: unable to compute USD value`);
|
|
18370
|
-
continue;
|
|
18371
|
-
}
|
|
18372
|
-
if (bidUsd.lt(requiredUsd)) {
|
|
18373
|
-
console.log(
|
|
18374
|
-
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidUsd.toString()}, required=${requiredUsd.toString()}, covers=${bidUsd.div(requiredUsd).mul(100).toFixed(2)}%)`
|
|
18375
|
-
);
|
|
18376
|
-
} else {
|
|
18377
|
-
console.log(`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: USD value=${bidUsd.toString()}`);
|
|
18378
|
-
}
|
|
18379
|
-
validBids.push({ bid, usdValue: bidUsd });
|
|
18380
|
-
}
|
|
18381
|
-
validBids.sort((a, b) => b.usdValue.comparedTo(a.usdValue));
|
|
18382
|
-
return validBids.map(({ bid }) => bid);
|
|
18383
|
-
}
|
|
18384
|
-
/**
|
|
18385
|
-
* Case C: mixed output tokens (at least one non-stable).
|
|
18386
|
-
* Price every token via on-chain DEX quotes, fall back to raw amounts
|
|
18387
|
-
* if pricing is unavailable. Partial fill bids are allowed.
|
|
18388
|
-
*/
|
|
18389
|
-
async sortMixedOutputs(bids, orderOutputs, chainId) {
|
|
18390
|
-
const requiredUsd = await this.computeOutputsUsdValue(orderOutputs, chainId);
|
|
18391
|
-
if (requiredUsd === null) {
|
|
18392
|
-
console.warn("[BidManager] sortMixedOutputs: output tokens unpriceable, falling back to raw-amount sort");
|
|
18393
|
-
return this.sortByRawAmountFallback(bids, orderOutputs);
|
|
18394
|
-
}
|
|
18395
|
-
console.log(`[BidManager] sortMixedOutputs: required USD value=${requiredUsd.toString()}`);
|
|
18396
|
-
const validBids = [];
|
|
18397
|
-
for (const bid of bids) {
|
|
18398
|
-
const bidUsd = await this.computeOutputsUsdValue(bid.outputs, chainId);
|
|
18399
|
-
if (bidUsd === null) {
|
|
18400
|
-
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: unable to price mixed outputs`);
|
|
18401
|
-
continue;
|
|
18402
|
-
}
|
|
18403
|
-
if (bidUsd.lt(requiredUsd)) {
|
|
18404
|
-
console.log(
|
|
18405
|
-
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidUsd.toString()}, required=${requiredUsd.toString()}, covers=${bidUsd.div(requiredUsd).mul(100).toFixed(2)}%)`
|
|
18406
|
-
);
|
|
18407
|
-
} else {
|
|
18408
|
-
console.log(
|
|
18409
|
-
`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: mixed USD value=${bidUsd.toString()}`
|
|
18410
|
-
);
|
|
18411
|
-
}
|
|
18412
|
-
validBids.push({ bid, usdValue: bidUsd });
|
|
18413
|
-
}
|
|
18414
|
-
validBids.sort((a, b) => b.usdValue.comparedTo(a.usdValue));
|
|
18415
|
-
return validBids.map(({ bid }) => bid);
|
|
18416
|
-
}
|
|
18417
|
-
/**
|
|
18418
|
-
* Fallback when DEX pricing is unavailable.
|
|
18419
|
-
* Computes total spread per bid. Bids missing a required token are rejected.
|
|
18420
|
-
* Bids offering less than required for a token are allowed (partial fill).
|
|
18421
|
-
* Sorted by total offered amount descending.
|
|
18422
|
-
*/
|
|
18423
|
-
sortByRawAmountFallback(bids, orderOutputs) {
|
|
18424
|
-
console.log(
|
|
18425
|
-
`[BidManager] sortByRawAmountFallback: checking ${bids.length} bid(s) against ${orderOutputs.length} required output(s)`
|
|
18426
|
-
);
|
|
18427
|
-
const validBids = [];
|
|
18428
|
-
for (const bid of bids) {
|
|
18429
|
-
let valid = true;
|
|
18430
|
-
let totalOffered = new Decimal2__default.default(0);
|
|
18431
|
-
let rejectReason = "";
|
|
18432
|
-
for (const required of orderOutputs) {
|
|
18433
|
-
const matching = bid.outputs.find((o) => o.token.toLowerCase() === required.token.toLowerCase());
|
|
18434
|
-
if (!matching) {
|
|
18435
|
-
valid = false;
|
|
18436
|
-
rejectReason = `missing output token=${required.token}`;
|
|
18437
|
-
break;
|
|
18438
|
-
}
|
|
18439
|
-
totalOffered = totalOffered.plus(new Decimal2__default.default(matching.amount.toString()));
|
|
18440
|
-
}
|
|
18441
|
-
if (!valid) {
|
|
18442
|
-
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED (fallback): ${rejectReason}`);
|
|
18443
|
-
continue;
|
|
18444
|
-
}
|
|
18445
|
-
const totalRequired = orderOutputs.reduce(
|
|
18446
|
-
(acc, o) => acc.plus(new Decimal2__default.default(o.amount.toString())),
|
|
18447
|
-
new Decimal2__default.default(0)
|
|
18448
|
-
);
|
|
18449
|
-
if (totalOffered.lt(totalRequired)) {
|
|
18450
|
-
console.log(
|
|
18451
|
-
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (fallback) (offered=${totalOffered.toString()}, required=${totalRequired.toString()}, covers=${totalOffered.div(totalRequired).mul(100).toFixed(2)}%)`
|
|
18452
|
-
);
|
|
18453
|
-
} else {
|
|
18454
|
-
console.log(
|
|
18455
|
-
`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED (fallback): totalOffered=${totalOffered.toString()}`
|
|
18456
|
-
);
|
|
18457
|
-
}
|
|
18458
|
-
validBids.push({ bid, totalOffered });
|
|
18459
|
-
}
|
|
18460
|
-
validBids.sort((a, b) => b.totalOffered.comparedTo(a.totalOffered));
|
|
18461
|
-
return validBids.map(({ bid }) => bid);
|
|
18462
|
-
}
|
|
18463
18147
|
// ── Token classification helpers ──────────────────────────────────
|
|
18464
18148
|
/**
|
|
18465
18149
|
* Returns `true` if `tokenAddr` is either USDC or USDT on the given chain.
|
|
@@ -18490,23 +18174,6 @@ var BidManager = class {
|
|
|
18490
18174
|
return configService.getUsdtDecimals(chainId);
|
|
18491
18175
|
}
|
|
18492
18176
|
// ── Basket valuation helpers ──────────────────────────────────────
|
|
18493
|
-
/**
|
|
18494
|
-
* Sums the USD value of a basket of stable tokens (USDC/USDT only),
|
|
18495
|
-
* normalising each amount by its decimal count and treating each token as $1.
|
|
18496
|
-
*
|
|
18497
|
-
* @param outputs - List of token/amount pairs where every token is a stable.
|
|
18498
|
-
* @param chainId - State-machine ID used to look up decimals.
|
|
18499
|
-
* @returns Total USD value as a `Decimal`.
|
|
18500
|
-
*/
|
|
18501
|
-
computeStablesUsdValue(outputs, chainId) {
|
|
18502
|
-
let total = new Decimal2__default.default(0);
|
|
18503
|
-
for (const output of outputs) {
|
|
18504
|
-
const tokenAddr = bytes32ToBytes20(output.token);
|
|
18505
|
-
const decimals = this.getStableDecimals(tokenAddr, chainId);
|
|
18506
|
-
total = total.plus(new Decimal2__default.default(output.amount.toString()).div(new Decimal2__default.default(10).pow(decimals)));
|
|
18507
|
-
}
|
|
18508
|
-
return total;
|
|
18509
|
-
}
|
|
18510
18177
|
/**
|
|
18511
18178
|
* Prices every token in the basket via on-chain DEX quotes (token → USDC).
|
|
18512
18179
|
* Stables are valued at $1. Non-stables are quoted through Uniswap
|
|
@@ -18521,6 +18188,7 @@ var BidManager = class {
|
|
|
18521
18188
|
const { asset: wethAddr } = configService.getWrappedNativeAssetWithDecimals(chainId);
|
|
18522
18189
|
let totalUsd = new Decimal2__default.default(0);
|
|
18523
18190
|
for (const output of outputs) {
|
|
18191
|
+
if (output.amount === 0n) continue;
|
|
18524
18192
|
const tokenAddr = bytes32ToBytes20(output.token);
|
|
18525
18193
|
if (this.isStableToken(tokenAddr, chainId)) {
|
|
18526
18194
|
const decimals = this.getStableDecimals(tokenAddr, chainId);
|
|
@@ -18644,6 +18312,14 @@ var GasEstimator = class {
|
|
|
18644
18312
|
*/
|
|
18645
18313
|
async estimateFillOrder(params, pricingOptions = {}) {
|
|
18646
18314
|
const { order } = params;
|
|
18315
|
+
if (params.outputs !== void 0 && params.inputs === void 0) {
|
|
18316
|
+
throw new Error("Custom output quotes require explicit inputs");
|
|
18317
|
+
}
|
|
18318
|
+
const inputs = (params.inputs ?? order.inputs).map((input) => ({
|
|
18319
|
+
...input,
|
|
18320
|
+
token: normalizeAddressForEvmBytes32(input.token)
|
|
18321
|
+
}));
|
|
18322
|
+
const quotedOutputs = params.outputs ?? order.output.assets;
|
|
18647
18323
|
const orderFeeGasPriceBumpPercent = pricingOptions.orderFeeGasPriceBumpPercent ?? 0n;
|
|
18648
18324
|
const solverPrivateKey = accounts.generatePrivateKey();
|
|
18649
18325
|
const solverAccountAddress = accounts.privateKeyToAddress(solverPrivateKey);
|
|
@@ -18652,7 +18328,7 @@ var GasEstimator = class {
|
|
|
18652
18328
|
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachineId);
|
|
18653
18329
|
const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(destStateMachineId);
|
|
18654
18330
|
const chainId = BigInt(Number.parseInt(destStateMachineId.split("-")[1]));
|
|
18655
|
-
const totalEthValue =
|
|
18331
|
+
const totalEthValue = quotedOutputs.filter((output) => bytes32ToBytes20(output.token) === ADDRESS_ZERO2).reduce((sum, output) => sum + output.amount, 0n);
|
|
18656
18332
|
const [sourceFeeToken, destFeeToken, gasPrice, latestBlock] = await Promise.all([
|
|
18657
18333
|
getFeeToken(this.ctx, this.ctx.source.config.stateMachineId, this.ctx.source),
|
|
18658
18334
|
getFeeToken(this.ctx, this.ctx.dest.config.stateMachineId, this.ctx.dest),
|
|
@@ -18661,7 +18337,7 @@ var GasEstimator = class {
|
|
|
18661
18337
|
]);
|
|
18662
18338
|
const baseFeePerGas = latestBlock.baseFeePerGas ?? gasPrice;
|
|
18663
18339
|
const feeTokenAsBytes32 = bytes20ToBytes32(destFeeToken.address);
|
|
18664
|
-
const assetsForOverrides = [...
|
|
18340
|
+
const assetsForOverrides = [...quotedOutputs];
|
|
18665
18341
|
if (!assetsForOverrides.some((asset) => asset.token.toLowerCase() === feeTokenAsBytes32.toLowerCase())) {
|
|
18666
18342
|
assetsForOverrides.push({ token: feeTokenAsBytes32, amount: 0n });
|
|
18667
18343
|
}
|
|
@@ -18684,6 +18360,7 @@ var GasEstimator = class {
|
|
|
18684
18360
|
]);
|
|
18685
18361
|
const { bundler: bundlerStateOverrides } = stateOverridesResult;
|
|
18686
18362
|
const fillOptions = {
|
|
18363
|
+
inputs,
|
|
18687
18364
|
relayerFee: crossChainFees.postRequestFee,
|
|
18688
18365
|
// Always dispatch with the fee token (see the method docs).
|
|
18689
18366
|
nativeDispatchFee: 0n,
|
|
@@ -18691,7 +18368,7 @@ var GasEstimator = class {
|
|
|
18691
18368
|
// bound here would only risk the estimate reverting on a slow bundler round trip.
|
|
18692
18369
|
// The caller sets the real one on the options it actually signs.
|
|
18693
18370
|
validUntil: 0n,
|
|
18694
|
-
outputs:
|
|
18371
|
+
outputs: quotedOutputs.map((asset) => ({
|
|
18695
18372
|
...asset,
|
|
18696
18373
|
token: normalizeAddressForEvmBytes32(asset.token)
|
|
18697
18374
|
}))
|
|
@@ -18703,12 +18380,8 @@ var GasEstimator = class {
|
|
|
18703
18380
|
let maxFeePerGas = gasPrice + gasPrice * BigInt(maxFeeBumpPercent) / 100n;
|
|
18704
18381
|
const orderForEstimation = { ...order, session: solverAccountAddress };
|
|
18705
18382
|
const commitment = orderCommitment(orderForEstimation);
|
|
18706
|
-
|
|
18707
|
-
const fillOrderCalldata = encodeFillOrder(
|
|
18708
|
-
transformOrderForContract(orderForEstimation),
|
|
18709
|
-
fillOptions,
|
|
18710
|
-
fillOptionsVersion
|
|
18711
|
-
);
|
|
18383
|
+
await assertGatewayRelease(this.ctx.dest.client, intentGatewayV2Address);
|
|
18384
|
+
const fillOrderCalldata = encodeFillOrder(transformOrderForContract(orderForEstimation), fillOptions);
|
|
18712
18385
|
let callGasLimit = 500000n;
|
|
18713
18386
|
let verificationGasLimit = 100000n;
|
|
18714
18387
|
let preVerificationGas = 100000n;
|
|
@@ -18855,7 +18528,8 @@ var GasEstimator = class {
|
|
|
18855
18528
|
totalGasCostWei,
|
|
18856
18529
|
totalGasInFeeToken: totalGasInSourceFeeToken,
|
|
18857
18530
|
relayerFeeInSourceFeeToken: crossChainFees.relayerFeeInSourceFeeToken,
|
|
18858
|
-
fillOptions
|
|
18531
|
+
fillOptions,
|
|
18532
|
+
inputs
|
|
18859
18533
|
};
|
|
18860
18534
|
}
|
|
18861
18535
|
/**
|
|
@@ -19018,35 +18692,47 @@ var OrderStatusChecker = class {
|
|
|
19018
18692
|
}
|
|
19019
18693
|
ctx;
|
|
19020
18694
|
/**
|
|
19021
|
-
*
|
|
19022
|
-
*
|
|
19023
|
-
*
|
|
19024
|
-
* A non-zero value at that slot means the solver has called `fillOrder` and the order is complete
|
|
19025
|
-
* from the user's perspective (the beneficiary has received their tokens).
|
|
18695
|
+
* Whether the order is finalized on the destination chain, read from the gateway's `_filled`
|
|
18696
|
+
* getter. It is set by the completing fill, and by a cancellation, which records the refund
|
|
18697
|
+
* beneficiary there. A partially filled order reads false; see {@link getFillProgress}.
|
|
19026
18698
|
*
|
|
19027
18699
|
* @param order - The V2 order to check. `order.id` is used as the commitment; if not set it is computed.
|
|
19028
|
-
* @returns True if the order has been filled on the destination chain, false otherwise.
|
|
19029
18700
|
*/
|
|
19030
18701
|
async isOrderFilled(order) {
|
|
19031
18702
|
const commitment = order.id ?? orderCommitment(order);
|
|
19032
|
-
const
|
|
19033
|
-
const
|
|
19034
|
-
const filledSlot = await this.ctx.dest.client.readContract({
|
|
18703
|
+
const gateway = this.ctx.dest.configService.getIntentGatewayAddress(destinationStateMachine(order));
|
|
18704
|
+
const finalizer = await this.ctx.dest.client.readContract({
|
|
19035
18705
|
abi: ABI3,
|
|
19036
|
-
address:
|
|
19037
|
-
functionName: "
|
|
18706
|
+
address: gateway,
|
|
18707
|
+
functionName: "_filled",
|
|
19038
18708
|
args: [commitment]
|
|
19039
18709
|
});
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
18710
|
+
return !/^0x0{40}$/i.test(finalizer);
|
|
18711
|
+
}
|
|
18712
|
+
/**
|
|
18713
|
+
* Output credited to the order so far, one entry per leg, read from `_partialFills` on the
|
|
18714
|
+
* destination chain. Several solvers can each fill a slice of a same-chain or cross-chain order,
|
|
18715
|
+
* so this, not {@link isOrderFilled}, says how far along an open order is. Surplus paid above
|
|
18716
|
+
* the order's rate is not counted.
|
|
18717
|
+
*
|
|
18718
|
+
* @param order - The V2 order to check. `order.id` is used as the commitment; if not set it is computed.
|
|
18719
|
+
*/
|
|
18720
|
+
async getFillProgress(order) {
|
|
18721
|
+
const commitment = order.id ?? orderCommitment(order);
|
|
18722
|
+
const gateway = this.ctx.dest.configService.getIntentGatewayAddress(destinationStateMachine(order));
|
|
18723
|
+
return Promise.all(
|
|
18724
|
+
order.output.assets.map(async (asset, index) => ({
|
|
18725
|
+
token: asset.token,
|
|
18726
|
+
amount: await readLegPartialFill(this.ctx.dest.client, gateway, commitment, index, asset.token)
|
|
18727
|
+
}))
|
|
18728
|
+
);
|
|
19045
18729
|
}
|
|
19046
18730
|
/**
|
|
19047
18731
|
* Checks if a V2 order has been refunded by reading the `_orders` mapping on the source chain.
|
|
19048
18732
|
*
|
|
19049
|
-
* Calls `_orders(commitment,
|
|
18733
|
+
* Calls `_orders(commitment, index)` for each input: escrow is held per leg, keyed by the input's
|
|
18734
|
+
* index, so inputs that repeat a token are read separately. A gateway not yet upgraded to per-leg
|
|
18735
|
+
* escrow is read by token instead, see {@link readLegEscrow}. When the order is placed the
|
|
19050
18736
|
* escrowed amounts are stored there. After a successful refund the contract zeroes them out.
|
|
19051
18737
|
* An order is considered refunded when all escrowed input amounts have been returned (i.e. are 0).
|
|
19052
18738
|
*
|
|
@@ -19058,14 +18744,14 @@ var OrderStatusChecker = class {
|
|
|
19058
18744
|
const commitment = order.id ?? orderCommitment(order);
|
|
19059
18745
|
const sourceStateMachineId = viem.isHex(order.source) ? viem.hexToString(order.source) : order.source;
|
|
19060
18746
|
const intentGatewayV2Address = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachineId);
|
|
19061
|
-
for (
|
|
19062
|
-
const
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
18747
|
+
for (let index = 0; index < order.inputs.length; index++) {
|
|
18748
|
+
const escrowedAmount = await readLegEscrow(
|
|
18749
|
+
this.ctx.source.client,
|
|
18750
|
+
intentGatewayV2Address,
|
|
18751
|
+
commitment,
|
|
18752
|
+
index,
|
|
18753
|
+
order.inputs[index].token
|
|
18754
|
+
);
|
|
19069
18755
|
if (escrowedAmount !== 0n) {
|
|
19070
18756
|
return false;
|
|
19071
18757
|
}
|
|
@@ -19073,726 +18759,466 @@ var OrderStatusChecker = class {
|
|
|
19073
18759
|
return true;
|
|
19074
18760
|
}
|
|
19075
18761
|
};
|
|
19076
|
-
|
|
19077
|
-
|
|
19078
|
-
function sortPoolSymbols(symbolA, symbolB) {
|
|
19079
|
-
return symbolA.toLowerCase() <= symbolB.toLowerCase() ? [symbolA, symbolB] : [symbolB, symbolA];
|
|
18762
|
+
function destinationStateMachine(order) {
|
|
18763
|
+
return viem.isHex(order.destination) ? viem.hexToString(order.destination) : order.destination;
|
|
19080
18764
|
}
|
|
19081
|
-
|
|
19082
|
-
|
|
19083
|
-
|
|
19084
|
-
|
|
19085
|
-
|
|
19086
|
-
return
|
|
19087
|
-
poolId: `${token0Symbol}-${token1Symbol}`,
|
|
19088
|
-
token0Symbol,
|
|
19089
|
-
token1Symbol
|
|
19090
|
-
};
|
|
18765
|
+
var ORDERBOOK_URLS = {
|
|
18766
|
+
mainnet: "https://orderbook.hyperfx.finance/mainnet/graphql",
|
|
18767
|
+
testnet: "https://orderbook.hyperfx.finance/testnet/graphql"
|
|
18768
|
+
};
|
|
18769
|
+
function orderbookUrlFor(stateMachineId) {
|
|
18770
|
+
return TESTNET_CHAINS.has(stateMachineId) ? ORDERBOOK_URLS.testnet : ORDERBOOK_URLS.mainnet;
|
|
19091
18771
|
}
|
|
19092
|
-
|
|
19093
|
-
|
|
19094
|
-
var
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19098
|
-
|
|
19099
|
-
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
|
|
19103
|
-
|
|
18772
|
+
var ORDERBOOK_DECIMALS = 18;
|
|
18773
|
+
var ORDERBOOK_SCALE = 10n ** BigInt(ORDERBOOK_DECIMALS);
|
|
18774
|
+
var OrderbookRequestError = class extends Error {
|
|
18775
|
+
constructor(message) {
|
|
18776
|
+
super(`HyperFX orderbook request failed: ${message}`);
|
|
18777
|
+
this.name = "OrderbookRequestError";
|
|
18778
|
+
}
|
|
18779
|
+
};
|
|
18780
|
+
var RATE_FIELDS = "side fillChain rate depthIn depthOut backingLiquidity sourceChains orderCount solverCount";
|
|
18781
|
+
var TOP_OF_BOOK_QUERY = `
|
|
18782
|
+
query TopOfBook($tokenA: String!, $tokenB: String!, $fillChain: String!, $sourceChain: String!) {
|
|
18783
|
+
books { id base quote }
|
|
18784
|
+
aToB: bestRate(tokenIn: $tokenA, tokenOut: $tokenB, fillChain: $fillChain, sourceChain: $sourceChain) { ${RATE_FIELDS} }
|
|
18785
|
+
bToA: bestRate(tokenIn: $tokenB, tokenOut: $tokenA, fillChain: $fillChain, sourceChain: $sourceChain) { ${RATE_FIELDS} }
|
|
18786
|
+
}`;
|
|
18787
|
+
var ROUTE_LIQUIDITY_QUERY = `
|
|
18788
|
+
query RouteLiquidity($route: RouteInput!) {
|
|
18789
|
+
books { id base quote }
|
|
18790
|
+
routeLiquidity(route: $route) {
|
|
18791
|
+
route bestRate slippageBps depthIn depthOut availableLiquidity maxFillableIn orderCount solverCount
|
|
18792
|
+
}
|
|
18793
|
+
}`;
|
|
18794
|
+
var QUOTE_QUERY = `
|
|
18795
|
+
query Quote($route: RouteInput!, $amountIn: BigInt!) {
|
|
18796
|
+
quote(route: $route, amountIn: $amountIn) {
|
|
18797
|
+
route side amountIn slippageBps fillable maxFillableIn
|
|
18798
|
+
fills { advertisedSize orderRate amountIn amountOut }
|
|
18799
|
+
}
|
|
18800
|
+
}`;
|
|
18801
|
+
var QUOTE_PESSIMISTIC_QUERY = `
|
|
18802
|
+
query QuotePessimistic($route: RouteInput!, $amountIn: BigInt!) {
|
|
18803
|
+
quotePessimistic(route: $route, amountIn: $amountIn) {
|
|
18804
|
+
route side amountIn amountOut rate priceBucket slippageBps fillable maxFillableIn
|
|
18805
|
+
}
|
|
18806
|
+
}`;
|
|
18807
|
+
var ORDERBOOK_QUERIES = {
|
|
18808
|
+
topOfBook: TOP_OF_BOOK_QUERY,
|
|
18809
|
+
routeLiquidity: ROUTE_LIQUIDITY_QUERY,
|
|
18810
|
+
quote: QUOTE_QUERY,
|
|
18811
|
+
quotePessimistic: QUOTE_PESSIMISTIC_QUERY
|
|
18812
|
+
};
|
|
18813
|
+
var HyperFxOrderbook = class {
|
|
18814
|
+
client;
|
|
18815
|
+
/** @param urlOrClient - The orderbook's GraphQL URL, or a configured `graphql-request` client. */
|
|
18816
|
+
constructor(urlOrClient = ORDERBOOK_URLS.mainnet) {
|
|
18817
|
+
this.client = typeof urlOrClient === "string" ? new graphqlRequest.GraphQLClient(urlOrClient) : urlOrClient;
|
|
18818
|
+
}
|
|
19104
18819
|
/**
|
|
19105
|
-
*
|
|
19106
|
-
*
|
|
19107
|
-
|
|
19108
|
-
|
|
19109
|
-
|
|
19110
|
-
|
|
19111
|
-
|
|
19112
|
-
|
|
19113
|
-
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
*/
|
|
19117
|
-
async getAvailableLiquidity(params) {
|
|
19118
|
-
const pool = resolveLiquidityPool(params.source.symbol, params.destination.symbol);
|
|
19119
|
-
const direction = params.source.symbol.toLowerCase() === pool.token0Symbol.toLowerCase() ? SELL : BUY;
|
|
19120
|
-
const variables = {
|
|
19121
|
-
poolId: pool.poolId,
|
|
19122
|
-
sourceChain: params.source.chain,
|
|
19123
|
-
destinationChain: params.destination.chain,
|
|
19124
|
-
direction
|
|
18820
|
+
* The best bid and ask on `fillChain` for the pair `tokenA`/`tokenB`, counting
|
|
18821
|
+
* only orders a swap from `sourceChain` can use.
|
|
18822
|
+
*/
|
|
18823
|
+
async topOfBook(params) {
|
|
18824
|
+
const data = await this.request(TOP_OF_BOOK_QUERY, params);
|
|
18825
|
+
const book = findBook(data.books, params.tokenA, params.tokenB);
|
|
18826
|
+
const rates = [data.aToB, data.bToA].filter((rate) => rate !== null).map(parseRate);
|
|
18827
|
+
return {
|
|
18828
|
+
book,
|
|
18829
|
+
bid: rates.find((rate) => rate.side === "BID") ?? null,
|
|
18830
|
+
ask: rates.find((rate) => rate.side === "ASK") ?? null
|
|
19125
18831
|
};
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
}
|
|
19130
|
-
const
|
|
19131
|
-
if (!chainLiquidity) return void 0;
|
|
19132
|
-
const route = response.poolRoutes.nodes[0];
|
|
18832
|
+
}
|
|
18833
|
+
/** Total liquidity on a route, no amount required. */
|
|
18834
|
+
async routeLiquidity(route) {
|
|
18835
|
+
const { books, routeLiquidity: raw } = await this.request(ROUTE_LIQUIDITY_QUERY, { route });
|
|
18836
|
+
const book = findBook(books, route.tokenIn, route.tokenOut);
|
|
19133
18837
|
return {
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
|
|
19137
|
-
|
|
19138
|
-
|
|
19139
|
-
|
|
19140
|
-
|
|
19141
|
-
|
|
19142
|
-
|
|
19143
|
-
|
|
19144
|
-
|
|
19145
|
-
...readLiquiditySlice(route.depth, route.bidCount, "explicit route"),
|
|
19146
|
-
updatedAt: readIndexerDate(route.lastUpdatedAt, "route lastUpdatedAt")
|
|
19147
|
-
} : null
|
|
18838
|
+
route: raw.route,
|
|
18839
|
+
book,
|
|
18840
|
+
side: sameSymbol(book.base, route.tokenIn) ? "BID" : "ASK",
|
|
18841
|
+
bestRate: optionalBigInt(raw.bestRate),
|
|
18842
|
+
slippageBps: raw.slippageBps,
|
|
18843
|
+
depthIn: BigInt(raw.depthIn),
|
|
18844
|
+
depthOut: BigInt(raw.depthOut),
|
|
18845
|
+
availableLiquidity: BigInt(raw.availableLiquidity),
|
|
18846
|
+
maxFillableIn: BigInt(raw.maxFillableIn),
|
|
18847
|
+
orderCount: raw.orderCount,
|
|
18848
|
+
solverCount: raw.solverCount
|
|
19148
18849
|
};
|
|
19149
18850
|
}
|
|
19150
18851
|
/**
|
|
19151
|
-
*
|
|
19152
|
-
*
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
async getBuyAndSellRates(params) {
|
|
19159
|
-
const pool = resolveLiquidityPool(params.tokenInSymbol, params.tokenOutSymbol);
|
|
19160
|
-
const response = await this.queryClient.request(BUY_AND_SELL_RATES, {
|
|
19161
|
-
poolId: pool.poolId
|
|
18852
|
+
* The optimistic quote for `amountIn` (1e18 tokenIn) on a route: the route's orders, best price
|
|
18853
|
+
* first, each taking what it can at its own price. The fills' `amountOut`s sum to the output.
|
|
18854
|
+
*/
|
|
18855
|
+
async quote(route, amountIn) {
|
|
18856
|
+
const { quote: raw } = await this.request(QUOTE_QUERY, {
|
|
18857
|
+
route,
|
|
18858
|
+
amountIn: amountIn.toString()
|
|
19162
18859
|
});
|
|
19163
|
-
|
|
19164
|
-
|
|
19165
|
-
|
|
19166
|
-
|
|
19167
|
-
|
|
19168
|
-
|
|
19169
|
-
|
|
19170
|
-
|
|
19171
|
-
|
|
19172
|
-
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
|
|
19179
|
-
|
|
18860
|
+
return {
|
|
18861
|
+
route: raw.route,
|
|
18862
|
+
side: raw.side,
|
|
18863
|
+
amountIn: BigInt(raw.amountIn),
|
|
18864
|
+
slippageBps: raw.slippageBps,
|
|
18865
|
+
fillable: raw.fillable,
|
|
18866
|
+
maxFillableIn: BigInt(raw.maxFillableIn),
|
|
18867
|
+
fills: raw.fills.map((fill) => ({
|
|
18868
|
+
advertisedSize: BigInt(fill.advertisedSize),
|
|
18869
|
+
orderRate: BigInt(fill.orderRate),
|
|
18870
|
+
amountIn: BigInt(fill.amountIn),
|
|
18871
|
+
amountOut: BigInt(fill.amountOut)
|
|
18872
|
+
}))
|
|
18873
|
+
};
|
|
18874
|
+
}
|
|
18875
|
+
/**
|
|
18876
|
+
* The pessimistic quote for `amountIn` (1e18 tokenIn) on a route: one price, from the first level
|
|
18877
|
+
* deep enough to fill the whole trade by itself, at which every order in it fills; the route's
|
|
18878
|
+
* worst price when no one level can but its levels together can.
|
|
18879
|
+
*/
|
|
18880
|
+
async quotePessimistic(route, amountIn) {
|
|
18881
|
+
const { quotePessimistic: raw } = await this.request(
|
|
18882
|
+
QUOTE_PESSIMISTIC_QUERY,
|
|
18883
|
+
{ route, amountIn: amountIn.toString() }
|
|
19180
18884
|
);
|
|
19181
|
-
const quoteIsTokenOut = quoteTokenSymbol === params.tokenOutSymbol;
|
|
19182
|
-
const orientedBuy = quoteIsTokenOut ? direct : reverse;
|
|
19183
|
-
const orientedSell = quoteIsTokenOut ? reverse : direct;
|
|
19184
18885
|
return {
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
|
|
19188
|
-
|
|
19189
|
-
|
|
19190
|
-
|
|
19191
|
-
|
|
19192
|
-
|
|
18886
|
+
route: raw.route,
|
|
18887
|
+
side: raw.side,
|
|
18888
|
+
amountIn: BigInt(raw.amountIn),
|
|
18889
|
+
amountOut: BigInt(raw.amountOut),
|
|
18890
|
+
rate: optionalBigInt(raw.rate),
|
|
18891
|
+
priceBucket: optionalBigInt(raw.priceBucket),
|
|
18892
|
+
slippageBps: raw.slippageBps,
|
|
18893
|
+
fillable: raw.fillable,
|
|
18894
|
+
maxFillableIn: BigInt(raw.maxFillableIn)
|
|
19193
18895
|
};
|
|
19194
18896
|
}
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
18897
|
+
async request(query, variables) {
|
|
18898
|
+
try {
|
|
18899
|
+
return await this.client.request(query, variables);
|
|
18900
|
+
} catch (error) {
|
|
18901
|
+
throw new OrderbookRequestError(describeError(error));
|
|
18902
|
+
}
|
|
19200
18903
|
}
|
|
19201
18904
|
};
|
|
18905
|
+
function describeError(error) {
|
|
18906
|
+
const graphqlErrors = error?.response?.errors;
|
|
18907
|
+
if (graphqlErrors?.length) return graphqlErrors.map((e) => e.message).join("; ");
|
|
18908
|
+
return error instanceof Error ? error.message : String(error);
|
|
18909
|
+
}
|
|
18910
|
+
function sameSymbol(a, b) {
|
|
18911
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
18912
|
+
}
|
|
18913
|
+
function findBook(books, tokenA, tokenB) {
|
|
18914
|
+
const book = books.find(
|
|
18915
|
+
(b) => sameSymbol(b.base, tokenA) && sameSymbol(b.quote, tokenB) || sameSymbol(b.base, tokenB) && sameSymbol(b.quote, tokenA)
|
|
18916
|
+
);
|
|
18917
|
+
if (!book) throw new OrderbookRequestError(`no book trades ${tokenA} for ${tokenB}`);
|
|
18918
|
+
return book;
|
|
18919
|
+
}
|
|
18920
|
+
function optionalBigInt(value) {
|
|
18921
|
+
return value === null ? null : BigInt(value);
|
|
18922
|
+
}
|
|
18923
|
+
function parseRate(raw) {
|
|
18924
|
+
return {
|
|
18925
|
+
side: raw.side,
|
|
18926
|
+
fillChain: raw.fillChain,
|
|
18927
|
+
rate: BigInt(raw.rate),
|
|
18928
|
+
depthIn: BigInt(raw.depthIn),
|
|
18929
|
+
depthOut: BigInt(raw.depthOut),
|
|
18930
|
+
backingLiquidity: BigInt(raw.backingLiquidity),
|
|
18931
|
+
sourceChains: raw.sourceChains,
|
|
18932
|
+
orderCount: raw.orderCount,
|
|
18933
|
+
solverCount: raw.solverCount
|
|
18934
|
+
};
|
|
18935
|
+
}
|
|
18936
|
+
|
|
18937
|
+
// src/protocols/intents/orderbook/types.ts
|
|
19202
18938
|
var UnsupportedLiquidityAssetError = class extends Error {
|
|
19203
18939
|
constructor(chain, asset) {
|
|
19204
|
-
super(`No configured
|
|
18940
|
+
super(`No configured asset found for ${asset} on ${chain}`);
|
|
19205
18941
|
this.name = "UnsupportedLiquidityAssetError";
|
|
19206
18942
|
}
|
|
19207
18943
|
};
|
|
19208
18944
|
var UnsupportedLiquidityChainError = class extends Error {
|
|
19209
18945
|
constructor(chainId) {
|
|
19210
|
-
super(`No configured
|
|
18946
|
+
super(`No configured chain found for chain ID ${chainId}`);
|
|
19211
18947
|
this.name = "UnsupportedLiquidityChainError";
|
|
19212
18948
|
}
|
|
19213
18949
|
};
|
|
19214
|
-
|
|
19215
|
-
|
|
19216
|
-
|
|
19217
|
-
|
|
19218
|
-
|
|
19219
|
-
|
|
19220
|
-
|
|
19221
|
-
|
|
19222
|
-
|
|
19223
|
-
|
|
19224
|
-
|
|
19225
|
-
|
|
19226
|
-
|
|
18950
|
+
var OrderbookQuoteNotConvergedError = class extends Error {
|
|
18951
|
+
constructor(route, rounds, lastAmountIn) {
|
|
18952
|
+
super(
|
|
18953
|
+
`No input for ${route.tokenIn} -> ${route.tokenOut} on ${route.sourceChain} -> ${route.destinationChain} delivered the requested output within ${rounds} quotes; the last tried ${lastAmountIn} raw units`
|
|
18954
|
+
);
|
|
18955
|
+
this.route = route;
|
|
18956
|
+
this.rounds = rounds;
|
|
18957
|
+
this.lastAmountIn = lastAmountIn;
|
|
18958
|
+
this.name = "OrderbookQuoteNotConvergedError";
|
|
18959
|
+
}
|
|
18960
|
+
route;
|
|
18961
|
+
rounds;
|
|
18962
|
+
lastAmountIn;
|
|
18963
|
+
};
|
|
18964
|
+
var InsufficientOrderbookLiquidityError = class extends Error {
|
|
18965
|
+
constructor(route, maxFillableIn) {
|
|
18966
|
+
super(
|
|
18967
|
+
`The HyperFX orderbook cannot fill ${route.tokenIn} -> ${route.tokenOut} on ${route.sourceChain} -> ${route.destinationChain}; max fillable input is ${maxFillableIn} raw units`
|
|
18968
|
+
);
|
|
18969
|
+
this.route = route;
|
|
18970
|
+
this.maxFillableIn = maxFillableIn;
|
|
18971
|
+
this.name = "InsufficientOrderbookLiquidityError";
|
|
19227
18972
|
}
|
|
19228
|
-
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
18973
|
+
route;
|
|
18974
|
+
maxFillableIn;
|
|
18975
|
+
};
|
|
18976
|
+
|
|
18977
|
+
// src/protocols/intents/orderbook/market.ts
|
|
18978
|
+
var MAX_EXACT_OUTPUT_ROUNDS = 16;
|
|
18979
|
+
var OrderbookMarket = class {
|
|
18980
|
+
constructor(configService, orderbook) {
|
|
18981
|
+
this.configService = configService;
|
|
18982
|
+
this.orderbook = orderbook;
|
|
18983
|
+
}
|
|
18984
|
+
configService;
|
|
18985
|
+
orderbook;
|
|
18986
|
+
async quoteIntent(params, sourceChain, destinationChain) {
|
|
18987
|
+
const orderbook = this.orderbook();
|
|
18988
|
+
if (!params.optimistic) {
|
|
18989
|
+
const { quote: quote2, tokenIn: tokenIn2, tokenOut: tokenOut2 } = await this.priceIntent(
|
|
18990
|
+
params,
|
|
18991
|
+
sourceChain,
|
|
18992
|
+
destinationChain,
|
|
18993
|
+
(route, amountIn) => orderbook.quotePessimistic(route, amountIn),
|
|
18994
|
+
levelQuoteTotals
|
|
18995
|
+
);
|
|
18996
|
+
return {
|
|
18997
|
+
route: quote2.route,
|
|
18998
|
+
side: quote2.side,
|
|
18999
|
+
amountIn: fromOrderbookAmount(quote2.amountIn, tokenIn2.decimals),
|
|
19000
|
+
amountOut: fromOrderbookAmount(quote2.amountOut, tokenOut2.decimals),
|
|
19001
|
+
rate: quote2.rate,
|
|
19002
|
+
priceBucket: quote2.priceBucket,
|
|
19003
|
+
slippageBps: quote2.slippageBps,
|
|
19004
|
+
fillable: quote2.fillable,
|
|
19005
|
+
maxFillableIn: fromOrderbookAmount(quote2.maxFillableIn, tokenIn2.decimals)
|
|
19006
|
+
};
|
|
19007
|
+
}
|
|
19008
|
+
const { quote, tokenIn, tokenOut } = await this.priceIntent(
|
|
19009
|
+
params,
|
|
19010
|
+
sourceChain,
|
|
19011
|
+
destinationChain,
|
|
19012
|
+
(route, amountIn) => orderbook.quote(route, amountIn),
|
|
19013
|
+
swapQuoteTotals
|
|
19014
|
+
);
|
|
19239
19015
|
return {
|
|
19240
|
-
|
|
19241
|
-
|
|
19016
|
+
route: quote.route,
|
|
19017
|
+
side: quote.side,
|
|
19018
|
+
amountIn: fromOrderbookAmount(quote.amountIn, tokenIn.decimals),
|
|
19019
|
+
slippageBps: quote.slippageBps,
|
|
19020
|
+
fillable: quote.fillable,
|
|
19021
|
+
maxFillableIn: fromOrderbookAmount(quote.maxFillableIn, tokenIn.decimals),
|
|
19022
|
+
legs: quote.fills.map((fill) => ({
|
|
19023
|
+
advertisedSize: fromOrderbookAmount(fill.advertisedSize, tokenOut.decimals),
|
|
19024
|
+
orderRate: fill.orderRate,
|
|
19025
|
+
amountIn: fromOrderbookAmount(fill.amountIn, tokenIn.decimals),
|
|
19026
|
+
amountOut: fromOrderbookAmount(fill.amountOut, tokenOut.decimals)
|
|
19027
|
+
}))
|
|
19242
19028
|
};
|
|
19243
|
-
} catch (error) {
|
|
19244
|
-
if (error instanceof InvalidLiquidityIndexerResponseError) throw error;
|
|
19245
|
-
throw new InvalidLiquidityIndexerResponseError(`${label} is not a positive integer`);
|
|
19246
19029
|
}
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19030
|
+
/**
|
|
19031
|
+
* The fillable quote for an exact input, or for the input found to deliver an
|
|
19032
|
+
* exact output, with the assets it trades.
|
|
19033
|
+
*/
|
|
19034
|
+
async priceIntent(params, sourceChain, destinationChain, price, totals) {
|
|
19035
|
+
validateQuoteParams(params);
|
|
19036
|
+
const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
|
|
19037
|
+
const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
|
|
19038
|
+
const route = toRoute(tokenIn, tokenOut);
|
|
19039
|
+
if (params.amountIn !== void 0) {
|
|
19040
|
+
const quote2 = await price(route, toOrderbookAmount(params.amountIn, tokenIn.decimals));
|
|
19041
|
+
const { fillable, amountOut, maxFillableIn } = totals(quote2);
|
|
19042
|
+
if (!fillable || fromOrderbookAmount(amountOut, tokenOut.decimals) === 0n) {
|
|
19043
|
+
throw this.insufficient(route, maxFillableIn, tokenIn);
|
|
19044
|
+
}
|
|
19045
|
+
return { quote: quote2, tokenIn, tokenOut };
|
|
19046
|
+
}
|
|
19047
|
+
const targetOut = toOrderbookAmount(params.amountOut, tokenOut.decimals);
|
|
19048
|
+
const quote = await this.quoteExactOutput(route, targetOut, tokenIn, price, totals);
|
|
19049
|
+
return { quote, tokenIn, tokenOut };
|
|
19050
|
+
}
|
|
19051
|
+
async availableLiquidity(params, sourceChain, destinationChain) {
|
|
19052
|
+
const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
|
|
19053
|
+
const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
|
|
19054
|
+
const liquidity = await this.orderbook().routeLiquidity(toRoute(tokenIn, tokenOut));
|
|
19055
|
+
const [base3, quote] = liquidity.side === "BID" ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
|
|
19056
|
+
return {
|
|
19057
|
+
sourceChain: tokenIn.chain,
|
|
19058
|
+
destinationChain: tokenOut.chain,
|
|
19059
|
+
tokenInSymbol: tokenIn.symbol,
|
|
19060
|
+
tokenOutSymbol: tokenOut.symbol,
|
|
19061
|
+
tokenAddress: tokenOut.address,
|
|
19062
|
+
route: liquidity.route,
|
|
19063
|
+
side: liquidity.side,
|
|
19064
|
+
baseTokenSymbol: base3.symbol,
|
|
19065
|
+
quoteTokenSymbol: quote.symbol,
|
|
19066
|
+
bestRate: formatOptional(liquidity.bestRate),
|
|
19067
|
+
availableLiquidity: format(liquidity.availableLiquidity),
|
|
19068
|
+
depthIn: format(liquidity.depthIn),
|
|
19069
|
+
depthOut: format(liquidity.depthOut),
|
|
19070
|
+
maxFillableIn: format(liquidity.maxFillableIn),
|
|
19071
|
+
orderCount: liquidity.orderCount,
|
|
19072
|
+
solverCount: liquidity.solverCount
|
|
19073
|
+
};
|
|
19251
19074
|
}
|
|
19252
|
-
|
|
19253
|
-
|
|
19254
|
-
|
|
19255
|
-
|
|
19256
|
-
|
|
19257
|
-
|
|
19258
|
-
|
|
19259
|
-
|
|
19260
|
-
}
|
|
19261
|
-
|
|
19262
|
-
|
|
19263
|
-
|
|
19264
|
-
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
19270
|
-
|
|
19271
|
-
|
|
19272
|
-
|
|
19075
|
+
async buyAndSellRates(params) {
|
|
19076
|
+
const tokenIn = this.assetBySymbol(params.sourceChain, params.tokenInSymbol);
|
|
19077
|
+
const tokenOut = this.assetBySymbol(params.destinationChain, params.tokenOutSymbol);
|
|
19078
|
+
const { book, bid, ask } = await this.orderbook().topOfBook({
|
|
19079
|
+
tokenA: tokenIn.symbol,
|
|
19080
|
+
tokenB: tokenOut.symbol,
|
|
19081
|
+
fillChain: tokenOut.chain,
|
|
19082
|
+
sourceChain: tokenIn.chain
|
|
19083
|
+
});
|
|
19084
|
+
const bidRate = bid?.rate ?? null;
|
|
19085
|
+
const askRate = ask?.rate ?? null;
|
|
19086
|
+
const mid = bidRate !== null && askRate !== null ? (bidRate + askRate) / 2n : null;
|
|
19087
|
+
const spread = bidRate !== null && askRate !== null && askRate >= bidRate ? askRate - bidRate : null;
|
|
19088
|
+
return {
|
|
19089
|
+
baseTokenSymbol: book.base,
|
|
19090
|
+
quoteTokenSymbol: book.quote,
|
|
19091
|
+
sourceChain: tokenIn.chain,
|
|
19092
|
+
destinationChain: tokenOut.chain,
|
|
19093
|
+
bid: formatOptional(bidRate),
|
|
19094
|
+
ask: formatOptional(askRate),
|
|
19095
|
+
mid: formatOptional(mid),
|
|
19096
|
+
spread: formatOptional(spread),
|
|
19097
|
+
spreadBps: spread !== null && mid ? Number(spread * 1000000n / mid) / 100 : null
|
|
19098
|
+
};
|
|
19273
19099
|
}
|
|
19274
|
-
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
|
|
19278
|
-
|
|
19100
|
+
/**
|
|
19101
|
+
* The orderbook only quotes an input amount, so an output is priced by
|
|
19102
|
+
* guessing the input from the best rate, then keeping the part of each quote
|
|
19103
|
+
* filled better than its worst rate and re-pricing the rest of `targetOut` at
|
|
19104
|
+
* the input-to-output ratio that part filled at, until a quote delivers it.
|
|
19105
|
+
* That ratio is the orderbook's own, with the protocol fee already taken off.
|
|
19106
|
+
*/
|
|
19107
|
+
async quoteExactOutput(route, targetOut, tokenIn, price, totals) {
|
|
19108
|
+
const liquidity = await this.orderbook().routeLiquidity(route);
|
|
19109
|
+
if (liquidity.bestRate === null) throw this.insufficient(route, 0n, tokenIn);
|
|
19110
|
+
const inputUnit = toOrderbookAmount(1n, tokenIn.decimals);
|
|
19111
|
+
let amountIn = roundUpTo(requiredInput(liquidity.side, targetOut, liquidity.bestRate), inputUnit);
|
|
19112
|
+
let lastAmountIn = amountIn;
|
|
19113
|
+
for (let round = 0; round < MAX_EXACT_OUTPUT_ROUNDS; round++) {
|
|
19114
|
+
if (amountIn > liquidity.maxFillableIn) throw this.insufficient(route, liquidity.maxFillableIn, tokenIn);
|
|
19115
|
+
const served = await price(route, amountIn);
|
|
19116
|
+
const quote = totals(served);
|
|
19117
|
+
if (quote.fillable && quote.amountOut >= targetOut) return served;
|
|
19118
|
+
lastAmountIn = amountIn;
|
|
19119
|
+
const betterIn = quote.amountIn - quote.worstIn;
|
|
19120
|
+
const betterOut = quote.amountOut - quote.worstOut;
|
|
19121
|
+
const next = quote.fillable && quote.worstOut > 0n ? betterIn + roundUpTo(divCeil((targetOut - betterOut) * quote.worstIn, quote.worstOut), inputUnit) : amountIn;
|
|
19122
|
+
amountIn = next > amountIn ? next : amountIn + inputUnit;
|
|
19123
|
+
}
|
|
19124
|
+
throw new OrderbookQuoteNotConvergedError(
|
|
19125
|
+
route,
|
|
19126
|
+
MAX_EXACT_OUTPUT_ROUNDS,
|
|
19127
|
+
fromOrderbookAmount(lastAmountIn, tokenIn.decimals)
|
|
19279
19128
|
);
|
|
19280
|
-
this.name = "UnsupportedIntentQuotePairError";
|
|
19281
19129
|
}
|
|
19282
|
-
|
|
19283
|
-
|
|
19284
|
-
constructor(tokenA, tokenB) {
|
|
19285
|
-
super(`No Phantom order price snapshot found for ${tokenA} -> ${tokenB}`);
|
|
19286
|
-
this.name = "PhantomSnapshotUnavailableError";
|
|
19130
|
+
insufficient(route, maxFillableIn, tokenIn) {
|
|
19131
|
+
return new InsufficientOrderbookLiquidityError(route, fromOrderbookAmount(maxFillableIn, tokenIn.decimals));
|
|
19287
19132
|
}
|
|
19288
|
-
|
|
19289
|
-
|
|
19290
|
-
|
|
19291
|
-
|
|
19292
|
-
|
|
19133
|
+
assetByAddress(chain, address) {
|
|
19134
|
+
const resolvedChain = resolveChain(chain);
|
|
19135
|
+
return withDecimals(
|
|
19136
|
+
resolvedChain,
|
|
19137
|
+
address,
|
|
19138
|
+
this.configService.getAssetMetadataByAddress(resolvedChain, address)
|
|
19139
|
+
);
|
|
19293
19140
|
}
|
|
19294
|
-
|
|
19295
|
-
|
|
19296
|
-
|
|
19297
|
-
const route = params.source && params.destination && params.tokenIn && params.tokenOut ? ` for ${params.tokenIn} -> ${params.tokenOut} on ${params.source} -> ${params.destination}` : "";
|
|
19298
|
-
const side = params.side ? ` ${params.side}` : "";
|
|
19299
|
-
super(`No indexed${side} rate available${route}`);
|
|
19300
|
-
this.name = "IndexedRateUnavailableError";
|
|
19141
|
+
assetBySymbol(chain, symbol) {
|
|
19142
|
+
const resolvedChain = resolveChain(chain);
|
|
19143
|
+
return withDecimals(resolvedChain, symbol, this.configService.getAssetMetadataBySymbol(resolvedChain, symbol));
|
|
19301
19144
|
}
|
|
19302
19145
|
};
|
|
19303
|
-
|
|
19304
|
-
|
|
19305
|
-
|
|
19306
|
-
|
|
19146
|
+
function resolveChain(chain) {
|
|
19147
|
+
const stateMachineId = getConfigByStateMachineId(chain)?.stateMachineId;
|
|
19148
|
+
if (!stateMachineId) throw new UnsupportedLiquidityChainError(chain);
|
|
19149
|
+
return stateMachineId;
|
|
19150
|
+
}
|
|
19151
|
+
function withDecimals(chain, asset, metadata) {
|
|
19152
|
+
if (!metadata) throw new UnsupportedLiquidityAssetError(chain, asset);
|
|
19153
|
+
const { decimals } = metadata;
|
|
19154
|
+
if (decimals === void 0 || !Number.isSafeInteger(decimals) || decimals < 0 || decimals > ORDERBOOK_DECIMALS) {
|
|
19155
|
+
throw new UnsupportedLiquidityAssetError(chain, `${metadata.symbol} (decimals are not configured)`);
|
|
19307
19156
|
}
|
|
19308
|
-
};
|
|
19309
|
-
|
|
19157
|
+
return { chain, symbol: metadata.symbol, address: metadata.address, decimals };
|
|
19158
|
+
}
|
|
19310
19159
|
function validateQuoteParams(params) {
|
|
19311
19160
|
const hasAmountIn = params.amountIn !== void 0;
|
|
19312
19161
|
const hasAmountOut = params.amountOut !== void 0;
|
|
19313
19162
|
if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
|
|
19314
19163
|
if (params.amountIn !== void 0 && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
|
|
19315
19164
|
if (params.amountOut !== void 0 && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
|
|
19316
|
-
if (params.tokenIn.toLowerCase() === params.tokenOut.toLowerCase()) {
|
|
19317
|
-
throw new Error("tokenIn and tokenOut cannot be the same");
|
|
19318
|
-
}
|
|
19319
19165
|
}
|
|
19320
|
-
|
|
19321
|
-
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
abi: IntentGatewayV2_default.ABI,
|
|
19328
|
-
functionName: "params"
|
|
19329
|
-
});
|
|
19330
|
-
const protocolFeeBps = Array.isArray(gatewayParams) ? BigInt(gatewayParams[4]) : BigInt(gatewayParams.protocolFeeBps ?? 0);
|
|
19331
|
-
if (protocolFeeBps < 0n || protocolFeeBps >= BPS_DENOMINATOR) {
|
|
19332
|
-
throw new Error(`Invalid IntentGateway protocol fee: ${protocolFeeBps} bps`);
|
|
19333
|
-
}
|
|
19334
|
-
return protocolFeeBps;
|
|
19335
|
-
}
|
|
19336
|
-
function deductProtocolFee(amount, protocolFeeBps) {
|
|
19337
|
-
if (protocolFeeBps <= 0n) return amount;
|
|
19338
|
-
const fee = amount * protocolFeeBps / BPS_DENOMINATOR;
|
|
19339
|
-
return amount - fee;
|
|
19166
|
+
function toRoute(tokenIn, tokenOut) {
|
|
19167
|
+
return {
|
|
19168
|
+
tokenIn: tokenIn.symbol,
|
|
19169
|
+
tokenOut: tokenOut.symbol,
|
|
19170
|
+
sourceChain: tokenIn.chain,
|
|
19171
|
+
destinationChain: tokenOut.chain
|
|
19172
|
+
};
|
|
19340
19173
|
}
|
|
19341
|
-
function
|
|
19342
|
-
|
|
19343
|
-
if (protocolFeeBps >= BPS_DENOMINATOR) throw new Error("protocolFeeBps must be less than 10,000");
|
|
19344
|
-
return divCeil(netAmount * BPS_DENOMINATOR, BPS_DENOMINATOR - protocolFeeBps);
|
|
19174
|
+
function requiredInput(side, amountOut, rate) {
|
|
19175
|
+
return side === "BID" ? divCeil(amountOut * ORDERBOOK_SCALE, rate) : divCeil(amountOut * rate, ORDERBOOK_SCALE);
|
|
19345
19176
|
}
|
|
19346
|
-
function
|
|
19347
|
-
|
|
19348
|
-
|
|
19177
|
+
function swapQuoteTotals(quote) {
|
|
19178
|
+
const worstFill = quote.fills.at(-1);
|
|
19179
|
+
if (quote.fillable && !worstFill)
|
|
19180
|
+
throw new OrderbookRequestError("the orderbook served a fillable quote with no fills");
|
|
19181
|
+
return {
|
|
19182
|
+
side: quote.side,
|
|
19183
|
+
amountIn: quote.amountIn,
|
|
19184
|
+
amountOut: quote.fills.reduce((total, fill) => total + fill.amountOut, 0n),
|
|
19185
|
+
fillable: quote.fillable,
|
|
19186
|
+
maxFillableIn: quote.maxFillableIn,
|
|
19187
|
+
worstIn: worstFill?.amountIn ?? 0n,
|
|
19188
|
+
worstOut: worstFill?.amountOut ?? 0n
|
|
19189
|
+
};
|
|
19349
19190
|
}
|
|
19350
|
-
|
|
19351
|
-
|
|
19352
|
-
|
|
19353
|
-
var UniswapV4IntentQuoteStrategy = class {
|
|
19354
|
-
constructor(chainConfigService) {
|
|
19355
|
-
this.chainConfigService = chainConfigService;
|
|
19356
|
-
}
|
|
19357
|
-
chainConfigService;
|
|
19358
|
-
baseQuoteClient;
|
|
19359
|
-
async quote(params, source, destination) {
|
|
19360
|
-
validateQuoteParams(params);
|
|
19361
|
-
const protocolFeeBps = await readProtocolFeeBps(this.chainConfigService, source);
|
|
19362
|
-
const quoteClient = this.resolveQuoteClient(source, destination);
|
|
19363
|
-
const poolConfig = this.resolvePoolConfig(params, source.stateMachineId, destination.stateMachineId);
|
|
19364
|
-
return params.amountIn !== void 0 ? this.quoteExactInput({ params, client: quoteClient, protocolFeeBps, poolConfig }) : this.quoteExactOutput({ params, client: quoteClient, protocolFeeBps, poolConfig });
|
|
19365
|
-
}
|
|
19366
|
-
resolveQuoteClient(source, destination) {
|
|
19367
|
-
if (source.stateMachineId === UNISWAP_INTENT_QUOTE_CHAIN) return source.client;
|
|
19368
|
-
if (destination.stateMachineId === UNISWAP_INTENT_QUOTE_CHAIN) return destination.client;
|
|
19369
|
-
if (this.baseQuoteClient) return this.baseQuoteClient;
|
|
19370
|
-
const rpcUrl = this.chainConfigService.getRpcUrl(UNISWAP_INTENT_QUOTE_CHAIN);
|
|
19371
|
-
if (!rpcUrl) throw new Error(`RPC URL is not configured for ${UNISWAP_INTENT_QUOTE_CHAIN}`);
|
|
19372
|
-
const baseQuoteClient = viem.createPublicClient({
|
|
19373
|
-
chain: chains$1.base,
|
|
19374
|
-
transport: viem.http(rpcUrl)
|
|
19375
|
-
});
|
|
19376
|
-
this.baseQuoteClient = baseQuoteClient;
|
|
19377
|
-
return baseQuoteClient;
|
|
19378
|
-
}
|
|
19379
|
-
resolvePoolConfig(params, source, destination) {
|
|
19380
|
-
const override = params.uniswapV4?.poolKey;
|
|
19381
|
-
if (override) {
|
|
19382
|
-
const poolKey = normalizePoolKey(override);
|
|
19383
|
-
const tokenInForQuote = viem.getAddress(override.currencyIn ?? params.tokenIn);
|
|
19384
|
-
if (tokenInForQuote !== poolKey.currency0 && tokenInForQuote !== poolKey.currency1) {
|
|
19385
|
-
throw new Error(
|
|
19386
|
-
`Input currency ${tokenInForQuote} is not part of the override pool (${poolKey.currency0}, ${poolKey.currency1}). For cross-chain quotes pass uniswapV4.poolKey.currencyIn with the Base-side input currency address.`
|
|
19387
|
-
);
|
|
19388
|
-
}
|
|
19389
|
-
return {
|
|
19390
|
-
poolKey,
|
|
19391
|
-
quoterAddress: this.resolveQuoterAddress(UNISWAP_INTENT_QUOTE_CHAIN, override.quoterAddress),
|
|
19392
|
-
tokenInForQuote
|
|
19393
|
-
};
|
|
19394
|
-
}
|
|
19395
|
-
const poolConfig = this.resolveConfiguredPool(params, source, destination, UNISWAP_INTENT_QUOTE_CHAIN);
|
|
19396
|
-
if (poolConfig) return poolConfig;
|
|
19397
|
-
throw new UnsupportedIntentQuotePairError({
|
|
19398
|
-
source,
|
|
19399
|
-
destination,
|
|
19400
|
-
tokenIn: params.tokenIn,
|
|
19401
|
-
tokenOut: params.tokenOut
|
|
19402
|
-
});
|
|
19403
|
-
}
|
|
19404
|
-
resolveConfiguredPool(params, sourceChain, destinationChain, quoteChain) {
|
|
19405
|
-
for (const pool of this.chainConfigService.getUniswapV4PoolConfigs(quoteChain)) {
|
|
19406
|
-
const resolvedPool = this.resolveConfiguredPoolTokens(quoteChain, pool);
|
|
19407
|
-
if (!resolvedPool) continue;
|
|
19408
|
-
const tokenInForQuote = this.matchPoolToken(params.tokenIn, sourceChain, resolvedPool);
|
|
19409
|
-
const tokenOutForQuote = this.matchPoolToken(params.tokenOut, destinationChain, resolvedPool);
|
|
19410
|
-
if (!tokenInForQuote || !tokenOutForQuote || tokenInForQuote.symbol === tokenOutForQuote.symbol) continue;
|
|
19411
|
-
const { currency0, currency1 } = sortCurrencies(resolvedPool[0].address, resolvedPool[1].address);
|
|
19412
|
-
return {
|
|
19413
|
-
poolKey: {
|
|
19414
|
-
currency0,
|
|
19415
|
-
currency1,
|
|
19416
|
-
fee: pool.fee,
|
|
19417
|
-
tickSpacing: pool.tickSpacing,
|
|
19418
|
-
hooks: viem.getAddress(pool.hooks ?? viem.zeroAddress)
|
|
19419
|
-
},
|
|
19420
|
-
quoterAddress: this.resolveQuoterAddress(quoteChain),
|
|
19421
|
-
tokenInForQuote: tokenInForQuote.address
|
|
19422
|
-
};
|
|
19423
|
-
}
|
|
19424
|
-
return null;
|
|
19191
|
+
function levelQuoteTotals(quote) {
|
|
19192
|
+
if (quote.fillable && quote.rate === null) {
|
|
19193
|
+
throw new OrderbookRequestError("the orderbook served a fillable quote with no rate");
|
|
19425
19194
|
}
|
|
19426
|
-
resolveQuoterAddress(chain, override) {
|
|
19427
|
-
const address = override ?? this.chainConfigService.getUniswapV4QuoterAddress(chain);
|
|
19428
|
-
if (!address || address === "0x" || address === viem.zeroAddress) {
|
|
19429
|
-
throw new Error(`Uniswap V4 quoter is not configured for chain ${chain}`);
|
|
19430
|
-
}
|
|
19431
|
-
return viem.getAddress(address);
|
|
19432
|
-
}
|
|
19433
|
-
resolveConfiguredPoolTokens(chain, pool) {
|
|
19434
|
-
const first = this.resolveConfiguredPoolToken(chain, pool.tokens[0]);
|
|
19435
|
-
const second = this.resolveConfiguredPoolToken(chain, pool.tokens[1]);
|
|
19436
|
-
return first && second ? [first, second] : null;
|
|
19437
|
-
}
|
|
19438
|
-
resolveConfiguredPoolToken(chain, symbol) {
|
|
19439
|
-
const address = this.chainConfigService.getAssetAddress(chain, symbol);
|
|
19440
|
-
if (!address || address === "0x") return null;
|
|
19441
|
-
return { symbol, address: viem.getAddress(address) };
|
|
19442
|
-
}
|
|
19443
|
-
matchPoolToken(tokenAddress, orderChain, poolTokens) {
|
|
19444
|
-
const addressMatch = poolTokens.find(
|
|
19445
|
-
(poolToken) => poolToken.address.toLowerCase() === tokenAddress.toLowerCase()
|
|
19446
|
-
);
|
|
19447
|
-
if (addressMatch) return addressMatch;
|
|
19448
|
-
const metadata = this.chainConfigService.getAssetMetadataByAddress(orderChain, tokenAddress);
|
|
19449
|
-
if (!metadata) return null;
|
|
19450
|
-
return poolTokens.find((poolToken) => poolToken.symbol === metadata.symbol) ?? null;
|
|
19451
|
-
}
|
|
19452
|
-
async quoteExactInput(args) {
|
|
19453
|
-
const amountIn = args.params.amountIn;
|
|
19454
|
-
if (amountIn === void 0) throw new Error("amountIn is required for an exact-input quote");
|
|
19455
|
-
const swapAmountIn = deductProtocolFee(amountIn, args.protocolFeeBps);
|
|
19456
|
-
const amountOut = await this.readV4QuoteExactInput(args.client, args.poolConfig, swapAmountIn);
|
|
19457
|
-
return {
|
|
19458
|
-
strategy: "uniswap_v4",
|
|
19459
|
-
tradeType: "EXACT_INPUT",
|
|
19460
|
-
amountIn,
|
|
19461
|
-
amountOut,
|
|
19462
|
-
quoteMetadata: {
|
|
19463
|
-
quoteChain: UNISWAP_INTENT_QUOTE_CHAIN,
|
|
19464
|
-
poolKey: args.poolConfig.poolKey,
|
|
19465
|
-
quoterAddress: args.poolConfig.quoterAddress,
|
|
19466
|
-
protocolFeeBps: args.protocolFeeBps
|
|
19467
|
-
}
|
|
19468
|
-
};
|
|
19469
|
-
}
|
|
19470
|
-
async quoteExactOutput(args) {
|
|
19471
|
-
const amountOut = args.params.amountOut;
|
|
19472
|
-
if (amountOut === void 0) throw new Error("amountOut is required for an exact-output quote");
|
|
19473
|
-
const swapAmountIn = await this.readV4QuoteExactOutput(args.client, args.poolConfig, amountOut);
|
|
19474
|
-
const amountIn = grossUpForProtocolFee(swapAmountIn, args.protocolFeeBps);
|
|
19475
|
-
return {
|
|
19476
|
-
strategy: "uniswap_v4",
|
|
19477
|
-
tradeType: "EXACT_OUTPUT",
|
|
19478
|
-
amountIn,
|
|
19479
|
-
amountOut,
|
|
19480
|
-
quoteMetadata: {
|
|
19481
|
-
quoteChain: UNISWAP_INTENT_QUOTE_CHAIN,
|
|
19482
|
-
poolKey: args.poolConfig.poolKey,
|
|
19483
|
-
quoterAddress: args.poolConfig.quoterAddress,
|
|
19484
|
-
protocolFeeBps: args.protocolFeeBps
|
|
19485
|
-
}
|
|
19486
|
-
};
|
|
19487
|
-
}
|
|
19488
|
-
async readV4QuoteExactInput(client, poolConfig, amountIn) {
|
|
19489
|
-
const data = viem.encodeFunctionData({
|
|
19490
|
-
abi: UNISWAP_V4_QUOTER_ABI,
|
|
19491
|
-
functionName: "quoteExactInputSingle",
|
|
19492
|
-
args: [
|
|
19493
|
-
{
|
|
19494
|
-
poolKey: poolConfig.poolKey,
|
|
19495
|
-
zeroForOne: getZeroForOne(poolConfig.tokenInForQuote, poolConfig.poolKey),
|
|
19496
|
-
exactAmount: amountIn,
|
|
19497
|
-
hookData: "0x"
|
|
19498
|
-
}
|
|
19499
|
-
]
|
|
19500
|
-
});
|
|
19501
|
-
const response = await client.call({ to: poolConfig.quoterAddress, data });
|
|
19502
|
-
if (!response.data || response.data === "0x") {
|
|
19503
|
-
throw new Error(`Uniswap V4 quoter at ${poolConfig.quoterAddress} returned no data`);
|
|
19504
|
-
}
|
|
19505
|
-
const [amountOut] = viem.decodeFunctionResult({
|
|
19506
|
-
abi: UNISWAP_V4_QUOTER_ABI,
|
|
19507
|
-
functionName: "quoteExactInputSingle",
|
|
19508
|
-
data: response.data
|
|
19509
|
-
});
|
|
19510
|
-
return amountOut;
|
|
19511
|
-
}
|
|
19512
|
-
async readV4QuoteExactOutput(client, poolConfig, amountOut) {
|
|
19513
|
-
const data = viem.encodeFunctionData({
|
|
19514
|
-
abi: UNISWAP_V4_QUOTER_ABI,
|
|
19515
|
-
functionName: "quoteExactOutputSingle",
|
|
19516
|
-
args: [
|
|
19517
|
-
{
|
|
19518
|
-
poolKey: poolConfig.poolKey,
|
|
19519
|
-
zeroForOne: getZeroForOne(poolConfig.tokenInForQuote, poolConfig.poolKey),
|
|
19520
|
-
exactAmount: amountOut,
|
|
19521
|
-
hookData: "0x"
|
|
19522
|
-
}
|
|
19523
|
-
]
|
|
19524
|
-
});
|
|
19525
|
-
const response = await client.call({ to: poolConfig.quoterAddress, data });
|
|
19526
|
-
if (!response.data || response.data === "0x") {
|
|
19527
|
-
throw new Error(`Uniswap V4 quoter at ${poolConfig.quoterAddress} returned no data`);
|
|
19528
|
-
}
|
|
19529
|
-
const [amountIn] = viem.decodeFunctionResult({
|
|
19530
|
-
abi: UNISWAP_V4_QUOTER_ABI,
|
|
19531
|
-
functionName: "quoteExactOutputSingle",
|
|
19532
|
-
data: response.data
|
|
19533
|
-
});
|
|
19534
|
-
return amountIn;
|
|
19535
|
-
}
|
|
19536
|
-
};
|
|
19537
|
-
function normalizePoolKey(poolKey) {
|
|
19538
19195
|
return {
|
|
19539
|
-
|
|
19540
|
-
|
|
19541
|
-
|
|
19542
|
-
|
|
19543
|
-
|
|
19196
|
+
side: quote.side,
|
|
19197
|
+
amountIn: quote.amountIn,
|
|
19198
|
+
amountOut: quote.amountOut,
|
|
19199
|
+
fillable: quote.fillable,
|
|
19200
|
+
maxFillableIn: quote.maxFillableIn,
|
|
19201
|
+
worstIn: quote.amountIn,
|
|
19202
|
+
worstOut: quote.amountOut
|
|
19544
19203
|
};
|
|
19545
19204
|
}
|
|
19546
|
-
function
|
|
19547
|
-
|
|
19548
|
-
const output = viem.getAddress(tokenOut);
|
|
19549
|
-
return BigInt(input) < BigInt(output) ? { currency0: input, currency1: output } : { currency0: output, currency1: input };
|
|
19550
|
-
}
|
|
19551
|
-
function getZeroForOne(tokenIn, poolKey) {
|
|
19552
|
-
return viem.getAddress(tokenIn).toLowerCase() === viem.getAddress(poolKey.currency0).toLowerCase();
|
|
19553
|
-
}
|
|
19554
|
-
|
|
19555
|
-
// src/protocols/intents/quote/phantomSnapshot.ts
|
|
19556
|
-
var PHANTOM_INTENT_QUOTE_CHAIN = "EVM-8453" /* BASE_MAINNET */;
|
|
19557
|
-
var BASE_SNAPSHOT_ASSET_BY_ORDER_ASSET = {
|
|
19558
|
-
USDC: "USDC",
|
|
19559
|
-
USDT: "USDC",
|
|
19560
|
-
cNGN: "cNGN"
|
|
19561
|
-
};
|
|
19562
|
-
var SUPPORTED_BASE_SNAPSHOT_PAIRS = /* @__PURE__ */ new Set(["USDC:cNGN", "cNGN:USDC"]);
|
|
19563
|
-
var PhantomSnapshotIntentQuoteStrategy = class {
|
|
19564
|
-
constructor(chainConfigService, getQueryClient) {
|
|
19565
|
-
this.chainConfigService = chainConfigService;
|
|
19566
|
-
this.getQueryClient = getQueryClient;
|
|
19567
|
-
this.pairResolver = new PhantomSnapshotPairResolver(chainConfigService);
|
|
19568
|
-
}
|
|
19569
|
-
chainConfigService;
|
|
19570
|
-
getQueryClient;
|
|
19571
|
-
pairResolver;
|
|
19572
|
-
async quote(params, source, destination) {
|
|
19573
|
-
validateQuoteParams(params);
|
|
19574
|
-
const pair = this.pairResolver.resolve(params, source.stateMachineId, destination.stateMachineId);
|
|
19575
|
-
if (!pair) {
|
|
19576
|
-
throw new UnsupportedIntentQuotePairError({
|
|
19577
|
-
source: source.stateMachineId,
|
|
19578
|
-
destination: destination.stateMachineId,
|
|
19579
|
-
tokenIn: params.tokenIn,
|
|
19580
|
-
tokenOut: params.tokenOut,
|
|
19581
|
-
quoteSource: "Phantom snapshot pair"
|
|
19582
|
-
});
|
|
19583
|
-
}
|
|
19584
|
-
const queryClient = this.getQueryClient();
|
|
19585
|
-
const [protocolFeeBps, snapshot] = await Promise.all([
|
|
19586
|
-
readProtocolFeeBps(this.chainConfigService, source),
|
|
19587
|
-
_queryLatestPhantomOrderPriceSnapshot({
|
|
19588
|
-
tokenA: pair.tokenA,
|
|
19589
|
-
tokenB: pair.tokenB,
|
|
19590
|
-
queryClient
|
|
19591
|
-
})
|
|
19592
|
-
]);
|
|
19593
|
-
if (!snapshot) throw new PhantomSnapshotUnavailableError(pair.tokenA, pair.tokenB);
|
|
19594
|
-
this.validateSnapshot(snapshot);
|
|
19595
|
-
return this.quoteSnapshot(params, protocolFeeBps, snapshot);
|
|
19596
|
-
}
|
|
19597
|
-
quoteSnapshot(params, protocolFeeBps, snapshot) {
|
|
19598
|
-
if (params.amountIn !== void 0) {
|
|
19599
|
-
const netAmountIn2 = deductProtocolFee(params.amountIn, protocolFeeBps);
|
|
19600
|
-
const amountOut = netAmountIn2 * snapshot.medianPrice / snapshot.standardAmount;
|
|
19601
|
-
if (amountOut <= 0n) {
|
|
19602
|
-
throw new InvalidPhantomSnapshotError(snapshot.commitment, "quote rounds down to zero output");
|
|
19603
|
-
}
|
|
19604
|
-
return this.buildResult("EXACT_INPUT", params.amountIn, amountOut, protocolFeeBps, snapshot);
|
|
19605
|
-
}
|
|
19606
|
-
if (params.amountOut === void 0) throw new Error("Quote amount is missing after validation");
|
|
19607
|
-
const netAmountIn = divCeil(params.amountOut * snapshot.standardAmount, snapshot.medianPrice);
|
|
19608
|
-
const amountIn = grossUpForProtocolFee(netAmountIn, protocolFeeBps);
|
|
19609
|
-
return this.buildResult("EXACT_OUTPUT", amountIn, params.amountOut, protocolFeeBps, snapshot);
|
|
19610
|
-
}
|
|
19611
|
-
buildResult(tradeType, amountIn, amountOut, protocolFeeBps, snapshot) {
|
|
19612
|
-
return {
|
|
19613
|
-
strategy: "phantom_snapshot",
|
|
19614
|
-
tradeType,
|
|
19615
|
-
amountIn,
|
|
19616
|
-
amountOut,
|
|
19617
|
-
quoteMetadata: {
|
|
19618
|
-
quoteChain: PHANTOM_INTENT_QUOTE_CHAIN,
|
|
19619
|
-
commitment: snapshot.commitment,
|
|
19620
|
-
tokenA: snapshot.tokenA,
|
|
19621
|
-
tokenB: snapshot.tokenB,
|
|
19622
|
-
standardAmount: snapshot.standardAmount,
|
|
19623
|
-
medianPrice: snapshot.medianPrice,
|
|
19624
|
-
lowestPrice: snapshot.lowestPrice,
|
|
19625
|
-
highestPrice: snapshot.highestPrice,
|
|
19626
|
-
blockNumber: snapshot.blockNumber,
|
|
19627
|
-
snapshotTime: snapshot.snapshotTime,
|
|
19628
|
-
bidCount: snapshot.bidCount,
|
|
19629
|
-
protocolFeeBps
|
|
19630
|
-
}
|
|
19631
|
-
};
|
|
19632
|
-
}
|
|
19633
|
-
validateSnapshot(snapshot) {
|
|
19634
|
-
if (snapshot.standardAmount <= 0n) {
|
|
19635
|
-
throw new InvalidPhantomSnapshotError(snapshot.commitment, "standardAmount must be greater than zero");
|
|
19636
|
-
}
|
|
19637
|
-
if (snapshot.medianPrice <= 0n) {
|
|
19638
|
-
throw new InvalidPhantomSnapshotError(snapshot.commitment, "medianPrice must be greater than zero");
|
|
19639
|
-
}
|
|
19640
|
-
if (snapshot.bidCount <= 0) {
|
|
19641
|
-
throw new InvalidPhantomSnapshotError(snapshot.commitment, "bidCount must be greater than zero");
|
|
19642
|
-
}
|
|
19643
|
-
if (Number.isNaN(snapshot.snapshotTime.getTime())) {
|
|
19644
|
-
throw new InvalidPhantomSnapshotError(snapshot.commitment, "snapshotTime is invalid");
|
|
19645
|
-
}
|
|
19646
|
-
}
|
|
19647
|
-
};
|
|
19648
|
-
var PhantomSnapshotPairResolver = class {
|
|
19649
|
-
constructor(chainConfigService) {
|
|
19650
|
-
this.chainConfigService = chainConfigService;
|
|
19651
|
-
}
|
|
19652
|
-
chainConfigService;
|
|
19653
|
-
resolve(params, sourceStateMachineId, destinationStateMachineId) {
|
|
19654
|
-
const tokenIn = this.resolveBaseSnapshotToken(sourceStateMachineId, params.tokenIn);
|
|
19655
|
-
const tokenOut = this.resolveBaseSnapshotToken(destinationStateMachineId, params.tokenOut);
|
|
19656
|
-
if (!tokenIn || !tokenOut || !isSupportedSnapshotPair(tokenIn.symbol, tokenOut.symbol)) return;
|
|
19657
|
-
return { tokenA: tokenIn.address, tokenB: tokenOut.address };
|
|
19658
|
-
}
|
|
19659
|
-
resolveBaseSnapshotToken(chain, tokenAddress) {
|
|
19660
|
-
const orderAsset = this.chainConfigService.getAssetMetadataByAddress(chain, tokenAddress)?.symbol;
|
|
19661
|
-
if (!orderAsset) return;
|
|
19662
|
-
const snapshotAsset = BASE_SNAPSHOT_ASSET_BY_ORDER_ASSET[orderAsset];
|
|
19663
|
-
if (!snapshotAsset) return;
|
|
19664
|
-
const address = this.chainConfigService.getAssetAddress(PHANTOM_INTENT_QUOTE_CHAIN, snapshotAsset);
|
|
19665
|
-
if (!isConfiguredAddress(address)) return;
|
|
19666
|
-
return { symbol: snapshotAsset, address };
|
|
19667
|
-
}
|
|
19668
|
-
};
|
|
19669
|
-
function isSupportedSnapshotPair(tokenA, tokenB) {
|
|
19670
|
-
return SUPPORTED_BASE_SNAPSHOT_PAIRS.has(`${tokenA}:${tokenB}`);
|
|
19205
|
+
function toOrderbookAmount(amount, decimals) {
|
|
19206
|
+
return amount * 10n ** BigInt(ORDERBOOK_DECIMALS - decimals);
|
|
19671
19207
|
}
|
|
19672
|
-
function
|
|
19673
|
-
return
|
|
19208
|
+
function fromOrderbookAmount(amount, decimals) {
|
|
19209
|
+
return amount / 10n ** BigInt(ORDERBOOK_DECIMALS - decimals);
|
|
19674
19210
|
}
|
|
19675
|
-
|
|
19676
|
-
|
|
19677
|
-
var IndexedRateIntentQuoteStrategy = class {
|
|
19678
|
-
constructor(chainConfigService, getQueryClient) {
|
|
19679
|
-
this.chainConfigService = chainConfigService;
|
|
19680
|
-
this.getQueryClient = getQueryClient;
|
|
19681
|
-
}
|
|
19682
|
-
chainConfigService;
|
|
19683
|
-
getQueryClient;
|
|
19684
|
-
async quote(params, source, destination) {
|
|
19685
|
-
validateQuoteParams(params);
|
|
19686
|
-
const sourceConfig = getConfigByStateMachineId(source.stateMachineId);
|
|
19687
|
-
const destinationConfig = getConfigByStateMachineId(destination.stateMachineId);
|
|
19688
|
-
if (!sourceConfig) throw new UnsupportedLiquidityChainError(source.stateMachineId);
|
|
19689
|
-
if (!destinationConfig) throw new UnsupportedLiquidityChainError(destination.stateMachineId);
|
|
19690
|
-
const tokenIn = this.resolveAsset(sourceConfig.stateMachineId, params.tokenIn);
|
|
19691
|
-
const tokenOut = this.resolveAsset(destinationConfig.stateMachineId, params.tokenOut);
|
|
19692
|
-
const [protocolFeeBps, rates] = await Promise.all([
|
|
19693
|
-
readProtocolFeeBps(this.chainConfigService, source),
|
|
19694
|
-
new LiquidityEngine(this.getQueryClient()).getBuyAndSellRates({
|
|
19695
|
-
sourceChain: sourceConfig.stateMachineId,
|
|
19696
|
-
destinationChain: destinationConfig.stateMachineId,
|
|
19697
|
-
tokenInSymbol: tokenIn.symbol,
|
|
19698
|
-
tokenOutSymbol: tokenOut.symbol
|
|
19699
|
-
})
|
|
19700
|
-
]);
|
|
19701
|
-
if (!rates) {
|
|
19702
|
-
throw new IndexedRateUnavailableError({
|
|
19703
|
-
source: sourceConfig.stateMachineId,
|
|
19704
|
-
destination: destinationConfig.stateMachineId,
|
|
19705
|
-
tokenIn: tokenIn.symbol,
|
|
19706
|
-
tokenOut: tokenOut.symbol
|
|
19707
|
-
});
|
|
19708
|
-
}
|
|
19709
|
-
const selectedRate = selectIndexedRate(rates, tokenIn.symbol, tokenOut.symbol);
|
|
19710
|
-
return quoteWithIndexedRate(params, tokenIn, tokenOut, selectedRate, rates, protocolFeeBps);
|
|
19711
|
-
}
|
|
19712
|
-
resolveAsset(chain, address) {
|
|
19713
|
-
const asset = this.chainConfigService.getAssetMetadataByAddress(chain, address);
|
|
19714
|
-
if (!asset) throw new UnsupportedLiquidityAssetError(chain, address);
|
|
19715
|
-
const { decimals } = asset;
|
|
19716
|
-
if (decimals === void 0 || !Number.isSafeInteger(decimals) || decimals < 0) {
|
|
19717
|
-
throw new InvalidIndexedRateError(`decimals are not configured for ${asset.symbol} on ${chain}`);
|
|
19718
|
-
}
|
|
19719
|
-
return { ...asset, decimals };
|
|
19720
|
-
}
|
|
19721
|
-
};
|
|
19722
|
-
function selectIndexedRate(rates, tokenInSymbol, tokenOutSymbol) {
|
|
19723
|
-
if (tokenInSymbol === rates.baseTokenSymbol && tokenOutSymbol === rates.quoteTokenSymbol) {
|
|
19724
|
-
return readIndexedRate2(
|
|
19725
|
-
"buy",
|
|
19726
|
-
rates.buyRate,
|
|
19727
|
-
rates.buyRateUpdatedAt,
|
|
19728
|
-
rates,
|
|
19729
|
-
tokenInSymbol,
|
|
19730
|
-
tokenOutSymbol
|
|
19731
|
-
);
|
|
19732
|
-
}
|
|
19733
|
-
if (tokenInSymbol === rates.quoteTokenSymbol && tokenOutSymbol === rates.baseTokenSymbol) {
|
|
19734
|
-
return readIndexedRate2(
|
|
19735
|
-
"sell",
|
|
19736
|
-
rates.sellRate,
|
|
19737
|
-
rates.sellRateUpdatedAt,
|
|
19738
|
-
rates,
|
|
19739
|
-
tokenInSymbol,
|
|
19740
|
-
tokenOutSymbol
|
|
19741
|
-
);
|
|
19742
|
-
}
|
|
19743
|
-
throw new InvalidIndexedRateError(
|
|
19744
|
-
`indexed pair ${rates.baseTokenSymbol}/${rates.quoteTokenSymbol} does not match ${tokenInSymbol}/${tokenOutSymbol}`
|
|
19745
|
-
);
|
|
19211
|
+
function roundUpTo(amount, unit) {
|
|
19212
|
+
return divCeil(amount, unit) * unit;
|
|
19746
19213
|
}
|
|
19747
|
-
function
|
|
19748
|
-
|
|
19749
|
-
throw new IndexedRateUnavailableError({
|
|
19750
|
-
source: rates.sourceChain,
|
|
19751
|
-
destination: rates.destinationChain,
|
|
19752
|
-
tokenIn: tokenInSymbol,
|
|
19753
|
-
tokenOut: tokenOutSymbol,
|
|
19754
|
-
side
|
|
19755
|
-
});
|
|
19756
|
-
}
|
|
19757
|
-
try {
|
|
19758
|
-
const scaledRate = viem.parseUnits(rate, INDEXED_RATE_DECIMALS);
|
|
19759
|
-
if (scaledRate <= 0n || Number.isNaN(updatedAt.getTime())) throw new Error();
|
|
19760
|
-
return { side, rate, scaledRate, updatedAt };
|
|
19761
|
-
} catch {
|
|
19762
|
-
throw new InvalidIndexedRateError(`${side} rate or timestamp is invalid`);
|
|
19763
|
-
}
|
|
19214
|
+
function divCeil(numerator, denominator) {
|
|
19215
|
+
return (numerator + denominator - 1n) / denominator;
|
|
19764
19216
|
}
|
|
19765
|
-
function
|
|
19766
|
-
|
|
19767
|
-
const outputUnit = 10n ** BigInt(tokenOut.decimals);
|
|
19768
|
-
if (params.amountIn !== void 0) {
|
|
19769
|
-
const netAmountIn2 = deductProtocolFee(params.amountIn, protocolFeeBps);
|
|
19770
|
-
const amountOut = selectedRate.side === "buy" ? netAmountIn2 * selectedRate.scaledRate * outputUnit / (inputUnit * INDEXED_RATE_SCALE) : netAmountIn2 * outputUnit * INDEXED_RATE_SCALE / (inputUnit * selectedRate.scaledRate);
|
|
19771
|
-
if (amountOut <= 0n) throw new InvalidIndexedRateError("quote rounds down to zero output");
|
|
19772
|
-
return buildResult("EXACT_INPUT", params.amountIn, amountOut, selectedRate, rates, protocolFeeBps);
|
|
19773
|
-
}
|
|
19774
|
-
if (params.amountOut === void 0) throw new Error("Quote amount is missing after validation");
|
|
19775
|
-
const netAmountIn = selectedRate.side === "buy" ? divCeil(params.amountOut * inputUnit * INDEXED_RATE_SCALE, selectedRate.scaledRate * outputUnit) : divCeil(params.amountOut * inputUnit * selectedRate.scaledRate, outputUnit * INDEXED_RATE_SCALE);
|
|
19776
|
-
const amountIn = grossUpForProtocolFee(netAmountIn, protocolFeeBps);
|
|
19777
|
-
return buildResult("EXACT_OUTPUT", amountIn, params.amountOut, selectedRate, rates, protocolFeeBps);
|
|
19217
|
+
function format(amount) {
|
|
19218
|
+
return viem.formatUnits(amount, ORDERBOOK_DECIMALS);
|
|
19778
19219
|
}
|
|
19779
|
-
function
|
|
19780
|
-
return
|
|
19781
|
-
strategy: "indexed_rates",
|
|
19782
|
-
tradeType,
|
|
19783
|
-
amountIn,
|
|
19784
|
-
amountOut,
|
|
19785
|
-
quoteMetadata: {
|
|
19786
|
-
sourceChain: rates.sourceChain,
|
|
19787
|
-
destinationChain: rates.destinationChain,
|
|
19788
|
-
baseTokenSymbol: rates.baseTokenSymbol,
|
|
19789
|
-
quoteTokenSymbol: rates.quoteTokenSymbol,
|
|
19790
|
-
rateSide: selectedRate.side,
|
|
19791
|
-
rate: selectedRate.rate,
|
|
19792
|
-
rateUpdatedAt: selectedRate.updatedAt,
|
|
19793
|
-
protocolFeeBps
|
|
19794
|
-
}
|
|
19795
|
-
};
|
|
19220
|
+
function formatOptional(amount) {
|
|
19221
|
+
return amount === null ? null : format(amount);
|
|
19796
19222
|
}
|
|
19797
19223
|
|
|
19798
19224
|
// src/protocols/intents/IntentGateway.ts
|
|
@@ -19833,8 +19259,10 @@ var IntentGateway = class _IntentGateway {
|
|
|
19833
19259
|
bidManager;
|
|
19834
19260
|
/** Estimates gas costs for filling an order and converts them to fee-token amounts. */
|
|
19835
19261
|
gasEstimator;
|
|
19836
|
-
/**
|
|
19837
|
-
|
|
19262
|
+
/** The HyperFX orderbook quotes, liquidity and rates are read from. */
|
|
19263
|
+
orderbook;
|
|
19264
|
+
/** Prices intents, liquidity and rates from {@link orderbook}. */
|
|
19265
|
+
market;
|
|
19838
19266
|
/**
|
|
19839
19267
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
19840
19268
|
*
|
|
@@ -19878,17 +19306,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
19878
19306
|
this.bidManager = bidManager;
|
|
19879
19307
|
this.gasEstimator = gasEstimator;
|
|
19880
19308
|
this._crypto = crypto;
|
|
19881
|
-
this.
|
|
19882
|
-
|
|
19883
|
-
dest.configService,
|
|
19884
|
-
() => this.requireIndexer().queryClient
|
|
19885
|
-
),
|
|
19886
|
-
phantom_snapshot: new PhantomSnapshotIntentQuoteStrategy(
|
|
19887
|
-
dest.configService,
|
|
19888
|
-
() => this.requireIndexer().queryClient
|
|
19889
|
-
),
|
|
19890
|
-
uniswap_v4: new UniswapV4IntentQuoteStrategy(dest.configService)
|
|
19891
|
-
};
|
|
19309
|
+
this.orderbook = new HyperFxOrderbook(orderbookUrlFor(dest.config.stateMachineId));
|
|
19310
|
+
this.market = new OrderbookMarket(dest.configService, () => this.orderbook);
|
|
19892
19311
|
}
|
|
19893
19312
|
/**
|
|
19894
19313
|
* Creates an initialized IntentGateway instance.
|
|
@@ -19934,89 +19353,50 @@ var IntentGateway = class _IntentGateway {
|
|
|
19934
19353
|
}
|
|
19935
19354
|
}
|
|
19936
19355
|
/**
|
|
19937
|
-
*
|
|
19938
|
-
*
|
|
19939
|
-
*
|
|
19940
|
-
* `strategy: "phantom_snapshot"` or `strategy: "uniswap_v4"` only when
|
|
19941
|
-
* explicitly requesting a legacy quote source. Provide exactly one of
|
|
19942
|
-
* `amountIn` or `amountOut`.
|
|
19943
|
-
*
|
|
19944
|
-
* The gateway's source and destination chains resolve the configured order
|
|
19945
|
-
* tokens; the indexer supplies the depth-weighted pool rate. Returned
|
|
19946
|
-
* `amountIn`/`amountOut` already account for the gateway's protocol fee
|
|
19947
|
-
* (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order inputs.
|
|
19356
|
+
* Points quotes, liquidity and rate reads at a HyperFX orderbook other than
|
|
19357
|
+
* the destination chain's network deployment ({@link ORDERBOOK_URLS}).
|
|
19358
|
+
* Returns `this` for chaining.
|
|
19948
19359
|
*
|
|
19949
|
-
* @param
|
|
19950
|
-
* @returns The quoted amounts plus strategy-specific metadata.
|
|
19951
|
-
* @throws {UnsupportedIntentQuoteStrategyError} For unknown strategies.
|
|
19952
|
-
* @throws {UnsupportedIntentQuotePairError} When the selected strategy does not support the pair.
|
|
19953
|
-
* @throws {IndexedRateUnavailableError} When the requested direction has no indexed rate.
|
|
19360
|
+
* @param orderbook - The orderbook's GraphQL URL, or a configured client.
|
|
19954
19361
|
*/
|
|
19362
|
+
withOrderbook(orderbook) {
|
|
19363
|
+
this.orderbook = typeof orderbook === "string" ? new HyperFxOrderbook(orderbook) : orderbook;
|
|
19364
|
+
return this;
|
|
19365
|
+
}
|
|
19955
19366
|
async quoteIntent(params) {
|
|
19956
|
-
|
|
19957
|
-
const destination = { stateMachineId: this.dest.config.stateMachineId, client: this.dest.client };
|
|
19958
|
-
const strategy = params.strategy ?? "indexed_rates";
|
|
19959
|
-
const handler = this.quoteStrategies[strategy];
|
|
19960
|
-
if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
|
|
19961
|
-
return handler.quote({ ...params, strategy }, source, destination);
|
|
19367
|
+
return this.market.quoteIntent(params, this.source.config.stateMachineId, this.dest.config.stateMachineId);
|
|
19962
19368
|
}
|
|
19963
19369
|
/**
|
|
19964
|
-
* Returns
|
|
19370
|
+
* Returns the orderbook liquidity serving a swap of `tokenIn` on the source
|
|
19371
|
+
* chain for `tokenOut` on the destination chain: the best rate, true and
|
|
19372
|
+
* virtual depth, and the largest input the route can fill.
|
|
19965
19373
|
*
|
|
19966
|
-
*
|
|
19967
|
-
* from the indexer's pair-centric liquidity entities. The SDK does not decide
|
|
19968
|
-
* whether unrestricted bidders cover the source chain. Amounts reflect the
|
|
19969
|
-
* latest rolling sample; they are not reservations or fill guarantees.
|
|
19970
|
-
*
|
|
19971
|
-
* Requires a prior call to {@link withQueryClient}.
|
|
19374
|
+
* Amounts reflect the live book; they are not reservations or fill guarantees.
|
|
19972
19375
|
*/
|
|
19973
19376
|
async queryAvailableLiquidity(params) {
|
|
19974
|
-
|
|
19975
|
-
|
|
19976
|
-
|
|
19977
|
-
|
|
19978
|
-
if (!destinationStateMachineId) throw new UnsupportedLiquidityChainError(this.dest.config.stateMachineId);
|
|
19979
|
-
const sourceToken = this.source.configService.getAssetMetadataByAddress(sourceStateMachineId, params.tokenIn);
|
|
19980
|
-
const destinationToken = this.dest.configService.getAssetMetadataByAddress(
|
|
19981
|
-
destinationStateMachineId,
|
|
19982
|
-
params.tokenOut
|
|
19377
|
+
return this.market.availableLiquidity(
|
|
19378
|
+
params,
|
|
19379
|
+
this.source.config.stateMachineId,
|
|
19380
|
+
this.dest.config.stateMachineId
|
|
19983
19381
|
);
|
|
19984
|
-
if (!sourceToken) throw new UnsupportedLiquidityAssetError(sourceStateMachineId, params.tokenIn);
|
|
19985
|
-
if (!destinationToken) throw new UnsupportedLiquidityAssetError(destinationStateMachineId, params.tokenOut);
|
|
19986
|
-
return new LiquidityEngine(queryClient).getAvailableLiquidity({
|
|
19987
|
-
source: {
|
|
19988
|
-
chain: sourceStateMachineId,
|
|
19989
|
-
...sourceToken
|
|
19990
|
-
},
|
|
19991
|
-
destination: {
|
|
19992
|
-
chain: destinationStateMachineId,
|
|
19993
|
-
...destinationToken
|
|
19994
|
-
}
|
|
19995
|
-
});
|
|
19996
19382
|
}
|
|
19997
19383
|
/**
|
|
19998
|
-
* Returns
|
|
19999
|
-
* units
|
|
20000
|
-
*
|
|
19384
|
+
* Returns the orderbook's best bid and ask for a pair, with the mid and
|
|
19385
|
+
* spread, in quote-token units per one base token. Only orders filled on the
|
|
19386
|
+
* destination chain that accept swaps from the source chain are counted.
|
|
19387
|
+
* Symbols are matched case-insensitively; chain IDs resolve configured token
|
|
19388
|
+
* deployments.
|
|
20001
19389
|
*/
|
|
20002
19390
|
async queryBuyAndSellRates(params) {
|
|
20003
|
-
const { queryClient } = this.requireIndexer();
|
|
20004
19391
|
const sourceChain = chainConfigs[params.sourceChainId]?.stateMachineId;
|
|
20005
19392
|
const destinationChain = chainConfigs[params.destinationChainId]?.stateMachineId;
|
|
20006
19393
|
if (!sourceChain) throw new UnsupportedLiquidityChainError(params.sourceChainId);
|
|
20007
19394
|
if (!destinationChain) throw new UnsupportedLiquidityChainError(params.destinationChainId);
|
|
20008
|
-
|
|
20009
|
-
const destinationToken = this.dest.configService.getAssetMetadataBySymbol(
|
|
20010
|
-
destinationChain,
|
|
20011
|
-
params.tokenOutSymbol
|
|
20012
|
-
);
|
|
20013
|
-
if (!sourceToken) throw new UnsupportedLiquidityAssetError(sourceChain, params.tokenInSymbol);
|
|
20014
|
-
if (!destinationToken) throw new UnsupportedLiquidityAssetError(destinationChain, params.tokenOutSymbol);
|
|
20015
|
-
return new LiquidityEngine(queryClient).getBuyAndSellRates({
|
|
19395
|
+
return this.market.buyAndSellRates({
|
|
20016
19396
|
sourceChain,
|
|
20017
19397
|
destinationChain,
|
|
20018
|
-
tokenInSymbol:
|
|
20019
|
-
tokenOutSymbol:
|
|
19398
|
+
tokenInSymbol: params.tokenInSymbol,
|
|
19399
|
+
tokenOutSymbol: params.tokenOutSymbol
|
|
20020
19400
|
});
|
|
20021
19401
|
}
|
|
20022
19402
|
/**
|
|
@@ -20267,6 +19647,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
20267
19647
|
/**
|
|
20268
19648
|
* Returns both the native token cost and the relayer fee for cancelling an
|
|
20269
19649
|
* order. Use `relayerFee` to approve the ERC-20 spend before submitting.
|
|
19650
|
+
* Same-chain orders use the direct local route for either `from` option and
|
|
19651
|
+
* return `{ nativeValue: 0n, relayerFee: 0n }`.
|
|
20270
19652
|
*
|
|
20271
19653
|
* Delegates to {@link OrderCanceller.quoteCancelOrder}.
|
|
20272
19654
|
*
|
|
@@ -20290,9 +19672,17 @@ var IntentGateway = class _IntentGateway {
|
|
|
20290
19672
|
*
|
|
20291
19673
|
* Delegates to {@link OrderCanceller.cancelOrder}.
|
|
20292
19674
|
*
|
|
19675
|
+
* Same-chain orders always use the direct source-gateway route. The order
|
|
19676
|
+
* user may call through the deadline; any account may call strictly after
|
|
19677
|
+
* it, pays the transaction gas, and cannot change the refund beneficiary.
|
|
19678
|
+
* The SDK yields unsigned transaction fields and accepts either the caller's
|
|
19679
|
+
* signed raw transaction or its already-broadcast transaction hash.
|
|
19680
|
+
*
|
|
20293
19681
|
* @param order - The order to cancel.
|
|
20294
|
-
* @param indexerClient - Indexer client used for ISMP request
|
|
20295
|
-
*
|
|
19682
|
+
* @param indexerClient - Indexer client used for cross-chain ISMP request
|
|
19683
|
+
* status streaming; the same-chain route does not access it.
|
|
19684
|
+
* @param options - Choose the cross-chain initiation side. Defaults to source;
|
|
19685
|
+
* ignored for routing when source and destination are the same chain.
|
|
20296
19686
|
* @yields {@link CancelEvent} objects describing each cancellation stage.
|
|
20297
19687
|
*/
|
|
20298
19688
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
@@ -20422,7 +19812,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
20422
19812
|
if (estimate.totalGasCostWei === 0n || estimate.totalGasInFeeToken === 0n) {
|
|
20423
19813
|
throw new Error("Gas estimation failed");
|
|
20424
19814
|
}
|
|
20425
|
-
const fees = isSameChain ? estimate.totalGasInFeeToken * 2n : (estimate.totalGasInFeeToken + estimate.relayerFeeInSourceFeeToken) * 105n / 100n;
|
|
19815
|
+
const fees = isSameChain ? estimate.totalGasInFeeToken * 2n : ((estimate.totalGasInFeeToken + estimate.relayerFeeInSourceFeeToken) * 105n + 99n) / 100n;
|
|
20426
19816
|
const { address: feeToken } = await this.source.getFeeTokenWithDecimals();
|
|
20427
19817
|
return {
|
|
20428
19818
|
fees,
|
|
@@ -20455,17 +19845,27 @@ var IntentGateway = class _IntentGateway {
|
|
|
20455
19845
|
return this._crypto.decodeERC7821Execute(callData);
|
|
20456
19846
|
}
|
|
20457
19847
|
/**
|
|
20458
|
-
* Checks whether an order
|
|
19848
|
+
* Checks whether an order is finalized on the destination chain.
|
|
20459
19849
|
*
|
|
20460
19850
|
* Delegates to {@link OrderStatusChecker.isOrderFilled}.
|
|
20461
19851
|
*
|
|
20462
19852
|
* @param order - The order to check.
|
|
20463
|
-
* @returns `true`
|
|
20464
|
-
*
|
|
19853
|
+
* @returns `true` once a completing fill or a destination-side cancellation
|
|
19854
|
+
* has finalized the order; `false` while it is open or only partly filled.
|
|
20465
19855
|
*/
|
|
20466
19856
|
async isOrderFilled(order) {
|
|
20467
19857
|
return this.orderStatusChecker.isOrderFilled(order);
|
|
20468
19858
|
}
|
|
19859
|
+
/**
|
|
19860
|
+
* Output credited to the order so far, one entry per leg.
|
|
19861
|
+
*
|
|
19862
|
+
* Delegates to {@link OrderStatusChecker.getFillProgress}.
|
|
19863
|
+
*
|
|
19864
|
+
* @param order - The order to check.
|
|
19865
|
+
*/
|
|
19866
|
+
async getFillProgress(order) {
|
|
19867
|
+
return this.orderStatusChecker.getFillProgress(order);
|
|
19868
|
+
}
|
|
20469
19869
|
/**
|
|
20470
19870
|
* Checks whether all escrowed inputs for an order have been refunded on the
|
|
20471
19871
|
* source chain.
|
|
@@ -20473,8 +19873,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
20473
19873
|
* Delegates to {@link OrderStatusChecker.isOrderRefunded}.
|
|
20474
19874
|
*
|
|
20475
19875
|
* @param order - The order to check.
|
|
20476
|
-
* @returns `true` if every input
|
|
20477
|
-
* in the `_orders` mapping on the source chain.
|
|
19876
|
+
* @returns `true` if every input's escrowed amount has been zeroed out
|
|
19877
|
+
* in the per-leg `_orders` mapping on the source chain.
|
|
20478
19878
|
*/
|
|
20479
19879
|
async isOrderRefunded(order) {
|
|
20480
19880
|
return this.orderStatusChecker.isOrderRefunded(order);
|
|
@@ -20511,9 +19911,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
20511
19911
|
}
|
|
20512
19912
|
requireIndexer() {
|
|
20513
19913
|
if (!this.indexer) {
|
|
20514
|
-
throw new Error(
|
|
20515
|
-
"IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods or Phantom quotes"
|
|
20516
|
-
);
|
|
19914
|
+
throw new Error("IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods");
|
|
20517
19915
|
}
|
|
20518
19916
|
return this.indexer;
|
|
20519
19917
|
}
|
|
@@ -20536,74 +19934,64 @@ var IntentGateway = class _IntentGateway {
|
|
|
20536
19934
|
const { queryClient, pollInterval, logger } = this.requireIndexer();
|
|
20537
19935
|
const streamLogger = logger.withTag("[orderStatusStream]");
|
|
20538
19936
|
const TERMINAL = ["FILLED", "REDEEMED", "REFUNDED"];
|
|
19937
|
+
const latestOrderStatus = (order2) => {
|
|
19938
|
+
const latest = order2.statuses[order2.statuses.length - 1];
|
|
19939
|
+
if (latest.status === "CANCELLED") {
|
|
19940
|
+
for (let i = order2.statuses.length - 1; i >= 0; i--) {
|
|
19941
|
+
if (TERMINAL.includes(order2.statuses[i].status)) return order2.statuses[i];
|
|
19942
|
+
}
|
|
19943
|
+
}
|
|
19944
|
+
return latest;
|
|
19945
|
+
};
|
|
20539
19946
|
let order;
|
|
20540
19947
|
while (!order) {
|
|
20541
19948
|
await sleep(pollInterval);
|
|
20542
19949
|
order = await _queryOrderInternal({ commitmentHash: commitment, queryClient, logger });
|
|
20543
19950
|
}
|
|
20544
19951
|
streamLogger.trace("`Order` found");
|
|
20545
|
-
|
|
19952
|
+
let latestStatus = latestOrderStatus(order);
|
|
20546
19953
|
yield { status: latestStatus.status, metadata: latestStatus.metadata };
|
|
20547
19954
|
if (TERMINAL.includes(latestStatus.status)) return;
|
|
20548
19955
|
while (true) {
|
|
20549
19956
|
await sleep(pollInterval);
|
|
20550
19957
|
const updatedOrder = await _queryOrderInternal({ commitmentHash: commitment, queryClient, logger });
|
|
20551
19958
|
if (!updatedOrder) continue;
|
|
20552
|
-
const newLatestStatus = updatedOrder
|
|
19959
|
+
const newLatestStatus = latestOrderStatus(updatedOrder);
|
|
20553
19960
|
if (newLatestStatus.status !== latestStatus.status) {
|
|
19961
|
+
latestStatus = newLatestStatus;
|
|
20554
19962
|
yield { status: newLatestStatus.status, metadata: newLatestStatus.metadata };
|
|
20555
19963
|
if (TERMINAL.includes(newLatestStatus.status)) return;
|
|
20556
19964
|
}
|
|
20557
19965
|
}
|
|
20558
19966
|
}
|
|
20559
19967
|
};
|
|
20560
|
-
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
|
|
20564
|
-
}
|
|
20565
|
-
return f;
|
|
19968
|
+
|
|
19969
|
+
// src/protocols/intents/liquidity-pool.ts
|
|
19970
|
+
function sortPoolSymbols(symbolA, symbolB) {
|
|
19971
|
+
return symbolA.toLowerCase() <= symbolB.toLowerCase() ? [symbolA, symbolB] : [symbolB, symbolA];
|
|
20566
19972
|
}
|
|
20567
|
-
|
|
20568
|
-
|
|
20569
|
-
|
|
20570
|
-
|
|
20571
|
-
|
|
20572
|
-
|
|
20573
|
-
|
|
20574
|
-
}
|
|
20575
|
-
|
|
20576
|
-
|
|
20577
|
-
|
|
20578
|
-
|
|
20579
|
-
|
|
20580
|
-
|
|
20581
|
-
|
|
20582
|
-
|
|
20583
|
-
|
|
20584
|
-
|
|
20585
|
-
|
|
20586
|
-
|
|
20587
|
-
|
|
20588
|
-
body: JSON.stringify(payload)
|
|
20589
|
-
}),
|
|
20590
|
-
timeout
|
|
20591
|
-
]);
|
|
20592
|
-
const body = await response.json();
|
|
20593
|
-
if (body?.error) {
|
|
20594
|
-
lastErr = new Error(`rpc error: ${JSON.stringify(body.error).slice(0, 200)}`);
|
|
20595
|
-
continue;
|
|
20596
|
-
}
|
|
20597
|
-
return body;
|
|
20598
|
-
} catch (err) {
|
|
20599
|
-
lastErr = err;
|
|
20600
|
-
} finally {
|
|
20601
|
-
if (timer) clearTimeout(timer);
|
|
20602
|
-
}
|
|
20603
|
-
}
|
|
20604
|
-
throw new PhantomRpcError(`RPC call failed after 4 attempts: ${url}`, lastErr);
|
|
19973
|
+
function poolSlug(symbolA, symbolB) {
|
|
19974
|
+
return sortPoolSymbols(symbolA, symbolB).join("-");
|
|
19975
|
+
}
|
|
19976
|
+
|
|
19977
|
+
// src/protocols/intents/rateFill.ts
|
|
19978
|
+
function ceilDiv(numerator, denominator) {
|
|
19979
|
+
return numerator === 0n ? 0n : (numerator - 1n) / denominator + 1n;
|
|
19980
|
+
}
|
|
19981
|
+
function previewRateFill(escrow, required, filled, take, offered) {
|
|
19982
|
+
if (escrow <= 0n || required <= 0n || take <= 0n || offered <= 0n) {
|
|
19983
|
+
throw new Error("RateFillInvalidAmount");
|
|
19984
|
+
}
|
|
19985
|
+
if (filled < 0n || filled >= required) throw new Error("RateFillNoProgress");
|
|
19986
|
+
if (ceilDiv(take * required, escrow) > offered) throw new Error("RateBelowOrder");
|
|
19987
|
+
const uncappedCredit = take * required / escrow;
|
|
19988
|
+
const credit = uncappedCredit < required - filled ? uncappedCredit : required - filled;
|
|
19989
|
+
const release = escrow * (filled + credit) / required - escrow * filled / required;
|
|
19990
|
+
if (credit === 0n || release === 0n) throw new Error("RateFillNoProgress");
|
|
19991
|
+
const ratePayment = ceilDiv(offered * release, take);
|
|
19992
|
+
const delivered = ratePayment > credit ? ratePayment : credit;
|
|
19993
|
+
return { credit, release, delivered, surplus: delivered - credit };
|
|
20605
19994
|
}
|
|
20606
|
-
var FILL_ORDER_ABI = IntentGatewayV2_default.ABI;
|
|
20607
19995
|
var DECLARATION_V1 = 1;
|
|
20608
19996
|
var DECLARATION_V2 = 2;
|
|
20609
19997
|
var PAYMASTER_ADDRESS_BYTES = 20;
|
|
@@ -20801,40 +20189,6 @@ function encodeAcceptedSourceChains(chains2) {
|
|
|
20801
20189
|
function decodeAcceptedSourceChains(paymasterAndData) {
|
|
20802
20190
|
return decodePhantomBidDeclaration(paymasterAndData).acceptedSources;
|
|
20803
20191
|
}
|
|
20804
|
-
var UNISWAP_QUOTE_HAIRCUT_BPS = 10n;
|
|
20805
|
-
function haircut(amount, bps) {
|
|
20806
|
-
return amount * (10000n - bps) / 10000n;
|
|
20807
|
-
}
|
|
20808
|
-
function applyUniswapQuoteHaircut(amount) {
|
|
20809
|
-
return haircut(amount, UNISWAP_QUOTE_HAIRCUT_BPS);
|
|
20810
|
-
}
|
|
20811
|
-
var SELECTOR_GATEWAY_PARAMS = "0xcff0ab96";
|
|
20812
|
-
var GATEWAY_PARAMS_WORDS = 6;
|
|
20813
|
-
var GATEWAY_PARAMS_FEE_WORD = 4;
|
|
20814
|
-
async function readProtocolFeeHaircutBps(evmRpcUrl, gatewayAddress) {
|
|
20815
|
-
const result = await rpcCall(evmRpcUrl, {
|
|
20816
|
-
id: 1,
|
|
20817
|
-
jsonrpc: "2.0",
|
|
20818
|
-
method: "eth_call",
|
|
20819
|
-
params: [{ to: gatewayAddress, data: SELECTOR_GATEWAY_PARAMS }, "latest"]
|
|
20820
|
-
});
|
|
20821
|
-
const hex = result.result;
|
|
20822
|
-
if (typeof hex !== "string" || hex.length < 2 + 64 * GATEWAY_PARAMS_WORDS) {
|
|
20823
|
-
throw new PhantomRpcError(`IntentGateway.params() returned no usable result from ${gatewayAddress} on ${evmRpcUrl}`);
|
|
20824
|
-
}
|
|
20825
|
-
const start = 2 + 64 * GATEWAY_PARAMS_FEE_WORD;
|
|
20826
|
-
const protocolFeeBps = BigInt(`0x${hex.slice(start, start + 64)}`);
|
|
20827
|
-
if (protocolFeeBps >= 10000n) {
|
|
20828
|
-
throw new PhantomRpcError(`IntentGateway ${gatewayAddress} reports an implausible protocol fee: ${protocolFeeBps} bps`);
|
|
20829
|
-
}
|
|
20830
|
-
return protocolFeeBps;
|
|
20831
|
-
}
|
|
20832
|
-
function applyProtocolFeeHaircut(amount, protocolFeeBps) {
|
|
20833
|
-
return haircut(amount, protocolFeeBps);
|
|
20834
|
-
}
|
|
20835
|
-
FILL_ORDER_ABI.find(
|
|
20836
|
-
(item) => item?.type === "function" && item?.name === "fillOrder"
|
|
20837
|
-
)?.inputs?.[0];
|
|
20838
20192
|
var TokenGateway = class {
|
|
20839
20193
|
source;
|
|
20840
20194
|
dest;
|
|
@@ -25050,9 +24404,9 @@ async function teleport(teleport_param) {
|
|
|
25050
24404
|
if (scaleEncodedAssetId === null) {
|
|
25051
24405
|
throw new Error("Unknown asset id provided");
|
|
25052
24406
|
}
|
|
25053
|
-
const
|
|
25054
|
-
const destination = convertStateMachineIdToEnum(
|
|
25055
|
-
const recipient = viem.hexToBytes(normalizeAddressForStateMachine(params.recipient,
|
|
24407
|
+
const destinationStateMachine2 = normalizeStateMachineId(params.destination);
|
|
24408
|
+
const destination = convertStateMachineIdToEnum(destinationStateMachine2);
|
|
24409
|
+
const recipient = viem.hexToBytes(normalizeAddressForStateMachine(params.recipient, destinationStateMachine2));
|
|
25056
24410
|
const teleportParams = {
|
|
25057
24411
|
destination,
|
|
25058
24412
|
recepient: Array.from(recipient),
|
|
@@ -25307,7 +24661,7 @@ async function teleportDot(param_) {
|
|
|
25307
24661
|
|
|
25308
24662
|
exports.ADDRESS_ZERO = ADDRESS_ZERO2;
|
|
25309
24663
|
exports.BundlerMethod = BundlerMethod;
|
|
25310
|
-
exports.
|
|
24664
|
+
exports.CONTRACT_VERSION_ABI = CONTRACT_VERSION_ABI;
|
|
25311
24665
|
exports.ChainConfigService = ChainConfigService;
|
|
25312
24666
|
exports.Chains = Chains;
|
|
25313
24667
|
exports.CryptoUtils = CryptoUtils;
|
|
@@ -25320,29 +24674,31 @@ exports.ERC7821_BATCH_MODE = ERC7821_BATCH_MODE;
|
|
|
25320
24674
|
exports.EvmChain = EvmChain;
|
|
25321
24675
|
exports.EvmHostABI = ABI;
|
|
25322
24676
|
exports.EvmLanguage = EvmLanguage;
|
|
25323
|
-
exports.
|
|
24677
|
+
exports.FILL_ORDER_SELECTOR = FILL_ORDER_SELECTOR;
|
|
25324
24678
|
exports.HyperClientStatus = HyperClientStatus;
|
|
25325
24679
|
exports.HyperFungibleToken = HyperFungibleToken;
|
|
25326
24680
|
exports.HyperFungibleTokenABI = HyperFungibleTokenABI;
|
|
24681
|
+
exports.HyperFxOrderbook = HyperFxOrderbook;
|
|
25327
24682
|
exports.INCLUSION_TIMEOUT_MS = INCLUSION_TIMEOUT_MS;
|
|
25328
|
-
exports.
|
|
24683
|
+
exports.InsufficientOrderbookLiquidityError = InsufficientOrderbookLiquidityError;
|
|
25329
24684
|
exports.IntentGateway = IntentGateway;
|
|
25330
24685
|
exports.IntentGatewayABI = ABI3;
|
|
25331
24686
|
exports.IntentOrderStatus = IntentOrderStatus;
|
|
25332
24687
|
exports.IntentsCoprocessor = IntentsCoprocessor;
|
|
25333
|
-
exports.InvalidIndexedRateError = InvalidIndexedRateError;
|
|
25334
|
-
exports.InvalidLiquidityIndexerResponseError = InvalidLiquidityIndexerResponseError;
|
|
25335
|
-
exports.InvalidPhantomSnapshotError = InvalidPhantomSnapshotError;
|
|
25336
24688
|
exports.IsmpClient = IsmpClient;
|
|
25337
|
-
exports.
|
|
24689
|
+
exports.MAX_DECLARED_ENTRIES = MAX_DECLARED_ENTRIES;
|
|
25338
24690
|
exports.MOCK_ADDRESS = MOCK_ADDRESS;
|
|
24691
|
+
exports.ORDERBOOK_DECIMALS = ORDERBOOK_DECIMALS;
|
|
24692
|
+
exports.ORDERBOOK_QUERIES = ORDERBOOK_QUERIES;
|
|
24693
|
+
exports.ORDERBOOK_URLS = ORDERBOOK_URLS;
|
|
25339
24694
|
exports.ORDER_V2_PARAM_TYPE = ORDER_V2_PARAM_TYPE;
|
|
25340
24695
|
exports.OrderStatus = OrderStatus;
|
|
25341
24696
|
exports.OrderStatusChecker = OrderStatusChecker;
|
|
24697
|
+
exports.OrderbookQuoteNotConvergedError = OrderbookQuoteNotConvergedError;
|
|
24698
|
+
exports.OrderbookRequestError = OrderbookRequestError;
|
|
25342
24699
|
exports.PACKED_USEROP_TYPEHASH = PACKED_USEROP_TYPEHASH;
|
|
25343
24700
|
exports.PERMIT2_SPONSORSHIP_BYTES = PERMIT2_SPONSORSHIP_BYTES;
|
|
25344
24701
|
exports.PLACE_ORDER_SELECTOR = PLACE_ORDER_SELECTOR;
|
|
25345
|
-
exports.PhantomSnapshotUnavailableError = PhantomSnapshotUnavailableError;
|
|
25346
24702
|
exports.PharosChain = PharosChain;
|
|
25347
24703
|
exports.PolkadotHubChain = PolkadotHubChain;
|
|
25348
24704
|
exports.REQUEST_COMMITMENTS_SLOT = REQUEST_COMMITMENTS_SLOT;
|
|
@@ -25353,6 +24709,7 @@ exports.RequestKind = RequestKind;
|
|
|
25353
24709
|
exports.RequestStatus = RequestStatus;
|
|
25354
24710
|
exports.SELECT_SOLVER_TYPEHASH = SELECT_SOLVER_TYPEHASH;
|
|
25355
24711
|
exports.STATE_COMMITMENTS_SLOT = STATE_COMMITMENTS_SLOT;
|
|
24712
|
+
exports.SUPPORTED_INTENTS_VERSION = SUPPORTED_INTENTS_VERSION;
|
|
25356
24713
|
exports.SubstrateChain = SubstrateChain;
|
|
25357
24714
|
exports.Swap = Swap;
|
|
25358
24715
|
exports.TESTNET_CHAINS = TESTNET_CHAINS;
|
|
@@ -25360,17 +24717,13 @@ exports.TeleportStatus = TeleportStatus;
|
|
|
25360
24717
|
exports.TimeoutStatus = TimeoutStatus;
|
|
25361
24718
|
exports.TokenGateway = TokenGateway;
|
|
25362
24719
|
exports.TronChain = TronChain;
|
|
25363
|
-
exports.UNISWAP_QUOTE_HAIRCUT_BPS = UNISWAP_QUOTE_HAIRCUT_BPS;
|
|
25364
24720
|
exports.USE_ETHERSCAN_CHAINS = USE_ETHERSCAN_CHAINS;
|
|
25365
|
-
exports.UnsupportedIntentQuotePairError = UnsupportedIntentQuotePairError;
|
|
25366
|
-
exports.UnsupportedIntentQuoteStrategyError = UnsupportedIntentQuoteStrategyError;
|
|
25367
24721
|
exports.UnsupportedLiquidityAssetError = UnsupportedLiquidityAssetError;
|
|
25368
24722
|
exports.UnsupportedLiquidityChainError = UnsupportedLiquidityChainError;
|
|
25369
24723
|
exports.WrappedHyperFungibleTokenABI = WrappedHyperFungibleTokenABI;
|
|
25370
24724
|
exports.__test = __test;
|
|
25371
24725
|
exports.adjustDecimals = adjustDecimals;
|
|
25372
|
-
exports.
|
|
25373
|
-
exports.applyUniswapQuoteHaircut = applyUniswapQuoteHaircut;
|
|
24726
|
+
exports.assertGatewayRelease = assertGatewayRelease;
|
|
25374
24727
|
exports.bytes20ToBytes32 = bytes20ToBytes32;
|
|
25375
24728
|
exports.bytes32ToBytes20 = bytes32ToBytes20;
|
|
25376
24729
|
exports.calculateAllowanceMappingLocation = calculateAllowanceMappingLocation;
|
|
@@ -25411,7 +24764,6 @@ exports.getChainId = getChainId;
|
|
|
25411
24764
|
exports.getConfigByStateMachineId = getConfigByStateMachineId;
|
|
25412
24765
|
exports.getContractCallInput = getContractCallInput;
|
|
25413
24766
|
exports.getContractCallInputs = getContractCallInputs;
|
|
25414
|
-
exports.getFillOptionsVersion = getFillOptionsVersion;
|
|
25415
24767
|
exports.getGasPriceFromEtherscan = getGasPriceFromEtherscan;
|
|
25416
24768
|
exports.getOrFetchStorageSlot = getOrFetchStorageSlot;
|
|
25417
24769
|
exports.getOrderPlacedFromTx = getOrderPlacedFromTx;
|
|
@@ -25424,6 +24776,7 @@ exports.getStorageSlot = getStorageSlot;
|
|
|
25424
24776
|
exports.getViemChain = getViemChain;
|
|
25425
24777
|
exports.hexToString = hexToString;
|
|
25426
24778
|
exports.hyperbridgeAddress = hyperbridgeAddress;
|
|
24779
|
+
exports.isCanonicalEvmToken = isCanonicalEvmToken;
|
|
25427
24780
|
exports.maxBigInt = maxBigInt;
|
|
25428
24781
|
exports.normalizeAddressForEvmBytes32 = normalizeAddressForEvmBytes32;
|
|
25429
24782
|
exports.normalizeAddressForStateMachine = normalizeAddressForStateMachine;
|
|
@@ -25431,6 +24784,7 @@ exports.normalizeEvmAddress = normalizeEvmAddress;
|
|
|
25431
24784
|
exports.normalizeEvmChainId = normalizeEvmChainId;
|
|
25432
24785
|
exports.normalizeStateMachineId = normalizeStateMachineId;
|
|
25433
24786
|
exports.orderCommitment = orderCommitment;
|
|
24787
|
+
exports.orderbookUrlFor = orderbookUrlFor;
|
|
25434
24788
|
exports.parseStateMachineId = parseStateMachineId;
|
|
25435
24789
|
exports.pharosAtlantic = pharosAtlantic;
|
|
25436
24790
|
exports.pharosMainnet = pharosMainnet;
|
|
@@ -25438,16 +24792,18 @@ exports.polkadotAssetHubPaseo = polkadotAssetHubPaseo;
|
|
|
25438
24792
|
exports.polkadotHubMainnet = polkadotHubMainnet;
|
|
25439
24793
|
exports.poolSlug = poolSlug;
|
|
25440
24794
|
exports.postRequestCommitment = postRequestCommitment;
|
|
24795
|
+
exports.previewRateFill = previewRateFill;
|
|
25441
24796
|
exports.queryAssetTeleported = queryAssetTeleported;
|
|
25442
24797
|
exports.queryGetRequest = queryGetRequest;
|
|
25443
24798
|
exports.queryPostRequest = queryPostRequest;
|
|
25444
24799
|
exports.quoteUniswap = quoteUniswap;
|
|
25445
|
-
exports.
|
|
24800
|
+
exports.readLegEscrow = readLegEscrow;
|
|
24801
|
+
exports.readLegPartialFill = readLegPartialFill;
|
|
25446
24802
|
exports.requestCommitmentKey = requestCommitmentKey;
|
|
25447
|
-
exports.resetFillOptionsVersionCache = resetFillOptionsVersionCache;
|
|
25448
24803
|
exports.responseCommitmentKey = responseCommitmentKey;
|
|
25449
24804
|
exports.retryPromise = retryPromise;
|
|
25450
24805
|
exports.sortPoolSymbols = sortPoolSymbols;
|
|
24806
|
+
exports.supportsRateFills = supportsRateFills;
|
|
25451
24807
|
exports.teleport = teleport;
|
|
25452
24808
|
exports.teleportDot = teleportDot;
|
|
25453
24809
|
exports.transformOrderForContract = transformOrderForContract;
|