<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Konrad Vale</title>
    <description>The latest articles on DEV Community by Konrad Vale (@konradvale).</description>
    <link>https://dev.to/konradvale</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4191026%2F22db0369-dac8-48be-b85d-06ee0ad2707f.png</url>
      <title>DEV Community: Konrad Vale</title>
      <link>https://dev.to/konradvale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/konradvale"/>
    <language>en</language>
    <item>
      <title>One extra letter in a USDC address flagged every Solana API we list</title>
      <dc:creator>Konrad Vale</dc:creator>
      <pubDate>Tue, 20 Oct 2026 08:56:19 +0000</pubDate>
      <link>https://dev.to/konradvale/one-extra-letter-in-a-usdc-address-flagged-every-solana-api-we-list-7d5</link>
      <guid>https://dev.to/konradvale/one-extra-letter-in-a-usdc-address-flagged-every-solana-api-we-list-7d5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short version:&lt;/strong&gt; for the first four days ToolVet ran, from 11 to 15 October 2026, the Solana USDC address in our table of known tokens had one letter too many. Every x402 API that charges USDC on Solana showed "Price n/a", carried a false security finding, lost 4 trust points, dropped out of price filters, and got an "avoid" verdict from the preflight check agents run before they pay. None of it was the sellers' fault. A correctness audit found it, we fixed it on 15 October, and the &lt;a href="https://toolvet.app/changelog" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; records it. This post covers what broke, why our tests missed it, and what catches it now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the token table is for
&lt;/h2&gt;

&lt;p&gt;An &lt;a href="https://www.x402.org" rel="noopener noreferrer"&gt;x402&lt;/a&gt; server answers an unpaid request with HTTP 402 and a payment challenge. The challenge gives the amount in the token's smallest unit, the token's address, the network and the address to pay. An amount of &lt;code&gt;2000&lt;/code&gt; is $0.002 only if you know the token is USDC, which has 6 decimals.&lt;/p&gt;

&lt;p&gt;So ToolVet keeps a small table: network, then token address, then symbol, decimals and whether the token is pegged to the dollar. When a challenge names a token that isn't in the table, we can't turn the amount into a price. We also flag it, because a challenge that asks for an unknown token could be asking for something worth nothing, or for a look-alike of a real stablecoin.&lt;/p&gt;

&lt;p&gt;This is the table as it shipped on 11 October:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** network -&amp;gt; lower-cased asset address/mint -&amp;gt; asset info */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;KNOWN_ASSETS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;KnownAsset&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Base mainnet&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eip155:8453&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;usdPegged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...Ethereum, Polygon, Arbitrum, Avalanche...&lt;/span&gt;
  &lt;span class="c1"&gt;// Solana mainnet&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solana:5eykt4usfv8p8njdtrepy1vzqkqzkvdp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;epjfwdd5aufqssqem2qn1xzybapc8g4wegggkzwytdt1v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;usdPegged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;lookupAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;KnownAsset&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;KNOWN_ASSETS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;normalizeNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()]?.[&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Spot the typo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.circle.com/stablecoins/usdc-contract-addresses" rel="noopener noreferrer"&gt;Circle publishes&lt;/a&gt; the Solana USDC mint as &lt;code&gt;EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&lt;/code&gt;. Lower-cased, it ends in &lt;code&gt;…c8g4weggkzwytdt1v&lt;/code&gt;. Our key ended in &lt;code&gt;…c8g4wegggkzwytdt1v&lt;/code&gt;: three &lt;code&gt;g&lt;/code&gt;s where there should be two, in a 44-character string with no capitals left to break it up.&lt;/p&gt;

&lt;p&gt;The lower-casing came from Ethereum. An EVM address can be written all in lower case or in the mixed case of an &lt;a href="https://eips.ethereum.org/EIPS/eip-55" rel="noopener noreferrer"&gt;EIP-55&lt;/a&gt; checksum, and both are the same address. Lower-casing both sides is the usual way to compare them, and we applied that rule to every network.&lt;/p&gt;

&lt;p&gt;Solana addresses are base58, where &lt;code&gt;G&lt;/code&gt; and &lt;code&gt;g&lt;/code&gt; are different digits. Lower-casing them still works for a lookup, as long as both sides are lower-cased and the key is right, which is why it looked harmless. What it cost us was the ability to check the key against its source. You can't paste Circle's mint into a search of the file and find it. A reviewer comparing the two strings has to lower-case one in their head, character by character.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one failed lookup did
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;lookupAsset&lt;/code&gt; returned &lt;code&gt;null&lt;/code&gt; for every Solana USDC challenge. Everything downstream read &lt;code&gt;null&lt;/code&gt; as "this seller asks for a token we don't know":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Price.&lt;/strong&gt; With no decimals, the amount couldn't become a price. The listing page showed "Price n/a", and the API and MCP tools returned no price.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filters and sorts.&lt;/strong&gt; A listing with no price drops out of price filters and price sorts. An agent searching with a budget never saw these APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security finding.&lt;/strong&gt; Every one got "Asks for an unrecognised token".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust score.&lt;/strong&gt; A valid challenge earns 10 points with a known token and 6 with an unknown one, so each lost 4.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preflight.&lt;/strong&gt; The paid preflight check, which an agent calls with a URL before paying it, answered "avoid".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing threw an error. Each listing's result, taken alone, looked like a reasonable judgment about that listing: an unpriced challenge for an unknown token is exactly what a dubious listing looks like. A bug in our reference data had turned into a verdict against the sellers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why our tests missed it
&lt;/h2&gt;

