MagicSpend 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(
<MagicSpend contract address>,
<UserOperation.sender and/or msg.sender of the withdraw call>,
<chain ID>,
withdrawRequest.asset,
withdrawRequest.amount,
withdrawRequest.nonce,
withdrawRequest.expiry
)
MagicSpend 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 MagicSpend product from Coinbase, which as a whole allows Coinbase users to seamlessly use their assets onchain.
![Diagram of Coinbase user making use of MagicSpend](https://private-user-images.githubusercontent.com/6678357/308399365-42d3a8fc-a376-4139-9ea9-040cf094d74b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3MjUxODgsIm5iZiI6MTczOTcyNDg4OCwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTM2NS00MmQzYThmYy1hMzc2LTQxMzktOWVhOS0wNDBjZjA5NGQ3NGIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTZUMTY1NDQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWQ0MWZmYWM0NThhNGRmNzE3YmViNTM4OTg3NzMyNTBmMGFjOTUzMzk2NWZmMjVkN2JhYmExNjM4NjQ2ZWU3YiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.JBFC8-wizdF20Jo_7Fsy3FwnAHt4_MD1bBMSCnjTcxs)
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 MagicSpend 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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3MjUxODgsIm5iZiI6MTczOTcyNDg4OCwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTQ1My0yMTI3NGZiMC1iOTAxLTRlMjAtYmMxYy1mMzIwY2FhNzZlNWIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTZUMTY1NDQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODNjODIyYmFhOWRkMzk5NTJhODI2N2FiMzQ1ZmJhYTkzNjc1ODg4NTA2OWI5MTBmZGQ3NGU3MjI0ZWZkODZlNCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.PdXdYXYLvlAFUi6wZL5hWlQJgcztEKP8yUxFCax6jGI)
- A ERC-4337 UserOperation is submitted to the bundler. The paymasterAndData field includes the MagicSpend 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 MagicSpend 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 MagicSpend, with actual gas used in transaction.
- MagicSpend 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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3MjUxODgsIm5iZiI6MTczOTcyNDg4OCwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTUwMC0xMjQ1NDhjYS0yMDlkLTQxYWMtODQ0YS1jYmY1NzE3YTcwMmUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTZUMTY1NDQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NjQwMGI4YTM5YTU5NTk4ODQzODVmZmE0ODQyZDg5MzVkMDQ4ZTFhZTMzNzIyMWRiMTUyMmFkMzhlM2FiMDMyYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.AhubxOcnuppVJcpbP7obZHzvOx6uEuX3v99G2Lp2t84)
This is the simplest flow. The MagicSpend 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.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk3MjUxODgsIm5iZiI6MTczOTcyNDg4OCwicGF0aCI6Ii82Njc4MzU3LzMwODM5OTU1OC00YjgxZmVhNy05YjQ1LTRjZmQtYWNkYi02NmY4OGY2YmM2NDIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTZUMTY1NDQ4WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODk4ZDJlNDY1NjM0MzA0NWQyYWYyNDZkN2FjNWM5NDY5Yzg2OTFhMmUxYTA2NjczMmNkZDFkOWIyMzg5MGZlZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.xO4C6usmiupkPH2vkZ1W_fKD_FhJyCzSPqoNEezHaLo)
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