Samsung Wallet sends USDC on Solana. Here's a 40-line script that tells which chain an address is for
The news, briefly On November 5, 2026, Samsung Wallet launched stablecoin accounts for eligible U.S. Galaxy users. The account holds USDC on Solana. Users can send it to other Samsung Wallet users or to "compatible ext
The news, briefly
On November 5, 2026, Samsung Wallet launched stablecoin accounts for eligible U.S. Galaxy users. The account holds USDC on Solana. Users can send it to other Samsung Wallet users or to "compatible external crypto wallets", and Bastion and Coinbase handle custody (The Block, Decrypt).
"Compatible" is doing a lot of work there. USDC is issued on many chains, and each issuance is a separate token. Send Solana USDC to an Ethereum address and, at best, the wallet blocks you. Sending on the wrong chain from a multi-network exchange is a common way to lose funds.
So I wrote a small script that answers one question: what chain family is this address from, judging by its format alone?
The script
No dependencies, Node 18+. It decodes base58 by hand and uses node:crypto for the TRON checksum.
// which-network.mjs
import { createHash } from 'node:crypto';
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
function base58Decode(str) {
let n = 0n;
for (const ch of str) {
const i = ALPHABET.indexOf(ch);
if (i < 0) return null;
n = n * 58n + BigInt(i);
}
const bytes = [];
while (n > 0n) { bytes.unshift(Number(n % 256n)); n /= 256n; }
for (const ch of str) { if (ch !== '1') break; bytes.unshift(0); }
return Uint8Array.from(bytes);
}
const sha256 = (b) => createHash('sha256').update(b).digest();
function classify(addr) {
if (/^0x[0-9a-fA-F]{40}$/.test(addr)) {
return 'EVM (20 bytes). Same format on Ethereum, Arbitrum, Base, BNB Chain, Avalanche C-Chain... the address alone cannot tell you which one.';
}
if (/^0x[0-9a-fA-F]{64}$/.test(addr)) {
return '32-byte hex. Matches Sui or Aptos style, not EVM. An EVM wallet cannot receive here.';
}
const raw = base58Decode(addr);
if (raw && raw.length === 25 && raw[0] === 0x41) {
const ok = sha256(sha256(raw.subarray(0, 21))).subarray(0, 4).equals(Buffer.from(raw.subarray(21)));
return ok ? 'TRON (base58check, 0x41 prefix, checksum OK).' : 'Looks like TRON but the checksum FAILS. Typo?';
}
if (raw && raw.length === 32 && addr.length >= 32 && addr.length <= 44) {
return 'Solana (base58, 32 bytes). No checksum in this format, so a typo can still decode to a valid-looking key.';
}
return 'Unknown format. Do not send until you know the network.';
}
for (const a of process.argv.slice(2)) console.log(`${a}\n -> ${classify(a)}\n`);
Running it
node which-network.mjs \
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \
0xA6ca3bF1a63bCab37725bF4B1FA3F74fBbc9596a \
TCz734oe5wBtXLWYrJAcC5RrRECarmEEsJ \
TCz734oe5wBtXLWYrJAcC5RrRECarmEEsK
Output:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
-> Solana (base58, 32 bytes). No checksum in this format, so a typo can still decode to a valid-looking key.
0xA6ca3bF1a63bCab37725bF4B1FA3F74fBbc9596a
-> EVM (20 bytes). Same format on Ethereum, Arbitrum, Base, BNB Chain, Avalanche C-Chain... the address alone cannot tell you which one.
TCz734oe5wBtXLWYrJAcC5RrRECarmEEsJ
-> TRON (base58check, 0x41 prefix, checksum OK).
TCz734oe5wBtXLWYrJAcC5RrRECarmEEsK
-> Looks like TRON but the checksum FAILS. Typo?
The first input is the USDC mint on Solana. The last one is the TRON address from line three with its final character changed, and the checksum catches it.
What the output teaches
TRON catches typos, Solana doesn't. A TRON address is base58check: 21 bytes of payload plus 4 bytes of double-SHA256. Change one character and the checksum almost certainly fails. A Solana address is a raw 32-byte public key in base58, so a mistyped address usually still decodes to 32 bytes and passes every format check. If your UI accepts pasted Solana addresses, the format check is nowhere near enough. Show the address back to the user in chunks, or require a small test send.
EVM addresses are ambiguous by design. 0x plus 40 hex chars is valid on every EVM chain. The address is the same on all of them, but the USDC contract and the balance are different. Format checks can't tell you whether the user meant Ethereum or Arbitrum, so the network has to be an explicit choice in your UI and never inferred. (EIP-55 mixed-case checksums help with typos, not with the chain question.)
32-byte hex is not EVM. Sui and Aptos use 32-byte hex addresses with the same 0x prefix. A regex that only checks ^0x[0-9a-f]+$ will happily accept them for an EVM transfer.
Where this fits
Samsung hides most of this behind a custodial account, which is a reasonable product choice. But the moment users send funds out, someone's code has to answer "is this address for the right chain?" A format check like this one is cheap first-line validation. It doesn't replace an explicit network selector, and it doesn't replace a test transaction.
The full script and its output are about 40 lines. Feel free to lift it.
Sources: The Block, "Samsung Wallet launches USDC accounts on Solana for US Galaxy users" (Nov 5, 2026); Decrypt, "Stablecoins Go Mainstream as Samsung Wallet Adds USDC on Solana" (Nov 5, 2026).
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.