Transfer funds
ChainGate lets you transfer funds from your wallet to any valid recipient address across supported blockchains. Whether you're using a UTXO-based chain (like Bitcoin, Litecoin, or Dogecoin) or an EVM-based chain (like Ethereum), the API provides a consistent flow: create a transfer, review fees, and sign + broadcast.
Every blockchain transaction incurs a fee. Always ensure you have enough funds to cover both the transaction amount and its fee. ChainGate estimates fees for you via recommendedFees() — gas prices on EVM chains, and sat/vB rates on UTXO chains.
If your wallet is encrypted, the askForPassword callback will be triggered when signing the transaction during signAndBroadcast().
Basic transaction flow
import { newWallet, ChainGate } from 'chaingate'
const { wallet } = newWallet()
const cg = new ChainGate()
// 1. Connect wallet to a network
const bitcoin = cg.connect(cg.networks.bitcoin, wallet)
// 2. Create an amount
const amount = cg.networks.bitcoin.amount('0.001')
// 3. Create a transfer (fetches fees, balance, and UTXOs automatically)
const tx = await bitcoin.transfer(amount, 'bc1q...')
// 4. Review recommended fees
const fees = tx.recommendedFees()
console.log('Normal fee enough funds?', fees.normal.enoughFunds)
// 5. Set fee tier and sign + broadcast
tx.setFee(fees.normal)
const broadcasted = await tx.signAndBroadcast()
console.log('TX ID:', broadcasted.transactionId)
// 6. Wait for confirmation (optional)
const cancel = broadcasted.onConfirmed((details) => {
console.log('Confirmed in block', details.blockHeight)
})
// Stop waiting at any time:
// cancel()
The flow is identical across chains. Swap cg.networks.bitcoin for cg.networks.litecoin, cg.networks.dogecoin, cg.networks.bitcoincash, or cg.networks.ethereum — every method (amount(), transfer(), recommendedFees(), signAndBroadcast()) has the same signature everywhere.
Sending an amount specified in fiat
If you prefer to send the fiat equivalent of an amount (e.g., "$25 worth of BTC"):
// Convert 25 USD to BTC at current rates
const amount = await cg.networks.bitcoin.amountFromCurrency('usd', 25)
const tx = await bitcoin.transfer(amount, 'bc1q...')
const fees = tx.recommendedFees()
tx.setFee(fees.normal)
const broadcasted = await tx.signAndBroadcast()
Supported fiat currencies
amountFromCurrency() accepts more than 120 fiat currencies identified by their ISO 4217 3-letter codes:
usd, eur, gbp, jpy, cny, aud, cad, chf, inr, brl, mxn, and many more.
// Send the equivalent of 100 EUR in ETH
const amount = await cg.networks.ethereum.amountFromCurrency('eur', 100)
Recommended fees
When you create a transfer, ChainGate automatically fetches recommended fee levels. Use tx.recommendedFees() to inspect them:
Available fee tiers
| Tier | Description |
|---|---|
low | Cheapest option, but slower confirmation |
normal | A balanced option for typical transactions |
high | Higher fee for faster confirmation |
maximum | Highest fee for the fastest possible confirmation |
Each tier includes:
enoughFunds(boolean) — Whether the wallet can cover the amount + fee.missingFunds(bigint | null, optional) — WhenenoughFundsisfalse, the exact amount of additional funds needed for the transaction to be broadcastable at this fee. Reported in satoshis on UTXO chains and in wei on EVM chains. May benullon UTXO when the gap cannot be estimated.estimatedConfirmationSecs(number) — Estimated seconds until confirmation.
UTXO-specific properties
feePerKbSat(bigint) — Fee rate in satoshis per kilobyte.estimatedFeeSat(bigint | null) — Estimated total fee in satoshis.
EVM-specific properties
maxFeePerGas(bigint) — Maximum fee per gas in wei (divide by1_000_000_000nfor gwei).maxPriorityFeePerGas(bigint) — Priority fee (tip) per gas in wei.gasEstimationFailed(boolean, optional) —truewhen on-chain gas estimation failed (typically because the wallet can't cover the simulated call) and a built-in heuristic has been used instead. TheenoughFundsandmissingFundsvalues still reflect a realistic estimate.
Setting a fee tier
Pass a tier object from recommendedFees() to setFee():
const fees = tx.recommendedFees()
tx.setFee(fees.high) // Use the "high" priority tier
Custom fees
Instead of using a recommended tier, you can set custom fee parameters:
UTXO custom fee
tx.setFee({ feePerKbSat: 15000n })
EVM custom fee
tx.setFee({
maxFeePerGas: 30_000_000_000n, // 30 gwei
maxPriorityFeePerGas: 2_000_000_000n, // 2 gwei
gasLimit: 50_000n // optional gas limit override
})
Checking funds
Always verify you have enough funds before broadcasting:
if (tx.enoughFunds()) {
const broadcasted = await tx.signAndBroadcast()
} else {
console.log('Insufficient funds')
}
How much is missing?
When a tier doesn't have enough funds, missingFunds tells you exactly how much more you need to deposit (or how much to subtract from amount) for the transaction to go through at that fee:
const fees = tx.recommendedFees()
if (!fees.normal.enoughFunds && fees.normal.missingFunds != null) {
// UTXO: missingFunds is in satoshis
// EVM: missingFunds is in wei
console.log('Need additional units:', fees.normal.missingFunds.toString())
}
This is handy for showing a precise "Add X to send this transaction" message in your UI rather than a generic "insufficient funds" warning.
Waiting for confirmation
After broadcasting, you can wait for the transaction to be confirmed on-chain:
const broadcasted = await tx.signAndBroadcast()
const cancel = broadcasted.onConfirmed((details) => {
console.log('Confirmed in block', details.blockHeight)
console.log('TX ID:', details.transactionId)
})
// Cancel polling at any time:
cancel()
EVM Ethereum example (full)
const cg = new ChainGate()
const eth = cg.connect(cg.networks.ethereum, wallet)
const amount = cg.networks.ethereum.amount('0.05')
const tx = await eth.transfer(amount, '0xRecipient...')
const fees = tx.recommendedFees()
console.log('Normal fee:', fees.normal.maxFeePerGas, 'wei')
tx.setFee(fees.high)
const broadcasted = await tx.signAndBroadcast()
console.log('TX ID:', broadcasted.transactionId)
Estimated transaction size
For UTXO transactions, you can check the estimated size (in virtual bytes) at the current fee rate:
const size = tx.estimatedSizeBytes()
console.log('Estimated size:', size, 'vbytes') // null if not enough funds
Chaining EVM transactions
You can broadcast several EVM transactions back-to-back without worrying about colliding on the same nonce — even when the network hasn't yet reflected the previous send.
ChainGate keeps track of the next nonce per address and chain, so the next transfer() call picks up where the previous one left off:
const eth = cg.connect(cg.networks.ethereum, wallet)
const tx1 = await eth.transfer(cg.networks.ethereum.amount('0.01'), '0xRecipientA...')
await tx1.signAndBroadcast()
// Sent right away — picks the next nonce automatically
const tx2 = await eth.transfer(cg.networks.ethereum.amount('0.02'), '0xRecipientB...')
await tx2.signAndBroadcast()
Same behaviour on EVM RPC connectors (Polygon, BNB Smart Chain, custom networks). If you ever need the value yourself, every EVM explorer exposes getNonce(address) that returns the next nonce to use:
const nonce = await cg.explore(cg.networks.ethereum).getNonce('0xYourAddress...')
Key points
- Uniform API:
transfer(),recommendedFees(),setFee(),signAndBroadcast()work for all networks — Bitcoin, Litecoin, Dogecoin, Bitcoin Cash, Ethereum, and any custom EVM RPC network. - Create amounts: Use
network.amount()for crypto amounts,network.amountFromCurrency()for fiat amounts. - Fee tiers: Pass a tier object from
recommendedFees()(e.g.fees.normal,fees.high) tosetFee(). Each tier includesenoughFundsandestimatedConfirmationSecs. - Custom fees: Pass an object with manual fee parameters to
setFee()for UTXO ({ feePerKbSat }) or EVM ({ maxFeePerGas, maxPriorityFeePerGas, gasLimit? }). - Transaction size: Use
estimatedSizeBytes()on UTXO transactions to get the virtual size at the current fee rate. - Confirmation tracking: Use
broadcasted.onConfirmed()to be notified when the transaction is mined. - Signing happens at broadcast:
signAndBroadcast()handles signing internally. Encrypted wallets prompt for the password at this point.