polyquest-wormhole
v2.0.2
Published
```bash npm i [email protected] ```
Downloads
108
Readme
PolyQuest Wormhole SDK Usage Guide
1. Install Packages
npm i [email protected]
"Latest version": "2.0.2",
2. Usage
import { Chain } from "@wormhole-foundation/sdk";
import { ethers } from "ethers";
import { BaseSignerWalletAdapter } from "@solana/wallet-adapter-base";
import { Network } from "@wormhole-foundation/sdk";
The AutomationBridge
class requires two parameters to be instantiated: signer
and network
. These parameters allow the class to interact with the blockchain and configure itself according to the provided environment (network).
- Current
signer
type:ethers.JsonRpcSigner | BaseSignerWalletAdapter
network
type:Network
Examples:
///EVM
import { ethers } from "ethers";
const getMetaMaskProvider = async () => {
if (window.ethereum && window.ethereum.providers) {
const providers = window.ethereum.providers;
const metaMaskProvider = providers.find(
(provider: any) => provider.isMetaMask
);
return metaMaskProvider;
}
if (window.ethereum && window.ethereum.isMetaMask) {
return window.ethereum;
}
return null;
};
const connectWallet = async () => {
const metaMaskProvider = await getMetaMaskProvider();
if (metaMaskProvider) {
try {
const provider = new ethers.BrowserProvider(metaMaskProvider);
const accounts = await metaMaskProvider.request({
method: "eth_requestAccounts",
});
await metaMaskProvider.request({
method: "wallet_addEthereumChain",
params: [
{
chainId: "0xA869",
chainName: "Avalanche Fuji Testnet",
nativeCurrency: {
name: "Avalanche",
symbol: "AVAX",
decimals: 18,
},
rpcUrls: ["https://api.avax-test.network/ext/bc/C/rpc"],
blockExplorerUrls: ["https://testnet.snowtrace.io/"],
},
],
});
} catch (err) {}
} else {
}
};
const metaMaskProvider = await getMetaMaskProvider();
await connectWallet();
const provider = new ethers.BrowserProvider(metaMaskProvider);
const signer = await provider.getSigner();
///SOLANA
import { AutomationBridge } from "@/polyquest-wormhole";
import { clusterApiUrl, Connection } from "@solana/web3.js";
import {
// BitgetWalletAdapter,
PhantomWalletAdapter,
} from "@solana/wallet-adapter-wallets";
try {
console.log("start...");
// // Step 3: Tạo provider cho Solana
const connection = new Connection(clusterApiUrl("devnet"));
const phantomWallet = new PhantomWalletAdapter();
try {
if (!phantomWallet.connected) {
await phantomWallet.connect();
}
} catch (error) {
console.error("Error connecting wallet:", error);
}
const bridge = new AutomationBridge(phantomWallet, "Testnet");
} catch (e) {}
There are two main functions: send()
and getPreviewTransaction()
.
send
: Used to automatically wrap tokens.getPreviewTransaction
: Used to preview the transaction information.
1. The send
Function
Purpose:
The send
function performs a token transaction from the source chain to the destination chain. It checks the validity of the token, balance, supported routes, and performs the transaction via the optimal route.
Input Parameters (SendProps
):
sourceChain
: The source blockchain where the token is located:type Chain
.sourceAddress
: The address on the source chain where the token is held:wallet address
.sourceTokenAddress
: The token address on the source chain:address | native
.destChain
: The destination blockchain where the token will be sent:type Chain
.destAddress
: The address on the destination chain to receive the token:wallet address
.amount
: The amount of tokens to be transferred:string
.
Return Value (SendReturn
):
sourceChain
: The source chain.sourceAddress
: The source address.sourceTokenAddress
: The source token address.sourceToken
: The source token symbol.destChain
: The destination chain.destAddress
: The destination address.destTokenAddress
: The destination token address.destToken
: The destination token symbol.amount
: The number of tokens sent.destAmount
: The actual amount received on the destination chain (if successful).transactionId
: The transaction ID.relayerFee
: The relayer fee (if applicable).minAmount
: The minimum amount required for the transaction.error
: Error message (if any).eta
: The estimated time of arrival (ETA) for the transaction.time
: The estimated time to complete the transaction as a string.
Steps:
Steps:
Preview the transaction: Before executing the transaction, call the
getPreviewTransaction()
function to gather preliminary information about the transaction, including the available routes and the estimated amount of tokens that will be received on the destination chain.Execute the transaction: Once the best route is determined from the preview, initiate the token transfer via the SDK. The
send()
method of the SDK will use the optimal route and handle all the necessary steps to transfer the tokens.- The method sends the transaction with parameters including the source token configuration, source/destination chains, source/destination addresses, and the amount of tokens.
Retrieve the transaction ID: After the transaction is sent, extract the transaction ID from the receipt. The transaction ID is used to track the status of the transfer and confirm its success.
Calculate relayer fee: If there are relayer fees involved, retrieve and format the relayer fee for the transaction. This fee is required by the relayer service to facilitate the cross-chain transfer.
Return the transaction result: Return the full transaction result, including the transaction ID, the actual amount received on the destination chain, the relayer fee, and the estimated time for the transaction completion.
2. The getPreviewTransaction
Function
Purpose:
The getPreviewTransaction
function provides a preview of a token transaction from the source chain to the destination chain. It estimates the token amount to be received on the destination chain without executing the transaction. This function allows users to check the transfer details, including estimated fees and the best route, before committing to the transaction.
Input Parameters (SendProps
):
- Same as the
send
function.
Return Value (SendReturn
):
Return Value:
The function returns an object containing three main parameters:
data (
SendReturn
): Information about the transaction including the estimated amount to be received, the relayer fee, and other details.sourceChain
: The source blockchain.sourceAddress
: The source wallet address.sourceTokenAddress
: The token address on the source blockchain.destChain
: The destination blockchain.destAddress
: The destination wallet address.destTokenAddress
: The token address on the destination blockchain.amount
: The amount of tokens to be transferred.destAmount
: The estimated amount to be received on the destination blockchain.relayerFee
: The fee charged by the relayer service (if applicable).minAmount
: The minimum amount required for the transaction to proceed.eta
: The estimated time of arrival for the transaction.time
: The estimated time to complete the transaction as a string.error
: Any error messages if the transaction is not supported or an issue occurs during the preview process.
routesQuotes: A record of the quotes for each supported route. Each entry in the record contains details about a specific route and whether it is successful or not. This helps in determining the best route for the transaction.
- The record includes the route name as the key, and the value is the quote result (
QuoteResult
) for that route.
- The record includes the route name as the key, and the value is the quote result (
bestRoute: The name of the best route that offers the most favorable conditions for the token transfer. This route is selected based on the highest amount of tokens that can be received on the destination chain, and other factors like relayer fees and estimated time of arrival.
Steps:
Validate source and destination chains: Ensure that both the source and destination chains are supported by the bridge. If either chain is not supported, return an error.
Fetch token configurations: Validate the source token by fetching its configuration from the token list. If the token is unsupported, return an error.
Fetch supported destination tokens: Get the list of supported tokens on the destination chain that can be swapped with the source token. If no valid options are available, return an error.
Check token balance: Fetch the balance of the source token at the source address to ensure the user has sufficient tokens to proceed with the transaction. If the balance is insufficient, return an error.
Check available routes: Fetch all supported routes for transferring tokens between the source and destination chains. Filter routes based on whether they are supported and check for any specific route preferences such as "Automatic".
Get quotes for the routes: For the supported routes, retrieve quotes that estimate the destination amount, relayer fees, and other transaction details. Use this data to determine the best route by comparing the destination amounts.
Determine the best route: Select the route that offers the highest destination amount and favorable terms (fees and time). This route will be considered the optimal one for the transaction.
Estimate relayer fees: If the best route involves relayer fees, calculate and format the fee based on the token configuration.
Return the transaction preview: Return the estimated destination amount, best route, relayer fee (if any), and the time estimate for the transaction. If applicable, include errors such as unsupported tokens, insufficient balance, or no available routes.
4. Example
1. Solana to Avalanche
import { AutomationBridge } from "@/polyquest-wormhole";
import { clusterApiUrl, Connection } from "@solana/web3.js";
import {
// BitgetWalletAdapter,
PhantomWalletAdapter,
} from "@solana/wallet-adapter-wallets";
try {
console.log("start...");
// // Step 3: Tạo provider cho Solana
const connection = new Connection(clusterApiUrl("devnet"));
const phantomWallet = new PhantomWalletAdapter();
try {
if (!phantomWallet.connected) {
await phantomWallet.connect();
}
} catch (error) {
console.error("Error connecting wallet:", error);
}
const bridge = new AutomationBridge(phantomWallet, "Testnet");
const result = await bridge.send({
sourceChain: "Solana",
sourceAddress: "8H2W7doVRnmKbPPL6AKv9bDP6cdr79CzVoM6o8ViEdvP",
sourceTokenAddress: "native",
destChain: "Avalanche",
destAddress: "0xEB055a6E41b7edC92951aCE0FcBFB6aD460E0AAA",
amount: "1.9",
});
console.log("Transaction result:", result);
} catch (error) {
console.error("Transaction failed:", error);
}
Response:
{
"sourceChain": "Solana",
"sourceAddress": "8H2W7doVRnmKbPPL6AKv9bDP6cdr79CzVoM6o8ViEdvP",
"sourceTokenAddress": "native",
"sourceToken": "SOL",
"destChain": "Avalanche",
"destAddress": "0xEB055a6E41b7edC92951aCE0FcBFB6aD460E0AAA",
"destTokenAddress": "So11111111111111111111111111111111111111112",
"destToken": "WSOL",
"amount": "1.9",
"destAmount": "1.886314",
"transactionId": "2SWWt9gMeqs9cUAR7q9EHGWJWhrJa9eyu7CszhaX2opYz178Lt7A9vmVqgkQV82ofgJ3LaQgaDYHi4uWbVjJNKuZ",
"relayerFee": {
"fee": 0.013685733,
"tokenKey": "WSOL"
},
"eta": 12805,
"time": "~13 sec"
}
2. Avalanche to Solana
import { ethers } from "ethers";
const getMetaMaskProvider = async () => {
if (window.ethereum && window.ethereum.providers) {
const providers = window.ethereum.providers;
const metaMaskProvider = providers.find(
(provider: any) => provider.isMetaMask
);
return metaMaskProvider;
}
if (window.ethereum && window.ethereum.isMetaMask) {
return window.ethereum;
}
return null;
};
const connectWallet = async () => {
const metaMaskProvider = await getMetaMaskProvider();
if (metaMaskProvider) {
try {
const provider = new ethers.BrowserProvider(metaMaskProvider);
const accounts = await metaMaskProvider.request({
method: "eth_requestAccounts",
});
await metaMaskProvider.request({
method: "wallet_addEthereumChain",
params: [
{
chainId: "0xA869",
chainName: "Avalanche Fuji Testnet",
nativeCurrency: {
name: "Avalanche",
symbol: "AVAX",
decimals: 18,
},
rpcUrls: ["https://api.avax-test.network/ext/bc/C/rpc"],
blockExplorerUrls: ["https://testnet.snowtrace.io/"],
},
],
});
} catch (err) {}
} else {
}
};
const metaMaskProvider = await getMetaMaskProvider();
await connectWallet();
const provider = new ethers.BrowserProvider(metaMaskProvider);
const signer = await provider.getSigner();
const bridge = new AutomationBridge(signer, "Testnet");
try {
console.log("Start...");
const result = await bridge.send({
sourceChain: "Avalanche",
sourceAddress: "0xEB055a6E41b7edC92951aCE0FcBFB6aD460E0AAA",
sourceTokenAddress: "0xb10563644a6AB8948ee6d7f5b0a1fb15AaEa1E03",
destChain: "Solana",
destAddress: "8H2W7doVRnmKbPPL6AKv9bDP6cdr79CzVoM6o8ViEdvP",
amount: "2",
});
console.log(result);
} catch (error) {
console.error("Transaction failed:", error);
}
Response:
{
"sourceChain": "Avalanche",
"sourceAddress": "0xeb055a6e41b7edc92951ace0fcbfb6ad460e0aaa",
"sourceTokenAddress": "0xb10563644a6AB8948ee6d7f5b0a1fb15AaEa1E03",
"sourceToken": "WSOL",
"destChain": "Solana",
"destAddress": "8H2W7doVRnmKbPPL6AKv9bDP6cdr79CzVoM6o8ViEdvP",
"destTokenAddress": "So11111111111111111111111111111111111111112",
"destToken": "WSOL",
"amount": "2",
"destAmount": "1.992616",
"transactionId": "0x733a776e0efcf6b161c248116ff0781d68a9bb6d2e65044ccb240ec98079d32c",
"relayerFee": {
"fee": 0.007384084,
"tokenKey": "WSOL"
},
"eta": 5,
"time": "~1 sec"
}
3. Celo to Solana
import { ethers } from "ethers";
const getMetaMaskProvider = async () => {
if (window.ethereum && window.ethereum.providers) {
const providers = window.ethereum.providers;
const metaMaskProvider = providers.find(
(provider: any) => provider.isMetaMask
);
return metaMaskProvider;
}
if (window.ethereum && window.ethereum.isMetaMask) {
return window.ethereum;
}
return null;
};
const connectWallet = async () => {
const metaMaskProvider = await getMetaMaskProvider();
if (metaMaskProvider) {
try {
const provider = new ethers.BrowserProvider(metaMaskProvider);
const accounts = await metaMaskProvider.request({
method: "eth_requestAccounts",
});
await metaMaskProvider.request({
method: "wallet_addEthereumChain",
params: [
{
chainId: "0xAef3",
chainName: "Celo Alfajores Testnet",
nativeCurrency: {
name: "CELO",
symbol: "A-CELO",
decimals: 18,
},
rpcUrls: ["https://alfajores-forno.celo-testnet.org"],
blockExplorerUrls: [
"https://alfajores-blockscout.celo-testnet.org/",
],
},
],
});
} catch (err) {}
} else {
}
};
const metaMaskProvider = await getMetaMaskProvider();
await connectWallet();
const provider = new ethers.BrowserProvider(metaMaskProvider);
const signer = await provider.getSigner();
const bridge = new AutomationBridge(signer, "Testnet");
try {
console.log("Start...");
const result = await bridge.send({
sourceChain: "Celo",
sourceAddress: "0xEB055a6E41b7edC92951aCE0FcBFB6aD460E0AAA",
sourceTokenAddress: "native",
destChain: "Solana",
destAddress: "8H2W7doVRnmKbPPL6AKv9bDP6cdr79CzVoM6o8ViEdvP",
amount: "2.4",
});
console.log(result);
} catch (error) {
console.error("Transaction failed:", error);
}
Response:
{
"sourceChain": "Celo",
"sourceAddress": "0xeb055a6e41b7edc92951ace0fcbfb6ad460e0aaa",
"sourceTokenAddress": "native",
"sourceToken": "CELO",
"destChain": "Solana",
"destAddress": "8H2W7doVRnmKbPPL6AKv9bDP6cdr79CzVoM6o8ViEdvP",
"destTokenAddress": "0xF194afDf50B03e69Bd7D057c1Aa9e10c9954E4C9",
"destToken": "CELO",
"amount": "2.4",
"destAmount": "0.441123",
"transactionId": "0x65a7acda49f0dfa6494c0de93b6055a31a1486f0ebb698063353562e0b095675",
"relayerFee": {
"fee": 1.9588770204665626,
"tokenKey": "CELO"
},
"eta": 5005,
"time": "~6 sec"
}