This repository hosts a lightweight data toolkit used to audit Paradex vault activity on Starknet. It focuses on reconstructing refund allocations from raw on-chain events gathered through the Starknet JSON-RPC API. The codebase is intentionally dependency-free so that it can be executed in restricted environments that only ship with the Python standard library.
Primary use cases:
- Generate structured JSON and CSV reports quantifying refunds owed to vault depositors.
- Experiment with different trade-window assumptions to see how exclusion rules impact refunds.
- Compare independently curated refund lists to validate reconciliation efforts.
├── compare_refunds.py # Compare two JSON refund sources.
├── refunds_after_close_cashflow*.py # Script entry points (one per refund policy).
└── vault_refunds/ # Shared library powering all scripts.
├── cli.py
├── events.py
├── refunds.py
├── rpc.py
└── utils.py
The vault_refunds package encapsulates all reusable logic: JSON-RPC plumbing, event parsing,
decimal handling, and refund computation. The root-level scripts are thin wrappers that select a
specific refund policy and expose it through a friendly CLI.
- Python 3.9 or newer.
- A Starknet JSON-RPC endpoint with access to the Paradex vault events you intend to analyse.
No additional dependencies are required.
All refund scripts share the same arguments; they only differ by the trade-window policy applied to deposits and/or withdraws. Logically they compute:
| Script | Mode | Refund Formula |
|---|---|---|
refunds_after_close_cashflow.py |
Standard | max(0, deposits - withdraws) |
refunds_after_close_cashflow_excl_window.py |
Exclude deposits in trade window | max(0, deposits_outside_window - withdraws) |
refunds_after_close_cashflow_excl_wdw_withdraws.py |
Exclude withdraws in trade window | max(0, deposits - withdraws_outside_window) |
refunds_after_close_cashflow_excl_both.py |
Exclude deposits and withdraws in trade window | max(0, deposits_outside_window - withdraws_outside_window) |
Typical command (refunds_after_close_cashflow.py shown, the others follow the same pattern):
python refunds_after_close_cashflow.py ^
--vault 0x... ^
--rpc https://my-starknet-node.example ^
--token-allowlist 0x...USDC ^
--postfilter-after 2025-08-12T12:30:00Z ^
--trade-start 2025-08-07T12:40:00Z ^
--trade-end 2025-08-12T12:30:00Z ^
--from-block 0 ^
--to-block -1 ^
--chunk-size 2048 ^
--out-json refunds_after_close_cashflow.json ^
--csv-out refunds_after_close_cashflow.csvKey arguments:
--vault: Paradex vault contract address.--rpc: Starknet JSON-RPC endpoint URL.--token-allowlist: ERC-20 addresses to keep (e.g. the USDC vault asset).--asset-decimals: Token decimals (default 6 for USDC).--deposit-selector/--withdraw-selector: Event selectors; defaults match the Paradex vault ABI.--postfilter-after: Only wallets with a withdraw strictly after this timestamp are considered.--trade-start/--trade-end: Inclusive trade window used in the exclusion logic.--from-block/--to-block: Optional block range (use-1to process up to the latest block).--chunk-size: Event pagination size (tune for your RPC provider).--out-json: JSON report path.--csv-out: Optional CSV summary path limited to addresses that receive a refund.
The JSON output follows the structure below:
compare_refunds.py helps validate that two JSON outputs agree within a configurable tolerance:
python compare_refunds.py --cashflow refunds_after_close_cashflow.json --legacy refunds_complet.jsonThe script reports:
- Address coverage of each file and the shared intersection.
- Aggregate refund totals for both sources.
- Number of addresses with differences above the tolerance.
- Largest discrepancies and addresses that appear in only one file (top five each).
- The repository avoids storing any sensitive information. Addresses and selectors included in the defaults are publicly known Paradex values.
- All strings are strictly ASCII to guarantee compatibility with terminals and CI logs.
python -m compileall .can be used to perform a quick static sanity check.- The new modular layout allows re-use from Jupyter notebooks or other scripts:
from vault_refunds.cli import run_cli, RefundMode
run_cli(RefundMode.STANDARD, argv=[
"--vault", "0x...",
"--rpc", "https://...",
"--token-allowlist", "0x...USDC",
"--out-json", "report.json",
])Choose the license that matches your publishing requirements before pushing the project to a public repository. Until then the code is provided without an explicit license.
{ "meta": { "vault": "0x...", "token_allowlist": ["0x..."], "asset_decimals": 6, "postfilter_after": "2025-08-12T12:30:00Z", "trade_window": { "start": "2025-08-07T12:40:00Z", "end": "2025-08-12T12:30:00Z", "rule": "Deposits ... excluded ..." }, "unknown_addr_in_deposits": 0, "unknown_addr_in_withdraws": 0, "events_scanned": { "deposits": 12345, "withdraws": 6789 }, "notes": [ "Refund = max(0, ...)" ] }, "totals": { "sum_deposits_all": "123.456000", "sum_withdraws_all": "12.340000", "sum_refund": "111.116000" }, "results": [ { "address": "0x...", "deposits_total": "10.000000", "withdraws_total": "1.000000", "refund_amount": "9.000000", "deposits": [ { "ts": "2025-08-10T12:00:00Z", "block_number": 123, "token": "0x...USDC", "amount": "5.000000", "tx": "0x..." } ], "withdraws": [ { "ts": "2025-08-12T13:00:00Z", "block_number": 456, "token": "0x...USDC", "amount": "1.000000", "tx": "0x..." } ] } ] }