chaingate
Version:
Multi-chain cryptocurrency SDK for TypeScript — unified API for Bitcoin, Ethereum, Litecoin, Dogecoin, Bitcoin Cash, Polygon, Arbitrum, and any EVM-compatible chain. Create wallets, query balances, send transactions, and manage tokens and NFTs across UTXO
136 lines (135 loc) • 5.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EvmRpcTransaction = void 0;
const evmTx_1 = require("../../utils/evmTx");
const evmGasFallback_1 = require("../../utils/evmGasFallback");
const BaseEvmTransaction_1 = require("../EvmConnector/BaseEvmTransaction");
const BroadcastedEvmRpcTransaction_1 = require("./BroadcastedEvmRpcTransaction");
/**
* An unsigned EVM transaction prepared by {@link EvmRpcConnector.transfer}.
*
* @example
* ```ts
* const network = cg.networks.evmRpc({ rpcUrl: '...', chainId: 56, name: 'BSC', symbol: 'BNB' });
* const conn = cg.connect(network, wallet);
* const tx = await conn.transfer(network.amount('0.1'), '0xRecipient...');
*
* // Inspect the current fee
* const fee = tx.currentFee();
*
* // Override with a custom fee and optional gas limit
* tx.setFee({ maxFeePerGas: 5_000_000_000n, maxPriorityFeePerGas: 1_000_000_000n, gasLimit: 50_000n });
*
* // Sign and broadcast
* const broadcasted = await tx.signAndBroadcast();
* ```
*/
class EvmRpcTransaction extends BaseEvmTransaction_1.BaseEvmTransaction {
/** @internal */
constructor(params) {
super({
fromAddress: params.fromAddress,
toAddress: params.toAddress,
valueWei: params.valueWei,
data: params.data,
nonce: params.nonce,
gasLimit: params.gasLimit,
chainId: params.chainId,
balanceWei: params.balanceWei,
getPrivateKey: params.getPrivateKey,
initialFee: {
maxFeePerGas: params.feeData.maxFeePerGas ?? params.feeData.gasPrice,
maxPriorityFeePerGas: params.feeData.maxPriorityFeePerGas ?? 0n,
},
});
this.explorer = params.explorer;
this.supportsEip1559 = params.feeData.supportsEip1559;
}
/**
* Returns the current fee parameters that will be used for signing.
*
* For EIP-1559 chains both `maxFeePerGas` and `maxPriorityFeePerGas` are
* meaningful. For legacy chains `maxFeePerGas` represents the gas price and
* `maxPriorityFeePerGas` is `0n`.
*/
currentFee() {
return { ...this._currentFee };
}
/**
* Overrides the fee for this transaction.
*
* @throws {@link TransactionAlreadySentError} if the transaction has already been sent.
*/
setFee(fee) {
this.applyFee(fee);
}
signTransaction(privateKey, params) {
if (this.supportsEip1559) {
return (0, evmTx_1.signEip1559Transaction)(params, privateKey);
}
return (0, evmTx_1.signLegacyTransaction)({
chainId: params.chainId,
nonce: params.nonce,
gasPrice: params.maxFeePerGas,
gasLimit: params.gasLimit,
to: params.to,
value: params.value,
data: params.data,
}, privateKey);
}
async broadcast(signedRaw) {
return this.explorer.sendRawTransaction(signedRaw);
}
recordNonceUsed() {
this.explorer.nonceCache.recordUsed(this.explorer.chainId, this.fromAddress, this.nonce);
}
buildBroadcasted(transactionId) {
return new BroadcastedEvmRpcTransaction_1.BroadcastedEvmRpcTransaction(transactionId, this.explorer);
}
/**
* Fetches all required on-chain data (nonce, gas, fees, balance) and
* constructs the transaction.
*
* @internal — used by {@link EvmRpcConnector.transfer}.
*/
static async create(params) {
const { explorer, fromAddress, toAddress, valueWei, data = '0x', getPrivateKey } = params;
// Fetch the nonce first so we can pass it to estimateGas (the nonce can
// affect the estimate for contracts whose execution depends on account
// state). Take the max with the locally cached nonce so consecutive sends
// from the same address don't reuse a nonce when the network hasn't yet
// observed the previous broadcast.
const networkNonce = await explorer.getNonce(fromAddress);
const cachedNonce = explorer.nonceCache.get(explorer.chainId, fromAddress);
const nonce = cachedNonce !== undefined && cachedNonce > networkNonce ? cachedNonce : networkNonce;
const estimateParams = {
from: fromAddress,
to: toAddress,
value: valueWei,
nonce,
};
if (data !== '0x') {
estimateParams.data = data;
}
const [gasEstimate, feeData, balance] = await Promise.all([
explorer.estimateGas(estimateParams).catch(() => null),
explorer.getFeeData(),
explorer.getBalance(fromAddress),
]);
const gasLimit = gasEstimate ?? (0, evmGasFallback_1.fallbackGasFromCalldata)(data);
return new EvmRpcTransaction({
explorer,
fromAddress,
toAddress,
valueWei,
data,
nonce,
gasLimit,
chainId: BigInt(explorer.chainId),
balanceWei: balance,
feeData,
getPrivateKey,
});
}
}
exports.EvmRpcTransaction = EvmRpcTransaction;