unrip/docs/operator-runbook.md
philipp 41b9ec680b
Some checks failed
deploy / deploy (push) Failing after 1m35s
Implement funded NEAR Intents trade loop
Proof: first non-mocked tradeable loop for one pair using funded NEAR Intents inventory, Kafka, and PostgreSQL.

Assumptions: solver-side execution is performed by signed token_diff quote responses over the Solver Relay; EURe is treated as 1:1 with EUR; k3s runtime uses unrip-dev.near as the named signer account.

Still fake: signer key is not yet registered on intents.near, strategy and executor remain disarmed by default, and no live mainnet quote response has been submitted from this repo yet.
2026-04-02 10:01:15 +02:00

4.5 KiB

Operator Runbook

This turn implements the first funded market-maker loop for the active BTC/EURe pair on NEAR Intents.

Verified venue flow

The implementation follows the official NEAR Intents market-maker path:

  1. Funding handles come from the Passive Deposit/Withdrawal Service deposit_address RPC for the configured treasury chains.
  2. Spendable inventory comes from the Verifier internal ledger on intents.near via mt_batch_balance_of.
  3. Pending deposits remain non-spendable and are tracked from recent_deposits.
  4. Real market-maker execution is a Solver Relay quote_response carrying a signed token_diff.
  5. Named NEAR accounts need the executor public key registered on intents.near via add_public_key before live submission will succeed.

The Message Bus settles matched intents on-chain after a user accepts the quote. The executor therefore submits quote responses; it does not bridge or top up inventory on the hot path.

Required env and secrets

Minimum required runtime values:

  • NEAR_INTENTS_API_KEY
  • NEAR_INTENTS_ACCOUNT_ID
  • NEAR_INTENTS_SIGNER_PRIVATE_KEY
  • POSTGRES_URL

Before the first live attempt on a named NEAR account, register the executor public key on intents.near from that named account:

near contract call-function as-transaction \
  intents.near add_public_key json-args '{
    "public_key": "ed25519:<executor-public-key>"
  }' prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
  sign-as <ACCOUNT_ID> network-config mainnet sign-with-keychain send

The executor stays disarmed by default even after the key is registered.

Local bring-up

npm install
cp .env.example .env
# fill NEAR_INTENTS_API_KEY, NEAR_INTENTS_ACCOUNT_ID, NEAR_INTENTS_SIGNER_PRIVATE_KEY
docker compose up -d --build

Services:

  • near-intents-ingest
  • market-reference-ingest
  • liquidity-manager
  • inventory-sync
  • history-writer
  • strategy-engine
  • trade-executor

Control APIs

Default local ports:

  • 8081 near-intents-ingest
  • 8082 market-reference-ingest
  • 8083 inventory-sync
  • 8084 liquidity-manager
  • 8085 history-writer
  • 8086 strategy-engine
  • 8087 trade-executor

Common inspection:

curl -s http://127.0.0.1:8081/healthz
curl -s http://127.0.0.1:8081/state
curl -s http://127.0.0.1:8086/state
curl -s http://127.0.0.1:8087/state

Useful controls:

curl -s -X POST http://127.0.0.1:8082/refresh
curl -s -X POST http://127.0.0.1:8083/refresh
curl -s -X POST http://127.0.0.1:8084/refresh

curl -s -X POST http://127.0.0.1:8086/arm
curl -s -X POST http://127.0.0.1:8086/disarm
curl -s -X PUT http://127.0.0.1:8086/limits \
  -H 'content-type: application/json' \
  -d '{"max_notional_eure":5}'

curl -s -X POST http://127.0.0.1:8087/arm
curl -s -X POST http://127.0.0.1:8087/disarm

Track a withdrawal so it stays visible in liquidity and inventory state:

curl -s -X POST http://127.0.0.1:8084/track-withdrawal \
  -H 'content-type: application/json' \
  -d '{"withdrawal_hash":"<near-burn-tx-hash>","asset_id":"nep141:btc.omft.near","chain":"btc:mainnet","amount":"1000"}'

Safe arming sequence

  1. Confirm market-reference-ingest is publishing fresh BTC/EUR data.
  2. Confirm inventory-sync shows credited spendable balances on intents.near.
  3. Confirm liquidity-manager shows the expected deposit handle and any pending funding separately from spendable inventory.
  4. Confirm history-writer has PostgreSQL connectivity.
  5. Keep STRATEGY_MAX_NOTIONAL_EURE=5 for the first live test.
  6. Arm strategy-engine first.
  7. Observe actionable decisions without venue errors.
  8. Arm trade-executor only when the signer key is registered and funded inventory is already credited.

What to inspect after a live attempt

  • decision.trade_decision for the reasoning chain.
  • cmd.execute_trade for the emitted quote response command.
  • exec.trade_result for submission outcome.
  • PostgreSQL tables:
    • swap_demand_events
    • market_price_events
    • intent_inventory_snapshots
    • liquidity_actions
    • trade_decisions
    • execute_trade_commands
    • trade_execution_results

Still fake

  • Settlement follow-up after user quote acceptance is only visible indirectly through Solver Relay quote-status observations; the repo records the live quote-response attempt, not an end-user acceptance flow it does not control.
  • The executor checks signer registration best-effort. If the verifier key-check view surface changes, the live submission itself remains the definitive signal.