Ksana
中文

Use the network

The command-line client

ksana-cli talks to one Ksana node over JSON-RPC. It makes keys, reads accounts, blocks and operations, sends transfers and contract calls on path B or path C, and runs both sides of a top-up.

On this page

ksana-cli reads the chain through a node’s JSON-RPC and signs operations on your machine with a key file, so no node ever sees your secret key. For path C and top-ups it also uses a wallet in your own bitcoind. The examples run against the public signet, the network to use today; mainnet has not launched.

Install

Build it from the repository. The quickstart lists the Ubuntu packages and the rustup setup the build needs.

Shell
git clone https://github.com/ksana-in-bitcoin/Ksana
cd Ksana
rustup toolchain install
cargo build --release --locked -p ksana-cli
target/release/ksana-cli --version
Output
ksana-cli 0.1.0

The binary is target/release/ksana-cli; put that directory on your PATH or copy the file into one. ksana-cli --help lists the commands, and ksana-cli <command> --help lists a command’s options.

Global options

Option Default What it sets
--rpc <URL> http://127.0.0.1:8545, or KSANA_RPC The node’s JSON-RPC address, over HTTP or HTTPS.
--chain <NETWORK> none devnet, signet or mainnet: the network you expect the node to be on.

Both may come before or after the command. Every command except key first reads the node’s chain ID and signs for that network. With --chain, a node on another network is refused before anything is signed or sent:

Output
ksana-cli: the node at https://signet.ksana.network/rpc is on signet (chain ID 1002), not devnet (--chain): refusing to sign for one network and send to another; drop --chain to use the node's network, or point --rpc at a devnet node

Pass --chain signet whenever you sign, so that a wrong --rpc cannot make you sign for another network.

Environment variables

Variable Stands for
KSANA_RPC --rpc
KSANA_BTC_RPC_URL --btc-rpc-url (path C and top-ups)
KSANA_BTC_RPC_USER --btc-rpc-user
KSANA_BTC_RPC_PASS --btc-rpc-pass

An option on the command line wins over its variable. ksana-cli <command> --help prints the current value of each variable next to its option, the bitcoind password included, so keep that output to yourself.

Output and exit codes

Results go to standard output as JSON with sorted keys; amounts, nonces and heights are decimal strings. Errors go to standard error as ksana-cli: <message> and exit with code 1, and a mistake in the options exits with code 2. An operation that a block includes but whose execution fails still exits with 0 and shows "failed", so scripts should check .status.status.

Wherever a command takes an account, you can write a Taproot address of the node’s network (tb1p… on the signet), the account as 64 hex digits, or @<key file> for the account of a key file. Amounts are always base units: KSA has 8 decimals, so 1 KSA is 100000000.

Keys

Shell
ksana-cli --chain signet key alice.key
Output
{
  "account": "44519c0982a42472e32bd9d90f0a82298697a190cd9c8ac2d23a2bee8d58d15f",
  "address": "tb1pg3geczvz5sj89cetm8vs7z5z9xrf0gvsekwg4skj8g47ar2c690surwrec",
  "internal_key": "95a204e1c34d497338d95c8cb901f8a8f71a0efb56faf7d46ae05a4f5fff9d78",
  "script": "512044519c0982a42472e32bd9d90f0a82298697a190cd9c8ac2d23a2bee8d58d15f"
}

key writes a new random secret key to the file (mode 0600) when the file does not exist, and reads it when it does. It never contacts the node and never prints the secret. The file holds the secret key as 64 hex digits, the same format ksana-keytool and the node’s funding key use.

account is the Taproot output key, which is your account; address is the same 32 bytes as a Taproot address; internal_key is the key before the Taproot tweak, and script the address’s output script. Without --chain or --network, key prints a devnet address (bcrt1p…); --network regtest|signet|testnet|mainnet picks the address encoding directly. Accounts explains how keys, accounts and addresses relate.

Read the chain

These commands only read. Each answer names the block it was read at in at.

account

Shell
ksana-cli account @bob.key
Output
{
  "account": "999c8c1a52fe8b7538327f9c5f3306552679255ba84b1a4a20a6d55ff581ebe9",
  "address": "tb1pnxwgcxjjl69h2wpj07w97vcx25n8jf2m4p935j3q5m24lavpa05srrsk8t",
  "at": {
    "hash": "2c1363cf56e91f58e8bd2167b74625120771ad3b0956ea215de540faa33df3ad",
    "height": "286"
  },
  "balances": [
    {
      "amount": "100000000",
      "asset": "0000000000000000000000000000000000000000000000000000000000000000"
    }
  ],
  "locked_fees": [],
  "nonce": "0"
}

