@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
JavaScript
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
;