UNPKG

@wormhole-foundation/sdk-connect

Version:

The core package for the Connect SDK, used in conjunction with 1 or more of the chain packages

173 lines 8.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AutomaticTokenBridgeRoute = void 0; const sdk_base_1 = require("@wormhole-foundation/sdk-base"); const sdk_definitions_1 = require("@wormhole-foundation/sdk-definitions"); const tokenTransfer_js_1 = require("../../protocols/tokenBridge/tokenTransfer.js"); const types_js_1 = require("../../types.js"); const wormhole_js_1 = require("../../wormhole.js"); const route_js_1 = require("../route.js"); const types_js_2 = require("../types.js"); class AutomaticTokenBridgeRoute extends route_js_1.AutomaticRoute { static NATIVE_GAS_DROPOFF_SUPPORTED = true; static meta = { name: "AutomaticTokenBridge", }; static supportedNetworks() { return ["Mainnet", "Testnet"]; } // get the list of chains this route supports static supportedChains(network) { if (sdk_base_1.contracts.tokenBridgeRelayerChains.has(network)) { return sdk_base_1.contracts.tokenBridgeRelayerChains.get(network); } return []; } // get the list of destination tokens that may be received on the destination chain static async supportedDestinationTokens(sourceToken, fromChain, toChain) { try { if (!(0, sdk_definitions_1.isNative)(sourceToken)) { const srcAtb = await fromChain.getAutomaticTokenBridge(); const srcIsAccepted = await srcAtb.isRegisteredToken(sourceToken.address); if (!srcIsAccepted) { return []; } } const expectedDestinationToken = await tokenTransfer_js_1.TokenTransfer.lookupDestinationToken(fromChain, toChain, sourceToken); const atb = await toChain.getAutomaticTokenBridge(); const acceptable = await atb.isRegisteredToken(expectedDestinationToken.address); if (!acceptable) { return []; } return [expectedDestinationToken]; } catch (e) { return []; } } getDefaultOptions() { return { nativeGas: 0.0 }; } async validate(request, params) { try { const options = params.options ?? this.getDefaultOptions(); if (options.nativeGas && (options.nativeGas > 1.0 || options.nativeGas < 0.0)) throw new Error("Native gas must be between 0.0 and 1.0 (0% and 100%)"); // native gas drop-off when the native token is the destination should be 0 const { destination } = request; if ((0, sdk_definitions_1.isNative)(destination.id.address) && options.nativeGas === 0.0) options.nativeGas = 0; const updatedParams = { ...params, options }; const validatedParams = { ...updatedParams, normalizedParams: await this.normalizeTransferParams(request, updatedParams), }; return { valid: true, params: validatedParams }; } catch (e) { return { valid: false, params, error: e }; } } async normalizeTransferParams(request, params) { const amt = request.parseAmount(params.amount); const inputToken = (0, sdk_definitions_1.isNative)(request.source.id.address) ? await request.fromChain.getNativeWrappedTokenId() : request.source.id; const atb = await request.fromChain.getAutomaticTokenBridge(); const fee = await atb.getRelayerFee(request.toChain.chain, inputToken.address); // Min amount is fee + 5% const minAmount = (fee * 105n) / 100n; if (sdk_base_1.amount.units(amt) < minAmount) { throw new types_js_2.MinAmountError(sdk_base_1.amount.fromBaseUnits(minAmount, amt.decimals)); } const redeemableAmount = sdk_base_1.amount.units(amt) - fee; let srcNativeGasAmount = sdk_base_1.amount.fromBaseUnits(0n, request.source.decimals); if (params.options && params.options.nativeGas > 0) { const dtb = await request.toChain.getAutomaticTokenBridge(); // the maxSwapAmount is in destination chain decimals let maxSwapAmount = await dtb.maxSwapAmount(request.destination.id.address); const redeemableAmountTruncated = sdk_base_1.amount.truncate(sdk_base_1.amount.fromBaseUnits(redeemableAmount, amt.decimals), tokenTransfer_js_1.TokenTransfer.MAX_DECIMALS); const dstDecimals = await request.toChain.getDecimals(request.destination.id.address); const dstAmountReceivable = sdk_base_1.amount.units(sdk_base_1.amount.scale(redeemableAmountTruncated, dstDecimals)); if (dstAmountReceivable < maxSwapAmount) { // can't swap more than the receivable amount maxSwapAmount = dstAmountReceivable; } const scale = 10000; const scaledGasPercent = BigInt(Math.floor(params.options.nativeGas * scale)); const dstNativeGasUnits = (maxSwapAmount * scaledGasPercent) / BigInt(scale); // the native gas percentage is applied to the max swap amount const dstNativeGasAmount = sdk_base_1.amount.fromBaseUnits(dstNativeGasUnits, request.destination.decimals); // convert the native gas amount to source chain decimals srcNativeGasAmount = sdk_base_1.amount.scale(sdk_base_1.amount.truncate(dstNativeGasAmount, tokenTransfer_js_1.TokenTransfer.MAX_DECIMALS), request.source.decimals); // can't request more gas than the redeemable amount if (sdk_base_1.amount.units(srcNativeGasAmount) > redeemableAmount) { srcNativeGasAmount = sdk_base_1.amount.fromBaseUnits(redeemableAmount, request.source.decimals); } } return { fee: sdk_base_1.amount.fromBaseUnits(fee, request.source.decimals), amount: amt, nativeGasAmount: srcNativeGasAmount, }; } async quote(request, params) { const atb = await request.fromChain.getAutomaticTokenBridge(); if ((0, sdk_definitions_1.isTokenId)(request.source.id)) { const isRegistered = await atb.isRegisteredToken(request.source.id.address); if (!isRegistered) { return { success: false, error: new Error("Source token is not registered"), }; } } try { let quote = await tokenTransfer_js_1.TokenTransfer.quoteTransfer(this.wh, request.fromChain, request.toChain, { automatic: true, amount: sdk_base_1.amount.units(params.normalizedParams.amount), token: request.source.id, nativeGas: sdk_base_1.amount.units(params.normalizedParams.nativeGasAmount), }); return request.displayQuote(quote, params); } catch (e) { return { success: false, error: e, }; } } async initiate(request, signer, quote, to) { const { params } = quote; const transfer = this.toTransferDetails(request, params, wormhole_js_1.Wormhole.chainAddress(signer.chain(), signer.address()), to); const txids = await tokenTransfer_js_1.TokenTransfer.transfer(request.fromChain, transfer, signer); return { from: transfer.from.chain, to: transfer.to.chain, state: types_js_1.TransferState.SourceInitiated, originTxs: txids, }; } async *track(receipt, timeout) { try { yield* tokenTransfer_js_1.TokenTransfer.track(this.wh, receipt, timeout); } catch (e) { throw e; } } toTransferDetails(request, params, from, to) { const transfer = { from, to, automatic: true, amount: sdk_base_1.amount.units(params.normalizedParams.amount), token: request.source.id, nativeGas: sdk_base_1.amount.units(params.normalizedParams.nativeGasAmount), }; return transfer; } } exports.AutomaticTokenBridgeRoute = AutomaticTokenBridgeRoute; //# sourceMappingURL=automatic.js.map