Introduction
SmartWallet is a smart contract wallet that enhances user authentication and operational flexibility on Ethereum-based networks. It supports Ethereum address and passkey owners, utilizing WebAuthnSol for signature validation. The wallet allows multiple owners and facilitates account-changing operations across any EVM chain with the same address. It adheres to ERC-4337 standards and integrates with paymasters like MagicSpend for broader utility.
Architecture Diagram
The system described through the provided code snippets outlines a comprehensive architecture incorporating account abstraction, signature verification, and smart contract interactions for managing ownership, authentication, and transactions. Here is an architecture diagram in a descriptive format that illustrates the overall system interactions:

Overview of the Whole System Interactions:
-
User Interaction: Users interact with their accounts to initiate transactions, which may include operations like transferring assets or invoking specific functionalities of a contract.
-
User Account: Represents an ERC-4337 compatible smart contract wallet, enabling account abstraction and allowing transactions to be executed without ETH for gas, relying on the EntryPoint and Paymaster for execution and funding.
-
Signature Verification: A crucial component ensuring that operations requested by the user account are duly signed by the rightful owners, employing ECDSA and WebAuthn for robust authentication mechanisms.
-
EntryPoint (EP): Serves as the gateway for user operations under the account abstraction model, coordinating the execution of transactions by interacting with Paymasters for gas sponsorship and ensuring the system's integrity.
-
Paymaster (PM): Manages the funding for transactions, deciding whether to sponsor a transaction based on the available funds and the legitimacy of the operation, as validated through signature checks and nonce verification.
-
Fund Management (FM): Handles the logistics of fund withdrawal requests from users, including validation of signatures and ensuring the security and authorization of the withdrawal operations.
-
Stake Management (SM): Interacts with the EntryPoint for managing stakes required for the operation of Paymasters within the account abstraction framework, ensuring the Paymaster has sufficient stake for transaction sponsorship.
-
MultiOwnable (MO): Manages ownership of the user account, allowing for multiple owners to control and manage the account through collective or individual permissions.
-
WebAuthn (WA): Provides an additional layer of security for authentication, allowing users to utilize WebAuthn as a method for verifying their identity during transactions or ownership management operations.
This architecture provides a comprehensive system for managing smart contract-based accounts, ensuring secure transactions through robust authentication mechanisms, facilitating account abstraction, and managing funds and ownership through a decentralized framework.
SequenceDiagram

Sequence Diagram Overview:
-
User Initiates a Transaction: The user starts the process by attempting to perform a transaction through their User Account (smart contract wallet).
-
Signature Validation: The User Account requests signature validation, which can involve traditional ECDSA checks or WebAuthn for more sophisticated authentication mechanisms.
-
Transaction Submission: Once the signature is validated, the User Account submits the transaction to the EntryPoint, which acts as a hub for account abstraction operations.
-
Gas Sponsorship Request: The EntryPoint forwards the transaction to the Paymaster for gas sponsorship, essential for executing the transaction.
-
Withdraw Request Verification: If the transaction involves withdrawing funds, the Paymaster verifies the signature associated with the withdraw request to ensure its legitimacy.
-
Funds Check: The Paymaster checks available funds to cover the transaction and potentially the withdraw request, interacting with the Fund Management component.
-
Sponsorship Confirmation & Execution: Once the Paymaster confirms sponsorship, the EntryPoint proceeds to execute the transaction.
-
Ownership Operation: The User Account can perform ownership-related operations, managed by the MultiOwnable component for cases involving multiple owners.
-
Authentication: For certain operations, additional user authentication might be required, which is where WebAuthn comes into play, providing a secure method of verifying the user's identity.
-
Stake Management: The Paymaster interacts with the Stake Management to handle stakes associated with the EntryPoint, ensuring there are sufficient funds to cover potential transactions.
This sequence outlines a comprehensive interaction flow within a system designed to leverage account abstraction, ensuring transactions can be executed securely and efficiently while providing mechanisms for ownership management and advanced authentication.
MultiOwnable.sol

