Chameleon
Start
OverviewHow it worksQuickstart
Concepts
ConceptsPrivacy model
Reference
The routerJavaScript engineContracts and addresses
Practice
Real examplesSelling and exitingSecurity and limitsFAQChangelog
Robinhood Chain · 4663

Real examples

Everything on this page was produced by running the code against a fork of the real Robinhood Chain: the real Pons curve, the real ERC-5564 announcer. The router in these runs was deployed on the local fork, so its address is local.

A buy straight into an arbitrary recipient

First check, before any router existed: does a Pons curve accept an arbitrary address as recipient? A live curve (symbol Sama) was bought with 0.1 ETH, recipient set to a fresh address.

before: token balance  buyer = 0   recipient = 0
cast send curve "buy(uint256,uint256,address)" 100000000000000000 0 <recipient> --value 0.1ether
status   1 (success)    gasUsed 100483
after:  token balance  buyer = 0   recipient = 49,788,193 tokens

The buyer ended with nothing and the recipient with the tokens. The CurveBuy event carries both addresses, which is why a router is needed: it makes itself the buyer.

The full round trip

tests-js/e2e-fork.mjs runs the whole flow with the JavaScript engine and the real contracts:

router deployed at 0xAA2a95A342b774512c64799597bD75389e7d3C7a        (local fork)
curve token 0x40D8c0f07fDd072F3D8aa6BE22697485bf69E597 "Sama"
stealth address 0xDDCc272db9E79D6689CE238b0Fc3399BC8086313  view tag 0x23
router.buy gas used 162095
scanned 1 announcement(s), found 1
announced amount 49725381927208932739397713 == on-chain balance
proceeds received 0.09604 ETH; gas dust left on stealth 0.000018157336455218 ETH

END-TO-END OK

What each line shows:

  1. The router was deployed from the real source file.
  2. The receiver derived keys, the sender derived the one-time address with the engine.
  3. The router bought 0.1 ETH worth into it for about 162,000 gas.
  4. The scanner read the real announcements, found exactly the one that is ours, and confirmed the announced amount equals the real on-chain balance.
  5. The stealth address, using only the gas dust it was sent, approved and sold everything. The proceeds went to a brand new address. About 0.0000019 ETH of the dust was spent on gas and the rest remained.

The contract tests

[PASS] test_tokensLandOnStealthNotOnCaller()
[PASS] test_gasDustReachesStealthAndRouterKeepsNothing()
[PASS] test_announcementMatchesErc5564Layout()
[PASS] test_curveSeesTheRouterAsBuyerNeverTheUser()
[PASS] test_stealthCanSellOnItsOwnUsingTheDust()
[PASS] test_revertsBelowMinimum()
[PASS] test_revertsOnBadEphemeralKey()
[PASS] test_revertsOnZeroStealth()
[PASS] test_revertsWhenDustSwallowsEverything()
[PASS] test_manyBuysManyStealthAddressesRouterStaysEmpty()
[PASS] test_gasUsedForOneBuy()        router.buy gas: 188550
11 passed; 0 failed

The engine against independent code

ok  a stealth address is found by its owner and the derived key controls it
ok  the derived stealth private key gives the same address in cast
ok  the checksum encoder agrees with cast
ok  somebody else cannot find or spend the address
ok  two buys to the same meta-address share nothing on chain
ok  view tags let the scanner skip about 255 out of 256 foreign announcements
ok  meta-address parsing rejects garbage and off-curve points
ok  announcement metadata follows the ERC-5564 token transfer layout
ok  router calldata is byte-for-byte what cast encodes
ok  announcement log decoding round-trips a real-shaped log
ok  the announcement event signature hash matches what cast computes
ok  skin colour is deterministic per address
12 passed

What a buy costs

About 190,000 gas through the router. At 0.02 gwei that is roughly 0.000004 ETH, plus the curve's own 1% fee and the gas dust you choose to send.