Why a bare USDC transfer cannot tell you what it paid for
Think about how a bank wire works. It carries a reference line, and your accounts team searches for the invoice number in that line. A raw stablecoin transfer has no such line. The token contract records who sent how much to whom, and that is all it was ever built to record.
This is fine for a person paying a friend. It breaks down when you run a business. If three customers each owe you the same amount in the same week, three identical transfers land in your wallet, and the chain gives you no way to tell them apart. You can guess from timing, but guesses do not survive an audit.
Most teams first reach for a spreadsheet and a naming rule. They ask customers to email a transaction hash, or to pay from a known address. That works for a handful of payments and falls apart at volume. The better answer is to put the reference where a machine can read it: next to the payment itself, or inside the amount.
How the Arc Memo contract attaches a reference to a transfer
Arc includes a predeployed Memo contract that wraps a call to another contract and emits your metadata as events [1]. The docs describe it as a way to attach an invoice or order reference to a contract call, so wallets and indexers can match on-chain transfers against off-chain records without changing the target contract [1]. The docs give the USDC ERC-20 interface as an example of a target [1].
The entry point takes four things: the target contract, the calldata to forward, a memo identifier you choose, and free-form memo bytes [1]. When the call succeeds, you get an ordered trail. A BeforeMemo event fires first, then the target's own events such as a USDC Transfer, then a Memo event carrying the sender, target, a hash of the calldata, your identifier and your memo bytes [1].
The clever part is who the token thinks is paying. The Memo contract routes the inner call through Arc's CallFrom precompile, which executes a call on behalf of the original sender [1]. So the USDC contract still sees your wallet as the sender, not the Memo contract [1]. Your books show the right payer, and the memo rides alongside.
Reading memos back: the query that closes the books
A memo is only useful if you can find it later. Arc's docs point to the indexed fields: you can query Memo events by memoId, sender and target [1]. If you set the memo identifier to your invoice number, a single lookup returns every payment that cites it, along with the transfer event that moved the money.
There is also a check for exactness. The Memo event includes a keccak256 hash of the forwarded calldata, so you can compare it with the hash of the call your application built [1]. If you need to rebuild the exact call later, the docs advise storing the original calldata yourself, since the chain keeps only the hash [1].
One habit matters more than any query. The docs say to encode the memo bytes consistently in your application, because the contract emits whatever bytes you give it [1]. If your billing system writes references in two different formats, your own lookups can miss some of them. Pick a format, write it down, and test your query on Arc Testnet before going live [1].
Which wallets can send a memo, and which cannot
Memos come with a firm wallet rule. The Memo contract must be called directly by an externally owned account, the ordinary kind of key-controlled wallet [1]. Browser and mobile wallets, hardware wallets, server-side signers and Circle developer-controlled wallets set up as EOAs all qualify [1].
Smart contract wallets do not. The unsupported list names ERC-4337 smart accounts, Safe and other multisig contract wallets, and any other account-abstraction setup where the transaction comes from a bundler, entry point or other middle contract [1]. When one of these calls the Memo contract, the sender that reaches it is the wallet contract or entry point rather than the person, and the call reverts because sender spoofing is not allowed [1].
For a treasury that uses a multisig, this is a real design constraint. The docs offer two ways out: have the contract wallet trigger a separate EOA-signed memo transaction, or attach the metadata in your own application layer instead [1]. If the child call reverts, the whole transaction reverts and the memo index rolls back [1].
Memos for many payments at once, and what SpendTheBits does
Paying a team or a vendor list means many transfers, and Arc has a contract for batching calls that keeps your wallet as the sender [2]. Multicall3From submits several contract calls in one transaction while keeping the original wallet as the sender for each one [2]. It emits no batch event of its own, so you verify the target contract's events: a successful batch of USDC transfers emits one Transfer event per transfer [2].
SpendTheBits uses this world in its Bulk payouts tool. It pays a pasted list or CSV of addresses or @handles in USDC on Arc with one signature on the phone, and shows each line as paid or not paid. Each payment can carry a short memo written on chain through Arc's memo contract. Results export as a CSV for the books, and a batch holds up to a few hundred people.
Two details matter for a finance lead. There is no SpendTheBits fee on bulk payouts today, and network gas is paid in USDC. Every recipient is screened against sanctions lists first, and spending guardrails apply to the batch total. SpendTheBits is fully non-custodial, so the phone signs and the funds never sit with us. For the wider picture, see our guide to accepting USDC payments.

The second fix: a unique amount for every order
Memos suit payments you send. For payments you receive from customers, there is a lighter method that needs nothing from the payer's wallet. Make each order's amount slightly unique, then match the payment to the order by amount. The payer can use any wallet, including ones that cannot attach a memo.
Arc Checkout in SpendTheBits lets a seller type an amount on their phone and show a QR code; the customer pays USDC on Arc from any wallet. A seller types an amount on their phone and shows a QR code. The customer pays USDC on Arc from any wallet, and the screen shows Paid about a second after the payment lands. Each checkout adds a few millionths of a dollar to the amount, so a payment matches its order on its own.
The sale is paid into the seller's own address through a payout contract nobody owns, which also pays a small SpendTheBits fee. Checkout sales are paid into the seller's own address through a payout contract nobody owns, and SpendTheBits never holds the money. Orders, a CSV export for today and an optional signed webhook are in the app. A sale is final on chain, and refunds are never automatic: the seller sends one from their own wallet, up to the sale amount.
One caution about precision. Native USDC on Arc uses 18 decimals, while the ERC-20 view uses 6, and both draw from the same balance [3]. The balanceOf call returns 0 for amounts below one millionth of a dollar, so do not build your matching on dust under that floor [3]. Use unique amounts for storefront-style sales, and use memos when you control the sending side.

Public and permanent: what never belongs in a memo
Here is the part that trips people up. A memo is an event on a public blockchain. Anyone can read it, now and years from now, and nobody can edit or delete it. For bulk payouts, each payment can carry a short memo written on chain through Arc's memo contract, and those memos are public and permanent.
So write references, not secrets. A short opaque code that means nothing to an outsider is the safest choice. A customer's name, a salary figure or an email address is not. If you need to tie a reference back to a person, keep that mapping in your own system and let the chain carry only the opaque code. The memo identifier field is built for exactly this kind of lookup key [1].
A public memo next to a public address can reveal who you pay and how often. SpendTheBits does not use Arc's opt-in privacy features, so assume the full record is visible. Circle runs Arc and issues USDC, and Circle can block an address from sending or receiving USDC.
Finally, close the loop with your accountant. The same ledger data can drive cost-basis lots and journal exports in CFO Books. If your accountant also needs gains tracking, our note on FIFO versus HIFO methods explains the choice. Arc's memo docs say the memo bytes are defined by your application and should be encoded consistently, so pick one format for USDC payment memos and reconciliation gets easier [1].
In the app · 3 steps
Attach memos and match payments in SpendTheBits
Two Arc tools carry the references your books need: memos on payouts and unique amounts on checkouts.
Add a memo per line
In Bulk payouts, each line can carry a short memo. Memos are public and permanent.

See memos on the result
After the batch, each paid line shows its memo, and the CSV export includes them.

Let Checkout match orders
Checkout adds a few millionths of a dollar to each amount, so a payment matches its order on its own.

Hold your own keys, keep the yield, skip the middleman.
SpendTheBits is a fully non-custodial wallet for 13 chains, free on iOS and Android.