Functionality of Functions in the MultiOwnable Smart Contract
addOwnerAddress
- Purpose: Allows adding a new owner to the contract using an Ethereum address. This facilitates straightforward ownership management.
- Usage: Can only be called by an existing owner (enforced through the
onlyOwner
modifier). The input is an Ethereum address, which is then encoded and added as a new owner.
addOwnerPublicKey
- Purpose: Facilitates adding a new owner using a public key, specifically targeting use cases where owners are identified through public keys rather than Ethereum addresses.
- Usage: Similar to
addOwnerAddress
, this function is restricted to existing owners. It accepts the x
and y
coordinates of a public key, encodes them, and adds the result as a new owner.
removeOwnerAtIndex
- Purpose: Removes an owner from the contract based on a specified index. This is useful for managing the dynamic nature of ownership.
- Usage: Only callable by an existing owner. It checks if the specified index has a registered owner and, if so, deletes the owner from storage.
isOwnerAddress
- Purpose: Checks if a given Ethereum address is registered as an owner of the contract.
- Usage: Publicly accessible. Returns true if the input address is an owner, false otherwise.
isOwnerPublicKey
- Purpose: Determines if a public key (given by its
x
and y
coordinates) is registered as an owner.
- Usage: Public function that returns true if the public key is an owner, otherwise false.
isOwnerBytes
- Purpose: Verifies if the provided raw bytes (representing either an Ethereum address or public key coordinates) correspond to a registered owner.
- Usage: Public visibility. Useful for cases where the owner identity format is not predetermined.
ownerAtIndex
- Purpose: Retrieves the raw bytes representing an owner (could be an Ethereum address or public key coordinates) based on the given index.
- Usage: Publicly accessible, returns the owner's raw bytes at the specified index, or an empty byte array if no owner is registered there.
nextOwnerIndex
- Purpose: Provides the next available index for adding a new owner. This helps in determining where the next owner will be added in the contract's storage.
- Usage: Public function that returns an integer representing the next index for a new owner.
_initializeOwners
- Purpose: Initializes the contract with a list of owners. Intended for use at contract deployment to set initial ownership.
- Usage: Internal function that takes an array of raw bytes (each representing an owner) and registers them as owners. Validates the length of the input to ensure it matches expected formats for addresses or public keys.
_addOwner
- Purpose: A convenience function that encapsulates the process of adding a new owner, abstracting away the indexing logic.
- Usage: Internal function called within
addOwnerAddress
and addOwnerPublicKey
to add the provided owner to the contract.
_addOwnerAtIndex
- Purpose: Directly adds an owner at a specific index, performing checks to ensure the owner is not already registered.
- Usage: Internal function that facilitates adding owners with more control over storage indices.
_checkOwner
- Purpose: Validates whether the caller of a function is an authorized owner or the contract itself, providing a basic access control mechanism.
- Usage: An internal function used by the
onlyOwner
modifier to restrict access to certain contract functions.
_getMultiOwnableStorage
- Purpose: Retrieves a reference to the contract's storage space dedicated to managing ownership information.
- Usage: Internal function providing low-level access to ownership data storage, utilizing Solidity's assembly language for direct memory manipulation.
Each function in the MultiOwnable
contract plays a specific role in managing ownership, from adding and removing owners to validating ownership and managing access control. The use of raw bytes for owner representation allows for flexibility in identifying owners, accommodating both Ethereum addresses and public key coordinates.

ERC1271.sol

