@hyperbridge/sdk 2.4.2 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.ts +87 -12
- package/dist/browser/index.js +662 -92
- package/dist/browser/index.js.map +1 -1
- package/dist/node/{IntentGatewayV2-PzbhFn_7.d.cts → IntentGatewayV2-tYGohDdW.d.cts} +62 -5
- package/dist/node/{IntentGatewayV2-PzbhFn_7.d.ts → IntentGatewayV2-tYGohDdW.d.ts} +62 -5
- package/dist/node/index.cjs +661 -90
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +28 -10
- package/dist/node/index.d.ts +28 -10
- package/dist/node/index.js +662 -92
- package/dist/node/index.js.map +1 -1
- package/dist/node/intents-helpers.cjs +518 -7
- package/dist/node/intents-helpers.cjs.map +1 -1
- package/dist/node/intents-helpers.d.cts +52 -10
- package/dist/node/intents-helpers.d.ts +52 -10
- package/dist/node/intents-helpers.js +516 -9
- package/dist/node/intents-helpers.js.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync } from 'fs';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { TextDecoder as TextDecoder$1, TextEncoder as TextEncoder$1 } from 'util';
|
|
4
4
|
import { createConsola, LogLevels } from 'consola';
|
|
5
|
-
import { defineChain, keccak256, toHex, createPublicClient, http, hexToBytes, toFunctionSelector, bytesToHex, encodeFunctionData, erc20Abi, bytesToBigInt, pad, toBytes, numberToBytes, decodeAbiParameters, getAddress, encodeAbiParameters, isHex, maxUint256, parseAbiParameters, encodePacked, parseAbiItem, concat, decodeFunctionData, hexToString as hexToString$1, decodeEventLog, parseEventLogs, parseUnits, concatHex, zeroAddress, decodeFunctionResult, formatUnits } from 'viem';
|
|
5
|
+
import { defineChain, keccak256, toHex, createPublicClient, http, hexToBytes, toFunctionSelector, bytesToHex, encodeFunctionData, erc20Abi, bytesToBigInt, pad, toBytes, numberToBytes, decodeAbiParameters, getAddress, encodeAbiParameters, isHex, isAddress, maxUint256, parseAbiParameters, encodePacked, parseAbiItem, concat, decodeFunctionData, hexToString as hexToString$1, decodeEventLog, parseEventLogs, parseUnits, concatHex, zeroAddress, decodeFunctionResult, formatUnits } from 'viem';
|
|
6
6
|
import { baseSepolia, optimismSepolia, arbitrumSepolia, soneium, gnosis, optimism, polygonAmoy, polygon, base, arbitrum, bsc, mainnet, sepolia, gnosisChiado, bscTestnet, tron, unichain } from 'viem/chains';
|
|
7
7
|
import { TronWeb } from 'tronweb';
|
|
8
8
|
import { flatten, zip, capitalize, maxBy, isNil } from 'lodash-es';
|
|
@@ -2709,6 +2709,7 @@ var chainConfigs = {
|
|
|
2709
2709
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2710
2710
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2711
2711
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2712
|
+
SimplexPaymaster: "0xD4340d7466e040626383cb9cda9307ba8E081149",
|
|
2712
2713
|
Usdt0Oft: "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee"
|
|
2713
2714
|
},
|
|
2714
2715
|
rpcEnvKey: "ETH_MAINNET",
|
|
@@ -2762,7 +2763,8 @@ var chainConfigs = {
|
|
|
2762
2763
|
UniswapV4StateView: "0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4",
|
|
2763
2764
|
Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
|
|
2764
2765
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2765
|
-
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
|
|
2766
|
+
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2767
|
+
SimplexPaymaster: "0xeD02f9f0df8F562B89cC5b25867Ad3C2d61252A9"
|
|
2766
2768
|
// "Usdt0Oft": Not available on BSC
|
|
2767
2769
|
},
|
|
2768
2770
|
rpcEnvKey: "BSC_MAINNET",
|
|
@@ -2820,6 +2822,7 @@ var chainConfigs = {
|
|
|
2820
2822
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2821
2823
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2822
2824
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2825
|
+
SimplexPaymaster: "0x7281Bccb4f0BCE44F3B8542d1fC5e51c2F5fC08C",
|
|
2823
2826
|
Usdt0Oft: "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92"
|
|
2824
2827
|
},
|
|
2825
2828
|
rpcEnvKey: "ARBITRUM_MAINNET",
|
|
@@ -2874,6 +2877,7 @@ var chainConfigs = {
|
|
|
2874
2877
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2875
2878
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2876
2879
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2880
|
+
SimplexPaymaster: "0x15b3B03C870c7ef252029c35A12d3b339F5c8d7f",
|
|
2877
2881
|
AerodromeRouter: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
|
|
2878
2882
|
UniswapV4PositionManager: "0x7c5f5a4bbd8fd63184577525326123b519429bdc",
|
|
2879
2883
|
UniswapV4PoolManager: "0x498581ff718922c3f8e6a244956af099b2652b2b",
|
|
@@ -2936,6 +2940,7 @@ var chainConfigs = {
|
|
|
2936
2940
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2937
2941
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2938
2942
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2943
|
+
SimplexPaymaster: "0xe99acFe0f5fC4C8ea54A187D8D3b05f136150095",
|
|
2939
2944
|
Usdt0Oft: "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"
|
|
2940
2945
|
},
|
|
2941
2946
|
rpcEnvKey: "POLYGON_MAINNET",
|
|
@@ -5231,6 +5236,9 @@ var ChainConfigService = class {
|
|
|
5231
5236
|
getCirclePaymasterAddress(chain) {
|
|
5232
5237
|
return this.getConfig(chain)?.addresses.CirclePaymaster;
|
|
5233
5238
|
}
|
|
5239
|
+
getSimplexPaymasterAddress(chain) {
|
|
5240
|
+
return this.getConfig(chain)?.addresses.SimplexPaymaster;
|
|
5241
|
+
}
|
|
5234
5242
|
getHyperbridgeAddress() {
|
|
5235
5243
|
return hyperbridgeAddress;
|
|
5236
5244
|
}
|
|
@@ -7051,6 +7059,16 @@ var ExpectedError = class _ExpectedError extends Error {
|
|
|
7051
7059
|
return error instanceof _ExpectedError;
|
|
7052
7060
|
}
|
|
7053
7061
|
};
|
|
7062
|
+
var MISSING_CONSENSUS_UPDATE_TIME_MESSAGE = "Consensus update time not found";
|
|
7063
|
+
var MissingConsensusUpdateTimeError = class _MissingConsensusUpdateTimeError extends Error {
|
|
7064
|
+
constructor(message = MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, options) {
|
|
7065
|
+
super(message, options);
|
|
7066
|
+
this.name = "Hyperbridge/SDK/MissingConsensusUpdateTimeError";
|
|
7067
|
+
}
|
|
7068
|
+
static isError(error) {
|
|
7069
|
+
return error instanceof _MissingConsensusUpdateTimeError || error instanceof Error && error.message.toLowerCase().includes(MISSING_CONSENSUS_UPDATE_TIME_MESSAGE.toLowerCase());
|
|
7070
|
+
}
|
|
7071
|
+
};
|
|
7054
7072
|
|
|
7055
7073
|
// src/configs/constants.ts
|
|
7056
7074
|
var ISMP_PREFIX = ":child_storage:default:ISMPv2";
|
|
@@ -7364,8 +7382,15 @@ var SubstrateChain = class _SubstrateChain {
|
|
|
7364
7382
|
id: stateMachineId,
|
|
7365
7383
|
height: Number(stateMachineHeight.height)
|
|
7366
7384
|
};
|
|
7367
|
-
|
|
7368
|
-
|
|
7385
|
+
try {
|
|
7386
|
+
const updateTime = await this.rpcClient.call("ismp_queryStateMachineUpdateTime", [payload]);
|
|
7387
|
+
return BigInt(updateTime);
|
|
7388
|
+
} catch (error) {
|
|
7389
|
+
if (MissingConsensusUpdateTimeError.isError(error)) {
|
|
7390
|
+
throw new MissingConsensusUpdateTimeError(MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, { cause: error });
|
|
7391
|
+
}
|
|
7392
|
+
throw error;
|
|
7393
|
+
}
|
|
7369
7394
|
}
|
|
7370
7395
|
/**
|
|
7371
7396
|
* Get the challenge period for a given state machine id.
|
|
@@ -8111,26 +8136,76 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8111
8136
|
};
|
|
8112
8137
|
}
|
|
8113
8138
|
/**
|
|
8114
|
-
*
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
const
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8139
|
+
* Reads the PhantomOrderRegistered events emitted in a single block.
|
|
8140
|
+
*/
|
|
8141
|
+
async getPhantomOrdersInBlock(blockNumber) {
|
|
8142
|
+
const blockHash = await this.api.rpc.chain.getBlockHash(blockNumber);
|
|
8143
|
+
const apiAt = await this.api.at(blockHash);
|
|
8144
|
+
const records = await apiAt.query.system.events();
|
|
8145
|
+
const orders = [];
|
|
8146
|
+
for (const { event } of records) {
|
|
8147
|
+
if (event.section !== "intentsCoprocessor" || event.method !== "PhantomOrderRegistered") continue;
|
|
8148
|
+
const [commitment, chain, createdAt, tokenA, tokenB, standardAmount] = event.data;
|
|
8149
|
+
orders.push({
|
|
8150
|
+
commitment: commitment.toHex(),
|
|
8151
|
+
chain: new TextDecoder().decode(hexToU8a(chain.toHex())),
|
|
8152
|
+
createdAt: createdAt.toNumber(),
|
|
8153
|
+
tokenA: tokenA.toHex(),
|
|
8154
|
+
tokenB: tokenB.toHex(),
|
|
8155
|
+
standardAmount: BigInt(standardAmount.toString())
|
|
8156
|
+
});
|
|
8157
|
+
}
|
|
8158
|
+
return orders;
|
|
8159
|
+
}
|
|
8160
|
+
/**
|
|
8161
|
+
* Polls for newly registered phantom orders, invoking the callback once per order.
|
|
8162
|
+
*
|
|
8163
|
+
* Each tick reads the current head and scans every block between the last one processed and that
|
|
8164
|
+
* head, so the block cursor — not the connection — determines what has been seen. This replaced a
|
|
8165
|
+
* system.events subscription, which was only as reliable as its socket: polkadot-js reconnects
|
|
8166
|
+
* the transport but does not reliably re-establish storage subscriptions, and anything emitted
|
|
8167
|
+
* while disconnected was lost silently. With a bid window measured in a handful of blocks, that
|
|
8168
|
+
* meant silently missed bids.
|
|
8169
|
+
*
|
|
8170
|
+
* Scanning a block range is gap-free rather than merely self-healing: an outage delays orders but
|
|
8171
|
+
* cannot drop them, because the cursor only advances past a block whose events were actually
|
|
8172
|
+
* read. Recovery replays the backlog.
|
|
8173
|
+
*
|
|
8174
|
+
* Returns a function that stops polling.
|
|
8175
|
+
*/
|
|
8176
|
+
pollPhantomOrders(callback, options = {}) {
|
|
8177
|
+
const { intervalMs = 6e3, maxBlocksPerPoll = 500, lookbackBlocks = 0, onError } = options;
|
|
8178
|
+
let cursor = null;
|
|
8179
|
+
let inFlight = false;
|
|
8180
|
+
let stopped = false;
|
|
8181
|
+
const tick = async () => {
|
|
8182
|
+
if (inFlight || stopped) return;
|
|
8183
|
+
inFlight = true;
|
|
8184
|
+
try {
|
|
8185
|
+
const head = (await this.api.rpc.chain.getHeader()).number.toNumber();
|
|
8186
|
+
if (cursor === null) {
|
|
8187
|
+
cursor = Math.max(head - 1 - lookbackBlocks, -1);
|
|
8188
|
+
}
|
|
8189
|
+
if (head <= cursor) return;
|
|
8190
|
+
const to = Math.min(head, cursor + maxBlocksPerPoll);
|
|
8191
|
+
for (let blockNumber = cursor + 1; blockNumber <= to; blockNumber++) {
|
|
8192
|
+
if (stopped) return;
|
|
8193
|
+
const orders = await this.getPhantomOrdersInBlock(blockNumber);
|
|
8194
|
+
for (const order of orders) callback(order);
|
|
8195
|
+
cursor = blockNumber;
|
|
8196
|
+
}
|
|
8197
|
+
} catch (err) {
|
|
8198
|
+
onError?.(err);
|
|
8199
|
+
} finally {
|
|
8200
|
+
inFlight = false;
|
|
8131
8201
|
}
|
|
8132
|
-
}
|
|
8133
|
-
|
|
8202
|
+
};
|
|
8203
|
+
void tick();
|
|
8204
|
+
const timer = setInterval(() => void tick(), intervalMs);
|
|
8205
|
+
return () => {
|
|
8206
|
+
stopped = true;
|
|
8207
|
+
clearInterval(timer);
|
|
8208
|
+
};
|
|
8134
8209
|
}
|
|
8135
8210
|
};
|
|
8136
8211
|
var TronChain = class _TronChain {
|
|
@@ -9263,7 +9338,12 @@ function sleep(ms) {
|
|
|
9263
9338
|
async function waitForChallengePeriod(chain, stateMachineHeight) {
|
|
9264
9339
|
const challengePeriod = await chain.challengePeriod(stateMachineHeight.id);
|
|
9265
9340
|
if (challengePeriod === BigInt(0)) return;
|
|
9266
|
-
const updateTime = await chain.stateMachineUpdateTime(stateMachineHeight)
|
|
9341
|
+
const updateTime = await retryPromise(() => chain.stateMachineUpdateTime(stateMachineHeight), {
|
|
9342
|
+
maxRetries: 3,
|
|
9343
|
+
backoffMs: 500,
|
|
9344
|
+
logMessage: "Fetching consensus update time while waiting for the challenge period",
|
|
9345
|
+
shouldRetry: (error) => !MissingConsensusUpdateTimeError.isError(error)
|
|
9346
|
+
});
|
|
9267
9347
|
let currentTimestamp = await chain.timestamp();
|
|
9268
9348
|
let timeElapsed = currentTimestamp - updateTime;
|
|
9269
9349
|
if (timeElapsed > challengePeriod) return;
|
|
@@ -9410,6 +9490,10 @@ function normalizeAddressForEvmBytes32(address) {
|
|
|
9410
9490
|
if (address.length === 66) return address;
|
|
9411
9491
|
return bytes20ToBytes32(address);
|
|
9412
9492
|
}
|
|
9493
|
+
function normalizeEvmAddress(address, field = "address") {
|
|
9494
|
+
if (!isAddress(address)) throw new TypeError(`${field} must be a valid EVM address`);
|
|
9495
|
+
return address.toLowerCase();
|
|
9496
|
+
}
|
|
9413
9497
|
function normalizeAddressForStateMachine(address, stateMachineId) {
|
|
9414
9498
|
return isEvmChain(normalizeStateMachineId(stateMachineId)) ? normalizeAddressForEvmBytes32(address) : address;
|
|
9415
9499
|
}
|
|
@@ -9417,14 +9501,16 @@ var DEFAULT_LOGGER = createConsola({
|
|
|
9417
9501
|
level: LogLevels.silent
|
|
9418
9502
|
});
|
|
9419
9503
|
async function retryPromise(operation, retryConfig) {
|
|
9420
|
-
const { logger = DEFAULT_LOGGER, logMessage = "Retry operation failed" } = retryConfig;
|
|
9504
|
+
const { logger = DEFAULT_LOGGER, logMessage = "Retry operation failed", shouldRetry } = retryConfig;
|
|
9421
9505
|
let lastError;
|
|
9422
9506
|
for (let i = 0; i < retryConfig.maxRetries; i++) {
|
|
9423
9507
|
try {
|
|
9424
9508
|
return await operation();
|
|
9425
9509
|
} catch (error) {
|
|
9510
|
+
if (shouldRetry && !shouldRetry(error)) throw error;
|
|
9426
9511
|
logger.trace(`Retrying(${i}) > ${logMessage}`);
|
|
9427
9512
|
lastError = error;
|
|
9513
|
+
if (i === retryConfig.maxRetries - 1) break;
|
|
9428
9514
|
await new Promise((resolve) => setTimeout(resolve, retryConfig.backoffMs * 2 ** i));
|
|
9429
9515
|
}
|
|
9430
9516
|
}
|
|
@@ -11495,6 +11581,55 @@ query LatestPhantomOrderPriceSnapshot($tokenA: String!, $tokenB: String!) {
|
|
|
11495
11581
|
}
|
|
11496
11582
|
}
|
|
11497
11583
|
}`;
|
|
11584
|
+
var LATEST_PHANTOM_ORDER_LIQUIDITY_SNAPSHOT = `
|
|
11585
|
+
query LatestPhantomOrderLiquiditySnapshot($tokenA: String!, $tokenB: String!) {
|
|
11586
|
+
phantomOrderPriceSnapshots(
|
|
11587
|
+
filter: {
|
|
11588
|
+
and: [
|
|
11589
|
+
{ tokenA: { equalTo: $tokenA } }
|
|
11590
|
+
{ tokenB: { equalTo: $tokenB } }
|
|
11591
|
+
]
|
|
11592
|
+
}
|
|
11593
|
+
orderBy: SNAPSHOT_TIME_DESC
|
|
11594
|
+
first: 1
|
|
11595
|
+
) {
|
|
11596
|
+
nodes {
|
|
11597
|
+
commitment
|
|
11598
|
+
tokenA
|
|
11599
|
+
tokenB
|
|
11600
|
+
snapshotTime
|
|
11601
|
+
}
|
|
11602
|
+
}
|
|
11603
|
+
}`;
|
|
11604
|
+
var LIQUIDITY_PROVIDER_BALANCES = `
|
|
11605
|
+
query LiquidityProviderBalanceAggregates($commitment: String!, $tokenAddress: String!) {
|
|
11606
|
+
liquidityProviderBalances(
|
|
11607
|
+
filter: {
|
|
11608
|
+
and: [
|
|
11609
|
+
{ commitment: { equalTo: $commitment } }
|
|
11610
|
+
{ tokenAddress: { equalTo: $tokenAddress } }
|
|
11611
|
+
]
|
|
11612
|
+
}
|
|
11613
|
+
) {
|
|
11614
|
+
aggregates {
|
|
11615
|
+
sum {
|
|
11616
|
+
balance
|
|
11617
|
+
}
|
|
11618
|
+
distinctCount {
|
|
11619
|
+
providerId
|
|
11620
|
+
}
|
|
11621
|
+
}
|
|
11622
|
+
groupedAggregates(groupBy: [CHAIN, TOKEN_ADDRESS]) {
|
|
11623
|
+
keys
|
|
11624
|
+
sum {
|
|
11625
|
+
balance
|
|
11626
|
+
}
|
|
11627
|
+
distinctCount {
|
|
11628
|
+
providerId
|
|
11629
|
+
}
|
|
11630
|
+
}
|
|
11631
|
+
}
|
|
11632
|
+
}`;
|
|
11498
11633
|
var TOKEN_GATEWAY_ASSET_TELEPORTED_STATUS = `
|
|
11499
11634
|
query TokenGatewayAssetTeleportedStatus($commitment: String!) {
|
|
11500
11635
|
tokenGatewayAssetTeleportedV2s(
|
|
@@ -12079,6 +12214,7 @@ function createCancellationStorage(options = {}) {
|
|
|
12079
12214
|
const decoded = decodeIProof(value);
|
|
12080
12215
|
return decoded;
|
|
12081
12216
|
}
|
|
12217
|
+
if (key2.includes("postCommitment")) return value;
|
|
12082
12218
|
throw new Error(`Unknown storage key type: ${key2}`);
|
|
12083
12219
|
};
|
|
12084
12220
|
const setItem = async (key2, value) => {
|
|
@@ -12092,6 +12228,10 @@ function createCancellationStorage(options = {}) {
|
|
|
12092
12228
|
await baseStorage.setItem(key2, encoded);
|
|
12093
12229
|
return;
|
|
12094
12230
|
}
|
|
12231
|
+
if (key2.includes("postCommitment") && typeof value === "string") {
|
|
12232
|
+
await baseStorage.setItem(key2, value);
|
|
12233
|
+
return;
|
|
12234
|
+
}
|
|
12095
12235
|
throw new Error(`Unknown storage key type: ${key2}`);
|
|
12096
12236
|
};
|
|
12097
12237
|
const removeItem = async (key2) => {
|
|
@@ -12105,11 +12245,25 @@ function createCancellationStorage(options = {}) {
|
|
|
12105
12245
|
});
|
|
12106
12246
|
}
|
|
12107
12247
|
var STORAGE_KEYS = Object.freeze({
|
|
12108
|
-
destProof: (orderId) => `cancel-order:${orderId}:destProof`,
|
|
12109
|
-
getRequest: (orderId) => `cancel-order:${orderId}:getRequest`,
|
|
12110
|
-
sourceProof: (orderId) => `cancel-order:${orderId}:sourceProof`,
|
|
12111
|
-
postCommitment: (orderId) => `cancel-order:${orderId}:postCommitment`
|
|
12248
|
+
destProof: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:destProof`,
|
|
12249
|
+
getRequest: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:getRequest`,
|
|
12250
|
+
sourceProof: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:sourceProof`,
|
|
12251
|
+
postCommitment: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:postCommitment`
|
|
12112
12252
|
});
|
|
12253
|
+
var LEGACY_STORAGE_KEYS = Object.freeze({
|
|
12254
|
+
destProof: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:destProof`,
|
|
12255
|
+
getRequest: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:getRequest`,
|
|
12256
|
+
sourceProof: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:sourceProof`,
|
|
12257
|
+
postCommitment: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:postCommitment`
|
|
12258
|
+
});
|
|
12259
|
+
function cancellationScope(orderId, source, destination) {
|
|
12260
|
+
if (!source || !destination) return orderId;
|
|
12261
|
+
return `${orderId}:${encodeURIComponent(normalizeStateMachineId(source))}:${encodeURIComponent(normalizeStateMachineId(destination))}`;
|
|
12262
|
+
}
|
|
12263
|
+
function legacyCancellationScope(orderId, source, destination) {
|
|
12264
|
+
if (!source || !destination) return orderId;
|
|
12265
|
+
return `${orderId}:${encodeURIComponent(source)}:${encodeURIComponent(destination)}`;
|
|
12266
|
+
}
|
|
12113
12267
|
function createUsedUserOpsStorage(options = {}) {
|
|
12114
12268
|
options.env ?? detectEnvironment();
|
|
12115
12269
|
const driver = loadDriver({ options }) ?? inMemoryDriver();
|
|
@@ -15275,6 +15429,29 @@ async function convertFeeTokenToWei(ctx, feeTokenAmount, feeTokenIn, evmChainID)
|
|
|
15275
15429
|
}
|
|
15276
15430
|
|
|
15277
15431
|
// src/protocols/intents/OrderPlacer.ts
|
|
15432
|
+
function deriveCanonicalPlacedOrder(order, args) {
|
|
15433
|
+
const canonicalOrder = {
|
|
15434
|
+
...order,
|
|
15435
|
+
user: args.user,
|
|
15436
|
+
source: args.source,
|
|
15437
|
+
destination: args.destination,
|
|
15438
|
+
deadline: args.deadline,
|
|
15439
|
+
nonce: args.nonce,
|
|
15440
|
+
fees: args.fees,
|
|
15441
|
+
session: args.session,
|
|
15442
|
+
predispatch: {
|
|
15443
|
+
assets: args.predispatch.map((asset) => ({ ...asset })),
|
|
15444
|
+
call: order.predispatch.call
|
|
15445
|
+
},
|
|
15446
|
+
inputs: args.inputs.map((asset) => ({ ...asset })),
|
|
15447
|
+
output: {
|
|
15448
|
+
beneficiary: args.beneficiary,
|
|
15449
|
+
assets: args.outputs.map((asset) => ({ ...asset })),
|
|
15450
|
+
call: order.output.call
|
|
15451
|
+
}
|
|
15452
|
+
};
|
|
15453
|
+
return { ...canonicalOrder, id: orderCommitment(canonicalOrder) };
|
|
15454
|
+
}
|
|
15278
15455
|
var OrderPlacer = class {
|
|
15279
15456
|
/**
|
|
15280
15457
|
* @param ctx - Shared IntentsV2 context providing the source chain client,
|
|
@@ -15291,17 +15468,16 @@ var OrderPlacer = class {
|
|
|
15291
15468
|
* 1. Yields `{ to, data, sessionPrivateKey }` — the caller must sign a
|
|
15292
15469
|
* transaction sending `data` to `to` and pass the signed transaction back
|
|
15293
15470
|
* via `gen.next(signedTx)`.
|
|
15294
|
-
* 2. Returns `{ order, transactionHash }` — the finalized order
|
|
15295
|
-
*
|
|
15296
|
-
* transaction hash.
|
|
15471
|
+
* 2. Returns `{ order, transactionHash }` — the finalized order rebuilt from
|
|
15472
|
+
* the canonical `OrderPlaced` fields with its computed `id`, plus the
|
|
15473
|
+
* placement transaction hash.
|
|
15297
15474
|
*
|
|
15298
15475
|
* A fresh ephemeral session key is generated for every call. The key is
|
|
15299
15476
|
* stored immediately (without a commitment) so it can be retrieved by
|
|
15300
15477
|
* address, then updated with the commitment once the `OrderPlaced` event
|
|
15301
|
-
* confirms the
|
|
15478
|
+
* confirms the canonical order.
|
|
15302
15479
|
*
|
|
15303
|
-
* @param order - The order to place.
|
|
15304
|
-
* with the generated session key address before yielding.
|
|
15480
|
+
* @param order - The order to place. It is not mutated.
|
|
15305
15481
|
* @param graffiti - Optional bytes32 tag for orderflow attribution /
|
|
15306
15482
|
* revenue share. Defaults to {@link DEFAULT_GRAFFITI} (bytes32 zero).
|
|
15307
15483
|
* @yields `{ to, data, sessionPrivateKey }` — target contract address,
|
|
@@ -15316,7 +15492,7 @@ var OrderPlacer = class {
|
|
|
15316
15492
|
const account = privateKeyToAccount(privateKey);
|
|
15317
15493
|
const sessionKeyAddress = account.address;
|
|
15318
15494
|
const createdAt = Date.now();
|
|
15319
|
-
order
|
|
15495
|
+
const placementOrder = { ...order, session: sessionKeyAddress };
|
|
15320
15496
|
await this.ctx.sessionKeyStorage.setSessionKeyByAddress(sessionKeyAddress, {
|
|
15321
15497
|
privateKey,
|
|
15322
15498
|
address: sessionKeyAddress,
|
|
@@ -15325,7 +15501,7 @@ var OrderPlacer = class {
|
|
|
15325
15501
|
const data = encodeFunctionData({
|
|
15326
15502
|
abi: ABI3,
|
|
15327
15503
|
functionName: "placeOrder",
|
|
15328
|
-
args: [transformOrderForContract(
|
|
15504
|
+
args: [transformOrderForContract(placementOrder), graffiti]
|
|
15329
15505
|
});
|
|
15330
15506
|
const intentGatewayAddress = this.ctx.source.configService.getIntentGatewayAddress(
|
|
15331
15507
|
normalizeStateMachineId(order.source)
|
|
@@ -15345,20 +15521,15 @@ var OrderPlacer = class {
|
|
|
15345
15521
|
if (!orderPlacedEvent) {
|
|
15346
15522
|
throw new Error("OrderPlaced event not found in transaction receipt");
|
|
15347
15523
|
}
|
|
15348
|
-
|
|
15349
|
-
order.inputs = orderPlacedEvent.args.inputs.map((input) => ({
|
|
15350
|
-
token: input.token,
|
|
15351
|
-
amount: input.amount
|
|
15352
|
-
}));
|
|
15353
|
-
order.id = orderCommitment(order);
|
|
15524
|
+
const finalizedOrder = deriveCanonicalPlacedOrder(placementOrder, orderPlacedEvent.args);
|
|
15354
15525
|
const sessionKeyData = {
|
|
15355
15526
|
privateKey,
|
|
15356
15527
|
address: sessionKeyAddress,
|
|
15357
|
-
commitment:
|
|
15528
|
+
commitment: finalizedOrder.id,
|
|
15358
15529
|
createdAt
|
|
15359
15530
|
};
|
|
15360
15531
|
await this.ctx.sessionKeyStorage.setSessionKeyByAddress(sessionKeyAddress, sessionKeyData);
|
|
15361
|
-
return { order, receipt };
|
|
15532
|
+
return { order: finalizedOrder, receipt };
|
|
15362
15533
|
}
|
|
15363
15534
|
};
|
|
15364
15535
|
|
|
@@ -15688,7 +15859,7 @@ var OrderExecutor = class {
|
|
|
15688
15859
|
}
|
|
15689
15860
|
}
|
|
15690
15861
|
};
|
|
15691
|
-
var OrderCanceller = class {
|
|
15862
|
+
var OrderCanceller = class _OrderCanceller {
|
|
15692
15863
|
/**
|
|
15693
15864
|
* @param ctx - Shared IntentsV2 context providing the source and destination
|
|
15694
15865
|
* chain clients, config service, and cancellation storage.
|
|
@@ -15697,6 +15868,9 @@ var OrderCanceller = class {
|
|
|
15697
15868
|
this.ctx = ctx;
|
|
15698
15869
|
}
|
|
15699
15870
|
ctx;
|
|
15871
|
+
static DEFAULT_MAX_RECOVERY_RESTARTS = 1;
|
|
15872
|
+
static PROOF_FRESHNESS_MAX_RETRIES = 3;
|
|
15873
|
+
static PROOF_FRESHNESS_BACKOFF_MS = 500;
|
|
15700
15874
|
logger = createConsola({
|
|
15701
15875
|
level: LogLevels.info,
|
|
15702
15876
|
formatOptions: { columns: 80, colors: true, compact: true, date: false }
|
|
@@ -15728,11 +15902,14 @@ var OrderCanceller = class {
|
|
|
15728
15902
|
* @returns The native token dispatch fee in wei.
|
|
15729
15903
|
*/
|
|
15730
15904
|
async quoteCancelFromSource(order) {
|
|
15731
|
-
if (order.source === order.destination) return { nativeValue: 0n, relayerFee: 0n };
|
|
15732
15905
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
15906
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15907
|
+
if (sourceStateMachine === destStateMachine) {
|
|
15908
|
+
return { nativeValue: 0n, relayerFee: 0n };
|
|
15909
|
+
}
|
|
15733
15910
|
const height = order.deadline + 1n;
|
|
15734
15911
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
15735
|
-
|
|
15912
|
+
destStateMachine
|
|
15736
15913
|
);
|
|
15737
15914
|
const slotHash = await this.ctx.dest.client.readContract({
|
|
15738
15915
|
abi: ABI3,
|
|
@@ -15744,8 +15921,8 @@ var OrderCanceller = class {
|
|
|
15744
15921
|
const context = encodeWithdrawalRequest(order, order.user);
|
|
15745
15922
|
const getRequest = {
|
|
15746
15923
|
source: sourceStateMachine,
|
|
15747
|
-
dest:
|
|
15748
|
-
from: this.ctx.source.configService.getIntentGatewayAddress(
|
|
15924
|
+
dest: destStateMachine,
|
|
15925
|
+
from: this.ctx.source.configService.getIntentGatewayAddress(destStateMachine),
|
|
15749
15926
|
nonce: await this.ctx.source.getHostNonce(),
|
|
15750
15927
|
height,
|
|
15751
15928
|
keys: [key],
|
|
@@ -15762,7 +15939,9 @@ var OrderCanceller = class {
|
|
|
15762
15939
|
* cancellation is complete.
|
|
15763
15940
|
*
|
|
15764
15941
|
* Delegates to `cancelOrderFromSource` or `cancelOrderFromDest` based on
|
|
15765
|
-
* the `from` parameter.
|
|
15942
|
+
* the `from` parameter. If Hyperbridge has pruned consensus data needed for
|
|
15943
|
+
* source-side GET recovery, clears its stale checkpoint and restarts the
|
|
15944
|
+
* source-side stream internally.
|
|
15766
15945
|
*
|
|
15767
15946
|
* @param order - The order to cancel.
|
|
15768
15947
|
* @param indexerClient - Indexer client used to stream ISMP request status
|
|
@@ -15772,12 +15951,32 @@ var OrderCanceller = class {
|
|
|
15772
15951
|
* cancellation lifecycle.
|
|
15773
15952
|
*/
|
|
15774
15953
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
15775
|
-
const
|
|
15954
|
+
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
15955
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15956
|
+
const isSameChain = sourceStateMachine === destStateMachine;
|
|
15776
15957
|
if (options.from === "destination" && !isSameChain) {
|
|
15777
15958
|
yield* this.cancelOrderFromDest(order, indexerClient);
|
|
15778
15959
|
return;
|
|
15779
15960
|
}
|
|
15780
|
-
|
|
15961
|
+
let recoveryRestarts = 0;
|
|
15962
|
+
while (true) {
|
|
15963
|
+
try {
|
|
15964
|
+
yield* this.cancelOrderFromSource(order, indexerClient);
|
|
15965
|
+
return;
|
|
15966
|
+
} catch (error) {
|
|
15967
|
+
if (!MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
15968
|
+
if (recoveryRestarts >= _OrderCanceller.DEFAULT_MAX_RECOVERY_RESTARTS) {
|
|
15969
|
+
throw new Error(
|
|
15970
|
+
`Cancellation recovery stopped after ${recoveryRestarts} restart(s): Hyperbridge no longer retains a required consensus update.`
|
|
15971
|
+
);
|
|
15972
|
+
}
|
|
15973
|
+
recoveryRestarts += 1;
|
|
15974
|
+
this.logger.warn(
|
|
15975
|
+
`Restarting cancellation recovery (${recoveryRestarts}/${_OrderCanceller.DEFAULT_MAX_RECOVERY_RESTARTS}) after a required consensus update was pruned`
|
|
15976
|
+
);
|
|
15977
|
+
await this.clearGetRecoveryCache(order);
|
|
15978
|
+
}
|
|
15979
|
+
}
|
|
15781
15980
|
}
|
|
15782
15981
|
/**
|
|
15783
15982
|
* Async generator that cancels an order by initiating the cancel from the
|
|
@@ -15803,11 +16002,10 @@ var OrderCanceller = class {
|
|
|
15803
16002
|
* @throws If the cancel transaction does not contain the expected on-chain event.
|
|
15804
16003
|
*/
|
|
15805
16004
|
async *cancelOrderFromSource(order, indexerClient) {
|
|
15806
|
-
const
|
|
15807
|
-
const
|
|
15808
|
-
const
|
|
15809
|
-
|
|
15810
|
-
);
|
|
16005
|
+
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
16006
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
16007
|
+
const isSameChain = sourceStateMachine === destStateMachine;
|
|
16008
|
+
const intentGatewayAddress = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine);
|
|
15811
16009
|
if (isSameChain) {
|
|
15812
16010
|
const data = encodeFunctionData({
|
|
15813
16011
|
abi: ABI3,
|
|
@@ -15836,18 +16034,37 @@ var OrderCanceller = class {
|
|
|
15836
16034
|
};
|
|
15837
16035
|
return;
|
|
15838
16036
|
}
|
|
16037
|
+
const storageKeys = this.recoveryStorageKeys(order);
|
|
16038
|
+
const legacyStorageKeys = this.legacyRecoveryStorageKeys(order);
|
|
15839
16039
|
const hyperbridge = indexerClient.hyperbridge;
|
|
15840
|
-
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
15841
16040
|
const sourceConsensusStateId = this.ctx.source.configService.getConsensusStateId(sourceStateMachine);
|
|
15842
|
-
let destIProof = await this.
|
|
16041
|
+
let destIProof = await this.getRecoveryItem(
|
|
16042
|
+
storageKeys.destProof,
|
|
16043
|
+
legacyStorageKeys.map((keys) => keys.destProof)
|
|
16044
|
+
);
|
|
15843
16045
|
if (!destIProof) {
|
|
15844
16046
|
destIProof = yield* this.fetchDestinationProof(order, indexerClient);
|
|
15845
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16047
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.destProof, destIProof);
|
|
15846
16048
|
} else {
|
|
15847
|
-
|
|
16049
|
+
let refreshed = false;
|
|
16050
|
+
try {
|
|
16051
|
+
await this.assertProofFresh(hyperbridge, destIProof);
|
|
16052
|
+
} catch (error) {
|
|
16053
|
+
if (!MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
16054
|
+
await this.removeRecoveryItems(
|
|
16055
|
+
storageKeys.destProof,
|
|
16056
|
+
...legacyStorageKeys.map((keys) => keys.destProof)
|
|
16057
|
+
);
|
|
16058
|
+
destIProof = yield* this.fetchDestinationProof(order, indexerClient);
|
|
16059
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.destProof, destIProof);
|
|
16060
|
+
refreshed = true;
|
|
16061
|
+
}
|
|
16062
|
+
if (!refreshed) yield { status: "DESTINATION_FINALIZED", proof: destIProof };
|
|
15848
16063
|
}
|
|
15849
|
-
|
|
15850
|
-
|
|
16064
|
+
await this.assertProofFresh(hyperbridge, destIProof);
|
|
16065
|
+
let getRequest = await this.getRecoveryItem(
|
|
16066
|
+
storageKeys.getRequest,
|
|
16067
|
+
legacyStorageKeys.map((keys) => keys.getRequest)
|
|
15851
16068
|
);
|
|
15852
16069
|
if (!getRequest) {
|
|
15853
16070
|
const quote = await this.quoteCancelFromSource(order);
|
|
@@ -15867,7 +16084,7 @@ var OrderCanceller = class {
|
|
|
15867
16084
|
const request = events.find((e) => e.eventName === "GetRequestEvent");
|
|
15868
16085
|
if (!request) throw new Error("GetRequest missing");
|
|
15869
16086
|
getRequest = request.args;
|
|
15870
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16087
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.getRequest, getRequest);
|
|
15871
16088
|
yield {
|
|
15872
16089
|
status: "CANCEL_STARTED",
|
|
15873
16090
|
receipt
|
|
@@ -15886,8 +16103,9 @@ var OrderCanceller = class {
|
|
|
15886
16103
|
metadata: statusUpdate.metadata
|
|
15887
16104
|
};
|
|
15888
16105
|
const sourceHeight = BigInt(statusUpdate.metadata.blockNumber);
|
|
15889
|
-
let sourceIProof = await this.
|
|
15890
|
-
|
|
16106
|
+
let sourceIProof = await this.getRecoveryItem(
|
|
16107
|
+
storageKeys.sourceProof,
|
|
16108
|
+
legacyStorageKeys.map((keys) => keys.sourceProof)
|
|
15891
16109
|
);
|
|
15892
16110
|
if (!sourceIProof) {
|
|
15893
16111
|
sourceIProof = await fetchSourceProof(
|
|
@@ -15897,8 +16115,9 @@ var OrderCanceller = class {
|
|
|
15897
16115
|
sourceConsensusStateId,
|
|
15898
16116
|
sourceHeight
|
|
15899
16117
|
);
|
|
15900
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16118
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.sourceProof, sourceIProof);
|
|
15901
16119
|
}
|
|
16120
|
+
await this.assertProofFresh(hyperbridge, sourceIProof);
|
|
15902
16121
|
await waitForChallengePeriod(hyperbridge, {
|
|
15903
16122
|
height: sourceIProof.height,
|
|
15904
16123
|
id: {
|
|
@@ -15906,6 +16125,10 @@ var OrderCanceller = class {
|
|
|
15906
16125
|
consensusStateId: sourceConsensusStateId
|
|
15907
16126
|
}
|
|
15908
16127
|
});
|
|
16128
|
+
await Promise.all([
|
|
16129
|
+
this.assertProofFresh(hyperbridge, sourceIProof),
|
|
16130
|
+
this.assertProofFresh(hyperbridge, destIProof)
|
|
16131
|
+
]);
|
|
15909
16132
|
const getRequestMessage = {
|
|
15910
16133
|
kind: "GetRequest",
|
|
15911
16134
|
requests: [getRequest],
|
|
@@ -15927,9 +16150,12 @@ var OrderCanceller = class {
|
|
|
15927
16150
|
status: "HYPERBRIDGE_FINALIZED",
|
|
15928
16151
|
metadata: statusUpdate.metadata
|
|
15929
16152
|
};
|
|
15930
|
-
await this.
|
|
15931
|
-
|
|
15932
|
-
|
|
16153
|
+
await this.removeRecoveryItems(
|
|
16154
|
+
storageKeys.destProof,
|
|
16155
|
+
storageKeys.getRequest,
|
|
16156
|
+
storageKeys.sourceProof,
|
|
16157
|
+
...legacyStorageKeys.flatMap((keys) => [keys.destProof, keys.getRequest, keys.sourceProof])
|
|
16158
|
+
);
|
|
15933
16159
|
return;
|
|
15934
16160
|
}
|
|
15935
16161
|
}
|
|
@@ -15946,9 +16172,11 @@ var OrderCanceller = class {
|
|
|
15946
16172
|
* @returns The native token dispatch fee in wei.
|
|
15947
16173
|
*/
|
|
15948
16174
|
async quoteCancelFromDest(order) {
|
|
15949
|
-
if (order.source === order.destination) return { nativeValue: 0n, relayerFee: 0n };
|
|
15950
|
-
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15951
16175
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
16176
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
16177
|
+
if (sourceStateMachine === destStateMachine) {
|
|
16178
|
+
return { nativeValue: 0n, relayerFee: 0n };
|
|
16179
|
+
}
|
|
15952
16180
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
15953
16181
|
const sourceIntentGateway = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine);
|
|
15954
16182
|
const relayerFee = await this.estimateRelayerFee(sourceStateMachine, destStateMachine);
|
|
@@ -15986,11 +16214,13 @@ var OrderCanceller = class {
|
|
|
15986
16214
|
* @throws If the cancel transaction does not contain a `PostRequestEvent`.
|
|
15987
16215
|
*/
|
|
15988
16216
|
async *cancelOrderFromDest(order, indexerClient) {
|
|
15989
|
-
const
|
|
16217
|
+
const storageKeys = this.recoveryStorageKeys(order);
|
|
15990
16218
|
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15991
16219
|
const intentGatewayAddress = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
15992
|
-
|
|
15993
|
-
|
|
16220
|
+
const legacyStorageKeys = this.legacyRecoveryStorageKeys(order);
|
|
16221
|
+
let commitment = await this.getRecoveryItem(
|
|
16222
|
+
storageKeys.postCommitment,
|
|
16223
|
+
legacyStorageKeys.map((keys) => keys.postCommitment)
|
|
15994
16224
|
);
|
|
15995
16225
|
if (!commitment) {
|
|
15996
16226
|
const quote = await this.quoteCancelFromDest(order);
|
|
@@ -16015,7 +16245,7 @@ var OrderCanceller = class {
|
|
|
16015
16245
|
if (!postEvent) throw new Error("PostRequestEvent not found in cancel transaction receipt");
|
|
16016
16246
|
const postArgs = postEvent.args;
|
|
16017
16247
|
commitment = postRequestCommitment(postArgs).commitment;
|
|
16018
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16248
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.postCommitment, commitment);
|
|
16019
16249
|
}
|
|
16020
16250
|
const statusStream = indexerClient.postRequestStatusStream(commitment);
|
|
16021
16251
|
for await (const statusUpdate of statusStream) {
|
|
@@ -16049,7 +16279,10 @@ var OrderCanceller = class {
|
|
|
16049
16279
|
if (refundEvents.length === 0) {
|
|
16050
16280
|
throw new Error("EscrowRefunded event not found in source-chain delivery receipt");
|
|
16051
16281
|
}
|
|
16052
|
-
await this.
|
|
16282
|
+
await this.removeRecoveryItems(
|
|
16283
|
+
storageKeys.postCommitment,
|
|
16284
|
+
...legacyStorageKeys.map((keys) => keys.postCommitment)
|
|
16285
|
+
);
|
|
16053
16286
|
yield {
|
|
16054
16287
|
status: "CANCELLATION_COMPLETE",
|
|
16055
16288
|
blockNumber: statusUpdate.metadata.blockNumber,
|
|
@@ -16092,7 +16325,7 @@ var OrderCanceller = class {
|
|
|
16092
16325
|
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
16093
16326
|
this.ctx.dest.config.stateMachineId
|
|
16094
16327
|
);
|
|
16095
|
-
const orderId = order
|
|
16328
|
+
const orderId = this.orderId(order);
|
|
16096
16329
|
const slotHash = await this.ctx.dest.client.readContract({
|
|
16097
16330
|
abi: ABI3,
|
|
16098
16331
|
address: intentGatewayV2Address,
|
|
@@ -16109,6 +16342,7 @@ var OrderCanceller = class {
|
|
|
16109
16342
|
yield { status: "DESTINATION_FINALIZED", proof };
|
|
16110
16343
|
return proof;
|
|
16111
16344
|
} catch (e) {
|
|
16345
|
+
if (MissingConsensusUpdateTimeError.isError(e)) throw e;
|
|
16112
16346
|
lastFailedHeight = latestHeight;
|
|
16113
16347
|
await sleep(1e4);
|
|
16114
16348
|
}
|
|
@@ -16139,6 +16373,7 @@ var OrderCanceller = class {
|
|
|
16139
16373
|
this.logger.info(`Unsigned GET ${commitment} submitted; waiting for Hyperbridge response receipt`);
|
|
16140
16374
|
await sleep(3e4);
|
|
16141
16375
|
} catch (error) {
|
|
16376
|
+
if (MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
16142
16377
|
this.logger.warn(
|
|
16143
16378
|
`Unsigned GET submit failed for ${commitment}; polling response receipt before failing: ${String(error)}`
|
|
16144
16379
|
);
|
|
@@ -16147,14 +16382,128 @@ var OrderCanceller = class {
|
|
|
16147
16382
|
await this.pollDeliveredReceipt(hyperbridge, commitment);
|
|
16148
16383
|
this.logger.info(`Confirmed Hyperbridge GET delivery for ${commitment}`);
|
|
16149
16384
|
} catch (error) {
|
|
16385
|
+
if (MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
16150
16386
|
const message2 = `Failed to deliver GET request to Hyperbridge; no response receipt found for ${commitment}: ${String(error)}`;
|
|
16151
16387
|
this.logger.error(message2);
|
|
16152
16388
|
throw new Error(message2);
|
|
16153
16389
|
}
|
|
16154
16390
|
}
|
|
16391
|
+
/** Verify that Hyperbridge still retains the consensus update for a proof. */
|
|
16392
|
+
async assertProofFresh(hyperbridge, proof) {
|
|
16393
|
+
await retryPromise(
|
|
16394
|
+
() => hyperbridge.stateMachineUpdateTime({
|
|
16395
|
+
height: proof.height,
|
|
16396
|
+
id: {
|
|
16397
|
+
stateId: parseStateMachineId(proof.stateMachine).stateId,
|
|
16398
|
+
consensusStateId: proof.consensusStateId
|
|
16399
|
+
}
|
|
16400
|
+
}),
|
|
16401
|
+
{
|
|
16402
|
+
maxRetries: _OrderCanceller.PROOF_FRESHNESS_MAX_RETRIES,
|
|
16403
|
+
backoffMs: _OrderCanceller.PROOF_FRESHNESS_BACKOFF_MS,
|
|
16404
|
+
logger: this.logger,
|
|
16405
|
+
logMessage: `Checking consensus update time for proof at height ${proof.height}`,
|
|
16406
|
+
shouldRetry: (error) => !MissingConsensusUpdateTimeError.isError(error)
|
|
16407
|
+
}
|
|
16408
|
+
);
|
|
16409
|
+
}
|
|
16410
|
+
/**
|
|
16411
|
+
* Drops the source-initiated GET recovery checkpoint after Hyperbridge prunes
|
|
16412
|
+
* a consensus update required by that recovery attempt.
|
|
16413
|
+
*/
|
|
16414
|
+
async clearGetRecoveryCache(order) {
|
|
16415
|
+
const keys = this.recoveryStorageKeys(order);
|
|
16416
|
+
const legacyStorageKeys = this.legacyRecoveryStorageKeys(order);
|
|
16417
|
+
await this.removeRecoveryItems(
|
|
16418
|
+
keys.destProof,
|
|
16419
|
+
keys.sourceProof,
|
|
16420
|
+
keys.getRequest,
|
|
16421
|
+
...legacyStorageKeys.flatMap((legacyKeys) => [
|
|
16422
|
+
legacyKeys.destProof,
|
|
16423
|
+
legacyKeys.sourceProof,
|
|
16424
|
+
legacyKeys.getRequest
|
|
16425
|
+
])
|
|
16426
|
+
);
|
|
16427
|
+
}
|
|
16428
|
+
/**
|
|
16429
|
+
* Returns the pair-scoped storage keys used to resume cancellation recovery
|
|
16430
|
+
* for an order.
|
|
16431
|
+
*
|
|
16432
|
+
* @param order - The order whose source/destination recovery state is stored.
|
|
16433
|
+
*/
|
|
16434
|
+
recoveryStorageKeys(order) {
|
|
16435
|
+
const orderId = this.orderId(order);
|
|
16436
|
+
return {
|
|
16437
|
+
destProof: STORAGE_KEYS.destProof(orderId, order.source, order.destination),
|
|
16438
|
+
getRequest: STORAGE_KEYS.getRequest(orderId, order.source, order.destination),
|
|
16439
|
+
sourceProof: STORAGE_KEYS.sourceProof(orderId, order.source, order.destination),
|
|
16440
|
+
postCommitment: STORAGE_KEYS.postCommitment(orderId, order.source, order.destination)
|
|
16441
|
+
};
|
|
16442
|
+
}
|
|
16443
|
+
/** Older SDK key shapes, checked once and migrated to the normalized pair-scoped key. */
|
|
16444
|
+
legacyRecoveryStorageKeys(order) {
|
|
16445
|
+
const orderId = this.orderId(order);
|
|
16446
|
+
return [
|
|
16447
|
+
{
|
|
16448
|
+
destProof: LEGACY_STORAGE_KEYS.destProof(orderId, order.source, order.destination),
|
|
16449
|
+
getRequest: LEGACY_STORAGE_KEYS.getRequest(orderId, order.source, order.destination),
|
|
16450
|
+
sourceProof: LEGACY_STORAGE_KEYS.sourceProof(orderId, order.source, order.destination),
|
|
16451
|
+
postCommitment: LEGACY_STORAGE_KEYS.postCommitment(orderId, order.source, order.destination)
|
|
16452
|
+
},
|
|
16453
|
+
{
|
|
16454
|
+
destProof: LEGACY_STORAGE_KEYS.destProof(orderId),
|
|
16455
|
+
getRequest: LEGACY_STORAGE_KEYS.getRequest(orderId),
|
|
16456
|
+
sourceProof: LEGACY_STORAGE_KEYS.sourceProof(orderId),
|
|
16457
|
+
postCommitment: LEGACY_STORAGE_KEYS.postCommitment(orderId)
|
|
16458
|
+
}
|
|
16459
|
+
];
|
|
16460
|
+
}
|
|
16461
|
+
async getRecoveryItem(currentKey, legacyKeys) {
|
|
16462
|
+
const current = await this.ctx.cancellationStorage.getItem(currentKey);
|
|
16463
|
+
if (current) return current;
|
|
16464
|
+
for (const legacyKey of new Set(legacyKeys)) {
|
|
16465
|
+
if (legacyKey === currentKey) continue;
|
|
16466
|
+
const legacy = await this.ctx.cancellationStorage.getItem(legacyKey);
|
|
16467
|
+
if (!legacy) continue;
|
|
16468
|
+
await this.ctx.cancellationStorage.setItem(currentKey, legacy);
|
|
16469
|
+
await this.ctx.cancellationStorage.removeItem(legacyKey);
|
|
16470
|
+
return legacy;
|
|
16471
|
+
}
|
|
16472
|
+
return null;
|
|
16473
|
+
}
|
|
16474
|
+
async removeRecoveryItems(...keys) {
|
|
16475
|
+
await Promise.all(
|
|
16476
|
+
[...new Set(keys)].map((key) => this.ctx.cancellationStorage.removeItem(key))
|
|
16477
|
+
);
|
|
16478
|
+
}
|
|
16479
|
+
/**
|
|
16480
|
+
* Returns the order identifier required to persist or clear recovery state.
|
|
16481
|
+
*
|
|
16482
|
+
* @param order - The order being cancelled.
|
|
16483
|
+
* @throws If the order has no identifier.
|
|
16484
|
+
*/
|
|
16485
|
+
orderId(order) {
|
|
16486
|
+
if (!order.id) throw new Error("An order id is required to recover cancellation");
|
|
16487
|
+
return order.id;
|
|
16488
|
+
}
|
|
16489
|
+
/**
|
|
16490
|
+
* Reads the Hyperbridge response receipt for a GET request commitment.
|
|
16491
|
+
*
|
|
16492
|
+
* @param hyperbridge - Hyperbridge chain client used to query the receipt.
|
|
16493
|
+
* @param commitment - Commitment of the GET request.
|
|
16494
|
+
* @returns The receipt commitment when delivered, otherwise `undefined`.
|
|
16495
|
+
*/
|
|
16155
16496
|
async queryDeliveredReceipt(hyperbridge, commitment) {
|
|
16156
16497
|
return hyperbridge.queryResponseReceipt(commitment);
|
|
16157
16498
|
}
|
|
16499
|
+
/**
|
|
16500
|
+
* Polls Hyperbridge until it records a response receipt for the GET request.
|
|
16501
|
+
*
|
|
16502
|
+
* @param hyperbridge - Hyperbridge chain client used to query the receipt.
|
|
16503
|
+
* @param commitment - Commitment of the GET request.
|
|
16504
|
+
* @returns The delivered response receipt commitment.
|
|
16505
|
+
* @throws If no receipt is observed within the configured retry limit.
|
|
16506
|
+
*/
|
|
16158
16507
|
async pollDeliveredReceipt(hyperbridge, commitment) {
|
|
16159
16508
|
this.logger.info(`Polling Hyperbridge GET response receipt for ${commitment}`);
|
|
16160
16509
|
return retryPromise(
|
|
@@ -17367,6 +17716,178 @@ var OrderStatusChecker = class {
|
|
|
17367
17716
|
return true;
|
|
17368
17717
|
}
|
|
17369
17718
|
};
|
|
17719
|
+
var COMMITMENT_PATTERN = /^0x[0-9a-f]{64}$/i;
|
|
17720
|
+
var LiquidityEngine = class {
|
|
17721
|
+
/**
|
|
17722
|
+
* @param queryClient - Nexus GraphQL client attached to the gateway.
|
|
17723
|
+
* @param chainConfigService - Resolves token decimals for formatted results.
|
|
17724
|
+
*/
|
|
17725
|
+
constructor(queryClient, chainConfigService) {
|
|
17726
|
+
this.queryClient = queryClient;
|
|
17727
|
+
this.chainConfigService = chainConfigService;
|
|
17728
|
+
}
|
|
17729
|
+
queryClient;
|
|
17730
|
+
chainConfigService;
|
|
17731
|
+
/**
|
|
17732
|
+
* Retrieves the newest directional Phantom snapshot for a pair and its
|
|
17733
|
+
* indexed output-token liquidity.
|
|
17734
|
+
*
|
|
17735
|
+
* Nexus filters balances to the canonical output token, then aggregates them
|
|
17736
|
+
* overall and by chain. The returned amounts are decimal strings: the total
|
|
17737
|
+
* uses the canonical Base output-token decimals, while each chain group uses
|
|
17738
|
+
* that chain's token decimals. They describe `snapshotTime`, not live
|
|
17739
|
+
* reservations or fill guarantees.
|
|
17740
|
+
*
|
|
17741
|
+
* @param params - Canonical Phantom-market input and output token addresses.
|
|
17742
|
+
* @returns The latest snapshot, or `undefined` if Nexus has no snapshot for
|
|
17743
|
+
* the directional pair.
|
|
17744
|
+
* @throws {InvalidAvailableLiquiditySnapshotError} If Nexus returns malformed
|
|
17745
|
+
* or internally inconsistent snapshot data.
|
|
17746
|
+
*/
|
|
17747
|
+
async getAvailableLiquiditySnapshot(params) {
|
|
17748
|
+
const tokenIn = normalizeEvmAddress(params.tokenIn, "tokenIn");
|
|
17749
|
+
const tokenOut = normalizeEvmAddress(params.tokenOut, "tokenOut");
|
|
17750
|
+
const response = await this.queryClient.request(
|
|
17751
|
+
LATEST_PHANTOM_ORDER_LIQUIDITY_SNAPSHOT,
|
|
17752
|
+
{ tokenA: tokenIn, tokenB: tokenOut }
|
|
17753
|
+
);
|
|
17754
|
+
const node = response?.phantomOrderPriceSnapshots?.nodes?.[0];
|
|
17755
|
+
if (!node) return;
|
|
17756
|
+
const commitment = node.commitment.toLowerCase();
|
|
17757
|
+
if (!COMMITMENT_PATTERN.test(commitment)) {
|
|
17758
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment || "<missing>", "commitment is not bytes32 hex");
|
|
17759
|
+
}
|
|
17760
|
+
if (node.tokenA.toLowerCase() !== tokenIn || node.tokenB.toLowerCase() !== tokenOut) {
|
|
17761
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, "snapshot token pair does not match the query");
|
|
17762
|
+
}
|
|
17763
|
+
const snapshotTime = new Date(dateStringtoTimestamp(node.snapshotTime));
|
|
17764
|
+
if (Number.isNaN(snapshotTime.getTime())) {
|
|
17765
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, "snapshotTime is invalid");
|
|
17766
|
+
}
|
|
17767
|
+
const { totalLiquidity, providerCount, liquidityByChain } = await this.querySnapshotLiquidityAggregates({
|
|
17768
|
+
commitment,
|
|
17769
|
+
tokenAddress: tokenOut
|
|
17770
|
+
});
|
|
17771
|
+
return {
|
|
17772
|
+
totalLiquidity: this.formatLiquidity(totalLiquidity, "EVM-8453" /* BASE_MAINNET */, tokenOut, commitment),
|
|
17773
|
+
providerCount,
|
|
17774
|
+
tokenAddress: tokenOut,
|
|
17775
|
+
snapshotTime,
|
|
17776
|
+
liquidityByChain: liquidityByChain.map((group) => ({
|
|
17777
|
+
...group,
|
|
17778
|
+
totalLiquidity: this.formatLiquidity(group.totalLiquidity, group.chain, group.tokenAddress, commitment)
|
|
17779
|
+
}))
|
|
17780
|
+
};
|
|
17781
|
+
}
|
|
17782
|
+
/**
|
|
17783
|
+
* Requests server-side sums and distinct provider counts for one immutable
|
|
17784
|
+
* snapshot/output-token pair, including chain-level aggregate groups.
|
|
17785
|
+
*
|
|
17786
|
+
* `commitment` uniquely identifies the selected snapshot
|
|
17787
|
+
*/
|
|
17788
|
+
async querySnapshotLiquidityAggregates(params) {
|
|
17789
|
+
const response = await this.queryClient.request(
|
|
17790
|
+
LIQUIDITY_PROVIDER_BALANCES,
|
|
17791
|
+
{ commitment: params.commitment, tokenAddress: params.tokenAddress }
|
|
17792
|
+
);
|
|
17793
|
+
const connection = response?.liquidityProviderBalances;
|
|
17794
|
+
const aggregates = connection?.aggregates;
|
|
17795
|
+
if (!connection || !aggregates) {
|
|
17796
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17797
|
+
params.commitment,
|
|
17798
|
+
"liquidityProviderBalances aggregates are missing"
|
|
17799
|
+
);
|
|
17800
|
+
}
|
|
17801
|
+
const totalLiquidity = parseSnapshotBigInt(aggregates.sum.balance ?? "0", params.commitment, "total balance");
|
|
17802
|
+
const providerCount = parseProviderCount(aggregates.distinctCount.providerId, params.commitment, "total");
|
|
17803
|
+
const liquidityByChain = connection.groupedAggregates.map((group, index) => {
|
|
17804
|
+
const [chain, tokenAddress] = group.keys;
|
|
17805
|
+
if (!chain?.trim() || !tokenAddress) {
|
|
17806
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17807
|
+
params.commitment,
|
|
17808
|
+
`liquidity group ${index} has invalid keys`
|
|
17809
|
+
);
|
|
17810
|
+
}
|
|
17811
|
+
const normalizedTokenAddress = normalizeIndexedLiquidityAddress(
|
|
17812
|
+
tokenAddress,
|
|
17813
|
+
params.commitment,
|
|
17814
|
+
`liquidity group ${index} tokenAddress`
|
|
17815
|
+
);
|
|
17816
|
+
if (normalizedTokenAddress !== params.tokenAddress) {
|
|
17817
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17818
|
+
params.commitment,
|
|
17819
|
+
`liquidity group ${index} tokenAddress does not match the snapshot output token`
|
|
17820
|
+
);
|
|
17821
|
+
}
|
|
17822
|
+
return {
|
|
17823
|
+
chain: chain.trim(),
|
|
17824
|
+
tokenAddress: normalizedTokenAddress,
|
|
17825
|
+
totalLiquidity: parseSnapshotBigInt(
|
|
17826
|
+
group.sum.balance ?? "0",
|
|
17827
|
+
params.commitment,
|
|
17828
|
+
`liquidity group ${index} balance`
|
|
17829
|
+
),
|
|
17830
|
+
providerCount: parseProviderCount(
|
|
17831
|
+
group.distinctCount.providerId,
|
|
17832
|
+
params.commitment,
|
|
17833
|
+
`liquidity group ${index}`
|
|
17834
|
+
)
|
|
17835
|
+
};
|
|
17836
|
+
});
|
|
17837
|
+
const groupedTotal = liquidityByChain.reduce((sum, group) => sum + group.totalLiquidity, 0n);
|
|
17838
|
+
if (groupedTotal !== totalLiquidity) {
|
|
17839
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17840
|
+
params.commitment,
|
|
17841
|
+
"grouped liquidity does not match the total liquidity"
|
|
17842
|
+
);
|
|
17843
|
+
}
|
|
17844
|
+
return { totalLiquidity, providerCount, liquidityByChain };
|
|
17845
|
+
}
|
|
17846
|
+
/** Formats a raw amount using the configured decimals for its chain/token. */
|
|
17847
|
+
formatLiquidity(amount, chain, tokenAddress, commitment) {
|
|
17848
|
+
const decimals = this.chainConfigService.getAssetMetadataByAddress(chain, tokenAddress)?.decimals;
|
|
17849
|
+
if (decimals === void 0) {
|
|
17850
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17851
|
+
commitment,
|
|
17852
|
+
`token decimals are not configured for ${tokenAddress} on ${chain}`
|
|
17853
|
+
);
|
|
17854
|
+
}
|
|
17855
|
+
return formatUnits(amount, decimals);
|
|
17856
|
+
}
|
|
17857
|
+
};
|
|
17858
|
+
var InvalidAvailableLiquiditySnapshotError = class extends Error {
|
|
17859
|
+
/** Creates an error that identifies the invalid snapshot and field/reason. */
|
|
17860
|
+
constructor(commitment, reason) {
|
|
17861
|
+
super(`Invalid available-liquidity snapshot ${commitment}: ${reason}`);
|
|
17862
|
+
this.name = "InvalidAvailableLiquiditySnapshotError";
|
|
17863
|
+
}
|
|
17864
|
+
};
|
|
17865
|
+
function parseSnapshotBigInt(value, commitment, field) {
|
|
17866
|
+
try {
|
|
17867
|
+
const amount = BigInt(value);
|
|
17868
|
+
if (amount < 0n) {
|
|
17869
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} cannot be negative`);
|
|
17870
|
+
}
|
|
17871
|
+
return amount;
|
|
17872
|
+
} catch (error) {
|
|
17873
|
+
if (error instanceof InvalidAvailableLiquiditySnapshotError) throw error;
|
|
17874
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} is not an integer`);
|
|
17875
|
+
}
|
|
17876
|
+
}
|
|
17877
|
+
function parseProviderCount(value, commitment, field) {
|
|
17878
|
+
const count = Number(value);
|
|
17879
|
+
if (!Number.isSafeInteger(count) || count < 0) {
|
|
17880
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} provider count is invalid`);
|
|
17881
|
+
}
|
|
17882
|
+
return count;
|
|
17883
|
+
}
|
|
17884
|
+
function normalizeIndexedLiquidityAddress(address, commitment, field) {
|
|
17885
|
+
try {
|
|
17886
|
+
return normalizeEvmAddress(address, field);
|
|
17887
|
+
} catch {
|
|
17888
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} is not a valid EVM address`);
|
|
17889
|
+
}
|
|
17890
|
+
}
|
|
17370
17891
|
|
|
17371
17892
|
// src/protocols/intents/quote/types.ts
|
|
17372
17893
|
var UnsupportedIntentQuoteStrategyError = class extends Error {
|
|
@@ -17653,12 +18174,14 @@ var PhantomSnapshotIntentQuoteStrategy = class {
|
|
|
17653
18174
|
constructor(chainConfigService, getQueryClient) {
|
|
17654
18175
|
this.chainConfigService = chainConfigService;
|
|
17655
18176
|
this.getQueryClient = getQueryClient;
|
|
18177
|
+
this.pairResolver = new PhantomSnapshotPairResolver(chainConfigService);
|
|
17656
18178
|
}
|
|
17657
18179
|
chainConfigService;
|
|
17658
18180
|
getQueryClient;
|
|
18181
|
+
pairResolver;
|
|
17659
18182
|
async quote(params, source, destination) {
|
|
17660
18183
|
validateQuoteParams(params);
|
|
17661
|
-
const pair = this.
|
|
18184
|
+
const pair = this.pairResolver.resolve(params, source.stateMachineId, destination.stateMachineId);
|
|
17662
18185
|
if (!pair) {
|
|
17663
18186
|
throw new UnsupportedIntentQuotePairError({
|
|
17664
18187
|
source: source.stateMachineId,
|
|
@@ -17731,7 +18254,13 @@ var PhantomSnapshotIntentQuoteStrategy = class {
|
|
|
17731
18254
|
throw new InvalidPhantomSnapshotError(snapshot.commitment, "snapshotTime is invalid");
|
|
17732
18255
|
}
|
|
17733
18256
|
}
|
|
17734
|
-
|
|
18257
|
+
};
|
|
18258
|
+
var PhantomSnapshotPairResolver = class {
|
|
18259
|
+
constructor(chainConfigService) {
|
|
18260
|
+
this.chainConfigService = chainConfigService;
|
|
18261
|
+
}
|
|
18262
|
+
chainConfigService;
|
|
18263
|
+
resolve(params, sourceStateMachineId, destinationStateMachineId) {
|
|
17735
18264
|
const tokenIn = this.resolveBaseSnapshotToken(sourceStateMachineId, params.tokenIn);
|
|
17736
18265
|
const tokenOut = this.resolveBaseSnapshotToken(destinationStateMachineId, params.tokenOut);
|
|
17737
18266
|
if (!tokenIn || !tokenOut || !isSupportedSnapshotPair(tokenIn.symbol, tokenOut.symbol)) return;
|
|
@@ -17783,6 +18312,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
17783
18312
|
gasEstimator;
|
|
17784
18313
|
/** Quote strategies for pricing orders before placement, keyed by strategy name. */
|
|
17785
18314
|
quoteStrategies;
|
|
18315
|
+
/** Resolves order tokens to canonical Phantom snapshot market pairs. */
|
|
18316
|
+
phantomSnapshotPairResolver;
|
|
17786
18317
|
/**
|
|
17787
18318
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
17788
18319
|
*
|
|
@@ -17826,6 +18357,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
17826
18357
|
this.bidManager = bidManager;
|
|
17827
18358
|
this.gasEstimator = gasEstimator;
|
|
17828
18359
|
this._crypto = crypto;
|
|
18360
|
+
this.phantomSnapshotPairResolver = new PhantomSnapshotPairResolver(dest.configService);
|
|
17829
18361
|
this.quoteStrategies = {
|
|
17830
18362
|
phantom_snapshot: new PhantomSnapshotIntentQuoteStrategy(
|
|
17831
18363
|
dest.configService,
|
|
@@ -17904,13 +18436,43 @@ var IntentGateway = class _IntentGateway {
|
|
|
17904
18436
|
if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
|
|
17905
18437
|
return handler.quote({ ...params, strategy }, source, destination);
|
|
17906
18438
|
}
|
|
18439
|
+
/**
|
|
18440
|
+
* Returns the output-token liquidity measured in the latest directional
|
|
18441
|
+
* Phantom snapshot for this gateway's source and destination.
|
|
18442
|
+
*
|
|
18443
|
+
* Pair resolution uses the same canonical Base market as {@link quoteIntent}.
|
|
18444
|
+
* The snapshot itself determines the output token and chain to aggregate. The
|
|
18445
|
+
* amount is in the token's smallest unit and reflects the indexer's
|
|
18446
|
+
* `snapshotTime`; it is not a live reservation or fill guarantee.
|
|
18447
|
+
*
|
|
18448
|
+
* Requires a prior call to {@link withQueryClient}.
|
|
18449
|
+
*/
|
|
18450
|
+
async queryAvailableLiquidity(params) {
|
|
18451
|
+
const { queryClient } = this.requireIndexer();
|
|
18452
|
+
const sourceStateMachineId = this.source.config.stateMachineId;
|
|
18453
|
+
const destinationStateMachineId = this.dest.config.stateMachineId;
|
|
18454
|
+
const pair = this.phantomSnapshotPairResolver.resolve(params, sourceStateMachineId, destinationStateMachineId);
|
|
18455
|
+
if (!pair) {
|
|
18456
|
+
throw new UnsupportedIntentQuotePairError({
|
|
18457
|
+
source: sourceStateMachineId,
|
|
18458
|
+
destination: destinationStateMachineId,
|
|
18459
|
+
tokenIn: params.tokenIn,
|
|
18460
|
+
tokenOut: params.tokenOut,
|
|
18461
|
+
quoteSource: "Phantom snapshot pair"
|
|
18462
|
+
});
|
|
18463
|
+
}
|
|
18464
|
+
return new LiquidityEngine(queryClient, this.dest.configService).getAvailableLiquiditySnapshot({
|
|
18465
|
+
tokenIn: pair.tokenA,
|
|
18466
|
+
tokenOut: pair.tokenB
|
|
18467
|
+
});
|
|
18468
|
+
}
|
|
17907
18469
|
/**
|
|
17908
18470
|
* Bidirectional async generator that orchestrates the full order lifecycle:
|
|
17909
18471
|
* placement, fee estimation, bid collection, and execution.
|
|
17910
18472
|
*
|
|
17911
18473
|
* **Yield/receive protocol:**
|
|
17912
|
-
* 1. If `order.fees` is unset or zero, estimates gas and sets
|
|
17913
|
-
*
|
|
18474
|
+
* 1. If `order.fees` is unset or zero, estimates gas on an internal copy and sets
|
|
18475
|
+
* same-chain fees to twice the estimate. Cross-chain orders retain a 1% buffer
|
|
17914
18476
|
* and include an additional 600k-gas fee uplift, while the wei cost used for
|
|
17915
18477
|
* the `value` field receives a 2% buffer.
|
|
17916
18478
|
* 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, sessionPrivateKey }`.
|
|
@@ -17920,8 +18482,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
17920
18482
|
* 4. Delegates to {@link OrderExecutor.executeOrder} and forwards all
|
|
17921
18483
|
* subsequent status updates until the order is filled, exhausted, or fails.
|
|
17922
18484
|
*
|
|
17923
|
-
* @param order - The order to place and execute. `order.fees`
|
|
17924
|
-
*
|
|
18485
|
+
* @param order - The order to place and execute. It is not mutated. `order.fees`
|
|
18486
|
+
* may be 0; fees are estimated automatically if so.
|
|
17925
18487
|
* @param graffiti - Optional bytes32 tag for orderflow attribution /
|
|
17926
18488
|
* revenue share. Defaults to {@link DEFAULT_GRAFFITI}.
|
|
17927
18489
|
* @param options - Optional tuning parameters:
|
|
@@ -17934,10 +18496,11 @@ var IntentGateway = class _IntentGateway {
|
|
|
17934
18496
|
* estimation returns zero.
|
|
17935
18497
|
*/
|
|
17936
18498
|
async *execute(order, graffiti = DEFAULT_GRAFFITI, options) {
|
|
18499
|
+
const executionOrder = { ...order };
|
|
17937
18500
|
let value;
|
|
17938
|
-
if (!
|
|
18501
|
+
if (!executionOrder.fees || executionOrder.fees === 0n) {
|
|
17939
18502
|
const estimate = await this.gasEstimator.estimateFillOrder({
|
|
17940
|
-
order,
|
|
18503
|
+
order: executionOrder,
|
|
17941
18504
|
maxPriorityFeePerGasBumpPercent: options?.maxPriorityFeePerGasBumpPercent,
|
|
17942
18505
|
maxFeePerGasBumpPercent: options?.maxFeePerGasBumpPercent
|
|
17943
18506
|
});
|
|
@@ -17952,9 +18515,9 @@ var IntentGateway = class _IntentGateway {
|
|
|
17952
18515
|
"source",
|
|
17953
18516
|
this.source.config.stateMachineId
|
|
17954
18517
|
);
|
|
17955
|
-
|
|
18518
|
+
executionOrder.fees = isSameChain ? estimate.totalGasInFeeToken * 2n : estimate.totalGasInFeeToken + (crossChainFeeBump + estimate.totalGasInFeeToken * 1n / 100n);
|
|
17956
18519
|
}
|
|
17957
|
-
const placeOrderGen = this.orderPlacer.placeOrder(
|
|
18520
|
+
const placeOrderGen = this.orderPlacer.placeOrder(executionOrder, graffiti);
|
|
17958
18521
|
const placeOrderFirst = await placeOrderGen.next();
|
|
17959
18522
|
if (placeOrderFirst.done) {
|
|
17960
18523
|
throw new Error("placeOrder generator completed without yielding");
|
|
@@ -18065,13 +18628,20 @@ var IntentGateway = class _IntentGateway {
|
|
|
18065
18628
|
const gen = this.execute(order, graffiti, options);
|
|
18066
18629
|
try {
|
|
18067
18630
|
let input;
|
|
18631
|
+
let finalizedOrder;
|
|
18068
18632
|
while (true) {
|
|
18069
18633
|
const { value, done } = await gen.next(input);
|
|
18070
18634
|
input = void 0;
|
|
18071
18635
|
if (done) break;
|
|
18072
|
-
if (value.status === "
|
|
18636
|
+
if (value.status === "ORDER_PLACED") {
|
|
18637
|
+
finalizedOrder = value.order;
|
|
18073
18638
|
yield value;
|
|
18074
|
-
|
|
18639
|
+
} else if (value.status === "BIDS_RECEIVED") {
|
|
18640
|
+
if (!finalizedOrder) {
|
|
18641
|
+
throw new Error("Received bids before the order was finalized");
|
|
18642
|
+
}
|
|
18643
|
+
yield value;
|
|
18644
|
+
input = await this.autoSelect(finalizedOrder, value.bids);
|
|
18075
18645
|
} else if (value.status === "AWAITING_PLACE_ORDER") {
|
|
18076
18646
|
input = yield value;
|
|
18077
18647
|
} else {
|
|
@@ -22849,6 +23419,6 @@ async function teleportDot(param_) {
|
|
|
22849
23419
|
return stream;
|
|
22850
23420
|
}
|
|
22851
23421
|
|
|
22852
|
-
export { ADDRESS_ZERO2 as ADDRESS_ZERO, BundlerMethod, ChainConfigService, Chains, CryptoUtils, DEFAULT_ADDRESS, DEFAULT_GRAFFITI, DOMAIN_TYPEHASH, DUMMY_PRIVATE_KEY, ERC20Method, ERC7821_BATCH_MODE, EvmChain, ABI as EvmHostABI, EvmLanguage, HyperClientStatus, HyperFungibleToken, HyperFungibleTokenABI, IntentGateway, ABI3 as IntentGatewayABI, IntentOrderStatus, IntentsCoprocessor, InvalidPhantomSnapshotError, IsmpClient, MOCK_ADDRESS, ORDER_V2_PARAM_TYPE, OrderStatus, OrderStatusChecker, PACKED_USEROP_TYPEHASH, PLACE_ORDER_SELECTOR, PhantomSnapshotUnavailableError, PharosChain, PolkadotHubChain, REQUEST_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, RESPONSE_COMMITMENTS_SLOT, RESPONSE_RECEIPTS_SLOT, RequestKind, RequestStatus, SELECT_SOLVER_TYPEHASH, STATE_COMMITMENTS_SLOT, SubstrateChain, Swap, TESTNET_CHAINS, TeleportStatus, TimeoutStatus, TokenGateway, TronChain, USE_ETHERSCAN_CHAINS, UnsupportedIntentQuotePairError, UnsupportedIntentQuoteStrategyError, WrappedHyperFungibleTokenABI, __test, adjustDecimals, bytes20ToBytes32, bytes32ToBytes20, calculateAllowanceMappingLocation, calculateBalanceMappingLocation, chainConfigs, constructRedeemEscrowRequestBody, constructRefundEscrowRequestBody, convertCodecToIGetRequest, convertCodecToIProof, convertIGetRequestToCodec, convertIProofToCodec, convertStateIdToStateMachineId, convertStateMachineEnumToString, convertStateMachineIdToEnum, createEvmChain, createQueryClient, decodeERC7821ExecuteBatch, decodeUserOpScale, encodeERC7821ExecuteBatch, encodeISMPMessage, encodeStateMachineId, encodeUserOpScale, encodeWithdrawalRequest, estimateGasForPost, fetchPrice, fetchSourceProof, generateRootWithProof, getChainId, getConfigByStateMachineId, getContractCallInput, getContractCallInputs, getGasPriceFromEtherscan, getOrFetchStorageSlot, getOrderPlacedFromTx, getPostRequestEventFromTx, getPostResponseEventFromTx, getRequestCommitment, getStateCommitmentFieldSlot, getStateCommitmentSlot, getStorageSlot, getViemChain, hexToString, hyperbridgeAddress, maxBigInt, normalizeAddressForEvmBytes32, normalizeAddressForStateMachine, normalizeEvmChainId, normalizeStateMachineId, orderCommitment, parseStateMachineId, pharosAtlantic, pharosMainnet, polkadotAssetHubPaseo, polkadotHubMainnet, postRequestCommitment, queryAssetTeleported, queryGetRequest, queryPostRequest, quoteUniswap, requestCommitmentKey, responseCommitmentKey, retryPromise, teleport, teleportDot, transformOrderForContract, tronChainIds, tronNile };
|
|
23422
|
+
export { ADDRESS_ZERO2 as ADDRESS_ZERO, BundlerMethod, ChainConfigService, Chains, CryptoUtils, DEFAULT_ADDRESS, DEFAULT_GRAFFITI, DOMAIN_TYPEHASH, DUMMY_PRIVATE_KEY, ERC20Method, ERC7821_BATCH_MODE, EvmChain, ABI as EvmHostABI, EvmLanguage, HyperClientStatus, HyperFungibleToken, HyperFungibleTokenABI, IntentGateway, ABI3 as IntentGatewayABI, IntentOrderStatus, IntentsCoprocessor, InvalidPhantomSnapshotError, IsmpClient, MOCK_ADDRESS, ORDER_V2_PARAM_TYPE, OrderStatus, OrderStatusChecker, PACKED_USEROP_TYPEHASH, PLACE_ORDER_SELECTOR, PhantomSnapshotUnavailableError, PharosChain, PolkadotHubChain, REQUEST_COMMITMENTS_SLOT, REQUEST_RECEIPTS_SLOT, RESPONSE_COMMITMENTS_SLOT, RESPONSE_RECEIPTS_SLOT, RequestKind, RequestStatus, SELECT_SOLVER_TYPEHASH, STATE_COMMITMENTS_SLOT, SubstrateChain, Swap, TESTNET_CHAINS, TeleportStatus, TimeoutStatus, TokenGateway, TronChain, USE_ETHERSCAN_CHAINS, UnsupportedIntentQuotePairError, UnsupportedIntentQuoteStrategyError, WrappedHyperFungibleTokenABI, __test, adjustDecimals, bytes20ToBytes32, bytes32ToBytes20, calculateAllowanceMappingLocation, calculateBalanceMappingLocation, chainConfigs, constructRedeemEscrowRequestBody, constructRefundEscrowRequestBody, convertCodecToIGetRequest, convertCodecToIProof, convertIGetRequestToCodec, convertIProofToCodec, convertStateIdToStateMachineId, convertStateMachineEnumToString, convertStateMachineIdToEnum, createEvmChain, createQueryClient, decodeERC7821ExecuteBatch, decodeUserOpScale, encodeERC7821ExecuteBatch, encodeISMPMessage, encodeStateMachineId, encodeUserOpScale, encodeWithdrawalRequest, estimateGasForPost, fetchPrice, fetchSourceProof, generateRootWithProof, getChainId, getConfigByStateMachineId, getContractCallInput, getContractCallInputs, getGasPriceFromEtherscan, getOrFetchStorageSlot, getOrderPlacedFromTx, getPostRequestEventFromTx, getPostResponseEventFromTx, getRequestCommitment, getStateCommitmentFieldSlot, getStateCommitmentSlot, getStorageSlot, getViemChain, hexToString, hyperbridgeAddress, maxBigInt, normalizeAddressForEvmBytes32, normalizeAddressForStateMachine, normalizeEvmAddress, normalizeEvmChainId, normalizeStateMachineId, orderCommitment, parseStateMachineId, pharosAtlantic, pharosMainnet, polkadotAssetHubPaseo, polkadotHubMainnet, postRequestCommitment, queryAssetTeleported, queryGetRequest, queryPostRequest, quoteUniswap, requestCommitmentKey, responseCommitmentKey, retryPromise, teleport, teleportDot, transformOrderForContract, tronChainIds, tronNile };
|
|
22853
23423
|
//# sourceMappingURL=index.js.map
|
|
22854
23424
|
//# sourceMappingURL=index.js.map
|