Reserve Accounts: Time-Delayed, Recoverable Vaults
Esta página aún no está disponible en tu idioma.
A reserve account (also called a vault) is an xRBX… address whose outgoing sends wait behind an unlock time before they settle. Until then the owner can call a send back, and if the vault key is ever compromised, a separate recovery key can sweep everything in the vault to a safe address. This guide covers creating, using, and recovering a reserve account with the VerifiedX Web SDK.
Prerequisites
Section titled “Prerequisites”vfx-web-sdk3.4.0 or later- A funded ordinary VFX address to fund the vault from (5 VFX covers activation)
How Reserve Accounts Work
Section titled “How Reserve Accounts Work”- Activation. A vault becomes a reserve account by sending a
Register()transaction: 4 VFX toReserve_Base, naming its recovery address. At least 0.5 VFX must remain in the vault afterwards. - Delayed sends. Every send from an activated vault carries an unlock time, at least 24 hours ahead. Until then the amount shows as locked: it has left the vault’s spendable balance but has not reached the recipient.
- Call back. Before the unlock time, the vault can cancel a pending send and the funds return.
- Recovery. The recovery key signs a
Recover()that sweeps the vault’s balance to the recovery address and permanently deactivates the vault. - Scope. The delay applies to VFX, vBTC and NFT sends. A fungible-token transfer from a vault carries the unlock time but settles immediately, so a vault protects treasury, not fund tokens. Domain operations, token deployment and multi-contract vBTC transfers are refused from a vault.
Step 1: Derive the Vault Keys
Section titled “Step 1: Derive the Vault Keys”The vault the VerifiedX web wallet pairs with an account is derived from that account’s main key, so the SDK produces the same vault address and recovery key as the wallet.
import { VfxClient, Network } from 'vfx-web-sdk';
const client = new VfxClient(Network.Testnet);
const mainPrivateKey = process.env.VFX_PRIVATE_KEY!;const main = { privateKey: mainPrivateKey, publicKey: client.publicFromPrivate(mainPrivateKey), address: client.addressFromPrivate(mainPrivateKey),};
const vault = client.reserveKeypairFromPrivateKey(mainPrivateKey);console.log(vault.address); // xRBX...console.log(vault.recoveryAddress); // ordinary x... address that receives a recovery sweepconsole.log(vault.restoreCode); // back this up: it restores both keysOther ways to get a vault:
client.reserveKeypairFromRestoreCode(code); // a CLI or wallet restore codeclient.reserveKeypairFromReservePrivateKey(key); // from the vault key aloneclient.generateReserveKeypair(); // a standalone vaultclient.reserveAddressFromPublic(publicKeyHex); // the xRBX address of an HSM-held keyAlways pass the ReserveKeypair object itself when signing. Its private key on its own resolves to that key’s ordinary x… address, not the vault.
Step 2: Fund and Register
Section titled “Step 2: Fund and Register”await client.sendCoin(main, vault.address, 5); // fund the vault// wait for it to confirm, then:await client.registerReserveAccount(vault); // 4 VFX Register()Confirm activation before sending from the vault:
const details = await client.getAddressDetails(vault.address);// { address: 'xRBX...', balance: 1.49999273, balanceLocked: 0, activated: true, deactivated: false, ... }Step 3: Send from the Vault
Section titled “Step 3: Send from the Vault”const hash = await client.sendCoin(vault, 'xRecipient...', 100); // settles in 24 hoursconst later = await client.sendCoin(vault, 'xRecipient...', 100, { unlockHours: 72 }); // or laterThe SDK enforces the 24-hour minimum (the network requires slightly less) and refuses unlockHours on an ordinary account. While a send is pending, getAddressDetails shows it in balanceLocked:
// after sending 0.25 from a vault holding 1.5:// { balance: 1.24998667, balanceTotal: 1.49998667, balanceLocked: 0.25, ... }Step 4: Call a Send Back
Section titled “Step 4: Call a Send Back”Before the unlock time passes, the vault can cancel the send:
await client.callBackReserveTransaction(vault, { hash });// once confirmed: balanceLocked returns to 0 and the amount is spendable againStep 5: Recover a Compromised Vault
Section titled “Step 5: Recover a Compromised Vault”If the vault key is exposed, the recovery key moves everything to the recovery address and deactivates the vault for good:
await client.recoverReserveAccount(vault);// vault: { balance: 0, activated: true, deactivated: true }// recovery address: receives the vault's full balanceA ReserveKeypair carries its recovery key, so the call needs nothing else. The recovery signature is time-stamped and valid for 10 minutes, so send it promptly after building it.
Keys in an HSM
Section titled “Keys in an HSM”Both the vault key and the recovery key can be held externally. The vault Signer presents the xRBX address; recovery takes its own signer (or keypair):
const vaultSigner = { address: client.reserveAddressFromPublic(vaultPublicKey), publicKey: vaultPublicKey, signDigest: (digestHex) => hsm.sign('vault-key', digestHex),};
await client.registerReserveAccount(vaultSigner, { recoveryAddress });await client.sendCoin(vaultSigner, 'xRecipient...', 100);await client.recoverReserveAccount(vaultSigner, { recoverySigner });See External Signing for the Signer contract.
Common Issues
Section titled “Common Issues”A send from a reserve account must wait at least 24 hours
Section titled “A send from a reserve account must wait at least 24 hours”The SDK’s minimum is 24 hours, matching the wallet.
... cannot be sent from a reserve account
Section titled “... cannot be sent from a reserve account”Domain purchases and management, token deployment and multi-contract vBTC transfers are not allowed from a vault. Use an ordinary account.
Invalid Transaction on register
Section titled “Invalid Transaction on register”The vault needs at least 4.5 VFX (4 for activation plus the 0.5 floor) and the funding transaction must be confirmed first.
Signing produced the wrong address
Section titled “Signing produced the wrong address”A vault private key passed as a plain keypair or privateKey signs for that key’s ordinary address. Pass the ReserveKeypair returned by the derivation helpers, or a Signer whose address is the xRBX form.
What’s Next?
Section titled “What’s Next?”- External Signing: HSM-held vault and recovery keys
- Fungible Tokens
- VfxClient API Reference: every reserve method and its parameters