UNPKG

@arcana/ca-sdk

Version:

Arcana Network's chain abstraction SDK for unified balance in Web3 apps

107 lines (106 loc) 4.37 kB
import { Universe } from "@arcana/ca-common"; import { createPublicClient, hexToBigInt, serializeTransaction, webSocket, } from "viem"; import { ZERO_ADDRESS } from "../../constants"; import { getLogger } from "../../logger"; import { simulateTransaction } from "../../simulate"; import { divDecimals, evmWaitForFill, getL1Fee } from "../../utils"; import { NativeRequestBase } from "../common/native.base"; const logger = getLogger(); class NativeTransfer extends NativeRequestBase { constructor(input) { super(input); this.input = input; this.destinationUniverse = Universe.ETHEREUM; const wsUrls = this.input.chain.rpcUrls?.default?.webSocket; if (!wsUrls?.length) { throw new Error(`Web-Socket RPC URL missing for chain ${this.input.chain.id}`); } this.publicClient = createPublicClient({ transport: webSocket(wsUrls[0]), }); } async simulateTx() { const { data, to, value } = this.input.evm.tx; const nativeToken = this.input.chainList.getNativeToken(this.input.chain.id); if (this.simulateTxRes) { let gasFee = 0n; if (!this.input.options.bridge) { const [{ gasPrice, maxFeePerGas }, l1Fee] = await Promise.all([ this.publicClient.estimateFeesPerGas(), getL1Fee(this.input.chain, serializeTransaction({ chainId: this.input.chain.id, data: data ?? "0x00", to: to, type: "eip1559", value: hexToBigInt(value ?? `0x00`), })), ]); const gasUnitPrice = maxFeePerGas ?? gasPrice; gasFee = this.simulateTxRes.gas * gasUnitPrice + l1Fee; } return { ...this.simulateTxRes, gasFee: divDecimals(gasFee, nativeToken.decimals), }; } const txsToSimulate = [ { from: ZERO_ADDRESS, input: data ?? "0x00", to, value: value ?? "0x00", }, ]; const [simulation, feeData, l1Fee] = await Promise.all([ simulateTransaction(this.input.chain.id, txsToSimulate, this.input.options.networkConfig.SIMULATION_URL), this.publicClient.estimateFeesPerGas(), getL1Fee(this.input.chain, serializeTransaction({ chainId: this.input.chain.id, data: data ?? "0x00", to: to, type: "eip1559", value: hexToBigInt(value ?? "0x00"), })), ]); const gasUnitPrice = feeData.maxFeePerGas ?? feeData.gasPrice ?? 0n; if (gasUnitPrice === 0n) { throw new Error("could not get maxFeePerGas or gasPrice from RPC"); } let gasFee = BigInt(simulation.data.gas_used) * gasUnitPrice + l1Fee; logger.debug("native:simulateTx", { feeData, l1Fee, maxFeePerGas: gasUnitPrice, simulation, totalGas: gasFee, totalGasInDecimal: divDecimals(gasFee, nativeToken.decimals), }); if (this.input.options.bridge) { gasFee = 0n; } this.simulateTxRes = { amount: divDecimals(value ?? "0", nativeToken.decimals), gas: BigInt(simulation.data.gas_used), gasFee: divDecimals(gasFee, nativeToken.decimals), token: { contractAddress: ZERO_ADDRESS, decimals: nativeToken.decimals, name: nativeToken.name, symbol: nativeToken.symbol, }, }; return this.simulateTxRes; } async waitForFill(requestHash, intentID, waitForDoubleCheckTx) { try { await Promise.all([ waitForDoubleCheckTx(), evmWaitForFill(this.input.chainList.getVaultContractAddress(this.input.chain.id), this.publicClient, requestHash, intentID, this.input.options.networkConfig.GRPC_URL, this.input.options.networkConfig.COSMOS_URL), ]); } finally { (await this.publicClient.transport.getRpcClient()).close(); } } } export default NativeTransfer;