Walkthrough.
Run a negotiation and settlement on Sepolia with two identities. These commands use the helper scripts in the main Erebus repository.
This page describes the Starknet backend. For Monad, see the Monad deal flow.
Before you start
Install the package from the quickstart first. The shell examples also need Git, Python 3, and a Rust toolchain. Clone the main repository, build its CLI, and initialize two Sepolia identities with the commands below. Choose separate accounts and keep the generated keys and state directories separate. Setup asks you to fund each account, then shields the deposit and registers the identity. The payer needs at least 1 STRK in shielded notes for this example; both sides also need public STRK for fees.
git clone https://github.com/PoulavBhowmick03/Erebus
cd Erebus
cargo build --manifest-path sdk/rs/Cargo.toml --bin erebus-cli
# Choose separate accounts and provide Sepolia RPC and prover endpoints.
erebus-init --network sepolia --role payer --config ~/.erebus-a/env --deposit 1 --writes 3
erebus-init --network sepolia --role payee --config ~/.erebus-b/env --deposit 1 --writes 2
# The shell helpers need explicit Sepolia values in each env file.
for erebus_env in ~/.erebus-a/env ~/.erebus-b/env; do
cat >> "$erebus_env" <<'EOF'
STARKNET_CHAIN_ID=0x534e5f5345504f4c4941
POOL_ADDRESS=0x0254a6b2997ef52e9f830ce1f543f6b29768295e8d17e2267d672c552cfe0d91
EOF
done
scripts/agent.sh ~/.erebus-a/env doctor
scripts/agent.sh ~/.erebus-b/env doctorRun the remaining commands from the cloned repository. The helper scripts use the CLI you just built. If setup pauses, use its printed resume command. Do not repeat a shield request with a new operation ID.
Budget for both public fees and shielded payment funds:
- The payee needs an allowance for two charged writes, its own open and its counter, even though it never pays the price itself. Opening a direction submits a real
apply_actionstransaction, incurring the same cost as any other write. - The pool fee comes out of the identity’s public STRK balance. A healthy shielded balance will not cover it, and neither will a large allowance.
doctorflags this as agas_balancewarning when it happens.
Negotiate
Both sides must open their own channel direction. A one-sided open causes an unknown channel handle error on the counterparty, preventing the payee from seeing the offer it needs to answer.
# A opens its direction and proposes
HANDLE_A=$(scripts/agent.sh ~/.erebus-a/env open \
"$(scripts/agent.sh ~/.erebus-b/env whoami)")
scripts/agent.sh ~/.erebus-a/env balance
scripts/agent.sh ~/.erebus-a/env offer "$HANDLE_A" 600000000000000000# B opens its own direction, then sees A's offer there
HANDLE_B=$(scripts/agent.sh ~/.erebus-b/env open \
"$(scripts/agent.sh ~/.erebus-a/env whoami)")
scripts/agent.sh ~/.erebus-b/env status "$HANDLE_B"
scripts/agent.sh ~/.erebus-b/env counter "$HANDLE_B" them:0 1000000000000000000The payer’s balance command checks its shielded notes before the offer. Through MCP, use get_note_balance. Values are expressed in base units, working out to 0.6 and 1.0 STRK in this example. Your agent chooses the prices and deadlines.
Every write takes an operation_id. Save the ID and request before the call. The helper scripts record these in the identity state directory.
Settle
Only the payer settles. accept_and_settle spends the caller’s notes, so the payee waits for the payer to accept its final offer.
# A reads B's counter through A's direction and settles
scripts/agent.sh ~/.erebus-a/env status "$HANDLE_A"
scripts/agent.sh ~/.erebus-a/env accept "$HANDLE_A" them:0Settlement consumes the payer’s notes, creates the payee’s note, returns change if the input values exceed the price, and leaves the channel pair open in case you want to run another deal. The result carries:
Proof generation and provider response times can keep a transaction pending for minutes. Use the recovery steps below if the result is uncertain.
Disclose one deal
grant_viewing_key writes a grant file scoped to one deal and one registered recipient, with an explicit expiry. reveal reads it back and reconstructs that deal. Neither one touches the chain, so neither costs gas.
Use the MCP request examples in the tool reference. Replace the example handles and IDs with values from your session. Choose a registered recipient, a future expiry, and a new output path. Open the file with reveal in that recipient’s session. A grant gives no spending authority. Expiry cannot erase data the recipient already read.
For a local observer example, run python3 scripts/observer.py scripts/fixtures/observer-wire-v3.json. This fixture check does not inspect your transaction or prove privacy against every observer. The script also accepts a Sepolia transaction hash. Compare its output with the authorized reveal. Counterparty addresses and transaction timing remain public.
When a write looks stuck
You must start recovery explicitly. Never generate a new operation_id for a stuck write, as doing so risks duplicate execution and double payment.
Follow this sequence to resolve a stalled transaction:
- Call
reconcilefirst to inspect state. It submits no transactions. - If the classification permits resumption, call
resume_operationwith the original operation_id. - If the proof expired, use
resume_operationto rebuild it only when the journal permits recovery. Keep the same operation_id.
For further setup and recovery instructions, read runbook.md ↗.