Magic Spend is a contract that allows onchain accounts to present valid Withdraw Requests and receive funds. A Withdraw Request is defined as
struct WithdrawRequest {
bytes signature;
address asset;
uint256 amount;
uint256 nonce;
uint48 expiry;
}
Where signature is an EIP-191 compliant signature of the message
abi.encode(
<Magic Spend contract address>,
<UserOperation.sender and/or msg.sender of the withdraw call>,
<chain ID>,
withdrawRequest.asset,
withdrawRequest.amount,
withdrawRequest.nonce,
withdrawRequest.expiry
)
Magic Spend is an ERC-4337 compliant paymaster (EntryPoint v0.6) and also enables withdraw requests with asset ETH (address(0)
) to be used to pay transaction gas.
This contract is part of a broader Magic Spend product from Coinbase, which as a whole allows Coinbase users to seamlessly use their assets onchain.
![Diagram of Coinbase user making use of Magic Spend](https://private-user-images.githubusercontent.com/6678357/308399365-42d3a8fc-a376-4139-9ea9-040cf094d74b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNzgyMzksIm5iZiI6MTcyNDM3NzkzOSwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTM2NS00MmQzYThmYy1hMzc2LTQxMzktOWVhOS0wNDBjZjA5NGQ3NGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgyMyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MjNUMDE1MjE5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NjNjYTc3Njc1MjMwYTQxNTI3NDgzMjRmZjY3MjU2N2JkNDcwNGIyMzEzZjA1Y2Q4MWYzZDdkYTE4ODcwMTg0MiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.dDC55jktn3QETiymZYP4Wh39dbQA1yaL6otKE89uLWk)
We have started a discussion around a possible new wallet RPC to enable apps to have better awareness of this "just in time" funding.
When the withdrawing account is an ERC-4337 compliant smart contract (like Smart Wallet), there are three different ways the Magic Spend smart contract can be used
- Pay gas only
- Transfer funds during execution only
- Pay gas and transfer funds during execution
![Pay gas only flow diagram](https://private-user-images.githubusercontent.com/6678357/308399453-21274fb0-b901-4e20-bc1c-f320caa76e5b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNzgyMzksIm5iZiI6MTcyNDM3NzkzOSwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTQ1My0yMTI3NGZiMC1iOTAxLTRlMjAtYmMxYy1mMzIwY2FhNzZlNWIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgyMyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MjNUMDE1MjE5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9YWE3ZmY0MzgyMDIzNWZkYjg1ZDEzNTdjMzhjNjkwOGYzYjJlNmFmZWZlNDc4Mjc5MWUzMjZhN2MxMWVlOTllMSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.Vk2NRIC-CAF0ZL7aQPrI9eIRG7cgCsADKWMwP-sNFPo)
- A ERC-4337 UserOperation is submitted to the bundler. The paymasterAndData field includes the Magic Spend address and the withdrawal request.
- Bundler (EOA) calls EntryPoint smart contract.
- Entrypoint first calls to
UserOperation.sender
, a smart contract wallet (SCW), to validate the user operation. - Entrypoint decrements the paymaster’s deposit in the Entrypoint. If the paymaster’s deposit is less than the gas cost, the transaction will revert.
- EntryPoint calls the Magic Spend contract to run validations on the withdrawal, including checking the signature and ensuring withdraw.value is greater than transaction max gas cost.
- Entrypoint calls to SCW with
UserOperation.calldata
- SCW does arbitrary operation, invoked by
UserOperation.calldata
. - Entrypoint makes post-op call to Magic Spend, with actual gas used in transaction.
- Magic Spend sends the SCW any withdraw.value minus actual gas used.
- Entrypoint refunds the paymaster if actual gas < estimated gas from (4.)
- Entrypoint pays bundler for tx gas
![Diagram of 'Transfer funds during execution only' flow](https://private-user-images.githubusercontent.com/6678357/308399500-124548ca-209d-41ac-844a-cbf5717a702e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNzgyMzksIm5iZiI6MTcyNDM3NzkzOSwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTUwMC0xMjQ1NDhjYS0yMDlkLTQxYWMtODQ0YS1jYmY1NzE3YTcwMmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgyMyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MjNUMDE1MjE5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NDQ3MWRhMGVkYWNjZDUwNDc0M2ViN2Y0YTliYWQ5YTI3YzkxZGZmNzczNzBmMTZiZjU5ZDZhYjJlZDFlMTU2ZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.yGb7sXFMWpj8kfg7LELncCyQChdjCgHOvsYsWweZPEU)
This is the simplest flow. The Magic Spend account is agnostic to any details of this transaction, even whether or not the caller is a SCW. It simply validates the withdraw and transfers funds if valid.
![Pay gas and transfer funds during execution](https://private-user-images.githubusercontent.com/6678357/308399558-4b81fea7-9b45-4cfd-acdb-66f88f6bc642.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNzgyMzksIm5iZiI6MTcyNDM3NzkzOSwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTU1OC00YjgxZmVhNy05YjQ1LTRjZmQtYWNkYi02NmY4OGY2YmM2NDIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgyMyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MjNUMDE1MjE5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MmZhZjMxYWM3MjBhNzcwMjkwYzdhN2U2YmM5OGZkMzQ2ZmFmOGYzYjU0M2E2ZWU0YjA5NjY3NzlkY2U2ODM0YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.TO7JO1HITJKOAyzhqhn2pS332lgFkXwJ8SXkapyE4vo)
This flow is like "Pay gas only” with the addition of (7.) and (8.). Here, the SCW also requests funds during execution. In this flow, a user might be, for example, trying to mint an NFT and needs funds for the mint.
Network | Contract Address |
---|---|
Base | 0x011A61C07DbF256A68256B1cB51A5e246730aB92 |
Base Sepolia | 0x011A61C07DbF256A68256B1cB51A5e246730aB92 |
After cloning the repo, run the tests using Forge, from Foundry
forge test
You can run the echinda tests with this make command
make echidna-test