All pages

Developer reference

Evidence

A transaction-by-transaction ledger of everything Trimmy has done on Flare Coston2, including the refusals that cost no gas.

Working with an agent? Every page here has a markdown twin, the whole site is one file at llms-full.txt, and trimmy-mcp lets it read live rules and compose a payment it cannot send.

Testnet. Trimmy runs on Flare Coston2. Nothing described here has run on Flare mainnet, and no page on this site describes real money.

Scope

Everything here is on Flare Coston2 (chain ID 114). Nothing has run on Flare mainnet. Each figure is recorded in docs/GROUND-TRUTH.md with the command that produced it. Hashes ending in are truncated there; the full 32 bytes are unrecorded.

The XRPL armed path

One XRPL payment. No EVM wallet, no FLR held. Deployment Trimmy 0x19F81AAB43f7a26B0659754b70179aDcAF43ef7C, 2026-08-09.

Step Evidence Proves
Payment built memo FE0000000000000186A0EBBE0E…, 42 bytes, executorFeeUBA = 100000 the 0xFE Smart Accounts branch
Decoded offline decode.dart re-derived the commitment from the pre-image the producer is not trusted
XRPL payment 384FE782BE520662EA579AB67A2232DE5BD650A8A0E2ACB75C2B8C80514B778A, tesSUCCESS, ledger 19771685 the only signature
FDC attestation round 1420803, proof after 8 polls provable on Flare
Smart Accounts executeDirectMintingWithData, tx 0xd504f3f3…, 747,096 gas mint plus batch, one call
Rule armed rule 1, account = 0x07a76b5c… derived from the XRPL address, not the gas payer
Keeper execution tx 0xd88f7cac…, 476,842 gas, sender 0xF0533D37… not the user, not the deployer
Fee split keeper vault shares 65,800 → 75,200 the 9,400 keeperFeeFlat, in balances not events

An earlier run put keeper and user on one address: the split showed only in the event log.

The same path ran on 2026-08-07 on an earlier deployment, untruncated: XRPL E41504D3356C15789D4B6602F0F2E8B151F04FFAA5BBF2E3F71640C92B59B6E0 (ledger 19698983), FDC 0x0a3f05f72f9425f93ff64290d862ffc6498e82e0dfb7a6f7e57448ea035a82d9 (round 1418293), execution 0x86d54bd6821b7598cde03d68f0e1642da1b4714a52e91e445396095bc12cf6cc (742,307 gas), keeper 0xa74e9fc270bef95449e5821c0403c26b28c00b095d0e7b7a25bc2496e18a37b1. The allowance it set was 1,009,400: exact, never unlimited.

The public executor never acted. Two arming payments, both tesSUCCESS, both watched 600 s: C122663D…326104 at executorFeeUBA = 0, and E41504D3…59B6E0 at executorFeeUBA = 100,000. Neither was picked up: a full fee was offered and the 0xFE branch still ignored, so we run our own executor.

Execution against a vault that is not ours

TESTearnXRP 0x9E63a5D282F2fBb7DcE822B98e363b2719D28319, a third-party vault, share price 1.05917. Trimmy 0xf73a2af0…, 2026-08-07, the M-1 vulnerable build (see provenance).

Step Tx
approve, exact size 0x7b88ac308da099e52874f8f4b1cc26ebf9df6c11b6b140bb12dfab878bed4a81
arm 0x6d791f9e02e74f7a65e843dcb155b6f27a9aa374b5e74681ed4f4b32d9ed68f0
execute, permissionless 0xf682b1ae694c0d0a7996acc64f8d9cc06cc095155bd5333a53370881001ec11a

FXRP 23.150001 → 22.150001. Vault shares 0 → 944,133, exactly previewDeposit(1 FXRP), credited to rule.account and not the caller.

A separate keeper 0xF0533D37F7ed8d1C45A87Bb35750DA4665bd6D9E, funded with gas and given no authority, executed rule 2 in 0x50ef27fd67464424b23687b740df65d2aa7d729d8b3df16deb314173f244a720: user shares 1,888,266 → 2,822,999, keeper shares 0 → 9,400. PersonalAccount.executeUserOp is onlyController: selector 0x2b2ee783 reverts OnlyController() 0x59907813 for anyone else, so a leaked keeper key drives nothing.

The live swaps

Pool 0xafcA1C5DfF08b3B8Bacb7721fb8189d2D8E7C3DB, FXRP/WC2FLR, fee tier 3000. It is ours and it is thin: 0.305637 FXRP and 49.999999996 WC2FLR at L = 155,310,565,707,002. Coston2 had no FXRP pool beforehand (80 getPool calls, 5 factories x 4 counter-tokens x 4 fee tiers, all address(0)).

# Sells Outcome
1 0.01 FXRP executed, tx 0x7edff76c…, received 1.702666 WC2FLR, 38 bips
2 0.05 FXRP refused, Too little received, no gas
3 0.05 FXRP refused after liquidity was raised 2.66x, no gas
4 0.05 FXRP executed, tx 0xc0e9dd88…, received 8.536698 WC2FLR, 5.6 bips

Row 1's oracle fair value was 0.01 x 170.9222 = 1.709222 WC2FLR. The model predicted 38.4 bips beforehand; the chain returned 38. The tick moved 327738 → 327721 and the pool's FXRP balance rose 305,637 → 315,637, exactly the sale.

The three refusals

The refused rows are the best evidence here.