ERC-1271 With Cross Account Replay Protection Smart Contract Function Descriptions
eip712Domain
- Purpose: Provides detailed information about the EIP-712 domain used to create compliant hashes. It specifies the domain fields used to construct a domain separator for signing data.
- Details: Returns a set of values defining the EIP-712 domain, including the domain's name, version, chain ID, verifying contract address, salt, and any extensions to the standard EIP-712 domain fields.
isValidSignature
- Purpose: Validates a given signature against a specified hash, ensuring it matches the expected signer's signature. This function specifically checks against a "replay-safe" version of the hash, adding an extra layer of security.
- Details: Takes an original hash and its corresponding signature, generates a "replay-safe" hash, and checks if the signature is valid for this modified hash. Returns a specific byte code indicating success or failure.
replaySafeHash
- Purpose: Creates a modified version of a given hash to prevent cross-account replay attacks. It does this by incorporating the contract's address and chain ID into the hash, making it unique to each account and chain.
- Details: Accepts an original hash and returns a new hash that is compliant with EIP-712, including additional data to ensure it cannot be reused across different accounts or chains.
domainSeparator
- Purpose: Calculates and returns the domain separator for the contract, which is a unique identifier used in the EIP-712 signing process to prevent certain types of replay attacks.
- Details: Constructs the domain separator based on the current EIP-712 domain information, including the contract's name, version, chain ID, and address.
_eip712Hash
- Purpose: Generates an EIP-712 compliant hash from a given input, using the contract's domain separator and the structured data's hash.
- Details: Internal function that takes a structured data hash (specifically for the "CoinbaseSmartWalletMessage" type) and returns its EIP-712 compliant hash by combining it with the contract's domain separator.
_hashStruct
- Purpose: Computes the EIP-712 hash of a structured data piece, specifically for "CoinbaseSmartWalletMessage", which includes a given hash as its content.
- Details: Internal function that encodes the structured data (using its type hash and the input hash) and then hashes the result to produce the EIP-712 hashStruct value.
_domainNameAndVersion
- Purpose: Abstract function that must be defined by the implementing contract. It should return the name and version of the signing domain used in EIP-712 domain separation.
- Details: Must be overridden by child contracts to provide specific domain name and version strings relevant to the particular implementation.
_validateSignature
- Purpose: Abstract function that validates a provided signature against a given message. It must be implemented by the contract to define how signature validation is performed.
- Details: Takes a message and its associated signature, and returns a boolean indicating whether the signature is valid. The actual validation logic is to be defined in the implementation.

CoinbaseSmartWalletFactory.sol

Coinbase Smart Wallet Factory Smart Contract Function Descriptions
Constructor
- Purpose: Initializes the smart contract with the address of the ERC-4337 implementation that will be used for deploying new account instances.
- Details: Sets the
implementation
variable to the address of the ERC-4337 implementation provided during the contract deployment.
createAccount
- Purpose: Deploys a new ERC-4337 compatible account using a minimal ERC1967 proxy that points to a predefined implementation. This function also initializes the newly created account with a set of owners.
- Details: Accepts an array of owners and a nonce to create a deterministic address for the new account. If the account with the given parameters hasn't been deployed before, it initializes the account with the provided owners. The function returns the instance of the created account.
getAddress
- Purpose: Computes and returns the deterministic address for an account that would be created with the specified set of owners and nonce. This address is based on the implementation address and the provided parameters.
- Details: Utilizes the
LibClone
library to predict the address of the account that would be created by createAccount
with the same parameters. This allows external entities to know the address of an account before it's actually created.
initCodeHash
- Purpose: Returns the hash of the initialization code used by the ERC1967 proxy. This hash is critical for computing deterministic addresses.
- Details: Calls
LibClone.initCodeHashERC1967
with the address of the ERC-4337 implementation to obtain the hash of the proxy's initialization code.
_getSalt
- Purpose: Generates a deterministic salt value based on the provided owners and nonce. This salt is used in the creation of deterministic addresses for new accounts.
- Details: Encodes the array of owners and the nonce into a single byte array and hashes it to produce a salt value. This internal function supports the deterministic creation process by providing a unique salt for each set of parameters.
Each function within the Coinbase Smart Wallet Factory is designed to facilitate the deployment and management of ERC-4337 accounts. By leveraging the ERC-4337 standard and the ERC1967 proxy pattern, this contract provides a scalable and efficient mechanism for creating and initializing smart contract-based accounts with multiple ownership configurations.

