{"id":18542732,"url":"https://github.com/coinbase/smart-wallet","last_synced_at":"2025-05-15T20:03:07.707Z","repository":{"id":225174572,"uuid":"763829389","full_name":"coinbase/smart-wallet","owner":"coinbase","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-19T08:20:18.000Z","size":21986,"stargazers_count":408,"open_issues_count":28,"forks_count":110,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-04-19T09:17:01.842Z","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-April-2024.pdf","citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-02-27T01:46:33.000Z","updated_at":"2025-04-18T20:59:12.000Z","dependencies_parsed_at":"2024-03-11T00:36:17.514Z","dependency_job_id":"52a246f4-e438-4f67-82db-c75e72ab4030","html_url":"https://github.com/coinbase/smart-wallet","commit_stats":{"total_commits":284,"total_committers":10,"mean_commits":28.4,"dds":0.323943661971831,"last_synced_commit":"d0491d4b4650e4f6606bd9172812bdfa9524190f"},"previous_names":["coinbase/smart-wallet"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsmart-wallet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsmart-wallet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsmart-wallet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coinbase%2Fsmart-wallet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coinbase","download_url":"https://codeload.github.com/coinbase/smart-wallet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414493,"owners_count":22067271,"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:09.911Z","updated_at":"2025-05-15T20:03:06.568Z","avatar_url":"https://github.com/coinbase.png","language":"Solidity","funding_links":[],"categories":["Solidity"],"sub_categories":[],"readme":"# Smart Wallet\n\nThis repository contains code for a new, [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) compliant smart contract wallet from Coinbase. \n\nIt supports \n- Multiple owners\n- Passkey owners and Ethereum address owners\n- Cross-chain replayability for owner updates and other actions: sign once, update everywhere. \n\n## Multiple Owners\nOur smart wallet supports a practically unlimited number of concurrent owners (max 2^256). Each owner can transact independently, without sign off from any other owner. \n\nOwners are identified as `bytes` to allow both Ethereum address owners and passkey (Secp256r1) public key owners. \n\n## Passkey owners and Ethereum address owners\nEthereum address owners can call directly to the smart contract wallet to transact and also transact via user operations. \n\nIn the ERC-4337 context, we expect `UserOperation.signature` to be the ABI encoding of a `SignatureWrapper` struct \n```solidity\nstruct SignatureWrapper {\n    uint8 ownerIndex;\n    bytes signatureData;\n}\n```\n\nOwner index identifies the owner who signed the user operation. This must be passed because secp256r1 verifiers require the public key as an input. This differs from `ecrecover`, which returns the signer address.\n\nWe pass an `ownerIndex` rather than the public key itself to optimize for calldata, which is currently the main cost driver on Ethereum layer 2 rollups, like Base. \n\nIf the signer is an Ethereum address, `signatureData` should be the packed ABI encoding of the `r`, `s`, and `v` signature values. \n\nIf the signer is a secp256r1 public key, `signatureData` should be the the ABI encoding of a [`WebAuthnAuth`](https://github.com/base-org/webauthn-sol/blob/main/src/WebAuthn.sol#L15-L34) struct. See [webauthn-sol](https://github.com/base-org/webauthn-sol) for more details. \n\n## Cross-chain replayability \nIf a user changes an owner or upgrade their smart wallet, they likely want this change applied to all instances of your smart wallet, across various chains. Our smart wallet allows users to sign a single user operation which can be permissionlessly replayed on other chains. \n\nThere is a special function, `executeWithoutChainIdValidation`, which can only be called by the `EntryPoint` contract (v0.6). \n\nIn `validateUserOp` we check if this function is being called. If it is, we recompute the userOpHash (which will be used for signature validation) to exclude the chain ID. \n\nCode excerpt from validateUserOp\n```solidity\n// 0xbf6ba1fc = bytes4(keccak256(\"executeWithoutChainIdValidation(bytes)\"))\nif (userOp.callData.length \u003e= 4 \u0026\u0026 bytes4(userOp.callData[0:4]) == 0xbf6ba1fc) {\n    userOpHash = getUserOpHashWithoutChainId(userOp);\n    if (key != REPLAYABLE_NONCE_KEY) {\n        revert InvalidNonceKey(key);\n    }\n} else {\n    if (key == REPLAYABLE_NONCE_KEY) {\n        revert InvalidNonceKey(key);\n    }\n}\n```\n\nTo help keep these cross-chain replayable user operations organized and sequential, we reserve a specific nonce key for only these user operations.\n\n`executeWithoutChainIdValidation` can only be used for calls to self and can only call a whitelisted set of functions. \n\n```solidity\nfunction executeWithoutChainIdValidation(bytes calldata data) public payable virtual onlyEntryPoint {\n    bytes4 selector = bytes4(data[0:4]);\n    if (!canSkipChainIdValidation(selector)) {\n        revert SelectorNotAllowed(selector);\n    }\n\n    _call(address(this), 0, data);\n}\n```\n\n`canSkipChainIdValidation` can be used to check which functions can be called.\n\nToday, allowed are \n- MultiOwnable.addOwnerPublicKey\n- MultiOwnable.addOwnerAddress\n- MultiOwnable.addOwnerAddressAtIndex\n- MultiOwnable.addOwnerPublicKeyAtIndex\n- MultiOwnable.removeOwnerAtIndex\n- UUPSUpgradeable.upgradeToAndCall\n\n## Deployments\nFactory and implementation are deployed via [Safe Singleton Factory](https://github.com/safe-global/safe-singleton-factory), which today will give the same address across 248 chains. See \"Deploying\" below for instructions on how to deploy to new chains. \n| Version   | Factory Address                        |\n|-----------|-----------------------------------------|\n| 1 | [0x0BA5ED0c6AA8c49038F819E587E2633c4A9F428a](https://basescan.org/address/0x0BA5ED0c6AA8c49038F819E587E2633c4A9F428a) |\n\n\n## Developing \nAfter cloning the repo, run the tests using Forge, from [Foundry](https://github.com/foundry-rs/foundry?tab=readme-ov-file)\n```bash\nforge test\n```\n\n## Deploying\nTo deploy on a new chain, in your `.env` set\n```bash\n#`cast wallet` name\nACCOUNT=\n# Node RPC URL\nRPC_URL=\n# Optional Etherscan API key for contract verification\nETHERSCAN_API_KEY=\n```\nSee [here](https://book.getfoundry.sh/reference/cast/cast-wallet-import) for more details on `cast wallet`.\n\nThen run \n```\nmake deploy\n```\n\n## Influences\nMuch of the code in this repository started from Solady's [ERC4337](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC4337.sol) implementation. We were also influenced by [DaimoAccount](https://github.com/daimo-eth/daimo/blob/master/packages/contract/src/DaimoAccount.sol), which pioneered using passkey signers on ERC-4337 accounts, and [LightAccount](https://github.com/alchemyplatform/light-account).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoinbase%2Fsmart-wallet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoinbase%2Fsmart-wallet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoinbase%2Fsmart-wallet/lists"}