A C11 blockchain node that ties money to data transparency — every coin carries optional, cryptographically-signed receipts that prove its origin, route, and ownership through every transaction in its lifecycle.
SupraBullion is a Truth-Currency. It grounds the utilitarian purpose of money — as a token of value — in optional, on-chain accountability. Investors are superimposed upon the coins they mint: their intent, encoded at purchase through lock parameters and nano-nosql schemas, travels with the coin across transfers and remains verifiable by any party the lock owner chooses to authorize.
Receipts are optional by design. A coin can be fully opaque, gossamer (partially visible), or clear (fully auditable). This flexibility lets the same protocol serve private transactions and fully auditable supply-chain settlement without changing the underlying architecture.
Peer nodes advance through a trust tier based on their transaction success rate. Miners with higher tiers access more of the network's data pool, creating an incentive structure that rewards reliability over raw compute power.
SupraBullion spawns 5 cooperating processes connected via POSIX named pipes under ./ipc/:
| Process | IPC Channel | Role |
|---|---|---|
bullion_event_loop |
CH_EVENT |
Main event processor; hosts REST API thread |
bullion_ssl_client |
CH_CLIENT |
Outbound encrypted peer connections (connects to peer port 4433) |
bullion_ssl_server |
CH_SERVER |
Inbound encrypted peer connections (port 4433) |
bullion_file_client |
CH_FCLIENT |
P2P file retrieval |
bullion_file_server |
CH_FSERVER |
P2P file serving (port 9001) |
Each block contains a linked list of assets, each containing a linked list of receipts:
bullion_blockchain
└─ bullion_block (blockheight, nonce, SHA256 hash, prev_hash,
│ locked, lock[256], lock_depth, lock_depth_count,
│ lock_depth_mode, lock_depth_expiry)
└─ bullion_asset* (LIQUID / NONLIQUID / CONTRACT; minted, reserve, value)
└─ bullion_receipt* (DEPOSIT / WITHDRAWAL / TRANSIT; amount, true_value, nosql data)
Mining consensus operates at three levels:
Setting "coin_nano_nosql":1 in a buy request attaches a typed schema to the minted coin. The schema is enforced on every subsequent transfer — a coin carrying a required field will reject any transaction that does not supply a conforming value. Schema fields persist in the receipt chain and are readable by lock owners according to the opacity level set at mint time.
| Level | Description |
|---|---|
OPAQUE |
No receipt data visible to non-lock-owners |
GOSSAMER |
Available receipts visible; some elided in transit |
CLEAR |
All receipts for unlocked coins fully visible |
POST /terminals (libmicrohttpd, port 8888)
└─ bullion_db_api.c (parse JSON, push to event queue)
└─ bullion_event_loop (dispatch via IPC pipe)
└─ bullion_ssl_client (main switch: blockchain ops per request_type)
└─ bullion_util_client_sig_workqueue (write result back to REST response)
gcc (C11) libssl libcrypto libcurl libmicrohttpd libcjson
libupnp libpthread zlib libexpat libm
make
./suprabullion # starts all 5 processes; data under ~/.suprabullion/
./suprabullion-gui --gui # same node + raygui REST client window
TLS certificates are generated automatically on first run — bullion_cert_ensure() writes a prime256v1 self-signed X.509v3 cert with SAN (DNS:localhost, IP:127.0.0.1) to ~/.suprabullion/certs/. No separate cert-gen step is needed.
curl -s -X POST -d 'json={
"request_type":"register","rest_sec":0,"coin_nano_nosql":0,
"ip":"127.0.0.1","ip_server":"127.0.0.1:4433","ip_fserver":"127.0.0.1:9001",
"email":"alice@example.com","fname":"Alice","lname":"Smith",
"username":"alice_smith","password":"password",
"hostname":"peer.example.com","description":"test node",
"node_ip":"127.0.0.1","node_port":"5000",
"dob_day":"06","dob_month":"06","dob_year":"1990",
"statement_descriptor":"suprasage","id_number":"000000000","ba_type":"checking"
}' http://localhost:8888/terminals
# Returns: {"request_id":1}
curl -s http://localhost:8888/terminals/1
# Poll until: {"request_id":1,"complete":1,"data":{"public_key":"<WALLET>",...}}
Every register, add_pm, buy, and sell request accepts an optional "payment_provider" field that selects which fiat gateway processes the money movement. When the field is absent the default is "stripe" so all existing API calls continue to work unchanged.
payment_provider |
Gateway | Notes |
|---|---|---|
"stripe" (default) |
Stripe | Full KYC registration; bank account, card, CashApp |
"paypal" |
PayPal REST API v2 | Email-based; Orders v2 + Payouts v1 |
"moonpay" |
MoonPay | Hosted widget URL or server-side transaction API |
"moneygram" |
MoneyGram Digital Send v3 | Recipient-based; cash pickup or bank deposit worldwide |
"flutterwave" |
Flutterwave v3 | Card, bank transfer, mobile money; NGN/USD/GHS |
sk_test_…).BULLION_STRIPE_API_KEY in headers/bullion_stripe.h.4242 4242 4242 4242 (any future date, any CVC).BULLION_STRIPE_TESTING 0 and swap in live keys for production.headers/bullion_paypal.h:
#define BULLION_PAYPAL_CLIENT_ID "YOUR_SANDBOX_CLIENT_ID"
#define BULLION_PAYPAL_SECRET "YOUR_SANDBOX_SECRET"
BULLION_PAYPAL_TESTING 0 and swap in live credentials for production.pk_test_…) and Test secret key (sk_test_…) into headers/bullion_moonpay.h:
#define BULLION_MOONPAY_PK "pk_test_YOUR_KEY"
#define BULLION_MOONPAY_SK "sk_test_YOUR_SECRET"
4000 0000 0000 0077 (Visa, any future date, any CVC).bullion_moonpay_create_transaction) requires MoonPay to grant server-side access; contact MoonPay support. Widget URLs work without approval.BULLION_MOONPAY_TESTING 0 and swap in live keys for production.headers/bullion_moneygram.h:
#define BULLION_MONEYGRAM_AGENT_PARTNER_ID "your_agent_partner_id"
#define BULLION_MONEYGRAM_API_KEY "your_api_key"
BULLION_MONEYGRAM_TESTING 1 to use the sandbox endpoint (https://sandboxapi.moneygram.com). Set to 0 for production.add_pm stores the recipient's name, country, receive method, and optional bank details locally. No MoneyGram API call is made until sell is issued.FLWSECK_TEST-…) and Test Public Key (FLWPUBK_TEST-…) into headers/bullion_flutterwave.h:
#define BULLION_FLW_SECRET_KEY "FLWSECK_TEST-your_key"
#define BULLION_FLW_PUBLIC_KEY "FLWPUBK_TEST-your_key"
BULLION_FLW_TESTING 1 to use sandbox mode. Set to 0 for production.5531 8866 5214 2950 / expiry 09/32 / CVV 564 / PIN 3310 (Visa alternative: 4187427415564246 / expiry 09/32 / CVV 828).BULLION_FLW_TESTING 0 and swap in live keys for production.Base URL: http://localhost:8888/terminals
All requests POST JSON with field request_type. The response is always {"request_id":N}. Poll GET /terminals/<N> until "complete":1.
request_type |
Description |
|---|---|
register |
Create a peer wallet and payment-provider identity |
add_pm |
Add a payment method (bank account, card, CashApp, PayPal email, MoonPay email) |
buy |
Mint new coins backed by a fiat payment |
sell |
Redeem coins to a fiat payout |
transfer |
Send coins between wallets |
contract |
Create a smart contract asset |
contract_cancel |
Cancel an open contract |
proposal |
Propose a block amendment |
payout |
Trigger an ROI payout |
handshake |
Initiate peer handshake |
process |
Process a pending event |
integrity |
Run chain integrity check |
peer_search |
Search for a peer on the network |
query |
Execute a nano-nosql query |
file |
Publish a file to the P2P network |
price |
Fetch live market prices for a currency pair, wallet SBLN balance, or USD value |
lock |
Apply (or re-configure) a supply chain lock on an existing block |
unlock |
Release a supply chain lock; only the lock owner may unlock |
Stripe (full KYC — requires address, DOB, SSN last 4, ID number)
WALLET="" # will be set from the response
curl -s -X POST -d 'json={
"request_type":"register","rest_sec":0,"coin_nano_nosql":0,
"payment_provider":"stripe",
"ip":"127.0.0.1","ip_server":"127.0.0.1:4433","ip_fserver":"127.0.0.1:9001",
"email":"alice@example.com","fname":"Alice","lname":"Smith",
"username":"alice_smith","password":"password",
"hostname":"peer.example.com","description":"test node",
"node_ip":"127.0.0.1","node_port":"5000",
"dob_day":"06","dob_month":"06","dob_year":"1990",
"statement_descriptor":"suprasage","id_number":"000000000","ba_type":"checking"
}' http://localhost:8888/terminals
PayPal (email + peer details only — no address/KYC required)
curl -s -X POST -d 'json={
"request_type":"register","rest_sec":0,"coin_nano_nosql":0,
"payment_provider":"paypal",
"ip":"127.0.0.1","ip_server":"127.0.0.1:4433","ip_fserver":"127.0.0.1:9001",
"email":"alice@example.com","fname":"Alice","lname":"Smith",
"username":"alice_paypal","password":"password",
"hostname":"peer.example.com","description":"paypal node",
"node_ip":"127.0.0.1","node_port":"5000"
}' http://localhost:8888/terminals
MoonPay (email + peer details only)
curl -s -X POST -d 'json={
"request_type":"register","rest_sec":0,"coin_nano_nosql":0,
"payment_provider":"moonpay",
"ip":"127.0.0.1","ip_server":"127.0.0.1:4433","ip_fserver":"127.0.0.1:9001",
"email":"alice@example.com","fname":"Alice","lname":"Smith",
"username":"alice_moonpay","password":"password",
"hostname":"peer.example.com","description":"moonpay node",
"node_ip":"127.0.0.1","node_port":"5000"
}' http://localhost:8888/terminals
MoneyGram (email + peer details; sender profile stored locally — no API call at registration)
curl -s -X POST -d 'json={
"request_type":"register","rest_sec":0,"coin_nano_nosql":0,
"payment_provider":"moneygram",
"ip":"127.0.0.1","ip_server":"127.0.0.1:4433","ip_fserver":"127.0.0.1:9001",
"email":"alice@example.com","fname":"Alice","lname":"Smith",
"username":"alice_moneygram","password":"password",
"hostname":"peer.example.com","description":"moneygram node",
"node_ip":"127.0.0.1","node_port":"5000"
}' http://localhost:8888/terminals
Flutterwave (email + peer details; creates a Flutterwave customer in the sandbox)
curl -s -X POST -d 'json={
"request_type":"register","rest_sec":0,"coin_nano_nosql":0,
"payment_provider":"flutterwave",
"ip":"127.0.0.1","ip_server":"127.0.0.1:4433","ip_fserver":"127.0.0.1:9001",
"email":"alice@example.com","fname":"Alice","lname":"Smith",
"username":"alice_flutterwave","password":"password","phone":"5550001234",
"hostname":"peer.example.com","description":"flutterwave node",
"node_ip":"127.0.0.1","node_port":"5000"
}' http://localhost:8888/terminals
Stripe — Bank account
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"stripe\",
\"key\":\"$WALLET\",
\"pm_type\":\"us_bank_account\",\"acct_type\":\"checking\",
\"bank_type\":\"us_bank_account\",\"bank_name\":\"STRIPE TEST BANK\",
\"bank_currency\":\"usd\",\"bank_country\":\"US\",
\"bank_routing_num\":\"110000000\",\"bank_account_num\":\"000123456789\"
}" http://localhost:8888/terminals
Stripe — Card
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"stripe\",
\"key\":\"$WALLET\",
\"pm_type\":\"card\",\"card_brand\":\"visa\",\"card_country\":\"US\",
\"card_number\":\"4242424242424242\",
\"card_exp_month\":\"12\",\"card_exp_year\":\"2030\",\"card_cvc\":\"123\"
}" http://localhost:8888/terminals
Stripe — CashApp
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"stripe\",
\"key\":\"$WALLET\",\"pm_type\":\"cashapp\",
\"bank_type\":\"cashapp\",\"bank_currency\":\"usd\"
}" http://localhost:8888/terminals
PayPal — link a PayPal email account
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"paypal\",
\"key\":\"$WALLET\",
\"paypal_email\":\"alice@example.com\",
\"currency\":\"usd\"
}" http://localhost:8888/terminals
MoonPay — link an email for the widget flow
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"moonpay\",
\"key\":\"$WALLET\",
\"email\":\"alice@example.com\",
\"currency\":\"usd\"
}" http://localhost:8888/terminals
MoneyGram — store a recipient for cash pickup or bank deposit
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"moneygram\",
\"key\":\"$WALLET\",
\"recipient_fname\":\"Bob\",\"recipient_lname\":\"Jones\",
\"receive_country\":\"USA\",\"receive_currency\":\"USD\",
\"receive_method\":\"CASH_PICKUP\",
\"phone\":\"5550009876\"
}" http://localhost:8888/terminals
For bank deposit, add "receive_method":"BANK_DEPOSIT" and supply "bank_account" and "bank_name" fields.
Flutterwave — add a card
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"flutterwave\",
\"key\":\"$WALLET\",
\"pm_type\":\"card\",
\"card_number\":\"5531886652142950\",
\"card_exp_month\":\"09\",\"card_exp_year\":\"2032\",
\"card_cvv\":\"564\",\"currency\":\"NGN\",\"country\":\"NG\"
}" http://localhost:8888/terminals
Flutterwave — add a bank account
curl -s -X POST -d "json={
\"request_type\":\"add_pm\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"flutterwave\",
\"key\":\"$WALLET\",
\"pm_type\":\"bank_account\",
\"bank_account_number\":\"0690000031\",\"bank_code\":\"044\",
\"bank_name\":\"Access Bank\",\"account_name\":\"Alice Smith\",
\"currency\":\"NGN\",\"country\":\"NG\"
}" http://localhost:8888/terminals
Stripe
curl -s -X POST -d "json={
\"request_type\":\"buy\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"stripe\",
\"payment_method\":\"cashapp\",\"transaction_type\":\"buy\",
\"transaction_to\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":100,\"payment_currency\":\"usd\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
PayPal (creates and auto-captures a PayPal Order in sandbox)
curl -s -X POST -d "json={
\"request_type\":\"buy\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"paypal\",
\"payment_method\":\"paypal\",\"transaction_type\":\"buy\",
\"transaction_to\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"USD\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
MoonPay (server-side; poll response for moonpay_redirect_url and open it in a browser)
curl -s -X POST -d "json={
\"request_type\":\"buy\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"moonpay\",
\"payment_method\":\"moonpay\",\"transaction_type\":\"buy\",
\"transaction_to\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"usd\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
# Poll /terminals/<id> — response includes {"moonpay_redirect_url":"https://..."}
# Open that URL in a browser to complete the MoonPay checkout flow.
Flutterwave (card charge in sandbox; poll response, then handle auth_mode if PIN/OTP required)
curl -s -X POST -d "json={
\"request_type\":\"buy\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"flutterwave\",
\"payment_method\":\"card\",\"transaction_type\":\"buy\",
\"transaction_to\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":1000,\"payment_currency\":\"NGN\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
Buy with Nano NoSQL schema (branded coin)
curl -s -X POST -d "json={
\"request_type\":\"buy\",\"rest_sec\":0,\"coin_nano_nosql\":1,
\"payment_method\":\"cashapp\",\"transaction_type\":\"buy\",
\"transaction_to\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"usd\",\"encryption\":\"rapid\",
\"nosql_schema_keys\":\"Brand,Model,Year\",
\"nosql_schema_vtypes\":\"string,string,int\",
\"nosql_schema_vreqs\":\"true,true,true\",
\"nosql_schema_vreq_opts\":\"none,none,none\",
\"nosql_schema_vreq_opacity\":\"CLEAR,CLEAR,CLEAR\",
\"nosql_schema_doc_url\":\"https://example.com/schema\"
}" http://localhost:8888/terminals
Stripe (payout to the connected bank account on file)
curl -s -X POST -d "json={
\"request_type\":\"sell\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"stripe\",
\"payment_method\":\"cashapp\",\"transaction_type\":\"sell\",
\"transaction_from\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"usd\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
PayPal (payout to the stored paypal_email — requires Payouts API access)
curl -s -X POST -d "json={
\"request_type\":\"sell\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"paypal\",
\"payment_method\":\"paypal\",\"transaction_type\":\"sell\",
\"transaction_from\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"USD\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
MoonPay (off-ramp; poll response for moonpay_sell_url and open it in a browser)
curl -s -X POST -d "json={
\"request_type\":\"sell\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"moonpay\",
\"payment_method\":\"moonpay\",\"transaction_type\":\"sell\",
\"transaction_from\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"usd\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
# Poll /terminals/<id> — response includes {"moonpay_sell_url":"https://..."}
MoneyGram (sends wallet balance to the stored recipient; fee quote is retrieved automatically)
curl -s -X POST -d "json={
\"request_type\":\"sell\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"moneygram\",
\"payment_method\":\"moneygram\",\"transaction_type\":\"sell\",
\"transaction_from\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":50,\"payment_currency\":\"USD\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
# Creates a PENDING send transaction, then commits it.
# Poll /terminals/<id> — response includes {"moneygram_transaction_id":"...",
# "moneygram_status":"COMMITTED","moneygram_fee":2.99}
Flutterwave (transfer fiat to the stored bank account)
curl -s -X POST -d "json={
\"request_type\":\"sell\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_provider\":\"flutterwave\",
\"payment_method\":\"bank_account\",\"transaction_type\":\"sell\",
\"transaction_from\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":5000,\"payment_currency\":\"NGN\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
# Poll /terminals/<id> — response includes {"flw_transfer_id":"...","flw_status":"NEW"}
WALLET_FROM="<sender public_key>"
WALLET_TO="<recipient public_key>"
curl -s -X POST -d "json={
\"request_type\":\"transfer\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_method\":\"cashapp\",\"transaction_type\":\"transfer\",
\"transaction_to\":\"$WALLET_TO\",\"transaction_from\":\"$WALLET_FROM\",
\"lock\":\"$WALLET_TO\",\"key\":\"$WALLET_FROM\",
\"amount\":25,\"payment_currency\":\"usd\",\"encryption\":\"rapid\"
}" http://localhost:8888/terminals
# SELECT all stripe clients for a wallet
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"query\":\"SELECT {*} FROM stripe_clients.clients WHERE {pkey_hash=$WALLET}\"
}" http://localhost:8888/terminals
# CREATE a collection
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"query\":\"CREATE COLLECTION Persons {Client=noschema}\"
}" http://localhost:8888/terminals
# INSERT a document
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"query\":\"CREATE Persons.Client {\\\"Name\\\":\\\"Alice Smith\\\",\\\"Company\\\":\\\"Acme\\\",\\\"ID\\\":1}\"
}" http://localhost:8888/terminals
# SELECT with WHERE filter
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"query\":\"SELECT {Name,Company} FROM Persons.Client WHERE {Company='Acme'}\"
}" http://localhost:8888/terminals
# UPDATE
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"query\":\"UPDATE Persons.Client SET {Name='Bob Jones'} WHERE ID = 1\"
}" http://localhost:8888/terminals
# DELETE
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"query\":\"DELETE {*} FROM Persons.Client WHERE {Name='Alice Smith'}\"
}" http://localhost:8888/terminals
lock and unlock let the holder of a wallet key apply a persistent hold on any block identified by its SHA256 hash (tx_hash). The lock owner receives a TRANSIT "pink slip" receipt each time the locked block is involved in a downstream transaction, enabling supply-chain visibility without requiring a transfer of ownership.
Required fields
| Field | lock |
unlock |
Description |
|---|---|---|---|
tx_hash |
yes | yes | SHA256 hash of the target block |
key |
yes | yes | Wallet public key of the caller (must match lock owner for unlock) |
lock_depth |
optional | — | Supply chain step limit (0 = unlimited) |
lock_depth_mode |
optional | — | 0=none, 1=count (step limit), 2=absolute (time only) |
lock_depth_expiry |
optional | — | Unix timestamp after which pink slips stop (0=never) |
lock_depth behaviour
lock_depth_mode |
Effect |
|---|---|
0 |
No supply chain tracking — lock is purely a hold marker |
1 |
Pink slips fire until lock_depth_count reaches lock_depth; further receipts suppressed |
2 |
Pink slips fire on every downstream transaction until lock_depth_expiry passes |
When lock_depth_expiry is set and the current time exceeds it, pink slips are suppressed regardless of mode. Setting lock_depth=0 with lock_depth_mode=1 is equivalent to mode 0.
Apply a lock (no supply chain depth)
TX_HASH="<shash from buy/transfer response>"
curl -s -X POST -d "json={
\"request_type\":\"lock\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"tx_hash\":\"$TX_HASH\",
\"key\":\"$WALLET\"
}" http://localhost:8888/terminals
# Returns: {"request_id":N}
# Poll: curl -s http://localhost:8888/terminals/N
# Success: {"request_id":N,"complete":1,"data":{...}}
Apply a lock with supply chain step tracking (count mode)
# Fire pink slip receipts for the next 3 downstream transfers, then stop.
curl -s -X POST -d "json={
\"request_type\":\"lock\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"tx_hash\":\"$TX_HASH\",
\"key\":\"$WALLET\",
\"lock_depth\":3,
\"lock_depth_mode\":1
}" http://localhost:8888/terminals
Apply a lock with a time-based expiry (absolute mode)
# Fire pink slip receipts on every transfer until Unix timestamp 1800000000.
curl -s -X POST -d "json={
\"request_type\":\"lock\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"tx_hash\":\"$TX_HASH\",
\"key\":\"$WALLET\",
\"lock_depth_mode\":2,
\"lock_depth_expiry\":1800000000
}" http://localhost:8888/terminals
Release a lock
# Only the key that originally applied the lock may unlock it.
curl -s -X POST -d "json={
\"request_type\":\"unlock\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"tx_hash\":\"$TX_HASH\",
\"key\":\"$WALLET\"
}" http://localhost:8888/terminals
Lock depth on mint / transfer
buy and transfer requests also accept the three lock_depth* fields. When present, the new block is locked to the caller's wallet immediately on creation and supply chain tracking begins from that first block rather than requiring a separate lock call.
# Mint a coin and immediately apply a 5-step supply chain lock.
curl -s -X POST -d "json={
\"request_type\":\"buy\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"payment_method\":\"cashapp\",\"transaction_type\":\"buy\",
\"transaction_to\":\"$WALLET\",\"lock\":\"$WALLET\",\"key\":\"$WALLET\",
\"amount\":100,\"payment_currency\":\"usd\",\"encryption\":\"rapid\",
\"lock_depth\":5,
\"lock_depth_mode\":1
}" http://localhost:8888/terminals
Filter wallet queries to unlocked coins only
Pass "unlocked_only":1 with any query request to exclude locked blocks from results:
curl -s -X POST -d "json={
\"request_type\":\"query\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"key\":\"$WALLET\",
\"unlocked_only\":1,
\"query\":\"SELECT {*} FROM blockchain.blocks WHERE {chain_key=$WALLET}\"
}" http://localhost:8888/terminals
The price request type fetches live market data from the fawazahmed0 Currency API CDN and/or reads the on-disk SBLN wallet balance for any registered public key. Results are cached for 60 seconds per pair so repeated polls do not hammer the CDN.
Fields
| Field | Required | Description |
|---|---|---|
pair |
for price/all | Currency pair in BASE_QUOTE format, e.g. BTC_USD, ETH_USD, XRP_EUR |
key |
for balance/all | Wallet public key returned from register |
query_type |
no | "price" (default), "balance", or "all" |
Poll GET /terminals/<id> until "complete":1 as with all other request types.
curl -s -X POST -d 'json={
"request_type":"price","rest_sec":0,"coin_nano_nosql":0,
"pair":"BTC_USD","query_type":"price"
}' http://localhost:8888/terminals
# Returns: {"request_id":N}
curl -s http://localhost:8888/terminals/N
# {"request_id":N,"complete":1,"data":{
# "pair":"BTC_USD",
# "buy_price":97512.34,
# "sell_price":97561.23,
# "mid_price":97536.79,
# "timestamp":1745612345
# }}
buy_price is 0.05% below mid; sell_price is 0.05% above mid — matching the WhiteBit-style spread used in the reference ext/price_fetcher/ examples.
Any pair supported by the CDN works: ETH_USD, SOL_EUR, XRP_GBP, USDT_BTC, etc. Use BASE_QUOTE with an underscore separator and standard ISO 4217 / ticker symbols in any case (btc_usd and BTC_USD are equivalent).
The SBLN token value in USD is derived from reserve / quantity of the latest block's quanta (the same formula used during minting). This reflects the actual backing ratio of the chain at query time.
curl -s -X POST -d "json={
\"request_type\":\"price\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"pair\":\"\",\"key\":\"$WALLET\",\"query_type\":\"balance\"
}" http://localhost:8888/terminals
curl -s http://localhost:8888/terminals/N
# {"request_id":N,"complete":1,"data":{
# "public_key":"<WALLET>",
# "balance_sbln":1000.0,
# "token_value_usd":0.001,
# "balance_usd":1.0,
# "timestamp":1745612345
# }}
curl -s -X POST -d "json={
\"request_type\":\"price\",\"rest_sec\":0,\"coin_nano_nosql\":0,
\"pair\":\"BTC_USD\",\"key\":\"$WALLET\",\"query_type\":\"all\"
}" http://localhost:8888/terminals
curl -s http://localhost:8888/terminals/N
# {"request_id":N,"complete":1,"data":{
# "pair":"BTC_USD",
# "buy_price":97512.34,
# "sell_price":97561.23,
# "mid_price":97536.79,
# "public_key":"<WALLET>",
# "balance_sbln":1000.0,
# "token_value_usd":0.001,
# "balance_usd":1.0,
# "timestamp":1745612345
# }}
SupraBullion implements the Coinbase Rosetta blockchain standard. All endpoints are under the /rosetta/ prefix and accept/return JSON.
Network identifier
{ "blockchain": "suprabullion", "network": "mainnet" }
Amount format: string integer in quanta (1 SBL = 100,000,000 quanta), symbol SBL, decimals 8.
| Endpoint | Description |
|---|---|
POST /rosetta/network/list |
List supported networks |
POST /rosetta/network/status |
Current node status, current block, genesis block, peers |
POST /rosetta/network/options |
Supported operations and errors |
POST /rosetta/block |
Fetch block by index or hash |
POST /rosetta/block/transaction |
Fetch a single transaction within a block |
POST /rosetta/account/balance |
Get account balance at a block |
POST /rosetta/account/coins |
List unspent coins for an account |
POST /rosetta/mempool |
List pending transaction IDs |
POST /rosetta/mempool/transaction |
Fetch a pending transaction |
| Endpoint | Description |
|---|---|
POST /rosetta/construction/derive |
Derive account identifier from public key |
POST /rosetta/construction/preprocess |
Pre-process operations before metadata fetch |
POST /rosetta/construction/metadata |
Fetch chain metadata needed to construct a transaction |
POST /rosetta/construction/payloads |
Build unsigned transaction and signing payloads |
POST /rosetta/construction/parse |
Parse a transaction (unsigned or signed) into operations |
POST /rosetta/construction/combine |
Combine unsigned transaction with signature(s) |
POST /rosetta/construction/hash |
Get the hash of a signed transaction |
POST /rosetta/construction/submit |
Broadcast a signed transaction; returns {"request_id":N} for polling via GET /terminals/N |
Peer discovery runs in a cascade so the network grows and heals without a single point of failure.
1. suprabullion.com/api/peers ← central registry (Laravel, mainnet bootstrap)
2. GET <known-peer>:8888/api/peers ← node-to-node fallback if central API is unreachable
3. SSL HANDSHAKE on port 4433 ← gossip: every blockchain connection exchanges peer lists
4. POST <peer>:8888/api/peers ← direct self-announce to any reachable node
5. UPnP at startup ← auto-forward 4433/8888/9001 on home routers
Every running node is a queryable peer registry. Any node that can reach another's port 8888 can bootstrap from it — the network becomes progressively more decentralised as more nodes join.
| Method | URL | Description |
|---|---|---|
GET |
/api/peers |
Return this node's known peer list (same JSON as central API) |
POST |
/api/peers |
Register a remote peer directly with this node |
Response format matches suprabullion.com/api/peers:
{"error":null,"data":[{"ip_server":"...","ip_fserver":"...","username":"...","level":0,"id":1}]}
On startup, bullion_upnp_map_ports() searches the LAN for a UPnP IGD router and maps ports 4433 (SSL), 8888 (REST), and 9001 (file server) TCP. Nodes behind home routers join the public network automatically without manual port-forward configuration. Fails silently if no UPnP-capable router is present.
suprabullion.com/api/ is a Laravel Sanctum API that serves as the mainnet bootstrap registry. Scaffolding for all 8 routes the C client requires is in laravel_peer_api/:
| File | Destination |
|---|---|
laravel_peer_api/routes_api.php |
routes/api.php |
laravel_peer_api/AuthController.php |
app/Http/Controllers/ |
laravel_peer_api/PeerController.php |
app/Http/Controllers/ |
laravel_peer_api/Peer.php |
app/Models/ |
laravel_peer_api/create_peers_table.php |
database/migrations/ |
After copying: php artisan migrate && php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Peers advance through tiers based on successful transaction percentiles:
| Tier | Requirement | Description |
|---|---|---|
BULL |
Entry level | New peer, few confirmed blocks |
BRONZE |
> 15% percentile | Established mining presence |
SILVER |
> 25% percentile | Reliable transaction handler |
GOLD |
> 45% percentile | High-trust peer, deeper data access |
DIAMOND |
> 60% percentile | Senior network participant |
MANNA |
> 75% percentile | Highest-trust, maximum data pool access |
Tier is recalculated after each block is finalized. Higher tiers receive preferential routing when peers select handlers for incoming transactions.
Runtime data is stored in ~/.suprabullion/ (created on first run):
~/.suprabullion/
database/ # Runtime data (blockchain/, Persons/, users/, stripe_clients/)
certs/ # TLS key.pem + cert.pem
ipc/ # Named pipes for inter-process communication
logs/ # Printf-based log output (error.log)
proc/ # PID files (ch_event, ch_client, ch_server)
tx_files/ # Uploaded asset files
wallets/ # User wallet directories
Source and static assets remain alongside the binary in the project directory:
source/ # C11 source files
headers/ # Header files
ext/ # Vendored libraries (cvector, parson, cJSON, microhttpd, uthash, lz4, upnp,
# raylib 5.5 + raygui 5.0)
assets/ # Static project assets
suprabullion_logo_shadow.png # Full logo with icon + wordmark + shadow (used in README)
suprabullion_icon.png # Full logo (icon + "suprabullion" wordmark)
android-chrome-192x192.png # Standalone icon 192 px (GUI titlebar + window icon)
laravel_peer_api/ # Laravel scaffolding for suprabullion.com peer registry API
Built-in price fetcher — price request type
A new request_type: "price" is now fully wired into the REST API. It fetches live market data from the fawazahmed0 Currency API CDN (the same source used in ext/price_fetcher/) and applies a ±0.05% buy/sell spread. Results are cached per-pair for 60 seconds using a process-local pthread_mutex-guarded cache. Three query_type modes are supported: "price" (market buy/sell/mid for any BASE_QUOTE pair), "balance" (on-disk SBLN wallet balance + USD value at current chain quanta rate), and "all" (both in one response). Implemented in source/bullion_price.c and headers/bullion_price.h; wired through bullion_req_handler.c (parse), bullion_db_api.c (IPC KV packaging), and the ssl_client outqueue dispatch in main.c.
Multi-algorithm database compression + BLNH hardened cipher
All database writes and reads now route through a central dispatch (bullion_compress / bullion_decompress in source/bullion_utilities.c) instead of calling bullion_zlib_compress_string directly. Five algorithms are fully wired: LZ4 (.blnlz), zlib (.blnz), RLE (.blnr), X-compressor (.blnx), LZ77 8-bit (.bln77). A new sixth algorithm, BLNH (.blnh), pipelines a 4096-byte sliding-window LZ77 with an XOR keystream derived from a 32-byte per-node key. DB files compressed with BLNH are opaque without the key. The active algorithm is selected by compression_type=N in user.conf; BLNH reads/writes compression_key=<64-hex> in the same file, generating a key from /dev/urandom on first use. Fixed two pre-existing bugs: inverted extension-to-algorithm mapping (.blnz was selecting LZ4, .blnlz was selecting zlib) and the commented-out LZ4 switch case. All wrapper functions prepend a 4-byte little-endian original-size header for self-contained decompression. Existing .blnz database files remain readable without migration.
Decentralised peer networking — gossip, node REST endpoint, UPnP
The peer discovery architecture was extended so the network can grow and recover without the central suprabullion.com API:
GET /api/peers and POST /api/peers on every node's port 8888 — each node now serves its known peer list in the same JSON format as the central API. Any node reachable on port 8888 can act as a bootstrap seed for new nodes.source/bullion_ssl_server.c) — every inbound connection on port 4433 now exchanges peer lists: the server extracts the connecting peer's ip_server from hdr->peer, adds it to hub->peers, then writes its full peer vector back over SSL.bullion_peer_query_node (source/bullion_peer.c) — when bullion_peer_api_get_all fails (central API unreachable), the ssl_client loop iterates known local peers and queries their :8888/api/peers endpoint until the target is found.bullion_upnp_map_ports (source/bullion_upnp_ctrlpt.c) — called once at startup, discovers the LAN IGD router via SSDP and maps ports 4433, 8888, 9001 TCP using libupnp SOAP AddPortMapping. Lets nodes behind home routers join the public network automatically.laravel_peer_api/) — five files implementing the 8 routes the C client calls against suprabullion.com/api/. See Peer Networking section.Supply chain lock depth (lock / unlock request types)
Two new request types — BULLION_LOCK (enum 16) and BULLION_UNLOCK (enum 17) — allow the holder of a wallet key to place a persistent hold on any block by its SHA256 hash, and to release it later. A lock is stored directly on the bullion_block struct; four new fields track the supply-chain state:
| Field | Type | Description |
|---|---|---|
lock_depth |
int |
Step limit for count mode (0 = unlimited) |
lock_depth_count |
int |
Steps fulfilled so far (incremented by notify_lock_originator) |
lock_depth_mode |
int |
0 = none, 1 = count, 2 = absolute (time-based) |
lock_depth_expiry |
long long |
Unix timestamp after which pink slips stop (0 = never) |
These fields are serialised into bullion_block_package / bullion_block_unpackage so lock state survives network transfer and DB round-trips. bullion_block_set_lock_depth is the canonical setter; it also resets lock_depth_count to 0.
notify_lock_originator (called after each successful downstream receipt) consults lock_depth_active before sending a TRANSIT pink slip to the lock owner. In count mode it increments lock_depth_count after each slip and suppresses further slips once the limit is reached. In absolute mode slips fire on every transaction until lock_depth_expiry passes.
BULLION_LOCK locates the target block in memory or falls back to the DB, applies the lock and depth settings, then persists the block via bullion_json_db_init_query. BULLION_UNLOCK verifies the caller's key matches block->lock before clearing all lock and depth fields.
buy and transfer also accept the three lock_depth* JSON fields; when present, init_block_from_chain applies the depth settings immediately after creating the new block so supply chain tracking begins from the first transaction without a separate lock call.
The query request now accepts "unlocked_only":1 to filter wallet results to blocks that are not currently locked.
MoneyGram and Flutterwave payment providers
source/bullion_moneygram.c and source/bullion_flutterwave.c add two additional payment backends. MoneyGram (Digital Send v3) implements the SELL path only: register stores the sender profile locally (no API call), add_pm stores recipient details (name, country, receive method, optional bank account), and sell fetches a live fee quote then creates and commits a send transaction. Cash pickup and bank deposit receive methods are both supported. Flutterwave (v3) mirrors the Stripe path: register creates a Flutterwave customer, add_pm stores a card (tokenised) or bank account, buy initiates a card charge or bank-transfer payment, and sell dispatches a payout transfer to the stored bank account. Supported currencies include NGN, USD, and GHS. Sandbox credentials are defined in the respective headers.
PayPal and MoonPay payment providers
source/bullion_paypal.c and source/bullion_moonpay.c add two new payment backends. All register, add_pm, buy, and sell requests now accept "payment_provider": "paypal" uses PayPal REST API v2 (OAuth2 client_credentials, Orders v2, Payouts v1); "moonpay" uses the MoonPay API (HMAC-SHA256-signed widget URLs, server-side transaction API). The default "stripe" path is unchanged. PayPal/MoonPay register requires only email and peer fields — the Stripe-only KYC fields (DOB, address, SSN, ID) are skipped. BULLION_SELL now correctly issues a fiat payout for all three providers; previously no payout was made for any provider.
Merkle proof seal — real receipt leaves + root anchored in block hash
Block hashes now cryptographically commit to the full transaction set. build_and_store_merkle (Upgrade A) collects actual receipt shash hex strings as merkle leaves instead of trivially duplicating block->shash; up to 8 receipts across the asset chain are hashed at their true 64-byte length with unused slots padded by the block hash. After the tree is built, the root is hex-encoded into block->transactions[0] and bullion_block_calculate_hash (Upgrade B) includes transactions[0] in its SHA256 input, so the final block->shash seals nonce + sdata + merkle_root in one binding hash. During PoW mining, transactions[0] is still empty, so the nonce search is unaffected.
~/.suprabullion/ data directory
bullion_home_init() is called at startup before any path operations. It creates ~/.suprabullion/ if absent and chdirs into it. All BULLION_PATH_* macros (./certs, ./database, ./ipc, ./logs, ./proc, ./tx_files, ./logs/error.log) then resolve under ~/.suprabullion/. All 5 child processes inherit the CWD via fork.
GUI asset display
suprabullion-gui now loads the project assets at startup via an exe-relative path (resolves through /proc/self/exe so assets are found after chdir to ~/.suprabullion/). assets/suprabullion_icon.png (full logo with wordmark) is displayed in the sidebar header. assets/android-chrome-192x192.png (standalone icon) is shown in the titlebar alongside the window title and set as the OS window icon via SetWindowIcon.
Rosetta / Mesh API
All 15 Coinbase Rosetta endpoints implemented under /rosetta/ in a new source/bullion_rosetta.c module. bullion_term_svr.c routes raw JSON bodies to the dispatcher; construction/submit integrates with the existing terminal queue. Response bodies carry Content-Type: application/json.
BULLION_QUERY — nano-nosql REST query
The query request type is now fully wired end-to-end: bullion_db_api.c populates the query and key kv fields, the ssl_client BULLION_QUERY case calls bullion_json_db_init_query and writes the result back via the workqueue, and bullion_req_handler.c serializes it into the standard {request_id, complete, data} JSON envelope. Supports SELECT, CREATE, INSERT, UPDATE, DELETE with WHERE filters.
DB checksum corruption fix
bullion_zlib_decompress_string allocated decompressed_size bytes but never null-terminated the output. bullion_cjson_db_checksum uses strlen(), so it hashed garbage bytes past the buffer, always producing the wrong hash. The result was [bullion_cjson_db_checksum] Corruption detected errors and ERROR client not found on every add_pm and buy after a fresh register. Fixed by allocating decompressed_size + 1 and setting output[decompressed_size] = '\0'.
Quanta minting fixes
Fixed -1 amount and (null) currency log output from bullion_quanta_token_mint. Quanta tokens now mint with correct amount and currency fields.
Thread safety — strtok → strtok_r
All IPC and JSON-parse paths that used strtok (not re-entrant) were replaced with strtok_r to eliminate data races in multi-threaded parse contexts.
Brand partition constraint validation
bullion_wallet_brand_partition now iterates the entire wallet->brands vector and applies each brand's JSON schema constraints to the transaction, not just the first brand entry.
Memory hardening
Critical and warning-level memory errors fixed across bullion_ssl_server.c, bullion_block.c, bullion_asset.c, bullion_receipt.c, and bullion_stripe.c. Replaced curl_* string calls with the C API throughout Stripe integration.
In-code TLS certificate generation — shell scripts removed
suprabullion-certgen, suprabullion-certtrust, and suprabullion-search have been removed from the project. Cert generation is now handled by bullion_cert_ensure() (source/bullion_cert.c) using the OpenSSL EVP/X509 APIs: prime256v1 EC private key, self-signed X.509v3 cert with DNS:localhost and IP:127.0.0.1 SANs, signed with SHA-256, 365-day validity. Called automatically at startup if certs/key.pem is absent. Private key written with chmod 0600. Runtime directories (certs/, database/, ipc/, logs/, proc/, tx_files/) have been removed from the project root; all data lives under ~/.suprabullion/.
SSL security hardening
configure_server_context() and configure_client_context() now use BULLION_CRT_FILE / BULLION_KEY_FILE (the locally generated self-signed cert) instead of the old Let's Encrypt paths. TLS 1.2 minimum enforced via SSL_CTX_set_min_proto_version. Deprecated SSL functions (ssl_client_main, ssl_server_main, bullion_ssl_server_load_certs, bullion_ssl_server_open_listen, bullion_ssl_server_show_certs, and their client-side equivalents) removed. All callers updated to use _ssl_client_main / _ssl_server_main. Commented-out OpenSSL 1.0 init boilerplate (SSL_library_init, OpenSSL_add_all_algorithms) removed — OpenSSL 1.1+ initialises automatically. Old RSA-key-fetch commented blocks in the BULLION_PROCESS case replaced with an explanatory note.
Initial release of the SupraBullion C11 blockchain node. Five-process IPC architecture, B.A.R three-layer mining, nano-nosql coin embedding, OPAQUE/GOSSAMER/CLEAR opacity levels, RSA + AES-GCM + AES-CCM cryptographic primitives, Stripe payment integration, LZ4-compressed block payloads, peer tier system, P2P file server/client, and REST API on port 8888.
make # build suprabullion binary
make clean # remove object files and binary
bash test_api.sh # run full API validation suite (requires running node)
Compiler: gcc -std=c11 -D_POSIX_C_SOURCE=200809L