@hyperbridge/sdk 1.3.4 → 1.3.6
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 +49 -14
- package/dist/browser/index.js +309 -87
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.d.ts +49 -14
- package/dist/node/index.js +309 -87
- package/dist/node/index.js.map +1 -1
- package/package.json +3 -2
package/dist/node/index.js
CHANGED
|
@@ -3,7 +3,7 @@ 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
5
|
import { flatten, zip, capitalize, maxBy, isNil } from 'lodash-es';
|
|
6
|
-
import { toHex, hexToBytes, encodePacked, keccak256, encodeAbiParameters, bytesToHex, concatHex, createPublicClient, http, encodeFunctionData, erc20Abi, bytesToBigInt, pad, toBytes, maxUint256, parseUnits } from 'viem';
|
|
6
|
+
import { toHex, hexToBytes, encodePacked, keccak256, encodeAbiParameters, bytesToHex, concatHex, createPublicClient, http, encodeFunctionData, erc20Abi, bytesToBigInt, pad, toBytes, maxUint256, formatUnits, parseUnits } from 'viem';
|
|
7
7
|
import mergeRace from '@async-generator/merge-race';
|
|
8
8
|
import { gnosisChiado, gnosis, bscTestnet, bsc, soneium, baseSepolia, base, optimismSepolia, optimism, arbitrumSepolia, arbitrum, mainnet, sepolia } from 'viem/chains';
|
|
9
9
|
import { hasWindow, isNode, env } from 'std-env';
|
|
@@ -13,6 +13,7 @@ import { WsProvider, ApiPromise } from '@polkadot/api';
|
|
|
13
13
|
import { RpcWebSocketClient } from 'rpc-websocket-client';
|
|
14
14
|
import { keccakAsU8a, decodeAddress, xxhashAsU8a } from '@polkadot/util-crypto';
|
|
15
15
|
import { GraphQLClient } from 'graphql-request';
|
|
16
|
+
import { Decimal } from 'decimal.js';
|
|
16
17
|
import { u8aToHex } from '@polkadot/util';
|
|
17
18
|
|
|
18
19
|
var __defProp = Object.defineProperty;
|
|
@@ -3410,18 +3411,18 @@ var addresses = {
|
|
|
3410
3411
|
["EVM-10200" /* GNOSIS_CHIADO */]: "0x0000000000000000000000000000000000000000",
|
|
3411
3412
|
["EVM-11155111" /* SEPOLIA */]: "0x0000000000000000000000000000000000000000",
|
|
3412
3413
|
["EVM-1" /* MAINNET */]: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
|
|
3413
|
-
["EVM-56" /* BSC_MAINNET */]: "
|
|
3414
|
-
["EVM-42161" /* ARBITRUM_MAINNET */]: "
|
|
3415
|
-
["EVM-8453" /* BASE_MAINNET */]: "
|
|
3414
|
+
["EVM-56" /* BSC_MAINNET */]: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
|
|
3415
|
+
["EVM-42161" /* ARBITRUM_MAINNET */]: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
|
|
3416
|
+
["EVM-8453" /* BASE_MAINNET */]: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24"
|
|
3416
3417
|
},
|
|
3417
3418
|
UniswapV2Factory: {
|
|
3418
3419
|
["EVM-97" /* BSC_CHAPEL */]: "0x12e036669DA18F4A2777853d6e2136b32AceEC86",
|
|
3419
3420
|
["EVM-10200" /* GNOSIS_CHIADO */]: "0x0000000000000000000000000000000000000000",
|
|
3420
3421
|
["EVM-11155111" /* SEPOLIA */]: "0x0000000000000000000000000000000000000000",
|
|
3421
3422
|
["EVM-1" /* MAINNET */]: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
|
|
3422
|
-
["EVM-56" /* BSC_MAINNET */]: "
|
|
3423
|
-
["EVM-42161" /* ARBITRUM_MAINNET */]: "
|
|
3424
|
-
["EVM-8453" /* BASE_MAINNET */]: "
|
|
3423
|
+
["EVM-56" /* BSC_MAINNET */]: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73",
|
|
3424
|
+
["EVM-42161" /* ARBITRUM_MAINNET */]: "0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9",
|
|
3425
|
+
["EVM-8453" /* BASE_MAINNET */]: "0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6"
|
|
3425
3426
|
},
|
|
3426
3427
|
BatchExecutor: {
|
|
3427
3428
|
["EVM-97" /* BSC_CHAPEL */]: "0x4CC58B5D8FBf838d062E4b21F75C327835B5F0ef",
|
|
@@ -3933,6 +3934,10 @@ var GetRequest = Struct({
|
|
|
3933
3934
|
* Substrate Keys
|
|
3934
3935
|
*/
|
|
3935
3936
|
keys: Vector(Vector(u8)),
|
|
3937
|
+
/*
|
|
3938
|
+
* The height of the state machine
|
|
3939
|
+
*/
|
|
3940
|
+
height: u64,
|
|
3936
3941
|
/*
|
|
3937
3942
|
* Some application-specific metadata relating to this request
|
|
3938
3943
|
*/
|
|
@@ -4059,6 +4064,24 @@ var TimeoutMessage = Enum({
|
|
|
4059
4064
|
requests: Vector(Request)
|
|
4060
4065
|
})
|
|
4061
4066
|
});
|
|
4067
|
+
var GetRequestsWithProof = Struct({
|
|
4068
|
+
/*
|
|
4069
|
+
* Requests to be fetched
|
|
4070
|
+
*/
|
|
4071
|
+
requests: Vector(GetRequest),
|
|
4072
|
+
/*
|
|
4073
|
+
* Membership batch proof for these requests
|
|
4074
|
+
*/
|
|
4075
|
+
source: Proof,
|
|
4076
|
+
/*
|
|
4077
|
+
* Storage proof for these responses
|
|
4078
|
+
*/
|
|
4079
|
+
response: Proof,
|
|
4080
|
+
/*
|
|
4081
|
+
* Signer information. Ideally should be their account identifier
|
|
4082
|
+
*/
|
|
4083
|
+
signer: Vector(u8)
|
|
4084
|
+
});
|
|
4062
4085
|
var Message = Enum({
|
|
4063
4086
|
/*
|
|
4064
4087
|
* A consensus update message
|
|
@@ -4807,6 +4830,8 @@ var EvmChain = class {
|
|
|
4807
4830
|
]
|
|
4808
4831
|
});
|
|
4809
4832
|
return encoded2;
|
|
4833
|
+
}).with({ kind: "GetRequest" }, (message2) => {
|
|
4834
|
+
throw new Error("GetResponse is not yet supported on Substrate chains");
|
|
4810
4835
|
}).exhaustive();
|
|
4811
4836
|
return encoded;
|
|
4812
4837
|
}
|
|
@@ -5122,8 +5147,13 @@ var SubstrateChain = class {
|
|
|
5122
5147
|
async submitUnsigned(message) {
|
|
5123
5148
|
if (!this.api) throw new Error("API not initialized");
|
|
5124
5149
|
const { api } = this;
|
|
5125
|
-
const args =
|
|
5126
|
-
|
|
5150
|
+
const args = encodeISMPMessage(message);
|
|
5151
|
+
let tx;
|
|
5152
|
+
if (message.kind === "GetRequest") {
|
|
5153
|
+
tx = api.tx.stateCoprocessor.handleUnsigned(args);
|
|
5154
|
+
} else {
|
|
5155
|
+
tx = api.tx.ismp.handleUnsigned(args);
|
|
5156
|
+
}
|
|
5127
5157
|
return new Promise((resolve, reject) => {
|
|
5128
5158
|
let unsub = () => {
|
|
5129
5159
|
};
|
|
@@ -5266,6 +5296,18 @@ function convertIPostRequestToCodec(request) {
|
|
|
5266
5296
|
}
|
|
5267
5297
|
};
|
|
5268
5298
|
}
|
|
5299
|
+
function convertIGetRequestToCodec(request) {
|
|
5300
|
+
return {
|
|
5301
|
+
source: convertStateMachineIdToEnum(request.source),
|
|
5302
|
+
dest: convertStateMachineIdToEnum(request.dest),
|
|
5303
|
+
from: Array.from(hexToBytes(request.from)),
|
|
5304
|
+
nonce: request.nonce,
|
|
5305
|
+
keys: request.keys.map((key) => Array.from(hexToBytes(key))),
|
|
5306
|
+
context: Array.from(hexToBytes(request.context)),
|
|
5307
|
+
timeoutTimestamp: request.timeoutTimestamp,
|
|
5308
|
+
height: request.height
|
|
5309
|
+
};
|
|
5310
|
+
}
|
|
5269
5311
|
function encodeISMPMessage(message) {
|
|
5270
5312
|
try {
|
|
5271
5313
|
return match(message).with({ kind: "PostRequest" }, (message2) => {
|
|
@@ -5292,6 +5334,31 @@ function encodeISMPMessage(message) {
|
|
|
5292
5334
|
]);
|
|
5293
5335
|
}).with({ kind: "GetResponse" }, (message2) => {
|
|
5294
5336
|
throw new Error("GetResponse is not yet supported on Substrate chains");
|
|
5337
|
+
}).with({ kind: "GetRequest" }, (message2) => {
|
|
5338
|
+
return GetRequestsWithProof.enc({
|
|
5339
|
+
requests: message2.requests.map((request) => convertIGetRequestToCodec(request)),
|
|
5340
|
+
source: {
|
|
5341
|
+
height: {
|
|
5342
|
+
height: message2.source.height,
|
|
5343
|
+
id: {
|
|
5344
|
+
consensusStateId: Array.from(toBytes(message2.source.consensusStateId)),
|
|
5345
|
+
id: convertStateMachineIdToEnum(message2.source.stateMachine)
|
|
5346
|
+
}
|
|
5347
|
+
},
|
|
5348
|
+
proof: Array.from(hexToBytes(message2.source.proof))
|
|
5349
|
+
},
|
|
5350
|
+
response: {
|
|
5351
|
+
height: {
|
|
5352
|
+
height: message2.response.height,
|
|
5353
|
+
id: {
|
|
5354
|
+
consensusStateId: Array.from(toBytes(message2.response.consensusStateId)),
|
|
5355
|
+
id: convertStateMachineIdToEnum(message2.response.stateMachine)
|
|
5356
|
+
}
|
|
5357
|
+
},
|
|
5358
|
+
proof: Array.from(hexToBytes(message2.response.proof))
|
|
5359
|
+
},
|
|
5360
|
+
signer: Array.from(hexToBytes(message2.signer))
|
|
5361
|
+
});
|
|
5295
5362
|
}).with({ kind: "TimeoutPostRequest" }, (message2) => {
|
|
5296
5363
|
return Vector(Message).enc([
|
|
5297
5364
|
{
|
|
@@ -5692,6 +5759,7 @@ async function _queryGetRequestInternal(params) {
|
|
|
5692
5759
|
const { statusMetadata, ...rest } = response.getRequests.nodes[0];
|
|
5693
5760
|
return {
|
|
5694
5761
|
...rest,
|
|
5762
|
+
commitment: commitmentHash,
|
|
5695
5763
|
timeoutTimestamp: BigInt(rest.timeoutTimestamp),
|
|
5696
5764
|
nonce: BigInt(rest.nonce),
|
|
5697
5765
|
height: BigInt(rest.height),
|
|
@@ -6109,6 +6177,120 @@ var IndexerClient = class {
|
|
|
6109
6177
|
);
|
|
6110
6178
|
return request;
|
|
6111
6179
|
}
|
|
6180
|
+
/**
|
|
6181
|
+
* Queries a GET request and returns it alongside its statuses,
|
|
6182
|
+
* including any finalization events.
|
|
6183
|
+
* @param hash - Can be commitment, hyperbridge tx hash, source tx hash, destination tx hash, or timeout tx hash
|
|
6184
|
+
* @returns Full GET request data with all inferred status events, including SOURCE_FINALIZED and HYPERBRIDGE_FINALIZED
|
|
6185
|
+
* @remarks Unlike queryGetRequest(), this method adds derived finalization status events by querying state machine updates
|
|
6186
|
+
*/
|
|
6187
|
+
async queryGetRequestWithStatus(hash) {
|
|
6188
|
+
let request = await this.queryGetRequest(hash);
|
|
6189
|
+
if (!request) return;
|
|
6190
|
+
request = await this.addGetRequestFinalityEvents(request);
|
|
6191
|
+
request.statuses = request.statuses.sort(
|
|
6192
|
+
(a, b) => COMBINED_STATUS_WEIGHTS[a.status] - COMBINED_STATUS_WEIGHTS[b.status]
|
|
6193
|
+
);
|
|
6194
|
+
return request;
|
|
6195
|
+
}
|
|
6196
|
+
/**
|
|
6197
|
+
* Enhances a GET request with finality events by querying state machine updates.
|
|
6198
|
+
*
|
|
6199
|
+
* This method augments a GET request object with additional inferred status events
|
|
6200
|
+
* that represent chain finality confirmations. It adds:
|
|
6201
|
+
* - SOURCE_FINALIZED: When the source chain has finalized the request
|
|
6202
|
+
* - HYPERBRIDGE_FINALIZED: When Hyperbridge has finalized the delivery confirmation and response is ready
|
|
6203
|
+
*
|
|
6204
|
+
* The method also generates appropriate calldata for submitting cross-chain proofs
|
|
6205
|
+
* when applicable.
|
|
6206
|
+
*
|
|
6207
|
+
* @param request - The GET request to enhance with finality events
|
|
6208
|
+
* @returns The request with finality events added
|
|
6209
|
+
* @private
|
|
6210
|
+
*/
|
|
6211
|
+
async addGetRequestFinalityEvents(request) {
|
|
6212
|
+
const events = [];
|
|
6213
|
+
const addFinalityEvents = (request2) => {
|
|
6214
|
+
this.logger.trace(`Added ${events.length} \`GetRequest\` finality events`, events);
|
|
6215
|
+
request2.statuses = [...request2.statuses, ...events];
|
|
6216
|
+
return request2;
|
|
6217
|
+
};
|
|
6218
|
+
let hyperbridgeDelivered;
|
|
6219
|
+
if (request.source === this.config.hyperbridge.stateMachineId) {
|
|
6220
|
+
hyperbridgeDelivered = request.statuses[0];
|
|
6221
|
+
return addFinalityEvents(request);
|
|
6222
|
+
} else {
|
|
6223
|
+
const sourceFinality = await this.queryStateMachineUpdateByHeight({
|
|
6224
|
+
statemachineId: request.source,
|
|
6225
|
+
height: request.statuses[0].metadata.blockNumber,
|
|
6226
|
+
chain: this.config.hyperbridge.stateMachineId
|
|
6227
|
+
});
|
|
6228
|
+
if (!sourceFinality) return addFinalityEvents(request);
|
|
6229
|
+
events.push({
|
|
6230
|
+
status: RequestStatus.SOURCE_FINALIZED,
|
|
6231
|
+
metadata: {
|
|
6232
|
+
blockHash: sourceFinality.blockHash,
|
|
6233
|
+
blockNumber: sourceFinality.height,
|
|
6234
|
+
transactionHash: sourceFinality.transactionHash,
|
|
6235
|
+
timestamp: sourceFinality.timestamp
|
|
6236
|
+
}
|
|
6237
|
+
});
|
|
6238
|
+
hyperbridgeDelivered = request.statuses.find((item) => item.status === RequestStatus.HYPERBRIDGE_DELIVERED);
|
|
6239
|
+
if (!hyperbridgeDelivered) return addFinalityEvents(request);
|
|
6240
|
+
}
|
|
6241
|
+
const hyperbridgeFinality = await this.queryStateMachineUpdateByHeight({
|
|
6242
|
+
statemachineId: this.config.hyperbridge.stateMachineId,
|
|
6243
|
+
height: hyperbridgeDelivered.metadata.blockNumber,
|
|
6244
|
+
chain: request.source
|
|
6245
|
+
});
|
|
6246
|
+
if (!hyperbridgeFinality) return addFinalityEvents(request);
|
|
6247
|
+
const sourceChain = await getChain(this.config.source);
|
|
6248
|
+
const hyperbridge = await getChain({
|
|
6249
|
+
...this.config.hyperbridge,
|
|
6250
|
+
hasher: "Keccak"
|
|
6251
|
+
});
|
|
6252
|
+
try {
|
|
6253
|
+
const response = await this.queryResponseByRequestId(request.commitment);
|
|
6254
|
+
if (!response) return addFinalityEvents(request);
|
|
6255
|
+
const proof = await hyperbridge.queryProof(
|
|
6256
|
+
{ Responses: [response.commitment] },
|
|
6257
|
+
request.source,
|
|
6258
|
+
BigInt(hyperbridgeFinality.height)
|
|
6259
|
+
);
|
|
6260
|
+
const calldata = sourceChain.encode({
|
|
6261
|
+
kind: "GetResponse",
|
|
6262
|
+
proof: {
|
|
6263
|
+
stateMachine: this.config.hyperbridge.stateMachineId,
|
|
6264
|
+
consensusStateId: this.config.hyperbridge.consensusStateId,
|
|
6265
|
+
proof,
|
|
6266
|
+
height: BigInt(hyperbridgeFinality.height)
|
|
6267
|
+
},
|
|
6268
|
+
responses: [
|
|
6269
|
+
{
|
|
6270
|
+
get: request,
|
|
6271
|
+
values: request.keys.map((key, index) => ({
|
|
6272
|
+
key,
|
|
6273
|
+
value: response.values[index] || "0x"
|
|
6274
|
+
}))
|
|
6275
|
+
}
|
|
6276
|
+
],
|
|
6277
|
+
signer: pad("0x")
|
|
6278
|
+
});
|
|
6279
|
+
events.push({
|
|
6280
|
+
status: RequestStatus.HYPERBRIDGE_FINALIZED,
|
|
6281
|
+
metadata: {
|
|
6282
|
+
blockHash: hyperbridgeFinality.blockHash,
|
|
6283
|
+
blockNumber: hyperbridgeFinality.height,
|
|
6284
|
+
transactionHash: hyperbridgeFinality.transactionHash,
|
|
6285
|
+
timestamp: hyperbridgeFinality.timestamp,
|
|
6286
|
+
calldata
|
|
6287
|
+
}
|
|
6288
|
+
});
|
|
6289
|
+
} catch (error) {
|
|
6290
|
+
this.logger.trace("Could not generate HYPERBRIDGE_FINALIZED event for GET request:", error);
|
|
6291
|
+
}
|
|
6292
|
+
return addFinalityEvents(request);
|
|
6293
|
+
}
|
|
6112
6294
|
/**
|
|
6113
6295
|
* Create a Stream of status updates for a post request.
|
|
6114
6296
|
* Stream ends when either the request reaches the destination or times out.
|
|
@@ -11373,8 +11555,6 @@ var UNISWAP_V4_QUOTER_ABI = [
|
|
|
11373
11555
|
inputs: [{ name: "revertData", type: "bytes", internalType: "bytes" }]
|
|
11374
11556
|
}
|
|
11375
11557
|
];
|
|
11376
|
-
|
|
11377
|
-
// src/protocols/intents.ts
|
|
11378
11558
|
var IntentGateway = class {
|
|
11379
11559
|
/**
|
|
11380
11560
|
* Creates a new IntentGateway instance for cross-chain operations.
|
|
@@ -11402,14 +11582,10 @@ var IntentGateway = class {
|
|
|
11402
11582
|
from: this.source.config.getIntentGatewayAddress(order.destChain),
|
|
11403
11583
|
to: this.source.config.getIntentGatewayAddress(order.sourceChain)
|
|
11404
11584
|
};
|
|
11405
|
-
const { decimals: sourceChainFeeTokenDecimals
|
|
11585
|
+
const { decimals: sourceChainFeeTokenDecimals } = await this.source.getFeeTokenWithDecimals();
|
|
11406
11586
|
const { address: destChainFeeTokenAddress, decimals: destChainFeeTokenDecimals } = await this.dest.getFeeTokenWithDecimals();
|
|
11407
11587
|
const { gas: postGasEstimate, postRequestCalldata } = await this.source.estimateGas(postRequest);
|
|
11408
|
-
const postGasEstimateInSourceFeeToken = await this.convertGasToFeeToken(
|
|
11409
|
-
postGasEstimate,
|
|
11410
|
-
this.source.client,
|
|
11411
|
-
sourceChainFeeTokenDecimals
|
|
11412
|
-
);
|
|
11588
|
+
const postGasEstimateInSourceFeeToken = await this.convertGasToFeeToken(postGasEstimate, "source");
|
|
11413
11589
|
const relayerFeeInSourceFeeToken = postGasEstimateInSourceFeeToken + 25n * 10n ** BigInt(sourceChainFeeTokenDecimals - 2);
|
|
11414
11590
|
const relayerFeeInDestFeeToken = adjustFeeDecimals(
|
|
11415
11591
|
relayerFeeInSourceFeeToken,
|
|
@@ -11464,6 +11640,7 @@ var IntentGateway = class {
|
|
|
11464
11640
|
}))
|
|
11465
11641
|
];
|
|
11466
11642
|
let destChainFillGas = 0n;
|
|
11643
|
+
let filledWithNativeToken = false;
|
|
11467
11644
|
try {
|
|
11468
11645
|
let protocolFeeInNativeToken = await this.quoteNative(postRequest, relayerFeeInDestFeeToken);
|
|
11469
11646
|
protocolFeeInNativeToken = protocolFeeInNativeToken + protocolFeeInNativeToken * 50n / 10000n;
|
|
@@ -11476,6 +11653,7 @@ var IntentGateway = class {
|
|
|
11476
11653
|
value: totalEthValue + protocolFeeInNativeToken,
|
|
11477
11654
|
stateOverride: stateOverrides
|
|
11478
11655
|
});
|
|
11656
|
+
filledWithNativeToken = true;
|
|
11479
11657
|
} catch {
|
|
11480
11658
|
console.warn(
|
|
11481
11659
|
`Could not estimate gas for fill order with native token as fees for chain ${order.destChain}, now trying with fee token as fees`
|
|
@@ -11510,28 +11688,25 @@ var IntentGateway = class {
|
|
|
11510
11688
|
stateOverride: stateOverrides
|
|
11511
11689
|
});
|
|
11512
11690
|
}
|
|
11513
|
-
const
|
|
11514
|
-
|
|
11515
|
-
|
|
11691
|
+
const fillGasInDestFeeToken = await this.convertGasToFeeToken(destChainFillGas, "dest");
|
|
11692
|
+
const fillGasInSourceFeeToken = adjustFeeDecimals(
|
|
11693
|
+
fillGasInDestFeeToken,
|
|
11694
|
+
destChainFeeTokenDecimals,
|
|
11516
11695
|
sourceChainFeeTokenDecimals
|
|
11517
11696
|
);
|
|
11518
11697
|
const protocolFeeInSourceFeeToken = adjustFeeDecimals(
|
|
11519
|
-
|
|
11520
|
-
await this.dest.quote(postRequest) + relayerFeeInDestFeeToken,
|
|
11698
|
+
await this.dest.quote(postRequest),
|
|
11521
11699
|
destChainFeeTokenDecimals,
|
|
11522
11700
|
sourceChainFeeTokenDecimals
|
|
11523
11701
|
);
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
this.source.client,
|
|
11531
|
-
sourceChainFeeTokenDecimals
|
|
11532
|
-
);
|
|
11702
|
+
let totalEstimateInSourceFeeToken = fillGasInSourceFeeToken + protocolFeeInSourceFeeToken + relayerFeeInSourceFeeToken;
|
|
11703
|
+
if (!filledWithNativeToken) {
|
|
11704
|
+
totalEstimateInSourceFeeToken = totalEstimateInSourceFeeToken + totalEstimateInSourceFeeToken * 200n / 10000n;
|
|
11705
|
+
}
|
|
11706
|
+
let totalNativeTokenAmount = await this.convertFeeTokenToNative(totalEstimateInSourceFeeToken, "source");
|
|
11707
|
+
totalNativeTokenAmount = totalNativeTokenAmount + totalNativeTokenAmount * 200n / 10000n;
|
|
11533
11708
|
return {
|
|
11534
|
-
feeTokenAmount:
|
|
11709
|
+
feeTokenAmount: totalEstimateInSourceFeeToken,
|
|
11535
11710
|
nativeTokenAmount: totalNativeTokenAmount,
|
|
11536
11711
|
postRequestCalldata
|
|
11537
11712
|
};
|
|
@@ -11541,47 +11716,82 @@ var IntentGateway = class {
|
|
|
11541
11716
|
* Uses USD pricing to convert between fee token amounts and native token costs.
|
|
11542
11717
|
*
|
|
11543
11718
|
* @param feeTokenAmount - The amount in fee token (DAI)
|
|
11544
|
-
* @param
|
|
11545
|
-
* @param feeTokenDecimals - The decimal places of the fee token
|
|
11719
|
+
* @param getQuoteIn - Whether to use "source" or "dest" chain for the conversion
|
|
11546
11720
|
* @returns The fee token amount converted to native token amount
|
|
11547
11721
|
* @private
|
|
11548
11722
|
*/
|
|
11549
|
-
async convertFeeTokenToNative(feeTokenAmount,
|
|
11550
|
-
const
|
|
11551
|
-
const
|
|
11552
|
-
|
|
11553
|
-
|
|
11723
|
+
async convertFeeTokenToNative(feeTokenAmount, getQuoteIn) {
|
|
11724
|
+
const client = this[getQuoteIn].client;
|
|
11725
|
+
const evmChainID = `EVM-${client.chain?.id}`;
|
|
11726
|
+
const wethAsset = this[getQuoteIn].config.getWrappedNativeAssetWithDecimals(evmChainID).asset;
|
|
11727
|
+
const feeToken = await this[getQuoteIn].getFeeTokenWithDecimals();
|
|
11728
|
+
try {
|
|
11729
|
+
const { amountOut } = await this.findBestProtocolWithAmountIn(
|
|
11730
|
+
getQuoteIn,
|
|
11731
|
+
feeToken.address,
|
|
11732
|
+
wethAsset,
|
|
11733
|
+
feeTokenAmount,
|
|
11734
|
+
"v2"
|
|
11735
|
+
);
|
|
11736
|
+
if (amountOut === 0n) {
|
|
11737
|
+
throw new Error();
|
|
11738
|
+
}
|
|
11739
|
+
return amountOut;
|
|
11740
|
+
} catch {
|
|
11741
|
+
const nativeCurrency = client.chain?.nativeCurrency;
|
|
11742
|
+
const chainId = client.chain?.id;
|
|
11743
|
+
const feeTokenAmountDecimal = new Decimal(formatUnits(feeTokenAmount, feeToken.decimals));
|
|
11744
|
+
const nativeTokenPriceUsd = new Decimal(await fetchPrice(nativeCurrency?.symbol, chainId));
|
|
11745
|
+
const totalCostInNativeToken = feeTokenAmountDecimal.dividedBy(nativeTokenPriceUsd);
|
|
11746
|
+
return parseUnits(totalCostInNativeToken.toFixed(nativeCurrency?.decimals), nativeCurrency?.decimals);
|
|
11554
11747
|
}
|
|
11555
|
-
const feeTokenAmountNumber = Number(feeTokenAmount) / Math.pow(10, feeTokenDecimals);
|
|
11556
|
-
const nativeTokenPriceUsd = await fetchPrice(nativeToken.symbol, chainId);
|
|
11557
|
-
const totalCostInNativeToken = feeTokenAmountNumber / nativeTokenPriceUsd;
|
|
11558
|
-
return BigInt(Math.floor(totalCostInNativeToken * Math.pow(10, nativeToken.decimals)));
|
|
11559
11748
|
}
|
|
11560
11749
|
/**
|
|
11561
11750
|
* Converts gas costs to the equivalent amount in the fee token (DAI).
|
|
11562
11751
|
* Uses USD pricing to convert between native token gas costs and fee token amounts.
|
|
11563
11752
|
*
|
|
11564
11753
|
* @param gasEstimate - The estimated gas units
|
|
11565
|
-
* @param
|
|
11566
|
-
* @param targetDecimals - The decimal places of the target fee token
|
|
11754
|
+
* @param gasEstimateIn - Whether to use "source" or "dest" chain for the conversion
|
|
11567
11755
|
* @returns The gas cost converted to fee token amount
|
|
11568
11756
|
* @private
|
|
11569
11757
|
*/
|
|
11570
|
-
async convertGasToFeeToken(gasEstimate,
|
|
11571
|
-
const
|
|
11758
|
+
async convertGasToFeeToken(gasEstimate, gasEstimateIn) {
|
|
11759
|
+
const client = this[gasEstimateIn].client;
|
|
11760
|
+
const gasPrice = await client.getGasPrice();
|
|
11572
11761
|
const gasCostInWei = gasEstimate * gasPrice;
|
|
11573
|
-
const
|
|
11574
|
-
const
|
|
11575
|
-
|
|
11576
|
-
|
|
11762
|
+
const evmChainID = `EVM-${client.chain?.id}`;
|
|
11763
|
+
const wethAddr = this[gasEstimateIn].config.getWrappedNativeAssetWithDecimals(evmChainID).asset;
|
|
11764
|
+
const feeToken = await this[gasEstimateIn].getFeeTokenWithDecimals();
|
|
11765
|
+
try {
|
|
11766
|
+
const { amountOut } = await this.findBestProtocolWithAmountIn(
|
|
11767
|
+
gasEstimateIn,
|
|
11768
|
+
wethAddr,
|
|
11769
|
+
feeToken.address,
|
|
11770
|
+
gasCostInWei,
|
|
11771
|
+
"v2"
|
|
11772
|
+
);
|
|
11773
|
+
if (amountOut === 0n) {
|
|
11774
|
+
throw new Error();
|
|
11775
|
+
}
|
|
11776
|
+
return amountOut;
|
|
11777
|
+
} catch {
|
|
11778
|
+
const nativeCurrency = client.chain?.nativeCurrency;
|
|
11779
|
+
const chainId = client.chain?.id;
|
|
11780
|
+
const gasCostInToken = new Decimal(formatUnits(gasCostInWei, nativeCurrency?.decimals));
|
|
11781
|
+
const tokenPriceUsd = await fetchPrice(nativeCurrency?.symbol, chainId);
|
|
11782
|
+
const gasCostUsd = gasCostInToken.times(tokenPriceUsd);
|
|
11783
|
+
const feeTokenPriceUsd = new Decimal(1);
|
|
11784
|
+
const gasCostInFeeToken = gasCostUsd.dividedBy(feeTokenPriceUsd);
|
|
11785
|
+
return parseUnits(gasCostInFeeToken.toFixed(feeToken.decimals), feeToken.decimals);
|
|
11577
11786
|
}
|
|
11578
|
-
const gasCostInToken = Number(gasCostInWei) / Math.pow(10, nativeToken.decimals);
|
|
11579
|
-
const tokenPriceUsd = await fetchPrice(nativeToken.symbol, chainId);
|
|
11580
|
-
const gasCostUsd = gasCostInToken * tokenPriceUsd;
|
|
11581
|
-
const feeTokenPriceUsd = await fetchPrice("DAI");
|
|
11582
|
-
const gasCostInFeeToken = gasCostUsd / feeTokenPriceUsd;
|
|
11583
|
-
return BigInt(Math.floor(gasCostInFeeToken * Math.pow(10, targetDecimals)));
|
|
11584
11787
|
}
|
|
11788
|
+
/**
|
|
11789
|
+
* Gets a quote for the native token cost of dispatching a post request.
|
|
11790
|
+
*
|
|
11791
|
+
* @param postRequest - The post request to quote
|
|
11792
|
+
* @param fee - The fee amount in fee token
|
|
11793
|
+
* @returns The native token amount required
|
|
11794
|
+
*/
|
|
11585
11795
|
async quoteNative(postRequest, fee) {
|
|
11586
11796
|
const dispatchPost = {
|
|
11587
11797
|
dest: toHex(postRequest.dest),
|
|
@@ -11603,37 +11813,38 @@ var IntentGateway = class {
|
|
|
11603
11813
|
* Finds the best Uniswap protocol (V2, V3, or V4) for swapping tokens given a desired output amount.
|
|
11604
11814
|
* Compares liquidity and pricing across different protocols and fee tiers.
|
|
11605
11815
|
*
|
|
11606
|
-
* @param
|
|
11816
|
+
* @param getQuoteIn - Whether to use "source" or "dest" chain for the swap
|
|
11607
11817
|
* @param tokenIn - The address of the input token
|
|
11608
11818
|
* @param tokenOut - The address of the output token
|
|
11609
11819
|
* @param amountOut - The desired output amount
|
|
11610
11820
|
* @returns Object containing the best protocol, required input amount, and fee tier (for V3/V4)
|
|
11611
11821
|
*/
|
|
11612
|
-
async findBestProtocolWithAmountOut(
|
|
11613
|
-
const
|
|
11822
|
+
async findBestProtocolWithAmountOut(getQuoteIn, tokenIn, tokenOut, amountOut) {
|
|
11823
|
+
const client = this[getQuoteIn].client;
|
|
11824
|
+
const evmChainID = `EVM-${client.chain?.id}`;
|
|
11614
11825
|
let amountInV2 = maxUint256;
|
|
11615
11826
|
let amountInV3 = maxUint256;
|
|
11616
11827
|
let amountInV4 = maxUint256;
|
|
11617
11828
|
let bestV3Fee = 0;
|
|
11618
11829
|
let bestV4Fee = 0;
|
|
11619
11830
|
const commonFees = [100, 500, 3e3, 1e4];
|
|
11620
|
-
const v2Router = this.source.config.getUniswapRouterV2Address(
|
|
11621
|
-
const v2Factory = this.source.config.getUniswapV2FactoryAddress(
|
|
11622
|
-
const v3Factory = this.source.config.getUniswapV3FactoryAddress(
|
|
11623
|
-
const v3Quoter = this.source.config.getUniswapV3QuoterAddress(
|
|
11624
|
-
const v4Quoter = this.source.config.getUniswapV4QuoterAddress(
|
|
11625
|
-
const wethAsset = this.source.config.getWrappedNativeAssetWithDecimals(
|
|
11831
|
+
const v2Router = this.source.config.getUniswapRouterV2Address(evmChainID);
|
|
11832
|
+
const v2Factory = this.source.config.getUniswapV2FactoryAddress(evmChainID);
|
|
11833
|
+
const v3Factory = this.source.config.getUniswapV3FactoryAddress(evmChainID);
|
|
11834
|
+
const v3Quoter = this.source.config.getUniswapV3QuoterAddress(evmChainID);
|
|
11835
|
+
const v4Quoter = this.source.config.getUniswapV4QuoterAddress(evmChainID);
|
|
11836
|
+
const wethAsset = this.source.config.getWrappedNativeAssetWithDecimals(evmChainID).asset;
|
|
11626
11837
|
const tokenInForQuote = tokenIn === ADDRESS_ZERO ? wethAsset : tokenIn;
|
|
11627
11838
|
const tokenOutForQuote = tokenOut === ADDRESS_ZERO ? wethAsset : tokenOut;
|
|
11628
11839
|
try {
|
|
11629
|
-
const v2PairExists = await
|
|
11840
|
+
const v2PairExists = await client.readContract({
|
|
11630
11841
|
address: v2Factory,
|
|
11631
11842
|
abi: uniswapV2Factory_default.ABI,
|
|
11632
11843
|
functionName: "getPair",
|
|
11633
11844
|
args: [tokenInForQuote, tokenOutForQuote]
|
|
11634
11845
|
});
|
|
11635
11846
|
if (v2PairExists !== ADDRESS_ZERO) {
|
|
11636
|
-
const v2AmountIn = await
|
|
11847
|
+
const v2AmountIn = await client.readContract({
|
|
11637
11848
|
address: v2Router,
|
|
11638
11849
|
abi: uniswapRouterV2_default.ABI,
|
|
11639
11850
|
functionName: "getAmountsIn",
|
|
@@ -11647,20 +11858,20 @@ var IntentGateway = class {
|
|
|
11647
11858
|
let bestV3AmountIn = maxUint256;
|
|
11648
11859
|
for (const fee of commonFees) {
|
|
11649
11860
|
try {
|
|
11650
|
-
const pool = await
|
|
11861
|
+
const pool = await client.readContract({
|
|
11651
11862
|
address: v3Factory,
|
|
11652
11863
|
abi: uniswapV3Factory_default.ABI,
|
|
11653
11864
|
functionName: "getPool",
|
|
11654
11865
|
args: [tokenInForQuote, tokenOutForQuote, fee]
|
|
11655
11866
|
});
|
|
11656
11867
|
if (pool !== ADDRESS_ZERO) {
|
|
11657
|
-
const liquidity = await
|
|
11868
|
+
const liquidity = await client.readContract({
|
|
11658
11869
|
address: pool,
|
|
11659
11870
|
abi: uniswapV3Pool_default.ABI,
|
|
11660
11871
|
functionName: "liquidity"
|
|
11661
11872
|
});
|
|
11662
11873
|
if (liquidity > BigInt(0)) {
|
|
11663
|
-
const quoteResult = (await
|
|
11874
|
+
const quoteResult = (await client.simulateContract({
|
|
11664
11875
|
address: v3Quoter,
|
|
11665
11876
|
abi: uniswapV3Quoter_default.ABI,
|
|
11666
11877
|
functionName: "quoteExactOutputSingle",
|
|
@@ -11700,7 +11911,7 @@ var IntentGateway = class {
|
|
|
11700
11911
|
hooks: ADDRESS_ZERO
|
|
11701
11912
|
// No hooks
|
|
11702
11913
|
};
|
|
11703
|
-
const quoteResult = (await
|
|
11914
|
+
const quoteResult = (await client.simulateContract({
|
|
11704
11915
|
address: v4Quoter,
|
|
11705
11916
|
abi: UNISWAP_V4_QUOTER_ABI,
|
|
11706
11917
|
functionName: "quoteExactOutputSingle",
|
|
@@ -11767,43 +11978,48 @@ var IntentGateway = class {
|
|
|
11767
11978
|
* Finds the best Uniswap protocol (V2, V3, or V4) for swapping tokens given an input amount.
|
|
11768
11979
|
* Compares liquidity and pricing across different protocols and fee tiers.
|
|
11769
11980
|
*
|
|
11770
|
-
* @param
|
|
11981
|
+
* @param getQuoteIn - Whether to use "source" or "dest" chain for the swap
|
|
11771
11982
|
* @param tokenIn - The address of the input token
|
|
11772
11983
|
* @param tokenOut - The address of the output token
|
|
11773
11984
|
* @param amountIn - The input amount to swap
|
|
11985
|
+
* @param selectedProtocol - Optional specific protocol to use ("v2", "v3", or "v4")
|
|
11774
11986
|
* @returns Object containing the best protocol, expected output amount, and fee tier (for V3/V4)
|
|
11775
11987
|
*/
|
|
11776
|
-
async findBestProtocolWithAmountIn(
|
|
11777
|
-
const
|
|
11988
|
+
async findBestProtocolWithAmountIn(getQuoteIn, tokenIn, tokenOut, amountIn, selectedProtocol) {
|
|
11989
|
+
const client = this[getQuoteIn].client;
|
|
11990
|
+
const evmChainID = `EVM-${client.chain?.id}`;
|
|
11778
11991
|
let amountOutV2 = BigInt(0);
|
|
11779
11992
|
let amountOutV3 = BigInt(0);
|
|
11780
11993
|
let amountOutV4 = BigInt(0);
|
|
11781
11994
|
let bestV3Fee = 0;
|
|
11782
11995
|
let bestV4Fee = 0;
|
|
11783
11996
|
const commonFees = [100, 500, 3e3, 1e4];
|
|
11784
|
-
const v2Router = this.source.config.getUniswapRouterV2Address(
|
|
11785
|
-
const v2Factory = this.source.config.getUniswapV2FactoryAddress(
|
|
11786
|
-
const v3Factory = this.source.config.getUniswapV3FactoryAddress(
|
|
11787
|
-
const v3Quoter = this.source.config.getUniswapV3QuoterAddress(
|
|
11788
|
-
const v4Quoter = this.source.config.getUniswapV4QuoterAddress(
|
|
11789
|
-
const wethAsset = this.source.config.getWrappedNativeAssetWithDecimals(
|
|
11997
|
+
const v2Router = this.source.config.getUniswapRouterV2Address(evmChainID);
|
|
11998
|
+
const v2Factory = this.source.config.getUniswapV2FactoryAddress(evmChainID);
|
|
11999
|
+
const v3Factory = this.source.config.getUniswapV3FactoryAddress(evmChainID);
|
|
12000
|
+
const v3Quoter = this.source.config.getUniswapV3QuoterAddress(evmChainID);
|
|
12001
|
+
const v4Quoter = this.source.config.getUniswapV4QuoterAddress(evmChainID);
|
|
12002
|
+
const wethAsset = this.source.config.getWrappedNativeAssetWithDecimals(evmChainID).asset;
|
|
11790
12003
|
const tokenInForQuote = tokenIn === ADDRESS_ZERO ? wethAsset : tokenIn;
|
|
11791
12004
|
const tokenOutForQuote = tokenOut === ADDRESS_ZERO ? wethAsset : tokenOut;
|
|
11792
12005
|
try {
|
|
11793
|
-
const v2PairExists = await
|
|
12006
|
+
const v2PairExists = await client.readContract({
|
|
11794
12007
|
address: v2Factory,
|
|
11795
12008
|
abi: uniswapV2Factory_default.ABI,
|
|
11796
12009
|
functionName: "getPair",
|
|
11797
12010
|
args: [tokenInForQuote, tokenOutForQuote]
|
|
11798
12011
|
});
|
|
11799
12012
|
if (v2PairExists !== ADDRESS_ZERO) {
|
|
11800
|
-
const v2AmountOut = await
|
|
12013
|
+
const v2AmountOut = await client.readContract({
|
|
11801
12014
|
address: v2Router,
|
|
11802
12015
|
abi: uniswapRouterV2_default.ABI,
|
|
11803
12016
|
functionName: "getAmountsOut",
|
|
11804
12017
|
args: [amountIn, [tokenInForQuote, tokenOutForQuote]]
|
|
11805
12018
|
});
|
|
11806
12019
|
amountOutV2 = v2AmountOut[1];
|
|
12020
|
+
if (selectedProtocol === "v2") {
|
|
12021
|
+
return { protocol: "v2", amountOut: amountOutV2 };
|
|
12022
|
+
}
|
|
11807
12023
|
}
|
|
11808
12024
|
} catch (error) {
|
|
11809
12025
|
console.warn("V2 quote failed:", error);
|
|
@@ -11811,20 +12027,20 @@ var IntentGateway = class {
|
|
|
11811
12027
|
let bestV3AmountOut = BigInt(0);
|
|
11812
12028
|
for (const fee of commonFees) {
|
|
11813
12029
|
try {
|
|
11814
|
-
const pool = await
|
|
12030
|
+
const pool = await client.readContract({
|
|
11815
12031
|
address: v3Factory,
|
|
11816
12032
|
abi: uniswapV3Factory_default.ABI,
|
|
11817
12033
|
functionName: "getPool",
|
|
11818
12034
|
args: [tokenInForQuote, tokenOutForQuote, fee]
|
|
11819
12035
|
});
|
|
11820
12036
|
if (pool !== ADDRESS_ZERO) {
|
|
11821
|
-
const liquidity = await
|
|
12037
|
+
const liquidity = await client.readContract({
|
|
11822
12038
|
address: pool,
|
|
11823
12039
|
abi: uniswapV3Pool_default.ABI,
|
|
11824
12040
|
functionName: "liquidity"
|
|
11825
12041
|
});
|
|
11826
12042
|
if (liquidity > BigInt(0)) {
|
|
11827
|
-
const quoteResult = (await
|
|
12043
|
+
const quoteResult = (await client.simulateContract({
|
|
11828
12044
|
address: v3Quoter,
|
|
11829
12045
|
abi: uniswapV3Quoter_default.ABI,
|
|
11830
12046
|
functionName: "quoteExactInputSingle",
|
|
@@ -11850,6 +12066,9 @@ var IntentGateway = class {
|
|
|
11850
12066
|
}
|
|
11851
12067
|
}
|
|
11852
12068
|
amountOutV3 = bestV3AmountOut;
|
|
12069
|
+
if (selectedProtocol === "v3") {
|
|
12070
|
+
return { protocol: "v3", amountOut: amountOutV3, fee: bestV3Fee };
|
|
12071
|
+
}
|
|
11853
12072
|
let bestV4AmountOut = BigInt(0);
|
|
11854
12073
|
for (const fee of commonFees) {
|
|
11855
12074
|
try {
|
|
@@ -11864,7 +12083,7 @@ var IntentGateway = class {
|
|
|
11864
12083
|
hooks: ADDRESS_ZERO
|
|
11865
12084
|
// No hooks
|
|
11866
12085
|
};
|
|
11867
|
-
const quoteResult = (await
|
|
12086
|
+
const quoteResult = (await client.simulateContract({
|
|
11868
12087
|
address: v4Quoter,
|
|
11869
12088
|
abi: UNISWAP_V4_QUOTER_ABI,
|
|
11870
12089
|
functionName: "quoteExactInputSingle",
|
|
@@ -11888,6 +12107,9 @@ var IntentGateway = class {
|
|
|
11888
12107
|
}
|
|
11889
12108
|
}
|
|
11890
12109
|
amountOutV4 = bestV4AmountOut;
|
|
12110
|
+
if (selectedProtocol === "v4") {
|
|
12111
|
+
return { protocol: "v4", amountOut: amountOutV4, fee: bestV4Fee };
|
|
12112
|
+
}
|
|
11891
12113
|
if (amountOutV2 === BigInt(0) && amountOutV3 === BigInt(0) && amountOutV4 === BigInt(0)) {
|
|
11892
12114
|
return {
|
|
11893
12115
|
protocol: null,
|