@wormhole-foundation/sdk-evm-tokenbridge
Version:
SDK for EVM chains, used in conjunction with @wormhole-foundation/sdk
115 lines • 6.37 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EvmAutomaticTokenBridge = void 0;
const sdk_connect_1 = require("@wormhole-foundation/sdk-connect");
const sdk_evm_1 = require("@wormhole-foundation/sdk-evm");
const index_js_1 = require("./index.js");
require("@wormhole-foundation/sdk-evm-core");
const sdk_evm_core_1 = require("@wormhole-foundation/sdk-evm-core");
class EvmAutomaticTokenBridge {
network;
chain;
provider;
contracts;
tokenBridgeRelayer;
tokenBridge;
core;
chainId;
constructor(network, chain, provider, contracts) {
this.network = network;
this.chain = chain;
this.provider = provider;
this.contracts = contracts;
if (network === 'Devnet')
throw new Error('AutomaticTokenBridge not supported on Devnet');
this.chainId = sdk_connect_1.nativeChainIds.networkChainToNativeChainId.get(network, chain);
const tokenBridgeAddress = this.contracts.tokenBridge;
if (!tokenBridgeAddress)
throw new Error(`Wormhole Token Bridge contract for domain ${chain} not found`);
this.tokenBridge = index_js_1.ethers_contracts.Bridge__factory.connect(tokenBridgeAddress, provider);
const relayerAddress = this.contracts.tokenBridgeRelayer;
if (!relayerAddress)
throw new Error(`Wormhole Token Bridge Relayer contract for domain ${chain} not found`);
this.tokenBridgeRelayer =
index_js_1.ethers_contracts.TokenBridgeRelayer__factory.connect(relayerAddress, provider);
this.core = new sdk_evm_core_1.EvmWormholeCore(network, chain, provider, contracts);
}
async *redeem(sender, vaa) {
const senderAddr = new sdk_evm_1.EvmAddress(sender).toString();
const txReq = await this.tokenBridgeRelayer.completeTransferWithRelay.populateTransaction((0, sdk_connect_1.serialize)(vaa));
yield this.createUnsignedTx((0, sdk_evm_1.addFrom)(txReq, senderAddr), 'TokenBridgeRelayer.completeTransferWithRelay');
}
static async fromRpc(provider, config) {
const [network, chain] = await sdk_evm_1.EvmPlatform.chainFromRpc(provider);
const conf = config[chain];
if (conf.network !== network)
throw new Error(`Network mismatch: ${conf.network} != ${network}`);
return new EvmAutomaticTokenBridge(network, chain, provider, conf.contracts);
}
//alternative naming: initiateTransfer
async *transfer(sender, recipient, token, amount, nativeGas) {
const senderAddr = new sdk_evm_1.EvmAddress(sender).toString();
const recipientChainId = (0, sdk_connect_1.toChainId)(recipient.chain);
const messageFee = await this.core.getMessageFee();
const recipientAddress = recipient.address
.toUniversalAddress()
.toUint8Array();
const nativeTokenGas = nativeGas ? nativeGas : 0n;
if ((0, sdk_connect_1.isNative)(token)) {
const txReq = await this.tokenBridgeRelayer.wrapAndTransferEthWithRelay.populateTransaction(nativeTokenGas, recipientChainId, recipientAddress, 0, // skip batching
{ value: amount + messageFee });
yield this.createUnsignedTx((0, sdk_evm_1.addFrom)(txReq, senderAddr), 'TokenBridgeRelayer.wrapAndTransferETHWithRelay');
}
else {
//TODO check for ERC-2612 (permit) support on token?
const tokenAddr = new sdk_evm_1.EvmAddress(token).toString();
const tokenContract = sdk_evm_1.EvmPlatform.getTokenImplementation(this.provider, tokenAddr);
const allowance = await tokenContract.allowance(senderAddr, this.tokenBridgeRelayer.target);
if (allowance < amount) {
const txReq = await tokenContract.approve.populateTransaction(this.tokenBridgeRelayer.target, amount);
yield this.createUnsignedTx((0, sdk_evm_1.addFrom)(txReq, senderAddr), 'AutomaticTokenBridge.Approve');
}
const txReq = await this.tokenBridgeRelayer.transferTokensWithRelay.populateTransaction(tokenAddr, amount, nativeTokenGas, recipientChainId, recipientAddress, 0, { value: messageFee });
yield this.createUnsignedTx((0, sdk_evm_1.addFrom)(txReq, senderAddr), 'TokenBridgeRelayer.TransferTokensWithRelay');
}
}
async getRelayerFee(destination, token) {
const destChainId = (0, sdk_connect_1.toChainId)(destination);
const srcTokenAddress = await this.tokenAddress(token);
const tokenContract = sdk_evm_1.EvmPlatform.getTokenImplementation(this.provider, srcTokenAddress);
const decimals = await tokenContract.decimals();
return await this.tokenBridgeRelayer.calculateRelayerFee(destChainId, srcTokenAddress, decimals);
}
// Return the amount of native gas that will be
// received when the incoming bridge transfer is redeemed
// Note: for a quote, this should be called on the destination chain
async nativeTokenAmount(token, amount) {
const address = await this.tokenAddress(token);
return this.tokenBridgeRelayer.calculateNativeSwapAmountOut(address, amount);
}
async maxSwapAmount(token) {
const address = await this.tokenAddress(token);
return this.tokenBridgeRelayer.calculateMaxSwapAmountIn(address);
}
async getRegisteredTokens() {
const tokens = await this.tokenBridgeRelayer.getAcceptedTokensList();
return tokens.map((address) => (0, sdk_connect_1.toNative)(this.chain, address));
}
async isRegisteredToken(token) {
const address = await this.tokenAddress(token);
return await this.tokenBridgeRelayer.isAcceptedToken(address);
}
async tokenAddress(token) {
return (0, sdk_connect_1.isNative)(token)
? await this.getWeth()
: new sdk_evm_1.EvmAddress(token).toString();
}
async getWeth() {
return sdk_evm_1.WETH_CONTRACTS[this.network]?.[this.chain] ?? this.tokenBridge.WETH();
}
createUnsignedTx(txReq, description, parallelizable = false) {
return new sdk_evm_1.EvmUnsignedTransaction((0, sdk_evm_1.addChainId)(txReq, this.chainId), this.network, this.chain, description, parallelizable);
}
}
exports.EvmAutomaticTokenBridge = EvmAutomaticTokenBridge;
//# sourceMappingURL=automaticTokenBridge.js.map