Skip to main content

Atomic USDx wallet โ€” Redis-backed balance engine, NowPayments deposits, ITC PSBT withdrawals, OTC rate engine

Project description

interchained-usdx

๐Ÿช™ interchained-usdx

Atomic, Redis-backed USDx wallet engine for the Interchained ecosystem.
Four independent modules. Zero application-level locks. Battle-tested in production.

PyPI Python 3.11+ Redis 6+ Tests: 24 passed Lua atomic License: GPLv3 async-first


โšก The Lore

In the Interchained ecosystem, USDx is the stable settlement layer โ€” minted from real crypto deposits, redeemable for native ITC tokens at a provably-fair OTC rate. It powers creator earnings, node operator rewards, game prize pools, and marketplace settlements.

Every balance mutation โ€” credit, debit, transfer, freeze โ€” executes as a single Redis Lua script. Atomically. No application-level locks. No race conditions. No double-spends. Just raw, nanosecond-precision financial logic running in the kernel of a battle-hardened in-memory database.

This is the engine behind $50k+ in transaction volume and 275+ live users on the Interchained network. Now open-sourced under GPLv3 for any project that demands the same standard.


๐Ÿ“ฆ Install

pip install interchained-usdx

๐Ÿ—บ๏ธ What's inside

Module Class What it does
usdx.wallet USDxWallet Atomic Redis balance engine โ€” credit / debit / transfer / freeze
usdx.payments NowPaymentsService Multi-chain crypto deposit handler via NowPayments (22 coins)
usdx.psbt PSBTBuilder + ITCRPCClient ITC blockchain PSBT payout builder, wallet-funded with auto fee estimation
usdx.otc OTCRateEngine Dynamic ITC โ†” USDx exchange rate driven by on-chain reserve / circulating supply

All four modules are independently usable โ€” pull only what you need.


๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        Your Application                      โ”‚
โ”‚                                                             โ”‚
โ”‚   from usdx import USDxWallet, NowPaymentsService,          โ”‚
โ”‚                    PSBTBuilder, OTCRateEngine               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”‚              โ”‚               โ”‚
             โ–ผ              โ–ผ               โ–ผ
     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
     โ”‚  USDxWallet  โ”‚ โ”‚NowPaymts โ”‚ โ”‚  PSBTBuilder     โ”‚
     โ”‚  (Lua core)  โ”‚ โ”‚  (HTTP)  โ”‚ โ”‚  (ITC RPC)       โ”‚
     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
            โ”‚              โ”‚              โ”‚
     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
     โ”‚          Redis 6+           โ”‚      โ”‚
     โ”‚  (atomic Lua scripts run    โ”‚      โ”‚
     โ”‚   inside the server,        โ”‚      โ”‚
     โ”‚   no app-level locks)       โ”‚      โ–ผ
     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  ITC Node RPC
                                      (PSBT payouts)

๐Ÿš€ Quick start

1 โ€” Balance engine

import asyncio
import redis.asyncio as aioredis
from usdx import USDxWallet, InsufficientBalance, AccountFrozen

async def main():
    r = aioredis.from_url("redis://localhost:6379/0")
    wallet = USDxWallet(r)

    # โ”€โ”€ Credit โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    tx = await wallet.credit("alice", 20.74, description="Welcome bonus", tx_type="bonus")
    print(tx.balance_after)   # 20.74

    # Premium creators get a 1.5ร— earnings multiplier
    tx = await wallet.credit("alice", 10.00, multiplier=1.5, description="Article view")
    print(tx.amount)          # 15.0  โ† applied inside the Lua script

    # โ”€โ”€ Debit โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    try:
        tx = await wallet.debit("alice", 3.99, description="Monthly subscription")
    except InsufficientBalance:
        print("Not enough funds")
    except AccountFrozen:
        print("Account is locked (fraud protection)")

    # โ”€โ”€ Atomic transfer (single Lua round-trip) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    debit_tx, credit_tx = await wallet.transfer("alice", "bob", 5.00, description="Tip")

    # โ”€โ”€ Account snapshot โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    info = await wallet.get_info("alice")
    print(info.balance, info.total_credited, info.is_frozen)

    # โ”€โ”€ Full transaction history โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    history = await wallet.get_history("alice", limit=10)
    for tx in history:
        print(f"{tx.direction:6s}  {tx.amount:8.2f}  {tx.description}")

    # โ”€โ”€ Fraud protection โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    await wallet.freeze("alice")    # blocks all outgoing transfers
    await wallet.unfreeze("alice")  # restores full access

