Pinned Tweet
Spent two weeks building a rug-pull detector on Solana. Not the "we flag suspicious
tokens" kind — one with a measured number next to every alert.
The signal: the creator adds liquidity to its own token. 97.9% of those ended in a
drain (422 of 431, 431 distinct wallets), median 8 minutes of warning before the
pool went to zero.
The part nobody publishes: it only catches 65.3% of pool rugs. The other 35% are dev
dumps and migration pulls, where the drain IS the event — there is nothing to warn
about beforehand. That's on the dashboard, not buried in a footnote.
I also killed four of my own hypotheses with data. ">10 launches in 24h" as a signal:
1.0% precision. Sell-share before the drain: inverted once I fixed the liquidity
metric. Both documented as discarded, with the numbers that killed them.
Calibrated against 17M frames from one full night of mainnet, over Solami's Blur
stream. TypeScript, 242 tests, docker compose up and it runs. Without an API key it
replays a real recorded hour through the same detector.
@useSolami
My property tests passed with 256 cases.
At 50,000, one failed. No sabotage.
The property said: if a swap works at a low price, it works at a higher one.
The counterexample: amount = 0. Price 1 → Ok(0). A huge price → MathOverflow.
In the reverse swap the price sits in the denominator. With 20+ decimals, price × 10^dec_b overflows u128 even when the real result fits.
The function wasn't unsafe: typed error, no panic, nothing leaves the pool. My property was false.
So I kept the half that's true, and documented the limit instead of reworking the math for 20+ decimal mints nobody uses.
🔑 proptest's default case count looks like a performance setting. It's a correctness setting.
xitter.cf/Ale_Beta/status/211002…
Repo: github.com/alebeta06/solana-…
New project: my first Solana program, coming from Solidity. A fixed-price SPL token swap in Rust + Anchor, deployed on devnet, with a Next.js frontend.
Anyone can create a market for two tokens and set its price. Anyone can add liquidity, and users swap in both directions at that price.
Stack: Rust + Anchor 1.2 for the program. Next.js, TypeScript and wallet adapter on the frontend. Devnet test tokens with Metaplex metadata and a public faucet that pays for your token accounts, so you can try it without asking anyone.
Inside, it made me deal with:
- Thinking in accounts instead of storage: PDA vaults and a canonical mint order, so one pair can't end up as two markets
- Not trusting the caller: token decimals are read from the Mint account, not passed as a parameter
- Property-based tests over the swap math: 500,000 generated cases found a panic that 27 integration tests missed
- A CI I sabotaged on purpose to check it can actually fail
5 instructions, 9 typed errors, 133 tests across three suites, and known limitations written down in the README. Educational code, not audited.
Try it on devnet (you'll need a little devnet SOL to swap), read the code, and tell me what you'd do differently:
Demo: solana-token-swap.vercel.app
Code: github.com/alebeta06/solana-…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#Solana #rustlang
Alejandro Betancourt retweeted
I fixed a vulnerability in my Solana swap and opened a panic. A property-based test found it, not me.
The fix first. The reference code took token decimals as an instruction parameter, even though the Mint accounts were right there. Declare decimals_a = 0 on a 9-decimal mint and the math is wrong forever, because the value is stored when the market is created. Two lines fixed it: read the decimals from the Mint.
What that fix opened: the caller can no longer lie about decimals, but the program now accepts whatever the Mint says. And an SPL mint can have any u8, from 0 to 255.
10^38 fits in a u128. 10^39 doesn't. The code did 10u128.pow(decimals) unchecked, so with a mint of 39+ decimals every swap panicked instead of returning the MathOverflow error the program already had for exactly that case.
27 integration tests never saw it. They all use 6 and 9 decimals, the range real tokens live in, which is the range anyone tests by hand.
The property tests sample decimals across the full 0..255. Capping them at 38 would have been a test designed to pass. proptest shrank the failure to the smallest case that still broke: amount = 0, price = 1, dec_a = 0, dec_b = 39.
The fix is a pow10() that uses checked_pow and returns the typed error. Side effect I didn't expect: the program binary shrank by 1,984 bytes.
How the tests were made: Claude Code wrote them. I chose the four properties the math had to obey and checked each one by breaking the code on purpose until it went red.
What I take from it: moving trust from the caller to the Mint doesn't remove the input. It widens it. Validating where a value comes from means validating its range too.
xitter.cf/Ale_Beta/status/211002…
New project: my first Solana program, coming from Solidity. A fixed-price SPL token swap in Rust + Anchor, deployed on devnet, with a Next.js frontend.
Anyone can create a market for two tokens and set its price. Anyone can add liquidity, and users swap in both directions at that price.
Stack: Rust + Anchor 1.2 for the program. Next.js, TypeScript and wallet adapter on the frontend. Devnet test tokens with Metaplex metadata and a public faucet that pays for your token accounts, so you can try it without asking anyone.
Inside, it made me deal with:
- Thinking in accounts instead of storage: PDA vaults and a canonical mint order, so one pair can't end up as two markets
- Not trusting the caller: token decimals are read from the Mint account, not passed as a parameter
- Property-based tests over the swap math: 500,000 generated cases found a panic that 27 integration tests missed
- A CI I sabotaged on purpose to check it can actually fail
5 instructions, 9 typed errors, 133 tests across three suites, and known limitations written down in the README. Educational code, not audited.
Try it on devnet (you'll need a little devnet SOL to swap), read the code, and tell me what you'd do differently:
Demo: solana-token-swap.vercel.app
Code: github.com/alebeta06/solana-…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#Solana #rustlang
Alejandro Betancourt retweeted
I sabotaged my CI and it stayed green.
That was the correct result.
Same type error, two runs:
❌ without `yarn typecheck` → green
✅ with it → red, tests never ran
Vitest doesn't check types. It strips them and runs the JavaScript.
So typecheck is its own step, before the tests.
🔑 A green check means nothing until you've seen it go red.
Repo: github.com/alebeta06/solana-…
xitter.cf/Ale_Beta/status/211002…
New project: my first Solana program, coming from Solidity. A fixed-price SPL token swap in Rust + Anchor, deployed on devnet, with a Next.js frontend.
Anyone can create a market for two tokens and set its price. Anyone can add liquidity, and users swap in both directions at that price.
Stack: Rust + Anchor 1.2 for the program. Next.js, TypeScript and wallet adapter on the frontend. Devnet test tokens with Metaplex metadata and a public faucet that pays for your token accounts, so you can try it without asking anyone.
Inside, it made me deal with:
- Thinking in accounts instead of storage: PDA vaults and a canonical mint order, so one pair can't end up as two markets
- Not trusting the caller: token decimals are read from the Mint account, not passed as a parameter
- Property-based tests over the swap math: 500,000 generated cases found a panic that 27 integration tests missed
- A CI I sabotaged on purpose to check it can actually fail
5 instructions, 9 typed errors, 133 tests across three suites, and known limitations written down in the README. Educational code, not audited.
Try it on devnet (you'll need a little devnet SOL to swap), read the code, and tell me what you'd do differently:
Demo: solana-token-swap.vercel.app
Code: github.com/alebeta06/solana-…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#Solana #rustlang
Alejandro Betancourt retweeted
Spent two weeks building a rug-pull detector on Solana. Not the "we flag suspicious
tokens" kind — one with a measured number next to every alert.
The signal: the creator adds liquidity to its own token. 97.9% of those ended in a
drain (422 of 431, 431 distinct wallets), median 8 minutes of warning before the
pool went to zero.
The part nobody publishes: it only catches 65.3% of pool rugs. The other 35% are dev
dumps and migration pulls, where the drain IS the event — there is nothing to warn
about beforehand. That's on the dashboard, not buried in a footnote.
I also killed four of my own hypotheses with data. ">10 launches in 24h" as a signal:
1.0% precision. Sell-share before the drain: inverted once I fixed the liquidity
metric. Both documented as discarded, with the numbers that killed them.
Calibrated against 17M frames from one full night of mainnet, over Solami's Blur
stream. TypeScript, 242 tests, docker compose up and it runs. Without an API key it
replays a real recorded hour through the same detector.
@useSolami
I sabotaged my CI and it stayed green.
That was the correct result.
Same type error, two runs:
❌ without `yarn typecheck` → green
✅ with it → red, tests never ran
Vitest doesn't check types. It strips them and runs the JavaScript.
So typecheck is its own step, before the tests.
🔑 A green check means nothing until you've seen it go red.
Repo: github.com/alebeta06/solana-…
xitter.cf/Ale_Beta/status/211002…
New project: my first Solana program, coming from Solidity. A fixed-price SPL token swap in Rust + Anchor, deployed on devnet, with a Next.js frontend.
Anyone can create a market for two tokens and set its price. Anyone can add liquidity, and users swap in both directions at that price.
Stack: Rust + Anchor 1.2 for the program. Next.js, TypeScript and wallet adapter on the frontend. Devnet test tokens with Metaplex metadata and a public faucet that pays for your token accounts, so you can try it without asking anyone.
Inside, it made me deal with:
- Thinking in accounts instead of storage: PDA vaults and a canonical mint order, so one pair can't end up as two markets
- Not trusting the caller: token decimals are read from the Mint account, not passed as a parameter
- Property-based tests over the swap math: 500,000 generated cases found a panic that 27 integration tests missed
- A CI I sabotaged on purpose to check it can actually fail
5 instructions, 9 typed errors, 133 tests across three suites, and known limitations written down in the README. Educational code, not audited.
Try it on devnet (you'll need a little devnet SOL to swap), read the code, and tell me what you'd do differently:
Demo: solana-token-swap.vercel.app
Code: github.com/alebeta06/solana-…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#Solana #rustlang
I fixed a vulnerability in my Solana swap and opened a panic. A property-based test found it, not me.
The fix first. The reference code took token decimals as an instruction parameter, even though the Mint accounts were right there. Declare decimals_a = 0 on a 9-decimal mint and the math is wrong forever, because the value is stored when the market is created. Two lines fixed it: read the decimals from the Mint.
What that fix opened: the caller can no longer lie about decimals, but the program now accepts whatever the Mint says. And an SPL mint can have any u8, from 0 to 255.
10^38 fits in a u128. 10^39 doesn't. The code did 10u128.pow(decimals) unchecked, so with a mint of 39+ decimals every swap panicked instead of returning the MathOverflow error the program already had for exactly that case.
27 integration tests never saw it. They all use 6 and 9 decimals, the range real tokens live in, which is the range anyone tests by hand.
The property tests sample decimals across the full 0..255. Capping them at 38 would have been a test designed to pass. proptest shrank the failure to the smallest case that still broke: amount = 0, price = 1, dec_a = 0, dec_b = 39.
The fix is a pow10() that uses checked_pow and returns the typed error. Side effect I didn't expect: the program binary shrank by 1,984 bytes.
How the tests were made: Claude Code wrote them. I chose the four properties the math had to obey and checked each one by breaking the code on purpose until it went red.
What I take from it: moving trust from the caller to the Mint doesn't remove the input. It widens it. Validating where a value comes from means validating its range too.
xitter.cf/Ale_Beta/status/211002…
New project: my first Solana program, coming from Solidity. A fixed-price SPL token swap in Rust + Anchor, deployed on devnet, with a Next.js frontend.
Anyone can create a market for two tokens and set its price. Anyone can add liquidity, and users swap in both directions at that price.
Stack: Rust + Anchor 1.2 for the program. Next.js, TypeScript and wallet adapter on the frontend. Devnet test tokens with Metaplex metadata and a public faucet that pays for your token accounts, so you can try it without asking anyone.
Inside, it made me deal with:
- Thinking in accounts instead of storage: PDA vaults and a canonical mint order, so one pair can't end up as two markets
- Not trusting the caller: token decimals are read from the Mint account, not passed as a parameter
- Property-based tests over the swap math: 500,000 generated cases found a panic that 27 integration tests missed
- A CI I sabotaged on purpose to check it can actually fail
5 instructions, 9 typed errors, 133 tests across three suites, and known limitations written down in the README. Educational code, not audited.
Try it on devnet (you'll need a little devnet SOL to swap), read the code, and tell me what you'd do differently:
Demo: solana-token-swap.vercel.app
Code: github.com/alebeta06/solana-…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#Solana #rustlang
New project: my first Solana program, coming from Solidity. A fixed-price SPL token swap in Rust + Anchor, deployed on devnet, with a Next.js frontend.
Anyone can create a market for two tokens and set its price. Anyone can add liquidity, and users swap in both directions at that price.
Stack: Rust + Anchor 1.2 for the program. Next.js, TypeScript and wallet adapter on the frontend. Devnet test tokens with Metaplex metadata and a public faucet that pays for your token accounts, so you can try it without asking anyone.
Inside, it made me deal with:
- Thinking in accounts instead of storage: PDA vaults and a canonical mint order, so one pair can't end up as two markets
- Not trusting the caller: token decimals are read from the Mint account, not passed as a parameter
- Property-based tests over the swap math: 500,000 generated cases found a panic that 27 integration tests missed
- A CI I sabotaged on purpose to check it can actually fail
5 instructions, 9 typed errors, 133 tests across three suites, and known limitations written down in the README. Educational code, not audited.
Try it on devnet (you'll need a little devnet SOL to swap), read the code, and tell me what you'd do differently:
Demo: solana-token-swap.vercel.app
Code: github.com/alebeta06/solana-…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#Solana #rustlang
Alejandro Betancourt retweeted
New project: Northwind Customer Management. A REST API in Rust with a Next.js admin panel on top.
Full CRUD over the classic Northwind database (93 customers, 16,282 orders): filter, sort, create, edit and delete customers.
Stack: Rust + Rocket, rusqlite (SQLite) and Docker on the backend. Next.js 15, TypeScript, Tailwind and shadcn/ui on the frontend. Backend on Render, frontend on Vercel.
A CRUD looks boring from the outside. Inside, it made me deal with:
- Concurrency: rusqlite's Connection isn't Sync, so Rocket won't even compile until it's behind a Mutex
- Referential integrity: deleting a customer with orders returns a 409, shown as a business rule, not as an error
- SQLite traps that only show up when you actually run things
- A free-tier backend that goes to sleep, handled in the UI with retries instead of a red error
15 tests, clippy clean with -D warnings, and a README that explains why each decision was made.
Try it, read the code, and tell me what you'd do differently:
Demo: northwind-fullstack.vercel.a…
(the first load can take up to a minute while the backend wakes up)
Code: github.com/alebeta06/northwi…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#rustlang
Someone in my replies read my code and found a bug I had documented as a design decision.
My Northwind demo runs its backend on Render's free tier, which sleeps after 15 minutes idle. The frontend handles that: retries plus a "server is waking up" notice.
But only until the server had answered once:
const coldStartPossible = !answeredOnce.current;
The comment above it explained why: once it answers, it's awake. True, until it falls asleep again with the tab still open.
Before touching anything, I measured it. Tab open for 20 minutes, Render logged the shutdown, then I sorted a column: 12.3 s of loading, then a 200, and no notice. Not the red error I expected from reading the code. Render holds the request while it boots.
The fix tracks when the server last answered, not whether it ever did. Any load after 10 minutes of silence gets the notice and the retries back. Verified on the live deploy: notice at 3 s, then data.
What I take from it: the comment wasn't wrong when I wrote it. The assumption under it stopped being true. The README made the same promise, so that changed too.
xitter.cf/Ale_Beta/status/210567…
New project: Northwind Customer Management. A REST API in Rust with a Next.js admin panel on top.
Full CRUD over the classic Northwind database (93 customers, 16,282 orders): filter, sort, create, edit and delete customers.
Stack: Rust + Rocket, rusqlite (SQLite) and Docker on the backend. Next.js 15, TypeScript, Tailwind and shadcn/ui on the frontend. Backend on Render, frontend on Vercel.
A CRUD looks boring from the outside. Inside, it made me deal with:
- Concurrency: rusqlite's Connection isn't Sync, so Rocket won't even compile until it's behind a Mutex
- Referential integrity: deleting a customer with orders returns a 409, shown as a business rule, not as an error
- SQLite traps that only show up when you actually run things
- A free-tier backend that goes to sleep, handled in the UI with retries instead of a red error
15 tests, clippy clean with -D warnings, and a README that explains why each decision was made.
Try it, read the code, and tell me what you'd do differently:
Demo: northwind-fullstack.vercel.a…
(the first load can take up to a minute while the backend wakes up)
Code: github.com/alebeta06/northwi…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#rustlang
New project: Northwind Customer Management. A REST API in Rust with a Next.js admin panel on top.
Full CRUD over the classic Northwind database (93 customers, 16,282 orders): filter, sort, create, edit and delete customers.
Stack: Rust + Rocket, rusqlite (SQLite) and Docker on the backend. Next.js 15, TypeScript, Tailwind and shadcn/ui on the frontend. Backend on Render, frontend on Vercel.
A CRUD looks boring from the outside. Inside, it made me deal with:
- Concurrency: rusqlite's Connection isn't Sync, so Rocket won't even compile until it's behind a Mutex
- Referential integrity: deleting a customer with orders returns a 409, shown as a business rule, not as an error
- SQLite traps that only show up when you actually run things
- A free-tier backend that goes to sleep, handled in the UI with retries instead of a red error
15 tests, clippy clean with -D warnings, and a README that explains why each decision was made.
Try it, read the code, and tell me what you'd do differently:
Demo: northwind-fullstack.vercel.a…
(the first load can take up to a minute while the backend wakes up)
Code: github.com/alebeta06/northwi…
Audio note: I recorded the video in Spanish. The English you hear is YouTube's auto-dubbed track, not my voice.
#rustlang
I don't write most of my code by hand. Claude Code does, and I approve it.
The part nobody talks about: six times in one project, the agent read the code and told me my own instruction was wrong 🧵
What this is not: the agent being smarter than me.
It's that it reads the current code and I work from a memory of the code. Those drift apart every single day, and I'm the one who can't tell.
So the workflow isn't "it writes, I approve".
It's: I decide what has to be true, it reports what is true, and the gap between those two is where the actual work happens.
Full project, 933 unit tests and 22 e2e:
github.com/alebeta06/chrome-…






