Skip to content

arkade-os/solver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

solver

solver is a Go implementation of a solver bot for the Arkade Intents. It ships the solverd daemon and the solver CLI.

A maker posts a swap offer as a VTXO on an Arkade. The solver bot watches the arkd transaction stream, finds offers that match its configured pairs and price ranges, and fulfills them atomically via an emulator-signed Arkade transaction.

Architecture

arkd tx stream  ─►  Solver  ─►  Plugin.Match(tx)  ─►  intent  ─►  Plugin.Solve(intent)
                       │
                       └── runs enabled plugins in one runtime

A solver bot is a small runtime that subscribes to arkd's transaction stream and hands every PSBT it sees to one or more plugins. A plugin is just two methods:

type Plugin interface {
    Match(ctx, tx) (intent any, ok bool)   // is this tx relevant? extract what I need
    Solve(ctx, intent)                     // react to it
}

Match is the cheap filter+decode pass; Solve is the (usually slow) reaction. The runtime (pkg/executor) calls Match sequentially for each plugin, then spawns a goroutine for each matched Solve. Panics in either are recovered so one buggy plugin can't take the bot down, and Run waits for in-flight solves to drain on shutdown.

Most plugins read protocol data from the Arkade extension TLV in the OP_RETURN output of the funding tx. Today one plugin ships with the daemon:

  • pkg/banco — swap solver library. Decodes a swap offer, range-checks the amount and price, and fulfills via the emulator.

solverd composes enabled plugins into one Executor runtime. The runtime may still use per-plugin arkd subscriptions internally so server-side filters can drop unrelated txs before they reach the bot. Adding a new protocol means writing a new Plugin and wiring it in cmd/solverd. See pkg/executor/README.md for the plugin authoring guide.

Packages

pkg/contract

Wire-protocol primitives for the swap.

  • Offer — typed swap offer, encoded as a TLV payload inside an Arkade extension packet (PacketType = 0x03). Methods: Serialize, ToPacket, FulfillScript, and VtxoScript (builds the swap taproot tree from the maker, emulator, and signer keys).
  • DeserializeOffer / FindBancoOffer — decode an offer from raw bytes or pull one out of an Arkade extension.
  • CreateOffer — maker-side helper: queries the emulator for its signer key, derives the maker address from the Arkade client, assembles an Offer, and returns the hex-encoded offer + extension packet + swap address to fund (CreateOfferParams / CreateOfferResult).
  • GetOffers — queries the indexer for VTXOs sitting at a swap address, used by a maker to check whether its offer is still live ([]OfferStatus).
  • FulfillOffer — taker-side atomic swap: builds the Arkade transaction that spends the swap VTXO to the maker's pkScript (paying WantAmount/WantAsset) and returns change to the taker, signs it with the emulator, and submits it (FulfillResult).

pkg/executor

Generic plugin-based executor runtime. Consumes a stream of PSBT packets and dispatches each one to its registered plugins.

  • Plugin interface — Match(ctx, *psbt.Packet) (intent any, ok bool) decides whether a tx is interesting; Solve(ctx, intent) reacts to a match.
  • Executor / New(plugins ...Plugin) — runtime wrapping one or more plugins.
  • Run(ctx, source) error — subscribes plugins, fans matches out to Solve goroutines, and returns ctx.Err() on cancel.

pkg/banco

The solver plugin and its supporting types — the building block for a taker bot.

  • Plugin / NewPlugin(Config) — implements executor.Plugin for the swap protocol: decodes the offer from a tx, looks up a matching configured pair, range-checks WantAmount, validates price within 1% of the feed, and fulfills via contract.FulfillOffer.
  • Config — dependencies: arksdk.ArkClient, emulator client, PairRepository, PriceFeed, optional FulfillmentListener, optional logrus.FieldLogger, and PriceCacheTTL (default 5 minutes).
  • Offer / NewOffer(*wire.MsgTx) — wraps contract.Offer with FundingTxid, DepositAsset, and DepositAmount extracted from the funding tx. Helpers: IsBTCDeposit, DepositAssetStr, WantAssetStr, ComputePrice.
  • Pair / PairRepository — trading pair definition (base/quote, min/max amount, decimals, price-feed URL, invert flag) and the read-only repository interface used by the plugin.
  • PriceFeed — pluggable price source; the plugin wraps it in an internal TTL cache.
  • FulfillmentEvent / FulfillmentListener — emitted after every successful fulfillment; the daemon wires a listener that persists trades to SQLite.
  • SubscribeArkd — helper that returns a <-chan *psbt.Packet from arkd's transaction stream, suitable for feeding into Executor.Run.

All pkg/ packages are intended to be importable by other projects and do not depend on any internal/ code.


Binaries

solverd

Daemon that boots a solver, a SQLite-backed wallet, the gRPC+REST API, and the web UI. Configured entirely through environment variables:

Variable Required Default Purpose
SOLVER_ARK_URL arkd gRPC endpoint
SOLVER_WALLET_SEED wallet seed (hex)
SOLVER_EMULATOR_URL emulator endpoint
SOLVER_WALLET_PASSWORD wallet unlock password
SOLVER_DATADIR $HOME/.solverd data directory (SQLite DB lives here)
SOLVER_GRPC_PORT 7070 gRPC listener
SOLVER_HTTP_PORT 7071 HTTP REST + web UI listener
SOLVER_LOG_LEVEL 4 (Info) logrus level
SOLVER_BANCO_ENABLED true enable the swap plugin

The banco plugin must be enabled. The daemon registers all enabled plugins in one solver runtime.

solver

CLI client for the HTTP API. Points at http://localhost:7071 by default (--server or SOLVER_SERVER to override). Commands:

solver pair add     --pair BTC/<asset> --min … --max … --price-feed …
solver pair update  …
solver pair remove  --pair …
solver pair list
solver status
solver balance
solver address

Building

make build          # builds ./solverd and ./solver
make docker         # builds the solverd image
make proto          # regenerates api-spec/protobuf/gen
make sqlc           # regenerates internal/infrastructure/db/sqlite/sqlc
make lint
make test           # unit tests

Integration tests

End-to-end tests run against a local nigiri + arkd stack:

make setup-test-env     # boot nigiri + arkd + emulator, fund arkd wallet
make integrationtest    # run ./test/e2e/...
make teardown-test-env

If nigiri is already running (e.g. in CI, where the vulpemventures/nigiri-github-action sets it up), use make docker-run and make docker-stop instead — they bring up the solverd-side stack and fund the arkd wallet without touching nigiri.

About

Solve intents living in the arkade virtual mempool

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors