{"id":18542735,"url":"https://github.com/coinbase/spend-permissions","last_synced_at":"2025-04-09T18:32:05.865Z","repository":{"id":258084228,"uuid":"873191204","full_name":"coinbase/spend-permissions","owner":"coinbase","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-08T05:04:41.000Z","size":9381,"stargazers_count":33,"open_issues_count":6,"forks_count":9,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-08T06:22:01.441Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coinbase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":"audits/Cantina-December-2024.pdf","citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-15T18:43:46.000Z","updated_at":"2025-04-08T05:04:45.000Z","dependencies_parsed_at":"2024-11-14T00:26:49.512Z","dependency_job_id":"a8a62e3e-7699-46e0-b0e3-f9a15174e3d4","html_url":"https://github.com/coinbase/spend-permissions","commit_stats":null,"previous_names":["coinbase/spend-permissions"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fspend-permissions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fspend-permissions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fspend-permissions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fspend-permissions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coinbase","download_url":"https://codeload.github.com/coinbase/spend-permissions/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248087842,"owners_count":21045598,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T20:10:14.948Z","updated_at":"2025-04-09T18:32:00.844Z","avatar_url":"https://github.com/coinbase.png","language":"Solidity","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spend Permissions\n\n\u003e :information_source: These contracts are unaudited. Please use at your own risk.\n\n**Spend Permissions enable apps to spend native and ERC-20 tokens on behalf of users.**\n\n## Deployments\n\n### Base Sepolia\n\n`SpendPermissionManager`: 0x6Bb91a81aa8C4edDBe04c774015279445fE68B5A\n\n`PublicERC6492Validator`: 0x111c9102952eEA29b02297E9ee4b8DB6265e763e\n\n## Design Overview\n\n### 1. Periphery addition to Coinbase Smart Wallet V1\n\nWhile implementing this feature as a new V2 wallet implementation was tempting, we decided to leverage the modular owner system from [Smart Wallet V1](https://github.com/coinbase/smart-wallet) and avoid a hard upgrade.\n\n### 2. Only Native and ERC-20 token support\n\nSpend Permissions only supports spending Native (e.g. ETH) and ERC-20 (e.g. USDC) tokens on a recurring period. This enables use cases like subscriptions out of the box (e.g 10 USDC per month) and also can support apps that want to avoid asking users for spend permissions every session.\n\nThis approach does **not** enable apps to make arbitrary external calls from user accounts, improving security by having a tighter and fully-known scope of account control.\n\n### 3. Spender-originated calls\n\nSpend Permissions allow users to delegate token spending to a `spender` address, presumably controlled by the app. When an app wants to spend user tokens, it calls into `SpendPermissionManager` from this `spender` address. `SpendPermissionManager` will then validate the spend is within the approved permission's allowance and calls into the user's account to transfer tokens.\n\nThis approach does **not** use the ERC-4337 EntryPoint to prompt external calls from user accounts, improving security by avoiding the possibility of ERC-4337 Paymasters spending users' tokens on gas fees.\n\n## End-to-end Journey\n\n### 1. App requests and user signs permissions (offchain)\n\nApps request spend permissions for users to sign by sending an `eth_signTypedData` RPC request containing the permission details.\n\nRead more details [here](./docs/diagrams/signSpendPermission.md).\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant A as App\n    participant WF as Wallet Frontend\n    participant U as User\n    participant WB as Wallet Backend\n\n    A-\u003e\u003eWF: eth_signTypedData\n    WF-\u003e\u003eU: approve permission\n    U--\u003e\u003eWF: signature\n    WF-\u003e\u003eWB: get account status\n    WB--\u003e\u003eWF: deploy status, initCode, current + pending owners\n    alt  account not deployed \u0026\u0026 manager in initCode\n        Note right of WF: wrap signature in ERC-6492\n    else manager not in initCode \u0026\u0026 manager not owner\n        WF-\u003e\u003eU: add manager\n        U--\u003e\u003eWF: signature\n    end\n    WF--\u003e\u003eA: signature\n```\n\n### 2. App approves and spends (onchain)\n\nSpenders (apps) spend tokens by calling `SpendPermissionManager.spend` with their spend permission values, a recipient, and an amount of tokens to spend.\n\nSpenders may want to batch this call with an additionally prepended call to [approve their permission via user signature](./approveWithSignature.md) unless the user has already approved the spend permission(s) directly via `SpendPermissionManager.approve`.\n\nRead more details [here](./docs/diagrams/spend.md).\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant S as Spender\n    participant PM as Permission Manager\n    participant A as Account\n    participant ERC20\n\n    alt\n    S-\u003e\u003ePM: approveWithSignature\n    Note over PM: validate signature and store approval\n    else\n    A-\u003e\u003ePM: approve\n    end\n    S-\u003e\u003ePM: spend\n    Note over PM: validate permission approved \u003cbr\u003e and spend value within allowance\n    PM-\u003e\u003eA: execute\n    Note over PM,A: transfer tokens\n    alt token is ERC-7528 address\n        A-\u003e\u003eS: call{value}()\n        Note over A,S: transfer native token to spender\n    else else is ERC-20 contract\n        A-\u003e\u003eERC20: transfer(spender, value)\n        Note over A,ERC20: transfer ERC-20 to spender\n    end\n```\n\n### 3. User revokes permission (onchain)\n\nUsers can revoke permissions at any time by calling `SpendPermissionManager.revoke`, which can also be batched via `CoinbaseSmartWallet.executeBatch`.\n\nRead more details [here](./docs/diagrams/revoke.md).\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant E as Entrypoint\n    participant A as Account\n    participant PM as Permission Manager\n\n    Note over E: Validation phase\n    E-\u003e\u003eA: validateUserOp\n    A--\u003e\u003eE: validation data\n    Note over E: Execution phase\n    E-\u003e\u003eA: executeBatch\n    loop\n        A-\u003e\u003ePM: revoke\n        Note over A,PM: SpendPermission data\n    end\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoinbase%2Fspend-permissions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoinbase%2Fspend-permissions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoinbase%2Fspend-permissions/lists"}