The Minotari Payment Processor is a service designed to handle and automate payment processing within the Minotari ecosystem. It integrates with a Tari base node and a Payment Receiver (PR) API to manage payment batches, sign transactions, broadcast them to the network, and confirm their status on-chain.
This project consists of two main workspaces:
This workspace contains autogenerated client code for interacting with external services.
To regenerate the client code, use the following make command:
make regenerate-clientThis is the main executable service of the project.
To get the minotari_payment_processor up and running, follow these steps:
First, you need to create and migrate the SQLite database:
mkdir -p data
sqlx database create
sqlx migrate runDatabase migrations are located in the migrations folder.
If the database schema changes, you need to regenerate the documentation in docs/db/db_schema.sql using the following command:
make db-dumpTransactions are signed by the standalone minotari_offline_signer binary. It keeps the spend and view keys in the OS keystore, encrypted with a passphrase, so it must be initialized once, out-of-band, before the processor can sign anything.
The minotari_offline_signer binary must be built from a tari revision that uses offline-signing payload format 4.0.0.
The unsigned payloads this service feeds the signer, and the signed payloads it reads back, are versioned. Both sides validate that version strictly and reject anything else outright. This service is pinned to a tari_transaction_components revision that speaks payload format 4.0.0 (see rev in minotari_payment_processor/Cargo.toml), so the signer must speak 4.0.0 too.
- Use tari v5.3.0-pre.3 (
9f5adb7), or any other revision matching the pinnedtari_transaction_componentsrevision. This is the earliest tari release that ships theminotari_offline_signerapplication while still on payload format4.0.0. - Do NOT use tari v5.4.0 or later. v5.4.0 bumped the payload format to
5.0.0and added a mandatorypayload_signaturefield. A signer built from v5.4.0+ cannot consume the4.0.0payloads this service produces, and its5.0.0output cannot be parsed back. Every signing attempt will fail, batches will exhaust their retries and be marked as failed.
A mismatch is reported in the log as a failure to deserialize the signed transaction, naming the payload format this service expects.
Build the signer from a checkout of a matching tari revision:
git clone https://github.com/tari-project/tari.git
cd tari
git checkout 9f5adb7 # tari v5.3.0-pre.3, payload format 4.0.0
cargo build --release -p minotari_offline_signer
# binary lands in target/release/minotari_offline_signer -> point OFFLINE_SIGNER_PATH at itNote that this service intentionally does not track the latest tari release: the unsigned payloads originate from the external Payment Receiver API, so moving to payload format 5.0.0 is a coordinated change across both services.
The signer must be initialized once before the processor can sign anything:
# The signer reads the keystore passphrase from TARI_PASSPHRASE
export TARI_PASSPHRASE="my_secure_passphrase"
# Either from a seed phrase...
minotari_offline_signer init seed-words --seed-words "word1 word2 ... word24"
# ...or from raw keys
minotari_offline_signer init keys --spend-key <PRIVATE_SPEND_KEY_HEX> --view-key <PRIVATE_VIEW_KEY_HEX>
# Confirm that it is ready
minotari_offline_signer statusThe passphrase used during init must match the OFFLINE_SIGNER_PASSPHRASE given to the payment processor, otherwise signing will fail.
The minotari_payment_processor is configured using environment variables. These variables can be set in a .env file in the project root or directly in your system environment.
Because the application uses structured configuration, hierarchical settings (like accounts) use double underscores (__) as separators.
DATABASE_URL(Mandatory): The URL for the SQLite database.- Example:
DATABASE_URL="sqlite://data/payments.db"
- Example:
TARI_NETWORK(Optional): The Tari network to run on. Defaults toMainNet.- Options:
MainNet,Esmeralda,NextNet,Igor. - Example:
TARI_NETWORK="Esmeralda"
- Options:
PAYMENT_RECEIVER(Mandatory): The URL of the Payment Receiver (PR) API.- Example:
PAYMENT_RECEIVER="http://localhost:9000"
- Example:
BASE_NODE(Mandatory): The URL of the Tari Base Node.- Example:
BASE_NODE="https://rpc.esmeralda.tari.com"
- Example:
OFFLINE_SIGNER_PATH(Mandatory): The path to theminotari_offline_signerexecutable, used for signing transactions. The binary must be built from a tari revision using offline-signing payload format4.0.0(v5.3.0-pre.3 /9f5adb7); see Offline Signer Setup.- Example:
OFFLINE_SIGNER_PATH="/usr/local/bin/minotari_offline_signer"
- Example:
OFFLINE_SIGNER_PASSPHRASE(Mandatory): The passphrase protecting the offline signer's keystore. It is passed to the signer via theTARI_PASSPHRASEenvironment variable, never as a command line argument.- Example:
OFFLINE_SIGNER_PASSPHRASE="my_secure_passphrase"
- Example:
LISTEN_IP(Optional): The IP address the HTTP API server will listen on. Defaults to0.0.0.0.- Example:
LISTEN_IP="0.0.0.0"
- Example:
LISTEN_PORT(Optional): The port the HTTP API server will listen on. Defaults to9145.- Example:
LISTEN_PORT="9145"
- Example:
CONFIRMATION_CHECKER_REQUIRED_CONFIRMATIONS(Optional): The number of confirmations required before a transaction is considered final. Defaults to10.- Example:
CONFIRMATION_CHECKER_REQUIRED_CONFIRMATIONS="10"
- Example:
MAX_INPUT_COUNT_PER_TX(Optional): The max number of UTXOs, which can be used in a single transaction. If it exceeds this amount, we do a COINJOIN. Defaults to400.- Example:
MAX_INPUT_COUNT_PER_TX="200"
- Example:
FEE_PER_GRAM(Optional): The fee per gram, in MicroMinotari, used when constructing transactions. Must be greater than0. Defaults to5.- Example:
FEE_PER_GRAM="5"
- Example:
REVEAL_PII(Optional): If set totrueor1, the application will stop masking sensitive data (like wallet addresses and amounts) in logs and API outputs. Defaults tofalse.- Example:
REVEAL_PII="true"
- Example:
The application supports configuring multiple payment receiver accounts. Because the number of accounts is dynamic, the configuration uses a specific pattern with double underscores (__) to map environment variables to specific accounts.
The format is: ACCOUNTS__<UNIQUE_IDENTIFIER>__<FIELD>
Each account requires three fields: NAME, VIEW_KEY (Hex), and PUBLIC_SPEND_KEY (Hex).
Example configuration for two accounts ("Primary" and "Backup"):
# Account 1: Identifier 'default'
ACCOUNTS__DEFAULT__NAME="default"
ACCOUNTS__DEFAULT__VIEW_KEY="a1b2c3d4..."
ACCOUNTS__DEFAULT__PUBLIC_SPEND_KEY="e5f6g7h8..."
# Account 2: Identifier 'backup'
ACCOUNTS__BACKUP__NAME="backup"
ACCOUNTS__BACKUP__VIEW_KEY="11223344..."
ACCOUNTS__BACKUP__PUBLIC_SPEND_KEY="55667788..."
## HTTP API
The service exposes an HTTP API that can be easily browsed using Swagger UI. If you are using the default port, you can access it at:
http://localhost:9145/swagger-ui/
The API definitions can be found in `minotari_payment_processor/src/api/mod.rs`.
## Background Workers
The `minotari_payment_processor` runs several background workers that perform specific tasks in the payment processing pipeline. Each worker executes its task and then sleeps for a configurable duration.
The workers are located in the `minotari_payment_processor/src/workers` directory and include:
* `batch_creator`: Responsible for creating new payment batches from received payments.
* `unsigned_tx_creator`: Creates unsigned transactions for payment batches by interacting with the Payment Receiver (PR) API.
* `transaction_signer`: Signs unsigned transactions using the `minotari_offline_signer`.
* `broadcaster`: Broadcasts signed transactions to the Tari base node.
* `confirmation_checker`: Checks the confirmation status of broadcasted transactions on the Tari blockchain.