Lets you pay everyday purchases with USDG, or borrow against tokenised Amazon stock without selling it. It holds collateral on-chain and returns it when you repay.




Athena Card is a non-custodial card app for Singapore & Australia. You hold your own keys. You fund, send, and spend from the app.
Athena Spend is the on-chain protocol built into that app for this buildathon. You pay everyday purchases in USDG. You can also borrow against tokenized Amazon stock without selling it. The tokens sit in the contract as collateral and come back when you repay.
Athena Spend is Solidity ^0.8.24 on OpenZeppelin Contracts v5.2.0. I used their AccessControl, Pausable, ReentrancyGuard, SafeERC20, and Math.mulDiv instead of writing my own. The contracts are immutable — no proxies — so there is no upgrade slot and no storage-collision risk. Amounts are integers only (USDG 6 decimals, AMZN 18, prices 8), so the spend limit cannot pick up a floating-point bug. Authorization is msg.sender and roles, never tx.origin. Every loop has a fixed bound I can name: Hertz is at most 20 holds.
Structure. The main contract orchestrates. It does not hide math. LtvLib turns AMZN × price × LTV into USDG with Math.mulDiv so a large balance cannot overflow the multiply. OracleLib is the only place a price is trusted. Types live in types/. Custom errors live in errors/. Interfaces are explicit. RebateBond is a separate contract: Athena Spend pays the merchant; the bond pays cashback. PreauthDesk sits on the same Spend. It does not rewrite capture. Hertz is at most 20 holds of 10 USDG, so the settle loop is bounded and named. Three calls a reviewer can hold in their head: enableSpend → authorizeAndCapture (or authorize + reverse) → repay / withdrawCollateral.
Why no proxy. An admin upgradeTo can silently change capture economics. I did not leave that door. Parameter knobs that exist (setLtvBps capped at 60% in the library even if a setter is later compromised, setPriceFeed, pause) are explicit and evented. A logic bug needs a new deploy and a new enableSpend.
Access and blast radius. AUTH_OPERATOR_ROLE posts taps. I never hold user keys. I cannot raise a session cap. I cannot skip spendableOf. enableSpend requires the cardholder’s EIP-712 SessionPermit. A leaked operator key can only tap accounts already enabled, up to remaining cap and current spendable. That is the blast radius, written down on purpose. PAUSER_ROLE stops new exposure. It never stops reverse, repay, or withdrawCash. Pause that traps funds is a finding. Mine does not.
Every state-changing path. Checks-effects-interactions. nonReentrant wherever tokens move or the bond is called. SafeERC20 on every transfer. Cash locks before credit. Merchant is paid before cashback. authId is unique (abi.encode, not packed) so a tap cannot replay. Reverse-after-capture reverts. Unpaid debt and locked credit block AMZN withdraw. There is no liquidation engine, so there is no liquidation bug surface.
Oracle. Credit reads require answer > 0 and updatedAt inside 2 hours. Views allow 25 hours. Sequencer uptime is checked when a feed is set. If the price is stale, zero, or paused, LTV is zero. Fail closed. A cash-only tap can still work. Weekend groceries should not revert because New York is shut. They should stop borrowing against AMZN.
Bond. Cashback is 5%, protocol 2%. If the bond cannot cover 7%, it pays pro-rata, emits the shortfall, and does not revert. An empty bond must not fail a grocery tap. A bond cannot pay out more than it was funded. That is an invariant, not a comment. payCapture is CAPTURE_ROLE — Athena Spend only. fundBond and fundCreditPool are permissionless recapitalisation, not a backdoor into user collateral.
Decimals and errors. USDG is 6 dp, AMZN is 18, prices are 8. Integer math only. Named custom errors on every failure (InsufficientSpendable, StalePrice, DuplicateAuthId, CapExceeded, …). NatSpec on every public and external function. If state changes, an indexed event fires.
Tests I actually run. cd contracts && forge test. Unit tests hit happy paths and each custom error by name. Fuzz: 256 locally, 1024 in CI. Invariants: 64 runs, depth 32. Properties that must hold after any sequence: spendable never exceeds cash plus LTV minus debt; the credit pool is fully backed by USDG in the contract; a bond never overpays; reverse-after-capture reverts; Authorized hold locks equal account locks. Film vector a judge can check by hand: 5 AMZN × $180 × 50% = 450 USDG.
What I do not claim. I do not claim Slither was run. Run slither .. Remaining tradeoffs are in contracts/THREAT_MODEL.md: admin can rotate the price feed (required for mock → Chainlink on mainnet); pause is liveness, not custody; operator bound is the session cap. Film settlement is MockUSDG named Global Dollar (Demo). Collateral is canonical testnet AMZN. The AMZN feed is a mock at $180 because Chainlink RHAMZN/USD has no code on testnet 46630. Shipping that mock on mainnet would be a finding. Production Paxos USDG and Chainlink addresses are in contracts/CANONICAL.md, checked on-chain.
Verify. contracts/README.md. Robinhood testnet AthenaSpend 0x89b5b4E7bd471b6e933D95a0384F50ec6DcD30C8. Arbitrum Sepolia Sourcify full match 0x600cb2C1F802322461AeE2BE540621dD4B6f59EB.
I am not building for people who already live on chain. I am building for people who already shop. They buy groceries. They hire a car. They do not want to sell the stock they are holding just to get through the week.
That is who I attract, and it is a large market. Every crypto card today asks you to spend cash, or to sell an asset first. Selling is painful twice: you lose the shares, and you can owe capital gains tax on the gain. Athena Spend is the card that does neither. You keep the Amazon. You spend USDG against it. You tap at Woolworths, Coles, or Bunnings the way you already shop. You do not need to understand DeFi. You need to understand one number: spendable.
That number is why a first-time user stays past the download. The Card tab shows what you can spend today — USDG you hold, plus up to half the value of AMZN you posted, without selling it. While earning a 5% USDG cashback.
Retention is the loop after the tap.
You come back because the stock is still yours. That is the lock-in, no points program can copy. If you sell AMZN to pay rent, the product is over. If you spend against it, you still own the upside, you still own the shares, and you still have a reason to open the app next week to repay, tap again, and check spendable.
You come back because cashback is real USDG, on every purchase, including credit-line spend. Not points. Not a partner portal. It lands in the same balance you spend from. Rewards, history, and the receipt after Woolworths exist so you can see it. People keep a card that pays them in money they can use tomorrow.
You come back because the rest of life is already in the app. Keys stay on your phone. Vault, biometric lock, send, receive, convert, AUD in through PayID / Osko, POLi, or card. You do not fund on one app and spend on another. Once your cash, your AMZN, and your cashback sit here, leaving means selling, moving, and starting again.
Hertz in the demo is the same job for a rental: lock a ceiling, settle what you used. Not a partner. The point for a user is simple — this card can hold, not only tap — so a weekend hire does not require a second product.
What I do have is a full card a person can live in, pointed at merchants they already know, with a reason to stay that compounds: keep the asset, keep the cashback, keep spending. We are planning to launch in Singapore and Australia. Same everyday spend. Same reason not to leave.
What makes Athena so different, is that it’s entirely non-custodial: the hold, the borrow, and the collateral all live in a smart contract you control, not in a company's ledger.
Most crypto card spends cash you already hold, or it sells the asset first. Most DeFi credit line is a lending market: post collateral, get a loan, get liquidated when the price moves. I did not build a better version of either. I built a debit tap whose limit includes tokenized Amazon stock — and the stock is never sold.
That is the boundary. The till sees a card. The chain sees authorize, capture, or reverse. Spendable is USDG cash plus 50% of AMZN you posted. Cash spends first. Credit fills the rest. AMZN stays in the contract. When you repay, it comes back. If you do not repay, you cannot withdraw it. There is no liquidation engine. I did not skip liquidation because it was hard. I skipped it because a grocery tap should not seize someone’s shares. The risk is exit, not a bot.
The second original move is time. Amazon’s market closes. Woolworths does not. A stale or weekend price does not block milk. It turns the AMZN line off and leaves cash on. Credit fails closed. The aisle still works. That is card thinking on an equity oracle, not oracle thinking on a card.
The third is Hertz. Real rentals pre-authorise a ceiling and capture the bill later. On-chain capture on this Spend is all-or-nothing per hold — there is no “take $87 of a $90 lock” without a new deploy. So I did not fake a partial capture. I built PreauthDesk: a 200 USDG ceiling becomes twenty 10 USDG holds. Settle 90 captures 90 and reverses the rest. If the bill is not on the 10 USDG grid, overshoot is less than one chunk, disclosed, never the rest of the ceiling. Same Spend. Capture is not rewritten. A rental and a supermarket share one rail.
Cashback is the fourth. It is not points in a database. It is USDG from a merchant rebate bond, 5% to you, 2% protocol, paid on capture. If the bond is short, it pays pro-rata and the tap still settles. An empty CLO must not fail a grocery purchase. In this demo I fund the bond. Merchants have not agreed to fund one yet. The design is still the design: cashback is settlement money, on-chain, in the same USDG the till was paid.
One product. One tap. Stock you did not sell. A spend line the rest of crypto card and DeFi credit both refused to be.
My friends & family live paycheck to paycheck with money already sitting in investments they are too afraid to touch. Groceries, fuel, and a rental still have to be paid. The market’s answer is: sell. Sell the stock, pay the bill, lose the shares, and pay capital gains tax on the way out. That is a genuine need, not a crypto one.
Selling is the expensive answer. In Australia, a disposal of shares is a capital gains event. Sell $20,000 of stock you bought at half the price, and you can owe tax on $10,000 of gain — thousands on one sale. Do that every year and a large share of every gain never compounds. Over a decade that tax is a house deposit you handed over so you could pay rent. Athena Spend does not sell. You borrow against tokenized Amazon stock and you spend. You are not in a disposal, so you are not paying capital gains tax on a sale that never happens. You keep the shares. You keep the upside. You keep the tax. Scale that across every tap, every year, for everyone who would otherwise have sold, and the money this card saves is the product. (Please note this is not tax advice, and the rules around crypto-backed borrowing are still developing).
The second need is speed. A till cannot wait for you to sign a transaction in the aisle. A non-custodial card that cannot settle at tap time is not a card. Athena Spend posts cash and/or AMZN first, under a cap you already signed. I submit the capture. You do not sign at the till. The merchant is paid in USDG. That is the real card problem, solved without taking your keys.
I built this because I was tired of watching my friends & family liquidate their future to fund their week. We are planning to launch in Singapore and Australia — same groceries, same rentals, same rule: you should not have to sell what you own to live.
Paxos USDG is the unit the card is denominated in. Enable, lock, capture, repay, cashback, protocol fee, credit, and debt are all USDG at 6 decimals — the same decimals as Paxos Global Dollar. The merchant address is paid in USDG. The AMZN line is a USDG limit, not a second currency. If it moves at tap time, it is USDG.
I wired the protocol to Paxos Global Dollar and checked the live tokens on-chain (name(), symbol(), decimals(), code size) before treating an address as real:
· Arbitrum One: 0x004B506865409877C9fA29bfb1ebA929984B9bbC
· Robinhood Chain mainnet: 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
· Robinhood Chain testnet (canonical Paxos, not the film token): 0x7E955252E15c84f5768B83c41a71F9eba181802F
Full table and RPC calls: contracts/CANONICAL.md.
The filmed testnet cannot mint that canonical Paxos token. Balances were zero, faucet() reverted, the Paxos public faucet does not issue it here. So, the demo settles in MockUSDG named Global Dollar (Demo) — 6 decimals, same shape as Paxos, never labelled Paxos. Production settlement is the Paxos addresses above. A judge can tell the difference because I wrote the difference down.
Integration includes how Paxos behaves. Live USDG is upgradeable. Paxos can pause transfers and freeze an address. If that happens, new captures fail closed at the token transfer. That is a Paxos dependency I accepted, not a surprise I hid.
The app funds and spends in the same unit: AUD in, USDG in the wallet, USDG out to the merchant. Athena Spend is a Paxos USDG card with an equity line on top — not a USDG mention on a USDC product.
Buildathon started on 14th September 2026 in 3 weeks, I built Athena Spend from a blank Foundry tree to a filmed, verified product — contracts, backend, app, Hertz, docs. I shipped to GitHub in batches. The work was daily. The dates below are the work.
I locked the product: three calls, USDG settlement, AMZN only, 50% LTV, no proxy, no liquidation. I stood up Foundry, OpenZeppelin v5.2.0, mocks, OracleLib, and LtvLib, with the 5 AMZN × $180 × 50% = 450 USDG vector in tests before I wrote the facade.
I wrote RebateBond (5% cashback, 2% protocol, pro-rata shortfall that never reverts a tap). Then AthenaSpend: EIP-712 session, cash-then-credit locks, authorize / capture / reverse / authorizeAndCapture, pause that does not trap exits. Unit tests for every named error. Invariants started here.
I finished forge test (fuzz + invariants). I live-called Robinhood testnet USDG and AMZN (decimals, balances). Canonical Paxos USDG on 46630 could not be minted. I documented that on 22 Sep and committed to MockUSDG named Global Dollar (Demo) for film, with real Paxos addresses in CANONICAL.md. I built the backend capture path (spendProvider, integer AUD→USDG, webhook authorizeAndCapture) and the app path (Enable Spend, Spendable on the Card tab, Woolworths Pay, receipt + hash). Base production stayed frozen behind a compile-time flag.
Dual deploy. Arbitrum Sepolia: AthenaSpend 0x600cb2…59EB, Sourcify full match, backup capture. Robinhood testnet 46630 (film): AthenaSpend 0x89b5b4…30C8, RebateBond, bonds, credit pool, Woolworths capture, then the credit-path tap — 450 USDG against 5 AMZN, stock not sold. ResetDemoWallet for film. AUD→USDG locked at 0.71102 from the 22 Sep ECB print.
First GitHub ship of the whole stack: contracts, backend, Flutter Spend path, threat model, deploy logs. 1c29fec.
I designed Hertz as a desk on the same Spend, not a second spend contract. Capture is all-or-nothing per hold, so a 200 USDG ceiling is twenty 10 USDG holds; settle 90 captures 90 and reverses the rest. Unit + invariant tests for the desk before it touched the film chain.
PreauthDesk live at 0x54a9…9C4a (Blockscout verified). Hertz 200 / 90 dry-run on-chain. Woolworths authorizeAndCapture still the operator EOA. Same day: Hertz check-in, hold, checkout, reap, kill-switch (HERTZ_PREAUTH + HERTZ_UI_ENABLED). Pushed e8282ad and 2b4c079. Hertz is a demo merchant, not a partner.
I live-called real Paxos USDG on Arbitrum One (0x004B50…9bbC) and Robinhood mainnet (0x5fc536…d168). Production settlement is Paxos. The film token is not.
Film reset: 5 AMZN, 0 cash, 0 debt, spendable 450 USDG. Assets polish for the recording. I froze the verified contracts. No on-chain AUD FX, no round-up, no Pay in 4.
I wrote the submission. I filmed the demo and the pitch — Woolworths tap, AMZN not sold, Hertz 200 / 90. Testnet demo on screen for the whole phone section.
I submitted Athena Spend.
Judges can check cd contracts && forge test, contracts/README.md, contracts/CANONICAL.md, Robinhood AthenaSpend 0x89b5b4E7bd471b6e933D95a0384F50ec6DcD30C8, Sepolia twin 0x600cb2C1F802322461AeE2BE540621dD4B6f59EB.
I am self-funded. I pay for all of Athena’s expenses — Railway for the backend, Sentry for unexpected crashes, Alchemy for confirming transactions, and the rest of the stack.