VfxClient API Reference
Esta página aún no está disponible en tu idioma.
The VfxClient is the main interface for interacting with the VerifiedX blockchain. It provides methods for wallet management, transactions, and address operations.
Constructor
Section titled “Constructor”new VfxClient(network, dryRun?)
Section titled “new VfxClient(network, dryRun?)”Creates a new VfxClient instance.
Parameters:
network(Network | string): The network to connect to (Network.Mainnet,Network.Testnet, or string equivalent)dryRun(boolean, optional): If true, transactions will not be broadcast (default: false)
Example:
import { VfxClient, Network } from 'vfx-web-sdk';
const client = new VfxClient(Network.Testnet);const dryRunClient = new VfxClient('mainnet', true);Keypair Management
Section titled “Keypair Management”generatePrivateKey()
Section titled “generatePrivateKey()”Generates a new random private key.
Returns: string - A hexadecimal private key
Example:
const privateKey = client.generatePrivateKey();console.log(privateKey); // "a1b2c3d4e5f6..."generateMnemonic(words?)
Section titled “generateMnemonic(words?)”Generates a BIP39 mnemonic phrase.
Parameters:
words(12 | 24, optional): Number of words in the mnemonic (default: 12)
Returns: string - A space-separated mnemonic phrase
Example:
const mnemonic12 = client.generateMnemonic(12);const mnemonic24 = client.generateMnemonic(24);console.log(mnemonic12); // "word1 word2 word3 ..."privateKeyFromMneumonic(mnemonic, index)
Section titled “privateKeyFromMneumonic(mnemonic, index)”Derives a private key from a mnemonic phrase.
Parameters:
mnemonic(string): The BIP39 mnemonic phraseindex(number): The derivation index (typically 0 for the first account)
Returns: string - The derived private key
Example:
const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";const privateKey = client.privateKeyFromMneumonic(mnemonic, 0);publicFromPrivate(privateKey)
Section titled “publicFromPrivate(privateKey)”Derives the public key from a private key.
Parameters:
privateKey(string): The private key in hexadecimal format
Returns: string - The corresponding public key
Example:
const privateKey = client.generatePrivateKey();const publicKey = client.publicFromPrivate(privateKey);addressFromPrivate(privateKey)
Section titled “addressFromPrivate(privateKey)”Derives the VFX address from a private key.
Parameters:
privateKey(string): The private key in hexadecimal format
Returns: string - The VFX address
Example:
const privateKey = client.generatePrivateKey();const address = client.addressFromPrivate(privateKey);console.log(address); // "VFX..."getSignature(message, privateKey)
Section titled “getSignature(message, privateKey)”Signs a message with a private key.
Parameters:
message(string): The message to signprivateKey(string): The private key to sign with
Returns: string - The signature
Example:
const signature = client.getSignature("Hello, VerifiedX!", privateKey);External Signing
Section titled “External Signing”Every method that signs accepts a Keypair or a Signer. A Signer keeps the
private key elsewhere (HSM, MPC service, hardware wallet):
interface Signer { address: string; // the VFX address the signature is verified against publicKey: string; // uncompressed secp256k1 public key, hex, 04 prefix optional // digestHex: 32-byte SHA-256 digest of the message, as hex. // Return the DER-encoded ECDSA signature as bytes, hex, or base64. signDigest(digestHex: string): Promise<Uint8Array | string> | Uint8Array | string;}The SDK builds the network signature (base64(DER).base58(publicKey)) from
the DER it receives and forces low-s, so signers that return high-s
signatures (AWS KMS) need no wrapper. The address is verified against the
public key on the client’s network before any request is made.
addressFromPublic(publicKeyHex)
Section titled “addressFromPublic(publicKeyHex)”Derives the network address for an uncompressed public key. Use it to obtain the address of an HSM-held key.
const address = client.addressFromPublic(await hsm.getPublicKeyHex());Transaction Methods
Section titled “Transaction Methods”sendCoin(keypair, toAddress, amount)
Section titled “sendCoin(keypair, toAddress, amount)”Sends VFX tokens to another address.
Parameters:
keypair(Keypair | Signer): A local keypair, or a Signer (see External Signing)toAddress(string): The recipient’s VFX addressamount(number): The amount of VFX to send
Returns: Promise<string | null> - The transaction hash, or null when the transaction never reached the node. A send whose outcome is unknown (the request went out but no response came back) throws TransactionDispatchError carrying the hash.
Example:
const keypair = { private: privateKey, public: client.publicFromPrivate(privateKey), address: client.addressFromPrivate(privateKey)};
const result = await client.sendCoin(keypair, "VFX_RECIPIENT_ADDRESS", 100);console.log(result.txHash);buyVfxDomain(keypair, domain)
Section titled “buyVfxDomain(keypair, domain)”Purchases a VFX domain name.
Parameters:
keypair(Keypair): The buyer’s keypairdomain(string): The domain name to purchase (e.g., “myapp.vfx”)
Returns: Promise<any> - Transaction result object
Example:
const result = await client.buyVfxDomain(keypair, "myawesomeapp.vfx");Requirements:
- Domain must be available
- Address must not already own a domain
- Sufficient VFX balance for domain cost
transferVfxDomain(keypair, toAddress)
Section titled “transferVfxDomain(keypair, toAddress)”Hands the signer’s .vfx domain to toAddress. Costs 5 VFX. The owned name is
read from Spyglass and the recipient is checked for an existing domain, both
strictly: an API outage fails the call rather than reading as “no domain”.
deleteVfxDomain(keypair)
Section titled “deleteVfxDomain(keypair)”Releases the signer’s .vfx domain. Costs 5 VFX.
transferBtcDomain(keypair, { btcFromAddress, btcToAddress, vfxToAddress })
Section titled “transferBtcDomain(keypair, { btcFromAddress, btcToAddress, vfxToAddress })”Moves a .btc domain to another Bitcoin address, managed by vfxToAddress
from then on. Costs 5 VFX. The signer must be the VFX account that currently
manages the domain for btcFromAddress; the node checks that pairing and that
btcToAddress has no domain. No Bitcoin signature is needed.
deleteBtcDomain(keypair, { btcFromAddress })
Section titled “deleteBtcDomain(keypair, { btcFromAddress })”Releases the .btc domain on btcFromAddress, managed by the signer. Costs 5 VFX.
The network refuses every domain operation from a reserve (xRBX) account.
vBTC V2
Section titled “vBTC V2”These methods create vBTC V2 vaults, move vBTC and withdraw it to Bitcoin through the explorer API (Spyglass). For the protocol behind them (watched vaults, pinned withdrawals, fee floors) see vBTC Integration. Every method that signs takes either privateKey or an external signer (see External Signing), and none of them runs on a dryRun client.
Since Core 9.0 the chain watches vaults created from the attestation recording height: their withdrawals are paid by the vault’s signers on a Bitcoin transaction the chain pins, with no FROST ceremony and no completion transaction. Vaults created before it (“legacy” vaults, is_watched: false) still complete withdrawals with a FROST ceremony. The withdrawal methods below handle both and say which they are dealing with.
Reading vaults
Section titled “Reading vaults”| Method | Returns |
|---|---|
listVbtcTokens() |
Every V2 vault the explorer indexes |
getVbtcTokens(address) |
The vaults address owns or holds vBTC on |
getVbtcTokenDetail(scIdentifier) |
One vault |
getVbtcTransfers(scIdentifier) |
The vault’s vBTC transfers |
getVbtcWithdrawals(scIdentifier) |
The vault’s withdrawal requests and their status |
A vault (VbtcV2Token) carries sc_identifier, owner_address, deposit_address, global_balance, is_watched, addresses (each holder’s balance) and available_balances (each holder’s balance minus its open withdrawal requests, which is what can be sent). Older explorer deployments omit the last two; fall back to addresses.
createVbtcToken({ ownerAddress, privateKey | signer, name, description, ticker, onProgress?, pollIntervalMs?, timeoutMs? })
Section titled “createVbtcToken({ ownerAddress, privateKey | signer, name, description, ticker, onProgress?, pollIntervalMs?, timeoutMs? })”Creates a vault owned by ownerAddress: it runs the key ceremony (the owner signs its start and share-distribution messages), waits for it to finish (default timeout 3 minutes, polled every 4 s), then signs and sends the contract create transaction. onProgress reports ceremony_started, ceremony_polling, ceremony_complete, contract_preparing and contract_sent.
Returns: Promise<{ transactionHash: string; scIdentifier: string; depositAddress: string }>
Send Bitcoin to depositAddress to fund the vault. The explorer may answer 404 for a new vault for a minute or two until it has indexed the create transaction.
transferVbtc({ scIdentifier, fromAddress, toAddress, amount, privateKey | signer })
Section titled “transferVbtc({ scIdentifier, fromAddress, toAddress, amount, privateKey | signer })”Sends amount vBTC from one vault to toAddress. A .vfx name is resolved to its address first, and a recipient on the other network is refused before anything is built.
Returns: Promise<{ transactionHash: string }>
transferVbtcMulti({ toAddress, totalAmount, privateKey | signer, inputs? })
Section titled “transferVbtcMulti({ toAddress, totalAmount, privateKey | signer, inputs? })”Sends totalAmount vBTC in one transaction drawn from several V2 contracts
the signer holds spendable balance on. Without inputs, balances come from
Spyglass’s available_balances (the address’s balance minus its open
withdrawal requests) and are allocated the way the CLI does: largest first,
ties by contract id, greedy, in whole satoshis so the inputs sum to the total
exactly. A transfer that one contract can cover goes through transferVbtc
instead, as the wallet does. The node caps a transfer at 25 contracts and
refuses it from a reserve account or to a shielded address.
Returns: Promise<{ transactionHash: string; inputs: Array<{ scIdentifier: string; amount: number }> }>
allocateVbtcInputs(balances, total) and vbtcMultiTransferData(...) are
exported for callers that fetch balances or choose contracts themselves.
requestWithdrawal({ scIdentifier, requestorAddress, btcAddress, amount, feeRate, privateKey | signer, onProgress?, pollIntervalMs?, timeoutMs? })
Section titled “requestWithdrawal({ scIdentifier, requestorAddress, btcAddress, amount, feeRate, privateKey | signer, onProgress?, pollIntervalMs?, timeoutMs? })”Withdraws amount vBTC from one vault to btcAddress at feeRate sat/vB: it sends the withdrawal request (type 27), then calls completeWithdrawal for it. The Bitcoin fee comes out of amount, and at least 546 sats must be left after a fee of 154 vB at feeRate, so the smallest withdrawal is 154 × feeRate + 546 sats. The SDK refuses a smaller one before building.
Returns: Promise<VbtcWithdrawalResult>: withdrawalRequestHash, paid, btcTransactionHash and completionTransactionHash (both empty while paid is false), and watched (the withdrawal’s state on a watched vault, else null).
On a watched vault the result usually comes back with paid: false: the chain has taken the request and the vault’s signers are paying it, which takes Bitcoin confirmations. Nothing more needs to be sent. Follow it with getWithdrawalPin, or call completeWithdrawal again later.
If the request is on chain but completing it fails, the error is a VbtcWithdrawalIncompleteError carrying withdrawalRequestHash. The chain refuses a new request while that one stands, so resume it with completeWithdrawal.
completeWithdrawal({ scIdentifier, requestorAddress, withdrawalRequestHash, btcAddress, amount, feeRate, privateKey | signer, onProgress?, pollIntervalMs?, timeoutMs? })
Section titled “completeWithdrawal({ scIdentifier, requestorAddress, withdrawalRequestHash, btcAddress, amount, feeRate, privateKey | signer, onProgress?, pollIntervalMs?, timeoutMs? })”Finishes a withdrawal request that is already on chain.
- Watched vault: sends nothing. It waits (up to
timeoutMs, default 3 minutes) until the node has recorded the request, then resolves withpaid: trueand the paying transaction if Bitcoin has paid it, orpaid: falseand its state inwatched.onProgressreportswatched_polling. It throwsVbtcWithdrawalClosedErrorif the withdrawal closed unpaid (released, expired or void); the vBTC has then been returned to the requester. - Legacy vault: runs the FROST signing ceremony, broadcasts the signed Bitcoin transaction and records the completion (type 28).
onProgressreportsfrost_preparing,frost_polling,frost_complete,btc_broadcastandcompletion_recorded. It is safe to call again for a request whose earlier attempt stopped before the broadcast. A transient ceremony failure says so in the error: wait about 60 seconds and call it again.
If the Bitcoin transaction may have been broadcast but the completion was not recorded, it throws VbtcWithdrawalUnrecordedError with btcTransactionHash and, when the broadcast outcome is unknown, signedBtcTxHex. Do not call completeWithdrawal again in that state: a second ceremony can pay the destination twice. Look the transaction up, re-broadcast signedBtcTxHex if it is missing (the same transaction can only confirm once), then call recordWithdrawalCompletion.
recordWithdrawalCompletion({ scIdentifier, requestorAddress, withdrawalRequestHash, btcTransactionHash, amount, btcDestination, privateKey | signer, onProgress? })
Section titled “recordWithdrawalCompletion({ scIdentifier, requestorAddress, withdrawalRequestHash, btcTransactionHash, amount, btcDestination, privateKey | signer, onProgress? })”Records an already-broadcast legacy withdrawal on the VFX chain (type 28) without running the ceremony again. This is the recovery path after a VbtcWithdrawalUnrecordedError, and it needs no ceremony state, so it works from a fresh process as long as the Bitcoin txid was kept.
Returns: Promise<VbtcWithdrawalResult> with paid: true.
requestWithdrawalMulti({ btcAddress, totalAmount, feeRate, privateKey | signer, inputs?, vaults?, maxFee? })
Section titled “requestWithdrawalMulti({ btcAddress, totalAmount, feeRate, privateKey | signer, inputs?, vaults?, maxFee? })”Withdraws totalAmount vBTC to one Bitcoin address from several vaults in one request (one type 27, one signature). The chain opens one share per vault under the request’s hash, and each share is paid by its own Bitcoin transaction, so feeRate (a whole number of sat/vB) is paid once per share, out of that share.
- Without
inputs, the vaults and amounts are chosen from the requester’s spendable balances (largest first, at most 10 vaults), limited tovaultswhen given. Withinputs, they must sum tototalAmount. - When one vault covers the total, the ordinary single-vault request is sent instead, as the node does.
- Before signing, the SDK checks that
btcAddressis on this network, every share clears the fee floor, and the transaction is the requester’s own type 27 carrying exactly these shares with a VFX fee no higher thanmaxFee(default 0.01). Otherwise it throwsPreSignCheckErrorand signs nothing. - Not available from a reserve (xRBX) account.
It sends the request and returns; it does not wait for payment.
Returns: Promise<{ withdrawalRequestHash: string; inputs: Array<{ scIdentifier: string; amount: number }>; totalAmount: number; btcAddress: string; feeRate: number; fee: number }>
Keep inputs: the share methods below take them as shares.
getWithdrawalShares({ withdrawalRequestHash, requestorAddress, shares })
Section titled “getWithdrawalShares({ withdrawalRequestHash, requestorAddress, shares })”Reads where each share of a request stands from the node. A single-vault request has one share.
Returns: Promise<VbtcWithdrawalShare[]>, each with scIdentifier, amount, outcome, watched, pinnedBtcTransactionHash and btcTransactionHash. outcome is one of:
| Outcome | Meaning |
|---|---|
paid |
Bitcoin paid it |
being_paid |
Pinned: the vault’s signers are paying it. Its fee can be raised, or it can be released |
waiting |
The vault’s free coins do not cover it yet; it pins when they do. It can be cancelled |
released |
Its requester gave it up; the vBTC came back less the release transaction’s fee |
cancelled |
Cancelled while waiting; the vBTC came back |
closed |
Closed unpaid another way (expired, void); the vBTC came back |
not_mined |
The node has not mined the request yet |
legacy |
A vault the chain does not watch: complete this share with completeWithdrawal |
followWithdrawalShares({ withdrawalRequestHash, requestorAddress, shares, onProgress?, pollIntervalMs?, timeoutMs? })
Section titled “followWithdrawalShares({ withdrawalRequestHash, requestorAddress, shares, onProgress?, pollIntervalMs?, timeoutMs? })”Reads the shares (every 15 s by default) until every one is final (paid, released, cancelled, closed or legacy) or timeoutMs passes (default 10 minutes), passing each read to onProgress. Paying takes Bitcoin confirmations, so a short timeout usually returns settled: false with the shares as they stand; call it again later.
Returns: Promise<{ withdrawalRequestHash: string; shares: VbtcWithdrawalShare[]; settled: boolean; lastError?: string }>
getWithdrawalPin({ scIdentifier, withdrawalRequestHash, requestorAddress })
Section titled “getWithdrawalPin({ scIdentifier, withdrawalRequestHash, requestorAddress })”Where a withdrawal (or one share) on a watched vault stands: state (Waiting, Pinned, Settled, Released or another closed state), paid, closed, the pinned Bitcoin transaction and its feeRate, the paying transaction, minimumNextFeeRate, and whether it can be raised (canRaiseFee), released (canRelease) or cancelled (canCancel). Returns null for a legacy vault. Throws VbtcNodeUnreachableError when the explorer could not reach the node; ask again.
bumpWithdrawalFee({ scIdentifier, withdrawalRequestHash, feeRate, privateKey | signer })
Section titled “bumpWithdrawalFee({ scIdentifier, withdrawalRequestHash, feeRate, privateKey | signer })”Raises the Bitcoin fee of a pinned withdrawal on a watched vault that is not confirming (type 44). The chain pins a replacement that spends the same coins, and the higher fee comes out of the withdrawal’s amount. feeRate must be at least minimumNextFeeRate from getWithdrawalPin. The SDK reads the withdrawal first and refuses unless it can be raised; a refusal by the node throws TransactionRefusedError with the node’s reason. For a multi-vault request, name the share’s vault and the request’s hash.
Returns: Promise<string | null>, the transaction hash.
releaseWithdrawal({ scIdentifier, withdrawalRequestHash, feeRate, privateKey | signer })
Section titled “releaseWithdrawal({ scIdentifier, withdrawalRequestHash, feeRate, privateKey | signer })”Gives up a pinned withdrawal on a watched vault (type 44): the chain pins a Bitcoin transaction that returns its coins to the vault, and once Bitcoin confirms it the vBTC comes back to the requester, less that transaction’s fee. If one of its payments confirms first, it is paid instead. feeRate follows the same rule as bumpWithdrawalFee, and the node also refuses a release whose fee does not beat the pinned transaction’s by its relay cost.
Returns: Promise<string | null>, the transaction hash.
cancelWithdrawal({ scIdentifier, ownerAddress, withdrawalRequestHash, privateKey | signer })
Section titled “cancelWithdrawal({ scIdentifier, ownerAddress, withdrawalRequestHash, privateKey | signer })”Cancels a withdrawal request (type 29). On a watched vault this works only while it is Waiting (canCancel), and the vBTC comes back at once; a pinned one can be released instead. For a multi-vault request, name the share’s vault and the request’s hash.
Returns: Promise<{ transactionHash: string }>
vBTC errors
Section titled “vBTC errors”All are exported from vfx-web-sdk.
| Error | When | What to do |
|---|---|---|
VbtcWithdrawalIncompleteError |
The request is on chain but completing it failed | Call completeWithdrawal with its withdrawalRequestHash |
VbtcWithdrawalUnrecordedError |
A legacy withdrawal’s Bitcoin transaction may be out, but its completion was not recorded | Never re-run completeWithdrawal. Re-broadcast signedBtcTxHex if the transaction is missing, then recordWithdrawalCompletion |
VbtcWithdrawalClosedError |
A watched withdrawal closed unpaid | Nothing; the vBTC is back with the requester. withdrawal holds its final state |
VbtcNodeUnreachableError |
The explorer could not reach the node for a withdrawal’s state | Ask again |
PreSignCheckError |
The transaction to sign was not the one asked for | Nothing was signed; check the inputs |
TransactionRefusedError |
The node refused the transaction | Read the node’s reason in the message |
Fungible Token Methods (VFX20)
Section titled “Fungible Token Methods (VFX20)”Every mutating method returns Promise<string | null> with the sendCoin
contract, honours dryRun, and pays the ordinary network fee from the signer’s
VFX balance. The signer’s address is the acting address: the owner for mint,
pause, ban, ownership change and topic creation; the holder for transfer, burn
and votes.
deployToken(signer, params)
Section titled “deployToken(signer, params)”Deploys a fungible token contract owned by the signer. The payload is compiled on the node through Spyglass; the resulting Type 17 deploy is sent from the signer’s address.
Parameters (DeployTokenParams):
name(string)ticker(string): at most 20 characters; stored upper-casedescription(string, optional): defaults tonamedecimalPlaces(number, optional): 1–18, default 8initialSupply(number, optional): whole tokens minted to the deployer at creation. Must be0for a mintable token — mint the opening balance withmintTokenafter deploy. A non-mintable token needs a positive supply.mintable,burnable,voting(boolean, optional): defaultfalseimage(TokenImage, optional):urlmust be publicly fetchable — Spyglass downloads it onto the node as the contract’s primary asset.thumbnailBase64is the small inline image wallets show; without it the node uses its default token image.
Returns: Promise<{ transactionHash: string; scIdentifier: string } | null> — the contract id is known before the send, so it is returned in dryRun too.
const deployed = await client.deployToken(signer, { name: 'Acme Fund I', ticker: 'ACME1', description: 'Units of Acme Fund I', mintable: true, burnable: true,});// deployed.scIdentifier is what every later call is addressed tomintToken(signer, { scIdentifier, amount, ticker?, name? })
Section titled “mintToken(signer, { scIdentifier, amount, ticker?, name? })”Owner only; the token must be mintable. Tokens are credited to the signer.
transferToken(signer, { scIdentifier, toAddress, amount, ticker?, name? })
Section titled “transferToken(signer, { scIdentifier, toAddress, amount, ticker?, name? })”Moves amount from the signer to toAddress.
burnToken(signer, { scIdentifier, amount, ticker?, name? })
Section titled “burnToken(signer, { scIdentifier, amount, ticker?, name? })”Burns from the signer’s own balance; the token must be burnable. Only a holder can burn its own tokens — there is no issuer-side burn.
toggleTokenPause(signer, { scIdentifier })
Section titled “toggleTokenPause(signer, { scIdentifier })”Owner only. Flips the token between paused (no transfers) and active. The node
toggles whatever the current state is, so never send this twice for one
intended change. The SDK reads the current is_paused from Spyglass first and
sends the resulting state in the transaction’s Pause field, as the node’s own
endpoint does; explorers and wallets display that field. It throws if the
current state cannot be read.
banTokenAddress(signer, { scIdentifier, address })
Section titled “banTokenAddress(signer, { scIdentifier, address })”Owner only. Stops address from sending the token. It can still receive, and
the network has no way to lift a ban.
transferTokenOwnership(signer, { scIdentifier, toAddress })
Section titled “transferTokenOwnership(signer, { scIdentifier, toAddress })”Owner only. Hands the owner role to toAddress.
createTokenVoteTopic(signer, { scIdentifier, name, description, votingDays, minimumVoteRequirement, blockHeight? })
Section titled “createTokenVoteTopic(signer, { scIdentifier, name, description, votingDays, minimumVoteRequirement, blockHeight? })”Owner only; the token must have voting enabled. Opens a yes/no topic for
votingDays days, anchored to the current block height (fetched from Spyglass
unless blockHeight is given).
castTokenVote(signer, { scIdentifier, topicUid, vote, ownerAddress? })
Section titled “castTokenVote(signer, { scIdentifier, topicUid, vote, ownerAddress? })”Casts the signer’s vote. The transaction is addressed to the token owner, looked up from Spyglass unless supplied.
Token reads
Section titled “Token reads”listFungibleTokens(page?, limit?)→PaginatedResponse<FungibleToken>getFungibleToken(scIdentifier)→{ token: FungibleToken; holders: Record<string, number> }getFungibleTokenBalances(address)→FungibleTokenBalance[](an address Spyglass has never seen yields[])listTokenVotingTopics(scIdentifier, page?, limit?)→PaginatedResponse<TokenVotingTopic>getTokenVotingTopic(topicId)→TokenVotingTopic
ticker and name travel in every token transaction for indexers and
wallets; when omitted the SDK reads them from Spyglass first.
Reserve (Vault) Account Methods
Section titled “Reserve (Vault) Account Methods”A reserve account is an xRBX… address on the same key material as an
ordinary address, with a different version prefix. Sends from it wait behind
an unlock time (24 hours minimum) and can be called back until they settle;
a recovery key can sweep the vault. The node applies the delay to VFX, vBTC
and NFT sends; a fungible-token transfer from a vault carries the unlock time
but settles at once.
reserveKeypairFromPrivateKey(mainPrivateKey)→ReserveKeypair— the vault the web wallet pairs with a main account, derived the same way (seed from the first 32 hex characters plus a counter, retried until the address isxRBX; recovery key seeded from the vault key). Pinned against the wallet’s keygen bundle by the compat tests.reserveKeypairFromReservePrivateKey(reservePrivateKey)— from the vault key alone; the recovery key is derived from it.reserveKeypairFromRestoreCode(code)— frombase64("<privateKey>//<recoveryPrivateKey>"), the code the CLI prints and the wallet backs up. The recovery key in the code is used as-is.generateReserveKeypair()— a standalone vault on a fresh key.reserveAddressFromPublic(publicKeyHex)— thexRBXaddress of a public key, for HSM-held vault keys.
Sign with the ReserveKeypair object itself. Its private key on its own
resolves to the key’s ordinary address. A Signer whose address is the
xRBX form is verified against reserveAddressFromPublic and signs for the
vault.
registerReserveAccount(signer, { recoveryAddress? })
Section titled “registerReserveAccount(signer, { recoveryAddress? })”Activates a funded vault with a 4 VFX Register() naming the recovery
address. The vault must already hold the 4 VFX plus the fee plus the 0.5 VFX
floor the node keeps on reserve accounts (5 VFX is the wallet’s funding
amount). recoveryAddress comes from a ReserveKeypair; a Signer must
supply it, and it must be an ordinary account.
sendCoin(keypair, toAddress, amount, { unlockHours? })
Section titled “sendCoin(keypair, toAddress, amount, { unlockHours? })”From a vault the send settles after unlockHours (default 24, the network
minimum) and can be called back before then. Asking for less than 24 hours,
or setting unlockHours from an ordinary account, throws before any request.
Every token method accepts the same unlockHours for sends from a vault.
callBackReserveTransaction(signer, { hash })
Section titled “callBackReserveTransaction(signer, { hash })”Cancels a pending send from the vault before its unlock time. hash is the
hash of the send. The node refuses once it has settled, and only the vault
that sent it can call it back.
recoverReserveAccount(signer, { recoverySigner?, recoveryAddress? })
Section titled “recoverReserveAccount(signer, { recoverySigner?, recoveryAddress? })”Sweeps the vault to its recovery address: pending sends are reversed and the
balance moves. Two signatures are needed. The vault key signs the
transaction; the recovery key signs ${SignatureTime}${recoveryAddress}. A
ReserveKeypair carries both. With a Signer for the vault, pass
recoverySigner (a keypair or another Signer) for the recovery key. The
node accepts the recovery signature for ten minutes.
Not available from a vault
Section titled “Not available from a vault”deployToken, buyVfxDomain and buyBtcDomain throw when signed by a
vault: the network only allows those transaction types from an ordinary
account.
Reading vault state
Section titled “Reading vault state”getAddressDetails on the xRBX address returns activated (a Register()
has been sent), deactivated (a Recover() has been sent) and
balanceLocked (sends still waiting to settle). listTransactionsForAddress
shows each pending send’s unlock_time and any callback_details.
Address Operations
Section titled “Address Operations”getAddressDetails(address)
Section titled “getAddressDetails(address)”Retrieves detailed information about a VFX address.
Parameters:
address(string): The VFX address to query
Returns: Promise<VfxAddress> - Address details object
Response Object:
{ address: string; balance: number; txCount: number; adnr?: string; // Domain name if owned}Example:
const details = await client.getAddressDetails("VFX_ADDRESS");console.log(`Balance: ${details.balance} VFX`);console.log(`Transactions: ${details.txCount}`);console.log(`Domain: ${details.adnr || 'None'}`);domainAvailable(domain)
Section titled “domainAvailable(domain)”Checks if a domain name is available for purchase.
Parameters:
domain(string): The domain name to check
Returns: Promise<boolean> - True if available, false if taken
Example:
const isAvailable = await client.domainAvailable("myapp.vfx");if (isAvailable) { console.log("Domain is available!");} else { console.log("Domain is already taken");}lookupDomain(domain)
Section titled “lookupDomain(domain)”Resolves a domain name to its VFX address.
Parameters:
domain(string): The domain name to resolve
Returns: Promise<string> - The VFX address associated with the domain
Example:
try { const address = await client.lookupDomain("example.vfx"); console.log(`example.vfx resolves to: ${address}`);} catch (error) { console.log("Domain not found");}lookupBtcDomain(domain)
Section titled “lookupBtcDomain(domain)”Resolves a domain name to its associated Bitcoin address.
Parameters:
domain(string): The domain name to resolve
Returns: Promise<string> - The Bitcoin address associated with the domain
Example:
try { const btcAddress = await client.lookupBtcDomain("example.vfx"); console.log(`Bitcoin address: ${btcAddress}`);} catch (error) { console.log("No Bitcoin address associated with domain");}listTransactionsForAddress(address, page?, limit?)
Section titled “listTransactionsForAddress(address, page?, limit?)”Retrieves transaction history for an address.
Parameters:
address(string): The VFX address to querypage(number, optional): Page number for pagination (default: 1)limit(number, optional): Number of transactions per page (default: 10)
Returns: Promise<PaginatedResponse<Transaction>> - Paginated transaction list
Example:
const transactions = await client.listTransactionsForAddress( "VFX_ADDRESS", 1, // page 20 // limit);
console.log(`Found ${transactions.data.length} transactions`);transactions.data.forEach(tx => { console.log(`TX: ${tx.hash}, Amount: ${tx.amount}`);});Keypair
Section titled “Keypair”interface Keypair { private: string; public: string; address: string;}Signer
Section titled “Signer”interface Signer { address: string; publicKey: string; signDigest(digestHex: string): Promise<Uint8Array | string> | Uint8Array | string;}ReserveKeypair
Section titled “ReserveKeypair”interface ReserveKeypair extends Keypair { recoveryPrivateKey: string; recoveryPublicKey: string; recoveryAddress: string; restoreCode: string; // base64("<privateKey>//<recoveryPrivateKey>")}FungibleToken
Section titled “FungibleToken”interface FungibleToken { sc_identifier: string; name: string; ticker: string; description: string | null; owner_address: string; can_mint: boolean; can_burn: boolean; can_vote: boolean; created_at: string; initial_supply: number; circulating_supply: number; decimal_places: number; image_url: string | null; is_paused: boolean; banned_addresses: string[]; nsfw: boolean;}VfxAddress
Section titled “VfxAddress”interface VfxAddress { address: string; balance: number; txCount: number; adnr?: string;}Transaction
Section titled “Transaction”interface Transaction { hash: string; from: string; to: string; amount: number; fee: number; timestamp: number; blockHeight?: number; status: 'pending' | 'confirmed' | 'failed';}PaginatedResponse
Section titled “PaginatedResponse”interface PaginatedResponse<T> { data: T[]; total: number; page: number; limit: number; hasNext: boolean; hasPrev: boolean;}Error Handling
Section titled “Error Handling”All async methods can throw errors. Common error scenarios:
Network Errors
Section titled “Network Errors”try { const details = await client.getAddressDetails(address);} catch (error) { if (error.message.includes('Network')) { console.log('Network connectivity issue'); }}Insufficient Balance
Section titled “Insufficient Balance”try { await client.sendCoin(keypair, toAddress, amount);} catch (error) { if (error.message.includes('insufficient')) { console.log('Not enough VFX balance'); }}Domain Errors
Section titled “Domain Errors”try { await client.buyVfxDomain(keypair, domain);} catch (error) { if (error.message.includes('already exists')) { console.log('Domain is already taken'); } else if (error.message.includes('already has')) { console.log('Address already owns a domain'); }}Constants
Section titled “Constants”Networks
Section titled “Networks”enum Network { Mainnet = 'mainnet', Testnet = 'testnet'}Transaction Types
Section titled “Transaction Types”enum TxType { Transfer = 'transfer', Adnr = 'adnr'}Best Practices
Section titled “Best Practices”Security
Section titled “Security”- Never log or expose private keys
- Validate addresses before sending transactions
- Use dry run mode for testing
Performance
Section titled “Performance”- Cache address details when possible
- Use pagination for large transaction lists
- Handle network timeouts gracefully
Error Handling
Section titled “Error Handling”- Always wrap async calls in try-catch
- Provide meaningful error messages to users
- Retry failed requests with exponential backoff
Examples
Section titled “Examples”Complete Wallet Implementation
Section titled “Complete Wallet Implementation”class VfxWallet { private client: VfxClient; private keypair: Keypair | null = null;
constructor(network: Network) { this.client = new VfxClient(network); }
async createWallet(): Promise<{ mnemonic: string; address: string }> { const mnemonic = this.client.generateMnemonic(12); const privateKey = this.client.privateKeyFromMneumonic(mnemonic, 0);
this.keypair = { private: privateKey, public: this.client.publicFromPrivate(privateKey), address: this.client.addressFromPrivate(privateKey) };
return { mnemonic, address: this.keypair.address }; }
async getBalance(): Promise<number> { if (!this.keypair) throw new Error('Wallet not initialized');
const details = await this.client.getAddressDetails(this.keypair.address); return details.balance; }
async send(toAddress: string, amount: number) { if (!this.keypair) throw new Error('Wallet not initialized');
return await this.client.sendCoin(this.keypair, toAddress, amount); }}Migration Notes
Section titled “Migration Notes”From v1.x to v2.x
Section titled “From v1.x to v2.x”- Constructor now requires explicit network parameter
btcnamespace added for Bitcoin functionality- New transaction list method with pagination
- Enhanced error messages and types