@wormhole-foundation/sdk-connect
Version:
The core package for the Connect SDK, used in conjunction with 1 or more of the chain packages
236 lines • 9.98 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.TBTCRoute = void 0;
const sdk_base_1 = require("@wormhole-foundation/sdk-base");
const route_js_1 = require("../route.js");
const sdk_definitions_1 = require("@wormhole-foundation/sdk-definitions");
const types_js_1 = require("../../types.js");
const wormhole_js_1 = require("../../wormhole.js");
const common_js_1 = require("../../common.js");
class TBTCRoute extends route_js_1.ManualRoute {
static meta = {
name: "ManualTBTC",
};
static supportedNetworks() {
return ["Mainnet"];
}
static supportedChains(network) {
return sdk_base_1.contracts.tokenBridgeChains(network);
}
static async supportedDestinationTokens(sourceToken, fromChain, toChain) {
if (!(await this.isSourceTokenSupported(sourceToken, fromChain))) {
return [];
}
const tbtcToken = sdk_definitions_1.TBTCBridge.getNativeTbtcToken(toChain.chain);
if (tbtcToken) {
return [tbtcToken];
}
const tb = await toChain.getTokenBridge();
const ethTbtc = sdk_definitions_1.TBTCBridge.getNativeTbtcToken("Ethereum");
try {
const wrappedTbtc = await tb.getWrappedAsset(ethTbtc);
return [wormhole_js_1.Wormhole.tokenId(toChain.chain, wrappedTbtc.toString())];
}
catch (e) {
if (e.message.includes("not a wrapped asset"))
return [];
throw e;
}
}
getDefaultOptions() {
return {};
}
async validate(request, params) {
const amount = request.parseAmount(params.amount);
const validatedParams = {
normalizedParams: {
amount,
},
options: params.options ?? this.getDefaultOptions(),
...params,
};
return { valid: true, params: validatedParams };
}
async quote(request, params) {
const eta = sdk_base_1.finality.estimateFinalityTime(request.fromChain.chain) + sdk_base_1.guardians.guardianAttestationEta;
return {
success: true,
params,
sourceToken: {
token: request.source.id,
amount: params.normalizedParams.amount,
},
destinationToken: {
token: request.destination.id,
amount: params.normalizedParams.amount,
},
eta,
expires: sdk_base_1.time.expiration(24, 0, 0),
};
}
async initiate(request, signer, quote, to) {
const amt = sdk_base_1.amount.units(quote.params.normalizedParams.amount);
const isEthereum = request.fromChain.chain === "Ethereum";
const nativeTbtc = sdk_definitions_1.TBTCBridge.getNativeTbtcToken(request.fromChain.chain);
const isNativeTbtc = nativeTbtc && (0, sdk_definitions_1.isSameToken)(quote.sourceToken.token, nativeTbtc);
if (isNativeTbtc && !isEthereum) {
return await this.transferNative(request, signer, to, amt);
}
if (!isNativeTbtc && isEthereum) {
throw new Error("Only tbtc can be transferred on Ethereum");
}
if (!isNativeTbtc) {
const tb = await request.fromChain.getTokenBridge();
const originalAsset = await tb.getOriginalAsset(quote.sourceToken.token.address);
const ethTbtc = sdk_definitions_1.TBTCBridge.getNativeTbtcToken("Ethereum");
if (!(0, sdk_definitions_1.isSameToken)(originalAsset, ethTbtc)) {
throw new Error("Can only transfer wrapped tbtc");
}
}
return await this.transferWrapped(request, signer, to, amt);
}
async transferNative(request, signer, to, amt) {
const sender = wormhole_js_1.Wormhole.parseAddress(signer.chain(), signer.address());
const bridge = await request.fromChain.getTBTCBridge();
const xfer = bridge.transfer(sender, to, amt);
const txIds = await (0, common_js_1.signSendWait)(request.fromChain, xfer, signer);
const receipt = {
originTxs: txIds,
state: types_js_1.TransferState.SourceInitiated,
from: request.fromChain.chain,
to: request.toChain.chain,
};
return receipt;
}
async transferWrapped(request, signer, to, amt) {
const sender = wormhole_js_1.Wormhole.parseAddress(signer.chain(), signer.address());
const toGateway = sdk_base_1.contracts.tbtc.get(request.fromChain.network, to.chain);
const tb = await request.fromChain.getTokenBridge();
let xfer;
if (toGateway) {
// payload3 transfer to gateway contract
xfer = tb.transfer(sender, wormhole_js_1.Wormhole.chainAddress(request.toChain.chain, toGateway), request.source.id.address, amt,
// payload is the recipient address
to.address.toUniversalAddress().toUint8Array());
}
else {
xfer = tb.transfer(sender, to, request.source.id.address, amt);
}
const txIds = await (0, common_js_1.signSendWait)(request.fromChain, xfer, signer);
const receipt = {
originTxs: txIds,
state: types_js_1.TransferState.SourceInitiated,
from: request.fromChain.chain,
to: request.toChain.chain,
};
return receipt;
}
async complete(signer, receipt) {
if (!(0, types_js_1.isAttested)(receipt)) {
throw new Error("The source must be finalized in order to complete the transfer");
}
const sender = wormhole_js_1.Wormhole.parseAddress(signer.chain(), signer.address());
const vaa = receipt.attestation.attestation;
const toChain = this.wh.getChain(receipt.to);
let xfer;
if (vaa.payloadLiteral === "TBTCBridge:GatewayTransfer") {
const bridge = await toChain.getTBTCBridge();
xfer = bridge.redeem(sender, vaa);
}
else {
const tb = await toChain.getTokenBridge();
// This is really a TokenBridge:Transfer VAA
const serialized = (0, sdk_definitions_1.serialize)(vaa);
const tbVaa = (0, sdk_definitions_1.deserialize)("TokenBridge:Transfer", serialized);
xfer = tb.redeem(sender, tbVaa);
}
const dstTxIds = await (0, common_js_1.signSendWait)(toChain, xfer, signer);
return {
...receipt,
state: types_js_1.TransferState.DestinationInitiated,
destinationTxs: dstTxIds,
};
}
async resume(txid) {
const vaa = await this.wh.getVaa(txid.txid, sdk_definitions_1.TBTCBridge.getTransferDiscriminator());
if (!vaa)
throw new Error("No VAA found for transaction: " + txid);
const ethTbtc = sdk_definitions_1.TBTCBridge.getNativeTbtcToken("Ethereum");
const { chain, address } = vaa.payload.token;
if (!(0, sdk_definitions_1.isSameToken)(ethTbtc, { chain, address })) {
throw new Error("Can only resume tbtc transfers");
}
return {
originTxs: [txid],
state: types_js_1.TransferState.Attested,
from: vaa.emitterChain,
to: vaa.payload.to.chain,
attestation: {
id: {
chain: vaa.emitterChain,
emitter: vaa.emitterAddress,
sequence: vaa.sequence,
},
attestation: vaa,
},
};
}
async *track(receipt, timeout) {
if ((0, types_js_1.isSourceInitiated)(receipt) || (0, types_js_1.isSourceFinalized)(receipt)) {
const { txid } = receipt.originTxs[receipt.originTxs.length - 1];
const vaa = await this.wh.getVaa(txid, sdk_definitions_1.TBTCBridge.getTransferDiscriminator(), timeout);
if (!vaa)
throw new Error("No VAA found for transaction: " + txid);
const msgId = {
chain: vaa.emitterChain,
emitter: vaa.emitterAddress,
sequence: vaa.sequence,
};
receipt = {
...receipt,
state: types_js_1.TransferState.Attested,
attestation: {
id: msgId,
attestation: vaa,
},
};
yield receipt;
}
if ((0, types_js_1.isAttested)(receipt)) {
const toChain = this.wh.getChain(receipt.to);
const toBridge = await toChain.getTokenBridge();
const isCompleted = await toBridge.isTransferCompleted(receipt.attestation.attestation);
if (isCompleted) {
receipt = {
...receipt,
state: types_js_1.TransferState.DestinationFinalized,
};
yield receipt;
}
}
yield receipt;
}
static async isSourceTokenSupported(sourceToken, fromChain) {
if ((0, sdk_definitions_1.isNative)(sourceToken.address)) {
return false;
}
// Native tbtc is supported
const nativeTbtc = sdk_definitions_1.TBTCBridge.getNativeTbtcToken(fromChain.chain);
if (nativeTbtc && (0, sdk_definitions_1.isSameToken)(sourceToken, nativeTbtc)) {
return true;
}
// Wormhole-wrapped Ethereum tbtc is supported
const tb = await fromChain.getTokenBridge();
try {
const originalAsset = await tb.getOriginalAsset(sourceToken.address);
return (0, sdk_definitions_1.isSameToken)(originalAsset, sdk_definitions_1.TBTCBridge.getNativeTbtcToken("Ethereum"));
}
catch (e) {
if (e.message.includes("not a wrapped asset"))
return false;
throw e;
}
}
}
exports.TBTCRoute = TBTCRoute;
//# sourceMappingURL=tbtc.js.map
;