balances lists what the account can spend now, one entry per asset; KSA is the asset of 64 zeros. nonce is the nonce the account’s next operation must carry. locked_fees lists income that is not unlocked yet, such as a producer’s fees and block rewards, one entry per block; it moves into balances once the block’s data is on Bitcoin. An account that has never been used shows nonce 0 and empty lists.

asset

Shell
ksana-cli asset
Output
{
  "asset": "0000000000000000000000000000000000000000000000000000000000000000",
  "at": {
    "hash": "2c1363cf56e91f58e8bd2167b74625120771ad3b0956ea215de540faa33df3ad",
    "height": "286"
  },
  "decimals": 8,
  "issuer": "0000000000000000000000000000000000000000000000000000000000000000",
  "name": "KSA",
  "total_supply": "11011956230000000"
}

Without an argument it shows KSA; give an asset ID (64 hex digits) for another asset. KSA’s total_supply is the genesis allocation plus the block rewards unlocked so far.

op

Shell
ksana-cli op 92e22273a7fab8430c6ae16b69b1f649fa4056aa2a0c3f27d10bf38e77908a0d
Output
{
  "block": {
    "hash": "d0f420c0aa6e9a99a9b9d3af66d0c88a6ad9b4ecc36a2389b78b42e5f1efc471",
    "height": "259"
  },
  "index": 0,
  "receipt": {
    "error": null,
    "events": [],
    "gas_used": "10000",
    "op_id": "92e22273a7fab8430c6ae16b69b1f649fa4056aa2a0c3f27d10bf38e77908a0d",
    "output": "",
    "success": true
  },
  "status": "btc_final"
}

block.height is the height of the main-chain block that accepted the operation’s block, index its place among the block’s entries, and receipt the result of executing it. status is one of these:

Status Meaning
pending In the node’s entry pool, not in a block yet.
fast_confirmed Included and executed successfully.
failed Included, but the execution failed; the fee is charged anyway.
skipped Included only by a parallel block that could not execute it; nothing is charged, and it goes back to the pool to be included again.
btc_final Executed successfully, and its block is final on Bitcoin.

An operation the node does not know is an error, ErrorObject { code: ServerError(-32004), message: "unknown op", … }. A path C operation stays unknown until a block includes it. Confirmations explains what each status guarantees.

block

ksana-cli block takes latest, a height or a block hash. A height names the main-chain block at that height; a hash can name any block, parallel blocks included.

The block that carried the quickstart’s transfer
Shell
ksana-cli block 262
Output
{
  "accepted_height": "262",
  "entries": [
    {
      "Sponsored": {
        "op": {
          "account": "44519c0982a42472e32bd9d90f0a82298697a190cd9c8ac2d23a2bee8d58d15f",
          "action": {
            "AssetTransfer": {
              "amount": "100000000",
              "asset": "0000000000000000000000000000000000000000000000000000000000000000",
              "to": "999c8c1a52fe8b7538327f9c5f3306552679255ba84b1a4a20a6d55ff581ebe9"
            }
          },
          "chain_id": 1002,
          "fee": {
            "Token": {
              "amount": "1"
            }
          },
          "max_gas": "1000000",
          "nonce": "0",
          "sig": {
            "Bip340": "3ea1a4ac0676edb5b98ea87cfda65c3ed49548d813072322ccde9085c85d5c0ef43c447b6764df91a0f16b6a4a13393f7131f2806934911c55d201b25735b6cb"
          },
          "version": 2
        }
      }
    }
  ],
  "hash": "2f22a435469f702c2d23b1142ac39034d019fd406331a094485a789a1cc7d7b3",
  "header": {
    "bits": 520435151,
    "btc_anchor": {
      "hash": "eae6f2a86febdd8ae21bee2da3902a07cb324648485c58944c708ddb0f000000",
      "height": 326320
    },
    "entries_root": "95c38f2dbe6fb6f88df48ed8110c1c24dc6f2996f4f73e47a55f60cb426626b3",
    "height": "262",
    "nonce": "197",
    "parents": [
      "81a22b58a74d0d6223cfb8c3c53a3ae21d13f0311c5d155f84863b5ba7be8639"
    ],
    "producer": "b40c816d58ee2578da0118a9c6feeca74b80280f92030bdfa510821ae2887954",
    "state_root": "e49f287ddfd7c232e655e8b9ae42626e4c745b5fcb26315dfa8ab2844f6e5e3e",
    "timestamp": "1791980120",
    "version": 2
  },
  "merged": [],
  "receipts": [
    {
      "error": null,
      "events": [],
      "gas_used": "10000",
      "op_id": "501a6cba0a23521fbd72bfb704959b2720fce86d8edbac967fa4e611f0ca8728",
      "output": "",
      "success": true
    }
  ],
  "settlement": null
}

