@wormhole-foundation/sdk-connect
Version:
The core package for the Connect SDK, used in conjunction with 1 or more of the chain packages
356 lines • 15.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Wormhole = void 0;
const sdk_base_1 = require("@wormhole-foundation/sdk-base");
const sdk_definitions_1 = require("@wormhole-foundation/sdk-definitions");
const circle_api_js_1 = require("./circle-api.js");
const config_js_1 = require("./config.js");
const config_js_2 = require("./config.js");
const cctpTransfer_js_1 = require("./protocols/cctp/cctpTransfer.js");
const tokenTransfer_js_1 = require("./protocols/tokenBridge/tokenTransfer.js");
const resolver_js_1 = require("./routes/resolver.js");
const tasks_js_1 = require("./tasks.js");
const whscan_api_js_1 = require("./whscan-api.js");
class Wormhole {
_network;
_platforms;
_chains;
config;
constructor(network, platforms, config) {
this._network = network;
this.config = (0, config_js_1.applyWormholeConfigOverrides)(network, config);
this._chains = new Map();
this._platforms = new Map();
for (const p of platforms) {
this._platforms.set(p._platform, new p(network, this.config.chains));
}
}
get network() {
return this._network;
}
/**
* Creates a CircleTransfer object to move Native USDC from one chain to another
* @param amount the amount to transfer
* @param from the address to transfer from
* @param to the address to transfer to
* @param automatic whether to use automatic delivery
* @param payload the payload to send with the transfer
* @param nativeGas the amount of native gas to send with the transfer
* @returns the CircleTransfer object
* @throws Errors if the chain or protocol is not supported
*/
async circleTransfer(amount, from, to, automatic, payload, nativeGas) {
if (automatic && payload)
throw new Error("Payload with automatic delivery is not supported");
if (!sdk_base_1.circle.isCircleChain(this.network, from.chain) ||
!sdk_base_1.circle.isCircleChain(this.network, to.chain) ||
!sdk_base_1.circle.isCircleSupported(this.network, from.chain) ||
!sdk_base_1.circle.isCircleSupported(this.network, to.chain))
throw new Error(`Network and chain not supported: ${this.network} ${from.chain} `);
// ensure the amount is > fee + native gas
if (automatic) {
const acb = await this.getChain(from.chain).getAutomaticCircleBridge();
const relayerFee = await acb.getRelayerFee(to.chain);
const minAmount = relayerFee + (nativeGas ? nativeGas : 0n);
if (amount < minAmount)
throw new Error(`Amount must be > ${minAmount} (relayerFee + nativeGas)`);
}
return await cctpTransfer_js_1.CircleTransfer.from(this, {
amount,
from,
to,
automatic,
payload,
nativeGas,
});
}
/**
* Creates a TokenTransfer object to move a token from one chain to another
* @param token the token to transfer
* @param amount the amount to transfer
* @param from the address to transfer from
* @param to the address to transfer to
* @param automatic whether to use automatic delivery
* @param payload the payload to send with the transfer
* @param nativeGas the amount of native gas to send with the transfer
* @returns the TokenTransfer object
* @throws Errors if the chain or protocol is not supported
*/
async tokenTransfer(token, amount, from, to, automatic, payload, nativeGas) {
return await tokenTransfer_js_1.TokenTransfer.from(this, {
token,
amount,
from,
to,
automatic,
payload,
nativeGas,
});
}
/**
* Gets a RouteResolver configured with the routes passed
* @param routes the list RouteConstructors to use
* @returns the RouteResolver
*/
resolver(routes) {
return new resolver_js_1.RouteResolver(this, routes);
}
/**
* Gets the contract addresses for a given chain
* @param chain the chain name
* @returns the contract addresses
*/
getContracts(chain) {
return this.config.chains[chain]?.contracts;
}
/**
* Returns the platform object, i.e. the class with platform-specific logic and methods
* @param chain the platform name
* @returns the platform context class
* @throws Errors if platform is not found
*/
getPlatform(platformName) {
const platform = this._platforms.get(platformName);
if (!platform)
throw new Error(`Not able to retrieve platform ${platformName}. Did it get registered in the constructor?`);
return platform;
}
/**
* Returns the chain "context", i.e. the class with chain-specific logic and methods
* @param chain the chain name
* @returns the chain context class
* @throws Errors if context is not found
*/
getChain(chain) {
const platform = (0, sdk_base_1.chainToPlatform)(chain);
if (!this._chains.has(chain))
this._chains.set(chain, this.getPlatform(platform).getChain(chain));
return this._chains.get(chain);
}
/**
* Gets the TokenId for a token representation on any chain
* These are the Wormhole wrapped token addresses, not necessarily
* the canonical version of that token
*
* @param chain The chain name to get the wrapped token address
* @param tokenId The Token ID (chain/address) of the original token
* @returns The TokenId on the given chain, null if it does not exist
* @throws Errors if the chain is not supported or the token does not exist
*/
async getWrappedAsset(chain, token) {
const ctx = this.getChain(chain);
const tb = await ctx.getTokenBridge();
return { chain, address: await tb.getWrappedAsset(token) };
}
/**
* Taking the original TokenId for some wrapped token chain
* These are the Wormhole wrapped token addresses, not necessarily
* the canonical version of that token
*
* @param tokenId The Token ID of the token we're looking up the original asset for
* @returns The Original TokenId corresponding to the token id passed,
* @throws Errors if the chain is not supported or the token does not exist
*/
async getOriginalAsset(token) {
const ctx = this.getChain(token.chain);
const tb = await ctx.getTokenBridge();
return await tb.getOriginalAsset(token.address);
}
/**
* Returns the UniversalAddress of the token. This may require fetching on-chain data.
* @param chain The chain to get the UniversalAddress for
* @param token The address to get the UniversalAddress for
* @returns The UniversalAddress of the token
*/
async getTokenUniversalAddress(chain, token) {
const ctx = this.getChain(chain);
const tb = await ctx.getTokenBridge();
return await tb.getTokenUniversalAddress(token);
}
/**
* Returns the native address of the token. This may require fetching on-chain data.
* @param chain The chain to get the native address for
* @param originChain The chain the token is from / native to
* @param token The address to get the native address for
* @returns The native address of the token
*/
async getTokenNativeAddress(chain, originChain, token) {
const ctx = this.getChain(chain);
const tb = await ctx.getTokenBridge();
return await tb.getTokenNativeAddress(originChain, token);
}
/**
* Gets the number of decimals for a token on a given chain
*
* @param chain The chain name or id of the token/representation
* @param token The token address
* @returns The number of decimals
*/
async getDecimals(chain, token) {
const ctx = this.getChain(chain);
return await ctx.getDecimals(token);
}
/**
* Fetches the balance of a given token for a wallet
*
* @param walletAddress The wallet address
* @param tokenId The token ID (its home chain and address on the home chain)
* @param chain The chain name or id
* @returns The token balance of the wormhole asset as a BigNumber
*/
async getBalance(chain, token, walletAddress) {
const ctx = this.getChain(chain);
return ctx.getBalance(walletAddress, token);
}
/**
* Gets the associated token account for chains that require it (only Solana currently).
*
* @param token the TokenId of the token to get the token account for
* @param recipient the address of the primary account that may require a separate token account
* @returns
*/
async getTokenAccount(recipient, token) {
return this.getChain(recipient.chain).getTokenAccount(recipient.address, token.address);
}
/**
* Gets the Raw VAA Bytes from the API or Guardian RPC, finality must be met before the VAA will be available.
*
* @param wormholeMessageId The WormholeMessageId corresponding to the VAA to be fetched
* @param timeout The total amount of time to wait for the VAA to be available
* @returns The VAA bytes if available
* @throws Errors if the VAA is not available after the retries
*/
async getVaaBytes(wormholeMessageId, timeout = config_js_2.DEFAULT_TASK_TIMEOUT) {
return await (0, whscan_api_js_1.getVaaBytesWithRetry)(this.config.api, wormholeMessageId, timeout);
}
/**
* Gets a VAA from the API or Guardian RPC, finality must be met before the VAA will be available.
*
* @param id The WormholeMessageId or Transaction hash corresponding to the VAA to be fetched
* @param decodeAs The VAA type to decode the bytes as
* @param timeout The total amount of time to wait for the VAA to be available
* @returns The VAA if available
* @throws Errors if the VAA is not available after the retries
*/
async getVaa(id, decodeAs, timeout = config_js_2.DEFAULT_TASK_TIMEOUT) {
if (typeof id === "string")
return await (0, whscan_api_js_1.getVaaByTxHashWithRetry)(this.config.api, id, decodeAs, timeout);
return await (0, whscan_api_js_1.getVaaWithRetry)(this.config.api, id, decodeAs, timeout);
}
/**
* Gets if the token bridge transfer VAA has been enqueued by the Governor.
* @param id The WormholeMessageId corresponding to the token bridge transfer VAA to check
* @returns True if the transfer has been enqueued, false otherwise
*/
async getIsVaaEnqueued(id) {
return await (0, whscan_api_js_1.getIsVaaEnqueued)(this.config.api, id);
}
/**
* Gets the CircleAttestation corresponding to the message hash logged in the transfer transaction.
* @param msgHash The keccak256 hash of the message emitted by the circle contract
* @param timeout The total amount of time to wait for the VAA to be available
* @returns The CircleAttestation as a string, if available
* @throws Errors if the CircleAttestation is not available after the retries
*/
async getCircleAttestation(msgHash, timeout = config_js_2.DEFAULT_TASK_TIMEOUT) {
return (0, circle_api_js_1.getCircleAttestationWithRetry)(this.config.circleAPI, msgHash, timeout);
}
/**
* Get the status of a transaction, identified by the chain, emitter address, and sequence number
*
* @param id the message id for the Wormhole Message to get transaction status for or originating Transaction hash
* @returns the TransactionStatus
*/
async getTransactionStatus(id, timeout = config_js_2.DEFAULT_TASK_TIMEOUT) {
let msgid;
// No txid endpoint exists to get the status by txhash yet
if (typeof id === "string") {
const vaa = await (0, whscan_api_js_1.getVaaByTxHashWithRetry)(this.config.api, id, "Uint8Array", timeout);
if (!vaa)
return null;
msgid = { emitter: vaa.emitterAddress, chain: vaa.emitterChain, sequence: vaa.sequence };
}
else {
msgid = id;
}
return await (0, whscan_api_js_1.getTransactionStatusWithRetry)(this.config.api, msgid, timeout);
}
/**
* Get recent transactions for an address
*
* @param address the string formatted address to get transactions for
* @returns the TransactionStatus
*/
async getTransactionsForAddress(address, pageSize = 50, page = 0) {
return (0, whscan_api_js_1.getTxsByAddress)(this.config.api, address, pageSize, page);
}
/**
* Parse an address from its canonical string format to a NativeAddress
*
* @param chain The chain the address is for
* @param address The address in canonical string format
* @returns The address in the NativeAddress format
*/
static parseAddress(chain, address) {
return (0, sdk_definitions_1.toNative)(chain, address);
}
/**
* Return a string in the canonical chain format representing the address
* of a token or account
*
* @param chainAddress The ChainAddress or TokenId to get a string address
* @returns The string address in canonical format for the chain
*/
static canonicalAddress(chainAddress) {
return (0, sdk_definitions_1.canonicalAddress)(chainAddress);
}
/**
* Parse an address from its canonical string format to a NativeAddress
*
* @param chain The chain the address is for
* @param address The native address in canonical string format
* @returns The ChainAddress
*/
static chainAddress(chain, address) {
return { chain, address: Wormhole.parseAddress(chain, address) };
}
/**
* Parse an address from its canonical string format to a NativeAddress
*
* @param chain The chain the address is for
* @param address The native address in canonical string format or the string "native"
* @returns The ChainAddress
*/
static tokenId(chain, address) {
return (0, sdk_definitions_1.isNative)(address) ? (0, sdk_definitions_1.nativeTokenId)(chain) : this.chainAddress(chain, address);
}
/**
* Parses all relevant information from a transaction given the sending tx hash and sending chain
*
* @param chain The sending chain name or context
* @param tx The sending transaction hash
* @returns The parsed WormholeMessageId
*/
static async parseMessageFromTx(chain, txid, timeout = config_js_2.DEFAULT_TASK_TIMEOUT) {
const task = async () => {
try {
const msgs = await chain.parseTransaction(txid);
// possible the node we hit does not have this data yet
// return null to signal retry
if (msgs.length === 0)
return null;
return msgs;
}
catch (e) {
console.error(e);
return null;
}
};
const parsed = await (0, tasks_js_1.retry)(task, chain.config.blockTime, timeout, "WormholeCore:ParseMessageFromTransaction");
if (!parsed)
throw new Error(`No WormholeMessageId found for ${txid}`);
return parsed;
}
}
exports.Wormhole = Wormhole;
//# sourceMappingURL=wormhole.js.map