@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.cjs
CHANGED
|
@@ -2720,6 +2720,7 @@ var chainConfigs = {
|
|
|
2720
2720
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2721
2721
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2722
2722
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2723
|
+
SimplexPaymaster: "0xD4340d7466e040626383cb9cda9307ba8E081149",
|
|
2723
2724
|
Usdt0Oft: "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee"
|
|
2724
2725
|
},
|
|
2725
2726
|
rpcEnvKey: "ETH_MAINNET",
|
|
@@ -2773,7 +2774,8 @@ var chainConfigs = {
|
|
|
2773
2774
|
UniswapV4StateView: "0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4",
|
|
2774
2775
|
Calldispatcher: "0xc71251c8b3e7b02697a84363eef6dce8dfbdf333",
|
|
2775
2776
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2776
|
-
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108"
|
|
2777
|
+
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2778
|
+
SimplexPaymaster: "0xeD02f9f0df8F562B89cC5b25867Ad3C2d61252A9"
|
|
2777
2779
|
// "Usdt0Oft": Not available on BSC
|
|
2778
2780
|
},
|
|
2779
2781
|
rpcEnvKey: "BSC_MAINNET",
|
|
@@ -2831,6 +2833,7 @@ var chainConfigs = {
|
|
|
2831
2833
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2832
2834
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2833
2835
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2836
|
+
SimplexPaymaster: "0x7281Bccb4f0BCE44F3B8542d1fC5e51c2F5fC08C",
|
|
2834
2837
|
Usdt0Oft: "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92"
|
|
2835
2838
|
},
|
|
2836
2839
|
rpcEnvKey: "ARBITRUM_MAINNET",
|
|
@@ -2885,6 +2888,7 @@ var chainConfigs = {
|
|
|
2885
2888
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2886
2889
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2887
2890
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2891
|
+
SimplexPaymaster: "0x15b3B03C870c7ef252029c35A12d3b339F5c8d7f",
|
|
2888
2892
|
AerodromeRouter: "0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43",
|
|
2889
2893
|
UniswapV4PositionManager: "0x7c5f5a4bbd8fd63184577525326123b519429bdc",
|
|
2890
2894
|
UniswapV4PoolManager: "0x498581ff718922c3f8e6a244956af099b2652b2b",
|
|
@@ -2947,6 +2951,7 @@ var chainConfigs = {
|
|
|
2947
2951
|
Permit2: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
|
|
2948
2952
|
EntryPointV08: "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108",
|
|
2949
2953
|
CirclePaymaster: "0x0578cFB241215b77442a541325d6A4E6dFE700Ec",
|
|
2954
|
+
SimplexPaymaster: "0xe99acFe0f5fC4C8ea54A187D8D3b05f136150095",
|
|
2950
2955
|
Usdt0Oft: "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"
|
|
2951
2956
|
},
|
|
2952
2957
|
rpcEnvKey: "POLYGON_MAINNET",
|
|
@@ -5242,6 +5247,9 @@ var ChainConfigService = class {
|
|
|
5242
5247
|
getCirclePaymasterAddress(chain) {
|
|
5243
5248
|
return this.getConfig(chain)?.addresses.CirclePaymaster;
|
|
5244
5249
|
}
|
|
5250
|
+
getSimplexPaymasterAddress(chain) {
|
|
5251
|
+
return this.getConfig(chain)?.addresses.SimplexPaymaster;
|
|
5252
|
+
}
|
|
5245
5253
|
getHyperbridgeAddress() {
|
|
5246
5254
|
return hyperbridgeAddress;
|
|
5247
5255
|
}
|
|
@@ -7062,6 +7070,16 @@ var ExpectedError = class _ExpectedError extends Error {
|
|
|
7062
7070
|
return error instanceof _ExpectedError;
|
|
7063
7071
|
}
|
|
7064
7072
|
};
|
|
7073
|
+
var MISSING_CONSENSUS_UPDATE_TIME_MESSAGE = "Consensus update time not found";
|
|
7074
|
+
var MissingConsensusUpdateTimeError = class _MissingConsensusUpdateTimeError extends Error {
|
|
7075
|
+
constructor(message = MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, options) {
|
|
7076
|
+
super(message, options);
|
|
7077
|
+
this.name = "Hyperbridge/SDK/MissingConsensusUpdateTimeError";
|
|
7078
|
+
}
|
|
7079
|
+
static isError(error) {
|
|
7080
|
+
return error instanceof _MissingConsensusUpdateTimeError || error instanceof Error && error.message.toLowerCase().includes(MISSING_CONSENSUS_UPDATE_TIME_MESSAGE.toLowerCase());
|
|
7081
|
+
}
|
|
7082
|
+
};
|
|
7065
7083
|
|
|
7066
7084
|
// src/configs/constants.ts
|
|
7067
7085
|
var ISMP_PREFIX = ":child_storage:default:ISMPv2";
|
|
@@ -7375,8 +7393,15 @@ var SubstrateChain = class _SubstrateChain {
|
|
|
7375
7393
|
id: stateMachineId,
|
|
7376
7394
|
height: Number(stateMachineHeight.height)
|
|
7377
7395
|
};
|
|
7378
|
-
|
|
7379
|
-
|
|
7396
|
+
try {
|
|
7397
|
+
const updateTime = await this.rpcClient.call("ismp_queryStateMachineUpdateTime", [payload]);
|
|
7398
|
+
return BigInt(updateTime);
|
|
7399
|
+
} catch (error) {
|
|
7400
|
+
if (MissingConsensusUpdateTimeError.isError(error)) {
|
|
7401
|
+
throw new MissingConsensusUpdateTimeError(MISSING_CONSENSUS_UPDATE_TIME_MESSAGE, { cause: error });
|
|
7402
|
+
}
|
|
7403
|
+
throw error;
|
|
7404
|
+
}
|
|
7380
7405
|
}
|
|
7381
7406
|
/**
|
|
7382
7407
|
* Get the challenge period for a given state machine id.
|
|
@@ -8122,26 +8147,76 @@ var IntentsCoprocessor = class _IntentsCoprocessor {
|
|
|
8122
8147
|
};
|
|
8123
8148
|
}
|
|
8124
8149
|
/**
|
|
8125
|
-
*
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
const
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8150
|
+
* Reads the PhantomOrderRegistered events emitted in a single block.
|
|
8151
|
+
*/
|
|
8152
|
+
async getPhantomOrdersInBlock(blockNumber) {
|
|
8153
|
+
const blockHash = await this.api.rpc.chain.getBlockHash(blockNumber);
|
|
8154
|
+
const apiAt = await this.api.at(blockHash);
|
|
8155
|
+
const records = await apiAt.query.system.events();
|
|
8156
|
+
const orders = [];
|
|
8157
|
+
for (const { event } of records) {
|
|
8158
|
+
if (event.section !== "intentsCoprocessor" || event.method !== "PhantomOrderRegistered") continue;
|
|
8159
|
+
const [commitment, chain, createdAt, tokenA, tokenB, standardAmount] = event.data;
|
|
8160
|
+
orders.push({
|
|
8161
|
+
commitment: commitment.toHex(),
|
|
8162
|
+
chain: new TextDecoder().decode(util.hexToU8a(chain.toHex())),
|
|
8163
|
+
createdAt: createdAt.toNumber(),
|
|
8164
|
+
tokenA: tokenA.toHex(),
|
|
8165
|
+
tokenB: tokenB.toHex(),
|
|
8166
|
+
standardAmount: BigInt(standardAmount.toString())
|
|
8167
|
+
});
|
|
8168
|
+
}
|
|
8169
|
+
return orders;
|
|
8170
|
+
}
|
|
8171
|
+
/**
|
|
8172
|
+
* Polls for newly registered phantom orders, invoking the callback once per order.
|
|
8173
|
+
*
|
|
8174
|
+
* Each tick reads the current head and scans every block between the last one processed and that
|
|
8175
|
+
* head, so the block cursor — not the connection — determines what has been seen. This replaced a
|
|
8176
|
+
* system.events subscription, which was only as reliable as its socket: polkadot-js reconnects
|
|
8177
|
+
* the transport but does not reliably re-establish storage subscriptions, and anything emitted
|
|
8178
|
+
* while disconnected was lost silently. With a bid window measured in a handful of blocks, that
|
|
8179
|
+
* meant silently missed bids.
|
|
8180
|
+
*
|
|
8181
|
+
* Scanning a block range is gap-free rather than merely self-healing: an outage delays orders but
|
|
8182
|
+
* cannot drop them, because the cursor only advances past a block whose events were actually
|
|
8183
|
+
* read. Recovery replays the backlog.
|
|
8184
|
+
*
|
|
8185
|
+
* Returns a function that stops polling.
|
|
8186
|
+
*/
|
|
8187
|
+
pollPhantomOrders(callback, options = {}) {
|
|
8188
|
+
const { intervalMs = 6e3, maxBlocksPerPoll = 500, lookbackBlocks = 0, onError } = options;
|
|
8189
|
+
let cursor = null;
|
|
8190
|
+
let inFlight = false;
|
|
8191
|
+
let stopped = false;
|
|
8192
|
+
const tick = async () => {
|
|
8193
|
+
if (inFlight || stopped) return;
|
|
8194
|
+
inFlight = true;
|
|
8195
|
+
try {
|
|
8196
|
+
const head = (await this.api.rpc.chain.getHeader()).number.toNumber();
|
|
8197
|
+
if (cursor === null) {
|
|
8198
|
+
cursor = Math.max(head - 1 - lookbackBlocks, -1);
|
|
8199
|
+
}
|
|
8200
|
+
if (head <= cursor) return;
|
|
8201
|
+
const to = Math.min(head, cursor + maxBlocksPerPoll);
|
|
8202
|
+
for (let blockNumber = cursor + 1; blockNumber <= to; blockNumber++) {
|
|
8203
|
+
if (stopped) return;
|
|
8204
|
+
const orders = await this.getPhantomOrdersInBlock(blockNumber);
|
|
8205
|
+
for (const order of orders) callback(order);
|
|
8206
|
+
cursor = blockNumber;
|
|
8207
|
+
}
|
|
8208
|
+
} catch (err) {
|
|
8209
|
+
onError?.(err);
|
|
8210
|
+
} finally {
|
|
8211
|
+
inFlight = false;
|
|
8142
8212
|
}
|
|
8143
|
-
}
|
|
8144
|
-
|
|
8213
|
+
};
|
|
8214
|
+
void tick();
|
|
8215
|
+
const timer = setInterval(() => void tick(), intervalMs);
|
|
8216
|
+
return () => {
|
|
8217
|
+
stopped = true;
|
|
8218
|
+
clearInterval(timer);
|
|
8219
|
+
};
|
|
8145
8220
|
}
|
|
8146
8221
|
};
|
|
8147
8222
|
var TronChain = class _TronChain {
|
|
@@ -9274,7 +9349,12 @@ function sleep(ms) {
|
|
|
9274
9349
|
async function waitForChallengePeriod(chain, stateMachineHeight) {
|
|
9275
9350
|
const challengePeriod = await chain.challengePeriod(stateMachineHeight.id);
|
|
9276
9351
|
if (challengePeriod === BigInt(0)) return;
|
|
9277
|
-
const updateTime = await chain.stateMachineUpdateTime(stateMachineHeight)
|
|
9352
|
+
const updateTime = await retryPromise(() => chain.stateMachineUpdateTime(stateMachineHeight), {
|
|
9353
|
+
maxRetries: 3,
|
|
9354
|
+
backoffMs: 500,
|
|
9355
|
+
logMessage: "Fetching consensus update time while waiting for the challenge period",
|
|
9356
|
+
shouldRetry: (error) => !MissingConsensusUpdateTimeError.isError(error)
|
|
9357
|
+
});
|
|
9278
9358
|
let currentTimestamp = await chain.timestamp();
|
|
9279
9359
|
let timeElapsed = currentTimestamp - updateTime;
|
|
9280
9360
|
if (timeElapsed > challengePeriod) return;
|
|
@@ -9421,6 +9501,10 @@ function normalizeAddressForEvmBytes32(address) {
|
|
|
9421
9501
|
if (address.length === 66) return address;
|
|
9422
9502
|
return bytes20ToBytes32(address);
|
|
9423
9503
|
}
|
|
9504
|
+
function normalizeEvmAddress(address, field = "address") {
|
|
9505
|
+
if (!viem.isAddress(address)) throw new TypeError(`${field} must be a valid EVM address`);
|
|
9506
|
+
return address.toLowerCase();
|
|
9507
|
+
}
|
|
9424
9508
|
function normalizeAddressForStateMachine(address, stateMachineId) {
|
|
9425
9509
|
return isEvmChain(normalizeStateMachineId(stateMachineId)) ? normalizeAddressForEvmBytes32(address) : address;
|
|
9426
9510
|
}
|
|
@@ -9428,14 +9512,16 @@ var DEFAULT_LOGGER = consola.createConsola({
|
|
|
9428
9512
|
level: consola.LogLevels.silent
|
|
9429
9513
|
});
|
|
9430
9514
|
async function retryPromise(operation, retryConfig) {
|
|
9431
|
-
const { logger = DEFAULT_LOGGER, logMessage = "Retry operation failed" } = retryConfig;
|
|
9515
|
+
const { logger = DEFAULT_LOGGER, logMessage = "Retry operation failed", shouldRetry } = retryConfig;
|
|
9432
9516
|
let lastError;
|
|
9433
9517
|
for (let i = 0; i < retryConfig.maxRetries; i++) {
|
|
9434
9518
|
try {
|
|
9435
9519
|
return await operation();
|
|
9436
9520
|
} catch (error) {
|
|
9521
|
+
if (shouldRetry && !shouldRetry(error)) throw error;
|
|
9437
9522
|
logger.trace(`Retrying(${i}) > ${logMessage}`);
|
|
9438
9523
|
lastError = error;
|
|
9524
|
+
if (i === retryConfig.maxRetries - 1) break;
|
|
9439
9525
|
await new Promise((resolve) => setTimeout(resolve, retryConfig.backoffMs * 2 ** i));
|
|
9440
9526
|
}
|
|
9441
9527
|
}
|
|
@@ -11506,6 +11592,55 @@ query LatestPhantomOrderPriceSnapshot($tokenA: String!, $tokenB: String!) {
|
|
|
11506
11592
|
}
|
|
11507
11593
|
}
|
|
11508
11594
|
}`;
|
|
11595
|
+
var LATEST_PHANTOM_ORDER_LIQUIDITY_SNAPSHOT = `
|
|
11596
|
+
query LatestPhantomOrderLiquiditySnapshot($tokenA: String!, $tokenB: String!) {
|
|
11597
|
+
phantomOrderPriceSnapshots(
|
|
11598
|
+
filter: {
|
|
11599
|
+
and: [
|
|
11600
|
+
{ tokenA: { equalTo: $tokenA } }
|
|
11601
|
+
{ tokenB: { equalTo: $tokenB } }
|
|
11602
|
+
]
|
|
11603
|
+
}
|
|
11604
|
+
orderBy: SNAPSHOT_TIME_DESC
|
|
11605
|
+
first: 1
|
|
11606
|
+
) {
|
|
11607
|
+
nodes {
|
|
11608
|
+
commitment
|
|
11609
|
+
tokenA
|
|
11610
|
+
tokenB
|
|
11611
|
+
snapshotTime
|
|
11612
|
+
}
|
|
11613
|
+
}
|
|
11614
|
+
}`;
|
|
11615
|
+
var LIQUIDITY_PROVIDER_BALANCES = `
|
|
11616
|
+
query LiquidityProviderBalanceAggregates($commitment: String!, $tokenAddress: String!) {
|
|
11617
|
+
liquidityProviderBalances(
|
|
11618
|
+
filter: {
|
|
11619
|
+
and: [
|
|
11620
|
+
{ commitment: { equalTo: $commitment } }
|
|
11621
|
+
{ tokenAddress: { equalTo: $tokenAddress } }
|
|
11622
|
+
]
|
|
11623
|
+
}
|
|
11624
|
+
) {
|
|
11625
|
+
aggregates {
|
|
11626
|
+
sum {
|
|
11627
|
+
balance
|
|
11628
|
+
}
|
|
11629
|
+
distinctCount {
|
|
11630
|
+
providerId
|
|
11631
|
+
}
|
|
11632
|
+
}
|
|
11633
|
+
groupedAggregates(groupBy: [CHAIN, TOKEN_ADDRESS]) {
|
|
11634
|
+
keys
|
|
11635
|
+
sum {
|
|
11636
|
+
balance
|
|
11637
|
+
}
|
|
11638
|
+
distinctCount {
|
|
11639
|
+
providerId
|
|
11640
|
+
}
|
|
11641
|
+
}
|
|
11642
|
+
}
|
|
11643
|
+
}`;
|
|
11509
11644
|
var TOKEN_GATEWAY_ASSET_TELEPORTED_STATUS = `
|
|
11510
11645
|
query TokenGatewayAssetTeleportedStatus($commitment: String!) {
|
|
11511
11646
|
tokenGatewayAssetTeleportedV2s(
|
|
@@ -12090,6 +12225,7 @@ function createCancellationStorage(options = {}) {
|
|
|
12090
12225
|
const decoded = decodeIProof(value);
|
|
12091
12226
|
return decoded;
|
|
12092
12227
|
}
|
|
12228
|
+
if (key2.includes("postCommitment")) return value;
|
|
12093
12229
|
throw new Error(`Unknown storage key type: ${key2}`);
|
|
12094
12230
|
};
|
|
12095
12231
|
const setItem = async (key2, value) => {
|
|
@@ -12103,6 +12239,10 @@ function createCancellationStorage(options = {}) {
|
|
|
12103
12239
|
await baseStorage.setItem(key2, encoded);
|
|
12104
12240
|
return;
|
|
12105
12241
|
}
|
|
12242
|
+
if (key2.includes("postCommitment") && typeof value === "string") {
|
|
12243
|
+
await baseStorage.setItem(key2, value);
|
|
12244
|
+
return;
|
|
12245
|
+
}
|
|
12106
12246
|
throw new Error(`Unknown storage key type: ${key2}`);
|
|
12107
12247
|
};
|
|
12108
12248
|
const removeItem = async (key2) => {
|
|
@@ -12116,11 +12256,25 @@ function createCancellationStorage(options = {}) {
|
|
|
12116
12256
|
});
|
|
12117
12257
|
}
|
|
12118
12258
|
var STORAGE_KEYS = Object.freeze({
|
|
12119
|
-
destProof: (orderId) => `cancel-order:${orderId}:destProof`,
|
|
12120
|
-
getRequest: (orderId) => `cancel-order:${orderId}:getRequest`,
|
|
12121
|
-
sourceProof: (orderId) => `cancel-order:${orderId}:sourceProof`,
|
|
12122
|
-
postCommitment: (orderId) => `cancel-order:${orderId}:postCommitment`
|
|
12259
|
+
destProof: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:destProof`,
|
|
12260
|
+
getRequest: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:getRequest`,
|
|
12261
|
+
sourceProof: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:sourceProof`,
|
|
12262
|
+
postCommitment: (orderId, source, destination) => `cancel-order:${cancellationScope(orderId, source, destination)}:postCommitment`
|
|
12123
12263
|
});
|
|
12264
|
+
var LEGACY_STORAGE_KEYS = Object.freeze({
|
|
12265
|
+
destProof: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:destProof`,
|
|
12266
|
+
getRequest: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:getRequest`,
|
|
12267
|
+
sourceProof: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:sourceProof`,
|
|
12268
|
+
postCommitment: (orderId, source, destination) => `cancel-order:${legacyCancellationScope(orderId, source, destination)}:postCommitment`
|
|
12269
|
+
});
|
|
12270
|
+
function cancellationScope(orderId, source, destination) {
|
|
12271
|
+
if (!source || !destination) return orderId;
|
|
12272
|
+
return `${orderId}:${encodeURIComponent(normalizeStateMachineId(source))}:${encodeURIComponent(normalizeStateMachineId(destination))}`;
|
|
12273
|
+
}
|
|
12274
|
+
function legacyCancellationScope(orderId, source, destination) {
|
|
12275
|
+
if (!source || !destination) return orderId;
|
|
12276
|
+
return `${orderId}:${encodeURIComponent(source)}:${encodeURIComponent(destination)}`;
|
|
12277
|
+
}
|
|
12124
12278
|
function createUsedUserOpsStorage(options = {}) {
|
|
12125
12279
|
options.env ?? detectEnvironment();
|
|
12126
12280
|
const driver = loadDriver({ options }) ?? inMemoryDriver__default.default();
|
|
@@ -15286,6 +15440,29 @@ async function convertFeeTokenToWei(ctx, feeTokenAmount, feeTokenIn, evmChainID)
|
|
|
15286
15440
|
}
|
|
15287
15441
|
|
|
15288
15442
|
// src/protocols/intents/OrderPlacer.ts
|
|
15443
|
+
function deriveCanonicalPlacedOrder(order, args) {
|
|
15444
|
+
const canonicalOrder = {
|
|
15445
|
+
...order,
|
|
15446
|
+
user: args.user,
|
|
15447
|
+
source: args.source,
|
|
15448
|
+
destination: args.destination,
|
|
15449
|
+
deadline: args.deadline,
|
|
15450
|
+
nonce: args.nonce,
|
|
15451
|
+
fees: args.fees,
|
|
15452
|
+
session: args.session,
|
|
15453
|
+
predispatch: {
|
|
15454
|
+
assets: args.predispatch.map((asset) => ({ ...asset })),
|
|
15455
|
+
call: order.predispatch.call
|
|
15456
|
+
},
|
|
15457
|
+
inputs: args.inputs.map((asset) => ({ ...asset })),
|
|
15458
|
+
output: {
|
|
15459
|
+
beneficiary: args.beneficiary,
|
|
15460
|
+
assets: args.outputs.map((asset) => ({ ...asset })),
|
|
15461
|
+
call: order.output.call
|
|
15462
|
+
}
|
|
15463
|
+
};
|
|
15464
|
+
return { ...canonicalOrder, id: orderCommitment(canonicalOrder) };
|
|
15465
|
+
}
|
|
15289
15466
|
var OrderPlacer = class {
|
|
15290
15467
|
/**
|
|
15291
15468
|
* @param ctx - Shared IntentsV2 context providing the source chain client,
|
|
@@ -15302,17 +15479,16 @@ var OrderPlacer = class {
|
|
|
15302
15479
|
* 1. Yields `{ to, data, sessionPrivateKey }` — the caller must sign a
|
|
15303
15480
|
* transaction sending `data` to `to` and pass the signed transaction back
|
|
15304
15481
|
* via `gen.next(signedTx)`.
|
|
15305
|
-
* 2. Returns `{ order, transactionHash }` — the finalized order
|
|
15306
|
-
*
|
|
15307
|
-
* transaction hash.
|
|
15482
|
+
* 2. Returns `{ order, transactionHash }` — the finalized order rebuilt from
|
|
15483
|
+
* the canonical `OrderPlaced` fields with its computed `id`, plus the
|
|
15484
|
+
* placement transaction hash.
|
|
15308
15485
|
*
|
|
15309
15486
|
* A fresh ephemeral session key is generated for every call. The key is
|
|
15310
15487
|
* stored immediately (without a commitment) so it can be retrieved by
|
|
15311
15488
|
* address, then updated with the commitment once the `OrderPlaced` event
|
|
15312
|
-
* confirms the
|
|
15489
|
+
* confirms the canonical order.
|
|
15313
15490
|
*
|
|
15314
|
-
* @param order - The order to place.
|
|
15315
|
-
* with the generated session key address before yielding.
|
|
15491
|
+
* @param order - The order to place. It is not mutated.
|
|
15316
15492
|
* @param graffiti - Optional bytes32 tag for orderflow attribution /
|
|
15317
15493
|
* revenue share. Defaults to {@link DEFAULT_GRAFFITI} (bytes32 zero).
|
|
15318
15494
|
* @yields `{ to, data, sessionPrivateKey }` — target contract address,
|
|
@@ -15327,7 +15503,7 @@ var OrderPlacer = class {
|
|
|
15327
15503
|
const account = accounts.privateKeyToAccount(privateKey);
|
|
15328
15504
|
const sessionKeyAddress = account.address;
|
|
15329
15505
|
const createdAt = Date.now();
|
|
15330
|
-
order
|
|
15506
|
+
const placementOrder = { ...order, session: sessionKeyAddress };
|
|
15331
15507
|
await this.ctx.sessionKeyStorage.setSessionKeyByAddress(sessionKeyAddress, {
|
|
15332
15508
|
privateKey,
|
|
15333
15509
|
address: sessionKeyAddress,
|
|
@@ -15336,7 +15512,7 @@ var OrderPlacer = class {
|
|
|
15336
15512
|
const data = viem.encodeFunctionData({
|
|
15337
15513
|
abi: ABI3,
|
|
15338
15514
|
functionName: "placeOrder",
|
|
15339
|
-
args: [transformOrderForContract(
|
|
15515
|
+
args: [transformOrderForContract(placementOrder), graffiti]
|
|
15340
15516
|
});
|
|
15341
15517
|
const intentGatewayAddress = this.ctx.source.configService.getIntentGatewayAddress(
|
|
15342
15518
|
normalizeStateMachineId(order.source)
|
|
@@ -15356,20 +15532,15 @@ var OrderPlacer = class {
|
|
|
15356
15532
|
if (!orderPlacedEvent) {
|
|
15357
15533
|
throw new Error("OrderPlaced event not found in transaction receipt");
|
|
15358
15534
|
}
|
|
15359
|
-
|
|
15360
|
-
order.inputs = orderPlacedEvent.args.inputs.map((input) => ({
|
|
15361
|
-
token: input.token,
|
|
15362
|
-
amount: input.amount
|
|
15363
|
-
}));
|
|
15364
|
-
order.id = orderCommitment(order);
|
|
15535
|
+
const finalizedOrder = deriveCanonicalPlacedOrder(placementOrder, orderPlacedEvent.args);
|
|
15365
15536
|
const sessionKeyData = {
|
|
15366
15537
|
privateKey,
|
|
15367
15538
|
address: sessionKeyAddress,
|
|
15368
|
-
commitment:
|
|
15539
|
+
commitment: finalizedOrder.id,
|
|
15369
15540
|
createdAt
|
|
15370
15541
|
};
|
|
15371
15542
|
await this.ctx.sessionKeyStorage.setSessionKeyByAddress(sessionKeyAddress, sessionKeyData);
|
|
15372
|
-
return { order, receipt };
|
|
15543
|
+
return { order: finalizedOrder, receipt };
|
|
15373
15544
|
}
|
|
15374
15545
|
};
|
|
15375
15546
|
|
|
@@ -15699,7 +15870,7 @@ var OrderExecutor = class {
|
|
|
15699
15870
|
}
|
|
15700
15871
|
}
|
|
15701
15872
|
};
|
|
15702
|
-
var OrderCanceller = class {
|
|
15873
|
+
var OrderCanceller = class _OrderCanceller {
|
|
15703
15874
|
/**
|
|
15704
15875
|
* @param ctx - Shared IntentsV2 context providing the source and destination
|
|
15705
15876
|
* chain clients, config service, and cancellation storage.
|
|
@@ -15708,6 +15879,9 @@ var OrderCanceller = class {
|
|
|
15708
15879
|
this.ctx = ctx;
|
|
15709
15880
|
}
|
|
15710
15881
|
ctx;
|
|
15882
|
+
static DEFAULT_MAX_RECOVERY_RESTARTS = 1;
|
|
15883
|
+
static PROOF_FRESHNESS_MAX_RETRIES = 3;
|
|
15884
|
+
static PROOF_FRESHNESS_BACKOFF_MS = 500;
|
|
15711
15885
|
logger = consola.createConsola({
|
|
15712
15886
|
level: consola.LogLevels.info,
|
|
15713
15887
|
formatOptions: { columns: 80, colors: true, compact: true, date: false }
|
|
@@ -15739,11 +15913,14 @@ var OrderCanceller = class {
|
|
|
15739
15913
|
* @returns The native token dispatch fee in wei.
|
|
15740
15914
|
*/
|
|
15741
15915
|
async quoteCancelFromSource(order) {
|
|
15742
|
-
if (order.source === order.destination) return { nativeValue: 0n, relayerFee: 0n };
|
|
15743
15916
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
15917
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15918
|
+
if (sourceStateMachine === destStateMachine) {
|
|
15919
|
+
return { nativeValue: 0n, relayerFee: 0n };
|
|
15920
|
+
}
|
|
15744
15921
|
const height = order.deadline + 1n;
|
|
15745
15922
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
15746
|
-
|
|
15923
|
+
destStateMachine
|
|
15747
15924
|
);
|
|
15748
15925
|
const slotHash = await this.ctx.dest.client.readContract({
|
|
15749
15926
|
abi: ABI3,
|
|
@@ -15755,8 +15932,8 @@ var OrderCanceller = class {
|
|
|
15755
15932
|
const context = encodeWithdrawalRequest(order, order.user);
|
|
15756
15933
|
const getRequest = {
|
|
15757
15934
|
source: sourceStateMachine,
|
|
15758
|
-
dest:
|
|
15759
|
-
from: this.ctx.source.configService.getIntentGatewayAddress(
|
|
15935
|
+
dest: destStateMachine,
|
|
15936
|
+
from: this.ctx.source.configService.getIntentGatewayAddress(destStateMachine),
|
|
15760
15937
|
nonce: await this.ctx.source.getHostNonce(),
|
|
15761
15938
|
height,
|
|
15762
15939
|
keys: [key],
|
|
@@ -15773,7 +15950,9 @@ var OrderCanceller = class {
|
|
|
15773
15950
|
* cancellation is complete.
|
|
15774
15951
|
*
|
|
15775
15952
|
* Delegates to `cancelOrderFromSource` or `cancelOrderFromDest` based on
|
|
15776
|
-
* the `from` parameter.
|
|
15953
|
+
* the `from` parameter. If Hyperbridge has pruned consensus data needed for
|
|
15954
|
+
* source-side GET recovery, clears its stale checkpoint and restarts the
|
|
15955
|
+
* source-side stream internally.
|
|
15777
15956
|
*
|
|
15778
15957
|
* @param order - The order to cancel.
|
|
15779
15958
|
* @param indexerClient - Indexer client used to stream ISMP request status
|
|
@@ -15783,12 +15962,32 @@ var OrderCanceller = class {
|
|
|
15783
15962
|
* cancellation lifecycle.
|
|
15784
15963
|
*/
|
|
15785
15964
|
async *cancelOrder(order, indexerClient, options = {}) {
|
|
15786
|
-
const
|
|
15965
|
+
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
15966
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15967
|
+
const isSameChain = sourceStateMachine === destStateMachine;
|
|
15787
15968
|
if (options.from === "destination" && !isSameChain) {
|
|
15788
15969
|
yield* this.cancelOrderFromDest(order, indexerClient);
|
|
15789
15970
|
return;
|
|
15790
15971
|
}
|
|
15791
|
-
|
|
15972
|
+
let recoveryRestarts = 0;
|
|
15973
|
+
while (true) {
|
|
15974
|
+
try {
|
|
15975
|
+
yield* this.cancelOrderFromSource(order, indexerClient);
|
|
15976
|
+
return;
|
|
15977
|
+
} catch (error) {
|
|
15978
|
+
if (!MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
15979
|
+
if (recoveryRestarts >= _OrderCanceller.DEFAULT_MAX_RECOVERY_RESTARTS) {
|
|
15980
|
+
throw new Error(
|
|
15981
|
+
`Cancellation recovery stopped after ${recoveryRestarts} restart(s): Hyperbridge no longer retains a required consensus update.`
|
|
15982
|
+
);
|
|
15983
|
+
}
|
|
15984
|
+
recoveryRestarts += 1;
|
|
15985
|
+
this.logger.warn(
|
|
15986
|
+
`Restarting cancellation recovery (${recoveryRestarts}/${_OrderCanceller.DEFAULT_MAX_RECOVERY_RESTARTS}) after a required consensus update was pruned`
|
|
15987
|
+
);
|
|
15988
|
+
await this.clearGetRecoveryCache(order);
|
|
15989
|
+
}
|
|
15990
|
+
}
|
|
15792
15991
|
}
|
|
15793
15992
|
/**
|
|
15794
15993
|
* Async generator that cancels an order by initiating the cancel from the
|
|
@@ -15814,11 +16013,10 @@ var OrderCanceller = class {
|
|
|
15814
16013
|
* @throws If the cancel transaction does not contain the expected on-chain event.
|
|
15815
16014
|
*/
|
|
15816
16015
|
async *cancelOrderFromSource(order, indexerClient) {
|
|
15817
|
-
const
|
|
15818
|
-
const
|
|
15819
|
-
const
|
|
15820
|
-
|
|
15821
|
-
);
|
|
16016
|
+
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
16017
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
16018
|
+
const isSameChain = sourceStateMachine === destStateMachine;
|
|
16019
|
+
const intentGatewayAddress = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine);
|
|
15822
16020
|
if (isSameChain) {
|
|
15823
16021
|
const data = viem.encodeFunctionData({
|
|
15824
16022
|
abi: ABI3,
|
|
@@ -15847,18 +16045,37 @@ var OrderCanceller = class {
|
|
|
15847
16045
|
};
|
|
15848
16046
|
return;
|
|
15849
16047
|
}
|
|
16048
|
+
const storageKeys = this.recoveryStorageKeys(order);
|
|
16049
|
+
const legacyStorageKeys = this.legacyRecoveryStorageKeys(order);
|
|
15850
16050
|
const hyperbridge = indexerClient.hyperbridge;
|
|
15851
|
-
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
15852
16051
|
const sourceConsensusStateId = this.ctx.source.configService.getConsensusStateId(sourceStateMachine);
|
|
15853
|
-
let destIProof = await this.
|
|
16052
|
+
let destIProof = await this.getRecoveryItem(
|
|
16053
|
+
storageKeys.destProof,
|
|
16054
|
+
legacyStorageKeys.map((keys) => keys.destProof)
|
|
16055
|
+
);
|
|
15854
16056
|
if (!destIProof) {
|
|
15855
16057
|
destIProof = yield* this.fetchDestinationProof(order, indexerClient);
|
|
15856
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16058
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.destProof, destIProof);
|
|
15857
16059
|
} else {
|
|
15858
|
-
|
|
16060
|
+
let refreshed = false;
|
|
16061
|
+
try {
|
|
16062
|
+
await this.assertProofFresh(hyperbridge, destIProof);
|
|
16063
|
+
} catch (error) {
|
|
16064
|
+
if (!MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
16065
|
+
await this.removeRecoveryItems(
|
|
16066
|
+
storageKeys.destProof,
|
|
16067
|
+
...legacyStorageKeys.map((keys) => keys.destProof)
|
|
16068
|
+
);
|
|
16069
|
+
destIProof = yield* this.fetchDestinationProof(order, indexerClient);
|
|
16070
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.destProof, destIProof);
|
|
16071
|
+
refreshed = true;
|
|
16072
|
+
}
|
|
16073
|
+
if (!refreshed) yield { status: "DESTINATION_FINALIZED", proof: destIProof };
|
|
15859
16074
|
}
|
|
15860
|
-
|
|
15861
|
-
|
|
16075
|
+
await this.assertProofFresh(hyperbridge, destIProof);
|
|
16076
|
+
let getRequest = await this.getRecoveryItem(
|
|
16077
|
+
storageKeys.getRequest,
|
|
16078
|
+
legacyStorageKeys.map((keys) => keys.getRequest)
|
|
15862
16079
|
);
|
|
15863
16080
|
if (!getRequest) {
|
|
15864
16081
|
const quote = await this.quoteCancelFromSource(order);
|
|
@@ -15878,7 +16095,7 @@ var OrderCanceller = class {
|
|
|
15878
16095
|
const request = events.find((e) => e.eventName === "GetRequestEvent");
|
|
15879
16096
|
if (!request) throw new Error("GetRequest missing");
|
|
15880
16097
|
getRequest = request.args;
|
|
15881
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16098
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.getRequest, getRequest);
|
|
15882
16099
|
yield {
|
|
15883
16100
|
status: "CANCEL_STARTED",
|
|
15884
16101
|
receipt
|
|
@@ -15897,8 +16114,9 @@ var OrderCanceller = class {
|
|
|
15897
16114
|
metadata: statusUpdate.metadata
|
|
15898
16115
|
};
|
|
15899
16116
|
const sourceHeight = BigInt(statusUpdate.metadata.blockNumber);
|
|
15900
|
-
let sourceIProof = await this.
|
|
15901
|
-
|
|
16117
|
+
let sourceIProof = await this.getRecoveryItem(
|
|
16118
|
+
storageKeys.sourceProof,
|
|
16119
|
+
legacyStorageKeys.map((keys) => keys.sourceProof)
|
|
15902
16120
|
);
|
|
15903
16121
|
if (!sourceIProof) {
|
|
15904
16122
|
sourceIProof = await fetchSourceProof(
|
|
@@ -15908,8 +16126,9 @@ var OrderCanceller = class {
|
|
|
15908
16126
|
sourceConsensusStateId,
|
|
15909
16127
|
sourceHeight
|
|
15910
16128
|
);
|
|
15911
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16129
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.sourceProof, sourceIProof);
|
|
15912
16130
|
}
|
|
16131
|
+
await this.assertProofFresh(hyperbridge, sourceIProof);
|
|
15913
16132
|
await waitForChallengePeriod(hyperbridge, {
|
|
15914
16133
|
height: sourceIProof.height,
|
|
15915
16134
|
id: {
|
|
@@ -15917,6 +16136,10 @@ var OrderCanceller = class {
|
|
|
15917
16136
|
consensusStateId: sourceConsensusStateId
|
|
15918
16137
|
}
|
|
15919
16138
|
});
|
|
16139
|
+
await Promise.all([
|
|
16140
|
+
this.assertProofFresh(hyperbridge, sourceIProof),
|
|
16141
|
+
this.assertProofFresh(hyperbridge, destIProof)
|
|
16142
|
+
]);
|
|
15920
16143
|
const getRequestMessage = {
|
|
15921
16144
|
kind: "GetRequest",
|
|
15922
16145
|
requests: [getRequest],
|
|
@@ -15938,9 +16161,12 @@ var OrderCanceller = class {
|
|
|
15938
16161
|
status: "HYPERBRIDGE_FINALIZED",
|
|
15939
16162
|
metadata: statusUpdate.metadata
|
|
15940
16163
|
};
|
|
15941
|
-
await this.
|
|
15942
|
-
|
|
15943
|
-
|
|
16164
|
+
await this.removeRecoveryItems(
|
|
16165
|
+
storageKeys.destProof,
|
|
16166
|
+
storageKeys.getRequest,
|
|
16167
|
+
storageKeys.sourceProof,
|
|
16168
|
+
...legacyStorageKeys.flatMap((keys) => [keys.destProof, keys.getRequest, keys.sourceProof])
|
|
16169
|
+
);
|
|
15944
16170
|
return;
|
|
15945
16171
|
}
|
|
15946
16172
|
}
|
|
@@ -15957,9 +16183,11 @@ var OrderCanceller = class {
|
|
|
15957
16183
|
* @returns The native token dispatch fee in wei.
|
|
15958
16184
|
*/
|
|
15959
16185
|
async quoteCancelFromDest(order) {
|
|
15960
|
-
if (order.source === order.destination) return { nativeValue: 0n, relayerFee: 0n };
|
|
15961
|
-
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
15962
16186
|
const sourceStateMachine = normalizeStateMachineId(order.source);
|
|
16187
|
+
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
16188
|
+
if (sourceStateMachine === destStateMachine) {
|
|
16189
|
+
return { nativeValue: 0n, relayerFee: 0n };
|
|
16190
|
+
}
|
|
15963
16191
|
const destIntentGateway = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
15964
16192
|
const sourceIntentGateway = this.ctx.source.configService.getIntentGatewayAddress(sourceStateMachine);
|
|
15965
16193
|
const relayerFee = await this.estimateRelayerFee(sourceStateMachine, destStateMachine);
|
|
@@ -15997,11 +16225,13 @@ var OrderCanceller = class {
|
|
|
15997
16225
|
* @throws If the cancel transaction does not contain a `PostRequestEvent`.
|
|
15998
16226
|
*/
|
|
15999
16227
|
async *cancelOrderFromDest(order, indexerClient) {
|
|
16000
|
-
const
|
|
16228
|
+
const storageKeys = this.recoveryStorageKeys(order);
|
|
16001
16229
|
const destStateMachine = normalizeStateMachineId(order.destination);
|
|
16002
16230
|
const intentGatewayAddress = this.ctx.dest.configService.getIntentGatewayAddress(destStateMachine);
|
|
16003
|
-
|
|
16004
|
-
|
|
16231
|
+
const legacyStorageKeys = this.legacyRecoveryStorageKeys(order);
|
|
16232
|
+
let commitment = await this.getRecoveryItem(
|
|
16233
|
+
storageKeys.postCommitment,
|
|
16234
|
+
legacyStorageKeys.map((keys) => keys.postCommitment)
|
|
16005
16235
|
);
|
|
16006
16236
|
if (!commitment) {
|
|
16007
16237
|
const quote = await this.quoteCancelFromDest(order);
|
|
@@ -16026,7 +16256,7 @@ var OrderCanceller = class {
|
|
|
16026
16256
|
if (!postEvent) throw new Error("PostRequestEvent not found in cancel transaction receipt");
|
|
16027
16257
|
const postArgs = postEvent.args;
|
|
16028
16258
|
commitment = postRequestCommitment(postArgs).commitment;
|
|
16029
|
-
await this.ctx.cancellationStorage.setItem(
|
|
16259
|
+
await this.ctx.cancellationStorage.setItem(storageKeys.postCommitment, commitment);
|
|
16030
16260
|
}
|
|
16031
16261
|
const statusStream = indexerClient.postRequestStatusStream(commitment);
|
|
16032
16262
|
for await (const statusUpdate of statusStream) {
|
|
@@ -16060,7 +16290,10 @@ var OrderCanceller = class {
|
|
|
16060
16290
|
if (refundEvents.length === 0) {
|
|
16061
16291
|
throw new Error("EscrowRefunded event not found in source-chain delivery receipt");
|
|
16062
16292
|
}
|
|
16063
|
-
await this.
|
|
16293
|
+
await this.removeRecoveryItems(
|
|
16294
|
+
storageKeys.postCommitment,
|
|
16295
|
+
...legacyStorageKeys.map((keys) => keys.postCommitment)
|
|
16296
|
+
);
|
|
16064
16297
|
yield {
|
|
16065
16298
|
status: "CANCELLATION_COMPLETE",
|
|
16066
16299
|
blockNumber: statusUpdate.metadata.blockNumber,
|
|
@@ -16103,7 +16336,7 @@ var OrderCanceller = class {
|
|
|
16103
16336
|
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayAddress(
|
|
16104
16337
|
this.ctx.dest.config.stateMachineId
|
|
16105
16338
|
);
|
|
16106
|
-
const orderId = order
|
|
16339
|
+
const orderId = this.orderId(order);
|
|
16107
16340
|
const slotHash = await this.ctx.dest.client.readContract({
|
|
16108
16341
|
abi: ABI3,
|
|
16109
16342
|
address: intentGatewayV2Address,
|
|
@@ -16120,6 +16353,7 @@ var OrderCanceller = class {
|
|
|
16120
16353
|
yield { status: "DESTINATION_FINALIZED", proof };
|
|
16121
16354
|
return proof;
|
|
16122
16355
|
} catch (e) {
|
|
16356
|
+
if (MissingConsensusUpdateTimeError.isError(e)) throw e;
|
|
16123
16357
|
lastFailedHeight = latestHeight;
|
|
16124
16358
|
await sleep(1e4);
|
|
16125
16359
|
}
|
|
@@ -16150,6 +16384,7 @@ var OrderCanceller = class {
|
|
|
16150
16384
|
this.logger.info(`Unsigned GET ${commitment} submitted; waiting for Hyperbridge response receipt`);
|
|
16151
16385
|
await sleep(3e4);
|
|
16152
16386
|
} catch (error) {
|
|
16387
|
+
if (MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
16153
16388
|
this.logger.warn(
|
|
16154
16389
|
`Unsigned GET submit failed for ${commitment}; polling response receipt before failing: ${String(error)}`
|
|
16155
16390
|
);
|
|
@@ -16158,14 +16393,128 @@ var OrderCanceller = class {
|
|
|
16158
16393
|
await this.pollDeliveredReceipt(hyperbridge, commitment);
|
|
16159
16394
|
this.logger.info(`Confirmed Hyperbridge GET delivery for ${commitment}`);
|
|
16160
16395
|
} catch (error) {
|
|
16396
|
+
if (MissingConsensusUpdateTimeError.isError(error)) throw error;
|
|
16161
16397
|
const message2 = `Failed to deliver GET request to Hyperbridge; no response receipt found for ${commitment}: ${String(error)}`;
|
|
16162
16398
|
this.logger.error(message2);
|
|
16163
16399
|
throw new Error(message2);
|
|
16164
16400
|
}
|
|
16165
16401
|
}
|
|
16402
|
+
/** Verify that Hyperbridge still retains the consensus update for a proof. */
|
|
16403
|
+
async assertProofFresh(hyperbridge, proof) {
|
|
16404
|
+
await retryPromise(
|
|
16405
|
+
() => hyperbridge.stateMachineUpdateTime({
|
|
16406
|
+
height: proof.height,
|
|
16407
|
+
id: {
|
|
16408
|
+
stateId: parseStateMachineId(proof.stateMachine).stateId,
|
|
16409
|
+
consensusStateId: proof.consensusStateId
|
|
16410
|
+
}
|
|
16411
|
+
}),
|
|
16412
|
+
{
|
|
16413
|
+
maxRetries: _OrderCanceller.PROOF_FRESHNESS_MAX_RETRIES,
|
|
16414
|
+
backoffMs: _OrderCanceller.PROOF_FRESHNESS_BACKOFF_MS,
|
|
16415
|
+
logger: this.logger,
|
|
16416
|
+
logMessage: `Checking consensus update time for proof at height ${proof.height}`,
|
|
16417
|
+
shouldRetry: (error) => !MissingConsensusUpdateTimeError.isError(error)
|
|
16418
|
+
}
|
|
16419
|
+
);
|
|
16420
|
+
}
|
|
16421
|
+
/**
|
|
16422
|
+
* Drops the source-initiated GET recovery checkpoint after Hyperbridge prunes
|
|
16423
|
+
* a consensus update required by that recovery attempt.
|
|
16424
|
+
*/
|
|
16425
|
+
async clearGetRecoveryCache(order) {
|
|
16426
|
+
const keys = this.recoveryStorageKeys(order);
|
|
16427
|
+
const legacyStorageKeys = this.legacyRecoveryStorageKeys(order);
|
|
16428
|
+
await this.removeRecoveryItems(
|
|
16429
|
+
keys.destProof,
|
|
16430
|
+
keys.sourceProof,
|
|
16431
|
+
keys.getRequest,
|
|
16432
|
+
...legacyStorageKeys.flatMap((legacyKeys) => [
|
|
16433
|
+
legacyKeys.destProof,
|
|
16434
|
+
legacyKeys.sourceProof,
|
|
16435
|
+
legacyKeys.getRequest
|
|
16436
|
+
])
|
|
16437
|
+
);
|
|
16438
|
+
}
|
|
16439
|
+
/**
|
|
16440
|
+
* Returns the pair-scoped storage keys used to resume cancellation recovery
|
|
16441
|
+
* for an order.
|
|
16442
|
+
*
|
|
16443
|
+
* @param order - The order whose source/destination recovery state is stored.
|
|
16444
|
+
*/
|
|
16445
|
+
recoveryStorageKeys(order) {
|
|
16446
|
+
const orderId = this.orderId(order);
|
|
16447
|
+
return {
|
|
16448
|
+
destProof: STORAGE_KEYS.destProof(orderId, order.source, order.destination),
|
|
16449
|
+
getRequest: STORAGE_KEYS.getRequest(orderId, order.source, order.destination),
|
|
16450
|
+
sourceProof: STORAGE_KEYS.sourceProof(orderId, order.source, order.destination),
|
|
16451
|
+
postCommitment: STORAGE_KEYS.postCommitment(orderId, order.source, order.destination)
|
|
16452
|
+
};
|
|
16453
|
+
}
|
|
16454
|
+
/** Older SDK key shapes, checked once and migrated to the normalized pair-scoped key. */
|
|
16455
|
+
legacyRecoveryStorageKeys(order) {
|
|
16456
|
+
const orderId = this.orderId(order);
|
|
16457
|
+
return [
|
|
16458
|
+
{
|
|
16459
|
+
destProof: LEGACY_STORAGE_KEYS.destProof(orderId, order.source, order.destination),
|
|
16460
|
+
getRequest: LEGACY_STORAGE_KEYS.getRequest(orderId, order.source, order.destination),
|
|
16461
|
+
sourceProof: LEGACY_STORAGE_KEYS.sourceProof(orderId, order.source, order.destination),
|
|
16462
|
+
postCommitment: LEGACY_STORAGE_KEYS.postCommitment(orderId, order.source, order.destination)
|
|
16463
|
+
},
|
|
16464
|
+
{
|
|
16465
|
+
destProof: LEGACY_STORAGE_KEYS.destProof(orderId),
|
|
16466
|
+
getRequest: LEGACY_STORAGE_KEYS.getRequest(orderId),
|
|
16467
|
+
sourceProof: LEGACY_STORAGE_KEYS.sourceProof(orderId),
|
|
16468
|
+
postCommitment: LEGACY_STORAGE_KEYS.postCommitment(orderId)
|
|
16469
|
+
}
|
|
16470
|
+
];
|
|
16471
|
+
}
|
|
16472
|
+
async getRecoveryItem(currentKey, legacyKeys) {
|
|
16473
|
+
const current = await this.ctx.cancellationStorage.getItem(currentKey);
|
|
16474
|
+
if (current) return current;
|
|
16475
|
+
for (const legacyKey of new Set(legacyKeys)) {
|
|
16476
|
+
if (legacyKey === currentKey) continue;
|
|
16477
|
+
const legacy = await this.ctx.cancellationStorage.getItem(legacyKey);
|
|
16478
|
+
if (!legacy) continue;
|
|
16479
|
+
await this.ctx.cancellationStorage.setItem(currentKey, legacy);
|
|
16480
|
+
await this.ctx.cancellationStorage.removeItem(legacyKey);
|
|
16481
|
+
return legacy;
|
|
16482
|
+
}
|
|
16483
|
+
return null;
|
|
16484
|
+
}
|
|
16485
|
+
async removeRecoveryItems(...keys) {
|
|
16486
|
+
await Promise.all(
|
|
16487
|
+
[...new Set(keys)].map((key) => this.ctx.cancellationStorage.removeItem(key))
|
|
16488
|
+
);
|
|
16489
|
+
}
|
|
16490
|
+
/**
|
|
16491
|
+
* Returns the order identifier required to persist or clear recovery state.
|
|
16492
|
+
*
|
|
16493
|
+
* @param order - The order being cancelled.
|
|
16494
|
+
* @throws If the order has no identifier.
|
|
16495
|
+
*/
|
|
16496
|
+
orderId(order) {
|
|
16497
|
+
if (!order.id) throw new Error("An order id is required to recover cancellation");
|
|
16498
|
+
return order.id;
|
|
16499
|
+
}
|
|
16500
|
+
/**
|
|
16501
|
+
* Reads the Hyperbridge response receipt for a GET request commitment.
|
|
16502
|
+
*
|
|
16503
|
+
* @param hyperbridge - Hyperbridge chain client used to query the receipt.
|
|
16504
|
+
* @param commitment - Commitment of the GET request.
|
|
16505
|
+
* @returns The receipt commitment when delivered, otherwise `undefined`.
|
|
16506
|
+
*/
|
|
16166
16507
|
async queryDeliveredReceipt(hyperbridge, commitment) {
|
|
16167
16508
|
return hyperbridge.queryResponseReceipt(commitment);
|
|
16168
16509
|
}
|
|
16510
|
+
/**
|
|
16511
|
+
* Polls Hyperbridge until it records a response receipt for the GET request.
|
|
16512
|
+
*
|
|
16513
|
+
* @param hyperbridge - Hyperbridge chain client used to query the receipt.
|
|
16514
|
+
* @param commitment - Commitment of the GET request.
|
|
16515
|
+
* @returns The delivered response receipt commitment.
|
|
16516
|
+
* @throws If no receipt is observed within the configured retry limit.
|
|
16517
|
+
*/
|
|
16169
16518
|
async pollDeliveredReceipt(hyperbridge, commitment) {
|
|
16170
16519
|
this.logger.info(`Polling Hyperbridge GET response receipt for ${commitment}`);
|
|
16171
16520
|
return retryPromise(
|
|
@@ -17378,6 +17727,178 @@ var OrderStatusChecker = class {
|
|
|
17378
17727
|
return true;
|
|
17379
17728
|
}
|
|
17380
17729
|
};
|
|
17730
|
+
var COMMITMENT_PATTERN = /^0x[0-9a-f]{64}$/i;
|
|
17731
|
+
var LiquidityEngine = class {
|
|
17732
|
+
/**
|
|
17733
|
+
* @param queryClient - Nexus GraphQL client attached to the gateway.
|
|
17734
|
+
* @param chainConfigService - Resolves token decimals for formatted results.
|
|
17735
|
+
*/
|
|
17736
|
+
constructor(queryClient, chainConfigService) {
|
|
17737
|
+
this.queryClient = queryClient;
|
|
17738
|
+
this.chainConfigService = chainConfigService;
|
|
17739
|
+
}
|
|
17740
|
+
queryClient;
|
|
17741
|
+
chainConfigService;
|
|
17742
|
+
/**
|
|
17743
|
+
* Retrieves the newest directional Phantom snapshot for a pair and its
|
|
17744
|
+
* indexed output-token liquidity.
|
|
17745
|
+
*
|
|
17746
|
+
* Nexus filters balances to the canonical output token, then aggregates them
|
|
17747
|
+
* overall and by chain. The returned amounts are decimal strings: the total
|
|
17748
|
+
* uses the canonical Base output-token decimals, while each chain group uses
|
|
17749
|
+
* that chain's token decimals. They describe `snapshotTime`, not live
|
|
17750
|
+
* reservations or fill guarantees.
|
|
17751
|
+
*
|
|
17752
|
+
* @param params - Canonical Phantom-market input and output token addresses.
|
|
17753
|
+
* @returns The latest snapshot, or `undefined` if Nexus has no snapshot for
|
|
17754
|
+
* the directional pair.
|
|
17755
|
+
* @throws {InvalidAvailableLiquiditySnapshotError} If Nexus returns malformed
|
|
17756
|
+
* or internally inconsistent snapshot data.
|
|
17757
|
+
*/
|
|
17758
|
+
async getAvailableLiquiditySnapshot(params) {
|
|
17759
|
+
const tokenIn = normalizeEvmAddress(params.tokenIn, "tokenIn");
|
|
17760
|
+
const tokenOut = normalizeEvmAddress(params.tokenOut, "tokenOut");
|
|
17761
|
+
const response = await this.queryClient.request(
|
|
17762
|
+
LATEST_PHANTOM_ORDER_LIQUIDITY_SNAPSHOT,
|
|
17763
|
+
{ tokenA: tokenIn, tokenB: tokenOut }
|
|
17764
|
+
);
|
|
17765
|
+
const node = response?.phantomOrderPriceSnapshots?.nodes?.[0];
|
|
17766
|
+
if (!node) return;
|
|
17767
|
+
const commitment = node.commitment.toLowerCase();
|
|
17768
|
+
if (!COMMITMENT_PATTERN.test(commitment)) {
|
|
17769
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment || "<missing>", "commitment is not bytes32 hex");
|
|
17770
|
+
}
|
|
17771
|
+
if (node.tokenA.toLowerCase() !== tokenIn || node.tokenB.toLowerCase() !== tokenOut) {
|
|
17772
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, "snapshot token pair does not match the query");
|
|
17773
|
+
}
|
|
17774
|
+
const snapshotTime = new Date(dateStringtoTimestamp(node.snapshotTime));
|
|
17775
|
+
if (Number.isNaN(snapshotTime.getTime())) {
|
|
17776
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, "snapshotTime is invalid");
|
|
17777
|
+
}
|
|
17778
|
+
const { totalLiquidity, providerCount, liquidityByChain } = await this.querySnapshotLiquidityAggregates({
|
|
17779
|
+
commitment,
|
|
17780
|
+
tokenAddress: tokenOut
|
|
17781
|
+
});
|
|
17782
|
+
return {
|
|
17783
|
+
totalLiquidity: this.formatLiquidity(totalLiquidity, "EVM-8453" /* BASE_MAINNET */, tokenOut, commitment),
|
|
17784
|
+
providerCount,
|
|
17785
|
+
tokenAddress: tokenOut,
|
|
17786
|
+
snapshotTime,
|
|
17787
|
+
liquidityByChain: liquidityByChain.map((group) => ({
|
|
17788
|
+
...group,
|
|
17789
|
+
totalLiquidity: this.formatLiquidity(group.totalLiquidity, group.chain, group.tokenAddress, commitment)
|
|
17790
|
+
}))
|
|
17791
|
+
};
|
|
17792
|
+
}
|
|
17793
|
+
/**
|
|
17794
|
+
* Requests server-side sums and distinct provider counts for one immutable
|
|
17795
|
+
* snapshot/output-token pair, including chain-level aggregate groups.
|
|
17796
|
+
*
|
|
17797
|
+
* `commitment` uniquely identifies the selected snapshot
|
|
17798
|
+
*/
|
|
17799
|
+
async querySnapshotLiquidityAggregates(params) {
|
|
17800
|
+
const response = await this.queryClient.request(
|
|
17801
|
+
LIQUIDITY_PROVIDER_BALANCES,
|
|
17802
|
+
{ commitment: params.commitment, tokenAddress: params.tokenAddress }
|
|
17803
|
+
);
|
|
17804
|
+
const connection = response?.liquidityProviderBalances;
|
|
17805
|
+
const aggregates = connection?.aggregates;
|
|
17806
|
+
if (!connection || !aggregates) {
|
|
17807
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17808
|
+
params.commitment,
|
|
17809
|
+
"liquidityProviderBalances aggregates are missing"
|
|
17810
|
+
);
|
|
17811
|
+
}
|
|
17812
|
+
const totalLiquidity = parseSnapshotBigInt(aggregates.sum.balance ?? "0", params.commitment, "total balance");
|
|
17813
|
+
const providerCount = parseProviderCount(aggregates.distinctCount.providerId, params.commitment, "total");
|
|
17814
|
+
const liquidityByChain = connection.groupedAggregates.map((group, index) => {
|
|
17815
|
+
const [chain, tokenAddress] = group.keys;
|
|
17816
|
+
if (!chain?.trim() || !tokenAddress) {
|
|
17817
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17818
|
+
params.commitment,
|
|
17819
|
+
`liquidity group ${index} has invalid keys`
|
|
17820
|
+
);
|
|
17821
|
+
}
|
|
17822
|
+
const normalizedTokenAddress = normalizeIndexedLiquidityAddress(
|
|
17823
|
+
tokenAddress,
|
|
17824
|
+
params.commitment,
|
|
17825
|
+
`liquidity group ${index} tokenAddress`
|
|
17826
|
+
);
|
|
17827
|
+
if (normalizedTokenAddress !== params.tokenAddress) {
|
|
17828
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17829
|
+
params.commitment,
|
|
17830
|
+
`liquidity group ${index} tokenAddress does not match the snapshot output token`
|
|
17831
|
+
);
|
|
17832
|
+
}
|
|
17833
|
+
return {
|
|
17834
|
+
chain: chain.trim(),
|
|
17835
|
+
tokenAddress: normalizedTokenAddress,
|
|
17836
|
+
totalLiquidity: parseSnapshotBigInt(
|
|
17837
|
+
group.sum.balance ?? "0",
|
|
17838
|
+
params.commitment,
|
|
17839
|
+
`liquidity group ${index} balance`
|
|
17840
|
+
),
|
|
17841
|
+
providerCount: parseProviderCount(
|
|
17842
|
+
group.distinctCount.providerId,
|
|
17843
|
+
params.commitment,
|
|
17844
|
+
`liquidity group ${index}`
|
|
17845
|
+
)
|
|
17846
|
+
};
|
|
17847
|
+
});
|
|
17848
|
+
const groupedTotal = liquidityByChain.reduce((sum, group) => sum + group.totalLiquidity, 0n);
|
|
17849
|
+
if (groupedTotal !== totalLiquidity) {
|
|
17850
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17851
|
+
params.commitment,
|
|
17852
|
+
"grouped liquidity does not match the total liquidity"
|
|
17853
|
+
);
|
|
17854
|
+
}
|
|
17855
|
+
return { totalLiquidity, providerCount, liquidityByChain };
|
|
17856
|
+
}
|
|
17857
|
+
/** Formats a raw amount using the configured decimals for its chain/token. */
|
|
17858
|
+
formatLiquidity(amount, chain, tokenAddress, commitment) {
|
|
17859
|
+
const decimals = this.chainConfigService.getAssetMetadataByAddress(chain, tokenAddress)?.decimals;
|
|
17860
|
+
if (decimals === void 0) {
|
|
17861
|
+
throw new InvalidAvailableLiquiditySnapshotError(
|
|
17862
|
+
commitment,
|
|
17863
|
+
`token decimals are not configured for ${tokenAddress} on ${chain}`
|
|
17864
|
+
);
|
|
17865
|
+
}
|
|
17866
|
+
return viem.formatUnits(amount, decimals);
|
|
17867
|
+
}
|
|
17868
|
+
};
|
|
17869
|
+
var InvalidAvailableLiquiditySnapshotError = class extends Error {
|
|
17870
|
+
/** Creates an error that identifies the invalid snapshot and field/reason. */
|
|
17871
|
+
constructor(commitment, reason) {
|
|
17872
|
+
super(`Invalid available-liquidity snapshot ${commitment}: ${reason}`);
|
|
17873
|
+
this.name = "InvalidAvailableLiquiditySnapshotError";
|
|
17874
|
+
}
|
|
17875
|
+
};
|
|
17876
|
+
function parseSnapshotBigInt(value, commitment, field) {
|
|
17877
|
+
try {
|
|
17878
|
+
const amount = BigInt(value);
|
|
17879
|
+
if (amount < 0n) {
|
|
17880
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} cannot be negative`);
|
|
17881
|
+
}
|
|
17882
|
+
return amount;
|
|
17883
|
+
} catch (error) {
|
|
17884
|
+
if (error instanceof InvalidAvailableLiquiditySnapshotError) throw error;
|
|
17885
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} is not an integer`);
|
|
17886
|
+
}
|
|
17887
|
+
}
|
|
17888
|
+
function parseProviderCount(value, commitment, field) {
|
|
17889
|
+
const count = Number(value);
|
|
17890
|
+
if (!Number.isSafeInteger(count) || count < 0) {
|
|
17891
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} provider count is invalid`);
|
|
17892
|
+
}
|
|
17893
|
+
return count;
|
|
17894
|
+
}
|
|
17895
|
+
function normalizeIndexedLiquidityAddress(address, commitment, field) {
|
|
17896
|
+
try {
|
|
17897
|
+
return normalizeEvmAddress(address, field);
|
|
17898
|
+
} catch {
|
|
17899
|
+
throw new InvalidAvailableLiquiditySnapshotError(commitment, `${field} is not a valid EVM address`);
|
|
17900
|
+
}
|
|
17901
|
+
}
|
|
17381
17902
|
|
|
17382
17903
|
// src/protocols/intents/quote/types.ts
|
|
17383
17904
|
var UnsupportedIntentQuoteStrategyError = class extends Error {
|
|
@@ -17664,12 +18185,14 @@ var PhantomSnapshotIntentQuoteStrategy = class {
|
|
|
17664
18185
|
constructor(chainConfigService, getQueryClient) {
|
|
17665
18186
|
this.chainConfigService = chainConfigService;
|
|
17666
18187
|
this.getQueryClient = getQueryClient;
|
|
18188
|
+
this.pairResolver = new PhantomSnapshotPairResolver(chainConfigService);
|
|
17667
18189
|
}
|
|
17668
18190
|
chainConfigService;
|
|
17669
18191
|
getQueryClient;
|
|
18192
|
+
pairResolver;
|
|
17670
18193
|
async quote(params, source, destination) {
|
|
17671
18194
|
validateQuoteParams(params);
|
|
17672
|
-
const pair = this.
|
|
18195
|
+
const pair = this.pairResolver.resolve(params, source.stateMachineId, destination.stateMachineId);
|
|
17673
18196
|
if (!pair) {
|
|
17674
18197
|
throw new UnsupportedIntentQuotePairError({
|
|
17675
18198
|
source: source.stateMachineId,
|
|
@@ -17742,7 +18265,13 @@ var PhantomSnapshotIntentQuoteStrategy = class {
|
|
|
17742
18265
|
throw new InvalidPhantomSnapshotError(snapshot.commitment, "snapshotTime is invalid");
|
|
17743
18266
|
}
|
|
17744
18267
|
}
|
|
17745
|
-
|
|
18268
|
+
};
|
|
18269
|
+
var PhantomSnapshotPairResolver = class {
|
|
18270
|
+
constructor(chainConfigService) {
|
|
18271
|
+
this.chainConfigService = chainConfigService;
|
|
18272
|
+
}
|
|
18273
|
+
chainConfigService;
|
|
18274
|
+
resolve(params, sourceStateMachineId, destinationStateMachineId) {
|
|
17746
18275
|
const tokenIn = this.resolveBaseSnapshotToken(sourceStateMachineId, params.tokenIn);
|
|
17747
18276
|
const tokenOut = this.resolveBaseSnapshotToken(destinationStateMachineId, params.tokenOut);
|
|
17748
18277
|
if (!tokenIn || !tokenOut || !isSupportedSnapshotPair(tokenIn.symbol, tokenOut.symbol)) return;
|
|
@@ -17794,6 +18323,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
17794
18323
|
gasEstimator;
|
|
17795
18324
|
/** Quote strategies for pricing orders before placement, keyed by strategy name. */
|
|
17796
18325
|
quoteStrategies;
|
|
18326
|
+
/** Resolves order tokens to canonical Phantom snapshot market pairs. */
|
|
18327
|
+
phantomSnapshotPairResolver;
|
|
17797
18328
|
/**
|
|
17798
18329
|
* Private constructor — use {@link IntentGateway.create} instead.
|
|
17799
18330
|
*
|
|
@@ -17837,6 +18368,7 @@ var IntentGateway = class _IntentGateway {
|
|
|
17837
18368
|
this.bidManager = bidManager;
|
|
17838
18369
|
this.gasEstimator = gasEstimator;
|
|
17839
18370
|
this._crypto = crypto;
|
|
18371
|
+
this.phantomSnapshotPairResolver = new PhantomSnapshotPairResolver(dest.configService);
|
|
17840
18372
|
this.quoteStrategies = {
|
|
17841
18373
|
phantom_snapshot: new PhantomSnapshotIntentQuoteStrategy(
|
|
17842
18374
|
dest.configService,
|
|
@@ -17915,13 +18447,43 @@ var IntentGateway = class _IntentGateway {
|
|
|
17915
18447
|
if (!handler) throw new UnsupportedIntentQuoteStrategyError(strategy);
|
|
17916
18448
|
return handler.quote({ ...params, strategy }, source, destination);
|
|
17917
18449
|
}
|
|
18450
|
+
/**
|
|
18451
|
+
* Returns the output-token liquidity measured in the latest directional
|
|
18452
|
+
* Phantom snapshot for this gateway's source and destination.
|
|
18453
|
+
*
|
|
18454
|
+
* Pair resolution uses the same canonical Base market as {@link quoteIntent}.
|
|
18455
|
+
* The snapshot itself determines the output token and chain to aggregate. The
|
|
18456
|
+
* amount is in the token's smallest unit and reflects the indexer's
|
|
18457
|
+
* `snapshotTime`; it is not a live reservation or fill guarantee.
|
|
18458
|
+
*
|
|
18459
|
+
* Requires a prior call to {@link withQueryClient}.
|
|
18460
|
+
*/
|
|
18461
|
+
async queryAvailableLiquidity(params) {
|
|
18462
|
+
const { queryClient } = this.requireIndexer();
|
|
18463
|
+
const sourceStateMachineId = this.source.config.stateMachineId;
|
|
18464
|
+
const destinationStateMachineId = this.dest.config.stateMachineId;
|
|
18465
|
+
const pair = this.phantomSnapshotPairResolver.resolve(params, sourceStateMachineId, destinationStateMachineId);
|
|
18466
|
+
if (!pair) {
|
|
18467
|
+
throw new UnsupportedIntentQuotePairError({
|
|
18468
|
+
source: sourceStateMachineId,
|
|
18469
|
+
destination: destinationStateMachineId,
|
|
18470
|
+
tokenIn: params.tokenIn,
|
|
18471
|
+
tokenOut: params.tokenOut,
|
|
18472
|
+
quoteSource: "Phantom snapshot pair"
|
|
18473
|
+
});
|
|
18474
|
+
}
|
|
18475
|
+
return new LiquidityEngine(queryClient, this.dest.configService).getAvailableLiquiditySnapshot({
|
|
18476
|
+
tokenIn: pair.tokenA,
|
|
18477
|
+
tokenOut: pair.tokenB
|
|
18478
|
+
});
|
|
18479
|
+
}
|
|
17918
18480
|
/**
|
|
17919
18481
|
* Bidirectional async generator that orchestrates the full order lifecycle:
|
|
17920
18482
|
* placement, fee estimation, bid collection, and execution.
|
|
17921
18483
|
*
|
|
17922
18484
|
* **Yield/receive protocol:**
|
|
17923
|
-
* 1. If `order.fees` is unset or zero, estimates gas and sets
|
|
17924
|
-
*
|
|
18485
|
+
* 1. If `order.fees` is unset or zero, estimates gas on an internal copy and sets
|
|
18486
|
+
* same-chain fees to twice the estimate. Cross-chain orders retain a 1% buffer
|
|
17925
18487
|
* and include an additional 600k-gas fee uplift, while the wei cost used for
|
|
17926
18488
|
* the `value` field receives a 2% buffer.
|
|
17927
18489
|
* 2. Yields `AWAITING_PLACE_ORDER` with `{ to, data, value, sessionPrivateKey }`.
|
|
@@ -17931,8 +18493,8 @@ var IntentGateway = class _IntentGateway {
|
|
|
17931
18493
|
* 4. Delegates to {@link OrderExecutor.executeOrder} and forwards all
|
|
17932
18494
|
* subsequent status updates until the order is filled, exhausted, or fails.
|
|
17933
18495
|
*
|
|
17934
|
-
* @param order - The order to place and execute. `order.fees`
|
|
17935
|
-
*
|
|
18496
|
+
* @param order - The order to place and execute. It is not mutated. `order.fees`
|
|
18497
|
+
* may be 0; fees are estimated automatically if so.
|
|
17936
18498
|
* @param graffiti - Optional bytes32 tag for orderflow attribution /
|
|
17937
18499
|
* revenue share. Defaults to {@link DEFAULT_GRAFFITI}.
|
|
17938
18500
|
* @param options - Optional tuning parameters:
|
|
@@ -17945,10 +18507,11 @@ var IntentGateway = class _IntentGateway {
|
|
|
17945
18507
|
* estimation returns zero.
|
|
17946
18508
|
*/
|
|
17947
18509
|
async *execute(order, graffiti = DEFAULT_GRAFFITI, options) {
|
|
18510
|
+
const executionOrder = { ...order };
|
|
17948
18511
|
let value;
|
|
17949
|
-
if (!
|
|
18512
|
+
if (!executionOrder.fees || executionOrder.fees === 0n) {
|
|
17950
18513
|
const estimate = await this.gasEstimator.estimateFillOrder({
|
|
17951
|
-
order,
|
|
18514
|
+
order: executionOrder,
|
|
17952
18515
|
maxPriorityFeePerGasBumpPercent: options?.maxPriorityFeePerGasBumpPercent,
|
|
17953
18516
|
maxFeePerGasBumpPercent: options?.maxFeePerGasBumpPercent
|
|
17954
18517
|
});
|
|
@@ -17963,9 +18526,9 @@ var IntentGateway = class _IntentGateway {
|
|
|
17963
18526
|
"source",
|
|
17964
18527
|
this.source.config.stateMachineId
|
|
17965
18528
|
);
|
|
17966
|
-
|
|
18529
|
+
executionOrder.fees = isSameChain ? estimate.totalGasInFeeToken * 2n : estimate.totalGasInFeeToken + (crossChainFeeBump + estimate.totalGasInFeeToken * 1n / 100n);
|
|
17967
18530
|
}
|
|
17968
|
-
const placeOrderGen = this.orderPlacer.placeOrder(
|
|
18531
|
+
const placeOrderGen = this.orderPlacer.placeOrder(executionOrder, graffiti);
|
|
17969
18532
|
const placeOrderFirst = await placeOrderGen.next();
|
|
17970
18533
|
if (placeOrderFirst.done) {
|
|
17971
18534
|
throw new Error("placeOrder generator completed without yielding");
|
|
@@ -18076,13 +18639,20 @@ var IntentGateway = class _IntentGateway {
|
|
|
18076
18639
|
const gen = this.execute(order, graffiti, options);
|
|
18077
18640
|
try {
|
|
18078
18641
|
let input;
|
|
18642
|
+
let finalizedOrder;
|
|
18079
18643
|
while (true) {
|
|
18080
18644
|
const { value, done } = await gen.next(input);
|
|
18081
18645
|
input = void 0;
|
|
18082
18646
|
if (done) break;
|
|
18083
|
-
if (value.status === "
|
|
18647
|
+
if (value.status === "ORDER_PLACED") {
|
|
18648
|
+
finalizedOrder = value.order;
|
|
18084
18649
|
yield value;
|
|
18085
|
-
|
|
18650
|
+
} else if (value.status === "BIDS_RECEIVED") {
|
|
18651
|
+
if (!finalizedOrder) {
|
|
18652
|
+
throw new Error("Received bids before the order was finalized");
|
|
18653
|
+
}
|
|
18654
|
+
yield value;
|
|
18655
|
+
input = await this.autoSelect(finalizedOrder, value.bids);
|
|
18086
18656
|
} else if (value.status === "AWAITING_PLACE_ORDER") {
|
|
18087
18657
|
input = yield value;
|
|
18088
18658
|
} else {
|
|
@@ -22959,6 +23529,7 @@ exports.hyperbridgeAddress = hyperbridgeAddress;
|
|
|
22959
23529
|
exports.maxBigInt = maxBigInt;
|
|
22960
23530
|
exports.normalizeAddressForEvmBytes32 = normalizeAddressForEvmBytes32;
|
|
22961
23531
|
exports.normalizeAddressForStateMachine = normalizeAddressForStateMachine;
|
|
23532
|
+
exports.normalizeEvmAddress = normalizeEvmAddress;
|
|
22962
23533
|
exports.normalizeEvmChainId = normalizeEvmChainId;
|
|
22963
23534
|
exports.normalizeStateMachineId = normalizeStateMachineId;
|
|
22964
23535
|
exports.orderCommitment = orderCommitment;
|