The header names the block’s parents, the Bitcoin block it is anchored to (btc_anchor, whose hash is in Bitcoin’s internal byte order), its producer and its state_root. entries and receipts pair up by position; merged lists the parallel blocks this block merges, and settlement holds the commit and reveal transactions the block carries, or null.

settlement

ksana-cli settlement <block> shows the Bitcoin transactions that carry a block’s data, and where they are:

  • status: pending (not sent yet), broadcast (sent, waiting for a Bitcoin block) or confirmed, with the Bitcoin block and its confirmation count under confirmed.
  • settled: true once this block and every block before it are on Bitcoin. This is the on-Bitcoin mark.
  • btc_final: true once the block is final.
  • carrier: the later block whose settlement carried this block’s data, when producers batched it; null when the block carries its own.
  • carrier_account: the account paid the carrier reward for landing the block’s data on Bitcoin, the producer of the block whose settlement carried it or a republisher’s payee; null when there is none, and the producer keeps that part.
  • txid_rpc and commit_txid_rpc: the reveal and commit transaction IDs as Bitcoin explorers write them; txid and commit_txid are the same in internal byte order, as are the hashes under confirmed.

A block with no body to land, an empty block or one holding only path C operations, has no settlement unless it carries one itself: the command answers -32004 with that block has no settlement transactions. The quickstart shows a full answer.

estimate-fee

Shell
ksana-cli estimate-fee
Output
{
  "at": {
    "hash": "2c1363cf56e91f58e8bd2167b74625120771ad3b0956ea215de540faa33df3ad",
    "height": "286"
  },
  "feerate_sat_vb": "2",
  "path_b": {
    "amount": "1",
    "per_kib": "1"
  }
}

path_b.amount is the node’s suggested --fee-token for a plain KSA transfer, in base units, and path_b.per_kib the suggested fee per KiB of an operation’s cost, for larger operations. feerate_sat_vb is the Bitcoin fee rate the node pays for its own settlements now, a reference for --btc-fee-rate. All three are suggestions; Operations and fees explains how fees work.

Send a transfer

Shell
ksana-cli --chain signet transfer --key alice.key --to @bob.key \
  --amount 100000000 --fee-token 1 --wait
Output
{
  "account": "44519c0982a42472e32bd9d90f0a82298697a190cd9c8ac2d23a2bee8d58d15f",
  "nonce": "0",
  "op_id": "501a6cba0a23521fbd72bfb704959b2720fce86d8edbac967fa4e611f0ca8728",
  "status": {
    "block": {
      "hash": "2f22a435469f702c2d23b1142ac39034d019fd406331a094485a789a1cc7d7b3",
      "height": "262"
    },
    "index": 0,
    "receipt": {
      "error": null,
      "events": [],
      "gas_used": "10000",
      "op_id": "501a6cba0a23521fbd72bfb704959b2720fce86d8edbac967fa4e611f0ca8728",
      "output": "",
      "success": true
    },
    "status": "fast_confirmed"
  }
}

transfer moves --amount base units of KSA to --to; --asset <ID> sends another asset. Without --wait the command prints account, nonce and op_id as soon as the node accepts the operation, and you follow it with ksana-cli op.

Options for sending

transfer, deploy, call and the exchange commands that change state (deposit, withdraw, lock, release) share these options. Each needs --key and exactly one of --fee-token and --native.

Option Default What it does
--key <FILE> required The key file that signs; its account sends the operation.
--fee-token <AMOUNT> Path B: the fee in KSA base units, paid to the producer.
--native Path C: carry the operation in your own Bitcoin transaction (below).
--nonce <N> the account’s nonce The operation’s nonce.
--max-gas <GAS> 1000000 The execution limit; a failed operation uses all of it.
--sig <SCHEME> bip340 bip340, or bip322, the scheme browser wallets use.
--wait off Wait until a block includes the operation (below).
--timeout <SECONDS> 120 How long --wait waits.