&lt;p&gt;The original test suite had the right address in it. The Bazaar importer test used a catalog entry with two payment options: USDC on Base, and USDC on Solana with the correct mint. But the test's assertions checked the listing's price, which came from the Base option, and that the entry had two options. No test priced a Solana option, so the one place the correct mint met the mistyped key went unchecked.&lt;/p&gt;

&lt;p&gt;The aggregate would have given it away at once: every Solana USDC listing had the same finding. But we were looking at listings one at a time, not counting findings per network.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we found it
&lt;/h2&gt;

&lt;p&gt;On 15 October we audited every number the site publishes: we read the code behind each one, reproduced each suspected error with a failing test, and had every finding re-checked independently. The audit came to 52 findings. This one was confirmed on a live listing page, and the &lt;a href="https://toolvet.app/changelog" rel="noopener noreferrer"&gt;changelog&lt;/a&gt; lists the ones that changed what people saw. The same table was also missing USDC on OP Mainnet: the network had a name but no token entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Two changes. Solana mints are now written exactly as Circle publishes them and compared exactly, and only EVM addresses are compared without case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KnownAsset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;usdPegged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;KNOWN_ASSETS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;KnownAsset&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eip155:8453&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x833589fcd6edb6e08f4c7c32d4f71b54bda02913&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eip155:10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x0b2c639c533813f4aa9d7837caf62653d097ff85&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// OP Mainnet, newly added&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;USDC&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cm"&gt;/** EVM addresses are compared without case (checksums); every other address, such as a Solana mint, exactly. */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addressKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;isEvmNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a test now checks the table against Circle's list, pasted in the form Circle publishes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Circle's published USDC addresses, as written there.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eip155:1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eip155:8453&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ...Polygon, Arbitrum, Avalanche, OP Mainnet...&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recognises USDC on every network Circle lists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;lookupAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;usdPegged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;atomicToUsd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ignores case in EVM addresses but not in Solana mints&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;lookupAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BASE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BASE_USDC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeNull&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;lookupAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SOL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SOL_USDC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())).&lt;/span&gt;&lt;span class="nf"&gt;toBeNull&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;lookupAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SOL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SOL_USDC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nf"&gt;toBeNull&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What matters is where the expected values come from: the source, pasted as published, never derived from our own table. A test that takes its expected value from the code under test can only confirm that the code agrees with itself.&lt;/p&gt;

&lt;p&gt;Each check after the fix recomputes a listing's price, trust score and findings from the challenge its endpoint returns.&lt;/p&gt;

&lt;h2&gt;
  
  
  If your code handles on-chain addresses
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Normalise per chain, not once for all of them.&lt;/strong&gt; Lower-case EVM addresses for comparison, or validate the checksum. Compare Solana addresses exactly. If you add a chain, look up its rules rather than reusing the last chain's.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep constants in the form the source publishes.&lt;/strong&gt; A reviewer should be able to search the file for the address they copied from the issuer's page and find it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test constants against the source, verbatim.&lt;/strong&gt; Paste the published list into the test, so the code and the test can't share a typo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count your "unknown" verdicts.&lt;/strong&gt; When one listing asks for an unknown token, suspect the listing. When every listing on a network does, suspect your table. A few lines after each scan would have caught this on day one:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// An unknown token on most listings of one network is our table, not the sellers.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;listings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknownToken&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;findingsByNetwork&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listings&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;unknownToken&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;listings&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`unknown-token finding on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;unknownToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;listings&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; listings on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We already apply the same reasoning to uptime: when listings on many sites fail their checks at once, ToolVet assumes the problem is on our side and doesn't announce the outages it confirms during that time. The &lt;a href="https://toolvet.app/methodology#status-pages-and-outages" rel="noopener noreferrer"&gt;methodology&lt;/a&gt; describes the rule. The token table had no such guard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the USDC address on Solana?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&lt;/code&gt; on mainnet and &lt;code&gt;4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU&lt;/code&gt; on devnet, according to &lt;a href="https://developers.circle.com/stablecoins/usdc-contract-addresses" rel="noopener noreferrer"&gt;Circle's list&lt;/a&gt;. Copy addresses from the issuer's page, not from a blog post, this one included.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are Solana addresses case-sensitive?
&lt;/h3&gt;

&lt;p&gt;Yes. Base58 uses upper- and lower-case letters as different digits, so changing the case of one letter gives a different address or an invalid one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are Ethereum addresses case-sensitive?
&lt;/h3&gt;

&lt;p&gt;No. The mixed case in an address like &lt;code&gt;0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&lt;/code&gt; is an EIP-55 checksum, and the all-lower-case form is the same address. Compare them lower-cased, or check the checksum.&lt;/p&gt;

&lt;h3&gt;
  
  
  My x402 API charges USDC on Solana. Do I need to do anything?
&lt;/h3&gt;

&lt;p&gt;No. Each check after 15 October recomputes your listing's price, trust score and findings from the challenge your endpoint returns. The free &lt;a href="https://toolvet.app/check" rel="noopener noreferrer"&gt;x402 checker&lt;/a&gt; shows what an agent sees when it calls your endpoint today.&lt;/p&gt;

&lt;p&gt;Found a number of ours that looks wrong? Write to &lt;a href="mailto:hello@toolvet.app"&gt;hello@toolvet.app&lt;/a&gt; with the listing's URL. Corrections go in the &lt;a href="https://toolvet.app/changelog" rel="noopener noreferrer"&gt;changelog&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://toolvet.app/blog/solana-usdc-mint-typo" rel="noopener noreferrer"&gt;ToolVet blog&lt;/a&gt;. ToolVet checks paid x402 APIs and remote MCP servers on a schedule and publishes how it scores them.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>typescript</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
