SDK
xeris-sdk 5.0.0npmMITNode 18+TypeScript
xeris-sdk builds, signs and submits Xeris transactions from Node or the browser.
Quick start
npm install xeris-sdk
# https://github.com/ZZachWWins/xeris-sdk
import { XerisClient, XerisKeypair } from 'xeris-sdk';
const client = XerisClient.testnet();
// from keypair_gen, wallet keygen or saveToFile
const wallet = XerisKeypair.fromJsonFile('./keypair.json');
const { signature } = await client.transferXrs(wallet, '<recipient>', 1);
const tx = await client.waitForConfirmation(signature);
console.log(tx.status); // "confirmed"
No faucet. Fund the address first; each transaction costs 0.001 XRS.
Classes
| Class | Signs with | Runs in |
|---|---|---|
XerisClient | your keypair | Node, servers, scripts |
XerisDApp | the user's wallet (window.xeris) | the browser |
XerisAgent | the agent's key, inside an owner's RegisterAgent limits | an agent process |
const testnet = XerisClient.testnet(); // 138.197.116.81, ports 56001 and 50008
// throws without a host or XERIS_MAINNET_HOST
const mainnet = XerisClient.mainnet('http://<host>');
const custom = new XerisClient('http://<host>',
{ rpcPort: 56001, explorerPort: 50008 });
Keys
const kp = XerisKeypair.generate();
kp.saveToFile('keypair.json'); // JSON array of 64 bytes, mode 0600
console.log(kp.publicKey); // base58
kp.sign(message); // Ed25519, 64 bytes
// the file xrs-node --validator and the wallet CLI read
const same = XerisKeypair.fromJsonFile('keypair.json');
Send and confirm
// status "ok" = admitted to the mempool; any {"error"} body throws RpcError
const { status, signature } = await client.transferXrs(wallet, to, 1.5);
// default 600,000 ms
const tx = await client.waitForConfirmation(signature, { timeoutMs: 30_000 });
tx.status; // "confirmed" | "partial" | "failed" | "included"
tx.confirmations; // current_slot - block_slot
Read
await client.getBalance(address); // lamports; 1 XRS = 1,000,000,000
await client.getAccountInfo(address); // data: balance, stake, is_validator, …
await client.getStats(); // data: block_height, current_slot, …
await client.getBlocks(1, 5); // data: [block], pagination
// [{ signature, slot, err, … }]
await client.getSignaturesForAddress(address, 20);
// RPC port: reward, fees, stake
await client.getNetworkEconomics();
Method index
Methods ending in Xrs take XRS as a number or decimal string; every other amount is base units.
Write
| Method | Instruction | Reference |
|---|---|---|
transferXrs(kp, to, xrs), transferLamports(kp, to, lamports) | NativeTransfer | 11 |
stakeXrs(kp, xrs), unstakeXrs(kp, xrs) | Stake, Unstake | 9, 10 |
wrapXrs(kp, xrs), unwrapXrs(kp, xrs) | WrapXrs, UnwrapXrs | 13, 14 |
createToken, mintTokens, transferToken, burnTokens | TokenCreate, TokenMint, TokenTransfer, TokenBurn | 3, 0, 1, 2 |
createRwaToken, rwaUpdateStatus, rwaTransfer | TokenCreateRWA, RWAUpdateStatus, RWATransfer | 6, 7, 8 |
deployContract, callContract | ContractDeploy, ContractCall | 5, 4 |
swap, swapByToken, addLiquidity, removeLiquidity, buyOnLaunchpad, sellOnLaunchpad | ContractCall | 4 |
submitAttestation(kp, slot, hash32) | ValidatorAttestation | 12 |
registerAgent, updateAgent | RegisterAgent, UpdateAgent | 15, 16 |
createIdentity, updateIdentity | CreateIdentity, UpdateIdentity | 18, 19 |
attestReputation, sendAgentMessage | AttestReputation, AgentMessage | 20, 21 |
conditionalOrder, cancelConditionalOrder | ConditionalOrder, CancelConditionalOrder | 23, 24 |
registerOracle, oracleSubmit | RegisterOracle, OracleSubmit | 25, 26 |
hardwareAttest | HardwareAttest | 27 |
registerCapability, updateCapability | RegisterCapability, UpdateCapability | 28, 29 |
postTask, claimTask, resolveTask | PostTask, ClaimTask, ResolveTask | 31, 32, 33 |
registerModel, updateModel | RegisterModel, UpdateModel | 34, 35 |
openDispute, resolveDispute, slashReport | OpenDispute, ResolveDispute, SlashReport | 36, 37, 38 |
createProposal, castVote, executeProposal | CreateProposal, CastVote, ExecuteProposal | 39, 40, 41 |
openChannel, closeChannel, forceCloseChannel | OpenChannel, CloseChannel, ForceCloseChannel | 42, 43, 44 |
agentHeartbeat | AgentHeartbeat | 45 |
zkProofSubmit, zkProofVerify, zkVkRegister | ZkProofSubmit, ZkProofVerify, ZkVkRegister | 46, 47, 61 |
pqKeyRegister, pqKeyRotate, pqAttest | PqKeyRegister, PqKeyRotate, PqAttest | 50, 51, 53 |
createDeal, acceptDeal, confirmDeal, cancelDeal, disputeDeal, settleDeal, reclaimDeal | CreateDeal … ReclaimDeal | 54, 55, 56, 57, 58, 59, 60 |
sendInstruction(kp, bytes) | any | envelope |
Read, RPC port
| Method | Route |
|---|---|
getHealth() | GET /health |
getRecentBlocks() | GET /blocks |
getStakeInfo(addr) | GET /stake/{address} |
getUnstaking(addr) | GET /account/{address}/unstaking |
getNetworkEconomics() | GET /network/economics |
getTokenList() | GET /tokens |
getTokenBalance(addr, id) | GET /token/balance/{address}/{token_id} |
getTokenAccounts(addr) | GET /token/accounts/{address} |
getContracts() | GET /contracts |
getContract(id) | GET /contract/{id} |
getContractQuote(id, inputToken, amount) | GET /contract/{id}/quote |
getVestingStatus(id, wallet) | GET /contract/{id}/vesting/{wallet} |
getLaunchpads() | GET /launchpads |
getLaunchpadQuote(id, lamports) | GET /launchpad/{id}/quote |
getAgentRegistry(owner) | GET /agent/registry/{owner} |
validateAgent(agent, owner) | GET /agent/validate/{agent}/{owner} |
agentPlan(body), planTransfer, planSwap, planBuyLaunchpad, planStake, planWrap, planUnwrap | POST /agent/plan |
getCapabilities() | GET /capabilities |
searchCapabilities(params) | GET /capabilities/search |
getTasks() | GET /tasks |
getTask(id) | GET /tasks/{id} |
getZkProofs(identity) | GET /zk/proofs/{identity} |
getZkProofStatus(id) | GET /zk/verify/{proof_id} |
getZkStats() | GET /zk/stats |
getPqKey(addr) | GET /pq/keys/{address} |
getPqStatus() | GET /pq/status |
getGovernanceProposals() | GET /governance/proposals |
getGovernanceLock(addr) | GET /governance/lock/{address} |
getPriceHistory(pool, limit) | GET /price-history |
getAllPoolPriceHistory() | GET /pools/price-history |
Read, explorer port
| Method | Route |
|---|---|
| JSON-RPC | |
getBalance(addr) | getBalance |
getAccountInfoRpc(addr) | getAccountInfo |
getSlot() | getSlot |
getBlockHeight() | getBlockHeight |
getLatestBlockhash(), getLatestBlockhashInfo() | getLatestBlockhash |
getBlockRpc(slot) | getBlock |
getTransactionRpc(sig) | getTransaction |
getSignaturesForAddress(addr, limit) | getSignaturesForAddress |
getHealthRpc() | getHealth |
getVersion() | getVersion |
| REST v2 | |
getStats() | GET /v2/stats |
getBlocks(page, size) | GET /v2/blocks |
getBlockBySlot(slot) | GET /v2/block/slot/{slot} |
getBlockByHash(hash) | GET /v2/block/hash/{hash} |
getTransactions(page, size) | GET /v2/transactions |
getTransaction(sig), waitForConfirmation(sig) | GET /v2/tx/{signature} |
getAccountInfo(addr) | GET /v2/account/{address} |
getAccountTransactions(addr, { page, pageSize, before }) | GET /v2/account/{address}/transactions |
getValidators() | GET /v2/validators |
search(q) | GET /v2/search |
getTokens({ after, limit }) | GET /v2/tokens |
getTokenHolders(id) | GET /v2/token/{id}/holders |
getRwaTokens() | GET /v2/rwa |
getRwa(id) | GET /v2/rwa/{id} |
getContractsV2() | GET /v2/contracts |
getContractV2(id) | GET /v2/contract/{id} |
getPools() | GET /v2/pools |
Tokens
import { toBaseUnits } from 'xeris-sdk';
// signer = mint authority; maxSupply in base units
await client.createToken(wallet, 'mytoken', 'My Token', 'MTK', 9,
toBaseUnits('1000000', 9));
// 1,000 MTK
await client.mintTokens(wallet, 'mytoken', to, toBaseUnits('1000', 9));
await client.transferToken(wallet, 'mytoken', to, toBaseUnits('50', 9));
// { native_xrs, token_accounts: [{ token_id, balance, … }] }
await client.getTokenAccounts(to);
DEX and launchpad
// the DEX and the launchpad spend wrapped XRS
await client.wrapXrs(wallet, 10);
// POST /agent/plan: amount_in in lamports, slippage 1 %
const swap = await client.planSwap(poolId, 'xrs_native', 1_000_000_000, 1);
// args: 16 raw bytes, amount_in ‖ min_output, u64 LE (encodeSwapCall)
await client.swap(wallet, poolId, swap.params.method,
1_000_000_000, swap.quote.min_amount_out);
const buy = await client.planBuyLaunchpad(launchpadId, 1_000_000_000, 1);
// args: JSON { xrs_amount, min_tokens_out }
await client.buyOnLaunchpad(wallet, launchpadId,
1_000_000_000, buy.quote.min_tokens_out);
// any plan: await client.sendInstruction(wallet, fromPlan(plan))
Browser
import { XerisDApp } from 'xeris-sdk';
// { host } for another node; mainnet needs one
const dapp = new XerisDApp();
await dapp.connect(); // window.xeris signs; the SDK holds no key
await dapp.getBalance(); // the connected address
const { signature } = await dapp.transferXrs(to, 5);
await dapp.waitForConfirmation(signature);
Agents
await client.registerAgent(
owner, 'ari-trader', agentKp.publicKey,
5_000_000_000, // max_per_tx, lamports
10_000_000_000, // max_daily, lamports, per 21,600 slots
[], // allowed_contracts, empty = any
// allowed_operations, exact strings from AGENT_OPERATIONS
['NativeTransfer', 'WrapXrs', 'UnwrapXrs'],
0, // expires_at_slot, 0 = never
);
import { XerisAgent } from 'xeris-sdk';
const agent = XerisAgent.testnet(agentKp, owner.publicKey);
await agent.getPermissions(); // { authorized, revoked, expired, agent }
// once, before the first heartbeat
await agent.createIdentity('Ari Trader', '{}');
// model hash, active tasks, capacity, status
await agent.heartbeat('', 1, 9, 'online');
const [task] = await agent.findTasks({ category: 'trading' });
await agent.claimTask(task.task_id);
// AgentExecute: runs as the owner, inside the limits
await agent.transferXrs(to, 2);
// swaps, launchpad buys and Stake cannot be delegated
await agent.completeTask(task.task_id, proof);
AgentExecute rules. Design: whitepaper.
Post-quantum keys
import { buildPqRotationMessage, CHAIN_ID_TESTNET } from 'xeris-sdk';
// ML-DSA-65 public key, 1,952 bytes; POST /pq-register
await client.pqKeyRegister(wallet, pqPublicKey, 'dilithium3', 3);
// { has_pq_key, algorithm, security_level, rotation_count, … }
const key = await client.getPqKey(wallet.publicKey);
await client.getPqStatus();
const msg = buildPqRotationMessage(
CHAIN_ID_TESTNET, pqPublicKey, newPqPublicKey, key.rotation_count);
// proof: the current key signs msg, ML-DSA-65, 3,309 bytes
await client.pqKeyRotate(wallet, newPqPublicKey, 'dilithium3', proof);
Raw instructions
import { Instructions, encodeU32, encodeU64, encodeString } from 'xeris-sdk';
// 36 bytes; builders take base units, positional, strict arity
const ix = Instructions.nativeTransfer(wallet.publicKey, to, 1_000_000_000);
// blockhash, sign, POST /submit; up to 16 instructions per transaction
await client.sendInstruction(wallet, ix);
// the same bytes by hand: u32 variant, then the fields in declaration order
Buffer.concat([encodeU32(11), encodeString(wallet.publicKey),
encodeString(to), encodeU64(1_000_000_000)]);
Test vectors
npm test
npm run test:vectors
Expected bytes: Instruction set.
Removed in 5.0
| Method | Reason | Now |
|---|---|---|
airdrop | the faucet is disabled on the node | FeatureDisabledError |
subDelegate | variant 22 is refused at ingress | FeatureDisabledError |
zkPrivateTransfer, sendZkPrivateTransfer | variant 48 is skipped by the dispatcher | FeatureDisabledError |
zkIdentityProof | variant 49, same | FeatureDisabledError |
pqSignedTransfer, sendPqTransfer | variant 52, same | FeatureDisabledError |
claimStakingReward | POST /stake/claim answers 501; rewards pay every 900 blocks | FeatureDisabledError |
governanceLock, governanceDelegate | no lock or delegation instruction exists | FeatureDisabledError |
XerisAgent.swapTokens, buyOnLaunchpad, sellOnLaunchpad, stakeXrs, unstakeXrs | cannot be delegated | FeatureDisabledError |
buildPqTransferMessage, createZkPrivateTransferProofs, domainHash | no on-chain path | removed |