CoinbaseSmartWallet.sol

Coinbase Smart Wallet Smart Contract Function Descriptions
Constructor
- Initializes the contract, setting up initial states or configurations that do not rely on external inputs. It prepares the contract for use, following deployment.
initialize
- Prepares the wallet with initial settings, particularly the assignment of owners if it has not been previously initialized. This ensures the wallet is ready for operation with designated control.
validateUserOp
- Processes and validates a
UserOperation
, ensuring it adheres to specified criteria such as signature validity and nonce correctness. This step is critical for transaction execution through account abstraction.
executeWithoutChainIdValidation
- Allows execution of transactions without validating the chain ID. This functionality supports operations that must be consistent across different chains, enhancing interoperability.
execute
- Facilitates the execution of specified calls or transactions from the wallet. This function is pivotal for carrying out intended actions on the blockchain.
executeBatch
- Executes multiple calls or transactions in a single operation, optimizing transaction execution by batching together several operations.
entryPoint
- Identifies the EntryPoint contract address, which is essential for interacting with the account abstraction layer and facilitating user operations.
getUserOpHashWithoutChainId
- Generates a hash for a
UserOperation
excluding the chain ID, supporting operations that are chain-agnostic.
implementation
- Provides the address of the contract's implementation, relevant for upgradeable contracts using the proxy pattern.
canSkipChainIdValidation
- Determines whether a function call can bypass chain ID validation based on its selector, adding flexibility to operations that require cross-chain compatibility.
_call
- A low-level function to execute calls to other contracts or addresses. This is a foundational operation for interacting with the broader Ethereum ecosystem.
_validateSignature
- Validates the signature associated with a transaction or operation, ensuring it originates from an authorized source. This function is crucial for security and preventing unauthorized actions.
_authorizeUpgrade
- Restricts upgrade operations to authorized entities, ensuring only designated owners can modify the contract's logic.
_domainNameAndVersion
- Supplies information about the domain and version used in signature verification, aiding in the creation of EIP-712 compliant messages.

WebAuthn.sol

WebAuthn Library Function Descriptions
verify
- Purpose: Confirms the authenticity of a WebAuthn authentication assertion, following a specific subset of verification steps from the WebAuthn specification. It checks the integrity and origin of the authentication assertion using the given challenge, user verification requirement, signature, and the public key coordinates.
- Operation:
- Validates that the "user present" and, if required, "user verified" flags are set within the authenticator data.
- Confirms that the client data JSON indicates a "webauthn.get" operation and contains the expected challenge.
- Verifies the signature over the concatenated authenticator data and client data JSON hash, ensuring it matches the provided public key.
- Utilizes the RIP-7212 precompiled contract for secp256r1 signature verification if available; otherwise, falls back to the FreshCryptoLib implementation.
- Guards against signature malleability by checking the 's' value of the signature.
The verify
function is designed to ensure the integrity and origin of WebAuthn authentication assertions in a blockchain context, incorporating elements such as signature verification and challenge confirmation while accommodating the specific operational requirements and assumptions of blockchain applications.

FCL.sol

