Blockchain Toolkits are not a header module. They are what an app you build on Kontext can do with money, tokens, storage and compute on other networks. Describe the job in Workspace Chat (e.g. "take payment in USDC", "let members connect their Phantom wallet", "store the contracts on Filecoin"), and the generator proposes the matching toolkit. It then seeds the toolkit's Motoko module into the app's backend canister and its React hook into the frontend.
Where you work with them. Two doors lead to the same projects:
Crypto Workshop (/crypto) — the module for building on these chains, beside Agents and the Launchpad (Starter tier and up). Its rooms: the front door, the Chain Atlas (a page for each chain and interop protocol, with the Internet Computer's the deepest), Your crypto apps (each app that imports a chain toolkit's hook, with its chains, deploy state, addresses read on press, and activity), one app's page, and the Bench. Start on a recipe or chain page writes a brief that names the toolkits and hands it to the workspace's own generate lane; Add to an app uses the update lane. The Workshop builds nothing itself, and every app in it also opens in the workspace.
Workspace Chat (/workspace) — describe the job in your own words; the matching toolkit is proposed on a card.
There are two lanes, and each toolkit is in exactly one:
Lane A — in the app's own canister (38 modules). The app holds a wallet on the Internet Computer's threshold keys: secp256k1 ECDSA, BIP-340 Schnorr (incl. Taproot) and Ed25519, derived per app and per signed-in person (or one app treasury). No private key exists on any machine, and there is no custodian and no browser extension. Transactions are built and signed by the canister, and reach other chains through non-replicated HTTPS outcalls.
Lane B — the person's own wallet (16 wallet kits). The person connects MetaMask, Phantom, Xverse, Keplr, Tonkeeper and the like in the browser. They sign and pay the fee, and no key ever leaves their wallet.
Built. P2TR addresses and key-path Schnorr signing
2
Bitcoin Ordinals
Built. Inscribe (commit + reveal), hold, send; fees never spend a collectible
3
Bitcoin Runes
Built. Send whole outputs or exact amounts, and mint; rune ids by name need the platform indexer key
4
BRC-20
Transfer and mint built; balances need the platform key (UNISAT_API_KEY)
5
Stacks
Built (module + Leather / Xverse kit)
6–7
Rootstock, Mezo
Built. EVM network rows
8
Lightning
Built; needs the owner's LNbits URL and keys
9
MultiversX
Built (module + DeFi Wallet / Web Wallet kit)
10
Filecoin, native
Wallet, FIL sends and actor calls work now; storage deals need a Lighthouse key
11
Hyperliquid
Built from the app treasury; trading stays off until the owner sets guardrails
12
Decentralized compute
Built; needs the owner's provider key (Akash, Fluence, io.net or Dispersed)
13
IO Intelligence
Built; needs an IO Intelligence key (the model list is keyless)
14
Render
Render's compute network (Dispersed) is a compute provider; rendering itself has no cloud API
15
Aethir
Token only. No self-serve booking API exists, so the ATH token row is what ships
16
DePIN tokens
Built. FLT, IO, RENDER and ATH as named tokens; AKT on the Akash (Cosmos) row. FLT staking is not built
Keys an owner may supply. Each key is checked with its provider before it is kept, lives on the app's canister, and is never returned by any method. They can be entered in the app itself or on the app's page in the Crypto Workshop, which sends each one straight to the app's owner-only setter and keeps nothing in the browser. Without a key, the feature says it is not configured and names the key; it never shows an empty result.
Platform (set once for every app):UNISAT_API_KEY, used for BRC-20 balances and rune ids.
Per app, spending the owner's own accounts:
Lighthouse (Filecoin deals)
Akash Console
Fluence
io.net IO Cloud
Dispersed public + secret key
IO Intelligence
LNbits URL + invoice / admin keys
Optional: Koios (Cardano), and Hiro or Glif (higher Stacks / Filecoin limits).
Not built:
Hyperliquid trading from the person's own wallet
FLT staking
Aethir compute booking
Toolkit reference
Every toolkit an app can use, 54 in all: what it does, who holds the key, what the owner sets, the states it reports, and every canister method. Grouped by network.
App platform
Kontext Files — kontext_files
Store files a person picks (photos, logos, PDFs) in the app's own backend canister, and serve each one at a URL that an <img> tag or an outside vendor can fetch. Uploads are split into pieces so a phone photo larger than one Internet Computer message still goes through. Each file's URL is unlisted: anyone holding the URL can open it, and a person's file list shows only their own files (the owner sees all of them).
Keys and custody: No signing key. File bytes are stored in the app's backend canister. Who may upload is set by the proposal card's scope: in an app for users any signed-in person may upload; otherwise only the owner.
Owner settings: None. The upload scope comes from the proposal card when the toolkit is accepted.
What people can do: Upload a file (sent in 1.5 MB pieces, then finished); list their files with name, type, size and URL; delete a file they uploaded. The owner lists and deletes every file.
States you will see: "You are not allowed to upload here."; "The file is empty."; "The file is larger than 50 MB."; "Not your upload."; "Chunk N is missing." when a piece never arrived; "Not your file." A file that is not finished, or a URL with the wrong token, answers 404 Not found.
Defaults: 1.5 MB per piece and 50 MB per file. Files are served at https://<backend-canister>.raw.icp0.io/files/<id>-<token> (the raw domain, because the responses are not certified), with a one-year immutable cache header and open cross-origin access.
Not included: Files is offered only when the prompt asks for it explicitly or names no storage vendor; when a storage vendor is named or chosen, that vendor is used instead.
Kontext Webhooks — kontext_webhooks
Receive HTTP POSTs from a vendor (Stripe, a form service, a booking widget) at a URL on the app's own canister, and queue them for the app's code to act on. The owner enables a named source, pastes its URL into the vendor's webhook settings, and the app's own methods read and acknowledge the queued events.
Keys and custody: No signing key. Each source gets an unguessable token in its URL, and that token is the only guard.
Owner settings:kontextWebhooksEnable(source) turns a source on and returns its URL path; the name is 1–40 lowercase letters, digits or dashes, and re-enabling keeps the same token. kontextWebhooksDisable(source) turns it off: the URL stops answering and events already queued stay.
What people can do: Only the owner uses this toolkit: enable or disable a source, list sources with their URLs and received counts, read events (oldest first, optionally one source, optionally including acknowledged ones), and mark an event handled. A non-owner gets an empty list or "Only the app owner can …".
States you will see: A POST with an unknown source or a wrong token gets 404 Not found (it never says which); a body over 256,000 bytes gets 413 Body too large; an accepted event gets 200 ok. A body that is not text is stored as an empty string.
Defaults: URL https://<backend-canister>.raw.icp0.io/webhooks/<source>/<token>, accepting POST or PUT. The queue holds 2,000 events; when full, the oldest acknowledged event is dropped first, otherwise the oldest event. A page of events returns at most 200.
Phrases that propose it: "webhook", "postback", "callback url", "incoming events", "inbound events", "listen for events", "when stripe", "payment succeeded"
Not included: Vendor signature schemes (such as Stripe's signature header) are not verified; the token in the URL is the guard.
Kontext Workspaces — kontext_tenancy
Separate households, teams or client workspaces inside one app. Each person belongs to at most one workspace, with a role, and people join with invite codes. The app stamps each of its rows with the workspace it belongs to, and every list only shows rows from the viewer's own workspace.
Keys and custody: No signing key. Membership is keyed on the signed-in person's principal; anonymous visitors cannot create or join.
Owner settings: None at app level. Within a workspace, its owner and admins manage members.
What people can do: Create a workspace (the creator becomes its owner); see their workspace and role; an owner or admin mints an invite code for admin, member or viewer (never above their own role, never owner), with a number of uses; join with a code; list members with roles and join dates; an admin lists open invites, changes a member's role and removes a member; any member may leave.
States you will see: No workspace yet (the screen offers create or join); "Sign in first."; "You already belong to a workspace."; "A name is 1-80 characters."; "Only an admin can invite."; "You cannot invite at that role."; "That invite is not valid."; "That invite has been used up."; "Ownership does not change here."; "The owner cannot be removed."; "Not in your workspace."
Defaults: Four roles — owner (created the workspace), admin (invites, roles, removes members), member (reads and writes the workspace's rows), viewer (reads only). An invite with 0 uses is treated as 1; the hook asks for 1 use when none is given.
Phrases that propose it: "multi-tenant", "workspaces", "households", "organizations", "invite code", "each team", "per client", "multiple families", "roles and permissions"
Not included: Ownership of a workspace cannot be moved or changed through these methods.
Kontext Audit Trail — kontext_audit
An append-only record of who did what and when. The app's own code writes an entry after each action that matters (an approval, a payment, a delete, a role change), and nothing removes an entry. Entries can be filtered by the thing acted on (for example booking:12) or by the action (for example booking.approve).
Keys and custody: No signing key. Each entry records the principal that performed the action.
Owner settings: None.
What people can do: Read the entries they are allowed to see: the owner sees every entry; a workspace owner or admin (when Workspaces is also mounted) sees their workspace's entries; anyone else sees entries they performed themselves.
States you will see: An empty list when nothing matches the filter or the viewer may see nothing.
Defaults: Up to 20,000 entries; past that, the oldest entry is dropped. A read returns at most 200 entries, oldest first. Each entry carries id, time, who, action, subject and a free-text detail.
Download the app's own tables as CSV or JSON: a backup, or a spreadsheet for an accountant. The app declares its tables once, and the export pages through them so a large table still downloads as one file.
Keys and custody: No signing key. The owner exports everything; a workspace owner or admin (when Workspaces is also mounted) exports only their workspace's rows.
Owner settings: None. The tables offered are the ones the app lists in its own kontextExportTables function (it starts empty).
What people can do: See the list of exportable tables; download one table as CSV or JSON. The download is saved as <table>.csv or <table>.json.
States you will see: "Only the app owner or a workspace admin can export." (and an empty table list) for anyone else; "No table named X." for an unknown table.
Defaults: 2,000 rows per page; every cell is text. CSV lines end in CRLF and cells with commas, quotes or line breaks are quoted.
Phrases that propose it: "export", "csv", "backup", "back up", "download all", "download my data", "data export", "export to excel", "spreadsheet of"
Internet Computer
Kontext ICP Tokens — kontext_icp_tokens
Hold and move ICRC-1 tokens (ICP, KTX, ckBTC, ckUSDC or any ICRC-1 ledger) from the app's own canister. The app keeps a list of tokens, reads balances from each token's ledger, sends transfers the canister signs, shows a deposit address, and keeps a typed history. Every balance is a ledger reading that carries the time it was read.
Keys and custody: The app's canister holds the funds in both modes. Owner scope: one treasury on the canister's default account that only the owner moves (the deposit address is public). User scope: every signed-in person has their own wallet at a subaccount derived from their principal, and the canister signs for them. The deposit address is the standard ICRC-1 text form (canister id, checksum and subaccount).
Owner settings:kontextIcpTokensAddToken(canisterId) adds any ICRC-1 ledger after asking it for its name, symbol, decimals and fee; kontextIcpTokensRemoveToken(canisterId) takes a token off the list (funds on the ledger are untouched); kontextIcpTokensSetTokenActive(canisterId, active) pauses or resumes a token.
What people can do: See the deposit address; see the token list and the suggested ledgers an add-token picker can offer; see cached balances and refresh them from the ledgers; send a token to a principal or an ICRC-1 account, with an optional memo; read their history, newest first (the owner sees everyone's).
States you will see: "Sign in to use your wallet." (user scope); "Only the owner may use this app's treasury." (owner scope); "Token not added to this wallet."; "Token X is paused."; "Amount must be greater than zero."; "The recipient cannot be anonymous."; "A memo is at most 32 bytes."; "Insufficient X: have …, need … including the fee."; the ledger's own refusals (Bad fee, Insufficient funds, Transaction too old, Created in the future, Duplicate of block N, The ledger is temporarily unavailable); "Not an ICRC-1 ledger (…)" when adding a canister that is not one. A balance that grew between two readings is recorded as a received entry labelled "Detected on refresh".
Defaults: ICP (ryjl3-tyaaa-aaaaa-aaaba-cai) and KTX (e42cg-yyaaa-aaaaa-qdvla-cai) are on the list from the start. The add-token picker suggests ICP, KTX, ckBTC, ckETH and ckUSDC. Up to 50 tokens and 5,000 history entries. Amounts use each token's own decimals (ckUSDC has 6), never a fixed 8.
Mint, hold and transfer NFTs on the Internet Computer's own NFT standard (ICRC-7). The app's canister is the collection, so any wallet, explorer or marketplace that reads ICRC-7 recognises the tokens without knowing the app. The app can also read what a person holds in another ICRC-7 collection.
Keys and custody: No signing key. Tokens are owned by principals on the collection's own records. The proposal card's scope decides who mints: the owner only, or any signed-in person. A token is moved by its holder, and burned by its holder or the app owner.
Owner settings:kontextIcpNftSetCollection(name, symbol, description, logo, supplyCap) sets the collection's details and an optional supply cap (which cannot be set below the number already minted); kontextIcpNftUpdate(tokenId, name, description, image, attributes) edits a token's metadata.
What people can do: Mint a token with a name, description, image URL and text attributes, to themselves or to a named principal; transfer a token they hold; burn a token; see their own tokens, all tokens (paged), one token, and the collection's recent history; read what they (or a named principal) hold in another ICRC-7 collection.
States you will see: "You are not allowed to mint here."; "A token needs a name."; "The collection's supply cap of N is reached."; "No such token."; "Not your token."; "The recipient cannot be anonymous."; "Sign in to see your tokens."; "Sign in, or name the owner to look up."; "Could not read collection …" when the other collection does not answer; the standard's transfer refusals (Transaction too old, Created in the future, Duplicate of transaction N, at most 20 transfers per call).
Defaults: The collection's name comes from the app's name, and its symbol from the app name's initials (up to five letters). Standard limits published: 100 per query batch, 20 per update batch, 50 per page by default and 200 at most, 32-byte memos, a 24-hour transaction window and 2 minutes of permitted clock drift. Batch transfers are not atomic.
Frontend hook:useKontextIcpNft — Canister methods:kontextIcpNftCollection, kontextIcpNftSetCollection, kontextIcpNftMint, kontextIcpNftTransfer, kontextIcpNftBurn, kontextIcpNftUpdate, kontextIcpNftMine, kontextIcpNftAll, kontextIcpNftGet, kontextIcpNftHistory, kontextIcpNftHoldings (plus the standard icrc7_* methods and icrc10_supported_standards)
Not included: ICRC-37 approvals (letting a marketplace move a token for its holder) and an ICRC-3 certified transaction log are not built.
Kontext ICP Payments — kontext_icp_payments
Charge in ICP, ckUSDC, ckBTC or any ICRC-1 token, with no card processor. Each invoice gets its own deposit address on the app's canister, so a payment is matched to its invoice without a memo. The canister confirms payment by reading the ledger, and then moves the funds to the app's treasury.
Keys and custody: The app's canister holds each invoice's deposit account and signs the sweep to its treasury (the canister's default account). The payer pays from any wallet.
Owner settings:kontextIcpPaymentsSetSweep(on) turns the sweep to the treasury on or off.
What people can do: Create an invoice with a token, an amount as plain text ("1.5"), a memo, an order reference and a time to live; see the invoice with its deposit address, status and amount; check it against the ledger now; list their invoices, optionally by status; cancel an open invoice. Depending on the proposal card's scope, anyone may start a checkout (a signed-in payer is recorded) or only the owner issues invoices.
States you will see: open, paid, expired, cancelled. Refusals include "Only the owner may issue invoices."; "Enter an amount like 1.5 (at most N decimals)."; "Amount must exceed the ledger fee of …"; "Not an ICRC-1 ledger (…)"; "Only an open invoice can be cancelled."; "Not your invoice."; "No such invoice."; "Too many invoices; archive some first."; "Ledger call failed: …". A sweep that fails leaves the funds on the invoice's account, and the invoice is still paid.
Defaults: An invoice lasts one hour unless a time to live is given, and 30 days at most. An open invoice is re-checked every 5 seconds while its screen is open, and a timer checks the 10 oldest open invoices every minute. Sweeping is on. The amount is parsed with the decimals the ledger reports when the invoice is created. Up to 20,000 invoices.
Not included: When the prompt names a card processor or card payments (Stripe, PayPal, Square, "credit card", "apple pay" and similar), that vendor is proposed instead unless the prompt asks for this toolkit explicitly.
Kontext ICP Ledger — kontext_icp_ledger
Issue the app's own token (loyalty points, store credit, an in-game currency, a community coin) as a real ICRC-1 and ICRC-2 ledger served by the app's canister. Any ICP wallet, DEX or explorer can read it under the standard method names. The owner mints within an optional cap, holders send and burn, and fees are burned.
Keys and custody: No signing key. Balances belong to principals on the app canister's own ledger records. There is no minting account; only the owner mints.
Owner settings:kontextIcpLedgerSetToken(name, symbol, fee, logo, supplyCap) sets the token's name, symbol, transfer fee (in smallest units, burned on each transfer), logo and an optional supply cap, which cannot be below the amount already minted. kontextIcpLedgerMint(to, amount, memo) mints to a principal.
What people can do: See the token (name, symbol, decimals, fee, total supply, cap, the ledger's canister id); see their balance and their own history; send to a principal; burn their own tokens; approve a spender through the standard icrc2_approve. The owner reads the full history.
States you will see: "Only the owner may mint."; "Minting N would pass the supply cap of M."; "Amount must be greater than zero."; "The recipient cannot be anonymous."; "Insufficient balance: have N."; "Only the owner may change the token."; the standard refusals (Bad fee, Insufficient funds, Insufficient allowance, Transaction too old, Created in the future, Duplicate of transaction N).
Defaults: The name comes from the app's name and the symbol from its initials (up to five letters); 8 decimals; a fee of 0; no cap. A 24-hour duplicate window with 2 minutes of drift, 32-byte memos, and up to 50,000 history entries.
Frontend hook:useKontextIcpLedger — Canister methods:kontextIcpLedgerToken, kontextIcpLedgerMyBalance, kontextIcpLedgerMyHistory, kontextIcpLedgerHistory, kontextIcpLedgerSend, kontextIcpLedgerMint, kontextIcpLedgerBurn, kontextIcpLedgerSetToken (plus the standard icrc1_* and icrc2_* methods)
Phrases that propose it: "loyalty points", "reward points", "in-game currency", "our own token", "community coin", "issue a token", "launch a token", "tokenomics", "store credit"
Kontext ICP Pull Payments — kontext_icrc2
Charge a person again without asking again. The person approves the app once, up to an amount and optionally until a date (the ICRC-2 standard), and the app pulls the token when a renewal, a metered charge or a settlement is due. It works on any ICRC-2 ledger: ICP, ckUSDC, ckBTC or another app's token.
Keys and custody: The app's canister is the approved spender; it holds no funds of its own until a pull lands in its treasury (the canister's default account). The approval is made from the person's own account: the hook approves from the account of the person's signed-in principal, and a person paying from an outside wallet approves the app's canister id.
Owner settings: None to configure. kontextIcrc2Pull(tokenCanister, payer, amount, memo, reference) lets the owner pull an approved amount by hand; the app's own logic pulls from its own methods.
What people can do: Approve the app for an amount of a token, with an optional expiry; see what they have approved (amount, symbol, expiry); see the pulls the app has made from them, newest first (the owner sees every pull).
States you will see: "Sign in first."; "Only the owner may pull a payment from here; app logic pulls from its own methods."; "Not an ICRC-2 ledger (…)"; "The payer approved only N — ask them to approve more"; "The payer's balance is N, not enough"; "Amount must be greater than zero."; "A memo is at most 32 bytes."; "Too many pulls recorded; archive some first."; the ledger's other refusals (Bad fee, Transaction too old, Duplicate of block N, The ledger is temporarily unavailable).
Defaults: Pulls land in the treasury. Up to 20,000 pulls are recorded.
Phrases that propose it: "recurring payments", "auto-renew", "metered billing", "usage-based billing", "pay as you go", "pull payment", "approve once", "direct debit", "billed monthly", "charge automatically"
Not included: When the prompt names a card processor or a saved card (Stripe, PayPal, Chargebee, "card on file" and similar), that vendor is proposed instead unless the prompt asks for this toolkit explicitly.
Accept real Bitcoin and Ether. A person sends BTC or ETH to an address the app gives them, and it arrives as ckBTC or ckETH in their app wallet, through the Internet Computer's own minters, with no exchange and no custodian. Withdrawals go back out to a Bitcoin or Ethereum address the same way.
Keys and custody: The app's canister holds the ckBTC and ckETH. In user scope (the default) each signed-in person has their own account, the same subaccount ICP Tokens uses, so a deposit shows in the wallet they already see. In owner scope the bridge serves the treasury and only the owner uses it. Before a withdrawal the canister approves the minter from that person's account, so funds leave only by that person's own withdrawal.
Owner settings: None. The minters and ledgers are fixed.
What people can do: Get a Bitcoin deposit address; after sending, ask the minter to mint confirmed deposits; estimate a withdrawal's fees (Bitcoin fee and minter fee); withdraw ckBTC to a Bitcoin address; get Ether deposit instructions (the minter's helper contract on Ethereum and the two bytes32 arguments that route the deposit to them); withdraw ckETH to an Ethereum address; see their bridge history (the owner sees all). Amounts are entered in BTC and ETH and converted to satoshis and wei.
States you will see: "No new deposit yet."; "N deposit(s) pending: X of Y confirmations."; "The minter is already processing this account — try again in a minute."; "A withdrawal is already processing — try again in a minute."; "Amount too low — the minimum is N sats." (or wei); "Insufficient ckBTC — balance is N sats."; "Insufficient ckETH — balance is N wei."; "Not a Bitcoin address."; "Not an Ethereum address (0x + 40 hex characters)."; "The recipient address is blocked: …"; "Not enough on the ck ledger to cover the amount and fees — balance is N."; "The ckETH minter does not publish a deposit-with-subaccount helper contract right now."; "The minter is temporarily unavailable: …"; "Sign in first." (user scope) or "Only the owner may use this app's treasury." (owner scope).
Defaults: ckBTC minter mqygn-kiaaa-aaaar-qaadq-cai and ledger mxzaz-hqaaa-aaaar-qaada-cai; ckETH minter sv3dd-oaaaa-aaaar-qacoa-cai and ledger ss2fx-dyaaa-aaaar-qacoq-cai. ckETH is minted by the minter when it sees the deposit on Ethereum, with no call from the app. Up to 20,000 history events.
Not included: When the prompt names an exchange or payment gateway (Coinbase, Binance, Kraken, BitPay, MoonPay, Transak and similar), that vendor is proposed instead unless the prompt asks for this toolkit explicitly.
Kontext Threshold Key — kontext_chain_key
A signing key held by the Internet Computer's subnet, never by any one machine. It is derived per app and per signed-in person, so the app can sign for other chains without a private key existing anywhere. Every other-chain module in the app signs through it, and it is added automatically when one of those modules is accepted.
Keys and custody: Threshold keys held by the subnet: secp256k1 (ECDSA) and Schnorr (BIP-340, including Taproot, and Ed25519). A person's key is derived from a purpose label plus their principal; the app's treasury key from the purpose label alone. The same person gets the same key every time, and a different one in each app. The public methods return a compressed secp256k1 public key and a 64-byte r‖s signature, both as hex. There is no private key to show or export.
Owner settings:kontextChainKeySetKeyName(name) picks the subnet key: key_1 (production, signs for real value), test_key_1 (the IC's test key, cheaper, never for value) or dfx_test_key (a local replica).
What people can do: A signed-in person reads their public key for a purpose and signs a 32-byte hash with it. The owner reads the treasury public key and signs with the treasury key. Anyone can read which key the app uses and how many signatures it has paid for.
States you will see: "Sign in first."; "The message hash must be hex."; "An ECDSA message hash is exactly 32 bytes."; "Only the owner may change the signing key."; "Only the owner may read the treasury key."; "Only the owner may sign with the treasury key."; "Unknown key name. Use key_1 (production), test_key_1 (IC test key) or dfx_test_key (local)."; "The threshold key did not answer: …"; "Signing failed: …".
Defaults:key_1, owner-switchable. One signature on key_1 costs about 26.2 billion cycles (about 2.6 Gas Station credits); on test_key_1 about 10 billion; public-key reads are free. The canister attaches a little more and the IC refunds the difference. Public keys are cached; signatures never are.
Reads any EVM chain in the app's chain table: the native balance of any address, a contract read (eth_call) and a transaction receipt. Every read goes through the Internet Computer's EVM RPC canister (7hfb6-caaaa-aaaar-qadga-cai). The canister sends the request to every public provider URL on the chain's row and requires them to agree. With three or more URLs, two must agree; with fewer, all must. The reader holds no key and sends nothing on its own. It is also the chain table that the EVM Wallet, Cross-Chain and Hyperliquid use.
Keys and custody: none. The reader signs nothing. Its methods are for signed-in people ("Sign in first."), because each read spends the app's cycles.
Owner settings:
kontextEvmRpcPutChain(chain) adds or replaces a chain row. A row has these fields:
chain id and name;
native symbol and decimals;
RPC URLs, which must be https://;
explorer transaction prefix;
legacyFees, for a chain without EIP-1559 base fees;
addressPrefix, "0x", or "xdc" on XDC;
testnet.
kontextEvmRpcRemoveChain(chainId) removes a row.
kontextEvmRpcRequest(chainId, method, paramsJson) sends a raw JSON-RPC request and returns the result as JSON text. The reply is capped at 16,384 bytes.
All three are owner-only ("Only the owner may change the chain table.", "Only the owner may send raw RPC requests.").
What people can do:
list the chains the app can reach, with name, symbol, decimals, explorer and testnet flag;
read the native balance of any address, shown by the chain's decimals;
read a contract (return data as hex);
read a receipt (status, block, gas used, logs). The receipt is null while the transaction is still pending, and the hook polls every 6 seconds until it lands.
States you will see:
"Sign in first.";
"Unknown chain id N. Add the chain first.";
"The providers disagreed on ; try again.";
"RPC error: …" for the chain's own answer, such as a revert;
"The EVM RPC canister did not answer: …". When the RPC canister cannot be reached, a read falls back to the row's first URL through one provider and one node. If that also fails, the error says "Direct read from failed too". A broadcast never falls back.
Fee and gas quotes (eth_gasPrice, eth_maxPriorityFeePerGas, eth_estimateGas) are the exception to strict agreement. When at least two providers answer and the highest quote is at most twice the lowest, the highest is used. A wider spread is refused.
kontextEvmRpcStats counts reads and fallbacks.
Defaults: 37 chain rows with public provider URLs and no provider keys. The owner can add rows or change them. The rows are:
Mainnets: Ethereum (1), Base (8453), Arbitrum One (42161), OP Mainnet (10), Polygon (137), BNB Smart Chain (56), Avalanche C-Chain (43114), Linea (59144), XDC Network (50), Hedera EVM through its JSON-RPC relay (295), Z Chain (9369), zkSync Era (324), Abstract (2741), Scroll (534352), Mantle (5000), Blast (81457), Unichain (130), World Chain (480), Ink (57073), Soneium (1868), Zora (7777777), Taiko (167000), opBNB (204), Gnosis (100), Celo (42220), Sonic (146), Cronos (25), Berachain (80094), Kaia (8217), HyperEVM (999), Sei EVM (1329), Monad (143), Filecoin FEVM (314), Rootstock (30) and Mezo (31612).
Testnets: Sepolia (11155111) and Base Sepolia (84532).
Legacy fees: XDC and Rootstock use legacy (type-0) fees.
Cost: a read attaches about 2 billion cycles plus about 1.5 billion per provider URL, and the RPC canister refunds what it does not spend.
Not included: broadcasting from the reader. Sends belong to the EVM Wallet.
Kontext EVM Wallet — kontext_evm
An EVM wallet inside the app's canister. Each signed-in person, or the app's treasury, gets one address that works on every chain in the table. The app can show native, ERC-20 and ERC-721 balances and send all three. Transactions are built, signed with the subnet's threshold key and broadcast by the canister, so there is no private key, custodian or browser extension. Selecting the wallet also mounts the threshold key and the EVM Reader it runs on.
Keys and custody:
The key is a threshold secp256k1 ECDSA key (derivation purpose kontext-evm), one per signed-in person.
An owner-scoped app has one treasury key that only the owner may use ("Only the owner may use this app's treasury wallet.").
Addresses are shown EIP-55 checksummed (0x…), except on XDC, where they are shown lowercase with an xdc prefix.
Owner settings: the wallet has none of its own. Chains are added, changed and removed with the EVM Reader's kontextEvmRpcPutChain and kontextEvmRpcRemoveChain, and a new row is usable by the wallet at once.
What people can do:
Address and balances:
see their address on a chain, to show or share as a QR;
see their native balance (ETH, POL, BNB, AVAX, XDC, HBAR, RBTC, Z and the rest), shown by the chain's decimals;
see an ERC-20 balance by token contract, with the token's own symbol and decimals.
Sends:
send the native coin, entered as a human amount such as "0.05";
transfer an ERC-20 (transfer);
transfer an ERC-721 they hold (safeTransferFrom).
NFTs and tracking:
read who owns an ERC-721 token and its metadata URI;
follow a send's receipt;
see their own send history, newest first (the owner sees every one).
States you will see:
A send returns a transaction hash and is pending until a receipt lands. The receipt is null until the transaction is mined, and the hook links the hash to the chain's explorer.
"Sign in first." / "Only the owner may use this app's treasury wallet."
"Enter a valid amount." (checked in the hook)
"Unknown chain id N." / "Not a valid address: …" / "Not a token contract address." / "No such token."
"The transaction would fail: …", when the gas estimate for a token or NFT call reverts, before anything is signed.
"Insufficient for the value plus gas."
"Nonce too low: a transaction with this nonce already exists. Try again." / "Nonce too high: an earlier transaction is still pending."
"The providers disagreed about the broadcast; check the transaction hash before retrying."
"Could not recover the signer from the signature; nothing was broadcast."
Defaults: the Reader's 37 chain rows, which the owner can change. Fees are worked out as follows:
Gas limit: a plain transfer uses 21,000. A token or NFT call uses the network's estimate plus 20%.
EIP-1559 chains: the maximum fee is twice the base fee plus the tip. The tip is read from the chain, with 1.5 gwei used when the chain will not quote one.
Legacy chains (XDC, Rootstock), or a block with no base fee: the transaction is priced by eth_gasPrice.
Cost: a send costs one threshold signature (about 26 billion cycles on key_1) plus four to six quorum reads.
Named tokens:
On Z Chain (chain 9369, native coin Z):ZCHAIN_TOKENS names MEOW (0x6ce4a22A…3113) and vMEOW, its voting wrapper (0x8C942834…189D), both 18 decimals.
On Ethereum:EVM_KNOWN_TOKENS names the DePIN tokens FLT (Fluence), ATH (Aethir) and RENDER (Render's Ethereum token), all 18 decimals.
Elsewhere: IO (io.net) and Render's main token are Solana SPL mints, named in the Solana toolkit.
Bitcoin-aligned chains: Rootstock is chain 30 (gas in RBTC), and Mezo is chain 31612 (gas in BTC).
Not included: ERC-1155. The module handles native coins, ERC-20 and ERC-721. ERC-1155 balances and transfers are in the EVM wallet kit, from the person's own wallet.
Kontext Cross-Chain — kontext_evm_interop
Moves value and messages between EVM chains from the app's own EVM Wallet, and from an EVM chain to Solana or Aptos through Chainlink CCIP. It also reads Chainlink and Pyth prices and resolves ZERO Name Service (ZNS) names on Z Chain.
Every contract address comes from one verified address book. A transfer is recorded with its source hash and a status. A job that runs every minute moves open transfers forward, and a Refresh does the same on demand. The destination leg is the app's own act where the protocol needs one (CCTP, Wormhole), because the same threshold key holds the same address on every EVM chain.
Keys and custody: the EVM Wallet's key and the same holder rule. Each signed-in person sends from their own address, or in an owner-scoped app only the owner sends from the treasury. Quotes and reads need only a signed-in person.
Owner settings:kontextEvmInteropPutChain(row) adds or replaces a chain row in the address book ("Only the owner may change the interop book."). A row carries:
its USDC address;
CCTP domain and contracts;
LayerZero endpoint id;
Wormhole chain id, core and token bridge;
CCIP selector and router;
Axelar name, gateway and gas service;
Hyperlane domain and Mailbox;
Chainlink feeds by pair;
the Pyth contract.
A chain the wallet sends on must also be in the EVM Reader's chain table.
What people can do, by protocol:
Circle CCTP (V2): send native USDC from one chain to another (amount in USDC's 6 decimals; the recipient defaults to the sender's own address). The canister approves USDC if needed, burns it with depositForBurn at standard finality, fetches Circle's attestation from iris-api.circle.com, then mints on the destination with receiveMessage. Statuses: burning, then attesting, then minted; attested means the attestation arrived but the mint failed and will be retried.
Chainlink CCIP, EVM to EVM: quote the fee (kontextEvmInteropCcipFee) and send a message, optionally with one token, to a receiver contract on another chain, with the fee paid in the native coin and the router's default extra args. The transfer is recorded as sent with the note to track the source hash on ccip.chain.link. The app does not read CCIP delivery itself.
Chainlink CCIP, EVM to Solana or Aptos:kontextEvmInteropCcipDestinations lists solana and aptos, and a send can be quoted and made to either.
To Solana: the receiver is the receiving program (base58), or empty for a token-only transfer. The gas limit is compute units, which must be 0 for a token-only transfer. tokenReceiver is the wallet (not its token account), and there are at most 64 accounts plus a writable bitmap.
To Aptos: the receiver is a 0x module or wallet address, and the gas limit is destination gas.
It is recorded as sent and tracked on ccip.chain.link.
Chainlink CCIP, Solana or Aptos to EVM (source legs): these live in the Solana and Aptos toolkits, not here.
From Solana: data messages paid in SOL (kontextSolanaCcipFee, kontextSolanaCcipSend), and one SPL token amount through a CCIP token pool (kontextSolanaCcipTokenFee, kontextSolanaCcipSendToken).
From Aptos: data messages (kontextAptosCcipFee, kontextAptosCcipSend).
LayerZero V2 (OFT): quote (nativeFee, lzTokenFee) and send an OFT token to another chain by endpoint id. An OFT adapter that locks an existing ERC-20 is approved first. The minimum received is 99% of the amount. The send carries the empty type-3 options (0x0003): an OFT with enforced options accepts them, and the method takes no options of its own for an OFT that needs extra executor gas. Status starts INFLIGHT and then follows LayerZero Scan's own status name, with the destination hash when it lands.
Wormhole token bridge: bridge a token (transferTokens), or the native coin when no token is given (wrapAndTransferETH), paying the core contract's message fee. The transfer is recorded as awaiting_vaa ("Waiting for the guardians to sign the VAA."). The minute job then reads the sequence off the source receipt, fetches the signed VAA from Wormholescan and calls completeTransfer on the destination from the same wallet: the status becomes redeemed with the destination hash, or signed if the redemption failed (it is retried). A transfer recorded as sent by an earlier version of the module is picked up the same way once the app is updated.
Axelar GMP: quote gas through Axelarscan (kontextEvmInteropAxelarGasQuote; the hook's default gas limit is 200,000) and call a contract on another chain with callContract. Gas is paid in a second transaction (addNativeGas, by the call's log index) because a canister cannot batch two calls into one. Statuses: called, then gas_paid, then Axelarscan's own status, with the destination hash when executed.
Hyperlane: the source chain's Mailbox quotes the fee (quoteDispatch), and the canister dispatches a message body to a contract on another chain that implements handle(). The message id is read from the source receipt. Delivery is read from the destination Mailbox's own delivered(messageId): the status is INFLIGHT until the Mailbox reports it, then delivered.
Chainlink price feeds: read a pair such as "ETH/USD" from the book (kontextEvmInteropPrice), or any feed by address (kontextEvmInteropFeedPrice). The price is scaled by the feed's decimals and shows when it last updated.
Pyth prices: read a price by 32-byte price id on a chain. It is the last price pushed on-chain, so the hook reports its age in seconds, and it can be old.
ZNS reads (Z Chain): resolve "wilder", "wilder.frank" or "0://wilder.frank". The result says whether the name is registered and gives its owner, resolver, the address and text it points to, and the domain NFT's token URI. An unregistered name answers registered: false, never an empty owner.
Transfers: list their own transfers, newest first (the owner sees all); Refresh one of their own ("Not your transfer.").
States you will see:
A transfer's done flag is true once its status is one of: minted, redeemed, delivered, executed, failed, error or expired, and for CCIP sent (CCIP delivers on its own; follow it on ccip.chain.link). A Wormhole transfer is done only once redeemed.
The minute job moves up to five open transfers a tick. After about two days of attempts it marks a transfer expired ("Gave up after two days; the source hash is still yours to check.").
Refusals, all given before anything is signed:
" is not available on ." or "Hyperlane is not deployed on .";
"The Wormhole token bridge is not deployed on .";
"No interop row for chain N.";
"No feed is known on ; add one with the feed's address.";
"Pyth is not deployed on in the book.";
"Unknown CCIP destination …";
"A Solana receiver takes at most 64 accounts.";
"A token-only transfer to Solana must set gasLimit (compute units) to 0.";
"The router did not answer getFee — the lane may not be open from .";
"Amount must be positive.";
"Approval failed: …";
"Not a ZNS name: …".
Defaults: the address book, which the owner can add to or change, holds eight chains: Ethereum, Base, Arbitrum One, OP Mainnet, Polygon, BNB Smart Chain, Avalanche C-Chain and Linea.
All eight: USDC, LayerZero, Wormhole core, CCIP, Axelar, Hyperlane and Pyth.
CCTP: every chain except BNB Smart Chain.
Wormhole token bridge: every chain except Linea.
Chainlink feeds: ETH/USD on every chain; Ethereum also has BTC/USD, USDC/USD and LINK/USD.
Pyth price id: the book names one, ETH/USD.
CCIP destinations outside the EVM: Solana and Aptos.
ZNS: its contracts on Z Chain (9369).
Explorer links (transferExplorerUrl):
LayerZero Scan, Wormholescan, ccip.chain.link and Axelarscan;
Phrases that propose it: "bridge usdc", "cctp", "layerzero", "wormhole", "ccip to solana", "axelar", "hyperlane", "zns name", "chainlink price", "pyth"
Not included:
ZNS registration, and looking up a name from an address. The registry is indexed by hash only.
The Hyperlane book has no rows for XDC, Hedera or Z Chain.
Chainlink Automation and Functions.
Kontext Hyperliquid Trading — kontext_hyperliquid
Trades Hyperliquid perpetual futures from the app's own treasury account. The app can read markets and mid prices and see the account's value, positions and open orders. It can also place limit and market orders, cancel resting orders and withdraw USDC. Trading is off until the owner sets guardrails, and the canister enforces them rather than the screen. Every order the owner did not place waits for the owner's approval unless the owner switches approval off.
Keys and custody:
One trading account: the app's EVM treasury key, a threshold secp256k1 key (purpose kontext-evm, no person), so its address is the same as the EVM Wallet's treasury address. Selecting Hyperliquid brings in the EVM Wallet with owner scope, which is how the owner funds the account.
Signing: orders, cancels and leverage changes are signed as Hyperliquid "L1 actions" (msgpack, then an EIP-712 Agent signature), and withdrawals as EIP-712 Withdraw. Both are signed by the subnet; no key exists anywhere.
Owner settings:
kontextHyperliquidSetGuardrails(g): "Only the owner may change the trading guardrails."
tradingOn: the master switch.
maxOrderCents and dailyCents: the per-order and daily USD notional ceilings, in cents. The per-order ceiling cannot be larger than the daily one.
markets: the coins allowed, such as ['BTC','ETH'].
maxLeverage: at most 50x.
requireApproval: on by default.
slippageBps: for market orders, 1 to 1,000 basis points.
Trading cannot be turned on until both ceilings, at least one market and a maximum leverage are set.
kontextHyperliquidSetNetwork(testnet): switches between mainnet and testnet, and clears the cached markets and the leverage the canister set.
kontextHyperliquidApprove(id) / kontextHyperliquidReject(id): decide an order that is waiting. An approved order is checked again against the guardrails and the day's total at that moment.
kontextHyperliquidCancel(id): cancels an order resting on the book.
kontextHyperliquidWithdraw(destination, amount): sends USDC to an Arbitrum (Ethereum) address, at most 6 decimals, less Hyperliquid's $1 fee.
What people can do:
Reads:
see the account address, markets (name, size decimals, maximum leverage, delisted) and a coin's mid price;
see the account value, withdrawable USDC, margin and positions (size, entry price, unrealized PnL, leverage, liquidation price), and open orders;
read any address's Hyperliquid account.
Orders:
place an order: coin, buy or sell, a price or "market", size, reduce-only, and time in force Gtc, Ioc or Alo. A market order is IOC priced at the mid plus or minus the slippage when it executes.
see order history (the owner sees everyone's; others see their own).
Who orders: in the default owner scope only the owner orders ("Only the owner may trade from this app."). In user scope, signed-in people may propose orders, and those wait for approval while it is on. The owner's own order is its own approval.
States you will see:
Order statuses:
awaiting approval, rejected, refused, resting, filled, cancelled and error;
unknown, which means the exchange's reply was lost, so check open orders.
An unfunded account: a fresh account shows an account value of "0" and is not funded yet. Fund the address with USDC through Hyperliquid's Arbitrum bridge.
Refusals, each naming the fence it hit:
"Trading is off. The owner turns it on after setting its limits.";
"Trading has no limits yet. The owner sets them first.";
" is not an allowed market (allowed: …).";
" is delisted; only reduce-only orders may close a position.";
"Hyperliquid refuses an order worth less than $10.";
"This order is worth $X, over the $Y per-order ceiling.";
"This order ($X) would pass today's $Y ceiling ($Z already used).";
prices off the exchange's tick rule (at most 5 significant figures and 6 minus the size decimals) and sizes off the size decimals, refused before signing;
"Hyperliquid has no perpetual market named …";
"Hyperliquid refused the order: …", in the exchange's own words.
Reduce-only orders skip the notional ceilings and the $10 minimum, but never the switch or the market list.
Leverage: before the first order on a market, the canister sets the market's leverage to cross at the lower of the owner's maximum and the market's own.
The daily total: counted per UTC day and committed before the order is sent, so a lost reply does not free room.
Defaults:
Trading: off, with approval required, slippage 100 basis points and no ceilings, markets or leverage.
Network: mainnet (api.hyperliquid.xyz); testnet is api.hyperliquid-testnet.xyz.
Market cache: the market list is cached for 10 minutes.
Phrases that propose it: "hyperliquid", "hyperliquid trading", "trade on hyperliquid", "hyperliquid bot", "perpetual futures", "perps trading", "trade perps", "perp positions"
Not included: trading from the person's own wallet. A browser wallet refuses the exchange's chainId-1337 typed data, so that path needs an ApproveAgent signature naming an agent key, which is a separate decision.
Bitcoin and its layers
Kontext Bitcoin Wallet — kontext_bitcoin
A native Bitcoin wallet inside the app's canister. Each signed-in person, or the app's treasury, gets a real bc1 address with an on-chain balance. Sends are built and signed by the canister and broadcast by the Internet Computer. There is no bridge, no wrapped token and no custodian, and no HTTPS outcall: balance, UTXOs, fees and broadcast all go through the IC's Bitcoin API on the management canister.
Keys and custody: a threshold secp256k1 ECDSA key per signed-in person (derivation purpose kontext-bitcoin), or in an owner-scoped app one treasury key that only the owner may use ("Only the owner may use this app's treasury wallet."). The address is native SegWit P2WPKH: bc1q… on mainnet, tb1q… on testnet4, bcrt1q… on regtest.
Owner settings:kontextBitcoinSetNetwork(network) switches between #mainnet, #testnet (Bitcoin testnet4) and #regtest (a local replica). Switching clears the cached keys, so addresses are re-derived for the new network.
What people can do:
see their address and confirmed balance (one confirmation);
read the network's current fee rate in sat/vB;
send BTC to a SegWit (bc1q…) or Taproot (bc1p…) address;
read the balance of any Bitcoin address;
see their own send history (the owner sees every holder's).
States you will see:
"Sign in first." for anonymous callers;
"Amount is below the dust limit (546 satoshis).";
an address that is not SegWit or Taproot, or whose checksum or key is wrong, is refused before anything is signed;
an address for another network is refused ("That address is for another network…");
"Insufficient confirmed bitcoin: N more satoshis needed (amount plus fee).";
"The Bitcoin API did not answer…" or "The Bitcoin API rejected the transaction…".
A sent transaction is recorded with status sent, and the txid is unconfirmed until the network confirms it. The hook links it to mempool.space to check.
Defaults: mainnet, owner-switchable to testnet4 or regtest. The fee is the median of the network's fee percentiles, never below 1 sat/vB. If the percentiles cannot be read, it falls back to 2 sat/vB. Coins are chosen largest-first from confirmed UTXOs, and change under 546 satoshis goes to the fee. Every transaction input needs its own threshold signature, so a send that spends three UTXOs signs three times.
Phrases that propose it: "bitcoin wallet", "send btc", "native bitcoin", "pay out in bitcoin", "bitcoin treasury", "sats", "segwit", "bc1", "utxo", "bitcoin testnet"
Not included: sends to legacy (1…, 3…) addresses, and sends to future SegWit versions (coins sent there cannot be spent yet). There is no refresh method: history keeps sent, and the explorer link shows whether the transaction confirmed.
Uses Bitcoin for more than payments, from the app's own wallet. Each signed-in person, or the treasury, gets a Taproot vault. From the vault an app can:
make an ordinals inscription on Bitcoin itself, from any content type (commit and reveal);
send inscriptions;
send and mint runes;
read BRC-20 balances, and inscribe BRC-20 transfers and mints.
Fees are paid from the app's Bitcoin wallet. A fee is never paid from an output that carries an inscription or a rune. What each output holds is read from ord.
Keys and custody:
Two threshold keys per signed-in person, or one pair for an owner-only treasury.
The vault is a BIP-86 Taproot (P2TR, bc1p…) address on a threshold BIP-340 Schnorr key (purpose kontext-ordinals).
The payment address is the Bitcoin Wallet's own P2WPKH key (bc1q…, purpose kontext-bitcoin), so one BTC balance pays for both toolkits.
Key-path spends are signed with the subnet applying the BIP-341 Taproot tweak (signSchnorrTaproot). An inscription's reveal is signed on the script path (signSchnorr). Payment inputs are signed with ECDSA.
Owner settings:
kontextOrdinalsSetNetwork(testnet) switches between mainnet (false) and Bitcoin testnet4 (true).
kontextOrdinalsSetEndpoints(ord, indexer) points the module at another ord server and another indexer route. Both must be https:// ("Endpoints must be https."), and an empty string leaves that endpoint unchanged. The network switch does not change either endpoint.
What people can do:
Vault:
see the vault and payment addresses;
see what the vault holds: inscriptions and rune totals, per output, the newest 40 outputs;
look up any inscription by id.
Inscriptions:
inscribe content (a content type plus a body of up to 60,000 bytes) into the vault or to a Taproot address;
send one inscription to a Taproot address.
Runes:
send runes by name. Whole outputs move by pointer. A partial amount moves by edict, which needs the rune id (block:tx), given or looked up by name. The rest returns to the vault.
mint one unit of an open rune's terms into the vault, by rune id.
BRC-20:
read a ticker's balance (available, transferable, overall);
inscribe a transfer (step one), then send that inscription once its reveal confirms (step two);
inscribe a mint.
History:
see transaction history, with status read from mempool.space.
States you will see:
Transaction status: a transaction starts as sent, then refreshes to pending or confirmed. A txid mempool.space does not know stays sent.
Vault view:unindexed counts new outputs ord has not indexed yet, whose contents are unknown. more means the vault has over 40 outputs.
Refusals:
"The platform's Bitcoin indexer is not configured (UNISAT_API_KEY): BRC-20 balances and rune ids are unavailable until it is." Never a zero balance.
"Send inscriptions and runes to a Taproot (bc1p…) address…"
"Not enough bitcoin in the app's Bitcoin wallet (…) to pay for this…", which counts the outputs skipped because they carry inscriptions or runes or are not indexed yet.
"Not enough spendable bitcoin among the first twelve outputs checked…"
an inscription "is not in this wallet".
sending is refused when the output holding the inscription carries other inscriptions or runes.
"A BRC-20 ticker is 4 or 5 characters."
"Not enough TICK available to transfer…"
"A rune id is block:tx, e.g. 840000:3."
"The commit … was broadcast but the reveal was refused…", when only the first half of an inscription landed.
Defaults:
Network: mainnet.
ord: https://ordinals.com, read through its keyless recursive /r/ endpoints.
Indexer: the platform route https://za.kontext.network/api/bitcoin-indexer.
Transaction status: mempool.space.
Postage: 546 satoshis on each collectible output.
Fees: the network's median fee rate.
The network and both endpoints are owner-configurable.
The platform indexer route (ZA):
BRC-20 balances and rune ids do not exist on Bitcoin itself; only an indexer knows them. So they come from /api/bitcoin-indexer on ZA (zoeAssistant/src/bitcoinIndexerRoutes.ts).
The route calls the UniSat Open API on one platform key, UNISAT_API_KEY. The key is set for the platform, never per app.
It answers four fixed questions: one ticker's BRC-20 balance, every BRC-20 an address holds, a rune's id by name, and every rune an address holds. The lists cover the first 100. /status reports whether the key is configured.
Networks: mainnet, testnet (testnet4) and signet.
Answers are cached across apps. Each upstream call has a 12-second deadline.
Without the key, every question answers HTTP 503 with the key's name, which the canister and the Bitcoin wallet kit report as not configured. A rate limit from UniSat is reported as such.
Not included: inscriptions or runes sent to non-Taproot addresses; inscription bodies over 60,000 bytes (every broadcast byte costs cycles).
Kontext Lightning Payments — kontext_lightning
Lightning payments through the owner's own LNbits wallet:
Receiving: people the app admits ask for bolt11 invoices, see them as a QR, and watch them until they are paid or expire.
Paying: the owner pays invoices from the same wallet, inside per-payment and daily limits that the canister enforces.
The Internet Computer has no native Lightning, because a Lightning node holds channel state and must stay online to route. So the canister drives a wallet on an LNbits instance the owner chooses (their own, a hosted one, or demo.lnbits.com while building) over LNbits' REST API. Every call is a non-replicated outcall, so one invoice or one payment is one request.
Keys and custody:
The owner's LNbits wallet holds the funds, and LNbits holds the channels.
The wallet's invoice key (create invoices, read the wallet) and admin key (spend) are kept on the app's canister. No method returns either one. Stats say only whether the wallet is connected and whether paying is possible.
No threshold key is involved.
Owner settings:
kontextLightningSetup(url, invoiceKey, adminKey) connects the wallet. The URL must start with https://, and the invoice key is required. Each key is checked by reading the wallet with it. A pair that names two different wallets is refused. An empty admin key keeps the app receive-only.
kontextLightningDisconnect() forgets the URL and both keys.
kontextLightningSetLimits(maxPaySat, dailyPaySat) sets the per-payment and daily ceilings in sats. The per-payment limit cannot be larger than the daily one.
kontextLightningBalance() reads the wallet's name and balance. It is owner-only.
What people can do:
Everyone the app admits:
ask for an invoice of N sats, with an optional memo of up to 639 characters and an optional expiry;
decode any bolt11 to see its amount, expiry and description;
refresh and list their own invoices.
In a user-scoped app that means every signed-in person. In an owner-scoped app only the owner asks for invoices.
The owner only:
pay a bolt11 from the wallet.
States you will see:
Entry status: each entry is pending, paid, expired (an invoice nobody paid in time), failed, or unknown. Unknown is a payment whose reply was lost; refresh asks LNbits what happened. Nothing is shown as paid unless LNbits says so.
Not set up:
"Lightning is not set up: the owner connects an LNbits wallet first."
"This app is receive-only: the owner has not given it the wallet's admin key."
"Payments are off until the owner sets a per-payment and a daily limit."
Payment refusals, each named before the admin key is used:
"This invoice names no amount…"
"This invoice has expired. Ask for a fresh one."
over the per-payment limit;
"Paying N sats would pass today's …-sat limit…"
"Not funded: the wallet holds N sats and this invoice asks …"
"This invoice was already paid (or is being paid) from this app…" A payment hash already paid or in flight is never paid twice.
Routing: "LNbits could not route the payment."
Defaults:
No instance is connected until the owner sets one up.
Paying is off until both limits are set.
An invoice expires after 3,600 seconds unless another expiry is given, capped at 7 days.
The daily limit resets at 00:00 UTC. Paid, pending and unknown payments count against it, and failed ones do not. The amount is committed against the day before the payment call, so a lost reply cannot free room for a second payment.
Phrases that propose it: "lightning payments", "lightning invoice", "lightning tip jar", "accept lightning", "pay with lightning", "bolt11", "lnbits", "lnurl", "sats over lightning", "lightning address"
Not included: IC-native Lightning (there is none); paying an invoice that names no amount (an open amount cannot be checked against the limits).
Kontext Stacks Wallet — kontext_stacks
A wallet for Stacks, Bitcoin's smart-contract layer, inside the app's canister. Each signed-in person, or the treasury, gets an SP address. The app can:
send STX;
read and send SIP-010 tokens (such as sBTC or ALEX) and SIP-009 NFTs;
call any Clarity contract.
Every token send carries an exact post-condition, so a contract cannot move more than the send says. Transactions go through the Stacks node API with no private key anywhere and no browser extension. For people who should sign with their own Leather or Xverse wallet, see the Stacks wallet kit (kontext_stacks_connect, Lane B).
Keys and custody:
A threshold secp256k1 key per signed-in person, or one treasury key only the owner may use.
The address is c32check: SP… on mainnet, ST… on testnet.
Transactions are SIP-005 standard single-signature. The key signs the presign sighash, and the txid is SHA-512/256 of the signed bytes.
Owner settings:
kontextStacksSetNetwork(testnet) switches between mainnet (false) and testnet (true).
kontextStacksSetEndpoint(url, apiKey, feeCapMicroStx) sets three things:
url: the owner's own node API endpoint, which must be https. It is tried before the public one.
apiKey: sent as x-api-key to that endpoint and to Hiro's endpoints. A Hiro key raises the rate limits.
feeCapMicroStx: the most a transaction may pay in fees. 0 keeps the current cap.
An empty url or apiKey clears it.
What people can do:
Balances:
see their address and STX balance: spendable, locked in stacking, and whether the address is funded;
read any Stacks address's balance.
STX:
send STX with an optional memo of up to 34 bytes.
Tokens and NFTs:
read a SIP-010 token's symbol, name, decimals and asset name from the contract;
read their balance of that token;
send it;
send a SIP-009 NFT they own. Ownership is read first.
Contracts:
call any public Clarity function. It runs in deny mode unless the caller lists post-conditions or passes allow mode, with optional STX attached.
run a read-only function, which the node runs for free.
History:
see their transaction history.
States you will see:
Not funded: an address that has never received STX. "This wallet (…) has never received STX, so it cannot pay a fee: send it some STX first." It is never shown as an empty wallet that could pay.
Transaction status: a transaction is pending until a block holds it. Then it is success, abort_by_response or abort_by_post_condition, or dropped_…. Stacks has no dry run for a write, so a call can still abort on-chain, and the fee is then spent.
Refusals:
"The network asks … STX in fees, above the … STX cap the owner set."
"Not enough STX: this needs …"
"Not enough TOKEN: …"
"Token N is not yours…"
"The memo is longer than 34 bytes."
"Not a Stacks address (SP…/ST…)"
"Stacks refused the transaction: …", with the node's reason.
"The Stacks API is rate-limiting this canister (HTTP 429). The owner can set a Hiro API key with the endpoint setting."
Defaults:
Network: mainnet.
Endpoints: https://api.hiro.so, and https://api.testnet.hiro.so on testnet.
Fee cap: 100,000 µSTX (0.1 STX).
Fee: the node's low-tier estimate.
Explorer links go to explorer.hiro.so.
The known tokens in the hook are sBTC (SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token) and ALEX (SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-alex). Any other SIP-010 contract works by its id.
The network, the endpoint and the fee cap are owner-configurable.
An app gets a Solana wallet held on the Internet Computer's threshold Ed25519 key. People can see their address, hold and send SOL and SPL tokens, and follow each send until the cluster confirms it. Every read and broadcast goes through the IC's SOL RPC canister, where several providers must agree. The same account can also send Chainlink CCIP messages and CCIP-pooled SPL tokens to eight EVM chains, paying the fee in SOL.
Keys and custody: threshold Ed25519 (Schnorr #ed25519, no pre-hash); one address per signed-in person, or, when the app is built with an owner scope, one treasury address only the owner can use. The address is the base58 public key. No private key exists anywhere and no browser extension is needed.
Owner settings:kontextSolanaSetCluster(devnet) switches between Mainnet (false) and Devnet (true). kontextSolanaSetRpcUrls(urls) replaces the RPC canister's default providers with the owner's own JSON-RPC endpoints, which then must agree; every URL must start with https:// or the call is refused, and an empty list returns to the defaults.
What people can do:
Wallet: see their address, their SOL balance, and the SOL balance of any address.
SOL: send SOL to a base58 address.
SPL tokens: read a balance by mint (with the token's decimals) and send to a wallet address; the recipient's associated token account is created in the same transaction when missing.
Chainlink CCIP to EVM: quote and send a data message (up to 256 bytes); quote and send an SPL token that has a CCIP pool on Solana (LINK today), approve and send in one versioned transaction.
Status: a list of their own sends, newest first (the owner sees every send), and a re-read of one send's status.
States you will see: a send is sent until the cluster reports processed, confirmed or finalized; failed: … carries the chain's error and unknown means the cluster has not seen it (or dropped it). A token balance for a mint the person never held is an error, never zero. CCIP sends refuse before signing with "Not funded: …" when SOL is under the fee plus 5,000 lamports, or the token balance is under the amount. When providers disagree: "The Solana providers disagreed on … ; try again." Anonymous callers get "Sign in first."
Defaults: Mainnet, through the SOL RPC canister tghme-zyaaa-aaaar-qarca-cai with its default providers and a two-of-three agreement; owner-configurable (Devnet, or custom https endpoints). The hook names four mints: USDC, IO (io.net), RENDER and ATH (Aethir). CCIP selectors in the hook: Ethereum, Optimism, BNB, Polygon, Base, Arbitrum, Avalanche and Linea. Fee is 5,000 lamports per signature.
Phrases that propose it: "solana wallet", "send sol", "spl token", "usdc on solana", "ccip from solana", "solana to ethereum", "bridge link from solana", "render token", "io.net token", "lamports"
Not included: CCIP token pools that ask the router to derive accounts on-chain (the CCTP USDC pool) are refused by name; the app never shows a list of CCIP chains or tokens it has not read. This module has no NFT methods (the Solana wallet kit can gate on one mint and send a classic NFT; listing a wallet's NFTs or gating a whole collection needs a DAS indexer key). NFT minting from the app is not built on Solana.
Kontext Stellar Wallet — kontext_stellar
An app gets a Stellar wallet held on the Internet Computer's threshold Ed25519 key. People can see their G… address, hold XLM and issued assets such as USDC, and pay other accounts with an optional text memo. A first XLM payment of at least 1 XLM to an account that does not exist yet creates it. Reads and submission go through Horizon over the IC's HTTPS outcall.
Keys and custody: threshold Ed25519; one G… address per signed-in person, or one owner-only treasury address. Stellar signs the transaction hash with plain Ed25519, which is what the IC key produces. No private key exists anywhere and no browser extension is needed.
Owner settings:kontextStellarSetNetwork(testnet) switches between the public network (false) and testnet (true). kontextStellarSetHorizon(url) points the wallet at another Horizon server; it must be https:// ("The Horizon URL must be https."), and an empty string returns to the network's default.
What people can do:
Wallet: see their address and every balance they hold (XLM and issued assets), and the balances of any G… address.
Payments: send XLM (native) or an issued asset written as CODE:GISSUER… to a G… address or a muxed M… address, with an optional text memo of up to 28 bytes.
Status: a list of their own payments, newest first (the owner sees every one), and a re-check of one payment with Horizon.
States you will see: an empty balance list means the account is not funded yet; it needs 1 XLM to exist. Sending from such a wallet is refused before signing: "This wallet (G…) is not funded yet — it needs at least 1 XLM to exist on Stellar." A payment to an account that does not exist is refused unless it is at least 1 XLM of XLM to a plain G… address; an issued asset to a new account is refused with "send it at least 1 XLM first". Horizon's rejection codes are passed through by name ("Stellar rejected the transaction: tx_bad_seq", "op_underfunded" and the like). A payment is sent until Horizon reports it in a ledger as confirmed, or failed: the network rejected it; when Horizon times out waiting (HTTP 504) the payment stays sent and a re-check asks again.
Defaults: the public network through https://horizon.stellar.org (testnet: https://horizon-testnet.stellar.org); both owner-configurable. Fee per operation is the ledger base fee (100 stroops) raised to Horizon's recent 80th percentile, capped at 0.01 XLM. Amounts are stroops, 7 decimals.
An app gets a Cosmos-SDK wallet held on the Internet Computer's threshold secp256k1 key. One key gives each person an address on every chain in the table (cosmos1…, osmo1…, celestia1… and so on). People can read balances, send the chain's own coin with a memo, and move tokens between chains with IBC transfers. Reads and broadcasts go through each chain's public REST endpoint over the IC's HTTPS outcall.
Keys and custody: threshold secp256k1 ECDSA, signed over the SIGN_MODE_DIRECT SignDoc with the signature normalised to low s; one address per signed-in person on each chain, or one owner-only treasury address per chain. The address is bech32 (hash160 of the compressed key) under each chain's prefix. No private key exists anywhere and Keplr is not needed.
Owner settings:kontextCosmosPutChain(chain) adds a chain or changes a built-in one: chain id, bech32 prefix, fee denom, symbol, decimals, REST host (must be https://), minimum gas price as a fraction (gasNum / gasDen) and explorer slug; a row missing its chain id, prefix, fee denom or gas price is refused. kontextCosmosSetDefaultChain(chainId) picks the chain used when a call names none; an unknown id is refused.
What people can do:
Wallet: see their address on a chain, the chain's own coin balance, every balance on that chain (IBC-denominated ones included), and any address's balances.
Sends: send the chain's own coin to an address on the same chain, with an optional memo; an address with another chain's prefix is refused.
IBC: send any denom over a transfer channel of the current chain to an address on the chain at the other end; the channel is read first, so a wrong channel is refused before signing. The transfer times out after ten minutes.
Status: their own sends on every chain, newest first (the owner sees every one), and a re-check of one send.
States you will see: an address that has never received anything cannot pay a fee, so a send from it is refused before signing: "This wallet (…) has never received anything on , so it cannot pay a fee yet." A send is sent until the chain reports it in a block as confirmed, or failed: … with the chain's log; a chain that rejects a broadcast is reported as " rejected the transaction (code N): …". A channel that does not exist: "No IBC transfer channel … on …".
Defaults: seven built-in chains, each on its publicnode REST host: Cosmos Hub (cosmoshub-4, ATOM), Osmosis (osmosis-1, OSMO), Celestia (celestia, TIA), Juno (juno-1, JUNO), Akash (akashnet-2, AKT), dYdX (dydx-mainnet-1, DYDX, 18 decimals) and Sei (pacific-1, SEI). The default chain is Cosmos Hub. Gas is 200,000 for a send and 300,000 for an IBC transfer, priced at each row's minimum gas price. All owner-configurable. Explorer links go to Mintscan.
Not included: Injective and other ethsecp256k1 chains are deliberately absent, because their addresses are derived differently. This module has no NFT or CosmWasm contract methods; CW-721 NFTs (holdings, gating and transfers) and CosmWasm calls are in the Cosmos wallet kit (Keplr / Leap), and Stargaze is not supported because no public REST endpoint answered.
Kontext Sui Wallet — kontext_sui
An app gets a Sui wallet held on the Internet Computer's threshold Ed25519 key. People can see their 0x… address, read their SUI balance and send SUI; each send is built as a programmable transaction and signed by the app's canister. Reads and broadcast go to a public Sui JSON-RPC node over the IC's HTTPS outcall.
Keys and custody: threshold Ed25519; one address per signed-in person, or one owner-only treasury address. The address is the BLAKE2b-256 hash of 0x00 and the public key, written 0x…. No private key exists anywhere and no browser extension is needed.
Owner settings:kontextSuiSetNetwork(testnet) switches between mainnet (false) and testnet (true). kontextSuiSetRpcUrl(url) points the wallet at any JSON-RPC endpoint; it must be https:// ("The RPC URL must be https."), and an empty string returns to the network's default.
What people can do:
Wallet: see their address, their SUI balance, and any address's SUI balance.
Send: send SUI to a 0x… address; the amount is split off the gas coin and transferred.
Status: their own sends, newest first (the owner sees every one), and a re-check of one send.
States you will see: a wallet with no coins is refused before signing: "This wallet holds no SUI yet." A send the balance cannot cover is refused with "Not enough SUI: …", naming the amount plus the 0.005 SUI gas budget. A send is sent until the node reports its effects as success, or failure: … with the node's error.
Defaults: mainnet through https://sui-rpc.publicnode.com (testnet: https://sui-testnet-rpc.publicnode.com); owner-configurable. Gas: the node's reference gas price, a 0.005 SUI budget (the node charges what it uses and refunds the rest), paid from up to the sixteen largest SUI coins. Amounts are MIST, 9 decimals. Explorer links go to Suiscan.
Not included: this module sends SUI only; it has no other coin types and no NFT methods. Coin types such as USDC, Move calls and NFTs (owned objects with their Display, gating by Move type, object transfers) are in the Sui wallet kit, where the person signs in their own wallet.
Kontext Aptos Wallet — kontext_aptos
An app gets an Aptos wallet held on the Internet Computer's threshold Ed25519 key. People can see their 0x… address, read their APT balance and send APT; a first payment creates the recipient's account. The same account can send Chainlink CCIP data messages to eight EVM chains, paying the fee in APT. Reads and submission go to an Aptos fullnode's REST API, and the chain id is read from that node rather than assumed.
Keys and custody: threshold Ed25519; one address per signed-in person, or one owner-only treasury address. The address is the SHA3-256 hash of the public key and 0x00, written 0x…. No private key exists anywhere and no browser extension is needed.
Owner settings:kontextAptosSetNetwork(testnet) points the wallet at the default fullnode for mainnet (false) or testnet (true). kontextAptosSetRestUrl(url) points it at any fullnode; it must be https:// ("The fullnode URL must be https."). Either change forgets the chain id, and the next call reads it from the new node, so the wallet never signs for the wrong chain.
What people can do:
Wallet: see their address, their APT balance, and any address's APT balance.
Send: send APT to a 0x… address through 0x1::aptos_account::transfer, which creates the recipient's account when needed.
Chainlink CCIP to EVM: quote the fee and send a data message (no tokens) to an EVM chain by its CCIP selector; fee and gas are paid in APT.
Status: their own sends, newest first (the owner sees every one), and a re-check of one send.
States you will see: an address the node does not know reads as a balance of 0. A send the balance cannot cover is refused before signing: "Not enough APT: …" (the amount plus a 2,000-unit gas ceiling, or the CCIP fee plus a 20,000-unit ceiling). A send is pending until the node returns the executed transaction as success or failure: <vm status>; unknown means the node has no record of the hash. The node's own rejection is passed through as "Aptos rejected the transaction: …". A destination CCIP does not serve: "CCIP does not serve destination selector … from Aptos." The network name in stats is what the node reports ("not read yet" before the first call).
Defaults: mainnet through https://aptos-rest.publicnode.com/v1; testnet through https://api.testnet.aptoslabs.com/v1; owner-configurable. Gas unit price is the node's estimate; sends expire after ten minutes. CCIP routers are built in for Aptos mainnet (chain id 1) and testnet (chain id 2); the hook's CCIP selectors are Ethereum, Optimism, BNB, Polygon, Base, Arbitrum, Avalanche and Linea. Amounts are octas, 8 decimals. Explorer links go to the Aptos Labs explorer.
Phrases that propose it: "aptos", "aptos wallet", "send apt", "apt token", "ccip from aptos", "aptos to ethereum", "aptos to evm", "octas", "aptos testnet"
Not included: CCIP token transfers from Aptos are not built; a message with no data is refused with that reason. This module sends APT only and has no NFT methods; coin and fungible-asset balances such as USDC, entry-function calls and digital assets (NFT holdings, collection gating, transfers) are in the Aptos wallet kit, where the person signs in their own wallet.
Kontext NEAR Wallet — kontext_near
An app gets a NEAR wallet held on the Internet Computer's threshold Ed25519 key. Each person gets an implicit account (64 hex characters). They can read their NEAR balance, send NEAR to an implicit account or a named account such as alice.near, and call contracts with gas and an attached deposit. Transactions are signed by the app's canister and sent through a public NEAR RPC node.
Keys and custody: threshold Ed25519; one implicit account per signed-in person, or one owner-only treasury account. The account id is the hex of the public key. No private key exists anywhere and no browser extension is needed.
Owner settings:kontextNearSetNetwork(testnet) switches between mainnet (false) and testnet (true). kontextNearSetRpcUrl(url) points the wallet at another RPC endpoint; it must be https:// ("The RPC URL must be https."), and an empty string returns to the network's default.
What people can do:
Wallet: see their implicit account, their NEAR balance, and any account's NEAR balance.
Send: send NEAR to an account id. A transfer to an implicit account that does not exist yet creates it; a named receiver must already exist.
Contract calls: call a method on a contract with JSON arguments, 1 to 300 TGas, and an optional deposit in yoctoNEAR.
Status: their own transactions, newest first (the owner sees every one), and a re-check of one.
States you will see: an account that has never received NEAR reads as a balance of 0, and sending from it is refused before anything is built: "This account (…) is not funded yet — send it some NEAR first; the transfer creates it." A transaction is pending until the node reports success, or failure: … with the node's outcome. Node errors come back as "NEAR RPC error: …" or "NEAR: …". Bad input is refused by name: "Not a NEAR account id: …", "A call needs a method name and 1–300 TGas.", "Arguments are not valid JSON: …".
Defaults: mainnet through https://rpc.mainnet.near.org (testnet: https://rpc.testnet.near.org); owner-configurable. Transactions are sent waiting for optimistic execution. The hook calls contracts with 30 TGas unless told otherwise and takes the deposit as NEAR text. Amounts are yoctoNEAR (24 decimals). Explorer links go to NearBlocks.
Not included: this module has no token (NEP-141) or NFT methods of its own. NEP-141 balances and transfers and NEP-171 NFTs (holdings, gating by contract, transfers) are in the NEAR wallet kit (NEAR Connect), where the person signs in their own wallet.
Kontext XRP Ledger Wallet — kontext_xrpl
An app gets an XRP Ledger wallet held on the Internet Computer's threshold Ed25519 key. Each person gets a classic r-address. They can read their XRP balance and send XRP with an optional destination tag and memo; a first payment to a new account must carry at least the base reserve, which creates it. Payments are signed by the app's canister and submitted through a public rippled node.
Keys and custody: threshold Ed25519; one r-address per signed-in person, or one owner-only treasury address. The r-address uses XRPL's own base58 alphabet with a double-SHA-256 checksum. No private key exists anywhere and no browser extension is needed.
Owner settings:kontextXrplSetNetwork(testnet) switches between mainnet (false) and testnet (true). kontextXrplSetRpcUrl(url) points the wallet at another rippled JSON-RPC endpoint; it must be https:// ("The RPC URL must be https."), and an empty string returns to the network's default.
What people can do:
Wallet: see their r-address, their XRP balance, and any r-address's XRP balance.
Payments: send XRP to an r-address, with an optional destination tag and an optional memo of up to 1 KB.
Status: their own payments, newest first (the owner sees every one), and a re-check of one payment.
States you will see: an address the ledger has never seen reads as a balance of 0, and sending from it is refused: "This wallet (r…) is not on the ledger yet — it needs to receive the base reserve first." A payment to a new account below the base reserve is refused before signing, naming the reserve in drops. "Not enough XRP: …" when the balance cannot cover the amount plus the fee (the reserve stays behind). The ledger's refusal codes (tec…, tef…, tem…) are passed through as "XRPL refused the payment: — ". A payment is pending until the ledger validates it, then validated, or failed: <result code>. Each payment names a last ledger about twenty ledgers out, so one that never validates expires rather than lingering.
Defaults: mainnet through https://xrplcluster.com (testnet: https://s.altnet.rippletest.net:51234); owner-configurable. The base reserve is read from the node (1 XRP today), not fixed. The fee is the open-ledger fee, floored at the network minimum and capped at 0.001 XRP. Amounts are drops, 6 decimals. Explorer links go to livenet.xrpl.org or testnet.xrpl.org.
Not included: this module sends XRP only; it has no issued-token, trust-line or NFT methods. Issued tokens such as RLUSD and XLS-20 NFTs (holdings, gating by issuer, the two-step offer and accept transfer) are in the XRP Ledger wallet kit (GemWallet), where the person approves in their own wallet.
Kontext Hedera Account — kontext_hedera
A Hedera account inside the app's own canister. People can hold and send HBAR, hold and send Hedera Token Service (HTS) tokens such as USDC on Hedera, create their own fungible tokens and NFT collections, mint and burn them, and post messages to Hedera Consensus Service (HCS) topics. Transactions are signed in the canister and sent straight to a Hedera consensus node over gRPC-web; balances, token lists, NFTs and history come from the public mirror node. Hedera's smart-contract service (the Hedera EVM) is a row on EVM Wallet, not part of this module.
Keys and custody: the Internet Computer's threshold Ed25519 key, one account per signed-in person, or one app treasury that only the owner may use. The address to fund is the key alias, written 0.0.<public key>; once HBAR reaches it, the account also has an ordinary 0.0.N id.
Owner settings:kontextHederaSetNetwork(network) switches between mainnet and testnet. kontextHederaSetNode(url, account) points at another consensus node's gRPC-web port (an https:// URL plus that node's 0.0.N account number); an empty URL and account 0 restore the default. kontextHederaSetMirror(url) points at another mirror node (https:// only); an empty URL restores the default.
What people can do:
HBAR: see the account and balance; send HBAR to a 0.0.N account or to a key alias, with an optional memo of up to 100 bytes. Sending to an alias creates that account.
HTS tokens: list the tokens held with their decimals; read a token's name, symbol, decimals, kind and total supply; send units to an existing 0.0.N account; associate the account with a token.
Creating tokens: create a fungible token (name, symbol, up to 18 decimals, initial supply, optional maximum supply) or an NFT collection (no decimals, no initial supply). The creating account becomes treasury and supply key, and admin key on request. Mint more units, mint NFT serials (one metadata value of up to 100 bytes per serial, usually a URI, up to ten per call), burn units or serials, send one NFT serial to a 0.0.N account, and list the NFTs held.
HCS: post a message of up to 1,024 bytes to an existing topic, and read a topic's latest messages (25 by default, up to 100), newest first.
History: every send, association, token action and message is recorded; refresh asks the node for the receipt and, once the node no longer has it, the mirror node. For a token creation, refresh also fills in the new token id.
States you will see: an account that has never received HBAR has no 0.0.N id yet; the hook shows the alias with "send HBAR here to open the account", re-checks every 30 seconds, and its balance reads 0. A send from it is refused before signing: "This account is not funded yet — send some HBAR to … first; the transfer creates it." A record is UNKNOWN until its receipt arrives, then SUCCESS or the network's failure by name, for example INSUFFICIENT_PAYER_BALANCE, BUSY, TOKEN_NOT_ASSOCIATED_TO_ACCOUNT or INSUFFICIENT_TOKEN_BALANCE. A node that returns no gRPC-web frame is reported with "try another node (setNode)". Anonymous callers get "Sign in first."
Defaults: mainnet. Consensus node https://node00.swirldslabs.com:443 (account 0.0.3) on mainnet and https://testnet-node00-00-grpc.hedera.com:443 (0.0.3) on testnet; mirror node https://mainnet-public.mirrornode.hedera.com or https://testnet.mirrornode.hedera.com. The fee ceiling is 1 HBAR per transaction and 30 HBAR for creating a token (the network charges the real fee, around a dollar for a token). All three are owner-configurable. Links go to HashScan.
Phrases that propose it: "hedera", "send hbar", "hedera consensus service", "hcs topic", "usdc on hedera", "hts token", "create a hedera token", "hedera nft", "mint on hedera", "hashscan"
Kontext Algorand Wallet — kontext_algorand
An Algorand wallet inside the app's own canister. People hold and send ALGO, and hold, send and opt into Algorand Standard Assets (ASAs) such as USDC on Algorand. Transactions are built and signed in the canister and posted to an algod node; the network parameters (genesis, round, fee) are read from algod on every send rather than fixed in code.
Keys and custody: the Internet Computer's threshold Ed25519 key, one address per signed-in person, or one app treasury that only the owner may use. Addresses are the standard 58-character Algorand form.
Owner settings:kontextAlgorandSetNetwork(testnet) switches to testnet when true and back to mainnet when false. kontextAlgorandSetAlgod(url, token) points at the owner's own algod node (https:// only) with an optional X-Algo-API-Token; empty values restore the public default.
What people can do:
ALGO: see the address (with a QR code), the balance, what is spendable and the minimum balance; send ALGO with an optional note of up to 1,000 bytes.
ASAs: read an asset's unit name, name, decimals and total; see the assets held; opt in to an asset (a zero transfer to itself, which raises the minimum balance by 0.1 ALGO); send an asset to an address that has opted in.
Look up any Algorand address's balance and holdings.
History of sends and opt-ins, refreshed from algod.
States you will see: each send or opt-in is pending, then confirmed, failed: <reason>, or unknown once algod stops tracking it (check the explorer). Refused before anything is signed, each with a sentence: "Not funded" when a send would leave the account under its minimum balance (0.1 ALGO plus 0.1 per asset held); an asset the account has not opted into or holds too little of; a receiver that "has not opted into asset …; Algorand would reject the transfer"; an asset already held (double opt-in); and an account that was rekeyed to another address, whose key the app does not hold. Anonymous callers get "Sign in first."
Defaults: mainnet through AlgoNode's public node, https://mainnet-api.algonode.cloud (testnet: https://testnet-api.algonode.cloud); both owner-configurable. The hook names USDC as asset 31566704 (Circle's USDC) and links to the Pera explorer.
Phrases that propose it: "algorand", "algorand wallet", "send algo", "algo payments", "usdc on algorand", "asa token", "algorand standard asset", "asset opt-in", "algorand testnet"
Kontext TRON Wallet — kontext_tron
A TRON wallet inside the app's own canister. People hold and send TRX, and hold and send TRC-20 tokens such as USDT on TRON. The canister reads energy and bandwidth prices live on every send and simulates each TRC-20 transfer before signing it, so a transfer that would revert or cost more than the owner allows is refused by name instead of burning TRX.
Keys and custody: the Internet Computer's threshold secp256k1 key (with its own derivation, separate from the EVM wallet), one address per signed-in person, or one app treasury that only the owner may use. Addresses are TRON's base58 T… form.
Owner settings:kontextTronSetNetwork(testnet) switches to the Nile testnet when true and back to mainnet when false. kontextTronSetEndpoint(url, apiKey, feeCapSun) adds the owner's own TRON HTTP API endpoint (https:// only), tried before the defaults, with its TRON-PRO-API-KEY, and sets the TRC-20 fee cap in sun (1 TRX = 1,000,000 sun); an empty URL goes back to the defaults alone, and a fee cap of 0 leaves the current cap unchanged.
What people can do:
TRX: see the address (with a QR code) and the balance; send TRX to any T… address.
TRC-20: read a token contract's symbol, name and decimals; see the balance of a token; send a token amount.
Look up any TRON address's TRX balance and whether it is activated.
History of sends, refreshed from the network.
States you will see: an address that has never received TRX is not activated (activated: false, "it exists once it receives TRX"), never a zero balance, and a send from it is refused. Each transaction is sent until a block holds it, then included, confirmed once solidified, failed: <receipt> if the contract failed, or expired if no block took it. Refused before signing, each with a reason: Not funded (amount plus worst-case fees, including the extra cost when the recipient is not yet activated); a token balance that is too small; "The token contract would refuse this transfer"; energy above the owner's fee cap; TRX short of the energy and bandwidth burn. When every endpoint rate-limits the canister (HTTP 429), it says so and names the fix: an endpoint with a TronGrid API key. A refusal from the node is passed through as "TRON refused the transaction: ".
Defaults: mainnet, trying PublicNode (https://tron-rpc.publicnode.com) first and TronGrid (https://api.trongrid.io) second; Nile testnet uses https://nile.trongrid.io. The TRC-20 fee cap starts at 100 TRX. All are owner-configurable. The hook names USDT on TRON (TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t, 6 decimals) and links to Tronscan.
Phrases that propose it: "tron wallet", "send trx", "pay in trx", "trc20", "usdt on tron", "usdt trc20", "tether on tron", "tronscan", "tron energy", "tron testnet"
Kontext Polkadot Wallet — kontext_polkadot
A Polkadot wallet inside the app's own canister, on Polkadot Asset Hub, which is where DOT balances now live. People hold and send DOT, and hold and send Asset Hub tokens such as USDT (asset 1984), USDC (asset 1337) or any other asset. Every transfer is fee-quoted by the network and validated by the node before it is submitted, so a malformed or unaffordable transfer is refused with the runtime's own reason.
Keys and custody: the Internet Computer's threshold Ed25519 key, one address per signed-in person, or one app treasury that only the owner may use. Addresses are SS58 (starting with 1 on Polkadot). Polkadot's usual sr25519 account type cannot be signed from the Internet Computer; Ed25519 accounts can, and that is what this module uses.
Owner settings:kontextPolkadotSetEndpoint(url) adds one Asset Hub JSON-RPC endpoint of the owner's own (https:// only), tried before the defaults; an empty URL removes it. kontextPolkadotSetNetwork(testnet) switches between Polkadot Asset Hub and Paseo Asset Hub, Polkadot's community testnet (PAS from the faucet, SS58 prefix 42); switching clears a custom endpoint.
What people can do:
DOT: see the address (with a QR code), the balance and what is spendable; send DOT.
Asset Hub tokens: read an asset's symbol, decimals and minimum balance; see a token balance; send a token amount. Fees are paid in DOT.
Look up any Polkadot address's balance.
History of sends, refreshed from the chain.
States you will see: an account holding nothing does not exist yet (exists: false); it exists once it holds 0.01 DOT, and spendable keeps that 0.01 DOT back. A send is sent, then included, finalized, or expired once its 64-block window passes. Status follows the account's nonce; the transfer's dispatch result is not read, so the two ways a transfer can fail after inclusion (keep-alive and the existential deposit) are refused before signing instead. Refused before signing, each with a sentence: Not funded (amount plus the quoted fee, keeping the 0.01 DOT deposit); a first transfer to a new account under 0.01 DOT; a token amount that would leave the sender under the asset's minimum balance; a first token transfer to someone under that minimum. The node's validation refusal is passed on by name (for example Payment, Stale, BadProof); a BadProof or Call refusal also says the runtime's transaction format has moved past the one this module encodes. An endpoint serving a different chain is refused by genesis or spec name.
Defaults: Polkadot Asset Hub mainnet through https://polkadot-asset-hub-rpc.polkadot.io, then https://asset-hub-polkadot-rpc.n.dwellir.com; Paseo Asset Hub through https://asset-hub-paseo-rpc.n.dwellir.com. The network and an extra endpoint are owner-configurable. DOT has 10 decimals. The hook links to Subscan.
Phrases that propose it: "polkadot", "polkadot wallet", "send dot", "pay in dot", "dot transfer", "polkadot asset hub", "usdt on polkadot", "usdc on polkadot", "ss58 address", "subscan"
Not included: reading a transfer's dispatch result after inclusion; an included transfer is reported as included or finalized, not as succeeded.
Kontext Cardano Wallet — kontext_cardano
A Cardano wallet inside the app's own canister, for ADA only. People hold and send ADA; the fee, the minimum output and the size limit are read from the live protocol parameters on every send, and transactions go to the network through Koios. Outputs that also hold native tokens are never spent, so a token never moves by accident.
Keys and custody: the Internet Computer's threshold Ed25519 key, one address per signed-in person, or one app treasury that only the owner may use. Addresses are enterprise addresses, addr1… on mainnet and addr_test… on preprod.
Owner settings:kontextCardanoSetNetwork(testnet) switches to the preprod testnet when true and back to mainnet when false. kontextCardanoSetKoios(url, token) points at another Koios endpoint (https:// only) with an optional API token; empty values restore the public default.
What people can do:
See the address (with a QR code), the ADA balance and what is spendable.
Send ADA to a Shelley-era address on the same network.
Look up any Cardano address's balance.
History of sends, refreshed through Koios.
States you will see: an address that has never received ADA reads funded: false ("send it ADA first"), not an error. tokenOutputs above 0 means some ADA sits beside tokens and is not spent here. A send is sent, then included, confirmed at 10 confirmations, or expired once the chain passes its time-to-live. Refused before signing, each with a sentence: an output under the network's minimum (about 1 ADA); Not funded (amount plus fee exceeds the ADA held in outputs without tokens); all ADA sitting beside tokens; a transaction over the size limit; an address for the other network; Byron-era addresses. A refusal from the network is passed on as "Cardano refused the transaction: …". Change too small to be its own output is added to the fee and recorded.
Defaults: mainnet through https://api.koios.rest/api/v1 (preprod: https://preprod.koios.rest/api/v1); both owner-configurable. ADA has 6 decimals. The hook links to Cardanoscan.
Not included: native tokens and NFTs on Cardano. The module sends ADA only and leaves outputs holding tokens untouched.
Kontext TON Wallet — kontext_ton
A TON wallet inside the app's own canister. On TON a wallet is itself a contract, so each person's wallet (the standard v4R2 contract) is deployed automatically with its first outgoing transfer. People hold and send TON, with an optional comment, and hold and send jettons such as USDT on TON. Every send is checked against the balance and a toncenter fee estimate before it is signed.
Keys and custody: the Internet Computer's threshold Ed25519 key, one wallet per signed-in person, or one app treasury that only the owner may use. The address to share is the non-bounceable UQ… form, which is the safe one before the wallet is deployed.
Owner settings:kontextTonSetNetwork(testnet) switches to testnet when true and back to mainnet when false. kontextTonSetApiKey(key) sets a toncenter API key; an empty key removes it.
What people can do:
TON: see the address (with a QR code) and the balance; send TON with an optional comment of up to 120 bytes.
Jettons: read a jetton's symbol and decimals from its master address; see the balance held; send a jetton amount. A jetton transfer attaches 0.05 TON for the jetton contracts' gas, and the unused part comes back.
Look up any TON address's balance.
History of sends, refreshed from the wallet's sequence number.
States you will see:deployed: false is normal until the first send. A wallet with no TON is refused with "not funded yet — send it TON first". A send is sent, then confirmed once the wallet's sequence number passes it, or expired if it was not taken before its deadline. Whether the outgoing message was later bounced is not read; the bounce case is refused before signing instead: a bounceable EQ… address with no deployed contract behind it is refused with the UQ… form to use. Also refused with a sentence: Not funded (amount plus the estimated fee, including deploying the wallet on its first send); a jetton the wallet does not hold or holds too little of; an address for the other network. A refusal from the network is passed on as "TON refused the message: …".
Defaults: mainnet through toncenter (https://toncenter.com/api/v2 and /api/v3; testnet uses https://testnet.toncenter.com). The network and API key are owner-configurable; the endpoint is not. TON has 9 decimals. The hook names USDT on TON (master EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs, 6 decimals) and links to Tonviewer.
Phrases that propose it: "ton wallet", "send ton", "toncoin", "pay in ton", "ton payments", "usdt on ton", "jetton", "jetton transfer", "tonviewer", "ton testnet"
Kontext MultiversX Wallet — kontext_multiversx
A MultiversX wallet inside the app's own canister. People hold and send EGLD, send ESDT tokens (USDC, USDT, WEGLD, MEX or any ESDT), send NFTs and SFTs, and call any smart contract. The chain id and gas schedule are read from the network, and a contract call's gas is simulated before it is signed.
Keys and custody: the Internet Computer's threshold Ed25519 key, one address per signed-in person, or one app treasury that only the owner may use. Addresses are erd1….
Owner settings:kontextMultiversxSetNetwork(devnet) switches to devnet when true and back to mainnet when false. kontextMultiversxSetEndpoints(api, gateway, feeCap) points at another MultiversX API and gateway (https:// only; empty restores the default) and sets the fee cap per transaction in the smallest EGLD unit (10^18 per EGLD); a fee cap of 0 leaves the current cap unchanged.
What people can do:
EGLD: see the address (with a QR code) and the balance; send EGLD with an optional note.
ESDT tokens: read a token's ticker and decimals; see the balance held; send a token amount.
NFTs and SFTs: send one by its identifier (COLLECTION-abcdef-nonce), with a quantity for SFTs (1 for an NFT).
Contracts: call any contract function with hex arguments (the hook has helpers for numbers, text and hex) and optional EGLD attached.
Look up any erd1… address's balance.
History of sends and calls, refreshed from the API.
States you will see: an address that has never received EGLD reads funded: false and cannot pay a fee yet ("send it some EGLD first"). A transaction is pending until the API reports success, fail or invalid. Refused before signing, each with a sentence: a fee above the owner's cap; not enough EGLD for the amount plus fees; not enough of a token, NFT or SFT; "The contract would refuse this call: …" from the simulation. A refusal from the network is passed on as "MultiversX refused the transaction: …".
Defaults: mainnet, https://api.multiversx.com and https://gateway.multiversx.com (devnet: https://devnet-api.multiversx.com, https://devnet-gateway.multiversx.com); fee cap 0.005 EGLD per transaction. All owner-configurable. The hook names USDC-c76f1f, USDT-f8c08c, WEGLD-bd4d79, MEX-455c57 and UTK-2f80e9, and links to the MultiversX explorer.
An app gets a native Filecoin wallet held by its own canister: an f1 address, FIL sends to any Filecoin or 0x address, and calls to Filecoin's built-in actors (multisig, miner and the like). The same toolkit stores files on Filecoin through Lighthouse, on the owner's Lighthouse account, and lists the Filecoin deals that hold each file. There is no private key anywhere and no browser extension.
Keys and custody: the Internet Computer's threshold secp256k1 key. With the default scope each signed-in person has their own f1 address; with owner scope there is one treasury address that only the owner may use ("Only the owner may use this app's treasury wallet."). Addresses are f1… on mainnet and t1… on testnet. Sends accept f1…, f410f…, f0… or a 0x… address (a 0x address becomes f410f…, or f0… for a masked id address).
Owner settings:kontextFilecoinSetNetwork(testnet) switches between mainnet and testnet. kontextFilecoinSetEndpoint(url, token, feeCapAttoFil) sets the owner's own Lotus node (https only) and its bearer token, tried before the public node; an empty url clears it, and a non-zero feeCapAttoFil sets the gas cap in attoFIL. kontextFilecoinSetDealKey(apiKey) connects a Lighthouse account: the key is checked by reading its usage with Lighthouse, a refused key is not kept, and no method returns it. kontextFilecoinClearDealKey disconnects it. kontextFilecoinSetStorePolicy(openToSignedIn, maxBytes) decides whether signed-in people may store files or only the owner, and sets the per-file cap in bytes (0, or anything above 1.8 MB, means 1.8 MB). kontextFilecoinDealUsage shows the owner the Lighthouse account's data limit and data used.
What people can do: see their address and FIL balance, check any address's balance, send FIL, call a built-in actor method with CBOR parameters, and follow each message to its result. Store a file (when the owner allows it), list stored files with a gateway link, and read the deals that hold a file's CID.
States you will see: not funded ("has never received FIL, so it has no account on-chain and cannot pay gas: send it some FIL first"), refused before signing; a gas refusal when the worst-case fee (fee cap × gas limit) is above the owner's cap; "Not enough FIL" naming the amount needed including gas; each message pending, then success or failed (exit N). For storage: "Storage deals are not configured" (no Lighthouse key), "Lighthouse refused that API key", "Only the owner may store files on Filecoin in this app.", a file over the per-file cap, an empty file. An empty deal list means no deal yet (Lighthouse makes deals over hours to days), not a failure. Deals are shown as reported by Lighthouse, not as verified on-chain.
Defaults: mainnet, through Glif (https://api.node.glif.io/rpc/v1; testnet uses https://api.calibration.node.glif.io/rpc/v1). Gas cap 0.01 FIL. Storing is owner-only with a 1.8 MB per-file cap. Stored files are read back from gateway.lighthouse.storage, and the hook links messages and addresses to filfox.info. The network, node, gas cap and store policy are owner-configurable.
Phrases that propose it: "filecoin wallet", "send fil", "pay in fil", "f1 address", "store on filecoin", "filecoin storage deals", "back up to filecoin", "archive to filecoin", "lighthouse storage"
Not included: FEVM (0x) smart-contract calls, which go through the EVM Wallet's Filecoin EVM row.
Arweave & AO — kontext_arweave
An app stores a record or a file permanently on Arweave from its own canister: the bytes become a signed data item, uploaded through the Turbo bundler, and are readable by anyone from any gateway by their id. The same account sends messages to AO processes (AO is Arweave's compute network), reads a message's result, and dry-runs a handler to read a process without committing anything. No wallet extension and no vendor account are needed.
Keys and custody: the Internet Computer's threshold secp256k1 key, as an Ethereum account: the same key and 0x address as the app's EVM Wallet, so one address is funded once. Data items use ANS-104 signature type 3 (Ethereum). By default the app has one treasury account that only the owner may use ("Only the owner may store to this app's Arweave account."); with the user scope each signed-in person stores and messages as their own account.
Owner settings:kontextArweaveSetEndpoint(endpoint, url) changes one service address, named upload (the bundler), payment (Turbo credits), gateway, fastGateway, mu (AO messenger unit) or cu (AO compute unit). URLs must be https.
What people can do: see the signing address and its Turbo credits; store a file, bytes or text (up to 1.5 MB per item) with a content type and up to 64 tags; read a stored item back by id; check whether an item is confirmed. Send a message with an Action, data and tags to an AO process, read that message's result, and dry-run a message to read a process's state. The history lists what was stored and sent.
States you will see: an item is bundled (served by the bundler, not yet on-chain), then "confirmed: N confirmations", or unknown; an AO message is sent. Credits of 0 mean only free-tier (small) items upload; a larger item is refused with the funding note naming the address to fund at payment.ardrive.io. "No item … on either gateway yet." when neither gateway has it. For AO: "Not an AO process id", "A message needs an Action.", "The messenger unit refused the message", and a compute unit that does not serve the process is reported by name ("not found in whitelist").
Defaults: bundler https://upload.ardrive.io, credits https://payment.ardrive.io, gateway https://arweave.net with https://turbo-gateway.com as the fast gateway (it serves an item the moment it is accepted; arweave.net once the bundle settles), AO units https://mu.ao-testnet.xyz and https://cu.ao-testnet.xyz. Every one is owner-configurable. The hook links items to viewblock.io and messages and processes to ao.link. Arweave has no testnet to switch to.
Not included: spawning an AO process (Lua), which is left to a later lane; native Arweave (RSA) keys, which cannot be signed from the Internet Computer, so the canister holds no AR wallet (AR transfers are in the Arweave wallet kit, Wander); and a dedicated helper for atomic assets, which are reachable only by sending the AO message yourself.
Aleph Cloud — kontext_aleph
An app writes to Aleph Cloud, a peer-to-peer storage and compute network, from its own canister. It can keep a key-value document (an aggregate), append records (posts), store files addressed by their sha256, ask the network to forget what it published, and run code on the network as a program (a function) or an instance (a virtual machine). Every message is signed by the app's threshold key and is readable by anyone on the network, so the data does not depend on the canister and needs no vendor account.
Keys and custody: the Internet Computer's threshold secp256k1 key, as an Ethereum account: the same key and 0x address as the app's EVM Wallet, so one funded address serves both. Messages are signed as Ethereum (ETH) messages. By default the app has one treasury account that only the owner may use ("Only the owner may publish to this app's Aleph account."); with the user scope each signed-in person publishes as their own account.
Owner settings:kontextAlephSetApiServer(url) changes the Aleph API server (https only). kontextAlephSetChannel(channel) sets the channel every message is published on (1–64 letters, digits, - or _).
What people can do:
AGGREGATE: set one key of the account's aggregate document to any JSON value (the key is 1–128 characters), and read a key back.
POST: append a record of a type (1–64 characters) with JSON content, and list the account's posts of a type, newest first.
STORE: store a file of up to 1.5 MB, addressed by its sha256, and read its bytes back by that hash.
FORGET: ask the network to forget one or more messages this account published, with an optional reason.
PROGRAM: deploy a function from a code archive already stored (zip, plain or squashfs, with an entrypoint such as main:app), with 1–12 vCPUs, 128–32768 MiB and optional always-on. Once placed it answers HTTP at aleph.sh/vm/<hash>.
INSTANCE: run a virtual machine from a root filesystem, reachable over SSH with the public keys given (at least one is required); the disk is at least ten times the memory and at most 1 TiB.
Read where the network placed a program or instance (its IPv6 address and node), what a message costs (ALEPH to hold, or credits), the account's ALEPH and credit balance, and the status of everything published.
States you will see: each message is processed, pending, forgotten, rejected or unknown. Aggregates and posts are free to publish; storing a file, a program or an instance is refused before signing when the account holds neither ALEPH nor credits ("… holds none. Fund that address, then try again."). The network's own refusals are named: "Aleph rejected the message as malformed" and "Aleph refused the message — this account … has no ALEPH or credits for it". Inline content must be under 50,000 bytes ("Store it as a file instead"). An allocation reads as not placed yet until the scheduler assigns a node. "No file … on Aleph." for an unknown hash.
Defaults: API server https://api2.aleph.im, channel KONTEXT, scheduler https://scheduler.api.aleph.cloud. Programs default to the SDK's Python 3.12 (Alpine Linux) runtime, 1 vCPU and 128 MiB; instances to Debian 12, 1 vCPU, 2048 MiB and a disk ten times the memory. Compute is paid by holding ALEPH on the Ethereum account. The API server and channel are owner-configurable. Aleph has no testnet to switch to. The hook links messages to explorer.aleph.cloud.
Not included: the person's-own-wallet Aleph kit (Lane B, the @aleph-sdk packages) is not built; every Aleph message is signed by the app's canister.
Decentralized Compute & AI — kontext_compute
An app finds capacity, deploys a container, reads its public address and stops it on four decentralized compute providers, with the same calls whichever provider is used: Akash, Fluence, io.net IO Cloud and Dispersed (Render Network's compute network, run by OTOY). It can also chat on io.net's IO Intelligence models. Everything runs on the owner's own provider accounts: the keys stay on the app's canister, nothing deploys until the owner sets spending limits, and every deployment is booked for a bounded time.
Keys and custody: no chain key is involved. The owner's provider API keys are set on the canister, each checked with a cheap authenticated read before it is kept (Akash /v1/user/me, Fluence /v2/users/balances, io.net /users/burn-rate, Dispersed /v1/users/me, IO Intelligence a one-token answer), and no method returns a key. Dispersed requests are HMAC-SHA256 signed inside the canister, so its secret key never leaves it. Deploying, checking, stopping, keys and limits are owner-only whatever the app's scope.
Owner settings:
kontextComputeSetKey(provider, apiKey) connects a provider: akash, fluence, ionet (or io.net) or dispersed (or render). A Dispersed key is the public key and the secret key on two lines. An empty key clears it; a key the provider refuses is "Not kept" and any previous key stays.
kontextComputeSetLimits(maxHourlyCents, maxActive, maxHours) sets the hourly price ceiling in US cents, the most deployments that may be live at once, and the longest booking in hours (1 to 48).
kontextComputeSetRelay(url) points stops at another relay (https only).
kontextComputeSetAiPolicy(openToSignedIn, maxTokens, dailyRequests, model) sets whether signed-in people may ask the AI (this takes effect only in an app built with the user scope; otherwise only the owner may use it), the token cap per answer (1 to 8,192), the daily request cap (0 means no daily cap), and the default model (empty leaves it unchanged).
What people can do: signed-in people can list offers and the IO Intelligence models; the owner deploys, refreshes, stops and lists deployments. A deployment names a container image, one HTTP port, environment variables, CPU, memory and storage, GPUs, the hours to book, and optionally its own ceiling (never above the owner's). Per provider:
Akash (Akash Console API): offers are Akash's GPU price list, read without a key (average hourly price and availability per GPU model). The deployment is an SDL whose maximum bid is the owner's ceiling, converted to uact per block, so the chain refuses a dearer bid; it is booked through runtimeLimitHours. It waits for bids, then refresh takes the cheapest open uact bid at or under the ceiling and leases it; with no such bid within ten minutes it is stopped with that reason. Stops go through the stop relay.
Fluence (Fluence Cloud API): CPU virtual machines only. Offers come from the VM prices of up to three clusters, each named "clusterId:configurationId". The VM, its IP and disk are quoted first and refused over the ceiling; the VM runs Ubuntu and cloud-init installs Docker and starts the container, and its address is the VM's public IP and port. The canister stops it directly.
io.net IO Cloud: offers are hardware types with the most GPUs per container. A deployment names a hardware id and a location id, uses at least one GPU, is priced first for its hours and refused over the ceiling (or when no total can be read), and is booked through duration_hours. Stops go through the stop relay.
Dispersed (Render Network compute): offers are filtered by GPU count. There must be an offer at or under the ceiling; the container runs as a persistent Docker job and its address is the run's node URL. A run found billing more than the ceiling is stopped on refresh. Stops go through the stop relay, already signed by the canister.
Every provider: once a deployment passes its booked hours, refresh stops it as expired.
Stop relay: a canister's outcall can send only GET, POST and HEAD, so the Akash (DELETE), io.net (DELETE) and Dispersed (PUT cancel) stops are sent by ZA's /api/compute-relay/stop. It serves one fixed URL per provider, checks the deployment id's shape, forwards only that provider's auth headers, stores nothing, and gives up after 20 seconds.
IO Intelligence: list the models (id, name, tier, context window, token prices; no key needed) and chat with system, user and assistant messages inside the owner's token and daily caps.
States you will see: a deployment is awaiting bids, starting, running, stopping, stopped, failed or expired. Refusals name their reason: "Compute has no limits yet", "already has N live deployments, the most the owner allows", "Compute on is not configured", " refused the owner's API key (HTTP n)", a quote over the ceiling, "Dispersed has no offer with N GPU(s) at or under $X/h right now", "A ceiling of $X/h is below Akash's smallest bid", and "The stop relay could not be reached …; the deployment still ends at its booked time." For the AI: "IO Intelligence is not configured", "The owner has not opened the AI to signed-in people.", "This app has used today's N AI answers.", and a rate-limit message when io.net answers 429.
Defaults: no limits (ceiling 0 and live cap 0, so nothing deploys until the owner sets them); longest booking 24 hours; relay https://za.kontext.network/api/compute-relay; AI closed to signed-in people, 512 tokens per answer, no daily cap, model meta-llama/Llama-3.3-70B-Instruct. Provider endpoints are fixed: console-api.akash.network, api.fluence.dev, api.io.solutions/enterprise/v1/io-cloud, api.dispersed.com and api.intelligence.io.solutions/api/v1; only the relay is owner-configurable.
Phrases that propose it: "decentralized gpu", "rent a gpu", "gpu marketplace", "deploy to akash", "fluence vm", "io.net gpu", "io cloud", "io intelligence", "render network compute", "dispersed compute"
Not included: Render's rendering service, which is a desktop app behind whitelisting with no cloud API, so Render compute means Dispersed; Aethir GPU booking, which has no self-serve booking API (an application form, ATH and a web portal), so Aethir ships only as the ATH token row, and its Aethir Mesh LLM API was not built; GPUs on Fluence (its current API is CPU VMs only); FLT staking.
Wallet kits (the person's own wallet)
A wallet kit (Lane B) is proposed on the same card as every other toolkit, when a clause of the prompt is about the person's own wallet: a wallet brand ("connect their Phantom", "Keplr"), a chain's own connect phrase ("connect their tron wallet") or a dapp phrase ("a near dapp"). Nothing is mounted in the app's Motoko backend: the kit is one seeded React hook, src/frontend/src/hooks/useKontext<Chain>Connect.ts, a locked platform file that every screen imports, and on later updates the app is recognised as having the kit because that file is present. A kit never forces Sign in with Kontext, because the wallet is the account, and it needs no <Provider> in App.tsx: the hook keeps one shared connection for every screen. Precedence is decided per clause. A generic connect phrase ("connect their wallet", "connect wallet button", "dapp") belongs to the EVM kit unless the clause names another chain, in which case it moves to that chain's kit ("connect their wallet on solana" is the Solana kit). When a kit matches, the same chain's Lane A module yields to it (for example the Solana wallet module to the Solana kit, the Bitcoin and Ordinals modules to the Bitcoin kit), as do the generic ICP wallet, NFT and invoicing rows, unless the clause also asks for work done while the person is away ("automatically", "every week", "payout", "treasury", "agents", "airdrop", "sweep"); then the kit and the Lane A module are both proposed and compose in one app. The browser packages some kits use (viem, @solana/web3.js, @mysten/sui, @aptos-labs/ts-sdk, @stellar/freighter-api, @gemwallet/api, @hot-labs/near-connect, @tonconnect/ui-react) are pre-installed in the bundler's warm pool, and live preview pre-bundles one only when the app actually imports it. The other eight kits (TRON, Cosmos, Arweave, Cardano, Polkadot, Bitcoin, Stacks, MultiversX) import no package: the wallet injects itself into the page, and the hook talks to it directly. Generated screens are checked so they do not read a wallet's window object or build their own chain client outside the hook.
Kontext EVM Wallet Connect — kontext_evm_connect
The person's own EVM wallet, connected in the browser: MetaMask, Rabby, Coinbase Wallet, Rainbow, Trust, OKX, Brave, or any wallet that announces itself through EIP-6963. The app can show native, ERC-20, ERC-721 and ERC-1155 balances, send any of them, gate a screen on holding an NFT, and read or write any contract from its ABI. The person signs and pays the gas, and the wallet is asked to add a chain it does not know.
Keys and custody: the person's own wallet; no key leaves it and nothing is stored on the app's canister. Address format 0x followed by 40 hex characters.
Owner settings: none. There is nothing on the app's canister to configure.
What people can do: connect (one button per discovered wallet) and disconnect; switch chain; send the native coin, ERC-20 tokens (by the token's own decimals), ERC-721 and ERC-1155 tokens; call any contract write or read; sign a plain-text message (a signature, not a sign-in: nothing on the canister verifies it); check whether they hold an NFT from a collection (token-gating); follow a transaction by its receipt.
States you will see:noWallet ("No browser wallet was found. Install one, or open this page in your wallet app's browser."), never a zero balance; a sent hash is pending until its receipt is found; "You declined the request in your wallet."; "Your wallet already has a request open. Finish it there first."; a chain outside the list is refused ("Chain N is not one this app offers."); a contract that is not an NFT errors by name rather than reading as "holds none".
Defaults: 35 mainnets plus Sepolia and Base Sepolia, from viem's own chain definitions plus Z Chain (chain 9369, rpc.zchain.org). The list includes Ethereum, Base, Arbitrum, Optimism, Polygon, BNB, Avalanche, zkSync, Scroll, Celo, Gnosis, Monad, HyperEVM, Hedera EVM, Rootstock (30) and Mezo (31612). Reads go through the wallet when it is on that chain, otherwise through the chain's public endpoints (Ethereum and BNB carry fallback endpoints, tried after the chain's default). Named tokens on Ethereum: FLT (Fluence), ATH (Aethir) and RENDER.
Frontend hook:useKontextEvmConnect — no canister methods; the wallet signs. Package:viem.
Not included: WalletConnect (it needs the owner's Reown project id); a phone with no extension gets open-in-MetaMask and open-in-Coinbase links instead.
The person's own Solana wallet, connected in the browser: Phantom, Solflare, Backpack, or any wallet that registers through the Wallet Standard. The app can show SOL and SPL-token balances (USDC and Token-2022 included), send them, run any program call built from instructions, and follow a signature's status. The recipient's token account is created when it is missing.
Keys and custody: the person's own wallet; no key leaves it and nothing is stored on the app's canister. Addresses are base58 public keys.
Owner settings: none.
What people can do: connect and disconnect; send SOL; send an SPL token by mint; send any set of program instructions; sign a message (not a sign-in); gate on a single NFT mint the person holds 1 of, and send a classic (non-programmable) NFT as a 1-unit token send.
States you will see:noWallet (no Solana wallet installed), never a zero balance; a token balance with no token account reads "0"; a signature is pending until its status is confirmed, with a non-null error meaning it failed on-chain; "You declined the request in your wallet."; "No token mint exists at … on …".
Defaults: mainnet, read through solana-rpc.publicnode.com then api.mainnet-beta.solana.com; a screen can switch to devnet (api.devnet.solana.com). Named mints: USDC, IO (io.net), RENDER and ATH (Aethir). Explorer links go to Solscan.
Frontend hook:useKontextSolanaConnect — no canister methods; the wallet signs. Package:@solana/web3.js (Wallet Standard discovery is inlined in the hook).
Phrases that propose it: "phantom wallet", "connect phantom", "connect their phantom", "solflare", "backpack wallet", "solana wallet adapter", "solana dapp", "connect a solana wallet"
Not included: listing a wallet's NFTs or gating on a whole collection. Both need a DAS indexer, which needs an API key this kit does not have.
Kontext Sui Wallet Connect — kontext_sui_connect
The person's own Sui wallet, connected in the browser: Slush, Suiet, Nightly, or any Wallet Standard wallet. The app can show SUI and any coin type's balance, send them (the SDK gathers the person's coins), run any Move call, and follow a transaction's status. NFTs are covered too: owned objects with their Display name and image, gating by Move type, and object transfers.
Keys and custody: the person's own wallet; no key leaves it and nothing is stored on the app's canister. Address format 0x followed by up to 64 hex characters.
Owner settings: none.
What people can do: connect and disconnect; send SUI or any coin type (USDC and others, by the coin's own metadata); run any Move call; list owned objects that have a Display template; gate on holding an object of a Move type; send an object they own (ownership read first); sign a message (not a sign-in).
States you will see:noWallet, never a zero balance; a digest is pending until its status is "success" or "failed"; "You declined the request in your wallet."; "This wallet cannot sign messages."; "That is not an object on Sui …".
Defaults: mainnet over the fullnode's gRPC-web (fullnode.<network>.sui.io); a screen can switch to testnet or devnet. Explorer links go to Suiscan.
Frontend hook:useKontextSuiConnect — no canister methods; the wallet signs. Package:@mysten/sui (gRPC client and transactions).
Phrases that propose it: "slush wallet", "suiet", "suiet wallet", "sui wallet extension", "sui dapp", "sui dapp kit", "connect a sui wallet", "connect their sui wallet"
The person's own Aptos wallet, connected in the browser: Petra, Nightly, OKX, Pontem, or any AIP-62 wallet. The app can show APT, coin and fungible-asset balances (read exactly through view functions), send them, submit any entry-function call, and follow a transaction's status. Digital assets (NFTs) are covered: holdings through the indexer, gating by collection, and object transfers.
Keys and custody: the person's own wallet; no key leaves it and nothing is stored on the app's canister. Address format 0x followed by up to 64 hex characters.
Owner settings: none.
What people can do: connect and disconnect; send APT or a fungible asset (USDC and others, by the asset's own metadata); submit any entry function; list digital assets and gate on a collection; send a token they own (ownership and transferability read first); sign a message (not a sign-in).
States you will see:noWallet, never a zero balance; a hash is pending until its status is "success" or "failed"; "That token is not owned by your account."; "That token is soulbound (its transfers are locked), so it cannot be sent."; "You declined the request in your wallet."
Defaults: the network follows the wallet (mainnet, testnet or devnet), read through the Aptos SDK's own endpoints. Native USDC is named by its fungible-asset metadata address. Explorer links go to the Aptos explorer.
Frontend hook:useKontextAptosConnect — no canister methods; the wallet signs. Package:@aptos-labs/ts-sdk.
Phrases that propose it: "petra wallet", "pontem wallet", "aptos wallet adapter", "aptos dapp", "connect an aptos wallet", "connect their aptos wallet", "connect your aptos wallet"
The person's own Stellar wallet, Freighter, connected in the browser. The app can show XLM and issued-asset (USDC and others) balances and send payments with a text or id memo. XLM sent to an account that does not exist yet creates it, and a missing trustline is refused by name before Freighter opens.
Keys and custody: the person's Freighter wallet; they sign every transaction in it and pay the fee. No key leaves the wallet and nothing is stored on the app's canister. Addresses are G followed by 55 characters. The transaction envelope is built in the hook, pinned byte for byte to @stellar/stellar-base, and Freighter shows exactly what is signed.
Owner settings: none.
What people can do: connect and disconnect Freighter; see balances; pay XLM or an issued asset with an optional memo (a text memo is at most 28 bytes); sign a message (not a sign-in).
States you will see:noWallet ("Freighter is not installed. Get it at freighter.app, then reload this page."), never a zero balance; funded: false for an account that does not exist yet ("This Stellar account is not funded yet: send it at least 1 XLM first."); a first payment to a new account under 1 XLM is refused; "That account has no trustline for …, so it cannot receive it."; a hash is pending until its status is "success" or "failed"; "You declined the request in Freighter."; a custom Freighter network is refused ("Switch it to Mainnet or Testnet.").
Defaults: the network Freighter is on, mainnet or testnet, read through horizon.stellar.org or horizon-testnet.stellar.org. Explorer links go to stellar.expert.
Frontend hook:useKontextStellarConnect — no canister methods; the wallet signs. Package:@stellar/freighter-api.
Phrases that propose it: "freighter wallet", "freighter extension", "connect freighter", "connect their freighter", "stellar dapp", "connect a stellar wallet", "connect their stellar wallet"
The person's own XRP Ledger wallet, GemWallet, connected in the browser. The app can show XRP and issued-token (RLUSD and others) balances and send payments with a destination tag. The base reserve for a new account and a missing trustline are checked first and refused by name. XLS-20 NFTs are covered: holdings, gating by issuer, and the ledger's two-step offer and accept transfer.
Keys and custody: the person's GemWallet; they approve every payment in it and pay the fee, and GemWallet submits it. No key leaves the wallet and nothing is stored on the app's canister. Addresses are classic r… addresses (checksum checked).
Owner settings: none.
What people can do: connect and disconnect GemWallet; see XRP and token balances; pay XRP or a token with an optional destination tag; list NFTs and gate on an issuer (optionally a taxon); transfer an NFT in two steps (the sender creates a 0-XRP sell offer only the recipient can take, and the recipient finds and accepts it); sign a message (not a sign-in).
States you will see:noWallet ("GemWallet is not installed. Get it at gemwallet.app, then reload this page."), never a zero balance; funded: false for an account that does not exist yet; a first payment below the live base reserve is refused ("the first payment to it must be at least … XRP, which creates it"); "That account has no trustline for this token, so it cannot receive it."; a hash is pending until "success" or "failed"; "You declined the request in GemWallet."; another GemWallet network is refused ("Switch it to Mainnet or Testnet.").
Defaults: the network GemWallet is on, mainnet (xrplcluster.com) or testnet (testnet.xrpl-labs.com); the reserve is read live from server_info. Explorer links go to livenet.xrpl.org or testnet.xrpl.org.
Frontend hook:useKontextXrplConnect — no canister methods; the wallet signs. Package:@gemwallet/api.
Phrases that propose it: "gemwallet", "connect gemwallet", "connect their gemwallet", "xrpl dapp", "connect an xrp wallet", "connect their xrp wallet", "connect an xrpl wallet"
Not included: Xaman (it needs an API key).
Kontext NEAR Wallet Connect — kontext_near_connect
The person's own NEAR wallet, picked in NEAR Connect's own selector: HOT, Meteor, Intear, MyNearWallet, Nightly, OKX and the rest of its manifest. The app can show NEAR and NEP-141 token (USDC and others) balances, send them, call any contract, and follow a transaction's status. An unregistered token recipient is registered in the same transaction. NEP-171 NFTs are covered: holdings with title and media, gating by contract, and transfers.
Keys and custody: the person's own wallet; they approve every transaction and pay the gas. No key leaves the wallet and nothing is stored on the app's canister. Addresses are NEAR account ids (like alice.near, or 64 hex characters).
Owner settings: none.
What people can do: connect through NEAR Connect's picker (or a named wallet) and disconnect; send NEAR or a NEP-141 token (a recipient not yet registered with the token contract gets storage_deposit plus ft_transfer in one transaction); run any contract function call; list NFTs by contract, or across contracts through FastNEAR's keyless index; gate on a contract; send an NFT (ownership read first); sign a message (not a sign-in).
States you will see:exists: false when the account does not exist; "The NEAR account … does not exist. Check the name."; a hash is pending until "success" or "failed" (an unknown hash reads as pending); "You declined the request in your wallet."; a contract refusal is reported as "NEAR refused …" with the network's cause name.
Defaults: mainnet (rpc.mainnet.near.org, then free.rpc.fastnear.com); a screen can switch to testnet (rpc.testnet.near.org). Explorer links go to nearblocks.io.
Frontend hook:useKontextNearConnect — no canister methods; the wallet signs. Package:@hot-labs/near-connect.
Phrases that propose it: "meteor wallet", "mynearwallet", "my near wallet", "intear wallet", "near dapp", "connect a near wallet", "connect their near wallet"
Not included: WalletConnect-only wallets are not offered (they need a Reown project id the platform does not hold).
Kontext TRON Wallet Connect — kontext_tron_connect
The person's own TRON wallet, TronLink or any wallet announcing itself by TIP-6963, connected in the browser. The wallet injects its own TronWeb, which builds every transaction and asks the person to sign. The app can show TRX and TRC-20 (USDT and others) balances, send them, and follow a transaction's status, and every cost is read live before the wallet opens. TRC-721 NFTs are covered for gating, lookup and transfer.
Keys and custody: the person's own wallet; they pay the energy and bandwidth. No key leaves the wallet and nothing is stored on the app's canister. Addresses are T followed by 33 characters.
Owner settings: none.
What people can do: connect and disconnect; send TRX or a TRC-20 token (a TRC-20 transfer is simulated first, so a revert or an energy burn beyond their TRX is refused by name); gate on a TRC-721 collection; look up one token's owner and URI; send a TRC-721 token (ownership read first, simulated); sign a message (not a sign-in).
States you will see:noWallet ("No TRON wallet is installed. Get TronLink at tronlink.org, then reload this page."), never a zero balance; activated: false for an account that has never held TRX ("Your TRON account is not activated yet: it needs to receive TRX first."); "Not enough TRX: this needs … including … TRX of network fees"; a txid is pending until "success" (confirmed once solidified) or "failed"; "Your wallet is locked. Unlock it and try again."; "You declined the request in your wallet."; a contract that is not TRC-721 errors by name.
Defaults: the network the wallet is on: mainnet (read through tron-rpc.publicnode.com, then api.trongrid.io), Nile or Shasta. Named token: USDT. Explorer links go to tronscan.org.
Frontend hook:useKontextTronConnect — no canister methods; the wallet signs. Package: no package (the wallet injects TronWeb).
Phrases that propose it: "tronlink", "connect tronlink", "connect their tronlink", "tron dapp", "connect a tron wallet", "connect their tron wallet", "connect your tron wallet"
Not included: listing every NFT an address owns; TRON has no such read without an indexer, so the app asks for the collection.
The person's own Cosmos wallet, Keplr or Leap, connected in the browser. On eight chains (Cosmos Hub, Osmosis, Noble, Neutron, Celestia, Juno, Akash and dYdX) the app can show balances, send the native token, Noble USDC or any denom, make IBC transfers over channels read live, call CosmWasm contracts, and follow a transaction's status. Every transaction is simulated on the live chain first, so a refusal or a fee the account cannot pay is named before the wallet opens. CW-721 NFTs are covered per collection.
Keys and custody: the person's own wallet; they approve every transaction and pay the fee. No key leaves the wallet and nothing is stored on the app's canister. Addresses are bech32 with each chain's own prefix (cosmos1…, osmo1…, noble1……); a switch of chain returns the address there. The transaction bytes are built in the hook, pinned byte for byte to cosmjs-types, and the wallet signs them.
Owner settings: none.
What people can do: connect (on a chosen chain) and switch chain; see balances; send a token with an optional memo; make an IBC transfer to a chain in the hook's route list; execute a CosmWasm contract; list and gate on a CW-721 collection, and send a CW-721 token (ownership read first, simulated); sign a message (an ADR-36 signature, not a sign-in).
States you will see:noWallet (no Cosmos wallet installed, keplr.app), never a zero balance; funded: false when the chain has never seen the address; a refusal from the live simulation or a fee shortfall is named before the wallet opens; "That address is not on this chain (expected …1…, got …1…)."; a chain outside the table is refused; "Your wallet does not support this chain."; a hash is pending until "success" or "failed"; a contract that is not CW-721 errors by name rather than reading as "holds none".
Defaults: Cosmos Hub (cosmoshub-4) when no chain is named; each chain reads from public REST endpoints (publicnode, Polkachu or cosmos.directory). Explorer links go to Mintscan.
Frontend hook:useKontextCosmosConnect — no canister methods; the wallet signs. Package: no package (the wallet injects itself).
Phrases that propose it: "keplr", "keplr wallet", "connect keplr", "leap wallet", "usdc on noble", "noble usdc", "wallet on osmosis", "osmosis dapp", "connect a cosmos wallet"
Not included: a chain-wide NFT index (Cosmos has none, so NFTs are read per collection); Stargaze, because no public REST endpoint answered.
The person's own Arweave wallet, Wander (formerly ArConnect) or any wallet exposing window.arweaveWallet, connected in the browser. The app can show AR balances and send AR, make permanent uploads the person signs, send AO messages and AO token transfers, and follow a transfer's status. The person signs and pays for each of these in the wallet.
Keys and custody: the person's own wallet; no key leaves it and nothing is stored on the app's canister. Addresses (and AO process ids) are 43 characters of base64url.
Owner settings: none.
What people can do: connect and disconnect; send AR (the fee is the gateway's live quote and the balance is checked first); upload data permanently through the Turbo bundler (free under its tier); send an AO message to any process and read its result; transfer an AO token, sized by the token's own Denomination with the balance read by dry-run (the AO token by default); sign a message (not a sign-in).
States you will see:noWallet ("No Arweave wallet is installed. Get Wander at wander.app, then reload this page."), never a zero balance; "Not enough AR: this needs … including the … AR network fee"; an upload above the free tier is refused by name ("the bundler wants Turbo credits for this wallet"); a transfer is pending until its status is "success"; an upload is permanent at its data URL once settled; "The AO compute unit did not answer …"; a process with no Denomination is refused as not a token.
Defaults: gateway arweave.net, uploads to upload.ardrive.io, AO messenger and compute units mu.ao-testnet.xyz and cu.ao-testnet.xyz. Explorer links go to ViewBlock.
Frontend hook:useKontextArweaveConnect — no canister methods; the wallet signs. Package: no package (the wallet injects itself).
Phrases that propose it: "arconnect", "connect wander", "connect their wander", "wander wallet extension", "arweave dapp", "ao dapp", "connect an arweave wallet", "their own arweave wallet"
Not included: a dedicated helper for Arweave atomic assets (they are reachable through an AO message).
Kontext TON Wallet Connect — kontext_ton_connect
The person's own TON wallet, connected through TON Connect's own picker (QR code, deep link, browser extension or Telegram): Tonkeeper, MyTonWallet, Telegram Wallet and every wallet in TON Connect's list. The app can show TON and jetton (USDT on TON and others) balances, send TON with a comment, send jettons by the token's own decimals, send any raw message a contract needs, sign text, and find a transfer's status by its message hash. NFTs are covered: holdings with a scam flag, gating by collection, and transfers.
Keys and custody: the person's own wallet; they approve every transfer and pay the fee. No key leaves the wallet and nothing is stored on the app's canister. Addresses are shown non-bounceable (UQ…). The comment and jetton-transfer cells and the message that carries them are built in the hook, pinned to @ton/core.
Owner settings: none. A wallet will not connect without a TON Connect manifest naming the app's origin, and the platform serves one for whatever origin the app runs on (only origins Kontext serves apps from).
What people can do: connect and disconnect; send TON with an optional comment; send a jetton (USDT by default; 0.05 TON travels with it for gas and the unused part comes back); send raw messages; list NFTs (showing the scam flag, never hiding it), gate on a collection, and send an NFT item (ownership read first); sign text (not a sign-in).
States you will see:exists: false when the address has never received anything; a short balance is refused by name before the wallet opens ("Not enough TON: this needs about …"); "You hold no … (no jetton wallet for it yet)."; "That NFT is not held by your wallet (a listed NFT is held by its sale contract until you delist it)."; a hash is pending until "success" or "failed"; "toncenter is rate-limiting this page; try again in a moment."; "You declined the request in your wallet."
Defaults: the network the wallet is on, mainnet or testnet, read through toncenter v3 (toncenter.com/api/v3, testnet.toncenter.com/api/v3). Explorer links go to tonviewer.com.
Frontend hook:useKontextTonConnect — no canister methods; the wallet signs. Package:@tonconnect/ui-react (the hook owns the one TON Connect session; a screen never adds its own provider).
Phrases that propose it: "tonkeeper", "ton connect", "tonconnect", "mytonwallet", "connect telegram wallet", "telegram mini app wallet", "ton dapp", "connect a ton wallet"
The person's own Cardano wallet, connected in the browser: Eternl, Lace, Vespr, Typhon, Yoroi, or any CIP-30 wallet. The wallet supplies its coins, signs and submits; the transaction is built in the hook. The app can show ADA and native-token balances, send ADA, tokens and NFTs, show NFTs with their CIP-25 or CIP-68 name and image, gate on a policy id, and follow a transaction's status.
Keys and custody: the person's own wallet; they approve every transaction and pay the fee. No key leaves the wallet and nothing is stored on the app's canister. The connected address is the wallet's addr1… change address (addr_test1… on a test network). The transaction's CBOR is pinned byte for byte to cardano-serialization-lib.
Owner settings: none.
What people can do: connect (one entry per CIP-30 wallet found, with its icon and name) and disconnect; send ADA; send a native token or an NFT (the minimum ADA an output needs travels with it, and every token not being sent returns in the change); read an asset's name, image, decimals and ticker; list NFTs and gate on a policy id; sign a message (a CIP-8 signature, not a sign-in).
States you will see:noWallet (no Cardano wallet installed; eternl.io, lace.io), never a zero balance; funded: false when nothing was sent to the address yet; "Cardano will not create an output under … : send at least that."; a shortfall, a wrong-network address, a stake address or a Byron-era address is refused by name before the wallet opens; a hash is pending until its status is "confirmed", and a transaction never lands as failed but expires unseen after about two hours; a transaction over the size limit asks the person to consolidate small outputs in their wallet.
Defaults: the network the wallet is on (mainnet, preprod or preview). Fee parameters, asset metadata, holdings and status are read through Kontext's /api/cardano service, because the public indexer blocks browsers. Explorer links go to cardanoscan.io.
Frontend hook:useKontextCardanoConnect — no canister methods; the wallet signs. Package: no package (the wallet injects itself).
The person's own Polkadot wallet, connected in the browser: Talisman, SubWallet, Polkadot{.js}, Nova, Fearless, Enkrypt, or any extension injecting window.injectedWeb3. It works on Polkadot Asset Hub, where DOT balances live. The app can show DOT, USDT and USDC balances, send them, list, gate on and transfer pallet_nfts items, and follow what the app sent. Every send is dry-run on the live runtime and validated by the node first, so a refusal is named in the runtime's own words before anything is submitted.
Keys and custody: the person's own wallet; they approve every transaction and pay the fee. No key leaves the wallet and nothing is stored on the app's canister. Addresses are Polkadot 1… addresses; when the wallet shares several accounts, the person picks one. The call and the extrinsic are built in the hook, pinned to @polkadot/api on the live metadata.
Owner settings: none.
What people can do: connect and choose an account; send DOT (the spendable amount keeps the 0.01 DOT existential deposit); send USDT or USDC; list NFTs by collection or owner, gate on a collection, and send an item; sign a message (not a sign-in).
States you will see:noWallet (no Polkadot wallet installed; talisman.xyz, subwallet.app), never a zero balance; exists: false when the account never received DOT; refusals named before submission, such as FundsUnavailable, an existential-deposit shortfall, or an item that is not theirs; a Kusama or Ethereum-style address is refused ("That is a Kusama address, not a Polkadot one."); status is pending, included, finalized or expired (its era passed unused) for what this app sent, and unknown for anything else.
Defaults: Polkadot Asset Hub only, through polkadot-asset-hub-rpc.polkadot.io, then Dwellir and OnFinality public endpoints; an endpoint serving another chain is refused. Explorer links go to Subscan.
Frontend hook:useKontextPolkadotConnect — no canister methods; the wallet signs. Package: no package (the wallet injects itself).
The person's own Bitcoin wallet, Unisat, Xverse or Leather, connected in the browser. The wallet builds, signs and broadcasts every transaction, because its coin selection keeps inscriptions out of a payment. The hook checks the recipient, the dust limit, the balance and the live fee rate first, and names every refusal. The app can show BTC balances and fee rates, send BTC, follow a transaction's status, and work with ordinals inscriptions.
Keys and custody: the person's own wallet; they approve every transaction and pay the fee. No key leaves the wallet and nothing is stored on the app's canister. The connected address is the wallet's payment address; inscriptions live at its ordinals (Taproot) address, which is the same address in Unisat. Recipients may be P2PKH, P2SH, SegWit v0 or Taproot.
Owner settings: none.
What people can do: connect and disconnect; read balances (confirmed and unconfirmed) and fee rates (fastest, half hour, hour, economy, minimum, in sat/vB); send BTC, optionally at a chosen fee rate (the wallet may show its own fee); list the wallet's inscriptions or any address's; send an inscription to a Taproot address (Unisat and Xverse only); gate on an inscription id or on a parent inscription, the on-chain way a collection is defined; sign a message (a BIP-322 signature, not a sign-in).
States you will see:noWallet ("No Bitcoin wallet is installed. Get Unisat (unisat.io), Xverse (xverse.app) or Leather (leather.io), then reload this page."), never a zero balance; funded: false when the chain never saw the address; dust, a wrong-network address, a bad checksum, a shortfall and an inscription not in the wallet are refused by name before the wallet opens; "That Taproot address has no valid output key: coins sent to it could never be spent."; "Leather does not let an app send an inscription: send it from Leather itself."; an address of a future SegWit version is refused ("That is a SegWit vN address this app does not send to."); status is pending, confirmed (with block height and confirmations) or not_found (never broadcast, or dropped).
Defaults: the network the wallet is on (mainnet, testnet4, signet or testnet). Balances, fees and status come from mempool.space; inscriptions from ordinals.com's recursive endpoints. Explorer links go to mempool.space.
Frontend hook:useKontextBitcoinConnect — no canister methods; the wallet signs. Package: no package (the wallet injects itself).
Phrases that propose it: "unisat", "xverse wallet", "connect leather", "sats connect", "bitcoin ordinals", "ordinals inscriptions", "bitcoin nft", "bitcoin dapp", "connect a bitcoin wallet", "connect their bitcoin wallet"
The person's own Stacks wallet, Leather or Xverse, connected in the browser. The wallet signs and broadcasts every transaction; the hook encodes the Clarity arguments and post-conditions and checks the recipient, the balance and the node's fee estimate first. The app can send STX with a memo, send SIP-010 tokens (sBTC, ALEX or any), show and send SIP-009 NFTs, call any Clarity contract read-only or signed, and follow a transaction's status. Token transfers go as contract calls in deny mode with an exact post-condition, so a contract cannot move more than the screen said.
Keys and custody: the person's own wallet; they approve and pay. No key leaves the wallet and nothing is stored on the app's canister. Addresses are SP… on mainnet and ST… on testnet, with the c32 checksum checked. Arguments and post-conditions are encoded byte for byte as @stacks/transactions does.
Owner settings: none.
What people can do: connect and disconnect; send STX with an optional memo; read a SIP-010 token and its balance and send it; list SIP-009 holdings (for galleries and token-gating) and send an NFT; call a read-only function; make a signed contract call, listing what it may move (deny mode, otherwise it aborts); sign a message (not a sign-in).
States you will see:noWallet (no Stacks wallet installed; leather.io, xverse.app), never a zero balance; funded: false when the address never received STX; a wrong-network address, a bad checksum, a shortfall, an unfunded wallet and an NFT not in the wallet are refused by name before the wallet opens; status is pending, success, abort_by_response or abort_by_post_condition (the fee is spent), dropped, or not_found.
Defaults: mainnet or testnet, read from the Stacks node API (api.hiro.so, api.testnet.hiro.so); the fee check uses the node's low estimate as the floor. Explorer links go to explorer.hiro.so.
Frontend hook:useKontextStacksConnect — no canister methods; the wallet signs. Package: no package (the wallet injects itself).
Phrases that propose it: "connect their stacks wallet", "connect a stacks wallet", "stacks dapp", "stacks connect", "leather stacks", "xverse stacks", "stx dapp", "stacks nft gallery", "hiro wallet"
The person's own MultiversX wallet: the MultiversX DeFi Wallet browser extension, or the MultiversX Web Wallet in a popup. The hook builds each transaction as @multiversx/sdk-core does (live nonce, the network's chain id and gas schedule, a contract call's gas simulated first), checks the recipient, the balance and the fee, and names every refusal; the wallet signs, and the hook broadcasts. The app can send EGLD with a note, send ESDT tokens (USDC, WEGLD or any), show and send NFTs and SFTs, call contracts, and follow status.
Keys and custody: the person's own wallet; they approve and pay. No key leaves the wallet and nothing is stored on the app's canister. Addresses are erd1… (bech32 checksum checked). The hook refuses a signed transaction the wallet changed.
Owner settings: none.
What people can do: connect (the Web Wallet is always offered, and the DeFi Wallet extension when installed) and disconnect; send EGLD with an optional note; read an ESDT token and its balance and send it; list NFTs and SFTs (for galleries and token-gating) and send one; call a contract, with a call the contract would refuse coming back with its message; sign a message (not a sign-in).
States you will see:funded: false when the address never received EGLD; a bad checksum, a shortfall, an unfunded wallet, an NFT not held and a transaction the wallet changed are refused by name; status is pending, success, fail or invalid (with a reason), or not_found.
Defaults: mainnet (api.multiversx.com, gateway.multiversx.com, Web Wallet at wallet.multiversx.com); a screen can switch to devnet. Explorer links go to explorer.multiversx.com.
Frontend hook:useKontextMultiversxConnect — no canister methods; the wallet signs. Package: no package.
Phrases that propose it: "connect their multiversx wallet", "connect a multiversx wallet", "multiversx dapp", "elrond dapp", "multiversx defi wallet", "multiversx web wallet", "multiversx extension", "multiversx nft gallery"
User journeys
BC-01. Give an app a wallet on another chain
Path:/workspace → Workspace Chat → proposal card
You do:
Open or create a project in Workspace Chat.
Describe the job in plain words — e.g. "members hold USDC on Base and can send it to each other".
Review the proposal card: it names the toolkit it matched (here EVM Wallet), and nothing is wired until you accept.
Accept it and let the build finish; the Motoko module and its hook are seeded into the app.
Deploy, sign in to the app, and open the wallet screen.
Result: Every signed-in person has their own address, derived from the subnet's threshold key, and a live balance read from the chain. Sends are signed by the canister, with no private key or browser extension anywhere.
BC-02. Take payment in ICP, ckUSDC or ckBTC
Path:/workspace → Workspace Chat → prompt "charge in ckUSDC"
You do:
Ask for crypto checkout in the prompt (ICP, ckUSDC, ckBTC or any ICRC-1 token).
Accept the ICP Payments proposal and deploy.
In the app, create an invoice; it gets its own deposit address.
The payer sends the amount to that address.
Check the invoice; the canister confirms it against the ledger and sweeps it to the treasury.
Result: Payments settle on-chain without a card processor. Each invoice shows paid or unpaid as the ledger reports it.
Decide the shape. Choose native BTC if it should stay Bitcoin on the Bitcoin network. Choose ckBTC if it should land in the app's ICP wallet (the Bitcoin & Ether Bridge).
Say which in the prompt, then accept the proposed toolkit.
Deploy; each signed-in person gets a bc1 address, or a deposit address for the bridge.
Send to it and refresh the balance.
Result: Real on-chain Bitcoin, read and sent through the Internet Computer's own Bitcoin API, with no wrapped token (native) or a 1:1 ckBTC credit (bridge).
BC-04. Inscribe an ordinal, send runes, move BRC-20
Fund the app's Bitcoin wallet, which pays fees; the Taproot vault holds the collectibles.
Inscribe content. The canister runs the commit and reveal transactions on Bitcoin itself.
Send an inscription, or send and mint runes by exact amount.
For BRC-20 balances and rune names, confirm the platform indexer key is set.
Result: Inscriptions and runes created and moved from the app's own vault. A fee is never taken from an output that carries an inscription or a rune. Without the indexer key, BRC-20 balances say not configured; they never read as zero.
BC-05. Let people use their own wallet
Path:/workspace → prompt naming the wallet (e.g. "connect Phantom", "sign in with Keplr")
You do:
Name the wallet or the chain's wallet in the prompt.
Accept the wallet kit proposal (Lane B).
Deploy. In the app, press Connect and approve in the wallet.
Sign a transaction; the wallet shows it and the person approves it there.
Result: The person keeps custody: they sign and pay the fee in their own wallet, and no key reaches the app. The app can pair this with a Lane A wallet when it also needs a treasury.
BC-06. Store files on Filecoin
Path: the deployed app → owner controls (Filecoin storage)
You do:
Accept Filecoin Wallet & Storage for the app and deploy.
As the owner, paste your Lighthouse API key. It is checked with Lighthouse before it is kept.
Set the storage policy: whether signed-in people may store files or only you, and the largest file allowed.
Store a file from the app, then open its deal status.
Result: The file is stored through Lighthouse on your own account, and its CID and deals are listed. Deals are labelled as reported by Lighthouse, because their ids do not resolve on-chain. The Filecoin wallet itself (f1 address, FIL sends, actor calls) works without any key.
BC-07. Run a container on decentralized compute with a spend ceiling
Path: the deployed app → owner controls (Compute)
You do:
Accept Decentralized Compute & AI and deploy.
Paste the key for your provider: Akash Console, Fluence, io.net IO Cloud, or Dispersed (Render's compute network).
Set an hourly USD ceiling, a live-deployment cap and the most hours a deployment may be booked for. Nothing deploys until the limits are set.
Browse offers with their prices, then deploy a container image.
Open its public address; refresh or stop it when done.
Result: A running deployment on your own provider account, booked for a bounded number of hours, so spending ends even if a stop never lands. On Akash, the ceiling becomes the bid limit, so the chain itself refuses a dearer bid.
BC-08. Chat on open-source models through IO Intelligence
Path: the deployed app → owner controls (IO Intelligence)
You do:
Paste an IO Intelligence API key.
Pick a model from the list (the list needs no key), and set the policy: the token cap per answer, the daily request cap, and whether signed-in people may ask or only you.
Ask a question from the app's chat screen.
Result: Answers from io.net-hosted open models on your account, stopped by the canister once a cap is reached.
BC-09. Trade Hyperliquid perpetuals from the treasury, with guardrails
Path: the deployed app → owner controls (Hyperliquid)
You do:
Accept Hyperliquid Trading and deploy; fund the treasury address with USDC on Hyperliquid.
Set guardrails: per-order and daily USD ceilings, allowed markets and maximum leverage.
Place a limit or market order; see positions and open orders.
Approve or reject any order you did not place yourself.
Result: Orders the canister enforces against your limits. Trading is off until guardrails exist, and orders you did not place wait for your approval.
BC-10. Take Lightning payments
Path: the deployed app → owner controls (Lightning)
You do:
Accept Lightning Payments and deploy.
Enter your LNbits URL and invoice / admin keys (your own instance, a hosted one, or demo.lnbits.com while building).
Set per-payment and daily limits for outgoing payments.
Anyone the app admits requests an invoice and sees it as a QR; it is watched until paid or expired.
Result: bolt11 invoices and owner-only payments within the limits the canister enforces. The Internet Computer has no native Lightning, so LNbits holds the channels.
BC-11. Move value between chains
Path:/workspace → prompt "bridge USDC from Base to Arbitrum" → Cross-Chain
You do:
Accept Cross-Chain along with the EVM Wallet.
Choose the route the job needs: native USDC via Circle CCTP; tokens and messages via Chainlink CCIP, including Solana and Aptos; or LayerZero, Wormhole, Axelar or Hyperlane.
Quote the fee, then send from the app's wallet.
Track delivery status until the destination confirms.
Result: Value or a message lands on the destination chain, sent from the app's threshold-key wallet with the protocol's own fee quote.
BC-12. Start a crypto app from the Crypto Workshop
Path:/crypto → a recipe or a chain page in the Chain Atlas → Start
You do:
Open the Crypto Workshop from the module switcher or go to /crypto.
Pick a recipe on the front door, or open a chain's page in the Chain Atlas.
Press Start and say what the app is for in your own words on the confirm sheet.
Let the workspace's generate lane build it, then open the project.
Result: An ordinary Kontext project whose brief named the chain and its toolkits as stated facts, so the engine keeps them; it appears under Your crypto apps and in the workspace.
BC-13. Add a chain to an app you already have
Path:/crypto → a chain's page → Add to an app
You do:
Open the chain's page in the Chain Atlas.
Choose Add to an app and pick the project.
Confirm; the update lane wires the named toolkit into that app.
Deploy the update.
Result: The same project gains the chain's module and hook through the update lane; nothing is copied and the app keeps its data if deployed as an upgrade.
BC-14. Store an app's provider keys from the Crypto Workshop
Path:/crypto → Your crypto apps → the app → Keys
You do:
Open the app's page under Your crypto apps.
Find the key the service needs (for example LNbits, Akash, Fluence, io.net, Dispersed, IO Intelligence, Lighthouse, toncenter or algod).
Paste it and save.
Read the status the app reports for that service.
Result: The key goes straight to the app's own owner-only setter, which checks it with the provider; the field clears and the browser keeps nothing, and a module that reports no status says "App does not report it".
BC-PLT-01. Let people upload photos and use each one by URL
Path:/workspace → prompt "members upload photos of their pets and we turn each one into a poster" → Kontext Files
You do:
Describe the job without naming a storage vendor, and accept the Kontext Files proposal.
Deploy, sign in to the app, and pick a photo on the upload screen.
The file is sent in 1.5 MB pieces and then finished.
Open the file from your list, or hand its URL to the vendor that makes the poster.
Result: The photo is stored in the app's own canister and served at an unlisted raw.icp0.io URL anyone holding it can open; a file over 50 MB is refused with "The file is larger than 50 MB."
BC-PLT-02. Receive Stripe events at the app's own URL
Path:/workspace → prompt "when stripe says payment succeeded, mark the booking paid" → Kontext Webhooks
You do:
Accept the Kontext Webhooks proposal and deploy.
As the owner, open the app's webhook settings and enable a source named stripe.
Copy the URL it shows and paste it into Stripe's webhook settings.
Trigger a payment; open the events list and see the event with its raw body.
The app's code acts on it and marks it handled.
Result: Events arrive at /webhooks/stripe/ on the app's canister and wait in a queue until acknowledged; a POST with a wrong token gets 404, and Stripe's own signature header is not checked.
BC-PLT-03. Give each family its own space with invite codes
Path:/workspace → prompt "multiple families share the app, each with their own lists and invite codes" → Kontext Workspaces
You do:
Accept the Kontext Workspaces proposal and deploy.
Sign in; with no workspace yet, the app offers create or join. Create one and name it.
As its owner, mint an invite code for the member role and send it to a relative.
The relative signs in, chooses join, and enters the code.
Open the members list to see both of you with your roles.
Result: Each family sees only its own rows; a second join attempt answers "You already belong to a workspace.", and a spent code answers "That invite has been used up."
BC-PLT-04. Change a member's role or remove them
Path: the deployed app → workspace members screen
You do:
Sign in as the workspace owner or an admin and open the members list.
Change a member to viewer so they can read but not write.
Remove a member who has left; a member can also leave on their own.
Result: The role change takes effect at once; ownership never changes here ("Ownership does not change here.") and the owner cannot be removed.
BC-PLT-05. See who approved a booking
Path:/workspace → prompt "keep an audit trail of who approved each booking" → Kontext Audit Trail
You do:
Accept the Kontext Audit Trail proposal and deploy.
Approve a booking in the app; the app records who, what and when.
Open the activity history and filter by the booking (for example booking:12) or by the action booking.approve.
Result: An append-only list, oldest first, that the owner sees in full, a workspace admin sees for their workspace, and anyone else sees only for their own actions.
BC-PLT-06. Download a table for the accountant
Path:/workspace → prompt "the owner can export the bookings to excel as a csv" → Kontext Export
You do:
Accept the Kontext Export proposal and let the build list the app's tables for export.
Deploy and sign in as the owner.
Open the export screen, pick the bookings table and choose CSV or JSON.
Result: A single bookings.csv (or bookings.json) is saved, assembled from 2,000-row pages; anyone who is not the owner or a workspace admin sees no tables.
BC-ICP-01. Give every member a token wallet
Path:/workspace → prompt "every member gets a crypto wallet on ICP to hold ICP and ckUSDC" → Kontext ICP Tokens
You do:
Accept the Kontext ICP Tokens proposal and deploy.
Sign in and open the wallet screen; copy your deposit address.
Send ICP to it from any ICP wallet.
Press refresh to read the balance from the ledger.
Send part of it to another principal or ICRC-1 account.
Result: The deposit appears as a received entry labelled "Detected on refresh", the send returns a block index, and a short balance says "Insufficient ICP: have …, need … including the fee."
BC-ICP-02. Add a token to the app's list
Path: the deployed app → wallet screen (owner)
You do:
Sign in as the owner and open the add-token picker.
Pick ckUSDC from the suggested ledgers, or paste any ledger's canister id.
Confirm; the canister asks the ledger for its name, symbol, decimals and fee.
Pause a token later if it should stop moving.
Result: The token joins the list with its own decimals; a canister that is not a ledger answers "Not an ICRC-1 ledger (…)", and a paused token refuses sends with "Token X is paused."
BC-ICP-03. Mint a membership NFT for each member
Path:/workspace → prompt "mint an nft for each member on our own canister" → Kontext ICP NFTs
You do:
Accept the Kontext ICP NFTs proposal and deploy.
As the owner, set the collection's name, symbol, description, logo and an optional supply cap.
Mint a token to a member's principal with a name, an image URL and attributes.
The member signs in and sees it under their tokens; they can transfer it.
Result: The app's canister is an ICRC-7 collection that ICRC-7 wallets and marketplaces can read; minting past the cap answers "The collection's supply cap of N is reached."
BC-ICP-04. Read what a person holds in another collection
Path: the deployed app → holdings screen
You do:
Sign in and open the screen that reads another collection.
Enter that collection's canister id (or the app supplies it).
The canister asks that collection which tokens you hold and their metadata.
Result: The list of your tokens there, with metadata; a collection that does not answer reports "Could not read collection …" rather than an empty list.
BC-ICP-05. Take payment in ckUSDC with an invoice
Path:/workspace → prompt "charge for tickets in ckUSDC with an invoice at checkout" → Kontext ICP Payments
You do:
Accept the Kontext ICP Payments proposal and deploy.
At checkout, the app creates an invoice for 12.5 ckUSDC with the order reference.
The payer sees the invoice's own deposit address (and its QR) and pays from any wallet.
Leave the screen open; it re-checks the invoice every 5 seconds.
Result: The invoice turns paid once the ledger shows the amount on its address, and the funds are swept to the treasury; an unpaid invoice turns expired after its time to live (one hour by default).
BC-ICP-06. Cancel or recheck an invoice
Path: the deployed app → invoices list
You do:
Open the invoices list and filter by status.
Press check on an open invoice to ask the ledger now.
Cancel an invoice that is no longer wanted.
Result: Only an open invoice can be cancelled ("Only an open invoice can be cancelled."); a paid invoice keeps its paid status even if the sweep to the treasury fails.
BC-ICP-07. Launch loyalty points as the app's own token
Path:/workspace → prompt "customers earn loyalty points and redeem them for store credit" → Kontext ICP Ledger
You do:
Accept the Kontext ICP Ledger proposal and deploy.
As the owner, set the token's name, symbol, fee and an optional supply cap.
Mint points to a customer's principal.
The customer signs in and sees their balance; they send points to a friend or burn them.
Result: A real ICRC-1 and ICRC-2 token served by the app's canister, readable by ICP wallets; minting past the cap answers "Minting N would pass the supply cap of M."
BC-ICP-08. Adjust the token and review its history
Path: the deployed app → owner controls (token)
You do:
As the owner, open the token settings.
Change the transfer fee, or set a supply cap.
Open the full history to see every mint, burn, transfer and approval.
Result: The new fee applies to the next transfer and is burned; a cap below what has already been minted is refused with "The cap cannot be below the N already minted."
BC-ICP-09. Set up a monthly renewal with one approval
Path:/workspace → prompt "members pay monthly in ckUSDC with auto-renew" → Kontext ICP Pull Payments
You do:
Accept the Kontext ICP Pull Payments proposal and deploy.
The member signs in and approves the app from their signed-in account for an amount (for example 30 ckUSDC), optionally until a date.
They check what they have approved on the allowance screen.
When a renewal is due, the app pulls the charge into its treasury.
Result: Each pull appears in the member's pull history; an allowance that is too small returns "The payer approved only N — ask them to approve more".
BC-ICP-10. Pay from an outside ICP wallet
Path: the deployed app → approval screen
You do:
Copy the app's canister id shown as the spender.
In your own ICP wallet, approve that canister id for an amount on the token's ledger.
Return to the app and check the allowance.
Result: The app can now pull up to the approved amount from that wallet's account; nothing moves until a charge is due.
BC-ICP-11. Accept Bitcoin that lands as ckBTC
Path:/workspace → prompt "fans can deposit bitcoin and hold it in the app" → Kontext Bitcoin & Ether Bridge
You do:
Accept the proposals (the Bitcoin & Ether Bridge together with ICP Tokens) and deploy.
Sign in and open the deposit screen; copy your Bitcoin address or scan its QR.
Send BTC to it from any Bitcoin wallet.
Press check deposit until the minter mints.
Result: Until the deposit is confirmed the check reports "N deposit(s) pending: X of Y confirmations."; after that it reports the ckBTC minted, which shows as ckBTC in the wallet.
BC-ICP-12. Withdraw ckBTC back to a Bitcoin address
Path: the deployed app → withdraw screen (Bitcoin)
You do:
Enter a Bitcoin address and an amount in BTC.
Review the estimated Bitcoin fee and minter fee.
Confirm; the canister approves the minter from your account and asks it to send.
Result: A ledger block index for the withdrawal; an amount under the minter's minimum answers "Amount too low — the minimum is N sats."
BC-ICP-13. Deposit Ether that lands as ckETH
Path: the deployed app → deposit screen (Ether)
You do:
Open the Ether deposit instructions.
Note the minter's helper contract on Ethereum and the two bytes32 arguments shown.
Call the helper contract's deposit from your Ethereum wallet with those arguments and the ETH amount.
Result: The minter mints ckETH to your app account when it sees the deposit, with no further step in the app; withdrawals go back out to a 0x address.
BC-ICP-14. Sign a hash with a person's threshold key
Path:/workspace → prompt "each user gets a signing key with a threshold key, no private key anywhere" → Kontext Threshold Key
You do:
Accept the Kontext Threshold Key proposal and deploy.
Sign in and read your public key for a purpose label (for example attestations).
Sign a 32-byte hash with that purpose.
Result: A compressed secp256k1 public key and a 64-byte r‖s signature, both hex; there is no private key to show or export, and a hash of the wrong length answers "An ECDSA message hash is exactly 32 bytes."
BC-ICP-15. Use the test key while building
Path: the deployed app → owner controls (threshold key)
You do:
As the owner, open the key settings and read the current key and signature count.
Switch to test_key_1 while trying things out.
Switch back to key_1 before anything of value is signed.
Result: Signatures on test_key_1 cost about 10 billion cycles instead of about 26.2 billion and must never be used for value; any other key name is refused.
BC-EVM-01. Read a balance, a contract or a receipt on any EVM chain
Path:/workspace → prompt "read any address balance on mantle network" → Kontext EVM Reader
You do:
Describe the screen and accept the EVM Reader proposal.
Deploy, sign in and pick a chain from the list the app shows.
Paste an address and read its balance.
Run a contract read, which returns the ABI-encoded answer as hex for the screen to decode.
Paste a transaction hash to read its receipt.
Result: Each answer comes from several public providers that had to agree (a disagreement shows "providers disagreed … try again" instead of a number), balances are shown by the chain's decimals, and a receipt reads as pending (null) until the transaction is mined.
BC-EVM-02. Add a chain the table does not have
Path: the deployed app → owner controls (EVM chain table)
You do:
Sign in as the owner.
Enter the chain id, name, native symbol and decimals.
Add one or more https RPC URLs and the explorer's transaction prefix.
Mark legacy fees if the chain has no EIP-1559 base fee, and save.
Result: The chain appears in the list for the Reader and the Wallet at once (Cross-Chain also needs a row in its own address book); a non-https URL or a missing name is refused, and anyone who is not the owner is told only the owner may change the table.
BC-EVM-03. Send a raw JSON-RPC request as the owner
Path: the deployed app → owner controls (EVM chain table)
You do:
Sign in as the owner.
Choose a chain and enter a JSON-RPC method such as eth_blockNumber.
Enter its parameters as a list and send.
Result: The answer comes back as JSON text through the same provider quorum (capped at 16,384 bytes), and a caller who is not the owner is refused with "Only the owner may send raw RPC requests."
BC-EVM-04. Give every member an address on EVM chains
Path:/workspace → prompt "members can send ETH on Arbitrum to each other" → Kontext EVM Wallet
You do:
Accept the EVM Wallet proposal and let the build finish.
Deploy, sign in and open the wallet screen.
Choose a chain and copy the address or scan its QR.
Send some of the chain's coin to it from another wallet.
Result: Each signed-in person has one address, the same on every chain in the table (shown with an xdc prefix on XDC), and the balance reads live from the chain.
BC-EVM-05. Send ETH or USDC from the app
Path: the deployed app → wallet screen (EVM)
You do:
Choose the chain and the coin or token to send.
Enter the recipient address and a human amount such as 0.05.
Press send.
Open the explorer link from the pending row and watch for the receipt.
Result: The canister prices the fee, signs with the threshold key and broadcasts; the send shows as pending with its hash until the receipt lands, and too little of the native coin for value plus gas is refused as "Insufficient … for the value plus gas".
BC-EVM-06. Hold MEOW on Z Chain
Path:/workspace → prompt "a z chain wallet so members can hold MEOW" → Kontext EVM Wallet
You do:
Accept the EVM Wallet proposal and deploy.
Sign in and open the wallet screen on Z Chain.
Copy the address and send it Z for gas and some MEOW.
Read the MEOW balance, and send MEOW to another address.
Result: The Z balance and the MEOW balance (by MEOW's own 18 decimals) are read from Z Chain, and a MEOW transfer is a pending hash with a zscan.live link until it is mined.
BC-EVM-07. Check and move an ERC-721 NFT
Path:/workspace → prompt "gate the app to wilder nft holders" → Kontext EVM Wallet
You do:
Accept the EVM Wallet proposal and deploy.
Sign in and enter the collection contract and a token id.
Read who owns the token and its metadata URI.
As the holder, transfer the token to another address.
Result: Ownership is read from the contract's own ownerOf, a token id that does not exist reads "No such token.", and the transfer is signed from the holder's address and stays pending until mined.
BC-EVM-08. Move USDC to another chain with Circle CCTP
Path:/workspace → prompt "let members bridge USDC to Base" → Kontext Cross-Chain
You do:
Accept Cross-Chain (the EVM Wallet it sends from is mounted with it) and deploy.
Sign in and hold USDC plus a little of the source chain's coin for gas.
Choose the source and destination chains and the USDC amount.
Send, then watch the transfer row.
Result: The USDC is burned on the source and minted on the destination after Circle attests; the row moves from burning to attesting to minted and names the mint's hash, and a chain without CCTP (BNB Smart Chain) is refused before anything is signed.
BC-EVM-09. Send a Chainlink CCIP message to another EVM chain
Path:/workspace → prompt "send a ccip message from base to arbitrum when an order ships" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Enter the receiver contract on the destination chain and the message as hex.
Quote the fee in the source chain's native coin.
Send, then open the transfer on ccip.chain.link.
Result: The message leaves from the app's wallet with the fee paid in the native coin; the row reads sent with the source hash, and delivery is checked on ccip.chain.link rather than inside the app.
BC-EVM-10. Send a CCIP message or tokens to Solana or Aptos
Path:/workspace → prompt "bridge a message to solana from base" → Kontext Cross-Chain
You do:
Accept Cross-Chain (the Solana toolkit is proposed beside it) and deploy.
Choose Solana or Aptos as the destination.
For Solana, give the receiving program, its accounts and compute units, or for a token-only transfer leave the receiver empty, set compute units to 0 and name the receiving wallet.
For Aptos, give the 0x receiving address and the destination gas.
Quote the fee, then send.
Result: The router quotes and accepts the send in the source chain's native coin and the row reads sent with a ccip.chain.link link, while a lane the router does not serve is refused with "the lane may not be open".
BC-EVM-11. Send an OFT token with LayerZero
Path:/workspace → prompt "send our OFT token to arbitrum with layerzero" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Enter the OFT contract, the destination chain, the amount and the recipient.
Read the quoted native fee.
Send, then watch the transfer row or open LayerZero Scan.
Result: An adapter OFT is approved first, the send pays the quoted fee, and the row stays INFLIGHT until LayerZero Scan reports the delivery status and the destination hash.
BC-EVM-12. Bridge a token through Wormhole
Path:/workspace → prompt "bridge tokens to avalanche with wormhole" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Choose the source and destination chains, and a token (or none, for the native coin).
Enter the amount and send.
Watch the transfer row; it can also be followed on Wormholescan.
Result: The source leg is locked or wrapped and the row reads awaiting_vaa until the guardians sign; the app then redeems it on the destination by itself and the row reads redeemed with the destination hash, and a chain without the token bridge (Linea) is refused up front.
BC-EVM-13. Call a contract on another chain with Axelar
Path:/workspace → prompt "call our vault contract on polygon through axelar gmp" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Get a gas quote for the route from Axelarscan.
Enter the destination contract and the payload as hex, and send with the quoted gas.
Watch the transfer row or open Axelarscan.
Result: The call goes out first and the gas is paid in a second transaction, so the row moves from called to gas_paid and then to Axelarscan's own status, with the destination hash once executed.
BC-EVM-14. Send a Hyperlane message to a contract on another chain
Path:/workspace → prompt "send a hyperlane message from base to arbitrum when an order ships" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Enter the receiving contract (one that implements handle()) and the message body as hex.
Read the fee the source Mailbox quotes.
Send, then watch the transfer row.
Result: The row stays INFLIGHT with the message id until the destination chain's Mailbox itself reports the message delivered, and the explorer link finds it by message id.
BC-EVM-15. Show a live price from Chainlink or Pyth
Path:/workspace → prompt "show the ETH price from a Chainlink price feed" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Sign in and choose the chain and the pair, such as ETH/USD.
Read the price and when it last updated.
Optionally read the Pyth price for the same asset and its age.
Result: The Chainlink answer is shown scaled by the feed's decimals with its update time, the Pyth price is shown with its age in seconds (it can be old), and a pair the book does not know is refused with a request for the feed's address.
BC-EVM-16. Resolve a ZNS name on Z Chain
Path:/workspace → prompt "resolve each member zns name to their address" → Kontext Cross-Chain
You do:
Accept Cross-Chain and deploy.
Sign in and enter a name such as wilder.frank.
Read the result.
Result: A registered name shows its owner, resolver, the address and text it points to and its domain NFT's URI; a name nobody holds shows as not registered, never as an empty owner.
BC-EVM-17. Turn on Hyperliquid trading with guardrails
Path:/workspace → prompt "trade perps on btc with a daily limit" → Kontext Hyperliquid Trading
You do:
Accept Hyperliquid Trading (it brings the EVM Wallet in owner scope) and deploy.
Sign in as the owner and open the guardrails form.
Set a per-order and a daily USD ceiling, the allowed markets such as BTC and ETH, and a maximum leverage.
Choose whether others' orders need your approval and the market-order slippage, then switch trading on.
Result: Trading is enabled only once both ceilings, at least one market and a leverage are set (otherwise the save is refused with what is missing), and everyone else sees trading as not enabled until then.
BC-EVM-18. Fund the trading account and read it
Path: the deployed app → owner controls (Hyperliquid)
You do:
Copy the trading account's address, which is the app's EVM treasury address.
Send USDC to it through Hyperliquid's Arbitrum bridge.
Wait for the account panel to refresh (it reads every 20 seconds).
Read the account value, withdrawable USDC, positions and open orders.
Result: The panel shows the account read from Hyperliquid's own API; before any deposit it shows an account value of 0, which means not funded rather than empty.
BC-EVM-19. Place a market or limit order
Path: the deployed app → trading screen (Hyperliquid)
You do:
Pick an allowed market and read its mid price.
Choose buy or sell, enter a size, and enter a price or choose market.
Place the order.
Watch it in the order history and open orders.
Result: The owner's order is placed at once and shows as resting or filled, and an order that breaks a guardrail (market not allowed, under $10, over the per-order or daily ceiling) is refused with the reason before anything is signed.
BC-EVM-20. Approve an order a member proposed
Path:/workspace → prompt "a hyperliquid bot that members can propose trades to" → Kontext Hyperliquid Trading
You do:
Build the app so signed-in members may propose orders, and deploy.
A member places an order, which shows as awaiting approval.
Sign in as the owner and open the order history.
Approve or reject the waiting order.
Result: An approved order is checked again against the guardrails and the day's total at that moment before it is placed, and a rejected one is kept in history as rejected.
BC-BTC-01. Give every member a native Bitcoin address
Path:/workspace → prompt "every member gets a bitcoin wallet and can send btc" → Kontext Bitcoin Wallet
You do:
Describe the app and say the bitcoin should stay native, not ckBTC.
Accept the Bitcoin Wallet proposal and let the build finish.
Deploy, sign in to the app and open the wallet screen.
Copy the bc1 address or scan its QR, and send it some bitcoin from another wallet.
Refresh the balance after the deposit has one confirmation.
Result: Each signed-in person has their own bc1q address derived from the threshold key, and the balance shows confirmed bitcoin read from the IC's Bitcoin API (unconfirmed deposits are not counted yet).
BC-BTC-02. Send bitcoin from the app
Path: the deployed app → wallet screen (Bitcoin)
You do:
Check the fee rate the screen shows in sat/vB.
Enter a bc1q or bc1p recipient address and an amount in BTC.
Press send.
Open the transaction on mempool.space from the history row.
Result: The canister selects coins, signs each input with the threshold key and broadcasts through the IC; history shows the txid as sent and it stays unconfirmed until the network confirms it, while an amount under 546 satoshis, a wrong-network address or too little confirmed bitcoin is refused before anything is signed.
BC-BTC-03. Choose native BTC or ckBTC
Path:/workspace → prompt "pay out in bitcoin" → Kontext Bitcoin Wallet
You do:
Decide whether the bitcoin should stay on the Bitcoin network or land in the app's ICP wallet as ckBTC.
For native bitcoin, use wallet or payout words such as "bitcoin wallet" or "pay out in bitcoin".
For ckBTC, use deposit words such as "deposit bitcoin"; the bridge is proposed with the ICP wallet.
Read the proposal card before accepting; when both fit, both are proposed side by side.
Result: The toolkit that is wired matches the shape asked for: a bc1 wallet on the Bitcoin network, or a ckBTC deposit address that credits the ICP wallet 1:1.
BC-BTC-04. Inscribe an ordinal from the app
Path:/workspace → prompt "members can inscribe ordinals from their own taproot wallet" → Kontext Ordinals, Runes & BRC-20
You do:
Accept the Ordinals proposal, then deploy and sign in.
Open the vault screen; note both addresses, the vault (bc1p) and the payment address (bc1q).
Send bitcoin to the payment address, since it pays every fee.
Choose a content type and the content (up to 60,000 bytes), then inscribe.
Watch the history row move from sent to pending to confirmed.
Result: The canister broadcasts a commit and a reveal on Bitcoin and returns the inscription id; the inscription appears in the vault once ord indexes it, and until then the vault view says some new outputs are not indexed yet.
BC-BTC-05. Send an inscription or runes to someone else
Path: the deployed app → vault screen (Ordinals)
You do:
Pick an inscription the vault holds, or a rune and an amount.
Enter the recipient's Taproot (bc1p) address.
Send, and leave the rune id empty to have it looked up by name.
Check the history row until it confirms.
Result: The inscription or runes move to the recipient with fees paid only from clean payment outputs; a non-Taproot address is refused, and a partial rune send without the platform indexer key says the indexer is not configured.
BC-BTC-06. Move BRC-20 tokens in two steps
Path: the deployed app → vault screen (BRC-20)
You do:
Enter the ticker (4 or 5 characters) and read its available, transferable and overall balance.
Inscribe a transfer for the amount; it is refused if the available balance does not cover it.
Wait for the reveal to confirm in history.
Send that transfer inscription to the recipient's Taproot address.
Result: The BRC-20 amount moves when the transfer inscription is sent; without UNISAT_API_KEY on the platform the balance and the transfer both say the indexer is not configured, never zero.
BC-BTC-07. Connect your LNbits wallet and set limits
Path: the deployed app → owner controls (Lightning)
You do:
In LNbits, open the wallet and copy its instance URL, invoice key and admin key.
Paste the URL and the invoice key; add the admin key only if the app should pay.
Save; both keys are checked against the instance before they are kept.
Set a per-payment limit and a daily limit in sats.
Result: The app shows the wallet as connected and able to pay; with no admin key it stays receive-only, and with no limits every payment is refused with "Payments are off until the owner sets a per-payment and a daily limit."
BC-BTC-08. Take a Lightning tip
Path:/workspace → prompt "add a lightning tip jar" → Kontext Lightning Payments
You do:
Accept the Lightning proposal and deploy, then connect your LNbits wallet as the owner.
As a visitor, sign in and ask for an invoice of an amount in sats.
Scan the QR, or copy the bolt11, into any Lightning wallet and pay it.
Watch the invoice in the list.
Result: The invoice turns paid once LNbits reports it paid, or expired if nobody pays before its expiry; until the owner connects a wallet the screen says Lightning is not set up.
BC-BTC-09. Pay a Lightning invoice as the owner
Path: the deployed app → owner controls (Lightning)
You do:
Paste a bolt11 invoice and decode it to see its amount, expiry and description.
Press pay.
If the entry shows unknown, refresh it before trying anything else.
Result: The payment goes through LNbits inside your limits; an invoice with no amount, an expired one, one over a limit, one the wallet cannot cover, or one already paid is refused by name before the admin key is used.
BC-BTC-10. Give members a Stacks wallet
Path:/workspace → prompt "members get a stacks wallet and can send stx" → Kontext Stacks Wallet
You do:
Accept the Stacks proposal and deploy.
Sign in and open the wallet screen to see your SP address and its QR.
Send STX to it from another wallet.
Refresh the balance.
Result: Each signed-in person has an SP address from the threshold key; before any STX arrives the wallet says it is not funded and cannot pay a fee yet, never that it is empty and ready.
BC-BTC-11. Send sBTC or another SIP-010 token
Path: the deployed app → wallet screen (Stacks tokens)
You do:
Pick the token (sBTC, ALEX, or a contract id) and check its balance.
Enter the recipient's SP address and an amount in the token's decimals.
Send.
Follow the history row until it leaves pending.
Result: The transfer is sent in deny mode with an exact post-condition naming the asset read from the contract, so the history shows success or abort_by_post_condition by name; a fee above the owner's cap is refused before signing.
BC-BTC-12. Call a Clarity contract from the app
Path: the deployed app → a screen built on a Clarity contract (Stacks)
You do:
Read contract state with a read-only function; the node answers for free.
Make a write call with the arguments and any post-conditions for what it may move.
Wait for the history row to settle.
Result: The call is signed by the canister and broadcast; if it tries to move an asset it did not declare it aborts on-chain instead, and the history says abort_by_post_condition or abort_by_response rather than success.
BC-CHN-01. Give every member a Solana wallet for USDC
Path:/workspace → prompt "members hold USDC on Solana and send it to each other" → Kontext Solana Wallet
You do:
Describe the job in Workspace Chat and accept the Kontext Solana Wallet proposal.
Deploy the app and sign in.
Open the wallet screen and copy your base58 address.
Send SOL for fees and USDC to that address from another wallet.
Enter a recipient's wallet address and an amount, then send USDC.
Result: The send returns a signature that shows as sent until the cluster reports confirmed or finalized; the recipient's token account is created if they never held USDC, and a USDC balance for someone who never held it shows an error rather than zero.
BC-CHN-02. Send LINK from Solana to Ethereum over CCIP
Path: the deployed app → wallet screen (Solana, CCIP)
You do:
Make sure the Solana address holds LINK and enough SOL for the fee.
Pick Ethereum as the destination and enter the receiving 0x address.
Enter the amount and read the fee quote in SOL.
Confirm the send.
Open the returned signature on ccip.chain.link to follow delivery.
Result: The canister approves and sends in one transaction; if SOL is under the fee plus 5,000 lamports or the LINK balance is short, it refuses with "Not funded" before anything is signed, and a mint with no CCIP pool is refused by name.
BC-CHN-03. Point the Solana wallet at Devnet for testing
Path: the deployed app → owner controls (Solana)
You do:
Sign in as the app owner.
Switch the cluster to Devnet.
Optionally enter your own https RPC endpoints; they must agree with each other.
Refresh the balance on the wallet screen.
Result: Reads and sends go to Devnet (or to your endpoints); a URL that is not https is refused, and non-owners are told only the owner may switch clusters.
BC-CHN-04. Pay contributors in USDC on Stellar
Path:/workspace → prompt "pay contributors in USDC on Stellar from a treasury wallet" → Kontext Stellar Wallet
You do:
Describe the job and accept the Kontext Stellar Wallet proposal.
Deploy and sign in as the owner, then copy the treasury's G… address.
Send at least 1 XLM to it so the account exists, then add USDC.
Pick USDC from the balance list, enter a contributor's G… address, an amount and an optional memo.
Send, then watch the payment in the history list.
Result: The payment shows as sent until Horizon reports it confirmed in a ledger; before the account holds 1 XLM, balances are an empty list and a send is refused as not funded yet.
BC-CHN-05. Open a new Stellar account with its first payment
Path: the deployed app → wallet screen (Stellar)
You do:
Enter the address of a Stellar account that has never been funded.
Enter an amount of XLM of at least 1.
Send.
Look the recipient up with the balance check for any address.
Result: The payment is submitted as a create-account and the new account appears with that XLM; less than 1 XLM, or an issued asset, to a missing account is refused with the reason.
BC-CHN-06. Hold ATOM and move it to Osmosis over IBC
Path:/workspace → prompt "members send atom and do ibc transfers to osmosis" → Kontext Cosmos Wallet
You do:
Accept the Kontext Cosmos Wallet proposal and deploy.
Sign in and open the wallet screen on Cosmos Hub; copy your cosmos1… address.
Send ATOM to it from another wallet so it can pay fees.
Start an IBC transfer on channel-141 to your osmo1… address with an amount.
Watch the transfer in the history list.
Result: The transfer shows as sent until the Hub reports it in a block as confirmed; before the address has received anything, the send is refused because it cannot pay a fee yet.
BC-CHN-07. Add a Cosmos chain the app does not know yet
Path: the deployed app → owner controls (Cosmos chains)
You do:
Sign in as the app owner.
Add a chain row with its chain id, bech32 prefix, fee denom, symbol, decimals, https REST host and minimum gas price.
Optionally make it the default chain.
Open the wallet screen and pick the new chain.
Result: Every signed-in person gets an address on the new chain from the same key; a REST host that is not https, or a row without a chain id, prefix, fee denom or gas price, is refused.
BC-CHN-08. Give each person a Sui address and send SUI
Path:/workspace → prompt "every member gets a sui wallet and can send sui" → Kontext Sui Wallet
You do:
Accept the Kontext Sui Wallet proposal and deploy.
Sign in and open the wallet screen; copy your 0x… address.
Send SUI to it from another wallet.
Enter a recipient's 0x… address and an amount, then send.
Result: The send returns a digest that shows as sent until the node reports success; a wallet with no SUI is refused as holding no SUI yet, and an amount that leaves no room for the 0.005 SUI gas budget is refused as not enough SUI.
BC-CHN-09. Use your own Sui node
Path: the deployed app → owner controls (Sui)
You do:
Sign in as the app owner.
Switch to testnet if you are testing.
Enter your own https JSON-RPC URL.
Refresh the balance on the wallet screen.
Result: Reads and sends go through your node; a URL that is not https is refused, and an empty URL returns to the publicnode default.
BC-CHN-10. Pay out in APT, including to people with no Aptos account yet
Path:/workspace → prompt "an aptos wallet that pays out apt to members" → Kontext Aptos Wallet
You do:
Accept the Kontext Aptos Wallet proposal and deploy.
Sign in, open the wallet screen and copy your 0x… address.
Send APT to it from another wallet.
Enter a recipient's 0x… address, even one that has never been used, and an amount.
Send and watch the history list.
Result: The send shows as pending until the node reports success, and the recipient's account is created by the transfer; a balance that cannot cover the amount plus the gas ceiling is refused as not enough APT before anything is signed.
BC-CHN-11. Send a CCIP message from Aptos to Base
Path: the deployed app → wallet screen (Aptos, CCIP)
You do:
Make sure the Aptos address holds APT.
Pick Base as the destination and enter the receiving contract's 0x address and the message data.
Read the fee quote in octas.
Send the message.
Follow it on ccip.chain.link with the returned hash.
Result: The router takes the message and the fee in APT; if the balance is under the fee plus the gas ceiling it is refused as not enough APT, and an empty message is refused because token transfers from Aptos are not built.
BC-CHN-12. Fund a NEAR implicit account and send NEAR
Path:/workspace → prompt "members get a near wallet and can send near to alice.near" → Kontext NEAR Wallet
You do:
Accept the Kontext NEAR Wallet proposal and deploy.
Sign in, open the wallet screen and copy your 64-character implicit account.
Send NEAR to it from another wallet; the transfer creates the account.
Enter alice.near (or another account) and an amount, then send.
Result: The transfer shows as pending until the node reports success; before the account has received NEAR its balance reads 0 and a send is refused as not funded yet.
BC-CHN-13. Call a NEAR contract with a deposit
Path: the deployed app → a screen that calls a contract (NEAR)
You do:
Enter the contract's account id and the method name.
Enter the arguments as JSON.
Set the gas (1 to 300 TGas) and any deposit in NEAR.
Submit the call and open it in the history list.
Result: The call is signed by the canister and shows as pending until the node reports success or failure; arguments that are not JSON, or gas outside 1 to 300 TGas, are refused before anything is signed.
BC-CHN-14. Pay out XRP with a destination tag
Path:/workspace → prompt "pay suppliers in xrp with a destination tag" → Kontext XRP Ledger Wallet
You do:
Accept the Kontext XRP Ledger Wallet proposal and deploy.
Sign in, open the wallet screen and copy your r-address.
Send at least the base reserve (1 XRP today) plus spending money to it from another wallet.
Enter the supplier's r-address, the amount, their destination tag and an optional memo.
Send and watch the payment in the history list.
Result: The payment shows as pending until the ledger validates it; before the wallet has received the reserve it reads 0 and a send is refused as not on the ledger yet.
BC-CHN-15. Create a new XRP Ledger account with a first payment
Path: the deployed app → wallet screen (XRP Ledger)
You do:
Enter an r-address that has never been funded.
Enter an amount of at least the base reserve.
Send.
Check the new address with the balance check for any address.
Result: The payment creates the account once validated; an amount below the reserve is refused before signing with the reserve named in drops.
BC-CHX-01. Open a Hedera account for each member
Path:/workspace → prompt "give every member an hbar wallet" → Kontext Hedera Account
You do:
Accept the Hedera proposal and deploy the app.
Sign in to the app and open the wallet screen.
Copy the alias shown (0.0.) and send some HBAR to it from any Hedera wallet.
Wait for the screen to re-check; the account id 0.0.N appears beside the alias.
Send HBAR to another account id, with an optional memo.
Result: The alias becomes a real Hedera account the moment HBAR reaches it, and the send shows as UNKNOWN until the node's receipt reports SUCCESS or names the failure; before funding, a send is refused with the alias to fund rather than attempted.
BC-CHX-02. Create a loyalty token on Hedera
Path:/workspace → prompt "create a hedera token for loyalty points" → Kontext Hedera Account
You do:
Accept the proposal and deploy; fund the account that will create the token with HBAR.
Create a fungible token with a name, symbol, decimals and initial supply.
Refresh the record until it shows SUCCESS and the new token id.
Mint more units later, or send units to a member's 0.0.N account.
Result: A new HTS token with the creating account as treasury and supply key; the token id is filled in from the mirror node on refresh, and a receiver with no association and no free automatic slot is refused as TOKEN_NOT_ASSOCIATED_TO_ACCOUNT.
BC-CHX-03. Mint NFTs on Hedera and give one away
Path:/workspace → prompt "mint nfts on hedera for event tickets" → Kontext Hedera Account
You do:
Accept the proposal, deploy and fund the account with HBAR.
Create an NFT collection (no decimals, no initial supply; set a maximum supply if the run is capped).
Mint serials, one metadata URI of up to 100 bytes per serial, up to ten at a time.
Send a serial to a member's 0.0.N account.
Open the NFT list to see what the account still holds.
Result: The serials exist on Hedera and move between accounts; more than ten per call or metadata over 100 bytes is refused before signing, with the reason.
BC-CHX-04. Record events on a Hedera Consensus Service topic
Path:/workspace → prompt "log each approval to an hcs topic" → Kontext Hedera Account
You do:
Accept the proposal, deploy and fund the account with HBAR.
Give the app the id of an existing topic (0.0.N).
Post a message of up to 1,024 bytes.
Open the topic view to read the latest messages, newest first.
Result: Each message is ordered and timestamped by Hedera and read back from the mirror node with its sequence number; a topic id that does not exist is reported as such.
BC-CHX-05. Pay members in ALGO
Path:/workspace → prompt "members get an algorand wallet and can send algo to each other" → Kontext Algorand Wallet
You do:
Accept the Algorand proposal and deploy.
Sign in, open the wallet screen and copy your address (or scan its QR code).
Fund it with ALGO from another wallet and wait for the balance to update.
Send an amount to another member's address, with an optional note.
Watch the history row move from pending to confirmed.
Result: ALGO leaves the canister-held address and the row shows confirmed with its round; a send that would dip under the 0.1 ALGO minimum balance is refused as Not funded before anything is signed.
Accept the proposal and deploy; fund the address with a little more than 0.2 ALGO (the minimum balance, the opt-in and the fee).
Opt the address in to USDC (asset 31566704).
Share the address with the payer.
Refresh the balance to see the USDC holding.
Send USDC onward to another address that has also opted in.
Result: The account holds USDC once opted in; sending to an address that has not opted in is refused with the reason, because Algorand would reject it after taking the fee.
BC-CHX-07. Take USDT on TRON
Path:/workspace → prompt "customers pay in usdt on tron" → Kontext TRON Wallet
You do:
Accept the TRON proposal and deploy.
Sign in and open the wallet screen; the T address shows as not activated.
Send some TRX to it so it exists on TRON and can pay for energy.
Share the address with the payer and refresh the USDT balance after they pay.
Send USDT onward; the canister simulates it before signing.
Result: USDT arrives and can be moved from the canister-held address; a transfer the contract would revert, or one whose energy exceeds the owner's fee cap, is refused with the reason and no TRX is burned.
BC-CHX-08. Send TRX and follow it to confirmation
Path:/workspace → prompt "a trx wallet for each member" → Kontext TRON Wallet
You do:
Accept the proposal, deploy and fund your address with TRX.
Enter a recipient's T address and an amount.
Send, then watch the history row.
Open the Tronscan link on the row.
Result: The row moves from sent to included to confirmed once the block is solidified, or reads expired if no block took it; sending to an address that is not yet activated costs extra TRX to create it, and that is included in the funding check.
BC-CHX-09. Hold and send DOT on Asset Hub
Path:/workspace → prompt "a polkadot wallet so members can send dot" → Kontext Polkadot Wallet
You do:
Accept the Polkadot proposal and deploy.
Sign in and copy your address (it starts with 1).
Send at least 0.01 DOT to it from another wallet on Polkadot Asset Hub.
Send DOT to another address; the fee is quoted first.
Watch the history row go from sent to included to finalized.
Result: The transfer is validated by the node before submission and tracked to finalized by the account's nonce; the first transfer to an account that does not exist yet must be at least 0.01 DOT or it is refused with that reason.
BC-CHX-10. Pay out USDT on Polkadot
Path:/workspace → prompt "pay contributors in usdt on polkadot" → Kontext Polkadot Wallet
You do:
Accept the proposal and deploy; the owner controls whether the app is on mainnet or the Paseo testnet.
Fund the wallet with DOT for fees and with USDT (asset 1984).
Enter a recipient address and a USDT amount.
Send and follow the history row.
Result: USDT moves on Asset Hub with the fee paid in DOT; an amount that would leave the sender under USDT's minimum balance, or a first transfer below it, is refused with the reason before anything is signed.
Sign in and copy the addr1 address (or show its QR code to the payer).
Wait for the payment, then refresh the balance.
Send ADA onward to another address, at least the minimum output.
Follow the history row until it reads confirmed.
Result: The balance updates once ADA arrives and a send is confirmed after 10 confirmations; before the first deposit the screen says the address has never received ADA rather than showing an error, and an amount under the minimum output is refused with the minimum stated.
BC-CHX-12. Try a Cardano wallet on preprod first
Path: the deployed app → owner controls (Cardano)
You do:
As the owner, switch the Cardano network to testnet (preprod).
Copy the wallet's addr_test address and fund it with preprod test ADA.
Send test ADA to another preprod address and watch it confirm.
Switch back to mainnet when the flow works.
Result: The same wallet works on preprod with addr_test addresses and Cardanoscan's preprod explorer; an address for the other network is refused with which network it belongs to.
BC-CHX-13. Give each member a TON wallet
Path:/workspace → prompt "members get a ton wallet and can send toncoin" → Kontext TON Wallet
You do:
Accept the TON proposal and deploy.
Sign in and copy your UQ address; the wallet reads as not deployed.
Fund it with TON from another wallet.
Send TON to another address with a short comment.
Watch the history row move from sent to confirmed.
Result: The first send also deploys the wallet contract, and its fee is included in the funding check; sending to a bounceable address with no contract behind it is refused with the non-bounceable form to use, so the coins do not bounce.
BC-CHX-14. Pay out USDT on TON
Path:/workspace → prompt "pay creators in usdt on ton" → Kontext TON Wallet
You do:
Accept the proposal, deploy and fund the wallet with TON for fees.
Receive USDT into the wallet and refresh the jetton balance.
Enter a recipient and an amount and send.
Follow the history row until it reads confirmed.
Result: The USDT moves through the jetton contracts with 0.05 TON attached for their gas (the unused part returns); a wallet that holds none of the jetton, or too little, is refused before anything is signed.
BC-CHX-15. Send EGLD and ESDT tokens
Path:/workspace → prompt "members can send egld and esdt tokens" → Kontext MultiversX Wallet
You do:
Accept the MultiversX proposal and deploy.
Sign in and copy your erd1 address; it reads as not funded.
Send it some EGLD from another wallet so it can pay fees.
Send EGLD, or send USDC by its token identifier, to another erd1 address.
Watch the history row move from pending to success.
Result: The transfer is signed in the canister and tracked to success, fail or invalid as the API reports it; a transfer whose fee exceeds the owner's cap, or that the wallet cannot cover, is refused with the amounts stated.
BC-CHX-16. Call a MultiversX smart contract from the app
Path:/workspace → prompt "call our multiversx smart contract when a member claims" → Kontext MultiversX Wallet
You do:
Accept the proposal, deploy and fund the calling wallet with EGLD.
Give the app the contract's erd1 address and the function name.
Pass the arguments (numbers, text or hex) and any EGLD to attach.
Send the call and follow its history row.
Result: The gas is simulated before signing and the call runs on MultiversX; a call the contract would refuse comes back with the contract's own message and nothing is sent.
BC-STO-01. Give each member a Filecoin wallet and send FIL
Path:/workspace → prompt "members get a filecoin wallet and can send fil to each other" → Filecoin Wallet & Storage
You do:
Accept the Filecoin Wallet & Storage proposal and deploy the app.
Sign in and open the wallet screen; your f1 address and FIL balance appear.
Send some FIL to that address from another wallet, then refresh the balance.
Enter a recipient (f1, f410f, f0 or 0x address) and an amount, and send.
Watch the message in the history list until it settles.
Result: The message is signed by the canister and moves from pending to success or failed (exit N); an address that never received FIL shows as not funded and a send from it is refused before anything is signed.
BC-STO-02. Connect Lighthouse and back files up to Filecoin
Path: the deployed app → owner controls (Filecoin storage)
You do:
Paste your Lighthouse API key; the canister checks it with Lighthouse before keeping it.
Choose whether signed-in people may store files or only you, and set the largest file allowed (up to 1.8 MB).
Store a file from the app's upload screen.
Open the stored file's link and its deal status.
Result: The file gets a CID and a Lighthouse gateway link; its deal list stays empty (no deal yet) until Lighthouse makes deals over the following hours to days, and deals are labelled as reported by Lighthouse.
BC-STO-03. Let members store their own files on Filecoin
Path: the deployed app → file storage screen (Filecoin)
You do:
As the owner, connect Lighthouse and set the store policy to open for signed-in people.
A member signs in and opens the storage screen.
The member picks a file under the per-file cap and stores it.
The member opens their stored-files list and checks the deal status of the new CID.
Result: The file is stored on the owner's Lighthouse account and appears in the member's own list with its CID and gateway link (the owner sees every member's files); while the policy is closed, a member's store is refused with "Only the owner may store files on Filecoin in this app."
BC-STO-04. Archive a record permanently on Arweave
Path:/workspace → prompt "keep a permanent archive of signed contracts on arweave" → Arweave & AO
You do:
Accept the Arweave & AO proposal and deploy the app.
As the owner, open the archive screen and pick a file under 1.5 MB.
Store it; the app shows the new item id with its gateway link.
Open the link, then check the item's status later.
Result: The item is signed by the canister and served by the Turbo gateway at once, shows as bundled until arweave.net reports confirmations, and can be read by anyone by its id forever.
BC-STO-05. Store a larger file by funding Turbo credits
Path: the deployed app → owner controls (Arweave)
You do:
Open the Arweave owner screen and note the signing address and its credits.
Try to store a file larger than the free tier while credits are 0.
Read the refusal, which names the address to fund.
Buy Turbo credits for that Ethereum address at payment.ardrive.io.
Store the file again.
Result: With credits at 0 the upload is refused with the funding note rather than failing silently; once the address holds Turbo credits, the larger item uploads and gets its id.
BC-STO-06. Message an AO process and read its answer
Path: the deployed app → AO screen
You do:
Enter the AO process id and an Action, with any data and tags.
Dry-run it to read the process without committing anything.
Send it as a real message; the app shows the message id.
Ask for the message's result.
Result: The dry-run and the result come back from the compute unit as the process's Messages and Output; if the unit does not serve that process, the app says so by name ("not found in whitelist") and the owner can point it at another unit.
BC-STO-07. Keep app settings and a public log on Aleph
Path:/workspace → prompt "save the app's settings and an activity log on aleph cloud" → Aleph Cloud
You do:
Accept the Aleph Cloud proposal and deploy the app.
As the owner, save the settings screen; the app writes them as the aggregate key you chose.
Record an activity entry; the app appends it as a post of its type.
Reload the app and open the settings and the activity list.
Result: The settings come back from the aggregate and the entries from the account's posts, newest first; both were free to publish and each message shows processed or pending in the history.
BC-STO-08. Fund the account and store a file on Aleph
Path: the deployed app → owner controls (Aleph)
You do:
Open the Aleph owner screen and copy the account's 0x address.
Check the balance; with no ALEPH and no credits it shows as not funded.
Send ALEPH to that Ethereum address.
Store a file of up to 1.5 MB.
Open its link by hash.
Result: The file is stored and addressed by its sha256 and anyone can fetch it from the Aleph API; before funding, the store is refused by name and nothing is signed.
BC-STO-09. Run a function on Aleph compute
Path: the deployed app → owner controls (Aleph compute)
You do:
Store the code archive (a zip) through the app; note its hash.
Deploy it as a program with its entrypoint (for example main:app).
Wait for the allocation to show the node it was placed on.
Check what it costs, then open its address.
Result: The program answers HTTP at aleph.sh/vm/ followed by its hash once the scheduler places it, paid by the ALEPH held on the account; an account with no ALEPH or credits is refused before the message is signed.
BC-STO-10. Forget something the app published
Path: the deployed app → owner controls (Aleph history)
You do:
Open the list of what the app published.
Pick one or more messages to remove.
Give a reason, optionally, and forget them.
Refresh the status of the original message.
Result: A FORGET message signed by the same account is sent, and the original message's status reads forgotten once the network processes it.
BC-STO-11. Deploy a container on Akash under a price ceiling
Path:/workspace → prompt "let me deploy containers to akash from the app" → Decentralized Compute & AI
You do:
Accept the Decentralized Compute & AI proposal and deploy the app.
As the owner, paste your Akash Console API key; it is checked with Akash before it is kept.
Set the limits: an hourly ceiling, how many deployments may be live, and the longest booking in hours.
Browse Akash's GPU prices, then deploy a container image with its port and the hours to book.
Wait while it shows awaiting bids, then open its address once it is running.
Result: The canister leases the cheapest Akash bid at or under your ceiling and shows the deployment running with its public address; if no bid that cheap arrives within ten minutes, it is stopped with that reason.
BC-STO-12. Rent a GPU container on io.net
Path: the deployed app → owner controls (Compute, io.net)
You do:
Paste your io.net IO Cloud API key.
Open the io.net offers and pick a hardware type and a location.
Enter the container image, port, number of GPUs and hours.
Deploy and watch the status until it runs.
Result: The booking is priced first and refused by name if the hourly price is over your ceiling or no total can be read; otherwise it runs for the booked hours through io.net's own time limit and shows its public address.
BC-STO-13. Run a job on Render Network compute (Dispersed)
Path: the deployed app → owner controls (Compute, Dispersed)
You do:
Paste your Dispersed public key and secret key, one per line.
Browse the Dispersed offers for the number of GPUs you need.
Deploy a container image and port with the hours to book.
Refresh the deployment to see its node address.
Result: The job is accepted only when an offer sits at or under your ceiling, every request is signed inside the canister so the secret never leaves it, and a run found billing more than the ceiling is stopped on refresh.
BC-STO-14. Stop a deployment before its time runs out
Path: the deployed app → owner controls (Compute deployments)
You do:
Open the list of deployments.
Pick a live one and press stop.
Refresh the list.
Result: A Fluence VM is terminated by the canister and shows stopping; Akash, io.net and Dispersed are stopped through the stop relay and show stopped, and if the relay cannot be reached the app says so and the deployment still ends at its booked time.
BC-STO-15. Open IO Intelligence chat to members with a daily cap
Path: the deployed app → owner controls (IO Intelligence)
You do:
Pick a model from the IO Intelligence list, which needs no key.
Paste your IO Intelligence API key; it is checked with a one-token answer.
Set the policy: open to signed-in people, the token cap per answer, the daily request cap and the default model.
A member asks a question from the app's chat screen.
Result: The member gets an answer from the chosen open model on your io.net account, cut to your token cap; once the day's requests are used the app refuses with "This app has used today's N AI answers." (opening to members works in an app built with the user scope).
BC-KIT-01. Let members connect MetaMask and pay in USDC on Base
Path:/workspace → prompt "let members connect their metamask and pay in USDC on Base" → Kontext EVM Wallet Connect
You do:
Describe the job in Workspace Chat, naming the person's own wallet.
Review the proposal card and accept the EVM wallet kit; nothing is added to the app's backend.
Deploy, open the app and press the button for the wallet the page found.
Approve the connection in the wallet, then send the USDC and approve the transfer there.
Watch the transfer until its receipt is found, then open the explorer link.
Result: The person paid from their own wallet on Base and paid the gas; the hash shows as pending until the chain returns its receipt, and a browser with no wallet sees "No browser wallet was found" instead of a zero balance.
BC-KIT-02. Gate a members page on holding an NFT
Path: the deployed app → wallet screen (EVM)
You do:
Connect the wallet from the app.
Open the members page, which checks the connected address against the collection.
Read the result: it holds the NFT or it does not.
Result: ERC-721 counts the whole collection, ERC-1155 checks one token id, and a contract that is not an NFT is refused by name rather than read as "holds none".
BC-KIT-03. Take SOL and USDC from a Phantom wallet
Path:/workspace → prompt "connect their phantom wallet to pay in USDC" → Kontext Solana Wallet Connect
You do:
Name Phantom (or Solflare, Backpack) in the prompt and accept the Solana wallet kit.
Deploy and connect the wallet from the app.
Send USDC to the shop's address and approve it in the wallet.
Wait for the signature status to read confirmed.
Result: The payment is signed and paid for in the person's wallet; the recipient's token account is created if it was missing, and the transfer stays pending until the status is confirmed.
BC-KIT-04. Send SUI and show a person's Sui NFTs
Path:/workspace → prompt "a sui dapp where people connect their sui wallet and show their collectibles" → Kontext Sui Wallet Connect
You do:
Accept the Sui wallet kit and deploy.
Connect Slush, Suiet or Nightly from the app.
Open the gallery, which lists owned objects that carry a Display name and image.
Send one object to another address and approve it in the wallet.
Result: The gallery shows the person's own objects, and the transfer is checked against ownership first, then stays pending until its digest reads success or failed.
BC-KIT-05. Pay in APT or USDC from Petra
Path:/workspace → prompt "connect their petra wallet to pay for tickets" → Kontext Aptos Wallet Connect
You do:
Accept the Aptos wallet kit and deploy.
Connect Petra (or Nightly, OKX, Pontem) from the app.
Send APT or USDC and approve it in the wallet.
Watch the transaction status.
Result: The payment runs on whichever network the wallet is on, balances are read exactly through view functions, and the hash stays pending until it reads success or failed.
BC-KIT-06. Accept a Stellar payment through Freighter
Path:/workspace → prompt "let donors connect freighter and give in XLM or USDC" → Kontext Stellar Wallet Connect
You do:
Accept the Stellar wallet kit and deploy.
Connect Freighter from the app.
Enter an amount, an optional memo and the asset, then approve in Freighter.
Watch the payment status.
Result: The donor signs in Freighter and pays the fee; a recipient with no trustline for the asset, or a first XLM payment under 1 XLM to a new account, is refused by name before Freighter opens.
BC-KIT-07. Send XRP with a destination tag from GemWallet
Path:/workspace → prompt "connect gemwallet so customers pay in XRP with their destination tag" → Kontext XRP Ledger Wallet Connect
You do:
Accept the XRP Ledger wallet kit and deploy.
Connect GemWallet from the app.
Send XRP with the destination tag and approve in GemWallet.
Watch the payment status.
Result: GemWallet submits the payment the person approved; a first payment below the live base reserve, or a token to an account with no trustline, is refused by name first.
BC-KIT-08. Hand over an XRPL NFT in two steps
Path: the deployed app → wallet screen (XRP Ledger)
You do:
The holder connects GemWallet and chooses an NFT they hold.
The holder creates the transfer offer to the recipient's address and approves it.
The recipient connects their own GemWallet, finds the offer and accepts it.
Result: The NFT moves only when the recipient accepts, because the offer is a 0-XRP sell offer that only that recipient can take.
BC-KIT-09. Pay with a NEAR wallet picked in NEAR Connect
Path:/workspace → prompt "a near dapp where fans connect their near wallet and tip in USDC" → Kontext NEAR Wallet Connect
You do:
Accept the NEAR wallet kit and deploy.
Press connect; NEAR Connect's own selector lists HOT, Meteor, Intear, MyNearWallet and others.
Send USDC to a creator's account and approve it in the wallet.
Result: If the creator is not yet registered with the token contract, registration and the transfer go in one transaction; a hash stays pending until it reads success or failed.
BC-KIT-10. Take USDT on TRON from TronLink
Path:/workspace → prompt "connect tronlink and pay in USDT" → Kontext TRON Wallet Connect
You do:
Accept the TRON wallet kit and deploy.
Connect TronLink from the app.
Send USDT; the hook simulates the transfer and reads the energy and bandwidth cost first.
Approve it in TronLink and watch the status.
Result: The transfer is confirmed once solidified; a revert, or a burn beyond the TRX the person holds, is refused by name before TronLink opens.
BC-KIT-11. Move USDC from Noble to Osmosis over IBC with Keplr
Path:/workspace → prompt "connect keplr and move noble usdc to osmosis" → Kontext Cosmos Wallet Connect
You do:
Accept the Cosmos wallet kit and deploy.
Connect Keplr (or Leap) on Noble from the app.
Choose Osmosis as the destination and enter the amount.
Approve in the wallet after the live simulation passes.
Result: The IBC transfer runs over a channel read live; a refusal from the simulation, or a fee the account cannot pay, is named before the wallet opens.
BC-KIT-12. Upload a file permanently with Wander
Path:/workspace → prompt "let people connect wander and store their poems permanently on arweave" → Kontext Arweave Wallet Connect
You do:
Accept the Arweave wallet kit and deploy.
Connect Wander from the app.
Pick the file and approve the upload in the wallet.
Open the permanent link once it settles.
Result: The person signs the upload and it is posted to the Turbo bundler; an upload above the free tier is refused with the reason (the bundler wants Turbo credits) instead of failing silently.
BC-KIT-13. Pay in USDT on TON from Tonkeeper or Telegram Wallet
Path:/workspace → prompt "a telegram mini app wallet checkout: connect tonkeeper and pay in USDT" → Kontext TON Wallet Connect
You do:
Accept the TON wallet kit and deploy.
Press connect; TON Connect's own picker offers a QR code, a deep link, an extension or Telegram.
Send USDT and approve it in the wallet.
Watch the status, found by the message hash.
Result: The wallet connects because the platform serves the app's TON Connect manifest for its origin; 0.05 TON travels with the jetton for gas and the unused part comes back.
BC-KIT-14. Gate a Cardano community on a policy id
Path:/workspace → prompt "connect eternl or lace and let holders of our cardano nft in" → Kontext Cardano Wallet Connect
You do:
Accept the Cardano wallet kit and deploy.
Pick the wallet from the list of CIP-30 wallets the page found.
Open the members page, which checks holdings against the policy id.
Result: Holders are let in, and their NFTs show with the CIP-25 or CIP-68 name and image; the holdings are read through Kontext's Cardano service because the public indexer blocks browsers.
BC-KIT-15. Send DOT on Asset Hub from Talisman
Path:/workspace → prompt "connect talisman and send DOT or USDT" → Kontext Polkadot Wallet Connect
You do:
Accept the Polkadot wallet kit and deploy.
Connect Talisman (or SubWallet, Polkadot{.js}, Nova) and pick an account if several are shared.
Send DOT or USDT and approve it in the wallet.
Watch the status move from pending to included and finalized.
Result: The send is dry-run on the live runtime and validated by the node first, so a shortfall or an existential-deposit problem is named before anything is submitted.
BC-KIT-16. Build a Bitcoin ordinals gallery with Xverse or Unisat
Path:/workspace → prompt "a bitcoin nft gallery where people connect xverse or unisat and show their ordinals inscriptions" → Kontext Bitcoin Wallet Connect
You do:
Accept the Bitcoin wallet kit and deploy.
Connect Unisat, Xverse or Leather from the app.
Open the gallery, which lists the wallet's inscriptions.
Send one inscription to a Taproot address and approve it in the wallet.
Result: The wallet builds and broadcasts the transaction; Leather is refused for inscription sends by name, and an inscription not in the wallet is refused before the wallet opens.
BC-KIT-17. Send sBTC from a Stacks wallet
Path:/workspace → prompt "connect a stacks wallet and send sBTC" → Kontext Stacks Wallet Connect
You do:
Accept the Stacks wallet kit and deploy.
Connect Leather or Xverse from the app.
Send sBTC and approve it in the wallet.
Watch the status.
Result: The transfer goes as a contract call in deny mode with an exact post-condition, so it cannot move more than the screen said; an abort still spends the fee and says so.
BC-KIT-18. Send EGLD from the MultiversX Web Wallet
Path:/workspace → prompt "a multiversx dapp where users connect a multiversx wallet and send EGLD" → Kontext MultiversX Wallet Connect
You do:
Accept the MultiversX wallet kit and deploy.
Press connect and choose the Web Wallet (a popup) or the DeFi Wallet extension.
Enter the recipient, the amount and an optional note, then approve in the wallet.
Watch the status.
Result: The hook broadcasts the signed transaction and refuses one the wallet changed; status reads pending, success, fail or invalid with a reason.
How it works
Selection. Each toolkit has phrases that propose it. Every phrase was probed against ordinary prose before it shipped: "the ripple effect" or "sui generis" propose nothing. A keyword only names what the module provides, so browser-extension names map to Lane B kits, never to Lane A modules. Proposals appear as cards; accepting one wires it.
Seeding. One generic native mount adds the module to the app's Motoko backend, together with the canister methods and a hook. Chain modules pull in what they need (e.g. the EVM wallet implies the threshold key and the EVM reader).
Signing (Lane A). The canister asks its subnet to sign: ECDSA for Bitcoin, EVM, TRON, Cosmos and Stacks; Schnorr (BIP-340 / Taproot) for Ordinals; Ed25519 for Solana, Sui, Aptos, NEAR, XRPL, Stellar, Hedera, Algorand, Polkadot, Cardano, TON and MultiversX. Filecoin uses secp256k1. Keys derive per app and per principal, so every person has their own address and the treasury is separate.
Exactness. Each chain's serializer is pinned byte for byte to that chain's own SDK, and the Motoko is executed in the real moc interpreter against recorded vectors; a string check is not enough. Endpoints are live-read before they become defaults, and each is owner-configurable.
Honest states. An unfunded address is a state, not an error: the module returns the address to fund. A missing key is not configured, and names the key. A network refusal is reported by the network's own name (BUSY, actNotFound…), never as an empty result.
Two narrow platform services (ZA):
Bitcoin indexer route. Read-only BRC-20 balances and rune ids through the UniSat Open API, on one platform key. Hiro's ordinals and runes APIs answer 410 Gone.
Compute stop relay (POST /api/compute-relay/stop). A canister outcall can only send GET, POST and HEAD. Akash and io.net stop with DELETE, and Dispersed with PUT. The relay makes exactly that one call:
fixed URL templates only;
ids validated by shape;
only the provider's auth headers forwarded;
nothing stored or logged.
Measured before relying on it:
The IC Bitcoin API returns txids in internal (reversed) byte order.
Akash runs about 613 blocks an hour.
Filecoin message CIDs match a live Lotus node.
Lighthouse deal ids do not resolve on-chain.
Record.docs/engine/BLOCKCHAIN_TOOLKITS_PLAN.md holds the plan and a newest-first log of what each wave measured.
Measured facts, by network
Each line was checked against a live network, the chain's own SDK, or an executed test, and is recorded in docs/engine/BLOCKCHAIN_TOOLKITS_PLAN.md.
App platform and Internet Computer
ICP mainnet, ckETH minter: minimum_withdrawal_amount exists only inside get_minter_info, not as its own method (read from the live minter's candid on 2026-09-26).
ICP mainnet, ckETH minter: a deposit routed to a subaccount must go through deposit_with_subaccount_helper_contract_address (depositEth(bytes32, bytes32)); the older principal-only helper cannot route to a subaccount, and the live minter publishes both.
ICP mainnet, ckBTC minter: the live NoNewUtxos reply also carries suspended_utxos, which the module's decode ignores.
ICP mainnet, ckBTC and ckETH minters: both interfaces were checked against the live minters' candid:service metadata on 2026-09-26; a variant case the module does not declare would fail to decode, so they are re-read when a minter announces a change.
ICRC-1 standard: the hooks' textual account encoding reproduces the standard's own example (k2t6j-…-6ae-6cc627i.1) and was cross-checked with Node's zlib.crc32.
Ethereum and EVM networks
Internet Computer (EVM RPC canister): in its live candid, read 2026-09-26, request is deprecated in favour of multi_request, so the reader calls only multi_request.
EVM networks (Wave 10a, 2026-09-27): each new default row was read live per provider URL with eth_chainId, the latest block, eth_maxPriorityFeePerGas, eth_gasPrice and a transfer eth_estimateGas. Of the explorers, 19 answered and 15 showed a real recent hash; four Etherscan-family sites answer 403 to a script.
zkSync Era and Filecoin FEVM: honest providers quote different gas and fees. zkSync Era's transfer estimate was 143,601 against 143,196, and Filecoin's tip was 200,660 / 199,623 / 198,962. This is why fee quotes are reconciled to the highest within twice the lowest instead of requiring agreement.
Not added as rows, after measurement:
Plasma, which had only one fully working public RPC;
Moonbeam, where every RPC that answered served a head 48 days old;
Fantom Opera, which migrated to Sonic.
No live send has been measured on the rows added in Wave 10a. That needs a funded threshold address.
Z Chain (9369): rpc.zchain.org answers eth_chainId 0x2499 and web3_clientVersion cdk-erigon v2.64, making it a Polygon CDK L2 of Ethereum. Blocks carry EIP-1559 fields with a base fee of 0, and zscan.live serves a working Blockscout v2 API.
Z Chain: MEOW's symbol and 18 decimals were read from the MEOW contract itself (2026-09-27).
Cross-Chain address book (2026-09-26): 88 entries on the eight chains were checked with eth_getCode plus an identifying view call, and 0 were wrong. Circle's, Axelar's and Wormhole's own address pages agree.
Circle CCTP: TokenMessenger has no localDomain(), so its identity check is localMessageTransmitter().
Wormhole (Linea): Linea has a Wormhole core contract (Wormhole chain id 38) and no token bridge.
Pyth (Ethereum): the on-chain price read live was a month old. On-chain Pyth prices are pushed, so a screen must show their age.
Hyperlane: the Mailbox address is different on every chain, and the domain id equals the chain id on all eight book chains. Ethereum's Mailbox answers localDomain() = 1 and quoted a dispatch to Base at 20,506,258,777,710 wei. XDC, Hedera and Z Chain have no Hyperlane registry entry.
Chainlink CCIP directory (2026-09-27): 76 EVM chains, and exactly three non-EVM mainnets: Solana, Aptos and Canton. Canton was dropped, because the router's fee quoter returns InvalidChainFamilySelector for it.
Chainlink CCIP (Ethereum router), measured live:
EVM to Aptos quoted 324,916,072,315,730 wei.
EVM to Solana (token-only) quoted 185,695,339,164,321 wei, against 189,379,653,578,301 wei to Base.
A receiver of 0x…01 is refused with Invalid32ByteAddress.
Chainlink CCIP (Aptos router): type_and_version is "Router 1.6.0", and get_dest_chains names all eight book EVM chains. A "hello" message to Ethereum quoted 76,985,823 octas.
Chainlink CCIP (Solana router): the Motoko-built data message simulates clean on mainnet, with get_fee 5,757,880 lamports and ccip_send using 116,177 compute units. A 1 LINK token send to Ethereum quoted 13,318,877 lamports and used 249,316 compute units, against 249,314 for the Chainlink SDK.
Chainlink CCIP SDK: @chainlink/ccip-sdk 1.14.0 needs Node 24 or later. The EVM-side extra args were pinned against ethers instead, and confirmed by the Aptos router's live get_fee.
ZNS (Z Chain): all seven ZNS contracts are verified on zscan.live. The subdomain hash keccak256(parent ‖ keccak256(label)) matches ZNSSubRegistrar.hashWithParent live. ZNSDomainToken.totalSupply() was 0 on 2026-09-27, so every name resolved as not registered.
Hyperliquid (mainnet and testnet, 2026-09-28): an order signed by the module's bytes from a fresh key came back "User or API Wallet does not exist.", and a withdrawal came back "Must deposit before performing actions. User: ". So the exchange recovered the module's own address.
Hyperliquid signing: a signature made over the other network's source value recovered to a stranger's address.
Hyperliquid (SDK): the msgpack, action hashes and EIP-712 digests are executed in the Motoko interpreter against hyperliquid-python-sdk vectors, and the SDK's own signatures recover to the key's address.
Hyperliquid (browser wallets): a browser wallet refuses the exchange's chainId-1337 typed data. This is why trading from a person's own wallet is not built.
Bitcoin and its layers
Bitcoin (mainnet): the IC Bitcoin API returns a UTXO's txid in internal byte order. The bytes from bitcoin_get_utxos_query equal mempool.space's txid only when reversed. Every canister send made before fix ZA aedb1e8 (2026-09-28) referenced its inputs by reversed txids and could not have been valid; txidOfUtxo now reverses them.
Bitcoin: the request shapes for bitcoin_get_balance, bitcoin_get_utxos, bitcoin_get_current_fee_percentiles and bitcoin_send_transaction were taken from the Bitcoin canister's live candid, read 2026-09-26.
Bitcoin: RIPEMD-160, BIP-173 bech32 addresses and the BIP-143 native-P2WPKH sighash are executed in the real Motoko interpreter against the standards' own vectors. The BIP-143 digest is also recomputed by an independent JavaScript implementation in the test.
Bitcoin (cost, as stated in the module): about 10B cycles for the UTXO read, 5B plus 20M per byte to broadcast, and about 26B cycles per input signature.
Bitcoin (Taproot): ordinals encoders run in the real Motoko interpreter against vectors recorded from bitcoinjs-lib, @scure/btc-signer, micro-ordinals and runestone-lib: 23 checks. They cover:
the BIP-341 key-path address;
the key-path and BIP-143 digests;
the ord envelope in 520-byte pushes;
the commit under the NUMS key and its control block;
runestones.
@noble's BIP-340 verifies a signature by the tweaked key against the output key the Motoko derived.
Hiro's ordinals and runes APIs answered 410 Gone (2026-09-27), and ordinals.com's JSON API is disabled. Its recursive /r/ endpoints are open without a key, which is why inscriptions and runes per output are read from ord and BRC-20 balances and rune ids come from the UniSat Open API.
ord (mainnet): /r/utxo carries runes as {"runes":{"NAME":{"amount","divisibility","symbol"}}}.
Bitcoin (Taproot): an output key must lie on secp256k1. Coins sent to any other 32 bytes can never be spent, so such an address is refused.
Lightning (LNbits): the module's API shapes were read from demo.lnbits.com's OpenAPI document on 2026-09-27.
Lightning (demo.lnbits.com, LNbits 1.6.1rc2): checked live were invoice create, status, decode, wallet read, the pay refusal, and wrong-key and malformed-invoice replies. Those replies are the fixture the decoders run against in the Motoko interpreter: 32 checks.
Lightning (LNbits): "Insufficient balance." comes back as HTTP 520 with status: "failed", not a 4xx. A definite refusal is therefore read from the body, and a transport error is not treated as one.
Lightning: the paid path of an outgoing payment has not been observed live, because it needs a funded wallet. It is the one unverified leg.
Stacks (mainnet): the node's middle fee tier read 0.166 STX for a plain transfer (2026-09-27), skewed by bots paying 1 to 2.5 STX per contract call. Confirmed transfers paid the 180 µSTX minimum the low tier gives, so the wallet uses the low tier.
Stacks (mainnet): the live network answered NotEnoughFunds for a transaction built by the Motoko module and SignatureValidation for the same transaction with a flipped signature.
Stacks: c32check addresses, every Clarity value kind, STX / FT / NFT post-conditions, payloads, the SIP-005 sighashes, the signed bytes and the txid match @stacks/transactions 7.x byte for byte, on mainnet and testnet. They are executed in the Motoko interpreter, and @noble verifies the SDK's signature.
Solana: the IC SOL RPC canister is tghme-zyaaa-aaaar-qarca-cai; its live candid was read 2026-09-26 and only the generic jsonRequest is used.
Solana: the associated token address of a fixed owner and the USDC mint, and a 1 SOL transfer message, were matched byte for byte against @noble reference code.
Solana: a CCIP data message built by the canister simulated clean on the mainnet router; get_fee returned 5,757,880 lamports and ccip_send used 116,177 compute units.
Solana: a CCIP LINK → Ethereum token transfer (934-byte v0 message) matched @chainlink/ccip-sdk 1.14.0 and simulated clean on mainnet at 249,316 compute units; get_fee for 1 LINK was 13,318,877 lamports.
Solana: the router's token registry for USDC sets supports_auto_derivation, which is why the USDC pool is refused and LINK is not.
Solana: publicnode and dRPC do not implement getAssetsByOwner, and Helius and Ankr need a key, so NFT collection listing needs a DAS key.
Stellar: https://horizon.stellar.org was read live on 2026-09-26 (accounts, /fee_stats, transactions, form-encoded POST /transactions, the 400 and 404 reply shapes).
Stellar: five transaction envelopes (a memo'd XLM payment, a create-account, USDC, a 12-character asset, a muxed destination) match @stellar/stellar-base 13.1.0 byte for byte in 33 executed vectors.
Stellar: @noble's Ed25519 verified stellar-base's signature over the hash the Motoko computed, which proves the IC's Ed25519 key signs what Stellar expects.
Stellar: the public network id is sha256 of "Public Global Stellar Network ; September 2015" (7ac33997…a979), recomputed rather than pinned.
Cosmos: each built-in chain id was read back from node_info on its publicnode REST host on 2026-09-26 (gaia v28.3.0, osmosis v31.1.0, celestia v9.0.4, juno v30.0.0, akash v2.1.0, dydx v9.7.1, sei pacific-1 v6.6.1).
Cosmos: node minimum gas prices read live: Hub 0.005uatom, Celestia 0.002utia, Akash 0.0025uakt, dYdX 12500000000adydx, Osmosis base fee 0.03uosmo; Juno and Sei publish none, so the chain registry's fee token is used.
Cosmos: the Hub ⇄ Osmosis IBC pair is channel-141 ⇄ channel-0, both open, each naming the other's chain id.
Cosmos: a never-funded address answers 404 code 5 on /auth/accounts.
Cosmos (wallet kit): CW-721 reads, gating and a simulated transfer_nft checked 38/38 on Juno; every public Stargaze REST endpoint tried was unreachable.
Sui: the public Mysten fullnode has retired JSON-RPC ("Method not found … migrate to gRPC or GraphQL", measured 2026-09-26), so the wallet defaults to publicnode (mainnet chain 35834a8a, testnet 4c78adac, both read live).
Sui: 17 vectors (whole transaction, intent hash, digest, serialized signature) match @mysten/sui 2.33.1 byte for byte, and @noble verifies the SDK's signature over the intent hash the Motoko computed.
Sui: the pure-Motoko BLAKE2b-256 matches @noble on five inputs, including an exact 128-byte block and a two-block message.
Sui (wallet kit): NFT holdings, gating by Move type and object transfers checked 28/28 as a real SuiNS owner.
Aptos: the Aptos Labs fullnode rate-limits anonymous callers (40,000 CU per five minutes, hit on the first probe), so mainnet defaults to publicnode (chain id 1, ledger info read live 2026-09-26).
Aptos: eight vectors match @aptos-labs/ts-sdk 7.3.0 byte for byte; the CCIP payload is pinned against the same SDK.
Aptos: both network defaults (publicnode for mainnet, api.testnet.aptoslabs.com for testnet) were answered live when the network switch was added.
Aptos: the CCIP router was read live (Router 1.6.0; get_dest_chains names 14 selectors including the eight EVM chains in the address book), and a live get_fee for a "hello" message to Ethereum returned 76,985,823 octas.
Aptos (wallet kit): digital-asset holdings, collection gating and object transfers checked 28/28; a soulbound token is refused.
NEAR: rpc.mainnet.near.org and rpc.testnet.near.org were read live on 2026-09-26 (chain ids "mainnet" and "testnet").
NEAR: a missing access key comes back as an in-result error rather than a JSON-RPC error, and that is read as "not funded yet"; UNKNOWN_TRANSACTION was observed as the pending shape.
NEAR: ten vectors (a Transfer and a FunctionCall transaction, the hash in hex and base58, the signed transaction) match near-api-js 7.3.1 byte for byte, and @noble verifies the SDK's signature over the hash the Motoko computed.
NEAR (wallet kit): NEP-171 holdings, nft_supply_for_owner gating and nft_transfer with 1 yocto checked 28/28 as a Paras holder.
XRP Ledger: xrplcluster.com was read live on 2026-09-26 (network id 0); s1.ripple.com reset the sandbox's connection twice, so it is not the default.
XRP Ledger: actNotFound is the shape of an account that does not exist yet; the base reserve is read from server_state (1 XRP today).
XRP Ledger: twelve vectors match xrpl.js 5.3.0 byte for byte, and @noble verifies the SDK's signature over the signing blob the Motoko built (XRPL's Ed25519 rule signs the whole blob, no hash).
XRP Ledger (wallet kit): XLS-20 holdings, issuer and taxon gating and the offer / accept transfer checked 35/35 against a holder and an open offer found by scanning ledgers.
Hedera, Algorand, TRON, Polkadot, Cardano, TON, MultiversX
Hedera mainnet: the consensus nodes node00.swirldslabs.com:443 (0.0.3) and node01-00-grpc.swirlds.com:443 (0.0.4) answered a plain HTTPS POST of a gRPC-web balance query, so the Internet Computer's HTTPS outcall reaches Hedera with no proxy.
Hedera: grpc-web.myhbarwallet.com returned grpc-status 14 with no frame, so it is not a default.
Hedera: a busy node answers BUSY (precheck 12) inside the reply, and a receipt 15 minutes old came back RECEIPT_NOT_FOUND (18), which is when the mirror node is asked instead.
Hedera mirror node: it names an alias in base32 (upper case, no padding) of the key; the 0.0.<DER hex> form a wallet accepts is refused by the mirror (HTTP 400), and so is lower case.
Hedera mirror node: an account created by an alias transfer has unlimited automatic token associations, so a fresh Kontext account receives HTS tokens with no association step; older accounts such as 0.0.98 show 0.
Hedera mirror node: USDC on Hedera is token 0.0.456858 with 6 decimals.
Hedera: transactions are pinned byte for byte to @hashgraph/sdk 2.81.0; Hedera signs the body bytes themselves (no hash), and the transaction hash is SHA-384 of the signed transaction.
Hedera: token creation, minting, burning and NFTs are pinned to the SDK by test vectors but were not exercised on the live network, because a real token creation costs HBAR the build session did not hold.
Algorand mainnet: a payment built by the Motoko against live params and posted to algod came back with the same transaction id the module computed and was refused only on authorisation; a flipped signature was refused as a bad signature, so the node decoded and verified it.
Algorand mainnet: the test key's account turned out to be rekeyed (auth-addr set), so the module now reads auth-addr and refuses a rekeyed account by name before signing.
Algorand: transactions are pinned to algosdk 3.x (canonical msgpack, "TX" prefix signed with no pre-hash); genesis, round and fee are read from /v2/transactions/params on every send.
TRON (live node): a TRX transfer built by the Motoko against a live block, from an unfunded key, was broadcast; the node returned the same transaction id, passed the signature and stopped at "account … does not exist"; a flipped signature came back SIGERROR.
TRON: TronGrid refuses a fourth request per second without an API key (HTTP 429), which is why PublicNode is tried first.
TRON (live): the energy fee measured 100 sun (not the 210 or 420 older docs quote), so chain parameters and account resources are read on every send.
TRON: /wallet/getblock {detail:false} returns about 0.5 KB, against 470 KB for getnowblock.
TRON: an address that never received TRX does not exist on the network (getaccount answers {}).
TRON: transactions are pinned to TronWeb 6.5.1 (signature as r ‖ s ‖ recovery id + 27).
Polkadot: the relay chain (rpc.polkadot.io) holds about 238 thousand DOT against 1.7 billion on Asset Hub (statemint) and carries a migration pallet, which is why the wallet targets Asset Hub and never the relay endpoint.
Polkadot Asset Hub: a Motoko-built transfer from an unfunded key was validated by the node as Invalid: Payment (format and signature accepted), and a flipped signature as Invalid: BadProof; a live fee quote of 8,808,355 planck is pinned.
Polkadot Asset Hub: transactions are pinned to @polkadot/api against the live metadata (spec 2005000, transaction version 15).
Paseo Asset Hub: it needs three extra extension bytes ahead of the era (transaction version 18); without them the runtime traps, and @polkadot/api's own v4 encoding traps it too.
Cardano (live, through Koios): fees, minimum output and size limit are read from Koios epoch_params (measured at 44 × size + 155,381 lovelace; 4,310 × (160 + output size); 16,384 bytes), never pinned in code.
Cardano (live node): a probe spending someone else's live output had its id computed by the node from the Motoko's bytes and our witness accepted (only the owner's missing witness was reported); a flipped signature added InvalidWitnessesUTXOW.
Cardano (Koios): Koios omits an output's asset_list unless the request sets "_extended": true, so the wallet asks for it; without it an output holding tokens looked token-free.
Cardano: transactions are pinned to @emurgo/cardano-serialization-lib (Conway-era CBOR).
TON (tonapi wallet emulator): with the balance overridden, the emulator took a Motoko-built deploying transfer from a fresh key; the message hash matched, the account went from uninit to active and the contract emitted the outgoing message exactly. Both public emulators skip the signature check, so the signature is proven by the test vectors against @ton/ton, not by the network.
TON mainnet: the test key's wallet is deployed with a zero balance and storage debt, so the network rejects every message to it before execution, which made it useless as a live judge.
TON: the wallet v4R2 code is pinned by hash, and the Motoko re-serializes it to the same bytes as @ton/core.
MultiversX mainnet: valid Motoko-built bytes drew "insufficient funds", and flipped bytes drew "invalid signature", so the network checked the signature over the module's bytes.
MultiversX gateway: gas simulation via /transaction/cost needs a gas limit set (60M is used); without one the gateway answers "insufficient balance".
MultiversX: the signed payload is the SDK's canonical JSON, matched byte for byte, with the BLAKE2b hash as the transaction id.
Storage and compute
Filecoin (Glif, mainnet): the unsigned-message CID the module computes is the one GasEstimateMessageGas returns, and the signed-message CID is the one Lotus named when refusing a flipped signature.
Filecoin (Glif): a valid signature from the module passes verification and reaches the nonce lookup ("actor not found"); a flipped byte fails with "signature verification failed".
Filecoin: the encoders are pinned to @zondax/izari-filecoin 1.2 and @ipld/dag-cbor and executed in the Motoko interpreter (74 checks), covering every address protocol, 0x to f410f and masked 0xff… to f0, message CBOR and the signed-message envelope.
Filecoin (Lighthouse): the deal ids Lighthouse reports do not resolve through the chain's StateMarketStorageDeal, StateGetClaim or StateGetAllocation, which is why deals are shown as reported by Lighthouse.
Filecoin (Lighthouse): an upload with a real Lighthouse key was not yet verified live when the toolkit shipped (no key was in hand).
Arweave (Turbo): POST upload.ardrive.io/v1/tx accepted a ~200-byte Ethereum-signed item from an address that had never paid (200, winc: "0"); turbo-gateway.com served it immediately while arweave.net returned 404 until the bundle settled.
Arweave (Turbo): an unfunded account reads as "User Not Found" on the payment service, which the hook shows as not funded rather than as an error.
AO (testnet units): cu.ao-testnet.xyz answers dryrun and result for a process it does not serve with {"error":"Process not found in whitelist"}, and mu.ao-testnet.xyz expects a signed item body.
Arweave: the data-item layout was read from @dha-team/arbundles 1.0.4's source; seventeen vectors run in the Motoko interpreter against its output (deep hash, Avro tags, the raw item byte for byte, its id, an AO message item), and @noble recovers the SDK's signature to the same address.
Aleph (api2.aleph.im): broadcast answers 200 processed, 202 pending and 422 InvalidMessageFormat, all three observed.
Aleph: the network's own pulse writer publishes AGGREGATE messages with a 0.0 ALEPH and 0 credit balance, so aggregates and posts are free to publish; STORE is metered.
Aleph: a stored file's hash was confirmed as the sha256 of its bytes by downloading a live 304-byte object and hashing it.
Aleph: seventeen vectors from @aleph-sdk/message 1.10.0 run in the Motoko interpreter (the EIP-55 address, AGGREGATE / POST / STORE content and hashes byte for byte, the signed buffer, the envelope and the FORGET content), and @noble recovers the SDK's signature to the same address.
Aleph compute: PROGRAM and INSTANCE item hashes are pinned against the SDK (7 vectors); the scheduler's allocation read and the price read were taken live.
Aleph: both api2 and api3 answered as API servers.
Akash: 1,000 blocks took 5,870 s, so an hour is 613 blocks; a USD ceiling becomes a maximum bid in uact per block at 1 ACT = $1, and bids in any denomination but uact are refused.
Akash Console API: gpu-prices, pricing and placement-options answer without a key.
IO Intelligence: the /models list answers without a key and listed 37 models.
Fluence, io.net IO Cloud and Dispersed: none reads anything without a key.
Fluence: the current API is CPU VMs only, and its old marketplace endpoints return 404.
Render Network: rendering is a desktop app (Render Network Manager) behind whitelisting with no API a canister can drive; Render compute means Dispersed.
Aethir: GPUs are booked through an application form, ATH and a web portal (bare metal for one week minimum), with no booking API.
Compute: HMAC-SHA256 and the Dispersed signature run in the Motoko interpreter against Node's crypto (keys of 3, 64 and 105 bytes); the SDL is parsed by js-yaml; the reply readers run against live keyless replies.
Compute: every authenticated success path (deploy, lease, stop and chat with a real key) was not yet verified live, because no provider key was in hand; io.net's CaaS hardware and price schemas are missing from its spec, so those readers are lenient and fail closed.
Wallet kits
EVM: all 35 viem default RPCs answered eth_chainId and eth_getBalance and passed a browser CORS preflight; BSC's default (thirdweb) once omitted Access-Control-Allow-Origin on a POST, so BSC and Ethereum carry a probed fallback endpoint.
EVM (Ethereum mainnet): BAYC #1's holder reads as holding, NameWrapper is detected as ERC-1155, and USDC is refused as not an NFT contract.
Solana mainnet: api.mainnet-beta.solana.com answered 403 from the network the tests ran on, and publicnode refuses the indexed calls (getTokenAccountsByOwner, getTokenAccountBalance, getTokenSupply), so token balances are read from the token account itself with getAccountInfo.
Solana mainnet: the Token-2022 program id was read off PYUSD's mint (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb).
Solana mainnet: publicnode and dRPC do not implement getAssetsByOwner, and Helius and Ankr need a key, which is why wallet-wide NFT listing is not built.
Aptos: the Aptos SDK fetches with credentials: 'include', so a wildcard CORS answer fails in a browser; the real API echoes the page's origin with Allow-Credentials. The SDK's getBalance returns a lossy number, so balances are read through view functions.
Sui mainnet: the kit's balances, coin selection and transaction status were exercised against the live fullnodes; the pool uses the gRPC client because Sui's public JSON-RPC is retiring.
Stellar mainnet: a key assumed unfunded was in fact funded, so tests use a random address confirmed 404 on Horizon each run.
NEAR: tx with wait_until: FINAL hangs about 30 seconds on an unknown hash before erroring, while NONE answers at once, so an unknown hash reads as pending.
TRON mainnet: getaccount answers an empty object for an account that was never activated; TronLink has no disconnect event, and an empty accountsChanged means the site was locked or revoked.
Cosmos Hub: a refused simulation comes back as HTTP 500 carrying the chain's own {code, message}; with a bonded validator's real public key behind a fake Keplr, the Hub decoded every byte and refused only the fake signature (code 4), for sends and IBC.
Arweave (arweave.net): the gateway answers "Transaction verification failed." alike for a well-signed unfunded transfer, a bad signature and a wrong id.
TON: TON Connect SDK 4 lists an injected wallet only when its registry names that wallet's JS-bridge key; toncenter v3 reports a never-seen address as uninit, read as not existing; toncenter without a key allows one request a second, so reads are paced and retried.
Cardano (mainnet, preprod, preview): Koios answers the CORS preflight but sends no Access-Control-Allow-Origin on the response, which is why reads go through Kontext's /api/cardano.
Cardano mainnet: the hook's ADA and NFT sends, signed with a random key over a real holder's UTXOs, were refused by the node with only MissingVKeyWitnessesUTXOW and InvalidWitnessesUTXOW, meaning no fee, min-ADA, conservation, input or TTL fault.
Polkadot Asset Hub: the live v16 metadata lists thirteen extensions for v4 and eighteen for v5; the hook's extrinsic signed with an unfunded key drew exactly Invalid: Payment, and one flipped bit drew BadProof.
Bitcoin (mempool.space): /tx/:id/status answers "unconfirmed" for a txid nobody broadcast, so status uses /tx/:id.
Bitcoin ordinals: Hiro's ordinals API answers 410 and ordinals.com's JSON API is disabled, but its recursive /r/ endpoints are open, so inscriptions are read from an address's outputs.
Stacks mainnet: the node's middle fee tier read 0.166 STX for a plain transfer, skewed by bots (measured for the Stacks module), so the kit's balance check also uses the low estimate as the floor.
Benefits
No private key anywhere. The app can sign for a chain without a seed phrase to lose or leak, and without a custodian.
Both custody models. The app's own wallet and treasury (Lane A), or the person's own wallet (Lane B), in the same app.
Guardrails are built in. Spend ceilings, caps and approvals are enforced by the canister. Trading and compute stay off until the owner sets limits.
Owner keys stay put. They are checked on entry, stored on the app's canister and never returned. Anything missing says so by name.
One prompt, many networks. 30+ chains, cross-chain protocols, permanent storage and decentralized GPU/CPU from the same build lane.
Who it's for
Primary: founders and builders creating apps that hold, charge, move or store value on-chain: marketplaces, loyalty tokens, NFT drops, crypto checkout, DePIN dashboards, trading desks and AI apps on open models.
Also: communities whose members already have wallets (Lane B), and owners who want a treasury without a custodian (Lane A).
Not: people looking for a standalone exchange or a personal wallet app for the Kontext platform itself. These toolkits live inside apps you build.