Wire @mysten/hashi into a real app โ construct the client, derive a deposit address, watch the Bitcoin chain yourself, submit and track a deposit, then burn hBTC back into native BTC.
Hashi ships as `@mysten/hashi` with `@mysten/sui` as a peer dependency. You never construct a Hashi client directly โ you build a normal Sui client and `$extend` it with `hashi()`. Every method then lives under `client.hashi.*`. The Bitcoin network is derived from the Sui client, not passed in: testnet and devnet both map to Bitcoin **signet**. Mainnet is not deployed, so `hashi()` throws there.
Each Sui address maps to exactly one Bitcoin deposit address. `generateDepositAddress({ suiAddress })` derives a **P2TR** taproot address (bech32m, `tb1p...` on signet) from the on-chain MPC master key and the guardian key. It is deterministic โ regenerate it whenever you need it instead of storing it. There is no registration step and no per-user setup transaction.
Before you write a transaction, read. The `view.*` namespace covers everything an integration needs: the governance snapshot, hBTC balances, per-digest status, gas and fee estimates, and a merged transaction history. Balances come back as `bigint` satoshis โ hBTC has **8 decimals**, matching Bitcoin exactly, so one satoshi of hBTC is one satoshi of BTC.
This is the single biggest surprise for integrators: `@mysten/hashi` does **not** scan the Bitcoin chain. `deposit()` demands the funding `txid`, `vout`, and `amountSats` as inputs. Finding them is your job โ mempool.space, an Esplora instance, or your own node. The bundled `bitcoin.*` helpers only work if you construct the client with a `btcRpcUrl` pointing at a verbose Bitcoin Core JSON-RPC node.
With the funding output in hand, `deposit()` records the UTXO on Sui. It runs three preflight checks before it signs anything โ structural validation, a pause check, and the per-UTXO minimum โ then executes. Note the shape of the call: `recipient` is a separate field from `signer`, which means a relayer can pay the Sui gas while hBTC mints to a user who holds no SUI at all.
The Sui `deposit` call only registers the UTXO. Minting takes two more transactions and roughly **70 minutes**: six Bitcoin confirmations at about ten minutes each, then a committee BLS approval carrying over two-thirds of stake, then a 10-minute delay window before `confirm_deposit` becomes callable. `depositStatus(digest).confirmableAtMs` gives you the exact earliest mint time.
`requestWithdrawal` escrows the hBTC on-chain and enqueues a request for the committee. The destination must be a bech32 P2WPKH or bech32m P2TR address whose HRP matches the configured network โ it is decoded client-side, so a wrong-network address throws `InvalidBitcoinAddressError` before you spend gas. The minimum out is the same 30,000 sats as the minimum in.
After the request, the committee drives four more steps. Approval carries a certificate. The commit step selects UTXOs, burns the escrowed hBTC, and locks the inputs. Then MPC signatures are recorded per input, the guardian co-signs at finalize, and confirmation marks the inputs spent. Every status is readable from `view.withdrawalStatus(digest)`.
Two things decide whether a user can back out, and one thing you can never paper over. Cancellation is owner-only, blocked until a 1-hour cooldown elapses, and impossible once the request reaches Processing. And the Bitcoin miner fee is deducted from the withdrawal output in BTC โ no amount of Sui gas sponsorship touches it.