Fresh CryptoLib (FCL) Functionality Explained
Constants
Defines constants related to the curve and operations:
- MODEXP_PRECOMPILE: Address for the modular exponentiation precompile used for efficient mathematical operations.
- Curve Parameters: Includes the prime field modulus (
p
), curve coefficients (a
and b
), base point coordinates (gx
and gy
), curve order (n
), and constants for optimization (minus_2
, minus_2modn
, minus_1
).
ecdsa_verify
- Purpose: Verifies an ECDSA signature given a message hash, signature components (
r
and s
), and the public key coordinates (Qx
and Qy
) of the signer.
- Operation: Checks the signature against the curve-defined parameters and the message, ensuring it was signed by the holder of the private key corresponding to the provided public key.
ecAff_isOnCurve
- Purpose: Determines if a point, defined by its
x
and y
coordinates, lies on the defined elliptic curve.
- Operation: Utilizes the elliptic curve equation to verify if the point satisfies the curve's equation.
FCL_nModInv
- Purpose: Computes the modular inverse of a number under the curve's order (
n
) using the modular exponentiation precompile for efficiency.
- Operation: Employs Fermat's Little Theorem for the modular inverse calculation, essential for cryptographic operations like signature verification.
ecZZ_mulmuladd_S_asm
- Purpose: Efficiently computes the combination of scalar multiplications (
scalar_u * G + scalar_v * Q
) using Strauss-Shamir's trick for ECDSA signature verification.
- Operation: Optimizes ECDSA signature verification through simultaneous multiple scalar multiplication, crucial for verifying signatures with less computational overhead.
ecAff_add
- Purpose: Adds two points on the elliptic curve in affine coordinates, handling edge cases like point doubling and the identity element.
- Operation: Implements elliptic curve point addition according to curve algebra, ensuring correct addition results within the curve's group structure.
ecAff_IsZero
- Purpose: Checks if a given elliptic curve point, represented in affine coordinates, is the identity element (zero point) of the curve.
- Operation: Identifies the curve's identity element, facilitating operations like point addition and scalar multiplication where the identity element has special rules.
ecZZ_SetAff
- Purpose: Converts a point from projective (or Jacobian) coordinates back to affine coordinates, which are more straightforward to work with for certain operations.
- Operation: Utilizes modular inversion to normalize projective coordinates to affine, necessary for finalizing cryptographic operations like signature verification.
ecZZ_Dbl
- Purpose: Doubles a point on the elliptic curve, given in projective coordinates, as part of elliptic curve point multiplication algorithms.
- Operation: Implements the point doubling formula specific to elliptic curves, optimizing the doubling operation in the context of ECDSA verification and other cryptographic algorithms.
ecZZ_AddN
- Purpose: Adds two elliptic curve points given in mixed coordinates, optimizing the addition for cryptographic applications like ECDSA.
- Operation: Efficiently combines points on the elliptic curve, respecting the algebraic structure of the curve, and optimizing for cases encountered in cryptographic routines.
FCL_pModInv
- Purpose: Calculates the modular inverse of a number under the elliptic curve's prime field modulus (
p
) using the modular exponentiation precompile.
- Operation: Applies Fermat's Little Theorem for calculating the modular inverse, a crucial step in cryptographic operations like signature verification and key generation.
The FCL library provides foundational operations for elliptic curve cryptography, focusing on efficiency and security, essential for implementing ECDSA signature verification and other cryptographic protocols on Ethereum.

MagicSpend.so

Magic Spend Smart Contract Functionality Explained
Constructor
- Initializes the contract by setting the initial owner through the
Ownable
pattern.
Receive ETH
- Allows the contract to receive Ether directly without a function call.
Validate Paymaster User Operation
- Validates an ERC-4337
UserOperation
for withdrawal requests, ensuring the request does not exceed the gas cost, is funded sufficiently, and has a valid signature. This method integrates with the ERC-4337 EntryPoint as a Paymaster.
Post Operation Handling
- Finalizes the transaction after user operation execution, handling the transfer of funds back to the user or managing gas costs.
Withdraw Gas Excess
- Enables users to withdraw any excess funds that were allocated for gas but not used during transaction execution.
Withdraw Funds
- Allows users to withdraw specified assets from the contract based on a signed withdrawal request.
Owner Withdraw
- Provides an exclusive function for the contract owner to withdraw assets to a specified beneficiary.
Deposit to EntryPoint
- Allows the owner to deposit ETH from the contract into the EntryPoint contract, facilitating future transactions.
Withdraw from EntryPoint
- Enables the contract owner to withdraw deposited funds from the EntryPoint to a specified beneficiary.
Add Stake to EntryPoint
- Allows the contract owner to add a stake to the EntryPoint, locking funds to meet the EntryPoint's staking requirements.
Unlock Stake from EntryPoint
- Permits the contract owner to initiate the unstaking process, making funds available for withdrawal after a cooldown period.
Withdraw Stake from EntryPoint
- Enables the contract owner to withdraw previously staked funds from the EntryPoint after they have been unlocked.
Validate Withdraw Signature
- Validates the signature associated with a withdrawal request, ensuring it matches the expected format and signer.
Get Hash for Withdraw Request
- Generates a hash for a withdrawal request, which is used to validate the request's signature.
Check Nonce Usage
- Determines if a specific nonce has already been used by an account to prevent replay attacks.
EntryPoint Address
- Provides the canonical address of the ERC-4337 EntryPoint contract the Paymaster interacts with.
Internal Functions:
- _validateRequest: Performs preliminary checks on a withdrawal request before processing.
- _withdraw: Handles the withdrawal of specified assets to a designated beneficiary.
This smart contract serves as a Paymaster for ERC-4337 transactions, managing funds, ensuring transactions are properly funded, and facilitating withdrawals. It implements security checks such as signature validation and nonce management to prevent unauthorized access and replay attacks.

