@hyperbridge/sdk 2.2.0 → 2.2.2
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 +4383 -4121
- package/dist/browser/index.js +1062 -522
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +1062 -520
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +4383 -4121
- package/dist/node/index.d.ts +4383 -4121
- package/dist/node/index.js +1062 -522
- package/dist/node/index.js.map +1 -1
- package/package.json +1 -1
package/dist/node/index.cjs
CHANGED
|
@@ -2579,7 +2579,7 @@ var chainConfigs = {
|
|
|
2579
2579
|
USDT: { balanceSlot: 151, allowanceSlot: 152 }
|
|
2580
2580
|
},
|
|
2581
2581
|
addresses: {
|
|
2582
|
-
IntentGateway: "
|
|
2582
|
+
IntentGateway: "0xE13fB34CAe12505ae51BaC8C405AF8EB27AC8058",
|
|
2583
2583
|
TokenGateway: "0xFcDa26cA021d5535C3059547390E6cCd8De7acA6",
|
|
2584
2584
|
Host: "0xEB944071A9Bf22810757C5BcFf7a2aE9663a311D",
|
|
2585
2585
|
UniswapRouter02: "0x9639379819420704457B07A0C33B678D9E0F8Df0",
|
|
@@ -2589,7 +2589,7 @@ var chainConfigs = {
|
|
|
2589
2589
|
UniswapV3Quoter: "0x0000000000000000000000000000000000000000",
|
|
2590
2590
|
UniswapV4Quoter: "0x0000000000000000000000000000000000000000",
|
|
2591
2591
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2592
|
-
SolverAccount: "
|
|
2592
|
+
SolverAccount: "0x0b5cfBc16ef60AD6930ba5A90Bb09475B7BF3815"
|
|
2593
2593
|
},
|
|
2594
2594
|
rpcEnvKey: "BSC_CHAPEL",
|
|
2595
2595
|
defaultRpcUrl: "https://bnb-testnet.api.onfinality.io/public",
|
|
@@ -2696,8 +2696,8 @@ var chainConfigs = {
|
|
|
2696
2696
|
DAI: { balanceSlot: 0, allowanceSlot: 0 }
|
|
2697
2697
|
},
|
|
2698
2698
|
addresses: {
|
|
2699
|
-
IntentGateway: "
|
|
2700
|
-
SolverAccount: "
|
|
2699
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2700
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
2701
2701
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2702
2702
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2703
2703
|
UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
|
|
@@ -2751,8 +2751,8 @@ var chainConfigs = {
|
|
|
2751
2751
|
DAI: { balanceSlot: 0, allowanceSlot: 0 }
|
|
2752
2752
|
},
|
|
2753
2753
|
addresses: {
|
|
2754
|
-
IntentGateway: "
|
|
2755
|
-
SolverAccount: "
|
|
2754
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2755
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
2756
2756
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2757
2757
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2758
2758
|
UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
|
|
@@ -2807,8 +2807,8 @@ var chainConfigs = {
|
|
|
2807
2807
|
DAI: { balanceSlot: 0, allowanceSlot: 0 }
|
|
2808
2808
|
},
|
|
2809
2809
|
addresses: {
|
|
2810
|
-
IntentGateway: "
|
|
2811
|
-
SolverAccount: "
|
|
2810
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2811
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
2812
2812
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2813
2813
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2814
2814
|
UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
|
|
@@ -2864,8 +2864,8 @@ var chainConfigs = {
|
|
|
2864
2864
|
DAI: { balanceSlot: 0, allowanceSlot: 0 }
|
|
2865
2865
|
},
|
|
2866
2866
|
addresses: {
|
|
2867
|
-
IntentGateway: "
|
|
2868
|
-
SolverAccount: "
|
|
2867
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2868
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
2869
2869
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
2870
2870
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2871
2871
|
UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
|
|
@@ -2889,6 +2889,7 @@ var chainConfigs = {
|
|
|
2889
2889
|
consensusStateId: "ETH0",
|
|
2890
2890
|
coingeckoId: "base",
|
|
2891
2891
|
layerZeroEid: 30184,
|
|
2892
|
+
uniswapV4Pools: [{ tokens: ["USDC", "cNGN"], fee: 1500, tickSpacing: 30 }],
|
|
2892
2893
|
popularTokens: [
|
|
2893
2894
|
"0x4200000000000000000000000000000000000006",
|
|
2894
2895
|
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
@@ -2922,8 +2923,8 @@ var chainConfigs = {
|
|
|
2922
2923
|
DAI: { balanceSlot: 0, allowanceSlot: 0 }
|
|
2923
2924
|
},
|
|
2924
2925
|
addresses: {
|
|
2925
|
-
IntentGateway: "
|
|
2926
|
-
SolverAccount: "
|
|
2926
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
2927
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
2927
2928
|
TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
|
|
2928
2929
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
2929
2930
|
UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
|
|
@@ -2993,7 +2994,7 @@ var chainConfigs = {
|
|
|
2993
2994
|
//wmatic, change it to wpol
|
|
2994
2995
|
DAI: "0x0000000000000000000000000000000000000000",
|
|
2995
2996
|
USDC: "0x693b854d6965ffeaae21c74049dea644b56fcacb",
|
|
2996
|
-
USDT: "
|
|
2997
|
+
USDT: "0x0000000000000000000000000000000000000000"
|
|
2997
2998
|
},
|
|
2998
2999
|
tokenDecimals: {
|
|
2999
3000
|
USDC: 18,
|
|
@@ -3004,13 +3005,13 @@ var chainConfigs = {
|
|
|
3004
3005
|
USDC: { balanceSlot: 1, allowanceSlot: 2 }
|
|
3005
3006
|
},
|
|
3006
3007
|
addresses: {
|
|
3007
|
-
IntentGateway: "
|
|
3008
|
+
IntentGateway: "0xE13fB34CAe12505ae51BaC8C405AF8EB27AC8058",
|
|
3008
3009
|
TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
|
|
3009
3010
|
Host: "0xEB944071A9Bf22810757C5BcFf7a2aE9663a311D",
|
|
3010
3011
|
Calldispatcher: "0x876F1891982E260026630c233A4897160A281Fb8",
|
|
3011
3012
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
3012
3013
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
3013
|
-
SolverAccount: "
|
|
3014
|
+
SolverAccount: "0x0b5cfBc16ef60AD6930ba5A90Bb09475B7BF3815"
|
|
3014
3015
|
},
|
|
3015
3016
|
rpcEnvKey: "POLYGON_AMOY",
|
|
3016
3017
|
defaultRpcUrl: "https://rpc-amoy.polygon.technology",
|
|
@@ -3033,8 +3034,8 @@ var chainConfigs = {
|
|
|
3033
3034
|
USDT: 6
|
|
3034
3035
|
},
|
|
3035
3036
|
addresses: {
|
|
3036
|
-
IntentGateway: "
|
|
3037
|
-
SolverAccount: "
|
|
3037
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3038
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
3038
3039
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
3039
3040
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3040
3041
|
UniswapRouter02: "0x4A7b5Da61326A6379179b40d00F57E5bbDC962c2",
|
|
@@ -3068,8 +3069,8 @@ var chainConfigs = {
|
|
|
3068
3069
|
USDT: 6
|
|
3069
3070
|
},
|
|
3070
3071
|
addresses: {
|
|
3071
|
-
IntentGateway: "
|
|
3072
|
-
SolverAccount: "
|
|
3072
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3073
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
3073
3074
|
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
|
|
3074
3075
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3075
3076
|
UniswapRouter02: "0xB2e26652e4BAd1e56055A051f922E06760cA0BFE",
|
|
@@ -3223,8 +3224,8 @@ var chainConfigs = {
|
|
|
3223
3224
|
USDT: 6
|
|
3224
3225
|
},
|
|
3225
3226
|
addresses: {
|
|
3226
|
-
IntentGateway: "
|
|
3227
|
-
SolverAccount: "
|
|
3227
|
+
IntentGateway: "0xAe041F7B0CB581876832830baeB6a2Aa2a3C9716",
|
|
3228
|
+
SolverAccount: "0x975e80B476cB1d4Cd06c292ce36898f2bE4159ea",
|
|
3228
3229
|
Host: "0x620128E2B19193d6Bd244a3AC8D3bBa0541B19c3",
|
|
3229
3230
|
Calldispatcher: "0xE2C7e576E26E0bE7aC97c6fE925bcDAbD87c4bEd"
|
|
3230
3231
|
},
|
|
@@ -5102,6 +5103,9 @@ var ChainConfigService = class {
|
|
|
5102
5103
|
getDaiAsset(chain) {
|
|
5103
5104
|
return this.getConfig(chain)?.assets?.DAI ?? "0x";
|
|
5104
5105
|
}
|
|
5106
|
+
getAssetAddress(chain, symbol) {
|
|
5107
|
+
return this.getConfig(chain)?.assets?.[symbol];
|
|
5108
|
+
}
|
|
5105
5109
|
getUsdtAsset(chain) {
|
|
5106
5110
|
return this.getConfig(chain)?.assets?.USDT ?? "0x";
|
|
5107
5111
|
}
|
|
@@ -5170,6 +5174,9 @@ var ChainConfigService = class {
|
|
|
5170
5174
|
getUniswapV4StateViewAddress(chain) {
|
|
5171
5175
|
return this.getConfig(chain)?.addresses.UniswapV4StateView ?? "0x";
|
|
5172
5176
|
}
|
|
5177
|
+
getUniswapV4PoolConfigs(chain) {
|
|
5178
|
+
return this.getConfig(chain)?.uniswapV4Pools ?? [];
|
|
5179
|
+
}
|
|
5173
5180
|
getPermit2Address(chain) {
|
|
5174
5181
|
return this.getConfig(chain)?.addresses.Permit2 ?? "0x";
|
|
5175
5182
|
}
|
|
@@ -5180,7 +5187,7 @@ var ChainConfigService = class {
|
|
|
5180
5187
|
return this.getConfig(chain)?.coingeckoId;
|
|
5181
5188
|
}
|
|
5182
5189
|
getEtherscanApiKey() {
|
|
5183
|
-
return typeof process !== "undefined" ? process
|
|
5190
|
+
return typeof process !== "undefined" ? process.env?.ETHERSCAN_API_KEY : void 0;
|
|
5184
5191
|
}
|
|
5185
5192
|
getCalldispatcherAddress(chain) {
|
|
5186
5193
|
return this.getConfig(chain)?.addresses.Calldispatcher ?? "0x";
|
|
@@ -9549,7 +9556,28 @@ function adjustDecimals(feeInFeeToken, fromDecimals, toDecimals) {
|
|
|
9549
9556
|
}
|
|
9550
9557
|
}
|
|
9551
9558
|
var USE_ETHERSCAN_CHAINS = /* @__PURE__ */ new Set(["EVM-137", "EVM-56", "EVM-1"]);
|
|
9552
|
-
var TESTNET_CHAINS = /* @__PURE__ */ new Set([
|
|
9559
|
+
var TESTNET_CHAINS = /* @__PURE__ */ new Set([
|
|
9560
|
+
"EVM-97",
|
|
9561
|
+
// BSC Chapel
|
|
9562
|
+
"EVM-10200",
|
|
9563
|
+
// Gnosis Chiado
|
|
9564
|
+
"EVM-11155111",
|
|
9565
|
+
// Sepolia
|
|
9566
|
+
"EVM-421614",
|
|
9567
|
+
// Arbitrum Sepolia
|
|
9568
|
+
"EVM-84532",
|
|
9569
|
+
// Base Sepolia
|
|
9570
|
+
"EVM-11155420",
|
|
9571
|
+
// Optimism Sepolia
|
|
9572
|
+
"EVM-80002",
|
|
9573
|
+
// Polygon Amoy
|
|
9574
|
+
"EVM-420420417",
|
|
9575
|
+
// Polkadot Asset Hub Paseo
|
|
9576
|
+
"EVM-3448148188",
|
|
9577
|
+
// Tron Nile
|
|
9578
|
+
"EVM-688689"
|
|
9579
|
+
// Pharos Atlantic
|
|
9580
|
+
]);
|
|
9553
9581
|
function collectCallInputsByAddress(call, targetContractAddress, acc) {
|
|
9554
9582
|
const normalizedTarget = targetContractAddress.toLowerCase();
|
|
9555
9583
|
if (call.calls && Array.isArray(call.calls)) {
|
|
@@ -9864,6 +9892,48 @@ var GetRequestClient = class {
|
|
|
9864
9892
|
async buildFinalized(request, hyperbridgeDelivered, response) {
|
|
9865
9893
|
const sourceChain = this.ctx.config.source;
|
|
9866
9894
|
const hyperbridge = this.ctx.config.hyperbridge;
|
|
9895
|
+
const { config } = hyperbridge;
|
|
9896
|
+
const finality = await this.queries.queryStateMachineUpdateByHeight({
|
|
9897
|
+
statemachineId: config.stateMachineId,
|
|
9898
|
+
height: hyperbridgeDelivered.metadata.blockNumber,
|
|
9899
|
+
chain: config.stateMachineId
|
|
9900
|
+
});
|
|
9901
|
+
if (finality) {
|
|
9902
|
+
const proof = await hyperbridge.queryProof(
|
|
9903
|
+
{ Responses: [response.commitment] },
|
|
9904
|
+
request.source,
|
|
9905
|
+
BigInt(finality.height)
|
|
9906
|
+
);
|
|
9907
|
+
const calldata = sourceChain.encode({
|
|
9908
|
+
kind: "GetResponse",
|
|
9909
|
+
proof: {
|
|
9910
|
+
stateMachine: config.stateMachineId,
|
|
9911
|
+
consensusStateId: config.consensusStateId,
|
|
9912
|
+
proof,
|
|
9913
|
+
height: BigInt(finality.height)
|
|
9914
|
+
},
|
|
9915
|
+
responses: [
|
|
9916
|
+
{
|
|
9917
|
+
get: request,
|
|
9918
|
+
values: request.keys.map((key, index) => ({
|
|
9919
|
+
key,
|
|
9920
|
+
value: response.values[index] || "0x"
|
|
9921
|
+
}))
|
|
9922
|
+
}
|
|
9923
|
+
],
|
|
9924
|
+
signer: viem.pad("0x")
|
|
9925
|
+
});
|
|
9926
|
+
return {
|
|
9927
|
+
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
9928
|
+
metadata: {
|
|
9929
|
+
blockHash: finality.blockHash,
|
|
9930
|
+
blockNumber: finality.height,
|
|
9931
|
+
transactionHash: finality.transactionHash,
|
|
9932
|
+
timestamp: finality.timestamp,
|
|
9933
|
+
calldata
|
|
9934
|
+
}
|
|
9935
|
+
};
|
|
9936
|
+
}
|
|
9867
9937
|
if (sourceChain instanceof EvmChain) {
|
|
9868
9938
|
const hyperbridgeSubstrate = hyperbridge;
|
|
9869
9939
|
const currentEpoch = await sourceChain.currentEpoch();
|
|
@@ -9872,18 +9942,18 @@ var GetRequestClient = class {
|
|
|
9872
9942
|
currentEpoch
|
|
9873
9943
|
);
|
|
9874
9944
|
if (!consensusResult) return void 0;
|
|
9875
|
-
const
|
|
9945
|
+
const proof = await hyperbridge.queryProof(
|
|
9876
9946
|
{ Responses: [response.commitment] },
|
|
9877
9947
|
request.source,
|
|
9878
9948
|
consensusResult.provenHeight
|
|
9879
9949
|
);
|
|
9880
|
-
const
|
|
9950
|
+
const calldata = sourceChain.encode({
|
|
9881
9951
|
kind: "BatchConsensusAndGetResponse",
|
|
9882
9952
|
consensusProofs: consensusResult.proofs,
|
|
9883
9953
|
proof: {
|
|
9884
|
-
stateMachine:
|
|
9885
|
-
consensusStateId:
|
|
9886
|
-
proof
|
|
9954
|
+
stateMachine: config.stateMachineId,
|
|
9955
|
+
consensusStateId: config.consensusStateId,
|
|
9956
|
+
proof,
|
|
9887
9957
|
height: consensusResult.provenHeight
|
|
9888
9958
|
},
|
|
9889
9959
|
responses: [
|
|
@@ -9905,50 +9975,11 @@ var GetRequestClient = class {
|
|
|
9905
9975
|
transactionHash: hyperbridgeDelivered.metadata.transactionHash,
|
|
9906
9976
|
// @ts-ignore
|
|
9907
9977
|
timestamp: hyperbridgeDelivered.metadata.timestamp,
|
|
9908
|
-
calldata
|
|
9978
|
+
calldata
|
|
9909
9979
|
}
|
|
9910
9980
|
};
|
|
9911
9981
|
}
|
|
9912
|
-
|
|
9913
|
-
statemachineId: this.ctx.config.hyperbridge.config.stateMachineId,
|
|
9914
|
-
height: hyperbridgeDelivered.metadata.blockNumber,
|
|
9915
|
-
chain: request.source
|
|
9916
|
-
});
|
|
9917
|
-
if (!hyperbridgeFinality) return void 0;
|
|
9918
|
-
const proof = await hyperbridge.queryProof(
|
|
9919
|
-
{ Responses: [response.commitment] },
|
|
9920
|
-
request.source,
|
|
9921
|
-
BigInt(hyperbridgeFinality.height)
|
|
9922
|
-
);
|
|
9923
|
-
const calldata = sourceChain.encode({
|
|
9924
|
-
kind: "GetResponse",
|
|
9925
|
-
proof: {
|
|
9926
|
-
stateMachine: this.ctx.config.hyperbridge.config.stateMachineId,
|
|
9927
|
-
consensusStateId: this.ctx.config.hyperbridge.config.consensusStateId,
|
|
9928
|
-
proof,
|
|
9929
|
-
height: BigInt(hyperbridgeFinality.height)
|
|
9930
|
-
},
|
|
9931
|
-
responses: [
|
|
9932
|
-
{
|
|
9933
|
-
get: request,
|
|
9934
|
-
values: request.keys.map((key, index) => ({
|
|
9935
|
-
key,
|
|
9936
|
-
value: response.values[index] || "0x"
|
|
9937
|
-
}))
|
|
9938
|
-
}
|
|
9939
|
-
],
|
|
9940
|
-
signer: viem.pad("0x")
|
|
9941
|
-
});
|
|
9942
|
-
return {
|
|
9943
|
-
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
9944
|
-
metadata: {
|
|
9945
|
-
blockHash: hyperbridgeFinality.blockHash,
|
|
9946
|
-
blockNumber: hyperbridgeFinality.height,
|
|
9947
|
-
transactionHash: hyperbridgeFinality.transactionHash,
|
|
9948
|
-
timestamp: hyperbridgeFinality.timestamp,
|
|
9949
|
-
calldata
|
|
9950
|
-
}
|
|
9951
|
-
};
|
|
9982
|
+
return void 0;
|
|
9952
9983
|
}
|
|
9953
9984
|
/**
|
|
9954
9985
|
* Streaming helper: waits (via `waitOrAbort`) for the consensus proof or
|
|
@@ -9963,7 +9994,12 @@ var GetRequestClient = class {
|
|
|
9963
9994
|
const hyperbridge = this.ctx.config.hyperbridge;
|
|
9964
9995
|
const stateMachineId = this.ctx.config.hyperbridge.config.stateMachineId;
|
|
9965
9996
|
const neededHeight = BigInt(request.statuses[hyperbridgeDeliveredIndex].metadata.blockNumber);
|
|
9966
|
-
|
|
9997
|
+
let finality = await this.queries.queryStateMachineUpdateByHeight({
|
|
9998
|
+
statemachineId: stateMachineId,
|
|
9999
|
+
height: Number(neededHeight),
|
|
10000
|
+
chain: stateMachineId
|
|
10001
|
+
});
|
|
10002
|
+
if (!finality && sourceChain instanceof EvmChain) {
|
|
9967
10003
|
const hyperbridgeSubstrate = hyperbridge;
|
|
9968
10004
|
const currentEpoch = await sourceChain.currentEpoch();
|
|
9969
10005
|
const consensusResult = await waitOrAbort(this.ctx, {
|
|
@@ -10007,18 +10043,20 @@ var GetRequestClient = class {
|
|
|
10007
10043
|
}
|
|
10008
10044
|
};
|
|
10009
10045
|
}
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10046
|
+
if (!finality) {
|
|
10047
|
+
finality = await waitOrAbort(this.ctx, {
|
|
10048
|
+
signal,
|
|
10049
|
+
promise: () => this.queries.queryStateMachineUpdateByHeight({
|
|
10050
|
+
statemachineId: stateMachineId,
|
|
10051
|
+
height: Number(neededHeight),
|
|
10052
|
+
chain: stateMachineId
|
|
10053
|
+
})
|
|
10054
|
+
});
|
|
10055
|
+
}
|
|
10018
10056
|
const proof = await hyperbridge.queryProof(
|
|
10019
10057
|
{ Responses: [response?.commitment] },
|
|
10020
10058
|
request.source,
|
|
10021
|
-
BigInt(
|
|
10059
|
+
BigInt(finality.height)
|
|
10022
10060
|
);
|
|
10023
10061
|
const calldata = sourceChain.encode({
|
|
10024
10062
|
kind: "GetResponse",
|
|
@@ -10026,7 +10064,7 @@ var GetRequestClient = class {
|
|
|
10026
10064
|
stateMachine: stateMachineId,
|
|
10027
10065
|
consensusStateId: this.ctx.config.hyperbridge.config.consensusStateId,
|
|
10028
10066
|
proof,
|
|
10029
|
-
height: BigInt(
|
|
10067
|
+
height: BigInt(finality.height)
|
|
10030
10068
|
},
|
|
10031
10069
|
responses: [
|
|
10032
10070
|
{
|
|
@@ -10042,10 +10080,10 @@ var GetRequestClient = class {
|
|
|
10042
10080
|
return {
|
|
10043
10081
|
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
10044
10082
|
metadata: {
|
|
10045
|
-
blockHash:
|
|
10046
|
-
blockNumber:
|
|
10047
|
-
transactionHash:
|
|
10048
|
-
timestamp:
|
|
10083
|
+
blockHash: finality.blockHash,
|
|
10084
|
+
blockNumber: finality.height,
|
|
10085
|
+
transactionHash: finality.transactionHash,
|
|
10086
|
+
timestamp: finality.timestamp,
|
|
10049
10087
|
calldata
|
|
10050
10088
|
}
|
|
10051
10089
|
};
|
|
@@ -10544,6 +10582,40 @@ var PostRequestClient = class {
|
|
|
10544
10582
|
async buildFinalized(request, hyperbridgeDelivered) {
|
|
10545
10583
|
const destChain = this.ctx.config.dest;
|
|
10546
10584
|
const hyperbridge = this.ctx.config.hyperbridge;
|
|
10585
|
+
const { config } = hyperbridge;
|
|
10586
|
+
const finality = await this.queries.queryStateMachineUpdateByHeight({
|
|
10587
|
+
statemachineId: config.stateMachineId,
|
|
10588
|
+
height: hyperbridgeDelivered.metadata.blockNumber,
|
|
10589
|
+
chain: config.stateMachineId
|
|
10590
|
+
});
|
|
10591
|
+
if (finality) {
|
|
10592
|
+
const proof = await hyperbridge.queryProof(
|
|
10593
|
+
{ Requests: [postRequestCommitment(request).commitment] },
|
|
10594
|
+
request.dest,
|
|
10595
|
+
BigInt(finality.height)
|
|
10596
|
+
);
|
|
10597
|
+
const calldata = destChain.encode({
|
|
10598
|
+
kind: "PostRequest",
|
|
10599
|
+
proof: {
|
|
10600
|
+
stateMachine: config.stateMachineId,
|
|
10601
|
+
consensusStateId: config.consensusStateId,
|
|
10602
|
+
proof,
|
|
10603
|
+
height: BigInt(finality.height)
|
|
10604
|
+
},
|
|
10605
|
+
requests: [request],
|
|
10606
|
+
signer: viem.pad("0x")
|
|
10607
|
+
});
|
|
10608
|
+
return {
|
|
10609
|
+
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
10610
|
+
metadata: {
|
|
10611
|
+
blockHash: finality.blockHash,
|
|
10612
|
+
blockNumber: finality.height,
|
|
10613
|
+
transactionHash: finality.transactionHash,
|
|
10614
|
+
timestamp: finality.timestamp,
|
|
10615
|
+
calldata
|
|
10616
|
+
}
|
|
10617
|
+
};
|
|
10618
|
+
}
|
|
10547
10619
|
if (destChain instanceof EvmChain) {
|
|
10548
10620
|
const hyperbridgeSubstrate = hyperbridge;
|
|
10549
10621
|
const currentEpoch = await destChain.currentEpoch();
|
|
@@ -10552,18 +10624,18 @@ var PostRequestClient = class {
|
|
|
10552
10624
|
currentEpoch
|
|
10553
10625
|
);
|
|
10554
10626
|
if (!consensusResult) return void 0;
|
|
10555
|
-
const
|
|
10627
|
+
const proof = await hyperbridge.queryProof(
|
|
10556
10628
|
{ Requests: [postRequestCommitment(request).commitment] },
|
|
10557
10629
|
request.dest,
|
|
10558
10630
|
consensusResult.provenHeight
|
|
10559
10631
|
);
|
|
10560
|
-
const
|
|
10632
|
+
const calldata = destChain.encode({
|
|
10561
10633
|
kind: "BatchConsensusAndPostRequest",
|
|
10562
10634
|
consensusProofs: consensusResult.proofs,
|
|
10563
10635
|
proof: {
|
|
10564
|
-
stateMachine:
|
|
10565
|
-
consensusStateId:
|
|
10566
|
-
proof
|
|
10636
|
+
stateMachine: config.stateMachineId,
|
|
10637
|
+
consensusStateId: config.consensusStateId,
|
|
10638
|
+
proof,
|
|
10567
10639
|
height: consensusResult.provenHeight
|
|
10568
10640
|
},
|
|
10569
10641
|
requests: [request],
|
|
@@ -10577,42 +10649,11 @@ var PostRequestClient = class {
|
|
|
10577
10649
|
transactionHash: hyperbridgeDelivered.metadata.transactionHash,
|
|
10578
10650
|
// @ts-ignore
|
|
10579
10651
|
timestamp: hyperbridgeDelivered.metadata.timestamp,
|
|
10580
|
-
calldata
|
|
10652
|
+
calldata
|
|
10581
10653
|
}
|
|
10582
10654
|
};
|
|
10583
10655
|
}
|
|
10584
|
-
|
|
10585
|
-
statemachineId: this.ctx.config.hyperbridge.config.stateMachineId,
|
|
10586
|
-
height: hyperbridgeDelivered.metadata.blockNumber,
|
|
10587
|
-
chain: request.dest
|
|
10588
|
-
});
|
|
10589
|
-
if (!hyperbridgeFinality) return void 0;
|
|
10590
|
-
const proof = await hyperbridge.queryProof(
|
|
10591
|
-
{ Requests: [postRequestCommitment(request).commitment] },
|
|
10592
|
-
request.dest,
|
|
10593
|
-
BigInt(hyperbridgeFinality.height)
|
|
10594
|
-
);
|
|
10595
|
-
const calldata = destChain.encode({
|
|
10596
|
-
kind: "PostRequest",
|
|
10597
|
-
proof: {
|
|
10598
|
-
stateMachine: this.ctx.config.hyperbridge.config.stateMachineId,
|
|
10599
|
-
consensusStateId: this.ctx.config.hyperbridge.config.consensusStateId,
|
|
10600
|
-
proof,
|
|
10601
|
-
height: BigInt(hyperbridgeFinality.height)
|
|
10602
|
-
},
|
|
10603
|
-
requests: [request],
|
|
10604
|
-
signer: viem.pad("0x")
|
|
10605
|
-
});
|
|
10606
|
-
return {
|
|
10607
|
-
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
10608
|
-
metadata: {
|
|
10609
|
-
blockHash: hyperbridgeFinality.blockHash,
|
|
10610
|
-
blockNumber: hyperbridgeFinality.height,
|
|
10611
|
-
transactionHash: hyperbridgeFinality.transactionHash,
|
|
10612
|
-
timestamp: hyperbridgeFinality.timestamp,
|
|
10613
|
-
calldata
|
|
10614
|
-
}
|
|
10615
|
-
};
|
|
10656
|
+
return void 0;
|
|
10616
10657
|
}
|
|
10617
10658
|
/**
|
|
10618
10659
|
* Streaming helper: waits for the consensus proof, fetches the messaging
|
|
@@ -10626,14 +10667,19 @@ var PostRequestClient = class {
|
|
|
10626
10667
|
const stateMachineId = this.ctx.config.hyperbridge.config.stateMachineId;
|
|
10627
10668
|
const neededHeight = BigInt(request.statuses[hyperbridgeDeliveredIndex].metadata.blockNumber);
|
|
10628
10669
|
this.logger.trace(`[streamFinalized] neededHeight=${neededHeight}`);
|
|
10629
|
-
|
|
10670
|
+
const commitment = postRequestCommitment(request).commitment;
|
|
10671
|
+
let finality = await this.queries.queryStateMachineUpdateByHeight({
|
|
10672
|
+
statemachineId: stateMachineId,
|
|
10673
|
+
height: Number(neededHeight),
|
|
10674
|
+
chain: stateMachineId
|
|
10675
|
+
});
|
|
10676
|
+
if (!finality && destChain instanceof EvmChain) {
|
|
10630
10677
|
const hyperbridgeSubstrate = hyperbridge;
|
|
10631
10678
|
const currentEpoch = await destChain.currentEpoch();
|
|
10632
10679
|
const consensusResult = await waitOrAbort(this.ctx, {
|
|
10633
10680
|
signal,
|
|
10634
10681
|
promise: () => hyperbridgeSubstrate.queryConsensusProofs(neededHeight, currentEpoch)
|
|
10635
10682
|
});
|
|
10636
|
-
const commitment = postRequestCommitment(request).commitment;
|
|
10637
10683
|
this.logger.trace(
|
|
10638
10684
|
`[streamFinalized] consensusProofs found (${consensusResult.proofs.length} proofs), provenHeight=${consensusResult.provenHeight}, commitment=${commitment}, dest=${request.dest}`
|
|
10639
10685
|
);
|
|
@@ -10665,45 +10711,45 @@ var PostRequestClient = class {
|
|
|
10665
10711
|
}
|
|
10666
10712
|
};
|
|
10667
10713
|
}
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10675
|
-
|
|
10714
|
+
if (!finality) {
|
|
10715
|
+
finality = await waitOrAbort(this.ctx, {
|
|
10716
|
+
signal,
|
|
10717
|
+
promise: () => this.queries.queryStateMachineUpdateByHeight({
|
|
10718
|
+
statemachineId: stateMachineId,
|
|
10719
|
+
height: Number(neededHeight),
|
|
10720
|
+
chain: stateMachineId
|
|
10721
|
+
})
|
|
10722
|
+
});
|
|
10723
|
+
}
|
|
10676
10724
|
const proof = await this.fetchProofWithRetry(
|
|
10677
10725
|
signal,
|
|
10678
|
-
() => hyperbridge.queryProof(
|
|
10679
|
-
{ Requests: [postRequestCommitment(request).commitment] },
|
|
10680
|
-
request.dest,
|
|
10681
|
-
BigInt(hyperbridgeFinalized.height)
|
|
10682
|
-
)
|
|
10726
|
+
() => hyperbridge.queryProof({ Requests: [commitment] }, request.dest, BigInt(finality.height))
|
|
10683
10727
|
);
|
|
10728
|
+
if (!(destChain instanceof EvmChain)) {
|
|
10729
|
+
const { stateId } = parseStateMachineId(stateMachineId);
|
|
10730
|
+
await waitForChallengePeriod(destChain, {
|
|
10731
|
+
height: BigInt(finality.height),
|
|
10732
|
+
id: { stateId, consensusStateId: this.ctx.config.hyperbridge.config.consensusStateId }
|
|
10733
|
+
});
|
|
10734
|
+
}
|
|
10684
10735
|
const calldata = destChain.encode({
|
|
10685
10736
|
kind: "PostRequest",
|
|
10686
10737
|
proof: {
|
|
10687
10738
|
stateMachine: stateMachineId,
|
|
10688
10739
|
consensusStateId: this.ctx.config.hyperbridge.config.consensusStateId,
|
|
10689
10740
|
proof,
|
|
10690
|
-
height: BigInt(
|
|
10741
|
+
height: BigInt(finality.height)
|
|
10691
10742
|
},
|
|
10692
10743
|
requests: [request],
|
|
10693
10744
|
signer: viem.pad("0x")
|
|
10694
10745
|
});
|
|
10695
|
-
const { stateId } = parseStateMachineId(stateMachineId);
|
|
10696
|
-
await waitForChallengePeriod(destChain, {
|
|
10697
|
-
height: BigInt(hyperbridgeFinalized.height),
|
|
10698
|
-
id: { stateId, consensusStateId: this.ctx.config.hyperbridge.config.consensusStateId }
|
|
10699
|
-
});
|
|
10700
10746
|
return {
|
|
10701
10747
|
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
10702
10748
|
metadata: {
|
|
10703
|
-
blockHash:
|
|
10704
|
-
blockNumber:
|
|
10705
|
-
transactionHash:
|
|
10706
|
-
timestamp:
|
|
10749
|
+
blockHash: finality.blockHash,
|
|
10750
|
+
blockNumber: finality.height,
|
|
10751
|
+
transactionHash: finality.transactionHash,
|
|
10752
|
+
timestamp: finality.timestamp,
|
|
10707
10753
|
calldata
|
|
10708
10754
|
}
|
|
10709
10755
|
};
|
|
@@ -14626,6 +14672,7 @@ function orderCommitment(order) {
|
|
|
14626
14672
|
return viem.keccak256(encoded);
|
|
14627
14673
|
}
|
|
14628
14674
|
async function convertGasToFeeToken(ctx, gasEstimate, gasEstimateIn, evmChainID, gasPriceOverride) {
|
|
14675
|
+
if (TESTNET_CHAINS.has(evmChainID)) return 1n;
|
|
14629
14676
|
const chain = ctx[gasEstimateIn];
|
|
14630
14677
|
const client = chain.client;
|
|
14631
14678
|
const gasPrice = gasPriceOverride ?? await retryPromise(() => client.getGasPrice(), {
|
|
@@ -14660,6 +14707,7 @@ async function convertGasToFeeToken(ctx, gasEstimate, gasEstimateIn, evmChainID,
|
|
|
14660
14707
|
}
|
|
14661
14708
|
}
|
|
14662
14709
|
async function convertFeeTokenToWei(ctx, feeTokenAmount, feeTokenIn, evmChainID) {
|
|
14710
|
+
if (TESTNET_CHAINS.has(evmChainID)) return 1n;
|
|
14663
14711
|
const chain = ctx[feeTokenIn];
|
|
14664
14712
|
const client = chain.client;
|
|
14665
14713
|
const wethAddr = chain.configService.getWrappedNativeAssetWithDecimals(evmChainID).asset;
|
|
@@ -14775,16 +14823,16 @@ var OrderPlacer = class {
|
|
|
14775
14823
|
return { order, receipt };
|
|
14776
14824
|
}
|
|
14777
14825
|
};
|
|
14826
|
+
|
|
14827
|
+
// src/protocols/intents/OrderExecutor.ts
|
|
14778
14828
|
var USED_USEROPS_STORAGE_KEY = (commitment) => `used-userops:${commitment.toLowerCase()}`;
|
|
14779
14829
|
var OrderExecutor = class {
|
|
14780
|
-
constructor(ctx, bidManager
|
|
14830
|
+
constructor(ctx, bidManager) {
|
|
14781
14831
|
this.ctx = ctx;
|
|
14782
14832
|
this.bidManager = bidManager;
|
|
14783
|
-
this.crypto = crypto;
|
|
14784
14833
|
}
|
|
14785
14834
|
ctx;
|
|
14786
14835
|
bidManager;
|
|
14787
|
-
crypto;
|
|
14788
14836
|
/**
|
|
14789
14837
|
* Sleeps until the order's block deadline is reached, then yields EXPIRED.
|
|
14790
14838
|
* Uses the chain's block time to calculate the sleep duration.
|
|
@@ -14855,17 +14903,6 @@ var OrderExecutor = class {
|
|
|
14855
14903
|
}
|
|
14856
14904
|
return fetchedBids;
|
|
14857
14905
|
}
|
|
14858
|
-
/**
|
|
14859
|
-
* Selects the best bid from the provided candidates, submits the
|
|
14860
|
-
* UserOperation, and persists the dedup entry to prevent resubmission.
|
|
14861
|
-
*/
|
|
14862
|
-
async submitBid(params) {
|
|
14863
|
-
const { order, freshBids, sessionPrivateKey, commitment, usedUserOps, userOpHashKey } = params;
|
|
14864
|
-
const result = await this.bidManager.selectBid(order, freshBids, sessionPrivateKey);
|
|
14865
|
-
usedUserOps.add(userOpHashKey(result.userOp));
|
|
14866
|
-
await this.persistUsedUserOps(commitment, usedUserOps);
|
|
14867
|
-
return result;
|
|
14868
|
-
}
|
|
14869
14906
|
/**
|
|
14870
14907
|
* Processes a fill result and returns updated fill accumulators,
|
|
14871
14908
|
* the status update to yield (if any), and whether the order is
|
|
@@ -14933,7 +14970,15 @@ var OrderExecutor = class {
|
|
|
14933
14970
|
}
|
|
14934
14971
|
/**
|
|
14935
14972
|
* Executes an intent order by racing bid polling against the order's
|
|
14936
|
-
* block deadline. Yields status updates at each lifecycle stage
|
|
14973
|
+
* block deadline. Yields status updates at each lifecycle stage and hands
|
|
14974
|
+
* bid selection to the consumer.
|
|
14975
|
+
*
|
|
14976
|
+
* This is a **bidirectional** generator: when it yields `BIDS_RECEIVED`, the
|
|
14977
|
+
* consumer picks a bid, calls `bid.execute()`, and feeds the resulting
|
|
14978
|
+
* {@link SelectBidResult} back via `gen.next(result)`. The generator then
|
|
14979
|
+
* records the dedup entry, emits `BID_SELECTED`, tracks the fill, and either
|
|
14980
|
+
* terminates or continues polling for the remaining amount. Feeding back
|
|
14981
|
+
* `undefined` (no bid executed this round) causes it to keep polling.
|
|
14937
14982
|
*
|
|
14938
14983
|
* **Same-chain:** `AWAITING_BIDS` → `BIDS_RECEIVED` → `BID_SELECTED`
|
|
14939
14984
|
* → (`FILLED` | `PARTIAL_FILL`)* → (`FILLED` | `EXPIRED`)
|
|
@@ -14944,7 +14989,6 @@ var OrderExecutor = class {
|
|
|
14944
14989
|
async *executeOrder(options) {
|
|
14945
14990
|
const { order, sessionPrivateKey, auctionTimeMs, pollIntervalMs = DEFAULT_POLL_INTERVAL, solver } = options;
|
|
14946
14991
|
const commitment = order.id;
|
|
14947
|
-
order.source === order.destination;
|
|
14948
14992
|
if (!this.ctx.intentsCoprocessor) {
|
|
14949
14993
|
yield { status: "FAILED", error: "IntentsCoprocessor required for order execution" };
|
|
14950
14994
|
return;
|
|
@@ -14972,11 +15016,24 @@ var OrderExecutor = class {
|
|
|
14972
15016
|
remainingAssets
|
|
14973
15017
|
});
|
|
14974
15018
|
const deadlineTimeout = this.deadlineStream(order.deadline, commitment);
|
|
14975
|
-
const
|
|
15019
|
+
const deadlinePromise = deadlineTimeout.next();
|
|
14976
15020
|
try {
|
|
14977
|
-
|
|
14978
|
-
|
|
14979
|
-
|
|
15021
|
+
let input;
|
|
15022
|
+
while (true) {
|
|
15023
|
+
const winner = input !== void 0 ? { from: "exec", r: await executionStream.next(input) } : await Promise.race([
|
|
15024
|
+
executionStream.next(void 0).then((r) => ({ from: "exec", r })),
|
|
15025
|
+
deadlinePromise.then((r) => ({ from: "deadline", r }))
|
|
15026
|
+
]);
|
|
15027
|
+
input = void 0;
|
|
15028
|
+
if (winner.from === "deadline") {
|
|
15029
|
+
if (!winner.r.done && winner.r.value) yield winner.r.value;
|
|
15030
|
+
return;
|
|
15031
|
+
}
|
|
15032
|
+
const { value, done } = winner.r;
|
|
15033
|
+
if (done) return;
|
|
15034
|
+
const fed = yield value;
|
|
15035
|
+
if (value.status === "BIDS_RECEIVED") input = fed;
|
|
15036
|
+
if (value.status === "EXPIRED" || value.status === "FILLED") return;
|
|
14980
15037
|
}
|
|
14981
15038
|
} finally {
|
|
14982
15039
|
console.log(`[OrderExecutor] Tearing down streams for commitment=${commitment}`);
|
|
@@ -14985,9 +15042,16 @@ var OrderExecutor = class {
|
|
|
14985
15042
|
}
|
|
14986
15043
|
}
|
|
14987
15044
|
/**
|
|
14988
|
-
* Core execution loop that polls for bids
|
|
14989
|
-
*
|
|
14990
|
-
*
|
|
15045
|
+
* Core execution loop that polls for bids and tracks fill progress. Builds
|
|
15046
|
+
* first-class {@link Bid} objects from the raw filler bids and yields them to
|
|
15047
|
+
* the consumer, which picks one, calls `bid.execute()`, and feeds the result
|
|
15048
|
+
* back via `gen.next(result)`. The loop then records the dedup entry, emits
|
|
15049
|
+
* `BID_SELECTED`, processes the fill, and continues polling for the remaining
|
|
15050
|
+
* amount on partial fills.
|
|
15051
|
+
*
|
|
15052
|
+
* Bidirectional: the value passed to `.next()` after a `BIDS_RECEIVED` yield is
|
|
15053
|
+
* the {@link SelectBidResult} from the executed bid (or `undefined` to skip the
|
|
15054
|
+
* round and keep polling).
|
|
14991
15055
|
*/
|
|
14992
15056
|
async *executionStream(params) {
|
|
14993
15057
|
const {
|
|
@@ -15002,12 +15066,7 @@ var OrderExecutor = class {
|
|
|
15002
15066
|
targetAssets
|
|
15003
15067
|
} = params;
|
|
15004
15068
|
let { totalFilledAssets, remainingAssets } = params;
|
|
15005
|
-
const
|
|
15006
|
-
const bidFailCounts = /* @__PURE__ */ new Map();
|
|
15007
|
-
const isFreshBid = (bid) => {
|
|
15008
|
-
const key = userOpHashKey(bid.userOp);
|
|
15009
|
-
return !usedUserOps.has(key) && (bidFailCounts.get(key) ?? 0) < MAX_BID_ATTEMPTS;
|
|
15010
|
-
};
|
|
15069
|
+
const isFreshBid = (bid) => !usedUserOps.has(userOpHashKey(bid.userOp));
|
|
15011
15070
|
const solverLockStartTime = Date.now();
|
|
15012
15071
|
yield { status: "AWAITING_BIDS", commitment, totalFilledAssets, remainingAssets };
|
|
15013
15072
|
try {
|
|
@@ -15016,13 +15075,13 @@ var OrderExecutor = class {
|
|
|
15016
15075
|
while (Date.now() < auctionEnd) {
|
|
15017
15076
|
try {
|
|
15018
15077
|
const bids = await this.fetchBids({ commitment, solver, solverLockStartTime });
|
|
15019
|
-
const
|
|
15020
|
-
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
yield { status: "NEW_BID", commitment,
|
|
15078
|
+
const newBids = bids.filter(
|
|
15079
|
+
(bid) => isFreshBid(bid) && !auctionSeenBids.has(userOpHashKey(bid.userOp))
|
|
15080
|
+
);
|
|
15081
|
+
for (const fillerBid of newBids) {
|
|
15082
|
+
auctionSeenBids.add(userOpHashKey(fillerBid.userOp));
|
|
15083
|
+
const [bid] = this.bidManager.buildBids(order, [fillerBid], sessionPrivateKey);
|
|
15084
|
+
if (bid) yield { status: "NEW_BID", commitment, bid };
|
|
15026
15085
|
}
|
|
15027
15086
|
} catch {
|
|
15028
15087
|
}
|
|
@@ -15034,8 +15093,8 @@ var OrderExecutor = class {
|
|
|
15034
15093
|
while (true) {
|
|
15035
15094
|
let freshBids;
|
|
15036
15095
|
try {
|
|
15037
|
-
const
|
|
15038
|
-
freshBids =
|
|
15096
|
+
const bids2 = await this.fetchBids({ commitment, solver, solverLockStartTime });
|
|
15097
|
+
freshBids = bids2.filter(isFreshBid);
|
|
15039
15098
|
} catch {
|
|
15040
15099
|
await sleep(pollIntervalMs);
|
|
15041
15100
|
continue;
|
|
@@ -15044,56 +15103,33 @@ var OrderExecutor = class {
|
|
|
15044
15103
|
await sleep(pollIntervalMs);
|
|
15045
15104
|
continue;
|
|
15046
15105
|
}
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
commitment,
|
|
15055
|
-
usedUserOps,
|
|
15056
|
-
userOpHashKey
|
|
15057
|
-
});
|
|
15058
|
-
} catch (err) {
|
|
15059
|
-
yield {
|
|
15060
|
-
status: "FAILED",
|
|
15061
|
-
commitment,
|
|
15062
|
-
totalFilledAssets,
|
|
15063
|
-
remainingAssets,
|
|
15064
|
-
error: `Failed to select bid and submit: ${err instanceof Error ? err.message : String(err)}`
|
|
15065
|
-
};
|
|
15066
|
-
try {
|
|
15067
|
-
const sorted = await this.bidManager.validateAndSortBids(freshBids, order);
|
|
15068
|
-
if (sorted.length > 0) {
|
|
15069
|
-
const key = userOpHashKey(sorted[0].bid.userOp);
|
|
15070
|
-
bidFailCounts.set(key, (bidFailCounts.get(key) ?? 0) + 1);
|
|
15071
|
-
}
|
|
15072
|
-
} catch {
|
|
15073
|
-
}
|
|
15106
|
+
const bids = this.bidManager.buildBids(order, freshBids, sessionPrivateKey);
|
|
15107
|
+
if (bids.length === 0) {
|
|
15108
|
+
await sleep(pollIntervalMs);
|
|
15109
|
+
continue;
|
|
15110
|
+
}
|
|
15111
|
+
const result = yield { status: "BIDS_RECEIVED", commitment, bidCount: bids.length, bids };
|
|
15112
|
+
if (!result) {
|
|
15074
15113
|
await sleep(pollIntervalMs);
|
|
15075
15114
|
continue;
|
|
15076
15115
|
}
|
|
15116
|
+
usedUserOps.add(userOpHashKey(result.userOp));
|
|
15117
|
+
await this.persistUsedUserOps(commitment, usedUserOps);
|
|
15077
15118
|
yield {
|
|
15078
15119
|
status: "BID_SELECTED",
|
|
15079
15120
|
commitment,
|
|
15080
|
-
selectedSolver:
|
|
15081
|
-
userOpHash:
|
|
15082
|
-
userOp:
|
|
15083
|
-
transactionHash:
|
|
15121
|
+
selectedSolver: result.solverAddress,
|
|
15122
|
+
userOpHash: result.userOpHash,
|
|
15123
|
+
userOp: result.userOp,
|
|
15124
|
+
transactionHash: result.txnHash
|
|
15084
15125
|
};
|
|
15085
|
-
const fill = this.processFillResult(
|
|
15086
|
-
submitResult,
|
|
15087
|
-
commitment,
|
|
15088
|
-
targetAssets,
|
|
15089
|
-
totalFilledAssets,
|
|
15090
|
-
remainingAssets
|
|
15091
|
-
);
|
|
15126
|
+
const fill = this.processFillResult(result, commitment, targetAssets, totalFilledAssets, remainingAssets);
|
|
15092
15127
|
totalFilledAssets = fill.totalFilledAssets;
|
|
15093
15128
|
remainingAssets = fill.remainingAssets;
|
|
15094
15129
|
if (fill.update) {
|
|
15095
15130
|
yield fill.update;
|
|
15096
15131
|
}
|
|
15132
|
+
if (fill.done) return;
|
|
15097
15133
|
}
|
|
15098
15134
|
} catch (err) {
|
|
15099
15135
|
yield {
|
|
@@ -15568,183 +15604,148 @@ var OrderCanceller = class {
|
|
|
15568
15604
|
return feeInDestFeeToken * 1005n / 1000n;
|
|
15569
15605
|
}
|
|
15570
15606
|
};
|
|
15571
|
-
var
|
|
15572
|
-
|
|
15573
|
-
|
|
15574
|
-
|
|
15575
|
-
|
|
15576
|
-
|
|
15577
|
-
*/
|
|
15578
|
-
constructor(ctx, crypto) {
|
|
15579
|
-
this.ctx = ctx;
|
|
15580
|
-
this.crypto = crypto;
|
|
15581
|
-
}
|
|
15607
|
+
var BidImpl = class {
|
|
15608
|
+
solverAddress;
|
|
15609
|
+
outputs;
|
|
15610
|
+
relayerFee;
|
|
15611
|
+
nativeDispatchFee;
|
|
15612
|
+
userOp;
|
|
15582
15613
|
ctx;
|
|
15583
15614
|
crypto;
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
|
|
15593
|
-
|
|
15594
|
-
|
|
15595
|
-
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15609
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15615
|
+
order;
|
|
15616
|
+
fillOptions;
|
|
15617
|
+
priceOutputs;
|
|
15618
|
+
sessionPrivateKey;
|
|
15619
|
+
intentGatewayV2Address;
|
|
15620
|
+
domainSeparator;
|
|
15621
|
+
/** Cached session-key signature over the `SelectSolver` message. */
|
|
15622
|
+
cachedSignature;
|
|
15623
|
+
constructor(params) {
|
|
15624
|
+
this.ctx = params.ctx;
|
|
15625
|
+
this.crypto = params.crypto;
|
|
15626
|
+
this.order = params.order;
|
|
15627
|
+
this.fillOptions = params.fillOptions;
|
|
15628
|
+
this.priceOutputs = params.priceOutputs;
|
|
15629
|
+
this.sessionPrivateKey = params.sessionPrivateKey;
|
|
15630
|
+
this.solverAddress = params.fillerBid.userOp.sender;
|
|
15631
|
+
this.outputs = params.fillOptions.outputs;
|
|
15632
|
+
this.relayerFee = params.fillOptions.relayerFee;
|
|
15633
|
+
this.nativeDispatchFee = params.fillOptions.nativeDispatchFee;
|
|
15634
|
+
this.userOp = params.fillerBid.userOp;
|
|
15635
|
+
this.intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
15636
|
+
normalizeStateMachineId(this.order.destination)
|
|
15637
|
+
);
|
|
15638
|
+
this.domainSeparator = CryptoUtils.getDomainSeparator(
|
|
15639
|
+
"IntentGateway",
|
|
15640
|
+
"2",
|
|
15641
|
+
this.chainId(),
|
|
15642
|
+
this.intentGatewayV2Address
|
|
15643
|
+
);
|
|
15644
|
+
}
|
|
15645
|
+
/** Resolves the destination chain id from the client or the state-machine id. */
|
|
15646
|
+
chainId() {
|
|
15647
|
+
return BigInt(
|
|
15613
15648
|
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
|
|
15614
15649
|
);
|
|
15615
|
-
const accountGasLimits = CryptoUtils.packGasLimits(verificationGasLimit, callGasLimit);
|
|
15616
|
-
const gasFees = CryptoUtils.packGasFees(maxPriorityFeePerGas, maxFeePerGas);
|
|
15617
|
-
const userOp = {
|
|
15618
|
-
sender: solverAccount,
|
|
15619
|
-
nonce,
|
|
15620
|
-
initCode: "0x",
|
|
15621
|
-
callData,
|
|
15622
|
-
accountGasLimits,
|
|
15623
|
-
preVerificationGas,
|
|
15624
|
-
gasFees,
|
|
15625
|
-
paymasterAndData,
|
|
15626
|
-
signature: "0x"
|
|
15627
|
-
};
|
|
15628
|
-
const userOpHash = CryptoUtils.computeUserOpHash(userOp, entryPointAddress, chainId);
|
|
15629
|
-
const sessionKey = order.session;
|
|
15630
|
-
const messageHash = viem.keccak256(viem.concat([userOpHash, order.id, sessionKey]));
|
|
15631
|
-
const solverSignature = await solverSigner.signMessage(messageHash, Number(chainId));
|
|
15632
|
-
const signature = viem.concat([order.id, solverSignature]);
|
|
15633
|
-
return { ...userOp, signature };
|
|
15634
15650
|
}
|
|
15635
15651
|
/**
|
|
15636
|
-
*
|
|
15637
|
-
* solver
|
|
15638
|
-
* UserOperation to the bundler.
|
|
15652
|
+
* Resolves the session key, signs the `SelectSolver` message for this bid's
|
|
15653
|
+
* solver, and caches the signature. Signs at most once per bid.
|
|
15639
15654
|
*
|
|
15640
|
-
*
|
|
15641
|
-
* 1. Decodes `fillOrder` calldata from each bid's `callData`.
|
|
15642
|
-
* 2. Sorts bids by output value (single-output: amount; all-stables: normalised
|
|
15643
|
-
* USD; mixed: DEX-quoted USD; fallback: raw amount).
|
|
15644
|
-
* 3. Iterates sorted bids, simulating each with `eth_call` until one passes.
|
|
15645
|
-
* 4. Appends the session-key's `SelectSolver` signature to the solver's
|
|
15646
|
-
* existing signature and submits via `eth_sendUserOperation`.
|
|
15647
|
-
* 5. For same-chain orders, waits for the transaction receipt and reads
|
|
15648
|
-
* `OrderFilled` / `PartialFill` events to determine fill status.
|
|
15649
|
-
*
|
|
15650
|
-
* @param order - The placed order for which to select a bid.
|
|
15651
|
-
* @param bids - Raw bids fetched from the Hyperbridge coprocessor.
|
|
15652
|
-
* @param sessionPrivateKey - Optional override; if omitted, the key is
|
|
15653
|
-
* looked up from `sessionKeyStorage` using `order.session`.
|
|
15654
|
-
* @returns A {@link SelectBidResult} containing the submitted UserOperation,
|
|
15655
|
-
* its hash, the winning solver address, transaction hash, and fill status.
|
|
15656
|
-
* @throws If the session key is not found, no valid bids exist, all
|
|
15657
|
-
* simulations fail, or the bundler rejects the UserOperation.
|
|
15655
|
+
* @throws If the session key is missing or signing fails.
|
|
15658
15656
|
*/
|
|
15659
|
-
async
|
|
15660
|
-
|
|
15661
|
-
const
|
|
15662
|
-
|
|
15663
|
-
const sessionKeyData = sessionPrivateKey ? { privateKey: sessionPrivateKey } : await this.ctx.sessionKeyStorage.getSessionKeyByAddress(sessionKeyAddress);
|
|
15657
|
+
async signSelection() {
|
|
15658
|
+
if (this.cachedSignature) return this.cachedSignature;
|
|
15659
|
+
const commitment = this.order.id;
|
|
15660
|
+
const sessionKeyAddress = this.order.session;
|
|
15661
|
+
const sessionKeyData = this.sessionPrivateKey ? { privateKey: this.sessionPrivateKey } : await this.ctx.sessionKeyStorage.getSessionKeyByAddress(sessionKeyAddress);
|
|
15664
15662
|
if (!sessionKeyData) {
|
|
15665
15663
|
throw new Error("SessionKey not found for commitment: " + commitment);
|
|
15666
15664
|
}
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
}
|
|
15673
|
-
const sortedBids = await this.validateAndSortBids(bids, order);
|
|
15674
|
-
console.log(`[BidManager] ${sortedBids.length}/${bids.length} bid(s) passed validation and sorting`);
|
|
15675
|
-
if (sortedBids.length === 0) {
|
|
15676
|
-
throw new Error("No valid bids found");
|
|
15677
|
-
}
|
|
15678
|
-
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
15679
|
-
normalizeStateMachineId(order.destination)
|
|
15680
|
-
);
|
|
15681
|
-
const domainSeparator = CryptoUtils.getDomainSeparator(
|
|
15682
|
-
"IntentGateway",
|
|
15683
|
-
"2",
|
|
15684
|
-
BigInt(
|
|
15685
|
-
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
|
|
15686
|
-
),
|
|
15687
|
-
intentGatewayV2Address
|
|
15665
|
+
const signature = await CryptoUtils.signSolverSelection(
|
|
15666
|
+
commitment,
|
|
15667
|
+
this.solverAddress,
|
|
15668
|
+
this.domainSeparator,
|
|
15669
|
+
sessionKeyData.privateKey
|
|
15688
15670
|
);
|
|
15689
|
-
|
|
15690
|
-
|
|
15691
|
-
console.log(`[BidManager] Simulating ${sortedBids.length} sorted bid(s) to find a valid one`);
|
|
15692
|
-
for (let idx = 0; idx < sortedBids.length; idx++) {
|
|
15693
|
-
const bidWithOptions = sortedBids[idx];
|
|
15694
|
-
const solverAddress2 = bidWithOptions.bid.userOp.sender;
|
|
15695
|
-
console.log(`[BidManager] Simulating bid ${idx + 1}/${sortedBids.length} from solver=${solverAddress2}`);
|
|
15696
|
-
const signature = await CryptoUtils.signSolverSelection(
|
|
15697
|
-
commitment,
|
|
15698
|
-
solverAddress2,
|
|
15699
|
-
domainSeparator,
|
|
15700
|
-
sessionKeyData.privateKey
|
|
15701
|
-
);
|
|
15702
|
-
if (!signature) {
|
|
15703
|
-
console.warn(`[BidManager] Bid ${idx + 1}: failed to sign solver selection, skipping`);
|
|
15704
|
-
continue;
|
|
15705
|
-
}
|
|
15706
|
-
const selectOptions = {
|
|
15707
|
-
commitment,
|
|
15708
|
-
solver: solverAddress2,
|
|
15709
|
-
signature
|
|
15710
|
-
};
|
|
15711
|
-
try {
|
|
15712
|
-
await this.simulate(bidWithOptions.bid, bidWithOptions.options, selectOptions, intentGatewayV2Address);
|
|
15713
|
-
console.log(`[BidManager] Bid ${idx + 1} from solver=${solverAddress2}: simulation PASSED`);
|
|
15714
|
-
selectedBid = bidWithOptions;
|
|
15715
|
-
sessionSignature = signature;
|
|
15716
|
-
break;
|
|
15717
|
-
} catch (err) {
|
|
15718
|
-
console.warn(
|
|
15719
|
-
`[BidManager] Bid ${idx + 1} from solver=${solverAddress2}: simulation FAILED: ${err instanceof Error ? err.message : String(err)}`
|
|
15720
|
-
);
|
|
15721
|
-
continue;
|
|
15722
|
-
}
|
|
15671
|
+
if (!signature) {
|
|
15672
|
+
throw new Error("Failed to sign solver selection");
|
|
15723
15673
|
}
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15674
|
+
this.cachedSignature = signature;
|
|
15675
|
+
return signature;
|
|
15676
|
+
}
|
|
15677
|
+
/**
|
|
15678
|
+
* Simulates this bid on-chain by batching the `select` and `fillOrder` calls
|
|
15679
|
+
* via `eth_call` from the solver's account, using the IntentGatewayV2 ERC-7821
|
|
15680
|
+
* batch-execute pattern.
|
|
15681
|
+
*
|
|
15682
|
+
* The native value forwarded to the simulation is the sum of any native-token
|
|
15683
|
+
* (`address(0)`) output amounts plus the Hyperbridge dispatch fee.
|
|
15684
|
+
*
|
|
15685
|
+
* @throws If the `eth_call` simulation reverts or errors.
|
|
15686
|
+
*/
|
|
15687
|
+
async simulate() {
|
|
15688
|
+
const signature = await this.signSelection();
|
|
15689
|
+
const selectOptions = {
|
|
15690
|
+
commitment: this.order.id,
|
|
15691
|
+
solver: this.solverAddress,
|
|
15692
|
+
signature
|
|
15693
|
+
};
|
|
15694
|
+
const nativeOutputs = this.fillOptions.outputs.reduce(
|
|
15695
|
+
(acc, o) => bytes32ToBytes20(o.token) === ADDRESS_ZERO2 ? acc + o.amount : acc,
|
|
15696
|
+
0n
|
|
15697
|
+
);
|
|
15698
|
+
const simulationValue = nativeOutputs + this.fillOptions.nativeDispatchFee;
|
|
15699
|
+
const selectCalldata = viem.encodeFunctionData({
|
|
15700
|
+
abi: ABI3,
|
|
15701
|
+
functionName: "select",
|
|
15702
|
+
args: [selectOptions]
|
|
15703
|
+
});
|
|
15704
|
+
const calls = [
|
|
15705
|
+
{ target: this.intentGatewayV2Address, value: 0n, data: selectCalldata },
|
|
15706
|
+
{ target: this.solverAddress, value: simulationValue, data: this.userOp.callData }
|
|
15707
|
+
];
|
|
15708
|
+
const batchedCalldata = this.crypto.encodeERC7821Execute(calls);
|
|
15709
|
+
try {
|
|
15710
|
+
await this.ctx.dest.client.call({
|
|
15711
|
+
account: this.solverAddress,
|
|
15712
|
+
to: this.solverAddress,
|
|
15713
|
+
data: batchedCalldata,
|
|
15714
|
+
value: simulationValue
|
|
15715
|
+
});
|
|
15716
|
+
} catch (e) {
|
|
15717
|
+
throw new Error(`Simulation failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
15727
15718
|
}
|
|
15728
|
-
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
|
|
15719
|
+
}
|
|
15720
|
+
/**
|
|
15721
|
+
* Signs the `SelectSolver` message with the session key, appends it to the
|
|
15722
|
+
* solver's existing UserOp signature, and submits the UserOperation to the
|
|
15723
|
+
* bundler. For same-chain orders, waits for the receipt and reads
|
|
15724
|
+
* `OrderFilled` / `PartialFill` logs to determine fill status.
|
|
15725
|
+
*
|
|
15726
|
+
* @returns A {@link SelectBidResult} with the submitted UserOperation, its hash,
|
|
15727
|
+
* the solver address, transaction hash, and fill status.
|
|
15728
|
+
* @throws If the bundler is not configured, the session key is missing, or the
|
|
15729
|
+
* bundler rejects the UserOperation.
|
|
15730
|
+
*/
|
|
15731
|
+
async execute() {
|
|
15732
|
+
const commitment = this.order.id;
|
|
15733
|
+
if (!this.ctx.bundlerUrl) {
|
|
15734
|
+
throw new Error("Bundler URL not configured");
|
|
15735
|
+
}
|
|
15736
|
+
const sessionSignature = await this.signSelection();
|
|
15737
|
+
const finalSignature = viem.concat([this.userOp.signature, sessionSignature]);
|
|
15733
15738
|
const signedUserOp = {
|
|
15734
|
-
...
|
|
15739
|
+
...this.userOp,
|
|
15735
15740
|
signature: finalSignature
|
|
15736
15741
|
};
|
|
15737
15742
|
const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(
|
|
15738
|
-
normalizeStateMachineId(order.destination)
|
|
15743
|
+
normalizeStateMachineId(this.order.destination)
|
|
15739
15744
|
);
|
|
15740
|
-
|
|
15741
|
-
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
|
|
15742
|
-
);
|
|
15743
|
-
const bundlerResult = await this.crypto.sendBundler(BundlerMethod.ETH_SEND_USER_OPERATION, [
|
|
15745
|
+
const userOpHash = await this.crypto.sendBundler(BundlerMethod.ETH_SEND_USER_OPERATION, [
|
|
15744
15746
|
CryptoUtils.prepareBundlerCall(signedUserOp),
|
|
15745
15747
|
entryPointAddress
|
|
15746
15748
|
]);
|
|
15747
|
-
const userOpHash = bundlerResult;
|
|
15748
15749
|
let txnHash;
|
|
15749
15750
|
let fillStatus;
|
|
15750
15751
|
let filledAssets;
|
|
@@ -15760,7 +15761,7 @@ var BidManager = class {
|
|
|
15760
15761
|
{ maxRetries: 5, backoffMs: 2e3, logMessage: "Fetching user operation receipt" }
|
|
15761
15762
|
);
|
|
15762
15763
|
txnHash = receipt.receipt.transactionHash;
|
|
15763
|
-
if (order.source === order.destination) {
|
|
15764
|
+
if (this.order.source === this.order.destination) {
|
|
15764
15765
|
try {
|
|
15765
15766
|
const chainReceipt = await this.ctx.dest.client.waitForTransactionReceipt({
|
|
15766
15767
|
hash: txnHash,
|
|
@@ -15789,12 +15790,12 @@ var BidManager = class {
|
|
|
15789
15790
|
}
|
|
15790
15791
|
}
|
|
15791
15792
|
} catch (err) {
|
|
15792
|
-
throw new Error(`Failed to
|
|
15793
|
+
throw new Error(`Failed to execute bid: ${err instanceof Error ? err.message : String(err)}`);
|
|
15793
15794
|
}
|
|
15794
15795
|
return {
|
|
15795
15796
|
userOp: signedUserOp,
|
|
15796
15797
|
userOpHash,
|
|
15797
|
-
solverAddress,
|
|
15798
|
+
solverAddress: this.solverAddress,
|
|
15798
15799
|
commitment,
|
|
15799
15800
|
txnHash,
|
|
15800
15801
|
fillStatus,
|
|
@@ -15802,7 +15803,177 @@ var BidManager = class {
|
|
|
15802
15803
|
};
|
|
15803
15804
|
}
|
|
15804
15805
|
/**
|
|
15805
|
-
*
|
|
15806
|
+
* Prices this bid's outputs in USD using the destination chain's DEX-quote
|
|
15807
|
+
* helpers. Returns `null` when any output token cannot be priced.
|
|
15808
|
+
*/
|
|
15809
|
+
async outputUsdValue() {
|
|
15810
|
+
return this.priceOutputs(this.outputs);
|
|
15811
|
+
}
|
|
15812
|
+
};
|
|
15813
|
+
var BidManager = class {
|
|
15814
|
+
/**
|
|
15815
|
+
* @param ctx - Shared IntentsV2 context providing the destination chain
|
|
15816
|
+
* client, coprocessor, bundler URL, and session-key storage.
|
|
15817
|
+
* @param crypto - Crypto utilities used for gas packing, UserOp hashing,
|
|
15818
|
+
* EIP-712 signing, and bundler calls.
|
|
15819
|
+
*/
|
|
15820
|
+
constructor(ctx, crypto) {
|
|
15821
|
+
this.ctx = ctx;
|
|
15822
|
+
this.crypto = crypto;
|
|
15823
|
+
}
|
|
15824
|
+
ctx;
|
|
15825
|
+
crypto;
|
|
15826
|
+
/**
|
|
15827
|
+
* Constructs a signed `PackedUserOperation` that a solver can submit to the
|
|
15828
|
+
* Hyperbridge coprocessor as a bid to fill an order.
|
|
15829
|
+
*
|
|
15830
|
+
* The solver's signature covers a hash that binds the UserOperation to the
|
|
15831
|
+
* order commitment and the session key address, so the IntentGatewayV2
|
|
15832
|
+
* contract can verify the solver's intent on-chain.
|
|
15833
|
+
*
|
|
15834
|
+
* @param options - Parameters describing the solver account, gas limits, fee
|
|
15835
|
+
* market values, and pre-built `callData` for the fill operation.
|
|
15836
|
+
* @returns A `PackedUserOperation` with the solver's signature prepended
|
|
15837
|
+
* with the order commitment.
|
|
15838
|
+
*/
|
|
15839
|
+
async prepareSubmitBid(options) {
|
|
15840
|
+
const {
|
|
15841
|
+
order,
|
|
15842
|
+
solverAccount,
|
|
15843
|
+
solverSigner,
|
|
15844
|
+
nonce,
|
|
15845
|
+
entryPointAddress,
|
|
15846
|
+
callGasLimit,
|
|
15847
|
+
verificationGasLimit,
|
|
15848
|
+
preVerificationGas,
|
|
15849
|
+
maxFeePerGas,
|
|
15850
|
+
maxPriorityFeePerGas,
|
|
15851
|
+
callData,
|
|
15852
|
+
paymasterAndData = "0x"
|
|
15853
|
+
} = options;
|
|
15854
|
+
const chainId = BigInt(
|
|
15855
|
+
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1])
|
|
15856
|
+
);
|
|
15857
|
+
const accountGasLimits = CryptoUtils.packGasLimits(verificationGasLimit, callGasLimit);
|
|
15858
|
+
const gasFees = CryptoUtils.packGasFees(maxPriorityFeePerGas, maxFeePerGas);
|
|
15859
|
+
const userOp = {
|
|
15860
|
+
sender: solverAccount,
|
|
15861
|
+
nonce,
|
|
15862
|
+
initCode: "0x",
|
|
15863
|
+
callData,
|
|
15864
|
+
accountGasLimits,
|
|
15865
|
+
preVerificationGas,
|
|
15866
|
+
gasFees,
|
|
15867
|
+
paymasterAndData,
|
|
15868
|
+
signature: "0x"
|
|
15869
|
+
};
|
|
15870
|
+
const userOpHash = CryptoUtils.computeUserOpHash(userOp, entryPointAddress, chainId);
|
|
15871
|
+
const sessionKey = order.session;
|
|
15872
|
+
const messageHash = viem.keccak256(viem.concat([userOpHash, order.id, sessionKey]));
|
|
15873
|
+
const solverSignature = await solverSigner.signMessage(messageHash, Number(chainId));
|
|
15874
|
+
const signature = viem.concat([order.id, solverSignature]);
|
|
15875
|
+
return { ...userOp, signature };
|
|
15876
|
+
}
|
|
15877
|
+
/**
|
|
15878
|
+
* Decodes raw filler bids into first-class {@link Bid} objects.
|
|
15879
|
+
*
|
|
15880
|
+
* Each bid's `fillOrder` fill-options are decoded from its ERC-7821 calldata;
|
|
15881
|
+
* bids whose calldata cannot be decoded into a valid `fillOrder` call are
|
|
15882
|
+
* silently dropped with a warning. The returned `Bid` instances are ready to
|
|
15883
|
+
* be ranked, simulated, and executed by the consumer.
|
|
15884
|
+
*
|
|
15885
|
+
* @param order - The placed order the bids are competing to fill.
|
|
15886
|
+
* @param bids - Raw filler bids fetched from the coprocessor.
|
|
15887
|
+
* @param sessionPrivateKey - Optional session-key override; looked up from
|
|
15888
|
+
* storage by `order.session` if omitted.
|
|
15889
|
+
* @returns Array of executable `Bid` objects (one per successfully decoded bid).
|
|
15890
|
+
*/
|
|
15891
|
+
buildBids(order, bids, sessionPrivateKey) {
|
|
15892
|
+
const chainId = this.ctx.dest.config.stateMachineId;
|
|
15893
|
+
const priceOutputs = (outputs) => this.computeOutputsUsdValue(outputs, chainId);
|
|
15894
|
+
const result = [];
|
|
15895
|
+
for (const fillerBid of bids) {
|
|
15896
|
+
const fillOptions = this.decodeBidFillOptions(fillerBid);
|
|
15897
|
+
if (!fillOptions) {
|
|
15898
|
+
console.warn(`[BidManager] Failed to decode fillOptions from bid by solver=${fillerBid.userOp.sender}`);
|
|
15899
|
+
continue;
|
|
15900
|
+
}
|
|
15901
|
+
result.push(
|
|
15902
|
+
new BidImpl({
|
|
15903
|
+
ctx: this.ctx,
|
|
15904
|
+
crypto: this.crypto,
|
|
15905
|
+
order,
|
|
15906
|
+
fillerBid,
|
|
15907
|
+
fillOptions,
|
|
15908
|
+
priceOutputs,
|
|
15909
|
+
sessionPrivateKey
|
|
15910
|
+
})
|
|
15911
|
+
);
|
|
15912
|
+
}
|
|
15913
|
+
console.log(`[BidManager] Built ${result.length}/${bids.length} bid(s) successfully`);
|
|
15914
|
+
return result;
|
|
15915
|
+
}
|
|
15916
|
+
/**
|
|
15917
|
+
* Decodes raw filler bids, sorts them, simulates each until one passes, signs
|
|
15918
|
+
* the `SelectSolver` message, and submits — all with no per-bid input from the
|
|
15919
|
+
* caller.
|
|
15920
|
+
*
|
|
15921
|
+
* Equivalent to `selectAndExecuteBest(order, buildBids(order, bids, key))`.
|
|
15922
|
+
*
|
|
15923
|
+
* @param order - The placed order to fill.
|
|
15924
|
+
* @param bids - Raw filler bids fetched from the coprocessor.
|
|
15925
|
+
* @param sessionPrivateKey - Optional session-key override; looked up from
|
|
15926
|
+
* storage by `order.session` if omitted.
|
|
15927
|
+
* @returns A {@link SelectBidResult} for the executed bid.
|
|
15928
|
+
*/
|
|
15929
|
+
async selectBid(order, bids, sessionPrivateKey) {
|
|
15930
|
+
return this.selectAndExecuteBest(order, this.buildBids(order, bids, sessionPrivateKey));
|
|
15931
|
+
}
|
|
15932
|
+
/**
|
|
15933
|
+
* Autopilot bid selection: sorts the given bids by output value, simulates
|
|
15934
|
+
* each in order until one passes, then executes that bid. For consumers that
|
|
15935
|
+
* do not need custom selection logic.
|
|
15936
|
+
*
|
|
15937
|
+
* @param order - The placed order to fill.
|
|
15938
|
+
* @param bids - Candidate bids (from {@link buildBids}).
|
|
15939
|
+
* @returns A {@link SelectBidResult} for the executed bid.
|
|
15940
|
+
* @throws If no valid bids exist, all simulations fail, or the bundler rejects
|
|
15941
|
+
* the UserOperation.
|
|
15942
|
+
*/
|
|
15943
|
+
async selectAndExecuteBest(order, bids) {
|
|
15944
|
+
const commitment = order.id;
|
|
15945
|
+
console.log(`[BidManager] selectAndExecuteBest called for commitment=${commitment}, ${bids.length} bid(s)`);
|
|
15946
|
+
if (!this.ctx.bundlerUrl) {
|
|
15947
|
+
throw new Error("Bundler URL not configured");
|
|
15948
|
+
}
|
|
15949
|
+
if (!this.ctx.intentsCoprocessor) {
|
|
15950
|
+
throw new Error("IntentsCoprocessor required");
|
|
15951
|
+
}
|
|
15952
|
+
const sortedBids = await this.sortBids(order, bids);
|
|
15953
|
+
console.log(`[BidManager] ${sortedBids.length}/${bids.length} bid(s) passed validation and sorting`);
|
|
15954
|
+
if (sortedBids.length === 0) {
|
|
15955
|
+
throw new Error("No valid bids found");
|
|
15956
|
+
}
|
|
15957
|
+
console.log(`[BidManager] Simulating ${sortedBids.length} sorted bid(s) to find a valid one`);
|
|
15958
|
+
for (let idx = 0; idx < sortedBids.length; idx++) {
|
|
15959
|
+
const bid = sortedBids[idx];
|
|
15960
|
+
console.log(`[BidManager] Simulating bid ${idx + 1}/${sortedBids.length} from solver=${bid.solverAddress}`);
|
|
15961
|
+
try {
|
|
15962
|
+
await bid.simulate();
|
|
15963
|
+
} catch (err) {
|
|
15964
|
+
console.warn(
|
|
15965
|
+
`[BidManager] Bid ${idx + 1} from solver=${bid.solverAddress}: simulation FAILED: ${err instanceof Error ? err.message : String(err)}`
|
|
15966
|
+
);
|
|
15967
|
+
continue;
|
|
15968
|
+
}
|
|
15969
|
+
console.log(`[BidManager] Bid ${idx + 1} from solver=${bid.solverAddress}: simulation PASSED`);
|
|
15970
|
+
return bid.execute();
|
|
15971
|
+
}
|
|
15972
|
+
console.error(`[BidManager] All ${sortedBids.length} bid(s) failed simulation for commitment=${commitment}`);
|
|
15973
|
+
throw new Error("No bids passed simulation");
|
|
15974
|
+
}
|
|
15975
|
+
/**
|
|
15976
|
+
* Sorts a list of bids for the given order by output value.
|
|
15806
15977
|
*
|
|
15807
15978
|
* Delegates to one of three strategies based on the order's output token
|
|
15808
15979
|
* composition:
|
|
@@ -15811,47 +15982,26 @@ var BidManager = class {
|
|
|
15811
15982
|
* - Mixed outputs: sort by DEX-quoted USD value descending, with a raw-amount
|
|
15812
15983
|
* fallback if pricing fails.
|
|
15813
15984
|
*
|
|
15814
|
-
*
|
|
15985
|
+
* Bids that cannot satisfy the order's token set are dropped.
|
|
15986
|
+
*
|
|
15815
15987
|
* @param order - The placed order whose output spec drives sorting logic.
|
|
15816
|
-
* @
|
|
15988
|
+
* @param bids - Executable bids to sort (from {@link buildBids}).
|
|
15989
|
+
* @returns Sorted array of `Bid` objects ready for simulation.
|
|
15817
15990
|
*/
|
|
15818
|
-
async
|
|
15991
|
+
async sortBids(order, bids) {
|
|
15819
15992
|
const outputs = order.output.assets;
|
|
15820
|
-
const decodedBids = this.decodeBids(bids);
|
|
15821
15993
|
if (outputs.length <= 1) {
|
|
15822
15994
|
console.log(`[BidManager] Using single-output sorting (1 output asset)`);
|
|
15823
|
-
return this.sortSingleOutput(
|
|
15995
|
+
return this.sortSingleOutput(bids, outputs[0]);
|
|
15824
15996
|
}
|
|
15825
15997
|
const chainId = this.ctx.dest.config.stateMachineId;
|
|
15826
15998
|
const allStables = outputs.every((o) => this.isStableToken(bytes32ToBytes20(o.token), chainId));
|
|
15827
15999
|
if (allStables) {
|
|
15828
16000
|
console.log(`[BidManager] Using all-stables sorting (${outputs.length} stable output assets)`);
|
|
15829
|
-
return this.sortAllStables(
|
|
16001
|
+
return this.sortAllStables(bids, outputs, chainId);
|
|
15830
16002
|
}
|
|
15831
16003
|
console.log(`[BidManager] Using mixed-output sorting (${outputs.length} output assets, some non-stable)`);
|
|
15832
|
-
return this.sortMixedOutputs(
|
|
15833
|
-
}
|
|
15834
|
-
/**
|
|
15835
|
-
* Decodes the `fillOrder` fill-options from each bid's ERC-7821 calldata.
|
|
15836
|
-
*
|
|
15837
|
-
* Bids whose calldata cannot be decoded or do not contain a valid
|
|
15838
|
-
* `fillOrder` call are silently dropped with a warning.
|
|
15839
|
-
*
|
|
15840
|
-
* @param bids - Raw bids to decode.
|
|
15841
|
-
* @returns Array of successfully decoded `{ bid, options }` pairs.
|
|
15842
|
-
*/
|
|
15843
|
-
decodeBids(bids) {
|
|
15844
|
-
const result = [];
|
|
15845
|
-
for (const bid of bids) {
|
|
15846
|
-
const fillOptions = this.decodeBidFillOptions(bid);
|
|
15847
|
-
if (fillOptions) {
|
|
15848
|
-
result.push({ bid, options: fillOptions });
|
|
15849
|
-
} else {
|
|
15850
|
-
console.warn(`[BidManager] Failed to decode fillOptions from bid by solver=${bid.userOp.sender}`);
|
|
15851
|
-
}
|
|
15852
|
-
}
|
|
15853
|
-
console.log(`[BidManager] Decoded ${result.length}/${bids.length} bid(s) successfully`);
|
|
15854
|
-
return result;
|
|
16004
|
+
return this.sortMixedOutputs(bids, outputs, chainId);
|
|
15855
16005
|
}
|
|
15856
16006
|
/**
|
|
15857
16007
|
* Extracts the `FillOptions` struct from a single bid's ERC-7821
|
|
@@ -15884,149 +16034,103 @@ var BidManager = class {
|
|
|
15884
16034
|
}
|
|
15885
16035
|
return null;
|
|
15886
16036
|
}
|
|
15887
|
-
/**
|
|
15888
|
-
* Simulates a bid on-chain by batching the `select` and `fillOrder` calls
|
|
15889
|
-
* via `eth_call` from the solver's account, using the IntentGatewayV2
|
|
15890
|
-
* ERC-7821 batch-execute pattern.
|
|
15891
|
-
*
|
|
15892
|
-
* The native value forwarded to the simulation is computed from the fill options:
|
|
15893
|
-
* sum of any native-token (address(0)) output amounts plus the dispatch fee.
|
|
15894
|
-
*
|
|
15895
|
-
* @param bid - The filler bid to simulate.
|
|
15896
|
-
* @param fillOptions - Decoded fill options from the bid's calldata.
|
|
15897
|
-
* @param selectOptions - The signed solver-selection parameters.
|
|
15898
|
-
* @param intentGatewayV2Address - Address of the IntentGatewayV2 contract on the destination chain.
|
|
15899
|
-
* @throws If the `eth_call` simulation reverts or errors.
|
|
15900
|
-
*/
|
|
15901
|
-
async simulate(bid, fillOptions, selectOptions, intentGatewayV2Address) {
|
|
15902
|
-
const solverAddress = bid.userOp.sender;
|
|
15903
|
-
const nativeOutputs = fillOptions.outputs.reduce(
|
|
15904
|
-
(acc, o) => bytes32ToBytes20(o.token) === ADDRESS_ZERO2 ? acc + o.amount : acc,
|
|
15905
|
-
0n
|
|
15906
|
-
);
|
|
15907
|
-
const simulationValue = nativeOutputs + fillOptions.nativeDispatchFee;
|
|
15908
|
-
const selectCalldata = viem.encodeFunctionData({
|
|
15909
|
-
abi: ABI3,
|
|
15910
|
-
functionName: "select",
|
|
15911
|
-
args: [selectOptions]
|
|
15912
|
-
});
|
|
15913
|
-
const calls = [
|
|
15914
|
-
{ target: intentGatewayV2Address, value: 0n, data: selectCalldata },
|
|
15915
|
-
{ target: solverAddress, value: simulationValue, data: bid.userOp.callData }
|
|
15916
|
-
];
|
|
15917
|
-
const batchedCalldata = this.crypto.encodeERC7821Execute(calls);
|
|
15918
|
-
try {
|
|
15919
|
-
await this.ctx.dest.client.call({
|
|
15920
|
-
account: solverAddress,
|
|
15921
|
-
to: solverAddress,
|
|
15922
|
-
data: batchedCalldata,
|
|
15923
|
-
value: simulationValue
|
|
15924
|
-
});
|
|
15925
|
-
} catch (e) {
|
|
15926
|
-
throw new Error(`Simulation failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
15927
|
-
}
|
|
15928
|
-
}
|
|
15929
16037
|
/**
|
|
15930
16038
|
* Case A: single output token.
|
|
15931
16039
|
* Filter bids by token match only, sort descending by amount.
|
|
15932
16040
|
* Partial fill bids are allowed — the contract determines fill status.
|
|
15933
16041
|
*/
|
|
15934
|
-
sortSingleOutput(
|
|
16042
|
+
sortSingleOutput(bids, requiredAsset) {
|
|
15935
16043
|
const requiredAmount = new Decimal2__default.default(requiredAsset.amount.toString());
|
|
15936
16044
|
console.log(
|
|
15937
16045
|
`[BidManager] sortSingleOutput: required token=${requiredAsset.token}, amount=${requiredAmount.toString()}`
|
|
15938
16046
|
);
|
|
15939
16047
|
const validBids = [];
|
|
15940
|
-
for (const
|
|
15941
|
-
const bidOutput =
|
|
16048
|
+
for (const bid of bids) {
|
|
16049
|
+
const bidOutput = bid.outputs[0];
|
|
15942
16050
|
const bidAmount = new Decimal2__default.default(bidOutput.amount.toString());
|
|
15943
16051
|
if (bidOutput.token.toLowerCase() !== requiredAsset.token.toLowerCase()) {
|
|
15944
16052
|
console.warn(
|
|
15945
|
-
`[BidManager] Bid from solver=${bid.
|
|
16053
|
+
`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: token mismatch (bid=${bidOutput.token}, required=${requiredAsset.token})`
|
|
15946
16054
|
);
|
|
15947
16055
|
continue;
|
|
15948
16056
|
}
|
|
15949
16057
|
if (bidAmount.lt(requiredAmount)) {
|
|
15950
16058
|
console.log(
|
|
15951
|
-
`[BidManager] Bid from solver=${bid.
|
|
16059
|
+
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidAmount.toString()}, required=${requiredAmount.toString()}, covers=${bidAmount.div(requiredAmount).mul(100).toFixed(2)}%)`
|
|
15952
16060
|
);
|
|
15953
16061
|
} else {
|
|
15954
16062
|
console.log(
|
|
15955
|
-
`[BidManager] Bid from solver=${bid.
|
|
16063
|
+
`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: amount=${bidAmount.toString()} (surplus=${bidAmount.minus(requiredAmount).toString()})`
|
|
15956
16064
|
);
|
|
15957
16065
|
}
|
|
15958
|
-
validBids.push({ bid,
|
|
16066
|
+
validBids.push({ bid, amount: bidOutput.amount });
|
|
15959
16067
|
}
|
|
15960
16068
|
validBids.sort((a, b) => {
|
|
15961
16069
|
const aAmt = new Decimal2__default.default(a.amount.toString());
|
|
15962
16070
|
const bAmt = new Decimal2__default.default(b.amount.toString());
|
|
15963
16071
|
return bAmt.comparedTo(aAmt);
|
|
15964
16072
|
});
|
|
15965
|
-
return validBids.map(({
|
|
16073
|
+
return validBids.map(({ bid }) => bid);
|
|
15966
16074
|
}
|
|
15967
16075
|
/**
|
|
15968
16076
|
* Case B: all outputs are USDC/USDT.
|
|
15969
16077
|
* Sum normalised USD values (treating each stable as $1) and sort descending.
|
|
15970
16078
|
* Partial fill bids are allowed.
|
|
15971
16079
|
*/
|
|
15972
|
-
sortAllStables(
|
|
16080
|
+
sortAllStables(bids, orderOutputs, chainId) {
|
|
15973
16081
|
const requiredUsd = this.computeStablesUsdValue(orderOutputs, chainId);
|
|
15974
16082
|
console.log(`[BidManager] sortAllStables: required USD value=${requiredUsd.toString()}`);
|
|
15975
16083
|
const validBids = [];
|
|
15976
|
-
for (const
|
|
15977
|
-
const bidUsd = this.computeStablesUsdValue(
|
|
16084
|
+
for (const bid of bids) {
|
|
16085
|
+
const bidUsd = this.computeStablesUsdValue(bid.outputs, chainId);
|
|
15978
16086
|
if (bidUsd === null) {
|
|
15979
|
-
console.warn(`[BidManager] Bid from solver=${bid.
|
|
16087
|
+
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: unable to compute USD value`);
|
|
15980
16088
|
continue;
|
|
15981
16089
|
}
|
|
15982
16090
|
if (bidUsd.lt(requiredUsd)) {
|
|
15983
16091
|
console.log(
|
|
15984
|
-
`[BidManager] Bid from solver=${bid.
|
|
16092
|
+
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidUsd.toString()}, required=${requiredUsd.toString()}, covers=${bidUsd.div(requiredUsd).mul(100).toFixed(2)}%)`
|
|
15985
16093
|
);
|
|
15986
16094
|
} else {
|
|
15987
|
-
console.log(
|
|
15988
|
-
`[BidManager] Bid from solver=${bid.userOp.sender} ACCEPTED: USD value=${bidUsd.toString()}`
|
|
15989
|
-
);
|
|
16095
|
+
console.log(`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: USD value=${bidUsd.toString()}`);
|
|
15990
16096
|
}
|
|
15991
|
-
validBids.push({ bid,
|
|
16097
|
+
validBids.push({ bid, usdValue: bidUsd });
|
|
15992
16098
|
}
|
|
15993
16099
|
validBids.sort((a, b) => b.usdValue.comparedTo(a.usdValue));
|
|
15994
|
-
return validBids.map(({
|
|
16100
|
+
return validBids.map(({ bid }) => bid);
|
|
15995
16101
|
}
|
|
15996
16102
|
/**
|
|
15997
16103
|
* Case C: mixed output tokens (at least one non-stable).
|
|
15998
16104
|
* Price every token via on-chain DEX quotes, fall back to raw amounts
|
|
15999
16105
|
* if pricing is unavailable. Partial fill bids are allowed.
|
|
16000
16106
|
*/
|
|
16001
|
-
async sortMixedOutputs(
|
|
16107
|
+
async sortMixedOutputs(bids, orderOutputs, chainId) {
|
|
16002
16108
|
const requiredUsd = await this.computeOutputsUsdValue(orderOutputs, chainId);
|
|
16003
16109
|
if (requiredUsd === null) {
|
|
16004
16110
|
console.warn("[BidManager] sortMixedOutputs: output tokens unpriceable, falling back to raw-amount sort");
|
|
16005
|
-
return this.sortByRawAmountFallback(
|
|
16111
|
+
return this.sortByRawAmountFallback(bids, orderOutputs);
|
|
16006
16112
|
}
|
|
16007
16113
|
console.log(`[BidManager] sortMixedOutputs: required USD value=${requiredUsd.toString()}`);
|
|
16008
16114
|
const validBids = [];
|
|
16009
|
-
for (const
|
|
16010
|
-
const bidUsd = await this.computeOutputsUsdValue(
|
|
16115
|
+
for (const bid of bids) {
|
|
16116
|
+
const bidUsd = await this.computeOutputsUsdValue(bid.outputs, chainId);
|
|
16011
16117
|
if (bidUsd === null) {
|
|
16012
|
-
console.warn(
|
|
16013
|
-
`[BidManager] Bid from solver=${bid.userOp.sender} REJECTED: unable to price mixed outputs`
|
|
16014
|
-
);
|
|
16118
|
+
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED: unable to price mixed outputs`);
|
|
16015
16119
|
continue;
|
|
16016
16120
|
}
|
|
16017
16121
|
if (bidUsd.lt(requiredUsd)) {
|
|
16018
16122
|
console.log(
|
|
16019
|
-
`[BidManager] Bid from solver=${bid.
|
|
16123
|
+
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (bid=${bidUsd.toString()}, required=${requiredUsd.toString()}, covers=${bidUsd.div(requiredUsd).mul(100).toFixed(2)}%)`
|
|
16020
16124
|
);
|
|
16021
16125
|
} else {
|
|
16022
16126
|
console.log(
|
|
16023
|
-
`[BidManager] Bid from solver=${bid.
|
|
16127
|
+
`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED: mixed USD value=${bidUsd.toString()}`
|
|
16024
16128
|
);
|
|
16025
16129
|
}
|
|
16026
|
-
validBids.push({ bid,
|
|
16130
|
+
validBids.push({ bid, usdValue: bidUsd });
|
|
16027
16131
|
}
|
|
16028
16132
|
validBids.sort((a, b) => b.usdValue.comparedTo(a.usdValue));
|
|
16029
|
-
return validBids.map(({
|
|
16133
|
+
return validBids.map(({ bid }) => bid);
|
|
16030
16134
|
}
|
|
16031
16135
|
/**
|
|
16032
16136
|
* Fallback when DEX pricing is unavailable.
|
|
@@ -16034,17 +16138,17 @@ var BidManager = class {
|
|
|
16034
16138
|
* Bids offering less than required for a token are allowed (partial fill).
|
|
16035
16139
|
* Sorted by total offered amount descending.
|
|
16036
16140
|
*/
|
|
16037
|
-
sortByRawAmountFallback(
|
|
16141
|
+
sortByRawAmountFallback(bids, orderOutputs) {
|
|
16038
16142
|
console.log(
|
|
16039
|
-
`[BidManager] sortByRawAmountFallback: checking ${
|
|
16143
|
+
`[BidManager] sortByRawAmountFallback: checking ${bids.length} bid(s) against ${orderOutputs.length} required output(s)`
|
|
16040
16144
|
);
|
|
16041
16145
|
const validBids = [];
|
|
16042
|
-
for (const
|
|
16146
|
+
for (const bid of bids) {
|
|
16043
16147
|
let valid = true;
|
|
16044
16148
|
let totalOffered = new Decimal2__default.default(0);
|
|
16045
16149
|
let rejectReason = "";
|
|
16046
16150
|
for (const required of orderOutputs) {
|
|
16047
|
-
const matching =
|
|
16151
|
+
const matching = bid.outputs.find((o) => o.token.toLowerCase() === required.token.toLowerCase());
|
|
16048
16152
|
if (!matching) {
|
|
16049
16153
|
valid = false;
|
|
16050
16154
|
rejectReason = `missing output token=${required.token}`;
|
|
@@ -16053,7 +16157,7 @@ var BidManager = class {
|
|
|
16053
16157
|
totalOffered = totalOffered.plus(new Decimal2__default.default(matching.amount.toString()));
|
|
16054
16158
|
}
|
|
16055
16159
|
if (!valid) {
|
|
16056
|
-
console.warn(`[BidManager] Bid from solver=${bid.
|
|
16160
|
+
console.warn(`[BidManager] Bid from solver=${bid.solverAddress} REJECTED (fallback): ${rejectReason}`);
|
|
16057
16161
|
continue;
|
|
16058
16162
|
}
|
|
16059
16163
|
const totalRequired = orderOutputs.reduce(
|
|
@@ -16062,17 +16166,17 @@ var BidManager = class {
|
|
|
16062
16166
|
);
|
|
16063
16167
|
if (totalOffered.lt(totalRequired)) {
|
|
16064
16168
|
console.log(
|
|
16065
|
-
`[BidManager] Bid from solver=${bid.
|
|
16169
|
+
`[BidManager] Bid from solver=${bid.solverAddress}: partial fill candidate (fallback) (offered=${totalOffered.toString()}, required=${totalRequired.toString()}, covers=${totalOffered.div(totalRequired).mul(100).toFixed(2)}%)`
|
|
16066
16170
|
);
|
|
16067
16171
|
} else {
|
|
16068
16172
|
console.log(
|
|
16069
|
-
`[BidManager] Bid from solver=${bid.
|
|
16173
|
+
`[BidManager] Bid from solver=${bid.solverAddress} ACCEPTED (fallback): totalOffered=${totalOffered.toString()}`
|
|
16070
16174
|
);
|
|
16071
16175
|
}
|
|
16072
|
-
validBids.push({ bid,
|
|
16176
|
+
validBids.push({ bid, totalOffered });
|
|
16073
16177
|
}
|
|
16074
16178
|
validBids.sort((a, b) => b.totalOffered.comparedTo(a.totalOffered));
|
|
16075
|
-
return validBids.map(({
|
|
16179
|
+
return validBids.map(({ bid }) => bid);
|
|
16076
16180
|
}
|
|
16077
16181
|
// ── Token classification helpers ──────────────────────────────────
|
|
16078
16182
|
/**
|
|
@@ -16681,6 +16785,262 @@ var OrderStatusChecker = class {
|
|
|
16681
16785
|
}
|
|
16682
16786
|
};
|
|
16683
16787
|
|
|
16788
|
+
// src/protocols/intents/quote/types.ts
|
|
16789
|
+
var UnsupportedIntentQuoteStrategyError = class extends Error {
|
|
16790
|
+
constructor(strategy) {
|
|
16791
|
+
super(`Unsupported intent quote strategy: ${strategy}`);
|
|
16792
|
+
this.name = "UnsupportedIntentQuoteStrategyError";
|
|
16793
|
+
}
|
|
16794
|
+
};
|
|
16795
|
+
var UnsupportedIntentQuotePairError = class extends Error {
|
|
16796
|
+
constructor(params) {
|
|
16797
|
+
super(
|
|
16798
|
+
`No Uniswap v4 pool config found for ${params.tokenIn.symbol ?? params.tokenIn.address} -> ${params.tokenOut.symbol ?? params.tokenOut.address} on ${params.source} -> ${params.destination}`
|
|
16799
|
+
);
|
|
16800
|
+
this.name = "UnsupportedIntentQuotePairError";
|
|
16801
|
+
}
|
|
16802
|
+
};
|
|
16803
|
+
|
|
16804
|
+
// src/protocols/intents/quote/uniswapV4.ts
|
|
16805
|
+
var UNISWAP_INTENT_QUOTE_CHAIN = "EVM-8453" /* BASE_MAINNET */;
|
|
16806
|
+
var BPS_DENOMINATOR = 10000n;
|
|
16807
|
+
var UniswapV4IntentQuoteStrategy = class {
|
|
16808
|
+
constructor(chainConfigService) {
|
|
16809
|
+
this.chainConfigService = chainConfigService;
|
|
16810
|
+
}
|
|
16811
|
+
chainConfigService;
|
|
16812
|
+
baseQuoteClient;
|
|
16813
|
+
async quote(params, source, destination) {
|
|
16814
|
+
this.validateQuoteParams(params);
|
|
16815
|
+
const protocolFeeBps = await this.readProtocolFeeBps(source.client, source.stateMachineId);
|
|
16816
|
+
const quoteClient = this.resolveQuoteClient(source, destination);
|
|
16817
|
+
const poolConfig = this.resolvePoolConfig(params, source.stateMachineId, UNISWAP_INTENT_QUOTE_CHAIN);
|
|
16818
|
+
return params.amountIn !== void 0 ? this.quoteExactInput({ params, client: quoteClient, protocolFeeBps, poolConfig }) : this.quoteExactOutput({ params, client: quoteClient, protocolFeeBps, poolConfig });
|
|
16819
|
+
}
|
|
16820
|
+
resolveQuoteClient(source, destination) {
|
|
16821
|
+
if (source.stateMachineId === UNISWAP_INTENT_QUOTE_CHAIN) return source.client;
|
|
16822
|
+
if (destination.stateMachineId === UNISWAP_INTENT_QUOTE_CHAIN) return destination.client;
|
|
16823
|
+
if (this.baseQuoteClient) return this.baseQuoteClient;
|
|
16824
|
+
const rpcUrl = this.chainConfigService.getRpcUrl(UNISWAP_INTENT_QUOTE_CHAIN);
|
|
16825
|
+
if (!rpcUrl) throw new Error(`RPC URL is not configured for ${UNISWAP_INTENT_QUOTE_CHAIN}`);
|
|
16826
|
+
const baseQuoteClient = viem.createPublicClient({
|
|
16827
|
+
chain: chains$1.base,
|
|
16828
|
+
transport: viem.http(rpcUrl)
|
|
16829
|
+
});
|
|
16830
|
+
this.baseQuoteClient = baseQuoteClient;
|
|
16831
|
+
return baseQuoteClient;
|
|
16832
|
+
}
|
|
16833
|
+
validateQuoteParams(params) {
|
|
16834
|
+
const hasAmountIn = params.amountIn !== void 0;
|
|
16835
|
+
const hasAmountOut = params.amountOut !== void 0;
|
|
16836
|
+
if (hasAmountIn === hasAmountOut) throw new Error("Provide exactly one of amountIn or amountOut");
|
|
16837
|
+
if (hasAmountIn && params.amountIn <= 0n) throw new Error("amountIn must be greater than zero");
|
|
16838
|
+
if (hasAmountOut && params.amountOut <= 0n) throw new Error("amountOut must be greater than zero");
|
|
16839
|
+
if (params.tokenIn.address.toLowerCase() === params.tokenOut.address.toLowerCase()) {
|
|
16840
|
+
throw new Error("tokenIn and tokenOut cannot be the same");
|
|
16841
|
+
}
|
|
16842
|
+
}
|
|
16843
|
+
async readProtocolFeeBps(client, chain) {
|
|
16844
|
+
const gatewayAddress = this.chainConfigService.getIntentGatewayAddress(chain);
|
|
16845
|
+
if (!gatewayAddress || gatewayAddress === "0x" || gatewayAddress === viem.zeroAddress) {
|
|
16846
|
+
throw new Error(`IntentGatewayV2 is not configured for chain ${chain}`);
|
|
16847
|
+
}
|
|
16848
|
+
const gatewayParams = await client.readContract({
|
|
16849
|
+
address: gatewayAddress,
|
|
16850
|
+
abi: IntentGatewayV2_default.ABI,
|
|
16851
|
+
functionName: "params"
|
|
16852
|
+
});
|
|
16853
|
+
if (isGatewayParamsTuple(gatewayParams)) return BigInt(gatewayParams[4]);
|
|
16854
|
+
return BigInt(gatewayParams.protocolFeeBps ?? 0);
|
|
16855
|
+
}
|
|
16856
|
+
resolvePoolConfig(params, source, destination) {
|
|
16857
|
+
const override = params.uniswapV4?.poolKey;
|
|
16858
|
+
if (override) {
|
|
16859
|
+
const poolKey = normalizePoolKey(override);
|
|
16860
|
+
const tokenInForQuote = viem.getAddress(override.currencyIn ?? params.tokenIn.address);
|
|
16861
|
+
if (tokenInForQuote !== poolKey.currency0 && tokenInForQuote !== poolKey.currency1) {
|
|
16862
|
+
throw new Error(
|
|
16863
|
+
`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.`
|
|
16864
|
+
);
|
|
16865
|
+
}
|
|
16866
|
+
return {
|
|
16867
|
+
poolKey,
|
|
16868
|
+
quoterAddress: this.resolveQuoterAddress(destination, override.quoterAddress),
|
|
16869
|
+
tokenInForQuote
|
|
16870
|
+
};
|
|
16871
|
+
}
|
|
16872
|
+
const poolConfig = this.resolveConfiguredPool(params, destination);
|
|
16873
|
+
if (poolConfig) return poolConfig;
|
|
16874
|
+
throw new UnsupportedIntentQuotePairError({
|
|
16875
|
+
source,
|
|
16876
|
+
destination,
|
|
16877
|
+
tokenIn: params.tokenIn,
|
|
16878
|
+
tokenOut: params.tokenOut
|
|
16879
|
+
});
|
|
16880
|
+
}
|
|
16881
|
+
resolveConfiguredPool(params, chain) {
|
|
16882
|
+
for (const pool of this.chainConfigService.getUniswapV4PoolConfigs(chain)) {
|
|
16883
|
+
const resolvedPool = this.resolveConfiguredPoolTokens(chain, pool);
|
|
16884
|
+
if (!resolvedPool) continue;
|
|
16885
|
+
const tokenInForQuote = matchPoolToken(params.tokenIn, resolvedPool);
|
|
16886
|
+
const tokenOutForQuote = matchPoolToken(params.tokenOut, resolvedPool);
|
|
16887
|
+
if (!tokenInForQuote || !tokenOutForQuote || tokenInForQuote.symbol === tokenOutForQuote.symbol) continue;
|
|
16888
|
+
const { currency0, currency1 } = sortCurrencies(resolvedPool[0].address, resolvedPool[1].address);
|
|
16889
|
+
return {
|
|
16890
|
+
poolKey: {
|
|
16891
|
+
currency0,
|
|
16892
|
+
currency1,
|
|
16893
|
+
fee: pool.fee,
|
|
16894
|
+
tickSpacing: pool.tickSpacing,
|
|
16895
|
+
hooks: viem.getAddress(pool.hooks ?? viem.zeroAddress)
|
|
16896
|
+
},
|
|
16897
|
+
quoterAddress: this.resolveQuoterAddress(chain),
|
|
16898
|
+
tokenInForQuote: tokenInForQuote.address
|
|
16899
|
+
};
|
|
16900
|
+
}
|
|
16901
|
+
return null;
|
|
16902
|
+
}
|
|
16903
|
+
resolveQuoterAddress(chain, override) {
|
|
16904
|
+
const address = override ?? this.chainConfigService.getUniswapV4QuoterAddress(chain);
|
|
16905
|
+
if (!address || address === "0x" || address === viem.zeroAddress) {
|
|
16906
|
+
throw new Error(`Uniswap V4 quoter is not configured for chain ${chain}`);
|
|
16907
|
+
}
|
|
16908
|
+
return viem.getAddress(address);
|
|
16909
|
+
}
|
|
16910
|
+
resolveConfiguredPoolTokens(chain, pool) {
|
|
16911
|
+
const first = this.resolveConfiguredPoolToken(chain, pool.tokens[0]);
|
|
16912
|
+
const second = this.resolveConfiguredPoolToken(chain, pool.tokens[1]);
|
|
16913
|
+
return first && second ? [first, second] : null;
|
|
16914
|
+
}
|
|
16915
|
+
resolveConfiguredPoolToken(chain, symbol) {
|
|
16916
|
+
const address = this.chainConfigService.getAssetAddress(chain, symbol);
|
|
16917
|
+
if (!address || address === "0x") return null;
|
|
16918
|
+
return { symbol, address: viem.getAddress(address) };
|
|
16919
|
+
}
|
|
16920
|
+
async quoteExactInput(args) {
|
|
16921
|
+
const amountIn = args.params.amountIn;
|
|
16922
|
+
const swapAmountIn = deductProtocolFee(amountIn, args.protocolFeeBps);
|
|
16923
|
+
const amountOut = await this.readV4QuoteExactInput(args.client, args.poolConfig, swapAmountIn);
|
|
16924
|
+
return {
|
|
16925
|
+
strategy: "uniswap_v4",
|
|
16926
|
+
tradeType: "EXACT_INPUT",
|
|
16927
|
+
amountIn,
|
|
16928
|
+
amountOut,
|
|
16929
|
+
quoteMetadata: {
|
|
16930
|
+
quoteChain: UNISWAP_INTENT_QUOTE_CHAIN,
|
|
16931
|
+
poolKey: args.poolConfig.poolKey,
|
|
16932
|
+
quoterAddress: args.poolConfig.quoterAddress,
|
|
16933
|
+
protocolFeeBps: args.protocolFeeBps
|
|
16934
|
+
}
|
|
16935
|
+
};
|
|
16936
|
+
}
|
|
16937
|
+
async quoteExactOutput(args) {
|
|
16938
|
+
const amountOut = args.params.amountOut;
|
|
16939
|
+
const swapAmountIn = await this.readV4QuoteExactOutput(args.client, args.poolConfig, amountOut);
|
|
16940
|
+
const amountIn = grossUpForProtocolFee(swapAmountIn, args.protocolFeeBps);
|
|
16941
|
+
return {
|
|
16942
|
+
strategy: "uniswap_v4",
|
|
16943
|
+
tradeType: "EXACT_OUTPUT",
|
|
16944
|
+
amountIn,
|
|
16945
|
+
amountOut,
|
|
16946
|
+
quoteMetadata: {
|
|
16947
|
+
quoteChain: UNISWAP_INTENT_QUOTE_CHAIN,
|
|
16948
|
+
poolKey: args.poolConfig.poolKey,
|
|
16949
|
+
quoterAddress: args.poolConfig.quoterAddress,
|
|
16950
|
+
protocolFeeBps: args.protocolFeeBps
|
|
16951
|
+
}
|
|
16952
|
+
};
|
|
16953
|
+
}
|
|
16954
|
+
async readV4QuoteExactInput(client, poolConfig, amountIn) {
|
|
16955
|
+
const data = viem.encodeFunctionData({
|
|
16956
|
+
abi: UNISWAP_V4_QUOTER_ABI,
|
|
16957
|
+
functionName: "quoteExactInputSingle",
|
|
16958
|
+
args: [
|
|
16959
|
+
{
|
|
16960
|
+
poolKey: poolConfig.poolKey,
|
|
16961
|
+
zeroForOne: getZeroForOne(poolConfig.tokenInForQuote, poolConfig.poolKey),
|
|
16962
|
+
exactAmount: amountIn,
|
|
16963
|
+
hookData: "0x"
|
|
16964
|
+
}
|
|
16965
|
+
]
|
|
16966
|
+
});
|
|
16967
|
+
const response = await client.call({ to: poolConfig.quoterAddress, data });
|
|
16968
|
+
if (!response.data || response.data === "0x") {
|
|
16969
|
+
throw new Error(`Uniswap V4 quoter at ${poolConfig.quoterAddress} returned no data`);
|
|
16970
|
+
}
|
|
16971
|
+
const [amountOut] = viem.decodeFunctionResult({
|
|
16972
|
+
abi: UNISWAP_V4_QUOTER_ABI,
|
|
16973
|
+
functionName: "quoteExactInputSingle",
|
|
16974
|
+
data: response.data
|
|
16975
|
+
});
|
|
16976
|
+
return amountOut;
|
|
16977
|
+
}
|
|
16978
|
+
async readV4QuoteExactOutput(client, poolConfig, amountOut) {
|
|
16979
|
+
const data = viem.encodeFunctionData({
|
|
16980
|
+
abi: UNISWAP_V4_QUOTER_ABI,
|
|
16981
|
+
functionName: "quoteExactOutputSingle",
|
|
16982
|
+
args: [
|
|
16983
|
+
{
|
|
16984
|
+
poolKey: poolConfig.poolKey,
|
|
16985
|
+
zeroForOne: getZeroForOne(poolConfig.tokenInForQuote, poolConfig.poolKey),
|
|
16986
|
+
exactAmount: amountOut,
|
|
16987
|
+
hookData: "0x"
|
|
16988
|
+
}
|
|
16989
|
+
]
|
|
16990
|
+
});
|
|
16991
|
+
const response = await client.call({ to: poolConfig.quoterAddress, data });
|
|
16992
|
+
if (!response.data || response.data === "0x") {
|
|
16993
|
+
throw new Error(`Uniswap V4 quoter at ${poolConfig.quoterAddress} returned no data`);
|
|
16994
|
+
}
|
|
16995
|
+
const [amountIn] = viem.decodeFunctionResult({
|
|
16996
|
+
abi: UNISWAP_V4_QUOTER_ABI,
|
|
16997
|
+
functionName: "quoteExactOutputSingle",
|
|
16998
|
+
data: response.data
|
|
16999
|
+
});
|
|
17000
|
+
return amountIn;
|
|
17001
|
+
}
|
|
17002
|
+
};
|
|
17003
|
+
function normalizePoolKey(poolKey) {
|
|
17004
|
+
return {
|
|
17005
|
+
currency0: viem.getAddress(poolKey.currency0),
|
|
17006
|
+
currency1: viem.getAddress(poolKey.currency1),
|
|
17007
|
+
fee: poolKey.fee,
|
|
17008
|
+
tickSpacing: poolKey.tickSpacing,
|
|
17009
|
+
hooks: viem.getAddress(poolKey.hooks)
|
|
17010
|
+
};
|
|
17011
|
+
}
|
|
17012
|
+
function sortCurrencies(tokenIn, tokenOut) {
|
|
17013
|
+
const input = viem.getAddress(tokenIn);
|
|
17014
|
+
const output = viem.getAddress(tokenOut);
|
|
17015
|
+
return BigInt(input) < BigInt(output) ? { currency0: input, currency1: output } : { currency0: output, currency1: input };
|
|
17016
|
+
}
|
|
17017
|
+
function matchPoolToken(token, poolTokens) {
|
|
17018
|
+
const tokenAddress = token.address.toLowerCase();
|
|
17019
|
+
const addressMatch = poolTokens.find((poolToken) => poolToken.address.toLowerCase() === tokenAddress);
|
|
17020
|
+
if (addressMatch) return addressMatch;
|
|
17021
|
+
const tokenSymbol = token.symbol?.toUpperCase();
|
|
17022
|
+
if (!tokenSymbol) return null;
|
|
17023
|
+
return poolTokens.find((poolToken) => poolToken.symbol.toUpperCase() === tokenSymbol) ?? null;
|
|
17024
|
+
}
|
|
17025
|
+
function getZeroForOne(tokenIn, poolKey) {
|
|
17026
|
+
return viem.getAddress(tokenIn).toLowerCase() === viem.getAddress(poolKey.currency0).toLowerCase();
|
|
17027
|
+
}
|
|
17028
|
+
function isGatewayParamsTuple(value) {
|
|
17029
|
+
return Array.isArray(value);
|
|
17030
|
+
}
|
|
17031
|
+
function deductProtocolFee(amount, protocolFeeBps) {
|
|
17032
|
+
if (protocolFeeBps <= 0n) return amount;
|
|
17033
|
+
const fee = amount * protocolFeeBps / BPS_DENOMINATOR;
|
|
17034
|
+
return amount - fee;
|
|
17035
|
+
}
|
|
17036
|
+
function grossUpForProtocolFee(netAmount, protocolFeeBps) {
|
|
17037
|
+
if (protocolFeeBps <= 0n) return netAmount;
|
|
17038
|
+
return divCeil(netAmount * BPS_DENOMINATOR, BPS_DENOMINATOR - protocolFeeBps);
|
|
17039
|
+
}
|
|
17040
|
+
function divCeil(numerator, denominator) {
|
|
17041
|
+
return (numerator + denominator - 1n) / denominator;
|
|
17042
|
+
}
|
|
17043
|
+
|
|
16684
17044
|
// src/protocols/intents/IntentGateway.ts
|
|
16685
17045
|
var IntentGateway = class _IntentGateway {
|
|
16686
17046
|
/** EVM chain on which orders are placed and escrowed. */
|
|
@@ -16707,6 +17067,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
16707
17067
|
bidManager;
|
|
16708
17068
|
/** Estimates gas costs for filling an order and converts them to fee-token amounts. */
|
|
16709
17069
|
gasEstimator;
|
|
17070
|
+
/** Quote strategies for pricing orders before placement, keyed by strategy name. */
|
|
17071
|
+
quoteStrategies;
|
|
16710
17072
|
/**
|
|
16711
17073
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
16712
17074
|
*
|
|
@@ -16744,12 +17106,15 @@ var IntentGateway = class _IntentGateway {
|
|
|
16744
17106
|
const bidManager = new BidManager(this.ctx, crypto);
|
|
16745
17107
|
const gasEstimator = new GasEstimator(this.ctx, crypto);
|
|
16746
17108
|
this.orderPlacer = new OrderPlacer(this.ctx);
|
|
16747
|
-
this.orderExecutor = new OrderExecutor(this.ctx, bidManager
|
|
17109
|
+
this.orderExecutor = new OrderExecutor(this.ctx, bidManager);
|
|
16748
17110
|
this.orderCanceller = new OrderCanceller(this.ctx);
|
|
16749
17111
|
this.orderStatusChecker = new OrderStatusChecker(this.ctx);
|
|
16750
17112
|
this.bidManager = bidManager;
|
|
16751
17113
|
this.gasEstimator = gasEstimator;
|
|
16752
17114
|
this._crypto = crypto;
|
|
17115
|
+
this.quoteStrategies = {
|
|
17116
|
+
uniswap_v4: new UniswapV4IntentQuoteStrategy(dest.configService)
|
|
17117
|
+
};
|
|
16753
17118
|
}
|
|
16754
17119
|
/**
|
|
16755
17120
|
* Creates an initialized IntentGateway instance.
|
|
@@ -16794,6 +17159,33 @@ var IntentGateway = class _IntentGateway {
|
|
|
16794
17159
|
}
|
|
16795
17160
|
}
|
|
16796
17161
|
}
|
|
17162
|
+
/**
|
|
17163
|
+
* Quotes an intent between this gateway's source and destination chains.
|
|
17164
|
+
*
|
|
17165
|
+
* `strategy` defaults to `uniswap_v4`, currently the only supported
|
|
17166
|
+
* strategy. Provide exactly one of `amountIn` or `amountOut`.
|
|
17167
|
+
*
|
|
17168
|
+
* The Uniswap quote strategy always prices against the configured Base
|
|
17169
|
+
* pool, regardless of this gateway's destination chain. Returned
|
|
17170
|
+
* `amountIn`/`amountOut` already account for the gateway's protocol fee
|
|
17171
|
+
* (`quoteMetadata.protocolFeeBps`), which the gateway deducts from order
|
|
17172
|
+
* inputs; apply only your own slippage tolerance before placing the order.
|
|
17173
|
+
*
|
|
17174
|
+
* @param params - Token pair, amount, and optional strategy/pool overrides.
|
|
17175
|
+
* @returns The quoted amounts plus strategy-specific metadata.
|
|
17176
|
+
* @throws {UnsupportedIntentQuoteStrategyError} For unknown strategies.
|
|
17177
|
+
* @throws {UnsupportedIntentQuotePairError} When no pool is configured for the pair.
|
|
17178
|
+
*/
|
|
17179
|
+
async quoteIntent(params) {
|
|
17180
|
+
const strategy = params.strategy ?? "uniswap_v4";
|
|
17181
|
+
const handler = this.quoteStrategies[strategy];
|
|
17182
|
+
if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
|
|
17183
|
+
return handler.quote(
|
|
17184
|
+
{ ...params, strategy },
|
|
17185
|
+
{ stateMachineId: this.source.config.stateMachineId, client: this.source.client },
|
|
17186
|
+
{ stateMachineId: this.dest.config.stateMachineId, client: this.dest.client }
|
|
17187
|
+
);
|
|
17188
|
+
}
|
|
16797
17189
|
/**
|
|
16798
17190
|
* Bidirectional async generator that orchestrates the full order lifecycle:
|
|
16799
17191
|
* placement, fee estimation, bid collection, and execution.
|
|
@@ -16848,17 +17240,38 @@ var IntentGateway = class _IntentGateway {
|
|
|
16848
17240
|
}
|
|
16849
17241
|
const { order: finalizedOrder, receipt: placementReceipt } = placeOrderSecond.value;
|
|
16850
17242
|
yield { status: "ORDER_PLACED", order: finalizedOrder, receipt: placementReceipt };
|
|
16851
|
-
|
|
16852
|
-
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
|
|
16856
|
-
|
|
16857
|
-
|
|
16858
|
-
|
|
16859
|
-
|
|
17243
|
+
yield* this.driveExecution(
|
|
17244
|
+
this.orderExecutor.executeOrder({
|
|
17245
|
+
order: finalizedOrder,
|
|
17246
|
+
sessionPrivateKey,
|
|
17247
|
+
auctionTimeMs: options.auctionTimeMs,
|
|
17248
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
17249
|
+
solver: options.solver
|
|
17250
|
+
})
|
|
17251
|
+
);
|
|
16860
17252
|
return;
|
|
16861
17253
|
}
|
|
17254
|
+
/**
|
|
17255
|
+
* Forwards updates from the executor's bidirectional generator to the caller,
|
|
17256
|
+
* threading the {@link SelectBidResult} the caller feeds back after a
|
|
17257
|
+
* `BIDS_RECEIVED` yield into the executor's `.next()`. Other yields expect no
|
|
17258
|
+
* feedback. This is what lets the consumer own `bid.execute()` while the
|
|
17259
|
+
* executor keeps tracking fills and continuing the auction.
|
|
17260
|
+
*/
|
|
17261
|
+
async *driveExecution(execGen) {
|
|
17262
|
+
try {
|
|
17263
|
+
let input;
|
|
17264
|
+
while (true) {
|
|
17265
|
+
const { value, done } = await execGen.next(input);
|
|
17266
|
+
input = void 0;
|
|
17267
|
+
if (done) break;
|
|
17268
|
+
const fed = yield value;
|
|
17269
|
+
if (value.status === "BIDS_RECEIVED") input = fed;
|
|
17270
|
+
}
|
|
17271
|
+
} finally {
|
|
17272
|
+
await execGen.return();
|
|
17273
|
+
}
|
|
17274
|
+
}
|
|
16862
17275
|
/**
|
|
16863
17276
|
* Validates that an order has the minimum fields required for post-placement
|
|
16864
17277
|
* resume (i.e. it was previously placed and has an on-chain identity).
|
|
@@ -16895,14 +17308,99 @@ var IntentGateway = class _IntentGateway {
|
|
|
16895
17308
|
*/
|
|
16896
17309
|
async *resume(order, options) {
|
|
16897
17310
|
this.assertOrderCanResume(order);
|
|
16898
|
-
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
17311
|
+
yield* this.driveExecution(
|
|
17312
|
+
this.orderExecutor.executeOrder({
|
|
17313
|
+
order,
|
|
17314
|
+
sessionPrivateKey: options.sessionPrivateKey,
|
|
17315
|
+
auctionTimeMs: options.auctionTimeMs,
|
|
17316
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
17317
|
+
solver: options.solver
|
|
17318
|
+
})
|
|
17319
|
+
);
|
|
17320
|
+
}
|
|
17321
|
+
/**
|
|
17322
|
+
* Batteries-included variant of {@link execute}: places the order and then
|
|
17323
|
+
* auto-selects the best bid each round via {@link selectAndExecuteBest}, with
|
|
17324
|
+
* no bid-selection input from the caller.
|
|
17325
|
+
*
|
|
17326
|
+
* The caller still signs the placement transaction: this generator yields
|
|
17327
|
+
* `AWAITING_PLACE_ORDER` and the caller must hand the signed tx back via
|
|
17328
|
+
* `gen.next(signedTx)` exactly as with {@link execute}. Every other stage
|
|
17329
|
+
* (`BIDS_RECEIVED`, `BID_SELECTED`, `FILLED`, …) is handled automatically and
|
|
17330
|
+
* surfaced for observation, so the rest of the loop needs no feedback.
|
|
17331
|
+
*
|
|
17332
|
+
* @param order - The order to place and execute.
|
|
17333
|
+
* @param graffiti - Optional orderflow-attribution tag.
|
|
17334
|
+
* @param options - Same tuning parameters as {@link execute}.
|
|
17335
|
+
* @yields {@link IntentOrderStatusUpdate} at each lifecycle stage.
|
|
17336
|
+
*/
|
|
17337
|
+
async *executeBest(order, graffiti = DEFAULT_GRAFFITI, options) {
|
|
17338
|
+
const gen = this.execute(order, graffiti, options);
|
|
17339
|
+
try {
|
|
17340
|
+
let input;
|
|
17341
|
+
while (true) {
|
|
17342
|
+
const { value, done } = await gen.next(input);
|
|
17343
|
+
input = void 0;
|
|
17344
|
+
if (done) break;
|
|
17345
|
+
if (value.status === "BIDS_RECEIVED") {
|
|
17346
|
+
yield value;
|
|
17347
|
+
input = await this.autoSelect(order, value.bids);
|
|
17348
|
+
} else if (value.status === "AWAITING_PLACE_ORDER") {
|
|
17349
|
+
input = yield value;
|
|
17350
|
+
} else {
|
|
17351
|
+
yield value;
|
|
17352
|
+
}
|
|
17353
|
+
}
|
|
17354
|
+
} finally {
|
|
17355
|
+
await gen.return();
|
|
17356
|
+
}
|
|
17357
|
+
}
|
|
17358
|
+
/**
|
|
17359
|
+
* Batteries-included variant of {@link resume}: auto-selects the best bid each
|
|
17360
|
+
* round via {@link selectAndExecuteBest}, with no bid-selection input from the
|
|
17361
|
+
* caller. A plain `for await` loop is sufficient — there is no placement step.
|
|
17362
|
+
*
|
|
17363
|
+
* @param order - A previously placed order with a valid `id` and `session`.
|
|
17364
|
+
* @param options - Optional tuning parameters for bid collection and execution.
|
|
17365
|
+
* @yields {@link IntentOrderStatusUpdate} at each execution stage.
|
|
17366
|
+
*/
|
|
17367
|
+
async *resumeBest(order, options) {
|
|
17368
|
+
const gen = this.resume(order, options);
|
|
17369
|
+
try {
|
|
17370
|
+
let input;
|
|
17371
|
+
while (true) {
|
|
17372
|
+
const { value, done } = await gen.next(input);
|
|
17373
|
+
input = void 0;
|
|
17374
|
+
if (done) break;
|
|
17375
|
+
yield value;
|
|
17376
|
+
if (value.status === "BIDS_RECEIVED") {
|
|
17377
|
+
input = await this.autoSelect(order, value.bids);
|
|
17378
|
+
}
|
|
17379
|
+
}
|
|
17380
|
+
} finally {
|
|
17381
|
+
await gen.return();
|
|
17382
|
+
}
|
|
17383
|
+
}
|
|
17384
|
+
/**
|
|
17385
|
+
* Auto-select wrapper used by {@link executeBest} / {@link resumeBest}.
|
|
17386
|
+
*
|
|
17387
|
+
* Runs {@link selectAndExecuteBest} and returns the {@link SelectBidResult} to
|
|
17388
|
+
* feed back to the executor. If selection fails this round — all bids fail
|
|
17389
|
+
* simulation, no valid bids, or the bundler rejects the UserOp — it swallows
|
|
17390
|
+
* the error and returns `undefined`, which tells the executor to keep polling
|
|
17391
|
+
* for fresh bids until the deadline rather than aborting the order. Swallowing
|
|
17392
|
+
* the error here (rather than letting it propagate) also keeps the executor's
|
|
17393
|
+
* `finally` teardown intact, since nothing throws across the suspended
|
|
17394
|
+
* generators.
|
|
17395
|
+
*/
|
|
17396
|
+
async autoSelect(order, bids) {
|
|
17397
|
+
try {
|
|
17398
|
+
return await this.selectAndExecuteBest(order, bids);
|
|
17399
|
+
} catch (err) {
|
|
17400
|
+
console.warn(
|
|
17401
|
+
`[IntentGateway] autoSelect: bid selection failed this round, continuing to poll: ${err instanceof Error ? err.message : String(err)}`
|
|
17402
|
+
);
|
|
17403
|
+
return void 0;
|
|
16906
17404
|
}
|
|
16907
17405
|
}
|
|
16908
17406
|
/**
|
|
@@ -16958,10 +17456,52 @@ var IntentGateway = class _IntentGateway {
|
|
|
16958
17456
|
return this.bidManager.prepareSubmitBid(options);
|
|
16959
17457
|
}
|
|
16960
17458
|
/**
|
|
16961
|
-
*
|
|
16962
|
-
*
|
|
17459
|
+
* Decodes raw filler bids into first-class {@link Bid} objects that can be
|
|
17460
|
+
* ranked, simulated, and executed by the consumer.
|
|
17461
|
+
*
|
|
17462
|
+
* Delegates to {@link BidManager.buildBids}.
|
|
17463
|
+
*
|
|
17464
|
+
* @param order - The placed order the bids are competing to fill.
|
|
17465
|
+
* @param bids - Raw filler bids fetched from the coprocessor.
|
|
17466
|
+
* @param sessionPrivateKey - Optional session key override; looked up from
|
|
17467
|
+
* storage by `order.session` if omitted.
|
|
17468
|
+
* @returns Array of executable {@link Bid} objects.
|
|
17469
|
+
*/
|
|
17470
|
+
buildBids(order, bids, sessionPrivateKey) {
|
|
17471
|
+
return this.bidManager.buildBids(order, bids, sessionPrivateKey);
|
|
17472
|
+
}
|
|
17473
|
+
/**
|
|
17474
|
+
* Sorts bids by output value using the same strategy the autopilot uses.
|
|
17475
|
+
*
|
|
17476
|
+
* Delegates to {@link BidManager.sortBids}.
|
|
17477
|
+
*
|
|
17478
|
+
* @param order - The placed order whose output spec drives sorting.
|
|
17479
|
+
* @param bids - Bids to sort (from {@link buildBids}).
|
|
17480
|
+
* @returns Sorted array of {@link Bid} objects.
|
|
17481
|
+
*/
|
|
17482
|
+
async sortBids(order, bids) {
|
|
17483
|
+
return this.bidManager.sortBids(order, bids);
|
|
17484
|
+
}
|
|
17485
|
+
/**
|
|
17486
|
+
* Autopilot bid selection: sorts the given bids, simulates each until one
|
|
17487
|
+
* passes, then executes it.
|
|
17488
|
+
*
|
|
17489
|
+
* Delegates to {@link BidManager.selectAndExecuteBest}.
|
|
17490
|
+
*
|
|
17491
|
+
* @param order - The placed order to fill.
|
|
17492
|
+
* @param bids - Candidate bids (from {@link buildBids}).
|
|
17493
|
+
* @returns A {@link SelectBidResult} with the submitted UserOperation, hashes,
|
|
17494
|
+
* and fill status.
|
|
17495
|
+
*/
|
|
17496
|
+
async selectAndExecuteBest(order, bids) {
|
|
17497
|
+
return this.bidManager.selectAndExecuteBest(order, bids);
|
|
17498
|
+
}
|
|
17499
|
+
/**
|
|
17500
|
+
* Decodes, sorts, simulates, signs, and submits the best of the given raw
|
|
17501
|
+
* filler bids with no per-bid input from the caller.
|
|
16963
17502
|
*
|
|
16964
|
-
* Delegates to {@link BidManager.selectBid}.
|
|
17503
|
+
* Delegates to {@link BidManager.selectBid}. Prefer {@link buildBids} +
|
|
17504
|
+
* {@link selectAndExecuteBest} (or {@link executeBest}) for new code.
|
|
16965
17505
|
*
|
|
16966
17506
|
* @param order - The placed order to fill.
|
|
16967
17507
|
* @param bids - Raw filler bids fetched from the coprocessor.
|
|
@@ -17881,7 +18421,7 @@ var HyperFungibleTokenABI = [
|
|
|
17881
18421
|
internalType: "uint256"
|
|
17882
18422
|
}
|
|
17883
18423
|
],
|
|
17884
|
-
stateMutability: "
|
|
18424
|
+
stateMutability: "nonpayable"
|
|
17885
18425
|
},
|
|
17886
18426
|
{
|
|
17887
18427
|
type: "function",
|
|
@@ -17932,7 +18472,7 @@ var HyperFungibleTokenABI = [
|
|
|
17932
18472
|
internalType: "uint256"
|
|
17933
18473
|
}
|
|
17934
18474
|
],
|
|
17935
|
-
stateMutability: "
|
|
18475
|
+
stateMutability: "nonpayable"
|
|
17936
18476
|
},
|
|
17937
18477
|
{
|
|
17938
18478
|
type: "function",
|
|
@@ -17983,7 +18523,7 @@ var HyperFungibleTokenABI = [
|
|
|
17983
18523
|
internalType: "uint256"
|
|
17984
18524
|
}
|
|
17985
18525
|
],
|
|
17986
|
-
stateMutability: "
|
|
18526
|
+
stateMutability: "nonpayable"
|
|
17987
18527
|
},
|
|
17988
18528
|
{
|
|
17989
18529
|
type: "function",
|
|
@@ -19002,7 +19542,7 @@ var WrappedHyperFungibleTokenABI = [
|
|
|
19002
19542
|
internalType: "uint256"
|
|
19003
19543
|
}
|
|
19004
19544
|
],
|
|
19005
|
-
stateMutability: "
|
|
19545
|
+
stateMutability: "nonpayable"
|
|
19006
19546
|
},
|
|
19007
19547
|
{
|
|
19008
19548
|
type: "function",
|
|
@@ -19053,7 +19593,7 @@ var WrappedHyperFungibleTokenABI = [
|
|
|
19053
19593
|
internalType: "uint256"
|
|
19054
19594
|
}
|
|
19055
19595
|
],
|
|
19056
|
-
stateMutability: "
|
|
19596
|
+
stateMutability: "nonpayable"
|
|
19057
19597
|
},
|
|
19058
19598
|
{
|
|
19059
19599
|
type: "function",
|
|
@@ -19104,7 +19644,7 @@ var WrappedHyperFungibleTokenABI = [
|
|
|
19104
19644
|
internalType: "uint256"
|
|
19105
19645
|
}
|
|
19106
19646
|
],
|
|
19107
|
-
stateMutability: "
|
|
19647
|
+
stateMutability: "nonpayable"
|
|
19108
19648
|
},
|
|
19109
19649
|
{
|
|
19110
19650
|
type: "function",
|
|
@@ -19646,13 +20186,13 @@ var HyperFungibleToken = class {
|
|
|
19646
20186
|
};
|
|
19647
20187
|
let totalNativeCost = 0n;
|
|
19648
20188
|
try {
|
|
19649
|
-
|
|
20189
|
+
const { result } = await this.source.client.simulateContract({
|
|
19650
20190
|
address: params.token,
|
|
19651
20191
|
abi: HyperFungibleTokenABI,
|
|
19652
20192
|
functionName: "quote",
|
|
19653
20193
|
args: [sendParams]
|
|
19654
20194
|
});
|
|
19655
|
-
totalNativeCost =
|
|
20195
|
+
totalNativeCost = result * 101n / 100n;
|
|
19656
20196
|
} catch {
|
|
19657
20197
|
}
|
|
19658
20198
|
return {
|
|
@@ -21606,6 +22146,8 @@ exports.TimeoutStatus = TimeoutStatus;
|
|
|
21606
22146
|
exports.TokenGateway = TokenGateway;
|
|
21607
22147
|
exports.TronChain = TronChain;
|
|
21608
22148
|
exports.USE_ETHERSCAN_CHAINS = USE_ETHERSCAN_CHAINS;
|
|
22149
|
+
exports.UnsupportedIntentQuotePairError = UnsupportedIntentQuotePairError;
|
|
22150
|
+
exports.UnsupportedIntentQuoteStrategyError = UnsupportedIntentQuoteStrategyError;
|
|
21609
22151
|
exports.WrappedHyperFungibleTokenABI = WrappedHyperFungibleTokenABI;
|
|
21610
22152
|
exports.__test = __test;
|
|
21611
22153
|
exports.adjustDecimals = adjustDecimals;
|