They cost nothing. Each died in the keeper's eth_call pre-simulation, so the keeper signed none of them. A rule that cannot execute costs an RPC round trip.

They refuted our own first diagnosis. We assumed depth was binding, deepened the pool 2.66x from 1.553e14 to 4.126e14, and were refused again. Computing the floor exactly showed the pool at 170.6357 against an oracle of 171.2618: 36.6 bips below, from row 1's own impact plus an FTSO move. With the 30-bip pool fee on top, no trade size fit inside the declared 50 bips. Staleness was binding, not depth, and a testnet pool has no arbitrageurs. Re-centring by hand (tx 0x38b77fff…) restored the peg and the same rule filled at 170.734 against 170.83.

The ledger counts three refusals across rows 2 and 3, then one fill at 5.6 bips once the venue was priced honestly. A stale venue gives a refusal, never a bad fill.

The confidential path

Step Evidence
Arm rule 0 on 0x19F81AAB…, trigger = 3, triggerValue = 0
Commit commitmentOf(0) = 0xeca87739…
Provision enclave returned {"ruleId":0,"commitment":"0xeca87739…","stored":true}, recomputing the commitment itself
Request pendingAction(0,0) = 0xc2cf1bea…, price from FTSO, not the caller
Verdict {"ruleId":0,"fire":true,"commitment":"0xeca87739…","nonce":0,"issuedAt":1786297877}, no threshold, no bounds
Accept tx 0x9a2af814…, status 1
Execute tx 0x233df51b…, spent = 1000000, keeper paid 9,400, rule closed

The threshold 1100000 appears nowhere on chain.

The enclave is a real GCP_AMD_SEV machine, 0xB33E5CF59e3ce1D58427B9F4E23d0444c128D3D7, not the simulated sentinel 0x194844cf417dde867073e5ab7199fa4d21fd82b5dbe2bdea8b3d7fc18d10fdc2 shared by 254 of Coston2's 268 active TEE machines. Only the first four bytes of its code hash are published (0xe9ab7410…). The full 32 bytes are not.

PRIVATE costs 517,962 gas against 383,451 for the plain path. The first attempt (0x486c9122…) ran out of gas after emitting Executed, so eth_estimateGas is unsafe here; the keeper sends an explicit limit.

Two free refusals against the fixed trigger, both cast call: a genuine enclave signature over a genuine fire verdict is rejected with NoEvaluationRequested(0, 7) (0xe6cf311f) because nobody asked it, and the caller-supplied-price entry point requestEvaluation(uint256,string,uint64) no longer exists. Regression: VerdictBinding.t.sol, 8 tests.

PRIVATE's trust model is strictly weaker than the other three triggers. It needs an enclave running, and its operator can censor a rule by declining to act. Not trustless.

Provenance

CREATE transactions and constructor arguments, from contracts/broadcast/.

Contract Address CREATE tx
Trimmy 0x19F81AAB43f7a26B0659754b70179aDcAF43ef7C 0x3a0c889aa9ba135f0cebc5d802eb01eb0b6e6e713980eb2b0f2caa12f3fc179a
TrimmyConfidentialTrigger 0x02EA709e2278EACDbA00D4A88caA604E3b35293b 0xb0f3ef76b8cd05bc793da39f45da25b945bc86987e074bb80969e563ec8bb782
Pool initialize(uint160) 0xafcA1C5DfF08b3B8Bacb7721fb8189d2D8E7C3DB 0xdc41179dbe8c05a9ef7efe35b32e136fbf3d253ce9f8c68a8b15101f37ff7119
tokens_  [(0x0b6A3645c240605887a5532109323A3E12273dc7,
           0x015852502f55534400000000000000000000000000, 6),   // FXRP, XRP/USD
          (0xC67DCE33D7A8efA5FfEB961899C73fe01bCe9273,
           0x01464c522f55534400000000000000000000000000, 18)]  // WC2FLR, FLR/USD
venues_  [(0xe2B3aE21461c4ad3415210630EA210e9F53CCEBc, 0, 3000),  // SwapRouter
          (0x9E63a5D282F2fBb7DcE822B98e363b2719D28319, 1, 0)]     // TESTearnXRP
maxFeedAge_            64
protocolFeeRecipient_  0x38d58d1BEA8FF21fd8397494f17F64A99bcF8E83
confidentialTrigger_   0x02EA709e2278EACDbA00D4A88caA604E3b35293b

The whole action surface: two tokens, two venues, written once in src/Trimmy.sol's constructor. No setter, no owner, no upgrade path.

Superseded deployments, left on chain:

Address Status
0xf73a2af06b315adaa1afe2c1a6c1a6933d8a6554 M-1 vulnerable, do not use
0xeaF2eA3924D5337B2Dd22ae7BFCACEdAc3D913D5 M-1 fixed, M-3 latent
0x3719bAC08F50eC2E165c3078412987d1a39C6D9C M-1 and M-3 fixed
0x6c74bC1154D32839A0900686450a9e2930c7bb46 simulated TEE
0x9c7876df…, trigger 0x1121702e… vulnerable requestEvaluation, do not arm PRIVATE against it

Non-upgradeable, so every fix is a redeploy: arm()'s selector moved from c33d4cc3 to cc0c55f4 when the price fields widened. Regressions for the two money bugs: M1Verify.t.sol (7 tests) and M3Regression.t.sol (4 tests), with 66 core tests green. test/research/ holds exploits, many written to fail, so no pass ratio is quoted.

Source on GitHub Read this page as markdown: /developers/evidence/index.md