Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tocsin - the exit radar for pons v2 on Robinhood Chain

the exit radar for pons v2 on Robinhood Chain local · open · read-only by default · no key required to use any of it


Everyone is building the thing that tells you when to get in.

Nobody is building the thing that tells you when to leave, because the entry is the part that feels like skill and the exit is the part that feels like luck. It isn't luck. Almost every position that goes to zero announces itself first, in the ledger, several minutes before it announces itself in the price — the creator moves the bag to three fresh wallets, the twenty-eight "holders" that share one funder start unwinding, the liquidity walks out while the candle stays flat, the tax quietly goes from 1% to 12%.

tocsin watches for that. It reads the wallets, not the chart. When something changes it rings, and it prints the sentence that made it ring.

A tocsin is the bell you ring when the town is on fire.

20 seconds of it running — left window is tocsin scan walking the chain, right window is tocsin watch on the positions you hold. Both panes are what the program printed; demo/render.py parses the same ANSI bytes your terminal gets and lays them on a grid. npm run record regenerates the whole clip from scratch.


What it actually does

It takes a token you hold, rebuilds its entire transfer history into a ledger, and asks about twenty questions of that ledger every few seconds:

it asks because
has the creator sold, and in what shape a drip, a split and a dump are three different futures
did the creator sell, or did the wallet the creator funded sell "dev still holds 100%" is technically true far more often than it is useful
how many of these holders are one person thirty wallets, one funder, one decision
is concentration rising right now someone is accumulating quietly, and it is not you
how much of this volume is round-trip four addresses passing a bag is not a market
are distinct buyers arriving or drying up the tape empties before the price does
how much liquidity is left, and whose is it 90% of the floor being one position owned by the creator is not a floor
what is this actually priced in some of these are quoted in NVDA and SPCX, not ETH
how big is your position against real depth past a certain size, you are the exit
did the tax change after you were already in it does, and nothing tells you

Then it adds those up into one number from 0 to 100, rings one of four bells, and prints every point that moved the number.

13:52:41 EXIT  $GOLDCARD    danger  98 · 6 wallets funded by the creator sold 13.55% of supply
13:52:41 Gold Card $GOLDCARD 0x62f2a1…04e3ba  ALARM   98
  creator 0x7a91…4c2f  holds 4.1% (4.10M GOLDCARD)  sold 0%  tax 1.0%  fees → third party
  top10 61.2% +5.3pp  holders 218 -14  2 clusters 23.4%
  flow 0.31  buyers 3/10m -19  sellers 41  round-trip 12%
  book ██░░░░░░░░░░░░░░░░░░  6.20 ETH to −30%  fdv 88.40 ETH  liq -41% /15m  quote ETH
  +30 6 wallets funded by the creator sold 13.55% of supply (0x9cd6…486b)
  +26 41% of pool liquidity pulled in 15m · +23 2 clusters hold 23.42% — largest is 19 wallets, same funder 0xbab4…
  +20 buy/sell pressure flipped 2.14 → 0.31 in 10m · +12 fees route to a third party — builder / KOL deal pattern
  -10 creator has not moved a token in 3h9m

The last line is the point. Every number tocsin shows you can be argued with, because tocsin shows you which sentence produced it.


Sixty seconds

git clone https://github.com/SpikeCalls/tocsin
cd tocsin
npm install

npm run demo            # a generated chain, scored by the real engine. no RPC, no keys.
node bin/tocsin.js rules      # every rule, its id, what it looks at
node bin/tocsin.js replay farm    # score one known shape and show the work

demo is not a video and not a mock-up. It generates transfer logs, funder maps and liquidity samples, and then feeds them to the same ledger, the same clustering, the same rules and the same renderer the live command uses. Every score in it was computed. That is also why the demo doubles as the test fixture — see test/engine.test.js.

Then, when you want it pointed at the real chain:

cp .env.example .env    # fill in RPC + the four addresses
node bin/tocsin.js doctor
node bin/tocsin.js add 0xYourToken --size 41000000
node bin/tocsin.js watch

Install

clone it — the way I would do it, because you should read src/score/rules.js before you trust any of this:

