UNPKG

@avalanche-sdk/client

Version:

A TypeScript SDK for interacting with the Avalanche network through JSON-RPC APIs. This SDK provides a comprehensive set of tools to interact with all Avalanche chains (P-Chain, X-Chain, C-Chain) and various APIs, including wallet functionality for transa

160 lines (143 loc) 5.06 kB
import { pvm, utils } from "@avalabs/avalanchejs"; import { isAddress } from "viem"; import { AvalancheWalletCoreClient } from "../../../clients/createAvalancheWalletCoreClient.js"; import { C_CHAIN_ALIAS, P_CHAIN_ALIAS } from "../../consts.js"; import { getBalance } from "../../pChain/getBalance.js"; import { getFeeState } from "../../pChain/getFeeState.js"; import { baseFee as getBaseFee } from "../../public/baseFee.js"; import { prepareImportTxn as prepareImportTxnCChain } from "../cChain/prepareImportTxn.js"; import { getContextFromURI } from "../getContextFromURI.js"; import { prepareExportTxn as prepareExportTxnPChain } from "../pChain/prepareExportTxn.js"; import { sendXPTransaction } from "../sendXPTransaction.js"; import { SendParameters, SendReturnType } from "../types/send.js"; import { avaxToNanoAvax, getBech32AddressFromAccountOrClient, nanoAvaxToAvax, } from "../utils.js"; import { waitForTxn } from "../waitForTxn.js"; export type TransferPtoCChainParameters = SendParameters; export type TransferPtoCChainReturnType = SendReturnType; export async function transferPtoCChain( client: AvalancheWalletCoreClient, params: TransferPtoCChainParameters ): Promise<TransferPtoCChainReturnType> { const context = params.context || (await getContextFromURI(client)); const isTestnet = context.networkID === 5; // Note: CChain and PChain have different bech32 addresses for seedless accounts on core // The value in both can be same for seed accounts // Get the bech32 C chain address let currentAccountCChainBech32Address = params.from; if (!currentAccountCChainBech32Address) { currentAccountCChainBech32Address = await getBech32AddressFromAccountOrClient( client, params.account, C_CHAIN_ALIAS, isTestnet ? "fuji" : "avax" ); } // Get the bech32 P chain address let currentAccountPChainBech32Address = params.from; if (!currentAccountPChainBech32Address) { currentAccountPChainBech32Address = await getBech32AddressFromAccountOrClient( client, params.account, P_CHAIN_ALIAS, isTestnet ? "fuji" : "avax" ); } if (!isAddress(params.to)) { throw new Error("Invalid `to` address"); } // Prepare the P chain export txn and C chain import txn and get the fee for each const [pChainExportTxnRequest, pChainFeeState, baseFee, balance] = await Promise.all([ await prepareExportTxnPChain(client, { exportedOutputs: [ { addresses: [currentAccountCChainBech32Address], amount: params.amount, }, ], destinationChain: "C", context, }), getFeeState(client.pChainClient), getBaseFee(client), nanoAvaxToAvax( ( await getBalance(client.pChainClient, { addresses: [currentAccountPChainBech32Address], }) ).balance ), ]); // Check if user has enough balance if (Number(balance) < params.amount) { throw new Error( `Insufficient balance: ${params.amount} AVAX is required, but only ${balance} AVAX is available` ); } // Calculate the fee for the P chain import txn const pChainExportTxnFee = pvm.calculateFee( pChainExportTxnRequest.tx.getTx(), context.platformFeeConfig.weights, pChainFeeState.price ); if (pChainExportTxnFee > avaxToNanoAvax(params.amount)) { throw new Error( `Transfer amount is too low: ${nanoAvaxToAvax( pChainExportTxnFee )} AVAX Fee is required for P chain export txn, but only ${ params.amount } AVAX is being transferred, try sending a higher amount` ); } // Send the P chain export txn const sendPChainExportTxn = await sendXPTransaction( client, pChainExportTxnRequest ); await waitForTxn(client, sendPChainExportTxn); // Prepare the C chain import txn const cChainImportTxnRequest = await prepareImportTxnCChain(client, { fromAddresses: [currentAccountCChainBech32Address], sourceChain: "P", toAddress: params.to, context, }); // Calculate the fee for the C chain import txn const cChainImportTxnFee = BigInt(baseFee) * BigInt(utils.costCorethTx(cChainImportTxnRequest.tx)); // Calculate the total fee const totalFee = pChainExportTxnFee + cChainImportTxnFee; if (totalFee > avaxToNanoAvax(params.amount)) { throw new Error( `Transfer amount is too low: ${nanoAvaxToAvax( cChainImportTxnFee )} AVAX Fee is required for C chain import txn, try sending a higher amount. P chain export txn hash: ${sendPChainExportTxn.txHash}` ); } // Send the C chain import txn const sendCChainImportTxn = await sendXPTransaction( client, cChainImportTxnRequest ); await waitForTxn(client, sendCChainImportTxn); return { txHashes: [ { txHash: sendPChainExportTxn.txHash, chainAlias: "P", }, { txHash: sendCChainImportTxn.txHash, chainAlias: "C", }, ], }; }