asyncio.run(main())

2 โ€” Custom Redis namespace

# Isolate keys per application / environment
wallet = USDxWallet(r, key_prefix="myapp:balance:", tx_prefix="myapp:tx:")

3 โ€” NowPayments deposits

Accept 22 cryptocurrencies โ€” BTC, ETH, USDT, TRX, BNB, XRP, DOGE, LTC, AVAX, and more.

from usdx import NowPaymentsService, USDxWallet

wallet = USDxWallet(redis_client)

async def on_confirmed(username: str, amount: float, currency: str, payment_id: str) -> bool:
    """Called automatically when a crypto payment reaches 'finished' status."""
    await wallet.credit(
        username, amount,
        description=f"Deposit via {currency.upper()}",
        tx_type="deposit",
        metadata={"payment_id": payment_id, "currency": currency},
    )
    return True  # return False to mark as failed without consuming idempotency token

svc = NowPaymentsService(
    redis_client,
    api_key="YOUR_NOWPAYMENTS_API_KEY",
    on_confirmed=on_confirmed,
    success_url="https://yourapp.com/wallet?status=success",
    cancel_url="https://yourapp.com/wallet?status=cancelled",
    namespace="myapp",       # Redis key namespace โ€” keeps keys isolated
    order_prefix="myapp",    # Prefix in NowPayments order_id field
)

# Create a deposit invoice โ€” redirect the user to payment_url
invoice = await svc.create_deposit_invoice("alice", 25.00, "usdttrc20")
print(invoice["payment_url"])     # โ†’ https://nowpayments.io/payment/...

# Check a payment's current status
status = await svc.check_payment_status(payment_id)
print(status["status"])           # "waiting" | "confirming" | "finished" | "failed"

# Handle an IPN webhook (wire this into your web framework)
await svc.handle_ipn_callback(ipn_payload)

# Manually trigger processing (idempotent โ€” safe to call multiple times)
result = await svc.process_completed_payment(payment_id)

4 โ€” PSBT withdrawals (ITC blockchain)

Build, sign, and broadcast multi-output ITC payouts โ€” wallet-funded, with automatic fee estimation.

from usdx import ITCRPCClient, PSBTBuilder, PSBTError

rpc = ITCRPCClient(
    rpc_url="http://127.0.0.1:8332",
    wallet_name="hot-wallet",
    username="rpcuser",
    password="rpcpass",
    fallback_fee=10.0,      # sat/byte fallback if estimatesmartfee fails
)
builder = PSBTBuilder(rpc, conf_target=6)   # target 6-block confirmation

# Build a batch payout โ€” as many recipients as you need
payouts = [
    {"address": "itc1qrecipient1...", "amount": 12.50},
    {"address": "itc1qrecipient2...", "amount":  7.25},
    {"address": "itc1qrecipient3...", "amount": 42.00},
]

tx_hex, info = await builder.create_payout(payouts)
print(f"Total payout : {info['total_payout']:.4f} ITC")
print(f"Network fee  : {info['fee']:.4f} ITC")
print(f"Est. size    : {info['estimated_size']} bytes")

txid = await builder.broadcast(tx_hex)
print(f"Broadcast txid: {txid}")

5 โ€” OTC rate engine

Drive a dynamic ITC โ†” USDx exchange rate from on-chain reserve and circulating supply.

from usdx import OTCRateEngine

engine = OTCRateEngine(
    redis_client,
    default_itc_reserve=10_000.0,   # initial ITC in the treasury reserve
    default_usdx_supply=1_000.0,    # initial USDx in circulation
)
await engine.initialize()           # seeds defaults on first run, no-op after

# Read the current rate
rate = await engine.get_rate()      # ITC per 1 USDx (e.g. 10.5)

# Update the reserve after a user deposits crypto
await engine.increment_supply(25.0, source="alice_deposit")
await engine.decrement_itc_reserve(12.5, source="alice_withdrawal")

