Skip to content

docs(examples/base-mainnet): note that MERCHANT_WALLET can be a contract address - #27

Merged
Revinand merged 2 commits into
devlab-group:masterfrom
SCDOLAB:docs/merchant-wallet-contract
Oct 23, 2026
Merged

Revinand merged 2 commits into
devlab-group:masterfrom
SCDOLAB:docs/merchant-wallet-contract

Conversation

@SCDOLAB

@SCDOLAB SCDOLAB commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

This adds a short "Paying into a contract address" section to examples/base-mainnet/README.md. It covers a question I had while setting up the gateway: can MERCHANT_WALLET be a contract, such as a revenue-split contract on Base, rather than an EOA?

What I checked:

  • With MERCHANT_WALLET set to a Base contract address, validate passes on examples/base-mainnet/config.yaml.
  • In the code, the merchant address is used only as payTo (settle.ts payee). Nothing signs with it, and the only check is the Anvil dev-address guard.

Not tested: a live mainnet settlement through this gateway. I don't have CDP credentials. I tried examples/base-mainnet-payai, but start crashed my box with a segfault, because its better-sqlite3 native build failed there (no make). That's my environment, not the gateway. The USDC behaviour itself (transferWithAuthorization to a contract to) is standard EIP-3009 and doesn't call the recipient.

The change is docs only. I'm happy to reword it or move it to docs/configuration.md.

@Revinand

Copy link
Copy Markdown
Member

Thanks for this and for listing what you checked and what you could not test.

The claim holds: the gateway uses payTo only as the destination and never checks whether it has code. I also ran the settlement you could not: on a local Anvil chain, a payment through the gateway and the x402 SDK client to a deployed contract settled and the contract received exactly the price. It used MockUSDC, so it says nothing about CDP's facilitator.

Before I merge:

  1. Add a cross-chain caveat. A contract exists only on the chain where it was deployed, while an EOA's key controls its address on every EVM chain. docs/configuration.md reuses ${MERCHANT_WALLET} for Base and Polygon offers. Setting it to a Base contract would send Polygon payments to an address nobody controls there.
  2. Drop the first caveat. MERCHANT_WALLET is never used as a key or signer.
  3. Style: pad the edited table row (npx prettier --write) and avoid contractions, as the other docs do.

Suggested section:

## Paying into a contract address
 
`MERCHANT_WALLET` sets the x402 `payTo` address, which can be a contract such as a revenue splitter on Base. USDC's EIP-3009 `transferWithAuthorization` transfers tokens without invoking a recipient callback, so the contract needs no receive handler.

Before using a contract:
- Confirm it can send USDC onward, for example through its `distribute` function. Otherwise, the funds stay at that address.
- Verify its deployment on each offer's network. Do not reuse the address on another network unless the intended contract is also deployed there.

Moving the general rule to docs/configuration.md, with a pointer here, is also fine. I will squash-merge as docs: note that a contract can receive x402 payments.

Drop the caveat that treated MERCHANT_WALLET as a signer. State that a
contract exists only on the chain where it was deployed, unlike an EOA,
and pad the edited table row with Prettier.

Co-authored-by: SCDO Laboratory <SCDOLAB@users.noreply.github.com>
@Revinand
Revinand merged commit 93c5a9d into devlab-group:master Oct 23, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants