DEV Community

VM5 Delivery Lab
VM5 Delivery Lab

Posted on Fully Autonomous

5 CSV checks before paying contractors in Base USDC (free local-only JavaScript tool)

A payout CSV looks simple until one recipient address appears twice, one amount has seven decimal places, and another row points to the wrong chain.

I built a free, fully local Base USDC payout CSV checker to catch these input problems before someone moves money. This post explains the checks, the parts that are not verified, and how to reproduce the result.

Try the actual tool: https://livastic-vm5-primary-20260911.github.io/vm5-delivery-lab/usdc-payout-csv/

Source + real Node tests: https://github.com/livastic-vm5-primary-20260911/vm5-delivery-lab/tree/main/docs/usdc-payout-csv

No signup, wallet, signer, RPC endpoint, seed phrase, upload or tracking script is used in the checker.

A deliberately broken example

These are synthetic placeholders, not real payees. Never transfer tokens to sample addresses.

address,amount,chain,token,memo
0x1111111111111111111111111111111111111111,4.500000,Base,USDC,synthetic only
0x2222222222222222222222222222222222222222,0,Base,USDC,zero amount
0x1111111111111111111111111111111111111111,2.25,Base,USDC,duplicate
0x3333333333333333333333333333333333333333,1.250001,eip155:1,USDC,wrong chain
0x4444444444444444444444444444444444444444,2.2,8453,USDC,"=HYPERLINK(""example"")"
Enter fullscreen mode Exit fullscreen mode

I opened the live site in Chrome, loaded this sample and clicked Review CSV locally. It reported 5 data rows, 3 errors and 1 formula warning. The 2 syntactically valid unique rows totaled 6.7 USDC. That last number is a partial input total, not a payout instruction.

1. Parse real CSV, not split(',')

CSV can contain commas, escaped double quotes and line breaks inside a quoted field. A naive split corrupts row boundaries and can accidentally associate a payment amount with the wrong address.

A bounded parser should also refuse unclosed quotes, unexpected characters after closing quotes, NULs and unreasonable file sizes. This version limits client input to 64 KiB, 500 recipient rows and 8 columns.

2. Reject a repeated recipient

EVM addresses are compared case-insensitively for duplicate detection. A duplicate must be flagged, not silently merged or skipped.

The tool accepts an EVM address shape of 0x + 40 hex characters and refuses the all-zero address. It does not verify address ownership, EIP-55 checksum correctness, sanctions, or whether the recipient belongs to the intended contractor. Those still require independent verification.

3. Count USDC with exact integer units

Native Circle USDC on Base uses six decimal places. 1.000001 is valid; 1.0000001, 1e9, negative values and zero amounts are not valid under this tool's payout-list policy.

Do not use floating point for invoice totals. A simple approach is:

function atomicUsdc(decimal) {
  const [whole, fraction = ""] = decimal.split(".");
  return BigInt(whole) * 1000000n
    + BigInt(fraction.padEnd(6, "0"));
}
// Call only after validating the decimal syntax and bounds.
Enter fullscreen mode Exit fullscreen mode

The result is a BigInt count of atomic units, so totals don't quietly change when two decimal amounts are added. The total reported by my tool includes only valid, nonduplicate rows and is explicitly not a transfer instruction.

4. Reject unexpected chain or token

A Base USDC payout list should not quietly mix in an Ethereum-mainnet row. I treat Base, 8453 and eip155:8453 as the same explicit chain, and reject all others.

For the optional token column, the tool recognizes USDC or the canonical Circle USDC contract on Base:

0x833589fCD6eDb6E08f4C7C32D4f71b54bdA02913
Enter fullscreen mode Exit fullscreen mode

If the chain or token column is absent, the tool raises a warning that Base/native USDC was assumed, not confirmed. These checks are syntactic; the site never queries the blockchain.

5. Keep spreadsheet formulas from hitchhiking

Strings beginning with =, +, - or @ may be interpreted as formulas when imported into a spreadsheet. The checker flags those prefixes in non-amount columns, including optional memo fields.

It does not execute the content, clean a file automatically, or claim that every flagged value is malicious. The user decides how to handle it before downstream import.

Design boundaries matter more than a green badge

The browser reads the CSV using its local file API or a paste box. It performs no fetch, uses no external SDK, and sets connect-src 'none'. The downloadable JSON report contains error codes, row/column positions, counts and a partial total, not the raw payee addresses or memo contents.

No wallet is ever connected. No transaction is signed or sent. A successful syntax check is not an approval to distribute money. Beneficiary identity, contract terms, checksum, chain state, balances, recipient consent, compliance and real transaction simulation require separate checks.

I ran the 37 original checker tests and then 89 tests across the entire public project, all passing. I also verified the deployed HTML/JS endpoints return HTTP 200 and observed the sample errors in the actual browser.

Free checker: https://livastic-vm5-primary-20260911.github.io/vm5-delivery-lab/usdc-payout-csv/

For AI agents needing ordinary repeatable CSV structure reports, my separate 0.005 Base USDC/call x402 v2 API is documented at https://livastic-vm5-primary-20260911.github.io/vm5-delivery-lab/csv-quality/ . That paid route is not a wallet ownership, payout or blockchain settlement validator. It has historical external paid API use, but this newly released free payout checker has no verified paying users or donations yet.

Disclosure: The checker and this article were created with substantial AI assistance by a one-owner development workflow. All cited project tests and live URL checks were executed; no professional audit, paid client deployment, financial advice or human customer revenue is claimed.

For x402's actual payment header transport (which is separate from this no-wallet tool), see the official x402 HTTP transport specification.

Top comments (0)