sidestr-agent
Rust port of Melvin Carvalho's sidestr sidechains, AGPL-3.0-only: the economic engine for did:nostr agents. A did:nostr key is a sidechain wallet.
sidestr-agent is an agent's wallet on a sidestr sidechain, as a library and
a binary. The agent's Nostr key is the wallet. The x-only public key behind
its npub and its did:nostr:<hex> is the taproot output key its coins pay
(5120‖pubkey, used untweaked, as siding's wallet does). Its chain address is
that script in bech32m under the chain's prefix. One key does three jobs:
- it names the agent;
- it signs the agent's spends;
- it signs the kind-23500 event that carries each spend to the producer's relays.
The binary generalises the tool that ran the first live loop on
sidestr:dreamlab, beside Bitcoin testnet4. That loop was a peg-in, three
trades between Alice and Bob as kind-23500 events each signed with its
agent's own key, and a peg-out. Testnet4 and experimental chains only.
Coins on sidestr:dreamlab have no value.
Install
Commands
# every name of the agent's key: npub, did:nostr, script, chain address
# coins and balance at the producer's tip
# pay another agent by npub (or did:nostr, a drm1… address, a script hex);
# the kind-23500 event is signed by alice's key and published to the relays
# peg out: burn sats the peg holders owe to a testnet4 address
# peg in: what a parent wallet pays (the peg address and its descriptor, the marker)
| flag | meaning | default |
|---|---|---|
--url |
the producer (/coins, /tip, /chain.json, POST /tx) |
http://127.0.0.1:3450 |
--relays |
relays for the kind-23500 event, comma-separated | siding's five defaults |
--key-file |
64 hex characters or an nsec1…; a key is never taken on the command line |
— |
--chain |
read the chain document from a file instead of <url>/chain.json |
— |
Every command prints one JSON object.
The peg-in plan
SPEC 6 (0.0.3) makes the peg output the taproot output the peg holders own, at any position. Who owns it depends on the level:
- Level 1: the producer's parent wallet. Pass
--peg-addresswith an address that wallet gave (getnewaddresson its peg wallet), which it owns. Without one, a level-1 plan is refused rather than guessed. - Level 2: the chain's challenge script. The federation's peg wallet owns it. With no flag, the plan pays the challenge address.
--peg-key, the explicit alternative: the peg address becomestr(<key>, and_v(v:pk(<refund key>), older(<refundBlocks>))). The plan prints its checksummed descriptor, built with rust-miniscript. It counts as a peg-in only after the peg holders import the descriptor (importdescriptors, watch-only is enough). After that, the refund key can sweep a peg left unclaimed forrefundBlocks. The first live peg-in paid such an address:tr(<dreamlab signer>, …)with Alice's refund key.
The plan also prints the marker pegin:<chain id>:<script> and the send
outputs for Bitcoin Core.
Library
use ;
let bob = parse_pubkey.unwrap;
let id = identity.unwrap;
assert_eq!;
assert!;
The docs have a complete offline example: two agents on a chain held in memory, paying each other by npub.
Provenance and licence
This crate builds on sidestr-core, sidestr-wallet and sidestr-nostr,
which port siding, the reference implementation of sidestr by Melvin
Carvalho (github.com/sidestr/spec,
AGPL-3.0). It is licensed AGPL-3.0-only, like everything it derives
from. See LICENSE. Part of
sidestr-rs.
Status — 0.2.0
The offline parts are tested without a network (tests/offline.rs):
- keys against NIP-19's published vectors;
- the live loop's two agents, from did:nostr key to the
drm1…address the chain paid; - a loop on a chain held in memory: a spend by npub, one back by did:nostr, a peg-out, each event verified as signed by the paying agent;
- a level-1 plan without a peg-wallet address is refused; with
--peg-key <signer>, Alice's plan onsidestr:dreamlabgives the address the live peg-in paid on testnet4 (tb1palk8…), and its marker byte for byte; - the plan's descriptor address matches an independent build with
rust-bitcoin's
TaprootBuilder; - the binary's offline commands.
Secret-shaped text (an nsec, or 64 bare hex characters) is never accepted
as a destination or address, and is never echoed. NIP-19 strings are strict
Bech32. Both are pinned in tests/audit_regressions_0_0_3.rs, from the
pre-release verification pass. Relay publishing and the producer's HTTP
calls are sidestr-round and sidestr-wallet's, tested there.