l o a d i n g

Documentation

SupraBullion

SupraBullion

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.


Mission

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.


Architecture

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)

B.A.R Three-Layer Mining

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:

  • Block — Merkle tree hash verified against peer consensus
  • Asset — value and reserve verified against chain state
  • Receipt — broadcast to all lock owners for their chunk of the transaction value

Nano NoSQL Coin Embedding

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.

Transparency Levels

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

Request Flow

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)

Quick Start

Prerequisites

gcc (C11)  libssl  libcrypto  libcurl  libmicrohttpd  libcjson
libupnp    libpthread  zlib  libexpat  libm

Build

make

Run

./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.

Smoke Test

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>",...}}

Payment Providers

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

Setting up Stripe (sandbox)

  1. Sign up at https://dashboard.stripe.com.
  2. In Developers → API keys copy the Test secret key (sk_test_…).
  3. Paste it as BULLION_STRIPE_API_KEY in headers/bullion_stripe.h.
  4. Use Stripe test card 4242 4242 4242 4242 (any future date, any CVC).
  5. Set BULLION_STRIPE_TESTING 0 and swap in live keys for production.

Setting up PayPal (sandbox)

  1. Sign up at https://developer.paypal.com.
  2. Go to My Apps & Credentials → Sandbox → Create App.
  3. Copy the Client ID and Secret into headers/bullion_paypal.h:
    #define BULLION_PAYPAL_CLIENT_ID "YOUR_SANDBOX_CLIENT_ID"
    #define BULLION_PAYPAL_SECRET    "YOUR_SANDBOX_SECRET"
  4. To test Payouts (SELL), enable Payouts under Products & Services in your PayPal business dashboard — sandbox access is granted automatically.
  5. Set BULLION_PAYPAL_TESTING 0 and swap in live credentials for production.

Setting up MoonPay (sandbox)

  1. Sign up at https://dashboard.moonpay.com.
  2. Go to Developers → API keys and copy the Test publishable key (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"
  3. Enable Sandbox mode in the MoonPay dashboard for test transactions.
  4. Test card: 4000 0000 0000 0077 (Visa, any future date, any CVC).
  5. Server-side transaction API (bullion_moonpay_create_transaction) requires MoonPay to grant server-side access; contact MoonPay support. Widget URLs work without approval.
  6. Set BULLION_MOONPAY_TESTING 0 and swap in live keys for production.

Setting up MoneyGram (sandbox)

  1. Apply for API access at https://developer.moneygram.com and create a sandbox application.
  2. Copy the Partner ID and API key into headers/bullion_moneygram.h:
    #define BULLION_MONEYGRAM_AGENT_PARTNER_ID  "your_agent_partner_id"
    #define BULLION_MONEYGRAM_API_KEY           "your_api_key"
  3. Leave BULLION_MONEYGRAM_TESTING 1 to use the sandbox endpoint (https://sandboxapi.moneygram.com). Set to 0 for production.
  4. MoneyGram supports SELL only (wallet balance → money transfer). BUY is not available — use Stripe, PayPal, or Flutterwave for fiat-to-coin purchases.
  5. 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.

Setting up Flutterwave (sandbox)

  1. Sign up at https://dashboard.flutterwave.com.
  2. Go to Settings → API Keys and copy the Test Secret Key (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"
  3. Leave BULLION_FLW_TESTING 1 to use sandbox mode. Set to 0 for production.
  4. Sandbox test card: 5531 8866 5214 2950 / expiry 09/32 / CVV 564 / PIN 3310 (Visa alternative: 4187427415564246 / expiry 09/32 / CVV 828).
  5. Set BULLION_FLW_TESTING 0 and swap in live keys for production.

REST API Reference

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 Types

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

Register a peer

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

Add a payment method

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

Buy (mint coins)

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

Sell (redeem coins → fiat payout)

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"}

Transfer coins

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

Query the nano-nosql database

# 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 a block (supply chain tracking)

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

Query prices and wallet balances

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.

Market price for a pair

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).

Wallet SBLN balance and USD value

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
# }}

Price and balance together

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
# }}

Rosetta / Mesh API

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.

Data API

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

Construction API

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 Networking

Peer discovery runs in a cascade so the network grows and heals without a single point of failure.

Discovery Cascade

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.

Peer Endpoints (port 8888)

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}]}

UPnP Port Mapping

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.

Central Registry (Laravel)

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"


Peer Tier System

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.


Directory Layout

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

Changelog

v1.1 (current)

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.
  • SSL HANDSHAKE gossip (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 registry scaffolding (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 — strtokstrtok_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.

v1.0

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.


Build Reference

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