Give your agent a wallet you control.
에이전트가 일회용 카드나 기계 결제 프로토콜로 온라인 결제하고, 모든 요청을 직접 승인
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
Independent, live proof-of-solvency monitor for Strike Finance. Reads Strike's lockers on Ethereum, Solana and Cardano, counts what Strike owes every trader, and shows the gap live. Read-only, open source, verifiable with one command, with Telegram safety alerts.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Every dollar on Strike, proven on-chain. ZeroGap is an independent, open-source, read-only proof-of-solvency and safety monitor for Strike Finance. It counts every dollar in Strike's on-chain lockers, counts every dollar Strike owes its users, and shows the gap live. Anyone can re-run the whole check with one command.
ZeroGap is an independent project. It is not affiliated with, endorsed by, or operated by Strike Finance. (Strike Finance is strikefinance.org, not the Bitcoin app "Strike".)
Live: https://zerogap-strike.vercel.app · Alerts: https://t.me/zerogap_alerts · Scan history: reports branch
| Problem | Strike V2 trades off-chain on the Strike Node, while user funds sit in on-chain lockers. Nobody could independently check that the lockers hold what Strike owes. |
| Solution | ZeroGap reads every locker on Ethereum, Solana and Cardano, sums every account from Strike's public API, and publishes a live reserve ratio (target exactly 100%), flow match, safety alerts and a personal "My Safety" check. Fully reproducible with one command. |
| Result | 99.16% (Drift, within 1%): $1.73M in reserves vs $1.75M owed to 3,487 accounts (0 failed). Reserves include Strike's market-maker bot on Aster ($34.2K), a separate line disclosed by Strike. ZeroGap's own checks found real issues that Strike confirmed: $79K of isolated-margin positions missing from margin_balance, false Solana flow alarms from relayed deposits, and the market-maker bot's off-chain funds. The rest of the gap is bridge funds being returned, per Strike. |
| Strike integrations | Locker contracts on 3 chains (ABI- and IDL-decoded) · leaderboard, /v2/account, /v2/balances · vault depositors · price feed + Credit prices · transfers stats · Builder Connect (builder code zerogap, testnet withdrawal proven) |
| Demo video | ▶ Watch on YouTube (5 min: 1-min pitch, then live demo) |
| Links | Live: https://zerogap-strike.vercel.app · Alerts: https://t.me/zerogap_alerts · Verify: npm run verify |
| Quality | 109 unit/integration tests + Playwright E2E + live mainnet smoke + fresh-clone verification (T6.6), all in CI |
| Criterion | ZeroGap |
|---|---|
| Innovation and creativity | The first independent proof-of-solvency for a hybrid DEX: an off-chain order book checked against on-chain lockers on three chains at once, with a target of exactly 100% (over is as suspicious as under). |
| Integration with Strike | Reads Strike's locker contracts on Ethereum, Solana and Cardano (ABI and IDL decoded); the leaderboard, /v2/account, /v2/balances, vault depositors, price index, Credit prices and transfer stats; Builder Connect with registered builder code zerogap for My Safety (testnet withdrawal proven). |
| Utility and impact | Traders can see that their money is backed, check their own account, and withdraw. Strike gets public, reproducible proof of reserves plus 24/7 safety alerts. It already found real issues that Strike's founder confirmed: isolated-margin balances missing from margin_balance ($77K) and relayed deposits that made Solana flows look wrong. |
| Technical execution | TypeScript monorepo; read-only collectors; pure, tested core; 109 unit and integration tests, Playwright E2E, a live smoke test and a fresh-clone verify, all in CI; live on Vercel with scheduled GitHub Actions; every number carries its source, timestamp and confidence. |
| Future potential | Can become Strike's public transparency page: per-user proofs, more chains and lockers as Strike adds them, an alerting API for partners, and hourly signed reports already published to the reports branch. |
flowchart LR
subgraph Chains["On-chain lockers (read-only)"]
ETH["Ethereum vault<br/>USDC · aEthUSDC"]
SOL["Solana vault + USDC account<br/>+ treasury PDA"]
ADA["Cardano deposit +<br/>protocol scripts"]
end
subgraph Strike["Strike public API"]
LB["/stat/v1/stats/leaderboard"]
ACC["/v2/account · /v2/balances"]
VD["/v2/vault/{id}/depositors"]
PR["/price/v2/premiumIndex<br/>/v2/credit/*"]
TR["/stat/v1/dashboard/transfers"]
end
subgraph Engine["ZeroGap engine (TypeScript)"]
COL["Collectors<br/>ethereum · solana · cardano<br/>accounts · prices · flows · safety"]
CORE["Core (pure, tested)<br/>valuation · liabilities · ratio<br/>flow check · alert rules"]
REP["Verify report<br/>JSON + sha256 + commit"]
end
subgraph Out["Outputs"]
WEB["Dashboard · Landing · My Safety<br/>(Vercel)"]
TG["Telegram alerts"]
GH["GitHub branches<br/>zerogap-data · reports"]
end
ETH & SOL & ADA --> COL
LB & ACC & VD & PR & TR --> COL
COL --> CORE --> REP
CORE --> TG
REP --> GH --> WEB
USER(("Trader")) -- "Builder Connect<br/>(signs in own wallet)" --> WEB
Collectors only read; the core is pure functions; outputs only read stored results, so a slow chain never blanks the dashboard.
Scheduled GitHub Actions run the engine (scan.yml) and the public hourly verify (verify.yml).
flowchart TD
A["List accounts<br/>leaderboard (exclude 6 vault accounts)"] --> B["Read every account live<br/>≤ 40 req/s · equity (wallet_balance + unrealized_pnl) + stakingRewardBalance<br/>+ discovered sub-accounts"]
B --> C["Add depositors' vault shares<br/>/v2/vault/{id}/depositors"]
C --> D["Cross-check: Σ shares ≈ each vault account"]
B --> E["Read lockers on-chain<br/>Ethereum · Solana · Cardano"]
E --> F["Price with ONE snapshot<br/>Strike index + Credit prices · stablecoins by contract"]
D --> G["Liabilities = margin + vault shares + staking"]
F --> H["Reserves"]
G & H --> I{"Ratio = reserves ÷ liabilities<br/>target 100.00%"}
I -->|"≤ ±0.01%"| J["Balanced"]
I -->|"≤ ±1% or known in-transit"| K["Drift / In transit"]
I -->|"> ±1%"| L["Needs review<br/>(never published as insolvency)"]
J & K & L --> M["Publish: dashboard + JSON report + history"]
E --> N["Safety monitor<br/>pause · queues · timelocks · rate limits · admin withdrawals"]
N --> O["Telegram alert (de-duplicated)"]
sequenceDiagram
actor U as Trader (wallet)
participant B as Browser (ZeroGap page)
participant S as Strike API
B->>B: Generate Ed25519 API-wallet key (stays in this tab)
B->>S: POST /auth/builder/request-signature (code=zerogap, public key)
S-->>B: message_to_sign
B->>U: Sign connect message
U-->>B: wallet signature
B->>S: POST /auth/builder/verify-signature
S-->>B: account_id
B->>S: GET /v2/account, /v2/balances
B-->>U: Account value, withdrawable now, checks vs lockers + platform ratio
B->>S: POST /v2/withdraw/quote (signed with API-wallet key)
S-->>B: message_to_sign (destination = user's own wallet)
B->>U: Sign withdrawal
U-->>B: wallet signature
B->>S: POST /v2/withdraw
S-->>B: status pending
ZeroGap never sees a key that can move funds: Strike pays out only to the connected wallet, and only after the user signs.
npm run verify)| USD | |
|---|---|
| Reserves: Ethereum, Solana and Cardano lockers | $1,696,613 |
| + Strike market-maker bot on external exchanges (Aster $34,196.04 · Lighter $1.00), disclosed by Strike | $34,197 |
| Reserves total | $1,730,810.31 |
Σ account equity (wallet_balance + unrealized_pnl, locked rewards and isolated margin included) | $632,637.47 |
| + Σ depositors' vault shares | $1,080,910.03 |
| + Σ staking rewards | $31,942.88 |
| + Commission | pending (not yet exposed by Strike) |
| Liabilities | $1,745,490.38 (3,487 accounts read, 0 failed, 6 vault accounts excluded) |
| Ratio | 99.16% · gap −$14,680 (−0.84%) → Drift |
Transparency note (requested by Strike): part of the reserves is held by Strike's market-maker bot
0x6139…1937 on the Aster exchange. It is not an on-chain locker; ZeroGap reads it live through read-only API access that
Strike provided (keys are kept out of this repo), and shows it as its own line everywhere. Anyone can check the bot's link to
Strike on-chain: it deposits USDC into Strike's Ethereum locker for Strike account 019d06a7…. Strike says the remaining
gap is funds being returned over the bridge today; ZeroGap re-runs automatically. Earlier steps of the investigation:
docs/GAP-INVESTIGATION.md and docs/DECISIONS.md #50–54. Live numbers:
the dashboard; history: the
reports branch.
git clone https://github.com/Lakshmikanth-3/ZeroGap && cd ZeroGap
npm install
npm run verify # or: npx zerogap verify
No keys are needed. It scans every Strike account (about 3 minutes at ≤40 requests/s), reads every locker on-chain, and prints
reserves by chain and address, the liabilities (accounts read, vaults excluded, failures), the price snapshot used,
the ratio, and the gap in USD and %. It also writes reports/<network>-<timestamp>.json, a plain JSON file with
every input: addresses, raw on-chain balances, decimals, prices with sources and timestamps, every account's raw
wallet_balance / unrealized_pnl / margin_balance / lockedRewards / stakingRewardBalance, every depositor's vault share, the per-vault cross-check,
open notes, the code commit and a content_sha256. Diff it against any
published scan: the dashboard's Download this scan (JSON) button, GET /api/report, or the hourly files in the
reports branch.
/me): a trader connects a wallet through Strike Builder Connect, sees their balance backed by the
lockers, and can withdraw by signing in their own wallet (proven on Strike testnet).reserves = Σ over lockers, assets: amount × price
amount = raw on-chain integer ÷ 10^decimals (Credit custody assets: Strike's raw_amount_scale)
price = Strike index price (ADA, ETH, SOL) | Strike Credit price (sUSDrf, LP, scaled aUSDC)
| 1.00 for fiat-redeemable stablecoins by contract (USDC, USDT, USDCx, USDM)
| iUSD: labelled $1 placeholder (price source pending) | anything else unpriced → excluded
liabilities = Σ (wallet_balance + unrealized_pnl) account equity, every non-vault account + sub-accounts
(locked rewards and isolated margin included; NOT margin_balance)
+ Σ depositors' current vault shares GET /v2/vault/{id}/depositors current_equity (not inside equity)
+ Σ stakingRewardBalance GET /v2/balances (withdrawable; not inside wallet_balance)
+ commission pending: not yet exposed by Strike (no value added)
ratio = reserves ÷ liabilities gap = reserves − liabilities (USD and % of liabilities)
status = Balanced |gap| ≤ 0.01% · Drift ≤ 1% · Needs review > 1% (never published as insolvency)
· In transit when |gap| ≤ the founder-stated in-transit amount ($10,000)
One price snapshot values every reserve row; it is taken right after the account scan, and both are timestamped.
| Locker | Address | Holds (23 Oct) |
|---|---|---|
| Ethereum vault | 0xbF4cFccd11257e568A936a7867D138f54A43cffa | USDC, aEthUSDC (Aave V3) |
| Solana vault account | Dj9NkHyMMLyQGnYz2necVuHF6ELXqxUa3EsRZNHiPrrt | SOL (rent); owns the USDC token account |
| Solana USDC token account | BT85fgyhyZhCtaNdciKEGoj7mU8E3EeFijPy6XCmCAA6 | USDC |
| Solana treasury PDA | H4nZyX3qGQwGH6wQn8G53uZ6LX8TqPZDakCN2M54icSH | SOL |
| Cardano deposit script | addr1w9yg…kls3 | ADA, USDM, USDCx, sUSDrf, LP_SUNDAE_USDCx_USDM, iUSD |
| Cardano protocol script | addr1w9m5…7jf2 | ADA, USDM |
Solana program 7XASQ24fiwoNHmTnQdi3k3WXMUXRaj7MdcHvkSducrB8 (IDL strike_vault, packages/collectors/abi/).
Ethereum vault ABI: packages/collectors/abi/ethereum-vault.json.
| Purpose | Strike endpoint (public, no key) |
|---|---|
| Account list | GET /stat/v1/stats/leaderboard (ids only; balances lag) |
| Account value | GET /v2/account?account_id= → wallet_balance, unrealized_pnl (equity), sub_accounts |
| Rewards | GET /v2/balances?account_id= → lockedRewards, stakingRewardBalance |
| Vault shares | GET /v2/vault/{id}/depositors → current_equity per depositor |
| Index prices | GET /price/v2/premiumIndex |
| Credit prices | GET /v2/credit/collateral-assets |
| Custody mapping | GET /v2/credit/settings → custody_asset_mappings |
| Reported flows | GET /stat/v1/dashboard/transfers |
| My Safety | Builder Connect /auth/builder/*, /v2/withdraw/* (builder code zerogap) |
wallet_balance + unrealized_pnl (23 Oct). margin_balance is not used: it equals
available_balance and leaves out isolated-margin positions ($77K across 47 accounts, found by ZeroGap's manual check).stakingRewardBalance, not inside wallet_balance) are added; locked rewards
are already inside wallet_balance and counted once. Commission balances are withdrawable too: pending until Strike exposes them.Dj9NkHy… and the USDC token account BT85fg…, de-duplicated.0x8f0e…eca7, base, bsc,
polygon …) arrive as USDC in the Ethereum locker. The daily flow match compares them as one "Solana + relayed" row
(22 Oct: 2,447.28 reported vs 2,447.45 on-chain, 99.99%).0x6139…1937) holds the other side of traders' positions on Lighter and Aster. Its
equity counts as a separate, disclosed reserve line, not an on-chain locker (founder, 23 Oct 18:43). Lighter is read
from its public API; Aster through read-only API access provided by Strike (kept out of the repo). Its link to Strike is
on-chain: it deposits into Strike's Ethereum locker for Strike account 019d06a7….The same engine also runs against Strike's testnet (ZEROGAP_NETWORK=testnet, dashboard /dashboard?network=testnet):
Sepolia vault 0x879e450F2482a2DEcbd27176A4c177e69Bd7A0E6, Solana devnet vault Di862rQJwGgMLtrchoBfkcehEKXPpYnppeA9Gmxtasin
(program FSNjjtrZP2BiuPfyRjTWQUybN8QNnEQgUogho79SMzXt), Cardano preprod script addr_test1wpuakhm8ftcwy2t00vhxp3rmqev90cs5xqf6ynu7f7rxrrg4rlm70,
and Strike's testnet accounts. It is clearly labelled as test funds and never alerts the public channel. Testnet balances are
faucet-credited, so the testnet ratio is not meaningful; mainnet is the published proof. All write actions (My Safety
withdrawals) were tested on testnet first. ZEROGAP_NETWORK=testnet npm run verify reproduces it.
cp .env.example .env # optional keys, all free tiers
npm start # http://localhost:8787 (/, /dashboard, /me, /api/state, /api/report)
| Optional key (free tier) | Effect |
|---|---|
ETH_RPC_URL (Alchemy) | Faster Ethereum state reads (logs use a wide-range public RPC) |
SOLANA_RPC_URL (Alchemy or Helius) | Avoids public Solana rate limits |
BLOCKFROST_PROJECT_ID | Cardano via Blockfrost instead of public Koios |
TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID | Alert delivery |
STRIKE_BUILDER_CODE | Enables My Safety (Builder Connect) |
DATABASE_URL (Supabase) | Postgres history (packages/db/schema.sql); otherwise data/*.jsonl |
Deployment: Vercel serves the pages and read-only API. The ZeroGap engine workflow runs one engine cycle on a schedule
and publishes state to the zerogap-data branch. The Hourly verify workflow appends a verify report to the reports branch.
Any always-on host can instead run docker build -t zerogap . && docker run -p 8787:8787 --env-file .env zerogap.
npm test # unit + mocked integration (recorded real fixtures; no network) — runs in CI on every push
npm run test:live # mainnet smoke tests
npm run test:e2e # Playwright against a running server (ZEROGAP_URL=…)
npm run test:t6.6 # fresh clone + npm install + npm run verify with no keys, compared with the live dashboard
Read-only: the server answers GET requests only, and no key that can move funds is ever stored. For My Safety, the Ed25519
API-wallet key is generated in the browser and never leaves the tab; withdrawals go only to the user's own wallet and need
the user's own signature. No secrets are committed (.env is git-ignored; .env.example holds placeholders only).
docs/PRD.md (plan) · docs/DECISIONS.md (every decision and finding, with evidence) · docs/PROGRESS.md (phase log and
test results) · docs/MANUAL-CHECKS.md (explorer and app spot checks) · docs/design/ZeroGap UI.html (design).
MIT. See LICENSE.