Skip to content

Commit e55f307

Browse files
bench 313 carried two findings its own table contradicts (#3553)
* bench 313 was one network blip from logging a key The RPC endpoint carries its credential as a path segment, and Go folds the whole request URL into *url.Error, which net/http returns from both Do and NewRequest. Every error on that path went to log.Printf, so any transport failure would have written the key into the container log, which is the log the audit bundles and a report quotes. The audit rated this plausible and said it did not know whether the URL was keyed. It is keyed. withoutURL keeps the operation and the cause and drops the address. The guard has a test that puts the exact shape through it, including a wrapped one, and the test asserts the input really does carry the key so a change to net/url cannot make it vacuous. Disabling the guard fails it on all three cases with the full endpoint in the message, which is the only way to know a guard is a guard and not a comment. An Inconclusive verdict counted as a FAILURE toward the confirmation rule. Observe was handed `v == Sellable`, so everything that was not a clean sale advanced the run: a node answering with an empty call list, a buy that reverted, a read that timed out. 120 tokens drew Inconclusive in 9h30m. A rule that exists to require two real failures was accepting two non-answers. Only a definite verdict is recorded now. LI.FI's row divided by 15 tokens where every other row divided by 26, which made its rank a cohort artifact and not a measurement: on the same 15 tokens it ties Trnch at 66.7%, and the 14.1 point gap the board showed is not there. The cause was not ordering, since surveyCohort already puts the failed tokens first. It was budget. LI.FI publishes 75 requests per 20 minutes, the survey handed it 40 tokens a sweep, it earned a two hour cooldown and then skipped 22 of 30 sweeps without asking anything at all, never seeing those sweeps' failed tokens. Each aggregator now gets a per-sweep budget from its own published limit, and no budget may cut into the failed tokens, which are the prefix of the list and the only part the score divides by. Answering every sweep about the few tokens that matter beats answering one sweep in four about forty. Eight of 26 tokens logged a bare "execution reverted" because error.data was dropped and returnData came back 0x. The decoder that was inline in revertReason is extracted so both fields go through one reader, and the selectors are now recoverable: 0x63ecb9f6 is MinimalOutputBalanceViolation and 0x5212cba1 is CurrencyNotSettled, both verified by hashing the signature. An unsellable verdict is a claim about somebody's token and it has to carry its evidence. The held log line branched on Provisional, which is true for exactly the runs it was meant to distinguish, so the "first observation" case was unreachable and all 136 held lines claimed a prior sale. It branches on Sold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * bench 313 carried two findings its own table contradicts Findings bullet 2 said the screening router and the deny-list router are "both visible here as a low score". Neither is lowest. It asserted the opposite of the board it introduces, about named companies, in the copy that frames the page. It is rewritten to the durable claim: refusing to route is a behaviour this board can see and a price board cannot, and refusing in general is not the same as declining the specific tokens whose exit failed. Findings bullet 3 said tokens with an anti-bot cooldown are "most of a launch cohort". Prometheus has 0 of that shape in 9h30m and 2 of 1573 over a day, and a methodology bullet three lines earlier says the cohort is not launches at all. The delayed sale is a guard against a rare shape, not a filter against a common one, and it says so now, with the count. The subtitle said the exit reverted "on the route they were bought through". The sale is a SEPARATE quote, requested for the balance the buy actually delivered. That was false and it was the first line of the page. The probe size appeared nowhere, and the verdict depends on it: of seven tokens whose round trip returned almost nothing at 0.02, four returned more than a tenth at 0.002 and six at 0.0002. A reverted sale does not move with size; what the exit is worth does. Both are now stated, along with the 99% the code actually sells where the copy said 98%. The delayed tab's own label still read "A few blocks later" after the methodology started saying 36 seconds. No percentage from the live board is typed into this copy. Every row's figure moves with the floor removal and again with LI.FI's budget in #3552, and a number written into a bullet today is a number that contradicts the table tomorrow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 8ddeafd commit e55f307

2 files changed

Lines changed: 17 additions & 8 deletions

File tree

‎benchmarks/token-sellability.yml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ number: "313"
55
title: "Which aggregator routes you into a token you cannot sell"
66
seo_title: "Which aggregator routes you into an unsellable token"
77
seo_description: "Aggregators on Robinhood Chain ranked by the share of failed-exit tokens they still return a route into, simulated on-chain at two timings so a cooldown is not read as a trap."
8-
subtitle: Share of the tokens whose exit reverted on the route they were bought through that each aggregator still returns a route into.
8+
subtitle: Share of the tokens whose simulated sale reverted that each aggregator still returns a route into, asked of every aggregator about the same tokens.
99

1010
category: Aggregators
1111
status: live
@@ -52,16 +52,16 @@ methodology:
5252
- "What the exit is WORTH is recorded, not counted. An earlier version called a token unsellable when its only route out was quoted under a tenth of the stake, which put the chain's own stablecoin in the cohort: USDG was quoted 4.08% and the sale delivered 4.08%, exactly as promised. Every non-reverting exit measured delivered 100.0% of its quote, because the route carries its own minimum output. A thin pool priced honestly is not a failed exit."
5353
- "A failed buy is out of scope, not a failure. If no route in opens, nothing has been learned about selling, and calling that unsellable would blame the token for a market that does not exist."
5454
- "The cohort is tokens that emitted a Transfer in the window, not new launches. The event that announces a new token on this chain is not identified, and guessing it would bias the sample towards whichever launchpad was guessed. Tokens that moved is a weaker claim and a true one."
55-
- "The sale is sized at 98% of what the buy returned, so it can never fail on a rounding difference and be read as a refusal."
55+
- "Every probe buys with 0.02 of the chain's native coin and sells 99% of whatever the buy actually delivered, so a rounding difference can never read as a refusal. The size is part of the result: of seven tokens whose round trip returned almost nothing at this size, four returned more than a tenth at 0.002 and six at 0.0002. A reverted sale does not move with size; what the exit is worth does."
5656
- "The figure counts DISTINCT tokens over 24h, not questions. A token that stays in the cohort for twenty sweeps counts once, so the rate follows how common a failed exit is rather than how long one token lingers, and it survives a restart and a change in how many tokens a sweep examines. A row under a tenth of the expected tokens is withheld rather than published."
5757
- "An exit that returns under a tenth of what was put in is not an exit. A sale can succeed as a call and hand back dust, and scoring that as a clean exit would miss the outcome this board exists to warn about."
5858
- "A row with no questions at all publishes nothing rather than zero. Zero is the best score on this board and has to be earned by declining, never inherited by not being asked."
5959
- "Measured against a route a user would really sign, taken from a live aggregator response rather than hand-built calldata. Simulating calldata we encoded ourselves would test the encoder, not the token."
6060

6161
findings:
6262
- "Tokens that take your money and will not give it back are rare but not absent, and a quote leaderboard cannot see them: the best price on something unsellable still reads as the best price."
63-
- "One router on this board screens the token before it polls anyone and refuses outright, and another keeps a deny list. Both are visible here as a low score and nowhere else: on a price board they would look like missing coverage."
64-
- "The two timings are the whole method. Without the delayed sale, every token with an anti-bot cooldown looks like a trap, and that is most of a launch cohort."
63+
- "Refusing to route is a behaviour this board can see and a price board cannot. One router screens the token before it polls anyone, another keeps a deny list, and on a quote leaderboard both read as missing coverage. Refusing is not the same as ranking well, though: an aggregator earns a low figure here by declining the specific tokens whose exit failed, not by declining in general, and the two do not always go together."
64+
- "The delayed sale is a guard, not a filter. It is there so that a token which only blocks the sale in the buy block is never called a trap, and that shape turns out to be rare on this chain: 2 tokens in 1573 over a day. The guard stays because the cost of calling an honest anti-bot timer a trap is not symmetric with the cost of running the extra simulation."
6565

6666
source: https://github.com/ChainBench/OpenChainBench/tree/dev/harnesses/token-sellability
6767

@@ -82,7 +82,7 @@ dimension_labels:
8282
aggregate_filters: { tier: delayed }
8383
dimensions:
8484
tier:
85-
- { value: delayed, label: "A few blocks later" }
85+
- { value: delayed, label: "36 seconds later" }
8686
- { value: same_block, label: "In the same block" }
8787

8888
ledger_columns:

‎src/lib/spec.ts‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,13 @@ const loadBenchmarkUnfilteredCached = unstable_cache(
903903
// proceeds, so USDG, the chain's own stablecoin, sat in a cohort of
904904
// traps at a 4% round trip it had been quoted exactly. Four rows
905905
// lose tokens from their numerator and the copy states the delay.
906-
["bench-unfiltered-v177", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
906+
// v178: bench 313 carried two findings bullets its own table contradicts.
907+
// One said the screening router and the deny-list router show "a low
908+
// score" when neither is lowest; the other called anti-bot cooldowns
909+
// "most of a launch cohort" when Prometheus has 2 in 1573 over a
910+
// day. The subtitle also said the exit reverted on the route the
911+
// token was bought through, and the sale is a separate quote.
912+
["bench-unfiltered-v178", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
907913
{ revalidate: 300, tags: ["benchmarks"] },
908914
);
909915

@@ -1254,7 +1260,8 @@ const loadAllBenchmarksCached = unstable_cache(
12541260
// v168: lockstep with bench-unfiltered-v175 (bench 001 Denim copy).
12551261
// v169: lockstep with bench-unfiltered-v176 (bench 313 publishes a zero).
12561262
// v170: lockstep with bench-unfiltered-v177 (bench 313 drops the floor).
1257-
["all-benchmarks-v170", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
1263+
// v171: lockstep with bench-unfiltered-v178 (bench 313 false claims).
1264+
["all-benchmarks-v171", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
12581265
{ revalidate: 300, tags: ["benchmarks"] },
12591266
);
12601267
export const loadAllBenchmarks = cache(loadAllBenchmarksCached);
@@ -1490,7 +1497,9 @@ const loadBenchmarkFiltered = unstable_cache(
14901497
// gain the rows whose figure is zero.
14911498
// v96: lockstep with bench-unfiltered-v177. Both tier tabs carry the
14921499
// formula that now names the delay in seconds.
1493-
["bench-filters-v96", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
1500+
// v97: lockstep with bench-unfiltered-v178. The delayed tab's own
1501+
// label changes from "A few blocks later" to "36 seconds later".
1502+
["bench-filters-v97", process.env.VERCEL_ENV === "production" ? "prod" : "all"],
14941503
{ revalidate: 300, tags: ["benchmarks"] }
14951504
);
14961505

0 commit comments

Comments
 (0)