Risk Assessment of the Smart Contract System
Centralization Risks
- Owner Privileges: With specific functions exclusively available to the contract's owner (e.g.,
ownerWithdraw
, entryPointDeposit
), there's a risk tied to the centralization of control. Malicious actions or security breaches involving the owner's account could lead to unauthorized asset transfers or manipulation of contract settings.
- Single Point of Failure: The reliance on specific addresses (e.g., the EntryPoint address in
MagicSpend
) introduces central points of failure. Should these addresses be compromised or become inactive, it could disrupt the system's functionality.
Systematic Risks
- External Dependency: The contracts rely heavily on external contracts and libraries (e.g.,
SafeTransferLib
, SignatureCheckerLib
). Changes or vulnerabilities in these dependencies could adversely affect the system's security and operability.
- Blockchain-Specific Risks: The contracts are exposed to risks inherent to the blockchain they are deployed on, including but not limited to, network congestion, changes in gas prices, and major forks. These factors could impact transaction costs and execution times, affecting user experience and contract reliability.
Architecture Risks
- Upgradeability: While upgradeability (via UUPS pattern in
CoinbaseSmartWallet
) ensures flexibility and the ability to fix bugs, it also introduces risks. Improperly managed upgrades could introduce vulnerabilities, disrupt service, or inadvertently change critical business logic.
- Cross-Contract Interactions: The system's reliance on interactions between multiple contracts (e.g., the interaction between
MagicSpend
and the EntryPoint contract) increases complexity and the potential for unintended behaviors, especially when contracts evolve independently over time.
Complexity Risks
- Smart Contract Interactions: The architecture involves multiple smart contracts with intricate interactions, including fund management, stake management, and execution of operations. The complexity of these interactions increases the likelihood of bugs or vulnerabilities, potentially leading to loss of funds or unauthorized access.
- Signature and Authentication Mechanisms: The system's security heavily relies on signature verification and authentication mechanisms (e.g.,
ERC1271
, WebAuthn
in verification). Complexity in these areas could lead to vulnerabilities, especially with non-standard signature formats or when integrating with external authentication systems.
Each of these risk areas requires careful consideration and ongoing monitoring to mitigate potential adverse impacts on the system and its users. Regular audits, thorough testing, and a robust security framework are critical to managing these risks effectively.
Conclusion
The smart contract system presents a sophisticated and flexible infrastructure for managing digital assets, authentication, and execution of operations within a blockchain environment. While it leverages advanced features like upgradeability and external dependencies to enhance functionality, it also introduces centralization, systematic, architectural, and complexity risks that necessitate rigorous security measures, including audits and testing. Overall, the system's success hinges on balancing innovation with robust risk management practices to ensure security and reliability.
Time spent:
13 hours