@hyperbridge/sdk 2.8.13 → 2.8.16
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 +748 -906
- package/dist/browser/index.js +1357 -2080
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +1377 -2098
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +405 -179
- package/dist/node/index.d.ts +405 -179
- package/dist/node/index.js +1357 -2080
- 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,727 +18759,374 @@ 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];
|
|
19080
|
-
}
|
|
19081
|
-
function poolSlug(symbolA, symbolB) {
|
|
19082
|
-
return sortPoolSymbols(symbolA, symbolB).join("-");
|
|
18762
|
+
function destinationStateMachine(order) {
|
|
18763
|
+
return viem.isHex(order.destination) ? viem.hexToString(order.destination) : order.destination;
|
|
19083
18764
|
}
|
|
19084
|
-
|
|
19085
|
-
|
|
19086
|
-
|
|
19087
|
-
|
|
19088
|
-
|
|
19089
|
-
|
|
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 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 amountOut rate fillable depth maxFillableIn
|
|
18798
|
+
fills { orderRate amountOut advertisedSize }
|
|
18799
|
+
}
|
|
18800
|
+
}`;
|
|
18801
|
+
var ORDERBOOK_QUERIES = {
|
|
18802
|
+
topOfBook: TOP_OF_BOOK_QUERY,
|
|
18803
|
+
routeLiquidity: ROUTE_LIQUIDITY_QUERY,
|
|
18804
|
+
quote: QUOTE_QUERY
|
|
18805
|
+
};
|
|
18806
|
+
var HyperFxOrderbook = class {
|
|
18807
|
+
client;
|
|
18808
|
+
/** @param urlOrClient - The orderbook's GraphQL URL, or a configured `graphql-request` client. */
|
|
18809
|
+
constructor(urlOrClient = ORDERBOOK_URLS.mainnet) {
|
|
18810
|
+
this.client = typeof urlOrClient === "string" ? new graphqlRequest.GraphQLClient(urlOrClient) : urlOrClient;
|
|
18811
|
+
}
|
|
19104
18812
|
/**
|
|
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
|
|
18813
|
+
* The best bid and ask on `fillChain` for the pair `tokenA`/`tokenB`, counting
|
|
18814
|
+
* only orders a swap from `sourceChain` can use.
|
|
18815
|
+
*/
|
|
18816
|
+
async topOfBook(params) {
|
|
18817
|
+
const data = await this.request(TOP_OF_BOOK_QUERY, params);
|
|
18818
|
+
const book = findBook(data.books, params.tokenA, params.tokenB);
|
|
18819
|
+
const rates = [data.aToB, data.bToA].filter((rate) => rate !== null).map(parseRate);
|
|
18820
|
+
return {
|
|
18821
|
+
book,
|
|
18822
|
+
bid: rates.find((rate) => rate.side === "BID") ?? null,
|
|
18823
|
+
ask: rates.find((rate) => rate.side === "ASK") ?? null
|
|
19125
18824
|
};
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
}
|
|
19130
|
-
const
|
|
19131
|
-
if (!chainLiquidity) return void 0;
|
|
19132
|
-
const route = response.poolRoutes.nodes[0];
|
|
18825
|
+
}
|
|
18826
|
+
/** Total liquidity on a route, no amount required. */
|
|
18827
|
+
async routeLiquidity(route) {
|
|
18828
|
+
const { books, routeLiquidity: raw } = await this.request(ROUTE_LIQUIDITY_QUERY, { route });
|
|
18829
|
+
const book = findBook(books, route.tokenIn, route.tokenOut);
|
|
19133
18830
|
return {
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
|
|
19137
|
-
|
|
19138
|
-
|
|
19139
|
-
|
|
19140
|
-
|
|
19141
|
-
|
|
19142
|
-
|
|
19143
|
-
|
|
19144
|
-
explicitRoute: route ? {
|
|
19145
|
-
...readLiquiditySlice(route.depth, route.bidCount, "explicit route"),
|
|
19146
|
-
updatedAt: readIndexerDate(route.lastUpdatedAt, "route lastUpdatedAt")
|
|
19147
|
-
} : null
|
|
18831
|
+
route: raw.route,
|
|
18832
|
+
book,
|
|
18833
|
+
side: book.base === route.tokenIn ? "BID" : "ASK",
|
|
18834
|
+
bestRate: raw.bestRate === null ? null : BigInt(raw.bestRate),
|
|
18835
|
+
depthIn: BigInt(raw.depthIn),
|
|
18836
|
+
depthOut: BigInt(raw.depthOut),
|
|
18837
|
+
availableLiquidity: BigInt(raw.availableLiquidity),
|
|
18838
|
+
maxFillableIn: BigInt(raw.maxFillableIn),
|
|
18839
|
+
orderCount: raw.orderCount,
|
|
18840
|
+
solverCount: raw.solverCount
|
|
19148
18841
|
};
|
|
19149
18842
|
}
|
|
19150
|
-
/**
|
|
19151
|
-
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
* source and destination chains remain part of the result because they define
|
|
19156
|
-
* the cross-chain route whose configured token symbols were resolved.
|
|
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
|
|
18843
|
+
/** The clearing price for `amountIn` (1e18 tokenIn) on a route, which may combine several solvers' orders. */
|
|
18844
|
+
async quote(route, amountIn) {
|
|
18845
|
+
const { quote: raw } = await this.request(QUOTE_QUERY, {
|
|
18846
|
+
route,
|
|
18847
|
+
amountIn: amountIn.toString()
|
|
19162
18848
|
});
|
|
19163
|
-
if (!response?.liquidityPools?.nodes) {
|
|
19164
|
-
throw new InvalidLiquidityIndexerResponseError("liquidity pool connection is missing");
|
|
19165
|
-
}
|
|
19166
|
-
const indexedPool = response.liquidityPools.nodes[0];
|
|
19167
|
-
if (!indexedPool) return void 0;
|
|
19168
|
-
validateIndexedPool(indexedPool, pool);
|
|
19169
|
-
const sell = readIndexedRate(indexedPool.sellRate, indexedPool.lastUpdatedAt, "pool sell rate");
|
|
19170
|
-
const buy = readIndexedRate(indexedPool.buyRate, indexedPool.lastUpdatedAt, "pool buy rate");
|
|
19171
|
-
const inputIsToken0 = params.tokenInSymbol.toLowerCase() === pool.token0Symbol.toLowerCase();
|
|
19172
|
-
const direct = inputIsToken0 ? sell : buy;
|
|
19173
|
-
const reverse = inputIsToken0 ? buy : sell;
|
|
19174
|
-
if (!direct && !reverse) return void 0;
|
|
19175
|
-
const quoteTokenSymbol = resolveQuoteTokenSymbol(
|
|
19176
|
-
params.tokenInSymbol,
|
|
19177
|
-
params.tokenOutSymbol,
|
|
19178
|
-
direct?.scaledRate,
|
|
19179
|
-
reverse?.scaledRate
|
|
19180
|
-
);
|
|
19181
|
-
const quoteIsTokenOut = quoteTokenSymbol === params.tokenOutSymbol;
|
|
19182
|
-
const orientedBuy = quoteIsTokenOut ? direct : reverse;
|
|
19183
|
-
const orientedSell = quoteIsTokenOut ? reverse : direct;
|
|
19184
18849
|
return {
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
|
|
19188
|
-
|
|
19189
|
-
|
|
19190
|
-
|
|
19191
|
-
|
|
19192
|
-
|
|
18850
|
+
route: raw.route,
|
|
18851
|
+
side: raw.side,
|
|
18852
|
+
amountIn: BigInt(raw.amountIn),
|
|
18853
|
+
amountOut: BigInt(raw.amountOut),
|
|
18854
|
+
rate: raw.rate === null ? null : BigInt(raw.rate),
|
|
18855
|
+
fillable: raw.fillable,
|
|
18856
|
+
depth: BigInt(raw.depth),
|
|
18857
|
+
maxFillableIn: BigInt(raw.maxFillableIn),
|
|
18858
|
+
fills: raw.fills.map((fill) => ({
|
|
18859
|
+
orderRate: BigInt(fill.orderRate),
|
|
18860
|
+
amountOut: BigInt(fill.amountOut),
|
|
18861
|
+
advertisedSize: BigInt(fill.advertisedSize)
|
|
18862
|
+
}))
|
|
19193
18863
|
};
|
|
19194
18864
|
}
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
18865
|
+
async request(query, variables) {
|
|
18866
|
+
try {
|
|
18867
|
+
return await this.client.request(query, variables);
|
|
18868
|
+
} catch (error) {
|
|
18869
|
+
throw new OrderbookRequestError(describeError(error));
|
|
18870
|
+
}
|
|
19200
18871
|
}
|
|
19201
18872
|
};
|
|
18873
|
+
function describeError(error) {
|
|
18874
|
+
const graphqlErrors = error?.response?.errors;
|
|
18875
|
+
if (graphqlErrors?.length) return graphqlErrors.map((e) => e.message).join("; ");
|
|
18876
|
+
return error instanceof Error ? error.message : String(error);
|
|
18877
|
+
}
|
|
18878
|
+
function findBook(books, tokenA, tokenB) {
|
|
18879
|
+
const book = books.find(
|
|
18880
|
+
(b) => b.base === tokenA && b.quote === tokenB || b.base === tokenB && b.quote === tokenA
|
|
18881
|
+
);
|
|
18882
|
+
if (!book) throw new OrderbookRequestError(`no book trades ${tokenA} for ${tokenB}`);
|
|
18883
|
+
return book;
|
|
18884
|
+
}
|
|
18885
|
+
function parseRate(raw) {
|
|
18886
|
+
return {
|
|
18887
|
+
side: raw.side,
|
|
18888
|
+
fillChain: raw.fillChain,
|
|
18889
|
+
rate: BigInt(raw.rate),
|
|
18890
|
+
depthIn: BigInt(raw.depthIn),
|
|
18891
|
+
depthOut: BigInt(raw.depthOut),
|
|
18892
|
+
backingLiquidity: BigInt(raw.backingLiquidity),
|
|
18893
|
+
sourceChains: raw.sourceChains,
|
|
18894
|
+
orderCount: raw.orderCount,
|
|
18895
|
+
solverCount: raw.solverCount
|
|
18896
|
+
};
|
|
18897
|
+
}
|
|
18898
|
+
|
|
18899
|
+
// src/protocols/intents/orderbook/types.ts
|
|
19202
18900
|
var UnsupportedLiquidityAssetError = class extends Error {
|
|
19203
18901
|
constructor(chain, asset) {
|
|
19204
|
-
super(`No configured
|
|
18902
|
+
super(`No configured asset found for ${asset} on ${chain}`);
|
|
19205
18903
|
this.name = "UnsupportedLiquidityAssetError";
|
|
19206
18904
|
}
|
|
19207
18905
|
};
|
|
19208
18906
|
var UnsupportedLiquidityChainError = class extends Error {
|
|
19209
18907
|
constructor(chainId) {
|
|
19210
|
-
super(`No configured
|
|
18908
|
+
super(`No configured chain found for chain ID ${chainId}`);
|
|
19211
18909
|
this.name = "UnsupportedLiquidityChainError";
|
|
19212
18910
|
}
|
|
19213
18911
|
};
|
|
19214
|
-
|
|
19215
|
-
|
|
19216
|
-
throw new InvalidLiquidityIndexerResponseError(`${label} provider count is invalid`);
|
|
19217
|
-
}
|
|
19218
|
-
return { totalLiquidity: formatIndexerAmount(depth, `${label} depth`), providerCount };
|
|
19219
|
-
}
|
|
19220
|
-
function formatIndexerAmount(value, label) {
|
|
19221
|
-
try {
|
|
19222
|
-
const amount = BigInt(value);
|
|
19223
|
-
if (amount < 0n) throw new Error();
|
|
19224
|
-
return viem.formatUnits(amount, INDEXER_FIXED_POINT_DECIMALS);
|
|
19225
|
-
} catch {
|
|
19226
|
-
throw new InvalidLiquidityIndexerResponseError(`${label} is not a non-negative integer`);
|
|
19227
|
-
}
|
|
19228
|
-
}
|
|
19229
|
-
function readIndexerDate(value, label) {
|
|
19230
|
-
const date = new Date(dateStringtoTimestamp(value));
|
|
19231
|
-
if (Number.isNaN(date.getTime())) throw new InvalidLiquidityIndexerResponseError(`${label} is invalid`);
|
|
19232
|
-
return date;
|
|
19233
|
-
}
|
|
19234
|
-
function readIndexedRate(value, lastUpdatedAt, label) {
|
|
19235
|
-
if (value === null) return void 0;
|
|
19236
|
-
try {
|
|
19237
|
-
const scaledRate = BigInt(value);
|
|
19238
|
-
if (scaledRate <= 0n) throw new Error();
|
|
19239
|
-
return {
|
|
19240
|
-
scaledRate,
|
|
19241
|
-
updatedAt: readIndexerDate(lastUpdatedAt, `${label} lastUpdatedAt`)
|
|
19242
|
-
};
|
|
19243
|
-
} catch (error) {
|
|
19244
|
-
if (error instanceof InvalidLiquidityIndexerResponseError) throw error;
|
|
19245
|
-
throw new InvalidLiquidityIndexerResponseError(`${label} is not a positive integer`);
|
|
19246
|
-
}
|
|
19247
|
-
}
|
|
19248
|
-
function validateIndexedPool(indexedPool, expected) {
|
|
19249
|
-
if (indexedPool.id.toLowerCase() !== expected.poolId.toLowerCase() || indexedPool.token0Symbol.toLowerCase() !== expected.token0Symbol.toLowerCase() || indexedPool.token1Symbol.toLowerCase() !== expected.token1Symbol.toLowerCase()) {
|
|
19250
|
-
throw new InvalidLiquidityIndexerResponseError(`pool identity does not match ${expected.poolId}`);
|
|
19251
|
-
}
|
|
19252
|
-
}
|
|
19253
|
-
function resolveQuoteTokenSymbol(tokenInSymbol, tokenOutSymbol, directRate, reverseRate) {
|
|
19254
|
-
const inputIsUsdStable = USD_STABLE_SYMBOLS.has(tokenInSymbol);
|
|
19255
|
-
const outputIsUsdStable = USD_STABLE_SYMBOLS.has(tokenOutSymbol);
|
|
19256
|
-
if (inputIsUsdStable !== outputIsUsdStable) return inputIsUsdStable ? tokenOutSymbol : tokenInSymbol;
|
|
19257
|
-
if (directRate !== void 0) return directRate >= POOL_RATE_SCALE ? tokenOutSymbol : tokenInSymbol;
|
|
19258
|
-
if (reverseRate !== void 0) return reverseRate >= POOL_RATE_SCALE ? tokenInSymbol : tokenOutSymbol;
|
|
19259
|
-
throw new InvalidLiquidityIndexerResponseError("cannot orient an empty rate pair");
|
|
19260
|
-
}
|
|
19261
|
-
function reciprocalRate(rate, label) {
|
|
19262
|
-
const numerator = POOL_RATE_SCALE * POOL_RATE_SCALE;
|
|
19263
|
-
const reciprocal = (numerator + rate - 1n) / rate;
|
|
19264
|
-
if (reciprocal <= 0n) throw new InvalidLiquidityIndexerResponseError(`${label} reciprocal underflowed`);
|
|
19265
|
-
return reciprocal;
|
|
19266
|
-
}
|
|
19267
|
-
|
|
19268
|
-
// src/protocols/intents/quote/types.ts
|
|
19269
|
-
var UnsupportedIntentQuoteStrategyError = class extends Error {
|
|
19270
|
-
constructor(strategy) {
|
|
19271
|
-
super(`Unsupported intent quote strategy: ${strategy}`);
|
|
19272
|
-
this.name = "UnsupportedIntentQuoteStrategyError";
|
|
19273
|
-
}
|
|
19274
|
-
};
|
|
19275
|
-
var UnsupportedIntentQuotePairError = class extends Error {
|
|
19276
|
-
constructor(params) {
|
|
18912
|
+
var OrderbookQuoteNotConvergedError = class extends Error {
|
|
18913
|
+
constructor(route, rounds, lastAmountIn) {
|
|
19277
18914
|
super(
|
|
19278
|
-
`No
|
|
18915
|
+
`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`
|
|
19279
18916
|
);
|
|
19280
|
-
this.
|
|
19281
|
-
|
|
19282
|
-
|
|
19283
|
-
|
|
19284
|
-
|
|
19285
|
-
|
|
19286
|
-
|
|
19287
|
-
|
|
19288
|
-
};
|
|
19289
|
-
var InvalidPhantomSnapshotError = class extends Error {
|
|
19290
|
-
constructor(commitment, reason) {
|
|
19291
|
-
super(`Invalid Phantom order price snapshot ${commitment}: ${reason}`);
|
|
19292
|
-
this.name = "InvalidPhantomSnapshotError";
|
|
19293
|
-
}
|
|
19294
|
-
};
|
|
19295
|
-
var IndexedRateUnavailableError = class extends Error {
|
|
19296
|
-
constructor(params) {
|
|
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";
|
|
19301
|
-
}
|
|
18917
|
+
this.route = route;
|
|
18918
|
+
this.rounds = rounds;
|
|
18919
|
+
this.lastAmountIn = lastAmountIn;
|
|
18920
|
+
this.name = "OrderbookQuoteNotConvergedError";
|
|
18921
|
+
}
|
|
18922
|
+
route;
|
|
18923
|
+
rounds;
|
|
18924
|
+
lastAmountIn;
|
|
19302
18925
|
};
|
|
19303
|
-
var
|
|
19304
|
-
constructor(
|
|
19305
|
-
super(
|
|
19306
|
-
|
|
18926
|
+
var InsufficientOrderbookLiquidityError = class extends Error {
|
|
18927
|
+
constructor(route, maxFillableIn) {
|
|
18928
|
+
super(
|
|
18929
|
+
`The HyperFX orderbook cannot fill ${route.tokenIn} -> ${route.tokenOut} on ${route.sourceChain} -> ${route.destinationChain}; max fillable input is ${maxFillableIn} raw units`
|
|
18930
|
+
);
|
|
18931
|
+
this.route = route;
|
|
18932
|
+
this.maxFillableIn = maxFillableIn;
|
|
18933
|
+
this.name = "InsufficientOrderbookLiquidityError";
|
|
19307
18934
|
}
|
|
18935
|
+
route;
|
|
18936
|
+
maxFillableIn;
|
|
19308
18937
|
};
|
|
19309
|
-
var BPS_DENOMINATOR = 10000n;
|
|
19310
|
-
function validateQuoteParams(params) {
|
|
19311
|
-
const hasAmountIn = params.amountIn !== void 0;
|
|
19312
|
-
const hasAmountOut = params.amountOut !== void 0;
|
|
19313
|
-
if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
|
|
19314
|
-
if (params.amountIn !== void 0 && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
|
|
19315
|
-
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
|
-
}
|
|
19320
|
-
async function readProtocolFeeBps(chainConfigService, source) {
|
|
19321
|
-
const gatewayAddress = chainConfigService.getIntentGatewayAddress(source.stateMachineId);
|
|
19322
|
-
if (!gatewayAddress || gatewayAddress === "0x" || gatewayAddress === viem.zeroAddress) {
|
|
19323
|
-
throw new Error(`IntentGatewayV2 is not configured for chain ${source.stateMachineId}`);
|
|
19324
|
-
}
|
|
19325
|
-
const gatewayParams = await source.client.readContract({
|
|
19326
|
-
address: gatewayAddress,
|
|
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;
|
|
19340
|
-
}
|
|
19341
|
-
function grossUpForProtocolFee(netAmount, protocolFeeBps) {
|
|
19342
|
-
if (protocolFeeBps <= 0n) return netAmount;
|
|
19343
|
-
if (protocolFeeBps >= BPS_DENOMINATOR) throw new Error("protocolFeeBps must be less than 10,000");
|
|
19344
|
-
return divCeil(netAmount * BPS_DENOMINATOR, BPS_DENOMINATOR - protocolFeeBps);
|
|
19345
|
-
}
|
|
19346
|
-
function divCeil(numerator, denominator) {
|
|
19347
|
-
if (denominator <= 0n) throw new Error("denominator must be greater than zero");
|
|
19348
|
-
return (numerator + denominator - 1n) / denominator;
|
|
19349
|
-
}
|
|
19350
18938
|
|
|
19351
|
-
// src/protocols/intents/
|
|
19352
|
-
var
|
|
19353
|
-
var
|
|
19354
|
-
constructor(
|
|
19355
|
-
this.
|
|
19356
|
-
|
|
19357
|
-
|
|
19358
|
-
|
|
19359
|
-
|
|
18939
|
+
// src/protocols/intents/orderbook/market.ts
|
|
18940
|
+
var MAX_EXACT_OUTPUT_ROUNDS = 16;
|
|
18941
|
+
var OrderbookMarket = class {
|
|
18942
|
+
constructor(configService, orderbook) {
|
|
18943
|
+
this.configService = configService;
|
|
18944
|
+
this.orderbook = orderbook;
|
|
18945
|
+
}
|
|
18946
|
+
configService;
|
|
18947
|
+
orderbook;
|
|
18948
|
+
async quoteIntent(params, sourceChain, destinationChain) {
|
|
19360
18949
|
validateQuoteParams(params);
|
|
19361
|
-
const
|
|
19362
|
-
const
|
|
19363
|
-
const
|
|
19364
|
-
|
|
19365
|
-
|
|
19366
|
-
|
|
19367
|
-
|
|
19368
|
-
|
|
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;
|
|
19425
|
-
}
|
|
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}`);
|
|
18950
|
+
const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
|
|
18951
|
+
const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
|
|
18952
|
+
const route = toRoute(tokenIn, tokenOut);
|
|
18953
|
+
if (params.amountIn !== void 0) {
|
|
18954
|
+
const quote2 = await this.orderbook().quote(route, toOrderbookAmount(params.amountIn, tokenIn.decimals));
|
|
18955
|
+
const amountOut2 = quote2.fillable ? fromOrderbookAmount(quote2.amountOut, tokenOut.decimals) : 0n;
|
|
18956
|
+
if (amountOut2 === 0n) throw this.insufficient(route, quote2.maxFillableIn, tokenIn);
|
|
18957
|
+
return buildQuote("EXACT_INPUT", params.amountIn, amountOut2, quote2, tokenIn, tokenOut);
|
|
19430
18958
|
}
|
|
19431
|
-
|
|
19432
|
-
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
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,
|
|
18959
|
+
const amountOut = params.amountOut;
|
|
18960
|
+
const quote = await this.quoteExactOutput(route, toOrderbookAmount(amountOut, tokenOut.decimals), tokenIn);
|
|
18961
|
+
return buildQuote(
|
|
18962
|
+
"EXACT_OUTPUT",
|
|
18963
|
+
fromOrderbookAmount(quote.amountIn, tokenIn.decimals),
|
|
19461
18964
|
amountOut,
|
|
19462
|
-
|
|
19463
|
-
|
|
19464
|
-
|
|
19465
|
-
|
|
19466
|
-
protocolFeeBps: args.protocolFeeBps
|
|
19467
|
-
}
|
|
19468
|
-
};
|
|
18965
|
+
quote,
|
|
18966
|
+
tokenIn,
|
|
18967
|
+
tokenOut
|
|
18968
|
+
);
|
|
19469
18969
|
}
|
|
19470
|
-
async
|
|
19471
|
-
const
|
|
19472
|
-
|
|
19473
|
-
const
|
|
19474
|
-
const
|
|
18970
|
+
async availableLiquidity(params, sourceChain, destinationChain) {
|
|
18971
|
+
const tokenIn = this.assetByAddress(sourceChain, params.tokenIn);
|
|
18972
|
+
const tokenOut = this.assetByAddress(destinationChain, params.tokenOut);
|
|
18973
|
+
const liquidity = await this.orderbook().routeLiquidity(toRoute(tokenIn, tokenOut));
|
|
18974
|
+
const [base3, quote] = liquidity.side === "BID" ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
|
|
19475
18975
|
return {
|
|
19476
|
-
|
|
19477
|
-
|
|
19478
|
-
|
|
19479
|
-
|
|
19480
|
-
|
|
19481
|
-
|
|
19482
|
-
|
|
19483
|
-
|
|
19484
|
-
|
|
19485
|
-
|
|
18976
|
+
sourceChain: tokenIn.chain,
|
|
18977
|
+
destinationChain: tokenOut.chain,
|
|
18978
|
+
tokenInSymbol: tokenIn.symbol,
|
|
18979
|
+
tokenOutSymbol: tokenOut.symbol,
|
|
18980
|
+
tokenAddress: tokenOut.address,
|
|
18981
|
+
route: liquidity.route,
|
|
18982
|
+
side: liquidity.side,
|
|
18983
|
+
baseTokenSymbol: base3.symbol,
|
|
18984
|
+
quoteTokenSymbol: quote.symbol,
|
|
18985
|
+
bestRate: formatOptional(liquidity.bestRate),
|
|
18986
|
+
availableLiquidity: format(liquidity.availableLiquidity),
|
|
18987
|
+
depthIn: format(liquidity.depthIn),
|
|
18988
|
+
depthOut: format(liquidity.depthOut),
|
|
18989
|
+
maxFillableIn: format(liquidity.maxFillableIn),
|
|
18990
|
+
orderCount: liquidity.orderCount,
|
|
18991
|
+
solverCount: liquidity.solverCount
|
|
19486
18992
|
};
|
|
19487
18993
|
}
|
|
19488
|
-
async
|
|
19489
|
-
const
|
|
19490
|
-
|
|
19491
|
-
|
|
19492
|
-
|
|
19493
|
-
|
|
19494
|
-
|
|
19495
|
-
|
|
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
|
-
]
|
|
18994
|
+
async buyAndSellRates(params) {
|
|
18995
|
+
const tokenIn = this.assetBySymbol(params.sourceChain, params.tokenInSymbol);
|
|
18996
|
+
const tokenOut = this.assetBySymbol(params.destinationChain, params.tokenOutSymbol);
|
|
18997
|
+
const { book, bid, ask } = await this.orderbook().topOfBook({
|
|
18998
|
+
tokenA: tokenIn.symbol,
|
|
18999
|
+
tokenB: tokenOut.symbol,
|
|
19000
|
+
fillChain: tokenOut.chain,
|
|
19001
|
+
sourceChain: tokenIn.chain
|
|
19524
19002
|
});
|
|
19525
|
-
const
|
|
19526
|
-
|
|
19527
|
-
|
|
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
|
-
return {
|
|
19539
|
-
currency0: viem.getAddress(poolKey.currency0),
|
|
19540
|
-
currency1: viem.getAddress(poolKey.currency1),
|
|
19541
|
-
fee: poolKey.fee,
|
|
19542
|
-
tickSpacing: poolKey.tickSpacing,
|
|
19543
|
-
hooks: viem.getAddress(poolKey.hooks)
|
|
19544
|
-
};
|
|
19545
|
-
}
|
|
19546
|
-
function sortCurrencies(tokenIn, tokenOut) {
|
|
19547
|
-
const input = viem.getAddress(tokenIn);
|
|
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) {
|
|
19003
|
+
const bidRate = bid?.rate ?? null;
|
|
19004
|
+
const askRate = ask?.rate ?? null;
|
|
19005
|
+
const mid = bidRate !== null && askRate !== null ? (bidRate + askRate) / 2n : null;
|
|
19006
|
+
const spread = bidRate !== null && askRate !== null && askRate >= bidRate ? askRate - bidRate : null;
|
|
19612
19007
|
return {
|
|
19613
|
-
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
|
|
19617
|
-
|
|
19618
|
-
|
|
19619
|
-
|
|
19620
|
-
|
|
19621
|
-
|
|
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
|
-
}
|
|
19008
|
+
baseTokenSymbol: book.base,
|
|
19009
|
+
quoteTokenSymbol: book.quote,
|
|
19010
|
+
sourceChain: tokenIn.chain,
|
|
19011
|
+
destinationChain: tokenOut.chain,
|
|
19012
|
+
bid: formatOptional(bidRate),
|
|
19013
|
+
ask: formatOptional(askRate),
|
|
19014
|
+
mid: formatOptional(mid),
|
|
19015
|
+
spread: formatOptional(spread),
|
|
19016
|
+
spreadBps: spread !== null && mid ? Number(spread * 1000000n / mid) / 100 : null
|
|
19631
19017
|
};
|
|
19632
19018
|
}
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
|
|
19638
|
-
|
|
19639
|
-
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19643
|
-
|
|
19644
|
-
|
|
19645
|
-
|
|
19646
|
-
|
|
19647
|
-
|
|
19648
|
-
|
|
19649
|
-
|
|
19650
|
-
|
|
19651
|
-
|
|
19652
|
-
|
|
19653
|
-
|
|
19654
|
-
|
|
19655
|
-
|
|
19656
|
-
|
|
19657
|
-
|
|
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}`);
|
|
19671
|
-
}
|
|
19672
|
-
function isConfiguredAddress(address) {
|
|
19673
|
-
return Boolean(address && address !== "0x" && !/^0x0{40}$/i.test(address));
|
|
19674
|
-
}
|
|
19675
|
-
var INDEXED_RATE_DECIMALS = 18;
|
|
19676
|
-
var INDEXED_RATE_SCALE = 10n ** BigInt(INDEXED_RATE_DECIMALS);
|
|
19677
|
-
var IndexedRateIntentQuoteStrategy = class {
|
|
19678
|
-
constructor(chainConfigService, getQueryClient) {
|
|
19679
|
-
this.chainConfigService = chainConfigService;
|
|
19680
|
-
this.getQueryClient = getQueryClient;
|
|
19019
|
+
/**
|
|
19020
|
+
* The orderbook only quotes an input amount, so an output is priced by
|
|
19021
|
+
* guessing the input from the best rate and raising it at each clearing
|
|
19022
|
+
* price until the quote delivers `targetOut`.
|
|
19023
|
+
*/
|
|
19024
|
+
async quoteExactOutput(route, targetOut, tokenIn) {
|
|
19025
|
+
const orderbook = this.orderbook();
|
|
19026
|
+
const liquidity = await orderbook.routeLiquidity(route);
|
|
19027
|
+
if (liquidity.bestRate === null) throw this.insufficient(route, 0n, tokenIn);
|
|
19028
|
+
const inputUnit = toOrderbookAmount(1n, tokenIn.decimals);
|
|
19029
|
+
let amountIn = roundUpTo(requiredInput(liquidity.side, targetOut, liquidity.bestRate), inputUnit);
|
|
19030
|
+
let lastAmountIn = amountIn;
|
|
19031
|
+
for (let round = 0; round < MAX_EXACT_OUTPUT_ROUNDS; round++) {
|
|
19032
|
+
if (amountIn > liquidity.maxFillableIn) throw this.insufficient(route, liquidity.maxFillableIn, tokenIn);
|
|
19033
|
+
const quote = await orderbook.quote(route, amountIn);
|
|
19034
|
+
if (quote.fillable && quote.amountOut >= targetOut) return quote;
|
|
19035
|
+
lastAmountIn = amountIn;
|
|
19036
|
+
const next = quote.rate === null ? amountIn : roundUpTo(requiredInput(quote.side, targetOut, quote.rate), inputUnit);
|
|
19037
|
+
amountIn = next > amountIn ? next : amountIn + inputUnit;
|
|
19038
|
+
}
|
|
19039
|
+
throw new OrderbookQuoteNotConvergedError(
|
|
19040
|
+
route,
|
|
19041
|
+
MAX_EXACT_OUTPUT_ROUNDS,
|
|
19042
|
+
fromOrderbookAmount(lastAmountIn, tokenIn.decimals)
|
|
19043
|
+
);
|
|
19681
19044
|
}
|
|
19682
|
-
|
|
19683
|
-
|
|
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);
|
|
19045
|
+
insufficient(route, maxFillableIn, tokenIn) {
|
|
19046
|
+
return new InsufficientOrderbookLiquidityError(route, fromOrderbookAmount(maxFillableIn, tokenIn.decimals));
|
|
19711
19047
|
}
|
|
19712
|
-
|
|
19713
|
-
const
|
|
19714
|
-
|
|
19715
|
-
|
|
19716
|
-
|
|
19717
|
-
|
|
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
|
|
19048
|
+
assetByAddress(chain, address) {
|
|
19049
|
+
const resolvedChain = resolveChain(chain);
|
|
19050
|
+
return withDecimals(
|
|
19051
|
+
resolvedChain,
|
|
19052
|
+
address,
|
|
19053
|
+
this.configService.getAssetMetadataByAddress(resolvedChain, address)
|
|
19731
19054
|
);
|
|
19732
19055
|
}
|
|
19733
|
-
|
|
19734
|
-
|
|
19735
|
-
|
|
19736
|
-
rates.sellRate,
|
|
19737
|
-
rates.sellRateUpdatedAt,
|
|
19738
|
-
rates,
|
|
19739
|
-
tokenInSymbol,
|
|
19740
|
-
tokenOutSymbol
|
|
19741
|
-
);
|
|
19056
|
+
assetBySymbol(chain, symbol) {
|
|
19057
|
+
const resolvedChain = resolveChain(chain);
|
|
19058
|
+
return withDecimals(resolvedChain, symbol, this.configService.getAssetMetadataBySymbol(resolvedChain, symbol));
|
|
19742
19059
|
}
|
|
19743
|
-
|
|
19744
|
-
|
|
19745
|
-
);
|
|
19060
|
+
};
|
|
19061
|
+
function resolveChain(chain) {
|
|
19062
|
+
const stateMachineId = getConfigByStateMachineId(chain)?.stateMachineId;
|
|
19063
|
+
if (!stateMachineId) throw new UnsupportedLiquidityChainError(chain);
|
|
19064
|
+
return stateMachineId;
|
|
19746
19065
|
}
|
|
19747
|
-
function
|
|
19748
|
-
if (!
|
|
19749
|
-
|
|
19750
|
-
|
|
19751
|
-
|
|
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`);
|
|
19066
|
+
function withDecimals(chain, asset, metadata) {
|
|
19067
|
+
if (!metadata) throw new UnsupportedLiquidityAssetError(chain, asset);
|
|
19068
|
+
const { decimals } = metadata;
|
|
19069
|
+
if (decimals === void 0 || !Number.isSafeInteger(decimals) || decimals < 0 || decimals > ORDERBOOK_DECIMALS) {
|
|
19070
|
+
throw new UnsupportedLiquidityAssetError(chain, `${metadata.symbol} (decimals are not configured)`);
|
|
19763
19071
|
}
|
|
19072
|
+
return { chain, symbol: metadata.symbol, address: metadata.address, decimals };
|
|
19073
|
+
}
|
|
19074
|
+
function validateQuoteParams(params) {
|
|
19075
|
+
const hasAmountIn = params.amountIn !== void 0;
|
|
19076
|
+
const hasAmountOut = params.amountOut !== void 0;
|
|
19077
|
+
if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
|
|
19078
|
+
if (params.amountIn !== void 0 && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
|
|
19079
|
+
if (params.amountOut !== void 0 && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
|
|
19764
19080
|
}
|
|
19765
|
-
function
|
|
19766
|
-
|
|
19767
|
-
|
|
19768
|
-
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
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);
|
|
19081
|
+
function toRoute(tokenIn, tokenOut) {
|
|
19082
|
+
return {
|
|
19083
|
+
tokenIn: tokenIn.symbol,
|
|
19084
|
+
tokenOut: tokenOut.symbol,
|
|
19085
|
+
sourceChain: tokenIn.chain,
|
|
19086
|
+
destinationChain: tokenOut.chain
|
|
19087
|
+
};
|
|
19778
19088
|
}
|
|
19779
|
-
function
|
|
19089
|
+
function requiredInput(side, amountOut, rate) {
|
|
19090
|
+
return side === "BID" ? divCeil(amountOut * ORDERBOOK_SCALE, rate) : divCeil(amountOut * rate, ORDERBOOK_SCALE);
|
|
19091
|
+
}
|
|
19092
|
+
function buildQuote(tradeType, amountIn, amountOut, quote, tokenIn, tokenOut) {
|
|
19093
|
+
if (quote.rate === null) throw new OrderbookRequestError("the orderbook served a fillable quote with no rate");
|
|
19094
|
+
const [base3, quoteToken] = quote.side === "BID" ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
|
|
19780
19095
|
return {
|
|
19781
|
-
strategy: "indexed_rates",
|
|
19782
19096
|
tradeType,
|
|
19783
19097
|
amountIn,
|
|
19784
19098
|
amountOut,
|
|
19785
19099
|
quoteMetadata: {
|
|
19786
|
-
sourceChain:
|
|
19787
|
-
destinationChain:
|
|
19788
|
-
|
|
19789
|
-
|
|
19790
|
-
|
|
19791
|
-
|
|
19792
|
-
|
|
19793
|
-
|
|
19100
|
+
sourceChain: tokenIn.chain,
|
|
19101
|
+
destinationChain: tokenOut.chain,
|
|
19102
|
+
route: quote.route,
|
|
19103
|
+
side: quote.side,
|
|
19104
|
+
baseTokenSymbol: base3.symbol,
|
|
19105
|
+
quoteTokenSymbol: quoteToken.symbol,
|
|
19106
|
+
rate: format(quote.rate),
|
|
19107
|
+
maxFillableIn: fromOrderbookAmount(quote.maxFillableIn, tokenIn.decimals),
|
|
19108
|
+
orderCount: quote.fills.length
|
|
19794
19109
|
}
|
|
19795
19110
|
};
|
|
19796
19111
|
}
|
|
19112
|
+
function toOrderbookAmount(amount, decimals) {
|
|
19113
|
+
return amount * 10n ** BigInt(ORDERBOOK_DECIMALS - decimals);
|
|
19114
|
+
}
|
|
19115
|
+
function fromOrderbookAmount(amount, decimals) {
|
|
19116
|
+
return amount / 10n ** BigInt(ORDERBOOK_DECIMALS - decimals);
|
|
19117
|
+
}
|
|
19118
|
+
function roundUpTo(amount, unit) {
|
|
19119
|
+
return divCeil(amount, unit) * unit;
|
|
19120
|
+
}
|
|
19121
|
+
function divCeil(numerator, denominator) {
|
|
19122
|
+
return (numerator + denominator - 1n) / denominator;
|
|
19123
|
+
}
|
|
19124
|
+
function format(amount) {
|
|
19125
|
+
return viem.formatUnits(amount, ORDERBOOK_DECIMALS);
|
|
19126
|
+
}
|
|
19127
|
+
function formatOptional(amount) {
|
|
19128
|
+
return amount === null ? null : format(amount);
|
|
19129
|
+
}
|
|
19797
19130
|
|
|
19798
19131
|
// src/protocols/intents/IntentGateway.ts
|
|
19799
19132
|
var ORDER_FEE_GAS_PRICE_BUMP_POLICY = {
|
|
@@ -19833,8 +19166,10 @@ var IntentGateway = class _IntentGateway {
|
|
|
19833
19166
|
bidManager;
|
|
19834
19167
|
/** Estimates gas costs for filling an order and converts them to fee-token amounts. */
|
|
19835
19168
|
gasEstimator;
|
|
19836
|
-
/**
|
|
19837
|
-
|
|
19169
|
+
/** The HyperFX orderbook quotes, liquidity and rates are read from. */
|
|
19170
|
+
orderbook;
|
|
19171
|
+
/** Prices intents, liquidity and rates from {@link orderbook}. */
|
|
19172
|
+
market;
|
|
19838
19173
|
/**
|
|
19839
19174
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
19840
19175
|
*
|
|
@@ -19878,17 +19213,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
19878
19213
|
this.bidManager = bidManager;
|
|
19879
19214
|
this.gasEstimator = gasEstimator;
|
|
19880
19215
|
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
|
-
};
|
|
19216
|
+
this.orderbook = new HyperFxOrderbook(orderbookUrlFor(dest.config.stateMachineId));
|
|
19217
|
+
this.market = new OrderbookMarket(dest.configService, () => this.orderbook);
|
|
19892
19218
|
}
|
|
19893
19219
|
/**
|
|
19894
19220
|
* Creates an initialized IntentGateway instance.
|
|
@@ -19934,89 +19260,66 @@ var IntentGateway = class _IntentGateway {
|
|
|
19934
19260
|
}
|
|
19935
19261
|
}
|
|
19936
19262
|
/**
|
|
19937
|
-
*
|
|
19263
|
+
* Points quotes, liquidity and rate reads at a HyperFX orderbook other than
|
|
19264
|
+
* the destination chain's network deployment ({@link ORDERBOOK_URLS}).
|
|
19265
|
+
* Returns `this` for chaining.
|
|
19266
|
+
*
|
|
19267
|
+
* @param orderbook - The orderbook's GraphQL URL, or a configured client.
|
|
19268
|
+
*/
|
|
19269
|
+
withOrderbook(orderbook) {
|
|
19270
|
+
this.orderbook = typeof orderbook === "string" ? new HyperFxOrderbook(orderbook) : orderbook;
|
|
19271
|
+
return this;
|
|
19272
|
+
}
|
|
19273
|
+
/**
|
|
19274
|
+
* Quotes an intent between this gateway's source and destination chains from
|
|
19275
|
+
* the HyperFX orderbook. Provide exactly one of `amountIn` or `amountOut`, in
|
|
19276
|
+
* raw token units.
|
|
19938
19277
|
*
|
|
19939
|
-
*
|
|
19940
|
-
*
|
|
19941
|
-
*
|
|
19942
|
-
*
|
|
19278
|
+
* An exact-input quote is the orderbook's clearing price for `amountIn`,
|
|
19279
|
+
* which may combine several solvers' orders. An exact-output quote finds the
|
|
19280
|
+
* smallest input whose clearing price delivers `amountOut`. A cross-chain
|
|
19281
|
+
* route only counts orders whose solvers accept the source chain.
|
|
19943
19282
|
*
|
|
19944
|
-
* The
|
|
19945
|
-
*
|
|
19946
|
-
* `amountIn`/`amountOut` already account for the gateway's protocol fee
|
|
19947
|
-
* (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order inputs.
|
|
19283
|
+
* The orderbook's rates already carry the gateway protocol fee, so the
|
|
19284
|
+
* returned amounts can be placed as the order's inputs and outputs directly.
|
|
19948
19285
|
*
|
|
19949
|
-
* @
|
|
19950
|
-
* @
|
|
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.
|
|
19286
|
+
* @throws {InsufficientOrderbookLiquidityError} When the route cannot fill the amount.
|
|
19287
|
+
* @throws {OrderbookRequestError} When the orderbook is unreachable or trades no book for the pair.
|
|
19954
19288
|
*/
|
|
19955
19289
|
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);
|
|
19290
|
+
return this.market.quoteIntent(params, this.source.config.stateMachineId, this.dest.config.stateMachineId);
|
|
19962
19291
|
}
|
|
19963
19292
|
/**
|
|
19964
|
-
* Returns
|
|
19293
|
+
* Returns the orderbook liquidity serving a swap of `tokenIn` on the source
|
|
19294
|
+
* chain for `tokenOut` on the destination chain: the best rate, true and
|
|
19295
|
+
* virtual depth, and the largest input the route can fill.
|
|
19965
19296
|
*
|
|
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}.
|
|
19297
|
+
* Amounts reflect the live book; they are not reservations or fill guarantees.
|
|
19972
19298
|
*/
|
|
19973
19299
|
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
|
|
19300
|
+
return this.market.availableLiquidity(
|
|
19301
|
+
params,
|
|
19302
|
+
this.source.config.stateMachineId,
|
|
19303
|
+
this.dest.config.stateMachineId
|
|
19983
19304
|
);
|
|
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
19305
|
}
|
|
19997
19306
|
/**
|
|
19998
|
-
* Returns
|
|
19999
|
-
* units
|
|
20000
|
-
*
|
|
19307
|
+
* Returns the orderbook's best bid and ask for a pair, with the mid and
|
|
19308
|
+
* spread, in quote-token units per one base token. Only orders filled on the
|
|
19309
|
+
* destination chain that accept swaps from the source chain are counted.
|
|
19310
|
+
* Symbols are matched case-insensitively; chain IDs resolve configured token
|
|
19311
|
+
* deployments.
|
|
20001
19312
|
*/
|
|
20002
19313
|
async queryBuyAndSellRates(params) {
|
|
20003
|
-
const { queryClient } = this.requireIndexer();
|
|
20004
19314
|
const sourceChain = chainConfigs[params.sourceChainId]?.stateMachineId;
|
|
20005
19315
|
const destinationChain = chainConfigs[params.destinationChainId]?.stateMachineId;
|
|
20006
19316
|
if (!sourceChain) throw new UnsupportedLiquidityChainError(params.sourceChainId);
|
|
20007
19317
|
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({
|
|
19318
|
+
return this.market.buyAndSellRates({
|
|
20016
19319
|
sourceChain,
|
|
20017
19320
|
destinationChain,
|
|
20018
|
-
tokenInSymbol:
|
|
20019
|
-
tokenOutSymbol:
|
|
19321
|
+
tokenInSymbol: params.tokenInSymbol,
|
|
19322
|
+
tokenOutSymbol: params.tokenOutSymbol
|
|
20020
19323
|
});
|
|
20021
19324
|
}
|
|
20022
19325
|
/**
|
|
@@ -20267,6 +19570,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
20267
19570
|
/**
|
|
20268
19571
|
* Returns both the native token cost and the relayer fee for cancelling an
|
|
20269
19572
|
* order. Use `relayerFee` to approve the ERC-20 spend before submitting.
|
|
19573
|
+
* Same-chain orders use the direct local route for either `from` option and
|
|
19574
|
+
* return `{ nativeValue: 0n, relayerFee: 0n }`.
|
|
20270
19575
|
*
|
|
20271
19576
|
* Delegates to {@link OrderCanceller.quoteCancelOrder}.
|
|
20272
19577
|
*
|
|
@@ -20290,9 +19595,17 @@ var IntentGateway = class _IntentGateway {
|
|
|
20290
19595
|
*
|
|
20291
19596
|
* Delegates to {@link OrderCanceller.cancelOrder}.
|
|
20292
19597
|
*
|
|
19598
|
+
* Same-chain orders always use the direct source-gateway route. The order
|
|
19599
|
+
* user may call through the deadline; any account may call strictly after
|
|
19600
|
+
* it, pays the transaction gas, and cannot change the refund beneficiary.
|
|
19601
|
+
* The SDK yields unsigned transaction fields and accepts either the caller's
|
|
19602
|
+
* signed raw transaction or its already-broadcast transaction hash.
|
|
19603
|
+
*
|
|
20293
19604
|
* @param order - The order to cancel.
|
|
20294
|
-
* @param indexerClient - Indexer client used for ISMP request
|
|
20295
|
-
*
|
|
19605
|
+
* @param indexerClient - Indexer client used for cross-chain ISMP request
|
|
19606
|
+
* status streaming; the same-chain route does not access it.
|
|
19607
|
+
* @param options - Choose the cross-chain initiation side. Defaults to source;
|
|
19608
|
+
* ignored for routing when source and destination are the same chain.
|
|
20296
19609
|
* @yields {@link CancelEvent} objects describing each cancellation stage.
|
|
20297
19610
|
*/
|
|
20298
19611
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
@@ -20422,7 +19735,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
20422
19735
|
if (estimate.totalGasCostWei === 0n || estimate.totalGasInFeeToken === 0n) {
|
|
20423
19736
|
throw new Error("Gas estimation failed");
|
|
20424
19737
|
}
|
|
20425
|
-
const fees = isSameChain ? estimate.totalGasInFeeToken * 2n : (estimate.totalGasInFeeToken + estimate.relayerFeeInSourceFeeToken) * 105n / 100n;
|
|
19738
|
+
const fees = isSameChain ? estimate.totalGasInFeeToken * 2n : ((estimate.totalGasInFeeToken + estimate.relayerFeeInSourceFeeToken) * 105n + 99n) / 100n;
|
|
20426
19739
|
const { address: feeToken } = await this.source.getFeeTokenWithDecimals();
|
|
20427
19740
|
return {
|
|
20428
19741
|
fees,
|
|
@@ -20455,17 +19768,27 @@ var IntentGateway = class _IntentGateway {
|
|
|
20455
19768
|
return this._crypto.decodeERC7821Execute(callData);
|
|
20456
19769
|
}
|
|
20457
19770
|
/**
|
|
20458
|
-
* Checks whether an order
|
|
19771
|
+
* Checks whether an order is finalized on the destination chain.
|
|
20459
19772
|
*
|
|
20460
19773
|
* Delegates to {@link OrderStatusChecker.isOrderFilled}.
|
|
20461
19774
|
*
|
|
20462
19775
|
* @param order - The order to check.
|
|
20463
|
-
* @returns `true`
|
|
20464
|
-
*
|
|
19776
|
+
* @returns `true` once a completing fill or a destination-side cancellation
|
|
19777
|
+
* has finalized the order; `false` while it is open or only partly filled.
|
|
20465
19778
|
*/
|
|
20466
19779
|
async isOrderFilled(order) {
|
|
20467
19780
|
return this.orderStatusChecker.isOrderFilled(order);
|
|
20468
19781
|
}
|
|
19782
|
+
/**
|
|
19783
|
+
* Output credited to the order so far, one entry per leg.
|
|
19784
|
+
*
|
|
19785
|
+
* Delegates to {@link OrderStatusChecker.getFillProgress}.
|
|
19786
|
+
*
|
|
19787
|
+
* @param order - The order to check.
|
|
19788
|
+
*/
|
|
19789
|
+
async getFillProgress(order) {
|
|
19790
|
+
return this.orderStatusChecker.getFillProgress(order);
|
|
19791
|
+
}
|
|
20469
19792
|
/**
|
|
20470
19793
|
* Checks whether all escrowed inputs for an order have been refunded on the
|
|
20471
19794
|
* source chain.
|
|
@@ -20473,8 +19796,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
20473
19796
|
* Delegates to {@link OrderStatusChecker.isOrderRefunded}.
|
|
20474
19797
|
*
|
|
20475
19798
|
* @param order - The order to check.
|
|
20476
|
-
* @returns `true` if every input
|
|
20477
|
-
* in the `_orders` mapping on the source chain.
|
|
19799
|
+
* @returns `true` if every input's escrowed amount has been zeroed out
|
|
19800
|
+
* in the per-leg `_orders` mapping on the source chain.
|
|
20478
19801
|
*/
|
|
20479
19802
|
async isOrderRefunded(order) {
|
|
20480
19803
|
return this.orderStatusChecker.isOrderRefunded(order);
|
|
@@ -20511,9 +19834,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
20511
19834
|
}
|
|
20512
19835
|
requireIndexer() {
|
|
20513
19836
|
if (!this.indexer) {
|
|
20514
|
-
throw new Error(
|
|
20515
|
-
"IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods or Phantom quotes"
|
|
20516
|
-
);
|
|
19837
|
+
throw new Error("IntentGateway: call withQueryClient(queryClient) before using indexer-backed methods");
|
|
20517
19838
|
}
|
|
20518
19839
|
return this.indexer;
|
|
20519
19840
|
}
|
|
@@ -20536,74 +19857,64 @@ var IntentGateway = class _IntentGateway {
|
|
|
20536
19857
|
const { queryClient, pollInterval, logger } = this.requireIndexer();
|
|
20537
19858
|
const streamLogger = logger.withTag("[orderStatusStream]");
|
|
20538
19859
|
const TERMINAL = ["FILLED", "REDEEMED", "REFUNDED"];
|
|
19860
|
+
const latestOrderStatus = (order2) => {
|
|
19861
|
+
const latest = order2.statuses[order2.statuses.length - 1];
|
|
19862
|
+
if (latest.status === "CANCELLED") {
|
|
19863
|
+
for (let i = order2.statuses.length - 1; i >= 0; i--) {
|
|
19864
|
+
if (TERMINAL.includes(order2.statuses[i].status)) return order2.statuses[i];
|
|
19865
|
+
}
|
|
19866
|
+
}
|
|
19867
|
+
return latest;
|
|
19868
|
+
};
|
|
20539
19869
|
let order;
|
|
20540
19870
|
while (!order) {
|
|
20541
19871
|
await sleep(pollInterval);
|
|
20542
19872
|
order = await _queryOrderInternal({ commitmentHash: commitment, queryClient, logger });
|
|
20543
19873
|
}
|
|
20544
19874
|
streamLogger.trace("`Order` found");
|
|
20545
|
-
|
|
19875
|
+
let latestStatus = latestOrderStatus(order);
|
|
20546
19876
|
yield { status: latestStatus.status, metadata: latestStatus.metadata };
|
|
20547
19877
|
if (TERMINAL.includes(latestStatus.status)) return;
|
|
20548
19878
|
while (true) {
|
|
20549
19879
|
await sleep(pollInterval);
|
|
20550
19880
|
const updatedOrder = await _queryOrderInternal({ commitmentHash: commitment, queryClient, logger });
|
|
20551
19881
|
if (!updatedOrder) continue;
|
|
20552
|
-
const newLatestStatus = updatedOrder
|
|
19882
|
+
const newLatestStatus = latestOrderStatus(updatedOrder);
|
|
20553
19883
|
if (newLatestStatus.status !== latestStatus.status) {
|
|
19884
|
+
latestStatus = newLatestStatus;
|
|
20554
19885
|
yield { status: newLatestStatus.status, metadata: newLatestStatus.metadata };
|
|
20555
19886
|
if (TERMINAL.includes(newLatestStatus.status)) return;
|
|
20556
19887
|
}
|
|
20557
19888
|
}
|
|
20558
19889
|
}
|
|
20559
19890
|
};
|
|
20560
|
-
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
|
|
20564
|
-
}
|
|
20565
|
-
return f;
|
|
19891
|
+
|
|
19892
|
+
// src/protocols/intents/liquidity-pool.ts
|
|
19893
|
+
function sortPoolSymbols(symbolA, symbolB) {
|
|
19894
|
+
return symbolA.toLowerCase() <= symbolB.toLowerCase() ? [symbolA, symbolB] : [symbolB, symbolA];
|
|
20566
19895
|
}
|
|
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);
|
|
19896
|
+
function poolSlug(symbolA, symbolB) {
|
|
19897
|
+
return sortPoolSymbols(symbolA, symbolB).join("-");
|
|
19898
|
+
}
|
|
19899
|
+
|
|
19900
|
+
// src/protocols/intents/rateFill.ts
|
|
19901
|
+
function ceilDiv(numerator, denominator) {
|
|
19902
|
+
return numerator === 0n ? 0n : (numerator - 1n) / denominator + 1n;
|
|
19903
|
+
}
|
|
19904
|
+
function previewRateFill(escrow, required, filled, take, offered) {
|
|
19905
|
+
if (escrow <= 0n || required <= 0n || take <= 0n || offered <= 0n) {
|
|
19906
|
+
throw new Error("RateFillInvalidAmount");
|
|
19907
|
+
}
|
|
19908
|
+
if (filled < 0n || filled >= required) throw new Error("RateFillNoProgress");
|
|
19909
|
+
if (ceilDiv(take * required, escrow) > offered) throw new Error("RateBelowOrder");
|
|
19910
|
+
const uncappedCredit = take * required / escrow;
|
|
19911
|
+
const credit = uncappedCredit < required - filled ? uncappedCredit : required - filled;
|
|
19912
|
+
const release = escrow * (filled + credit) / required - escrow * filled / required;
|
|
19913
|
+
if (credit === 0n || release === 0n) throw new Error("RateFillNoProgress");
|
|
19914
|
+
const ratePayment = ceilDiv(offered * release, take);
|
|
19915
|
+
const delivered = ratePayment > credit ? ratePayment : credit;
|
|
19916
|
+
return { credit, release, delivered, surplus: delivered - credit };
|
|
20605
19917
|
}
|
|
20606
|
-
var FILL_ORDER_ABI = IntentGatewayV2_default.ABI;
|
|
20607
19918
|
var DECLARATION_V1 = 1;
|
|
20608
19919
|
var DECLARATION_V2 = 2;
|
|
20609
19920
|
var PAYMASTER_ADDRESS_BYTES = 20;
|
|
@@ -20801,40 +20112,6 @@ function encodeAcceptedSourceChains(chains2) {
|
|
|
20801
20112
|
function decodeAcceptedSourceChains(paymasterAndData) {
|
|
20802
20113
|
return decodePhantomBidDeclaration(paymasterAndData).acceptedSources;
|
|
20803
20114
|
}
|
|
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
20115
|
var TokenGateway = class {
|
|
20839
20116
|
source;
|
|
20840
20117
|
dest;
|
|
@@ -25050,9 +24327,9 @@ async function teleport(teleport_param) {
|
|
|
25050
24327
|
if (scaleEncodedAssetId === null) {
|
|
25051
24328
|
throw new Error("Unknown asset id provided");
|
|
25052
24329
|
}
|
|
25053
|
-
const
|
|
25054
|
-
const destination = convertStateMachineIdToEnum(
|
|
25055
|
-
const recipient = viem.hexToBytes(normalizeAddressForStateMachine(params.recipient,
|
|
24330
|
+
const destinationStateMachine2 = normalizeStateMachineId(params.destination);
|
|
24331
|
+
const destination = convertStateMachineIdToEnum(destinationStateMachine2);
|
|
24332
|
+
const recipient = viem.hexToBytes(normalizeAddressForStateMachine(params.recipient, destinationStateMachine2));
|
|
25056
24333
|
const teleportParams = {
|
|
25057
24334
|
destination,
|
|
25058
24335
|
recepient: Array.from(recipient),
|
|
@@ -25307,7 +24584,7 @@ async function teleportDot(param_) {
|
|
|
25307
24584
|
|
|
25308
24585
|
exports.ADDRESS_ZERO = ADDRESS_ZERO2;
|
|
25309
24586
|
exports.BundlerMethod = BundlerMethod;
|
|
25310
|
-
exports.
|
|
24587
|
+
exports.CONTRACT_VERSION_ABI = CONTRACT_VERSION_ABI;
|
|
25311
24588
|
exports.ChainConfigService = ChainConfigService;
|
|
25312
24589
|
exports.Chains = Chains;
|
|
25313
24590
|
exports.CryptoUtils = CryptoUtils;
|
|
@@ -25320,29 +24597,31 @@ exports.ERC7821_BATCH_MODE = ERC7821_BATCH_MODE;
|
|
|
25320
24597
|
exports.EvmChain = EvmChain;
|
|
25321
24598
|
exports.EvmHostABI = ABI;
|
|
25322
24599
|
exports.EvmLanguage = EvmLanguage;
|
|
25323
|
-
exports.
|
|
24600
|
+
exports.FILL_ORDER_SELECTOR = FILL_ORDER_SELECTOR;
|
|
25324
24601
|
exports.HyperClientStatus = HyperClientStatus;
|
|
25325
24602
|
exports.HyperFungibleToken = HyperFungibleToken;
|
|
25326
24603
|
exports.HyperFungibleTokenABI = HyperFungibleTokenABI;
|
|
24604
|
+
exports.HyperFxOrderbook = HyperFxOrderbook;
|
|
25327
24605
|
exports.INCLUSION_TIMEOUT_MS = INCLUSION_TIMEOUT_MS;
|
|
25328
|
-
exports.
|
|
24606
|
+
exports.InsufficientOrderbookLiquidityError = InsufficientOrderbookLiquidityError;
|
|
25329
24607
|
exports.IntentGateway = IntentGateway;
|
|
25330
24608
|
exports.IntentGatewayABI = ABI3;
|
|
25331
24609
|
exports.IntentOrderStatus = IntentOrderStatus;
|
|
25332
24610
|
exports.IntentsCoprocessor = IntentsCoprocessor;
|
|
25333
|
-
exports.InvalidIndexedRateError = InvalidIndexedRateError;
|
|
25334
|
-
exports.InvalidLiquidityIndexerResponseError = InvalidLiquidityIndexerResponseError;
|
|
25335
|
-
exports.InvalidPhantomSnapshotError = InvalidPhantomSnapshotError;
|
|
25336
24611
|
exports.IsmpClient = IsmpClient;
|
|
25337
|
-
exports.
|
|
24612
|
+
exports.MAX_DECLARED_ENTRIES = MAX_DECLARED_ENTRIES;
|
|
25338
24613
|
exports.MOCK_ADDRESS = MOCK_ADDRESS;
|
|
24614
|
+
exports.ORDERBOOK_DECIMALS = ORDERBOOK_DECIMALS;
|
|
24615
|
+
exports.ORDERBOOK_QUERIES = ORDERBOOK_QUERIES;
|
|
24616
|
+
exports.ORDERBOOK_URLS = ORDERBOOK_URLS;
|
|
25339
24617
|
exports.ORDER_V2_PARAM_TYPE = ORDER_V2_PARAM_TYPE;
|
|
25340
24618
|
exports.OrderStatus = OrderStatus;
|
|
25341
24619
|
exports.OrderStatusChecker = OrderStatusChecker;
|
|
24620
|
+
exports.OrderbookQuoteNotConvergedError = OrderbookQuoteNotConvergedError;
|
|
24621
|
+
exports.OrderbookRequestError = OrderbookRequestError;
|
|
25342
24622
|
exports.PACKED_USEROP_TYPEHASH = PACKED_USEROP_TYPEHASH;
|
|
25343
24623
|
exports.PERMIT2_SPONSORSHIP_BYTES = PERMIT2_SPONSORSHIP_BYTES;
|
|
25344
24624
|
exports.PLACE_ORDER_SELECTOR = PLACE_ORDER_SELECTOR;
|
|
25345
|
-
exports.PhantomSnapshotUnavailableError = PhantomSnapshotUnavailableError;
|
|
25346
24625
|
exports.PharosChain = PharosChain;
|
|
25347
24626
|
exports.PolkadotHubChain = PolkadotHubChain;
|
|
25348
24627
|
exports.REQUEST_COMMITMENTS_SLOT = REQUEST_COMMITMENTS_SLOT;
|
|
@@ -25353,6 +24632,7 @@ exports.RequestKind = RequestKind;
|
|
|
25353
24632
|
exports.RequestStatus = RequestStatus;
|
|
25354
24633
|
exports.SELECT_SOLVER_TYPEHASH = SELECT_SOLVER_TYPEHASH;
|
|
25355
24634
|
exports.STATE_COMMITMENTS_SLOT = STATE_COMMITMENTS_SLOT;
|
|
24635
|
+
exports.SUPPORTED_INTENTS_VERSION = SUPPORTED_INTENTS_VERSION;
|
|
25356
24636
|
exports.SubstrateChain = SubstrateChain;
|
|
25357
24637
|
exports.Swap = Swap;
|
|
25358
24638
|
exports.TESTNET_CHAINS = TESTNET_CHAINS;
|
|
@@ -25360,17 +24640,13 @@ exports.TeleportStatus = TeleportStatus;
|
|
|
25360
24640
|
exports.TimeoutStatus = TimeoutStatus;
|
|
25361
24641
|
exports.TokenGateway = TokenGateway;
|
|
25362
24642
|
exports.TronChain = TronChain;
|
|
25363
|
-
exports.UNISWAP_QUOTE_HAIRCUT_BPS = UNISWAP_QUOTE_HAIRCUT_BPS;
|
|
25364
24643
|
exports.USE_ETHERSCAN_CHAINS = USE_ETHERSCAN_CHAINS;
|
|
25365
|
-
exports.UnsupportedIntentQuotePairError = UnsupportedIntentQuotePairError;
|
|
25366
|
-
exports.UnsupportedIntentQuoteStrategyError = UnsupportedIntentQuoteStrategyError;
|
|
25367
24644
|
exports.UnsupportedLiquidityAssetError = UnsupportedLiquidityAssetError;
|
|
25368
24645
|
exports.UnsupportedLiquidityChainError = UnsupportedLiquidityChainError;
|
|
25369
24646
|
exports.WrappedHyperFungibleTokenABI = WrappedHyperFungibleTokenABI;
|
|
25370
24647
|
exports.__test = __test;
|
|
25371
24648
|
exports.adjustDecimals = adjustDecimals;
|
|
25372
|
-
exports.
|
|
25373
|
-
exports.applyUniswapQuoteHaircut = applyUniswapQuoteHaircut;
|
|
24649
|
+
exports.assertGatewayRelease = assertGatewayRelease;
|
|
25374
24650
|
exports.bytes20ToBytes32 = bytes20ToBytes32;
|
|
25375
24651
|
exports.bytes32ToBytes20 = bytes32ToBytes20;
|
|
25376
24652
|
exports.calculateAllowanceMappingLocation = calculateAllowanceMappingLocation;
|
|
@@ -25411,7 +24687,6 @@ exports.getChainId = getChainId;
|
|
|
25411
24687
|
exports.getConfigByStateMachineId = getConfigByStateMachineId;
|
|
25412
24688
|
exports.getContractCallInput = getContractCallInput;
|
|
25413
24689
|
exports.getContractCallInputs = getContractCallInputs;
|
|
25414
|
-
exports.getFillOptionsVersion = getFillOptionsVersion;
|
|
25415
24690
|
exports.getGasPriceFromEtherscan = getGasPriceFromEtherscan;
|
|
25416
24691
|
exports.getOrFetchStorageSlot = getOrFetchStorageSlot;
|
|
25417
24692
|
exports.getOrderPlacedFromTx = getOrderPlacedFromTx;
|
|
@@ -25424,6 +24699,7 @@ exports.getStorageSlot = getStorageSlot;
|
|
|
25424
24699
|
exports.getViemChain = getViemChain;
|
|
25425
24700
|
exports.hexToString = hexToString;
|
|
25426
24701
|
exports.hyperbridgeAddress = hyperbridgeAddress;
|
|
24702
|
+
exports.isCanonicalEvmToken = isCanonicalEvmToken;
|
|
25427
24703
|
exports.maxBigInt = maxBigInt;
|
|
25428
24704
|
exports.normalizeAddressForEvmBytes32 = normalizeAddressForEvmBytes32;
|
|
25429
24705
|
exports.normalizeAddressForStateMachine = normalizeAddressForStateMachine;
|
|
@@ -25431,6 +24707,7 @@ exports.normalizeEvmAddress = normalizeEvmAddress;
|
|
|
25431
24707
|
exports.normalizeEvmChainId = normalizeEvmChainId;
|
|
25432
24708
|
exports.normalizeStateMachineId = normalizeStateMachineId;
|
|
25433
24709
|
exports.orderCommitment = orderCommitment;
|
|
24710
|
+
exports.orderbookUrlFor = orderbookUrlFor;
|
|
25434
24711
|
exports.parseStateMachineId = parseStateMachineId;
|
|
25435
24712
|
exports.pharosAtlantic = pharosAtlantic;
|
|
25436
24713
|
exports.pharosMainnet = pharosMainnet;
|
|
@@ -25438,16 +24715,18 @@ exports.polkadotAssetHubPaseo = polkadotAssetHubPaseo;
|
|
|
25438
24715
|
exports.polkadotHubMainnet = polkadotHubMainnet;
|
|
25439
24716
|
exports.poolSlug = poolSlug;
|
|
25440
24717
|
exports.postRequestCommitment = postRequestCommitment;
|
|
24718
|
+
exports.previewRateFill = previewRateFill;
|
|
25441
24719
|
exports.queryAssetTeleported = queryAssetTeleported;
|
|
25442
24720
|
exports.queryGetRequest = queryGetRequest;
|
|
25443
24721
|
exports.queryPostRequest = queryPostRequest;
|
|
25444
24722
|
exports.quoteUniswap = quoteUniswap;
|
|
25445
|
-
exports.
|
|
24723
|
+
exports.readLegEscrow = readLegEscrow;
|
|
24724
|
+
exports.readLegPartialFill = readLegPartialFill;
|
|
25446
24725
|
exports.requestCommitmentKey = requestCommitmentKey;
|
|
25447
|
-
exports.resetFillOptionsVersionCache = resetFillOptionsVersionCache;
|
|
25448
24726
|
exports.responseCommitmentKey = responseCommitmentKey;
|
|
25449
24727
|
exports.retryPromise = retryPromise;
|
|
25450
24728
|
exports.sortPoolSymbols = sortPoolSymbols;
|
|
24729
|
+
exports.supportsRateFills = supportsRateFills;
|
|
25451
24730
|
exports.teleport = teleport;
|
|
25452
24731
|
exports.teleportDot = teleportDot;
|
|
25453
24732
|
exports.transformOrderForContract = transformOrderForContract;
|