Kieran Crown
Blog

How I built a crypto perps trader in a morning with Claude

A recruiter said I lacked hands-on crypto experience. By lunch I had an iPhone app placing signed orders on the Hyperliquid testnet. What Claude did, what I did, and what I would change.

6 min read
React NativeSkiaWeb3ClaudePip
Three screens from Pip: the trade screen, a 20x risk warning, and an open position

On Thursday a recruiter passed on me for a founding mobile engineer role at a crypto trading startup. The note was polite and specific: the React Native and startup background was strong, but the client wanted someone who had worked on a wallet, brokerage or trading product. No hands-on Web3.

That is a fair reading of my CV. It is also a gap you can close in a morning if you already know how to build the hard part, which is a real-time, money-moving mobile app. So I built one. It is called Pip, it trades perpetuals on the Hyperliquid testnet, and the repo went public at four o’clock.

Trade screen and the fill state
Left: the trade screen, with the custom Skia chart and the pet docked above the confirm button. Right: the fill, read back by Pip.

What it does

Sign in with an email code. Privy creates an embedded wallet behind that, so there is no seed phrase anywhere in the UI. Approve a trading key once, then place market or limit orders on BTC, ETH or SOL perps and they are signed on the phone with no wallet prompt. There is a live order book, a candlestick chart with a crosshair, positions with margin health, and a small pixel creature called Pip who reads your order back to you before you confirm, acknowledges the fill, and turns amber when you set 15× and tells you what move would liquidate you.

There is also a paper mode, because the Hyperliquid testnet faucet only pays out to wallets that have deposited on mainnet. A demo that only works for the author is not a demo, so anyone can install it and trade simulated fills against live testnet prices.

How the morning went

I used Claude Code for nearly all the typing. The split of work was roughly what it has been on my last three projects: I decide, it types, I review.

The first hour was reading, not writing. Before any app code existed we read the type definitions of the three libraries that mattered, Privy’s Expo SDK, viem, and a community Hyperliquid SDK, straight out of node_modules. That is the single habit that made the rest of the morning fast. Docs for these libraries are out of date within weeks, and the .d.ts files never are. The one API question I would have got wrong from memory, the shape of the wallet object the Hyperliquid client accepts, was answered by a forty-line interface.

Then the pet. I already had a design, made the night before in Claude Design, with the sprite as a small canvas-drawing function in the design file itself. Claude ported that function to TypeScript, packed all thirty-two frames into one texture at launch, and rendered it with a Skia Image using nearest-neighbour sampling. I checked the port by rendering the whole atlas to a PNG and looking at it. Pixel-perfect, first time, which I did not expect.

The chart is the part I cared about most, because it is the part a trading founder would judge. It is custom Skia. Forty candles become two paths, one green and one red, so a frame is two draw calls. The crosshair runs on the UI thread with Reanimated; its price label is formatted and measured in a worklet. React only hears about it when your finger crosses into a new candle, which is when the haptic fires and the OHLC row updates. This is the same architecture as the game engine in Overbloom, just with less state.

Then the wallet plumbing. Hyperliquid has no API keys. Every action is signed by a wallet. The trick the fast front ends use is an agent wallet: the main wallet signs one approveAgent action, and from then on a separate key signs orders. That key can trade and cancel but cannot withdraw. In Pip it is generated on the phone with viem, stored in the iOS keychain, and never leaves. The approval is EIP-712, signed through Privy’s provider wrapped in a viem wallet client, which turns out to be exactly the shape the Hyperliquid SDK wants.

Market menu and a 20x warning
Left: the market selector is the title, on Liquid Glass. Right: at 20x Pip turns amber and quotes the move that would liquidate you.

The bug that proved it worked

I could not fund the testnet wallet before lunch, so I tapped Approve with an empty one to see what would happen. Hyperliquid answered:

Must deposit before performing actions. User: 0x46ef…b843

That is the best error I got all day. The address is my Privy wallet. For the exchange to name it, it had to recover the signer from the signature, which means the embedded wallet signed the right EIP-712 domain, the SDK encoded the action correctly, and the whole chain from email login to a Hyperliquid server was intact. The only thing missing was money. I mapped that message to something friendlier and disabled Approve until the wallet is funded.

What Claude got wrong

Plenty, and all of it was findable.

The paper-trading ledger’s first version handled an opposite-side order by booking the PnL and then replacing the position with a full-size one in the other direction. A short against a long should reduce, not flip. I caught it by reading the function, not by running it. The fix moved the ledger into a pure module with no React or native imports, and six tests now pin the netting, averaging, flipping and fees.

The Account screen read the “trading key approved” flag once, on first render, before Privy had loaded the wallet, so it was always unticked. Same class of bug I have written myself a hundred times.

The first build crashed on launch. Nothing to do with the app: the Xcode 27 SDK refuses to start apps on the old window lifecycle and Expo’s template still uses it. I have a config plugin for that from my games; it now lives in this repo too and in a note so the next project starts with it.

Positions and account
Left: a position with its margin health; Pip only appears here when health drops under 60%. Right: the account, with the pet switchable off.

What I would change

Change: I would have designed the paper mode first, not as a fallback. It ended up being the thing that lets anyone use the app, and it is where the best tests live.

Change: I would have written the honest SETUP.md before the code, not after. Writing down the faucet’s mainnet-deposit gate and the known gaps in the live path made the scope clear, and a reviewer who finds a gap I have already documented reads it as judgement, not as a miss.

Change: I would not claim the fill until I have seen one. The signing path is verified against the exchange; an actual order filling is not, and the README says so. Overclaiming on a portfolio piece is worse than a known gap.

Was it worth a morning?

The recruiter was right that I had not shipped a trading product. What I had shipped was Apple Pay and Google Pay through certification at a payments company, a digital bank’s app as the only mobile engineer, and two GPU-heavy React Native games. The crypto-specific layer is signing, nonces, agent wallets and perps maths, and it is learnable in a morning when the mobile craft underneath is not.

The repo is github.com/kierancrown/pip. It runs with no keys at all.