git clone https://github.com/SpikeCalls/tocsin && cd tocsin && npm install

or globally, if you already read it:

npm install -g github:SpikeCalls/tocsin
tocsin demo

Requirements: Node ≥ 20. Three dependencies: viem, commander, ws. No build step, no bundler, no telemetry, no account. Nothing leaves your machine except JSON-RPC to the endpoint you put in .env.


Addresses

.env.example ships with PONS_FACTORY, PONS_ROUTER, V4_POOL_MANAGER and V4_STATE_VIEW empty, and that is deliberate.

I am not going to hardcode a protocol address you did not verify and then have you point a sell router at it because a README told you to. Get them from the protocol's own docs or from a launch transaction in the explorer, put them in .env, and then run:

node bin/tocsin.js doctor

which checks the endpoint answers, that each address actually has code, and that the ABI in src/chain/abi.js matches what is deployed. If doctor is unhappy, everything downstream of it is fiction.

Everything except live reads works with none of this set. demo, replay, rules and the whole test suite run on a fresh clone.


Commands

command what it does
tocsin watch score every position you hold, forever, and ring when one turns
tocsin scan rank every graduated token on the chain by how badly it wants you gone
tocsin dossier <token> everything it knows about one token, printed long, including every cluster and every rule that fired
tocsin guard watch, and act. dry run unless you pass --live, which asks again in words
tocsin board the same data in a browser, served from 127.0.0.1 only
tocsin demo the generated chain, scored by the real engine
tocsin replay <shape> clean drip split farm drain wash taxraise — score a known shape and show the work
tocsin rules every rule, its id, and what it looks at
tocsin doctor check the endpoint, the addresses, and the ABI
tocsin add / rm / ls the watchlist, which is a flat JSON file you can edit by hand

watch

The narrow column is the one you leave open. It prints one line per position per pass and most of those lines say hold, which is the job — a radar that alarms on everything is a radar you learn to ignore. Anything above calm also gets a full card in the wide window.

Four bells:

bell score what it means
CALM 0–24 nothing in the ledger is asking you to leave
STIR 25–49 one thing changed. worth knowing, not worth acting on
TOLL 50–74 trim. more than one thing is pointing the same way
ALARM 75–100 the shape of an exit is fully formed

guard

The only part of this program that can spend anything, and it is built to be hard to use by accident. Five gates, all of which must open:

  1. --live on the command line. Never from .env, never a default.
  2. PRIVATE_KEY exists and derives the address that holds the position.
  3. The bell is at or above GUARD_MIN_LEVEL (default alarm).
  4. The tranche fits inside GUARD_MAX_DEPTH_FRACTION of real measured book depth — default 8%. If it doesn't fit it is trimmed, and the trim is printed, not hidden.
  5. The session budget has not been spent.

Dry run is not a mode you opt into. It is the mode you have to opt out of, in writing, by typing a word into a prompt. And the dry run exercises the same code path the live run does, which is the entire reason to have one.

Live sending is intentionally not wired to a router in this build. src/guard/sell.js is where you point it at yours, and that is a decision you should make with your eyes open rather than inherit from a stranger's default.


How it works

                 ┌──────────────────────────────────────────┐
   JSON-RPC ───► │ src/chain/client.js                       │  chunked getLogs,
                 │   polite queue, backoff, gap tracking     │  multicall, no
                 └───────────────────┬──────────────────────┘  silent truncation
                                     ▼
                 ┌──────────────────────────────────────────┐
                 │ src/read/live.js  →  snapshot             │  ← src/demo/world.js
                 └───────────────────┬──────────────────────┘     produces the
                                     ▼                             identical shape
                 ┌──────────────────────────────────────────┐
                 │ src/read/ledger.js                        │  balances, first-seen,
                 │   buildLedger()                           │  per-wallet in/out,
                 └───────────────────┬──────────────────────┘  buy/sell events
                                     ▼
        ┌────────────┬───────────────┼───────────────┬──────────────┐
        ▼            ▼               ▼               ▼              ▼
   clusters.js   creator.js      flow.js       liquidity.js     fees.js
   union-find    shape + hop   wash + tape     depth + LP     route + change
        └────────────┴───────────────┼───────────────┴──────────────┘
                                     ▼
                 ┌──────────────────────────────────────────┐
                 │ src/score/rules.js  →  engine.js          │  points + a sentence
                 └───────────────────┬──────────────────────┘  per rule
                                     ▼
                 ┌──────────────────────────────────────────┐
                 │ src/view.js  →  one shape                 │
                 └───┬───────────┬────────────┬─────────────┘
                     ▼           ▼            ▼
                 terminal     board      guard plan

