Keelchain
Docs / Deposits and withdrawals

Funding an account

Keelchain accounts hold assets from other chains through vaults: a threshold-signed key per chain whose child addresses are handed out to accounts. You send coins to your child address on the external chain, the observers watch it, and after that chain's confirmation depth the amount is credited to your Keelchain account as a vault asset (BTC.BTC, TRON.USDT, TRON.TRX, ETH.ETH, ETH.USDT). KEEL and KUSD never leave the chain: KUSD is minted only against vaulted USDT, KEEL is transferred.

On the public testnet the external chains are Bitcoin signet and Tron Nile. Mainnet coins sent to a testnet address are lost.

1. Get your deposit address

The chain assigns the address; it is not derived in the wallet. Three ways:

Keel Wallet. Open the wallet, card Receive, press Bitcoin or Tron. The wallet asks the chain for an address the first time (a free signed action, no site involved) and shows it with a copy button from then on.

CLI.

keel --rpc https://testnet.keelchain.com/rpc --chain-id 3 send --secret <secret> deposit-address BTC
keel --rpc https://testnet.keelchain.com/rpc --chain-id 3 deposit-address BTC <your address>

SDK.

const rpc = new RpcClient("https://testnet.keelchain.com/rpc");
const { index, address } = await rpc.requestDepositAddress(key, "BTC", 3);

Under the hood: the account signs RequestDepositAddress { chain }; the chain records the next free index for that account and chain; anyone can read the address at /v1/vaults/BTC/addresses?owner=<account> or /v1/vaults/BTC/addresses/<index>. One index per account per chain; asking again returns the same one. A custodial client's users keep their index across the client's vault rotations; only the address derived from it changes (models.md, "Rotating to a fresh pool").

2. Send coins to it

Any amount works. Deposits above large_deposit_usd_micro (50,000 USD equivalent) are held for large_deposit_delay_blocks before they are usable.

3. See it land

The chain learns about a deposit only when an observer reports it at the required depth, so for the first minutes the chain has nothing to show. The wallet and the explorer fill that gap by looking the deposit address up on the external network's public API (mempool.space for Bitcoin, TronGrid for Tron) straight from the browser, and merge what they see with the chain's own rows. Each incoming transaction moves through these stages:

Stage Meaning
seen in the external network's mempool, no confirmation yet
confirming confirmed, below the required depth (1 of 2 confirmations)
observing deep enough; the observers' quorum is being collected
held credited, but delayed as a large deposit until a release height
credited in your balance
rejected the observers disagreed; nothing credited

Coins can also stay in your wallet, under your own key, and be moved into Keel when you want to trade: wallet.md §5b.

If nothing appears after a few minutes, check the network: the testnet addresses live on Bitcoin signet and Tron Nile. Coins sent on testnet3, testnet4, Shasta or a mainnet to the same address string are on a different ledger, the observers never see them, and they cannot be credited.

What has to be true on the chain side

Withdrawing

Withdraw { asset, to, amount } (wallet: Send, CLI: keel send withdraw BTC.BTC <address> <sats>) queues a payout; the observers batch, sign with the vault key and broadcast. The flat withdrawal fee comes from withdraw_flat_fee_usd_micro.