Skip to content

Commit c9d6c05

Browse files
authored
[sdk]: estimate order in source native (#713)
1 parent aff8110 commit c9d6c05

File tree

4 files changed

+63
-20
lines changed

4 files changed

+63
-20
lines changed

sdk/packages/sdk/src/protocols/intents/GasEstimator.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import type { HexString } from "@/types"
2828
import type { IntentGatewayContext } from "./types"
2929
import { BundlerMethod } from "./types"
3030
import type { BundlerGasEstimate, PimlicoGasPriceEstimate } from "./types"
31-
import { getFeeToken, transformOrderForContract, convertGasToFeeToken } from "./utils"
31+
import { getFeeToken, transformOrderForContract, convertGasToFeeToken, convertFeeTokenToWei } from "./utils"
3232
import { CryptoUtils } from "./CryptoUtils"
3333

3434
/**
@@ -241,17 +241,15 @@ export class GasEstimator {
241241
preVerificationGas = (BigInt(gasEstimate.preVerificationGas) * 105n) / 100n
242242

243243
if (pimlicoGasPrices) {
244-
const level =
245-
pimlicoGasPrices.fast ?? pimlicoGasPrices.standard ?? pimlicoGasPrices.slow ?? null
244+
const level = pimlicoGasPrices.fast ?? pimlicoGasPrices.standard ?? pimlicoGasPrices.slow ?? null
246245

247246
if (level) {
248247
const pimMaxFeePerGas = BigInt(level.maxFeePerGas)
249248
const pimMaxPriorityFeePerGas = BigInt(level.maxPriorityFeePerGas)
250249

251250
maxFeePerGas = pimMaxFeePerGas + (pimMaxFeePerGas * BigInt(maxFeeBumpPercent)) / 100n
252251
maxPriorityFeePerGas =
253-
pimMaxPriorityFeePerGas +
254-
(pimMaxPriorityFeePerGas * BigInt(priorityFeeBumpPercent)) / 100n
252+
pimMaxPriorityFeePerGas + (pimMaxPriorityFeePerGas * BigInt(priorityFeeBumpPercent)) / 100n
255253
}
256254
}
257255
} catch (e) {
@@ -275,19 +273,22 @@ export class GasEstimator {
275273
}
276274

277275
const totalGas = callGasLimit + verificationGasLimit + preVerificationGas
278-
const totalGasCostWei = totalGas * maxFeePerGas
276+
const rawTotalGasCostWei = totalGas * maxFeePerGas
277+
279278
const totalGasInDestFeeToken = await convertGasToFeeToken(
280279
this.ctx,
281280
totalGas,
282281
"dest",
283282
destStateMachineId,
284283
gasPrice,
285284
)
286-
const totalGasInSourceFeeToken = adjustDecimals(
287-
totalGasInDestFeeToken,
288-
destFeeToken.decimals,
289-
sourceFeeToken.decimals,
290-
)
285+
const totalGasInSourceFeeToken = isSameChain
286+
? totalGasInDestFeeToken
287+
: adjustDecimals(totalGasInDestFeeToken, destFeeToken.decimals, sourceFeeToken.decimals)
288+
289+
const totalGasCostWei = isSameChain
290+
? rawTotalGasCostWei
291+
: await convertFeeTokenToWei(this.ctx, totalGasInSourceFeeToken, "source", souceStateMachineId)
291292

292293
return {
293294
callGasLimit,

sdk/packages/sdk/src/protocols/intents/utils.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,50 @@ export async function convertGasToFeeToken(
219219
return parseUnits(gasCostInFeeToken.toFixed(feeToken.decimals), feeToken.decimals)
220220
}
221221
}
222+
223+
/**
224+
* Converts a fee-token amount on a given chain into the equivalent native wei amount.
225+
*
226+
* First attempts a Uniswap V2 quote (fee token -> WETH). If that quote fails or
227+
* returns zero, falls back to a price-oracle estimate assuming the fee token is $1.
228+
*
229+
* @param ctx - Shared IntentsV2 context.
230+
* @param feeTokenAmount - Amount in fee token units (scaled by fee token decimals).
231+
* @param feeTokenIn - Which chain side the fee-token amount belongs to (`"source"` or `"dest"`).
232+
* @param evmChainID - State-machine ID of the chain used for conversion.
233+
* @returns Native wei-equivalent amount.
234+
*/
235+
export async function convertFeeTokenToWei(
236+
ctx: IntentGatewayContext,
237+
feeTokenAmount: bigint,
238+
feeTokenIn: "source" | "dest",
239+
evmChainID: string,
240+
): Promise<bigint> {
241+
const chain = ctx[feeTokenIn]
242+
const client = chain.client
243+
const wethAddr = chain.configService.getWrappedNativeAssetWithDecimals(evmChainID).asset
244+
const feeToken = await getFeeToken(ctx, evmChainID, chain)
245+
246+
try {
247+
const { amountOut } = await ctx.swap.findBestProtocolWithAmountIn(
248+
client,
249+
feeToken.address,
250+
wethAddr,
251+
feeTokenAmount,
252+
evmChainID,
253+
{ selectedProtocol: "v2" },
254+
)
255+
if (amountOut === 0n) {
256+
throw new Error()
257+
}
258+
return amountOut
259+
} catch {
260+
const nativeCurrency = client.chain?.nativeCurrency
261+
const chainId = Number.parseInt(evmChainID.split("-")[1])
262+
const feeTokenAmountInToken = new Decimal(formatUnits(feeTokenAmount, feeToken.decimals))
263+
const nativeTokenPriceUsd = await fetchPrice(nativeCurrency?.symbol, chainId)
264+
const feeTokenAmountUsd = feeTokenAmountInToken.times(new Decimal(1))
265+
const nativeAmount = feeTokenAmountUsd.dividedBy(nativeTokenPriceUsd)
266+
return parseUnits(nativeAmount.toFixed(nativeCurrency?.decimals ?? 18), nativeCurrency?.decimals ?? 18)
267+
}
268+
}

sdk/packages/sdk/src/tests/sequential/intentGateway.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,10 @@ async function runCrossChainEstimate(srcKey: string, destKey: string) {
116116
const estimate = await intentGateway.estimateFillOrder({ order })
117117

118118
console.log(`${srcKey} => ${destKey}`)
119+
console.log("Estimated cost (totalGasCostWei):", estimate.totalGasCostWei)
119120
console.log("Estimated fee (totalGasInFeeToken):", estimate.totalGasInFeeToken)
120121

122+
assert(estimate.totalGasCostWei > 0n)
121123
assert(estimate.totalGasInFeeToken > 0n)
122124
}
123125

@@ -138,6 +140,8 @@ async function runSameChainEstimate(chainKey: string) {
138140

139141
const estimate = await intentGateway.estimateFillOrder({ order })
140142

143+
console.log(`${chainKey} same-chain estimated cost (totalGasCostWei):`, estimate.totalGasCostWei)
141144
console.log(`${chainKey} same-chain USDC => EXT, estimated fee:`, estimate.totalGasInFeeToken)
145+
assert(estimate.totalGasCostWei > 0n)
142146
assert(estimate.totalGasInFeeToken > 0n)
143147
}

sdk/packages/simplex/src/tests/strategies/basic.testnet.test.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -263,15 +263,6 @@ describe("Filler V2 - Solver Selection ON", () => {
263263
console.log(`Order placed successfully with ID: ${order.id}`)
264264
}
265265

266-
for await (const status of gen) {
267-
if (status.status === "BID_SELECTED") {
268-
console.log(`Bid selected: solver=${status.selectedSolver}, userOpHash=${status.userOpHash}`)
269-
}
270-
if (status.status === "FAILED") {
271-
throw new Error(`Order execution failed: ${status.error}`)
272-
}
273-
}
274-
275266
expect(order.id).toBeDefined()
276267
expect(order.user).toBe(bytes20ToBytes32(beneficiaryAddress))
277268
expect(order.source).toBe(toHex(bscChapelId))

0 commit comments

Comments
 (0)