There is one place that opens a socket, one place that folds transfers into balances, one place that decides what is dangerous, and one shape that every surface renders. The terminal, the browser dashboard and the sell plan all read the same object; there is no second version of the truth that only the dashboard sees.

Two design decisions worth defending:

The score has no memory of price. Not one rule reads a candle. This is not purity, it is that price is the last thing to know and I wanted the earliest thing.

The demo is the fixture. src/demo/world.js fakes the chain, not the output. If I had faked the output, the screenshots would look great and the code would be untested, which is the normal arrangement and the reason most of these tools do not survive contact with a real launch.


Tests

npm test

30 tests, no network, no mocking framework, run in about half a second. They cover the parts where being wrong is expensive:

  • the ledger, including the bug where a mint counted as a sell by the zero address
  • clustering, including the case where a dust transfer must not merge two people
  • flow, including a ring that round-trips one bag and a window with nothing in it
  • the engine's determinism, and its behaviour when a rule is handed a missing field
  • all five of guard's gates, including the depth cap and the session budget

What it misses

LIMITATIONS.md — read it before you rely on any of this.

Short version: funder attribution is a proxy and can be fooled by a CEX withdrawal; timestamps between two anchor blocks are interpolated; a public RPC that truncates a log range makes a score partial and tocsin says partial but cannot conjure the missing data; a creator who never touches the token again and instead sells the LP position looks quiet to the creator rules; nothing here sees the mempool, so a sell that lands in the same block as the alarm is a sell you did not beat; and a token can be perfectly clean by every rule in this repo and still go to zero because nobody wanted it.

A tool that hides its blind spots is the one that costs you money.


FAQ

Does it need my private key? No. Every read command works with an address or nothing at all. Only guard --live touches a key, and it will not arm without you typing a word into a prompt.

Does anything leave my machine? JSON-RPC to the endpoint in your .env. That is the entire outbound surface. board binds to 127.0.0.1, not your LAN.

Can I run it on a token I don't hold? Yes — tocsin dossier <token>. The depth rule is the only one that needs a position size, and it just stays quiet.

Will it front-run the rug? Sometimes, and you should assume not. It sees what is confirmed on chain. It does not see the mempool and it will not race anybody. What it reliably does is catch the setup: the split, the farm unwinding, the liquidity walking out — which usually happens minutes to hours before the last candle, not milliseconds.

Why is it so opinionated about units? Because "$4.2M FDV" on a book quoted in a thin equity token is a sentence that has cost people real money. Every figure here carries the asset it was measured in.


Contributing

Rules are the interesting surface. A rule is thirty lines in src/score/rules.js, it takes a context and returns points plus a sentence, and it needs a test in test/engine.test.js that drives it from a shape in src/demo/world.js. If you have a pattern you have watched cost you money, that is exactly the thing worth adding.

Please do not send a PR that adds a price feed to the scoring path.


The owl

demo/avatar.py draws it. Rectangles on a 29x29 board, no anti-aliasing, no gradients, no vector file to lose — which is also why it survives being scaled down to a 40px avatar. Three other drafts are in docs/ if you prefer a bell, a watchdog or a goose.

python3 demo/avatar.py  --out docs/ --only owl   # the mascot
python3 demo/profile.py --out docs/              # the banner and the bell strip

Two enormous eyes and nothing else worth mentioning, which is a fair description of what this program does all day.


MIT. It runs on your machine, not mine.

About

The exit radar for pons v2 on Robinhood Chain. Reads the wallet, not the chart. Local, open, read-only by default.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages