ordinals-wallet
ordinals-wallet/ow-cliBuild, debug, and extend the Ordinals Wallet CLI (ow-cli) — a Bitcoin Ordinals marketplace tool for buying, selling, listing, and transferring inscriptions, runes, BRC-20, and Alkanes tokens. Use when working on ow-cli code, its API client, PSBT signing, escrow flows, or any Bitcoin Ordinals / inscription / rune marketplace feature.
SKILL.md
name: ordinals-wallet description: Build, debug, and extend the Ordinals Wallet CLI (ow-cli) — a Bitcoin Ordinals marketplace tool for buying, selling, listing, and transferring inscriptions, runes, BRC-20, and Alkanes tokens. Use when working on ow-cli code, its API client, PSBT signing, escrow flows, or any Bitcoin Ordinals / inscription / rune marketplace feature.
Ordinals Wallet CLI Skill
Project overview
ow-cli is a CLI for Ordinals Wallet. It lets users buy, sell, list, transfer inscriptions and runes from the terminal. Turborepo monorepo at ~/proj/ow/ow-cli with three packages:
| Package | Path | Purpose |
|---|---|---|
@ow-cli/core |
packages/core |
BIP39/BIP32 key derivation, WIF decode, P2TR address, PSBT signing |
@ow-cli/api |
packages/api |
Typed HTTP client for all OW API endpoints (axios) + TAP socket |
@ow-cli/cli |
packages/cli |
Commander.js CLI commands wiring core + api |
Key commands
ow wallet create|import|info|inscriptions|tokens
ow wallet consolidate --fee-rate N [--utxos txid:vout:value,...]
ow market buy <inscription_id> --fee-rate N
ow market buy-rune <txid:vout> --fee-rate N
ow market buy-bulk --ids <id1,id2,...> --fee-rate N
ow market buy-alkane --outpoints <op1,op2,...> --fee-rate N
ow market list <inscription_id> --price N
ow market list-bulk --collection <slug> --above-floor <pct>
ow market delist <inscription_id>
ow inscription info <id>
ow inscription inscribe <file> --fee-rate N
ow inscription send <id> --to <addr> --fee-rate N
ow collection info|listings|history|search
ow send <sats> --to <addr> --fee-rate N
ow fee-estimate
ow wallet rune balance
ow wallet rune send --rune-id <block:tx> --amount N --divisibility N --to <addr> --fee-rate N --outpoints <list>
ow wallet rune split --rune-id <block:tx> --amount N --splits N --divisibility N --fee-rate N --outpoints <list>
ow wallet alkane balance
ow wallet alkane send --rune-id <block:tx> --amount N --divisibility N --to <addr> --fee-rate N --outpoints <list>
ow wallet alkane split --rune-id <block:tx> --amount N --splits N --divisibility N --fee-rate N --outpoints <list>
ow wallet brc20 balance
ow wallet brc20 inscribe-transfer --ticker <name> --amount N --fee-rate N [--splits N]
ow wallet brc20 send [inscription_id] --to <addr> --fee-rate N
ow wallet tap balance
ow wallet tap inscribe-transfer --ticker <name> --amount N --fee-rate N [--splits N]
ow wallet tap send [inscription_id] --to <addr> --fee-rate N
All commands accept --json for machine output and --debug for full API errors.
API base
All HTTP goes through https://turbo.ordinalswallet.com. The client is configured in packages/api/src/client.ts.
Key endpoints:
GET /wallet/:address— wallet info, inscriptions, balancesGET /wallet/:address/utxos|rune-balance|brc20-balance|alkanes-balanceGET /inscription/:id— inscription detailGET /wallet/fee-estimates— fee ratesPOST /wallet/broadcast— broadcast raw txPOST /wallet/purchase|purchase-bulk|purchase-bulk-runes— build purchase PSBTsPOST /wallet/escrow|escrow-bulk— build escrow PSBTsPOST /wallet/send|inscription/send— build send PSBTsPOST /rune/transfer— build rune transfer PSBT (simple or edict-based)POST /alkane/transfer— build alkane transfer PSBTPOST /wallet/build— build consolidation PSBTPOST /wallet/broadcast-bulk— broadcast multiple raw txsPOST /wallet/purchase-bulk-alkanes— build alkane purchase PSBTPOST /market/purchase|purchase-rune— submit signed purchasePOST /market/escrow-bulk— submit signed escrow listingPOST /market/cancel-escrow— cancel listingPOST /inscribe/estimate|upload— inscription cost estimate and uploadGET /collection/:slug|:slug/escrows|:slug/sold-escrows|:slug/statsGET /v2/search/:input— search collections/inscriptions
PSBT signing flow
All signing happens in packages/core/src/signer.ts. Two functions:
signPsbt(opts)
- Parse PSBT with
allowLegacyWitnessUtxo - For each input matching the wallet's P2TR script: set
tapInternalKey - Sign with
signIdxusing sighash types[DEFAULT, ALL, SINGLE|ANYONECANPAY] - Finalize by setting
finalScriptWitness = [tapKeySig] - If
disableExtract: return PSBT hex (for escrow listings). Otherwise: return raw tx hex.
signPurchaseFlow(privateKey, publicKey, setupHex, purchaseHex)
- Sign and extract the setup PSBT → raw tx
- Get the setup txid from the signed transaction
- In the purchase PSBT, replace zero-txid placeholder inputs with the real setup txid
- Sign and extract the purchase PSBT → raw tx
- Return
{ signedSetup, signedPurchase }
Type system
All API types live in packages/api/src/types.ts. No any types — everything is fully typed. Key interfaces:
WalletInfo,WalletInscription,InscriptionDetailRuneBalance,Brc20Balance,AlkanesBalanceEscrow,CollectionMetadata,CollectionStatsFeeEstimates(fields:fastestFee,halfHourFee,hourFee,economyFee,minimumFee)BuildPurchaseRequest/Response,SubmitPurchaseRequest/ResponseBuildEscrowRequest/Response,SubmitEscrowRequest/ResponseSearchResult,SearchCollectionInscribeEstimateRequest/Response,InscribeUploadResponseRuneEdict,RuneOutpoint,BuildRuneEdictTransferRequest,BuildAlkaneTransferRequestBuildConsolidateRequest/Response,BuildPurchaseAlkanesRequest,BroadcastBulkResult
TAP protocol types are in packages/api/src/tap.ts (TapToken).
Testing
pnpm test # all packages
pnpm build # build all
- Core tests:
packages/core/__tests__/— keys, signer, address - API tests:
packages/api/__tests__/— MSW mock server, all endpoints - CLI tests:
packages/cli/__tests__/— validators, errors, output formatting
MSW handlers are in packages/api/__tests__/handlers.ts. Vitest config per-package.
Conventions
- ESM-only (
"type": "module",.jsextensions in imports) tsupfor builds,vitestfor tests- No
anytypes anywhere — useunknown+ type guards or specific interfaces noImplicitAnyenabled intsconfig.base.json- Keystore encrypted with AES-256-GCM at
~/.ow-cli/keystore.json - CLI validators in
packages/cli/src/utils/validate.tsthrowCliError handleError()inpackages/cli/src/utils/errors.tsmaps errors → user messagesformatJson(data: unknown),formatSats(),formatTable()inpackages/cli/src/output.ts