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.1.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.1-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: interchained_usdx-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 fb24b1375b1167ddc29628c1e17a11007abaa49b0801874facfecc93b5f035a2
MD5 b39ae5c3454879e18ec8a29051a8f72e
BLAKE2b-256 bde921a6fb667598528f42bd552647ad4f46e75c776eb44e4ce111b8865c3420

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for interchained_usdx-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0d037408504bc1e65c6f58045170248b93ee3dc2a3bebc68946b8e0e225ccfbb
MD5 9962430a80c3aecaf32a57c5afdd4b2c
BLAKE2b-256 5c8784c341e571f02d864b5cf497ecdb517eaf17e6308c9b25c1cce753a37f9d

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