# Full treasury snapshot
stats = await engine.get_stats()
# {
#   "itc_reserve":   9987.5,
#   "usdx_supply":   1025.0,
#   "current_rate":  9.74,
#   "paused":        False,
#   "last_updated":  "2026-06-12T14:30:00Z"
# }

๐Ÿ”‘ Redis key layout

Every key prefix is configurable at construction time.

usdx:balance:{user_id}           โ†’ HASH   balance / total_credited / total_debited / is_frozen / created_at / last_updated
usdx:tx:{user_id}                โ†’ ZSET   JSON transaction records, score = UTC timestamp (ms)
usdx:otc:itc_reserve             โ†’ STRING ITC reserve amount
usdx:otc:usdx_supply             โ†’ STRING circulating USDx supply
usdx:otc:rate_history            โ†’ ZSET   historical rate snapshots
usdx:payment:invoice:{id}        โ†’ HASH   NowPayments invoice state
usdx:payment:user:{u}:invoices   โ†’ ZSET   per-user invoice index

โš›๏ธ Atomicity guarantee

Every state-changing wallet operation is a single EVAL call โ€” no multi-exec, no application-level locks, no read-modify-write round trips.

credit(user, 10.00)
  โ””โ”€โ–บ EVAL _LUA_CREDIT  โ”€โ”€โ–บ Redis executes atomically:
                                HINCRBYFLOAT balance
                                HINCRBYFLOAT total_credited
                                HSET last_updated
                              โ—„โ”€โ”€ returns [new_balance]

If Redis crashes mid-operation: the script either ran fully or not at all. If two processes call debit simultaneously: one wins, the other gets INSUFFICIENT_BALANCE. No coordination required between workers.


๐Ÿงช Tests

pip install -e ".[dev]"   # installs pytest, fakeredis, lupa, ruff, mypy
pytest                    # 24 tests โ€” all green
ruff check usdx/          # linting
mypy usdx/                # strict type-checking

Note: lupa (Lua runtime) is required for fakeredis to execute EVAL in tests. It is listed in [dev] extras and installed automatically.


๐Ÿ“ Examples

See examples/ for runnable code:

Example Description
quickstart.py End-to-end async script covering every method
fastapi_wallet_app/ Full REST API skeleton โ€” drop-in FastAPI service with Pydantic models, lifespan Redis, and Swagger UI

๐Ÿ”Œ Companion package

The TypeScript HTTP client โ€” @interchained/usdx โ€” pairs with this package:

import { USDxClient } from "@interchained/usdx";
const client = new USDxClient({ baseUrl: "https://api.yourapp.com" });
const balance = await client.getBalance("alice");

Zero production dependencies. Works in Node.js 18+, browsers, Deno, and Bun.


๐Ÿค Contributing

  1. Fork โ†’ branch โ†’ make your changes
  2. pip install -e ".[dev]" and run pytest โ€” all 24 must stay green
  3. ruff check usdx/ && mypy usdx/ โ€” zero warnings
  4. Open a PR with a clear description of what changed and why

Please report security issues via private message, not public issues.


๐Ÿ“œ License

GNU General Public License v3.0 or later. See LICENSE for the full text.

interchained-usdx  Copyright (C) 2024  Interchained
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under the terms of the GPLv3.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

interchained_usdx-0.1.0.tar.gz (35.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

interchained_usdx-0.1.0-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

Details for the file interchained_usdx-0.1.0.tar.gz.

File metadata

  • Download URL: interchained_usdx-0.1.0.tar.gz
  • Upload date:
  • Size: 35.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for interchained_usdx-0.1.0.tar.gz
Algorithm Hash digest
SHA256 89665e602f57503e0561c0c154e766e491f240703067aa26dccfb3b0b3a5846a
MD5 3cc2a819566ea43ae53fa7d1b7f37956
BLAKE2b-256 a000ce1a46ccd837375ddc5df9977e26bbdb7217b6dbef9f26371eb2b0550cc5

See more details on using hashes here.

File details

Details for the file interchained_usdx-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for interchained_usdx-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 def28a908a0310c6685ecfc0e4afb10b8bcd32a8b5eae2a4b7a32b63293e2134
MD5 f968ee1bc5dbce33ede168aae3258f3d
BLAKE2b-256 a4fbef8e97b2e31d836bb76bd6dc28ad906d28b916846475ddca6b88c81dd226

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page