Skip to main content

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.

Transaction fees

Every blockchain transaction incurs a fee. Always ensure you have enough funds to cover both the transaction amount and its fee.

Encrypted wallets

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({ apiKey: 'your-api-key' })

// 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()

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)

When you create a transfer, ChainGate automatically fetches recommended fee levels. Use tx.recommendedFees() to inspect them:

Available fee tiers

TierDescription
lowCheapest option, but slower confirmation
normalA balanced option for typical transactions
highHigher fee for faster confirmation
maximumHighest fee for the fastest possible confirmation

Each tier includes:

  • enoughFunds (boolean) — Whether the wallet can cover the amount + fee.
  • 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.
  • maxPriorityFeePerGas (bigint) — Priority fee (tip) per gas in wei.

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')
}

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({ apiKey: 'your-api-key' })
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

Key points

  • Uniform API: transfer(), recommendedFees(), setFee(), signAndBroadcast() work for all networks.
  • 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) to setFee(). Each tier includes enoughFunds and estimatedConfirmationSecs.
  • 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.