EVM Invoicing
Status: partly runnable, last checked 2026-11-02. The verification below runs for anyone. The invoice pattern needs access to the private spawn-proto repo. Testnet only.
Verify a prediction yourself
This computes a CREATE2 address locally and compares it with the factory’s own answer on Sepolia. It uses only public tools and needs no Dial code or account. The values are the test vector from spawn-proto.
npm install viemimport { createPublicClient, getCreate2Address, http, parseAbi } from 'viem'
import { sepolia } from 'viem/chains'
const factory = '0xBd9680E4dD16Bc3bebE8557F47FFA54184679334'
const salt = '0xc037ee33b1d559f7d95f9bed05d88af5d3569b5fe00ac1b6a4b38dfff85b5636'
const initCodeHash = '0xcf6ca536764062ad2d04a612020107da8826bdbb4de1566dd7f012ab61f9136f'
const local = getCreate2Address({ from: factory, salt, bytecodeHash: initCodeHash })
const client = createPublicClient({ chain: sepolia, transport: http() })
const onchain = await client.readContract({
address: factory,
abi: parseAbi(['function computeAddress(bytes32, bytes32) view returns (address)']),
functionName: 'computeAddress',
args: [salt, initCodeHash],
})
console.log({ local, onchain, match: local === onchain })Both values should be 0x2041F7F77d7FDf50199F516e7e433194f3faD2d8.
What this proves: the formula and the deployed factory agree. What it doesn’t prove: that a program ever ran. Nothing is deployed at this address, because it’s a test vector. Don’t send funds to it.
How the invoice pattern works
- Create. The pattern creates a Request Network invoice, then builds forwarder init code with the beneficiary, payment reference and fee.
- Predict. It computes the CREATE2 address and stores the salt and init code. Losing them means losing the ability to deploy at that address.
- Share. The payer gets the address, a QR code and an
ethereum:payment URI. - Watch. A signed Alchemy webhook reports activity at the address.
- Deploy. The service deploys the forwarder, which forwards the balance during construction.
- Reconcile. Webhooks update the stored state.
Using the package
With repo access, the entry point on main is createInvoiceSpawn from @decoperations/spawn-proto-patterns-invoice, published privately to GitHub Packages. Its createxAddress option is why the next warning matters.
Don’t pass the canonical CreateX address and then fund the result. The prediction may not match the deployed address. See the open issue. Use the Sepolia repo factory for testing on dev, with Sepolia ETH only. These forwarders don’t handle ERC-20 tokens, so never send USDC to them.
Testnet safety
- Use Sepolia ETH, and never real funds.
- Keep the salt and init code until the program has finished.
- Treat “funds arrived” and “executed” as separate states.
- Check the forwarder’s balance and the beneficiary’s receipt on an explorer. A webhook is only a signal.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Addresses don’t match | Wrong factory, wrong chain, a different salt, or changed constructor arguments |
| Deploy reverts | Contract already deployed at that address, or a failed transfer in the constructor |
| Webhook never fires | Address not registered with the watcher, or wrong network |
| Second payment reverts | GenericForwarderMinimal has no receive function |
Next: read the full EVM adapter page.
Explore invoicing: Programmable Invoicing and invoicing on Ethereum