The default nonce is the account’s nonce at the chain tip, and it does not count operations still waiting in the node’s pool. If you send a second operation before the first is in a block, both carry the same nonce and the node refuses the second with -32011: an op with the same nonce already exists; replacing it needs a higher sponsored fee. Use --wait between operations, or give each one its --nonce; a higher --fee-token with the same nonce replaces an operation that is still waiting.

Contracts

Contracts are WebAssembly modules. Write a contract covers building one, and the token and pool tutorial deploys and uses two on the signet step by step.

deploy

Shell
ksana-cli --chain signet deploy --key alice.key \
  --code crates/ksana-execution/tests/data/token.wasm \
  --init-args 040000005465737403000000545354080010a5d4e80000000000000000000000 \
  --fee-token 1 --wait | tee deploy.json

--code is the wasm file and --init-args the hex of the arguments the contract’s init receives (none by default). --fund attaches assets to init (below). The repository keeps a built token at crates/ksana-execution/tests/data/token.wasm; its init takes a name, a symbol, the decimals and the supply, here "Test", "TST", 8 and 1,000,000,000,000 base units.

Deploying costs 100,000 gas plus 20 gas per byte of code before init runs, so the default --max-gas of 1,000,000 covers code up to about 40 KB. A whole operation, code included, must fit in 64 KiB (MAX_OP_BYTES).

Find the contract ID

deploy does not print the new contract’s ID: you compute it. It is the SHA-256 of the deploying account, the deploy operation’s nonce as an 8-byte little-endian integer, and the SHA-256 of the code. This shell function computes it with Python:

Shell
contract_id() {  # account nonce wasm-file
  python3 -c 'import hashlib, sys
code = hashlib.sha256(open(sys.argv[3], "rb").read()).digest()
seed = bytes.fromhex(sys.argv[1]) + int(sys.argv[2]).to_bytes(8, "little") + code
print(hashlib.sha256(seed).hexdigest())' "$@"
}
contract_id d08a82dc475034a5f18bb589be8343472e67996b830764889bcbed12e24510bf 0 \
  crates/ksana-execution/tests/data/token.wasm
Output
f622bdcea40708c8776b36dbe387e7285b57f8c3734d370a31b63c5c10756740

That is a token deployed on the signet from account d08a82dc… with nonce 0, the one the query below reads. For your own deployment, pass the account and nonce that deploy printed (this uses jq):

Shell
TOKEN=$(contract_id "$(jq -r .account deploy.json)" "$(jq -r .nonce deploy.json)" \
  crates/ksana-execution/tests/data/token.wasm)

When init emits an event, as the token’s does, the deploy receipt’s events[].contract shows the same ID.

query

query runs a contract method on the node without sending anything, so it costs no fee and needs no key:

Shell
ksana-cli query --contract f622bdcea40708c8776b36dbe387e7285b57f8c3734d370a31b63c5c10756740 \
  --method metadata
Output
{
  "error": null,
  "events": [],
  "gas_used": "37780",
  "op_id": null,
  "output": "0e0000005475746f7269616c20546f6b656e0300000054555408",
  "success": true
}

output is the method’s return value in hex, here the Borsh encoding of ("Tutorial Token", "TUT", 8). --args passes arguments, --caller <ACCOUNT> sets the caller the method sees (32 zero bytes by default), and --fund simulates attached assets.

call

call sends a contract call as an operation. This one moves 250 base units of the token you deployed above, which init gave to your account, to another account; the arguments (to, amount) are encoded as Borsh:

Shell
TO=999c8c1a52fe8b7538327f9c5f3306552679255ba84b1a4a20a6d55ff581ebe9
AMOUNT=fa000000000000000000000000000000   # 250 as a 16-byte little-endian integer
ksana-cli --chain signet call --key alice.key --contract "$TOKEN" \
  --method transfer --args "$TO$AMOUNT" --fee-token 1 --wait

The result has the same shape as a transfer’s. A method that reverts gives "status": "failed" with the reason in .status.receipt.error, and the command still exits with 0.

Arguments and attached funds

--args and --init-args take the raw argument bytes in hex (a 0x prefix is allowed); ksana-cli does not encode anything for you. The example contracts read Borsh: a tuple of the arguments in order, a single argument as itself, and no bytes for none.

Type Borsh encoding
u8, u32, u64, u128 little-endian, 1, 4, 8 or 16 bytes
[u8; 32] (an account or contract ID) the 32 bytes
String, Vec<u8> the length as a 4-byte little-endian integer, then the bytes

--fund attaches assets to deploy, call and query: --fund 5000 attaches 5,000 base units of KSA, and --fund <asset ID>:<amount> another asset. Repeat it for several assets, at most 16, each asset once.

Path C with bitcoind

With --native, the operation travels in a Bitcoin transaction of your own instead of a node’s pool: you pay the Bitcoin fee and no KSA fee, and every producer must include the operation once the transaction has its confirmations. Operations and fees explains when that helps.

ksana-cli builds the transaction, has a bitcoind wallet add inputs and change and sign them, signs the operation over the transaction’s first input, and broadcasts it. You need:

  • your own bitcoind on the same Bitcoin network as the node (signet for the public signet), reachable over plain http://: the CLI has no TLS for bitcoind;
  • a wallet in it holding some sBTC; a transfer at the default 2 sat/vB costs about 700 sats of fee;
  • Bitcoin Core 30 or later, or -datacarriersize=100000, so that your bitcoind relays the transaction’s large OP_RETURN output.

The hosted Bitcoin RPC proxy has no wallet methods, so it cannot do this. Run a node shows how to set up bitcoind on signet.

Shell
export KSANA_BTC_RPC_URL=http://127.0.0.1:38332
export KSANA_BTC_RPC_USER=ksana
export KSANA_BTC_RPC_PASS=<password>
ksana-cli --chain signet transfer --key alice.key --to @bob.key --amount 100000000 \
  --native --btc-wallet <wallet>

The command prints account, nonce, op_id and btc_txid, the Bitcoin transaction ID as explorers write it. --btc-wallet names the bitcoind wallet that pays (bitcoind’s only loaded wallet when you leave it out), and --btc-fee-rate sets the fee rate in sat/vB (default 2).

On the signet a block includes the operation once its transaction has 2 Bitcoin confirmations (NATIVE_CONFIRMATIONS 1 plus ANCHOR_DEPTH 1); on mainnet it will take 5. Until then ksana-cli op <op_id> answers unknown op. Leave out --wait, or give it --timeout 3600: the default 120 seconds runs out long before.

Exchange

A top-up sells KSA for bitcoin through an exchange contract: the seller locks KSA for one buyer, and the buyer’s Bitcoin payment carries the claim. The exchange commands are the seller’s side, written for the example contract ksa-exchange. On the signet nobody runs a standing exchange, so to try it you deploy one yourself.

Shell
(cd contracts && cargo rustc --release --locked --target wasm32-unknown-unknown \
  --package ksa-exchange --crate-type cdylib)
WASM=contracts/target/wasm32-unknown-unknown/release/ksa_exchange.wasm
ksana-cli --chain signet deploy --key seller.key --code $WASM --fee-token 1 --wait \
  | tee exchange.json
EXCHANGE=$(contract_id "$(jq -r .account exchange.json)" "$(jq -r .nonce exchange.json)" $WASM)

The contract’s init takes no arguments, and contract_id is the function from Find the contract ID. Then, as the seller:

Shell
ksana-cli --chain signet exchange lock --key seller.key --fee-token 1 \
  --exchange "$EXCHANGE" --ksa 3000000 --price 100 --fund 3000000 \
  --address <a fresh tb1 address of yours> --beneficiary <buyer's account> \
  --expiry <Bitcoin height> --wait

This locks 3,000,000 base units of KSA for the buyer at 100 base units per sat, so 30,000 sats buy all of it. The result’s lock field is the lock number; give it and the exchange ID to the buyer.

  • --fund attaches KSA to the call, which goes into your available balance in the contract before the lock takes --ksa from it. exchange deposit --amount <N> adds to that balance ahead of time, and exchange withdraw --amount <N> takes from it; neither touches a lock.
  • --address (or --script <hex>) is where the buyer pays. Use a fresh address for every lock: the contract refuses a payment script that any earlier lock used.
  • --expiry is a Bitcoin height above the one the current block is anchored to (header.btc_anchor.height in ksana-cli block latest). Signet makes a block about every ten minutes, so add enough for the buyer to pay.
  • exchange release --lock <N> returns what is still locked to your available balance. It works only once the anchored Bitcoin height reaches the expiry plus 6 blocks.

Two commands only read:

Shell
ksana-cli exchange show --exchange "$EXCHANGE" --lock 0
ksana-cli exchange balance --exchange "$EXCHANGE" --seller @seller.key

show prints the lock’s seller, beneficiary, payment script, price, the ksa still locked, expiry, sats_for_all (the sats that buy all of it) and its state: open, released, or claimed with what was paid. balance prints your available balance in the contract.

Top-up

top-up is the buyer’s side. One Bitcoin transaction pays the lock’s address and carries the claim as a path C operation, signed with a one-time key, so your own account signs nothing and spends no nonce.

Shell
ksana-cli --chain signet top-up --exchange <exchange ID> --lock <lock number> \
  --beneficiary @buyer.key --sats 30000 --btc-wallet <wallet>

Before paying, the command reads the lock and refuses to pay when:

  • its beneficiary is not --beneficiary, since the KSA would go to someone else;
  • it is not open;
  • 3 or fewer Bitcoin blocks are left before its expiry (--expiry-margin, default 3);
  • --sats differs from what buys all the KSA still locked. --allow-partial lets you buy part of it and leave the rest locked for you; --allow-overpay lets you pay more, which buys nothing more.

It needs bitcoind as path C does, and prints the op_id of the claim, the btc_txid, the Bitcoin fee, the ksa you get and the lock’s terms. The KSA reaches the beneficiary when a block includes the claim, 2 Bitcoin confirmations later on the signet. The signet wallet does the same from a browser.

Waiting and timeouts

--wait asks the node for the operation’s status every half second and returns at fast_confirmed, failed or btc_final; a pending or skipped operation keeps it waiting. After --timeout seconds (default 120) it prints the status if the last one it saw was skipped, and otherwise stops with an error and exit code 1:

Output
ksana-cli: timed out waiting for the op to be included (120 seconds)

To find out what happened:

  • Run ksana-cli account for the sending account: when nonce has gone up, a block has included the operation.
  • For path C, look for the transaction in the funding wallet (bitcoin-cli -signet -rpcwallet=<wallet> listtransactions) and wait for its confirmations.
  • List the account’s latest operations, newest first, with the node’s ksana_getAccountOps method. It takes the account as 64 hex digits and gives each operation’s op_id and status (this uses jq):
Shell
ACCOUNT=$(ksana-cli account @alice.key | jq -r .account)
BODY='{"jsonrpc":"2.0","id":1,"method":"ksana_getAccountOps","params":["'$ACCOUNT'",null,5]}'
curl -sS https://signet.ksana.network/rpc -H 'content-type: application/json' \
  --data "$BODY" | jq .result
Output
{
  "ops": [
    {
      "op_id": "501a6cba0a23521fbd72bfb704959b2720fce86d8edbac967fa4e611f0ca8728",
      "status": "fast_confirmed",
      "block": {
        "height": "262",
        "hash": "2f22a435469f702c2d23b1142ac39034d019fd406331a094485a789a1cc7d7b3"
      },
      "index": 0,
      "position": "262:0:0"
    },
    {
      "op_id": "92e22273a7fab8430c6ae16b69b1f649fa4056aa2a0c3f27d10bf38e77908a0d",
      "status": "fast_confirmed",
      "block": {
        "height": "259",
        "hash": "d0f420c0aa6e9a99a9b9d3af66d0c88a6ad9b4ecc36a2389b78b42e5f1efc471"
      },
      "index": 0,
      "position": "259:0:0"
    }
  ],
  "next": null,
  "at": {
    "height": "286",
    "hash": "2c1363cf56e91f58e8bd2167b74625120771ad3b0956ea215de540faa33df3ad"
  }
}

The list covers the operations the account signed and the transfers it received; the second one here is the faucet’s. Do not send an operation again with a new nonce until you know the first one failed, or both can go through. The JSON-RPC reference describes ksana_getAccountOps and its paging.

Common errors

Message What to do
reading the chain ID of the node at …: … Connection refused The node is not running or --rpc is wrong.
… Method not found … while reading the chain ID --rpc points at something other than a node, such as an indexer.
invalid account: invalid address: validation error The address belongs to another network than the node’s.
the following required arguments were not provided: <--fee-token <FEE_TOKEN>|--native> Choose path B (--fee-token) or path C (--native).
-32011 … an op with the same nonce already exists An earlier operation is still waiting; wait for it or set --nonce.
bitcoind …: … https feature is not enabled Use http:// for bitcoind.
bitcoind fundrawtransaction: … Method not found That bitcoind has no wallet, as with the hosted proxy. Use your own bitcoind with a wallet.