Smart Wallet Implementation with Solidity

Muhammad Waqas
Coinmonks
6 min readJun 30, 2024

--

Smart Wallet

Photo by CardMapr.nl on Unsplash

Requirements

  1. Single Owner: The wallet has one owner.
  2. Fund Reception: The wallet should be able to receive funds, no matter what.
  3. Fund Spending: It is possible for the owner to spend funds on any kind of address, whether it’s an Externally Owned Account (EOA — with a private key) or a Contract Address.
  4. Allowance Management: It should be possible to allow certain people to spend up to a certain amount of funds.
  5. Owner Change by Guardians: It should be possible to set the owner to a different address by a minimum of 3 out of 5 guardians, in case funds are lost.

Overview

In this article, we will explore the implementation of a smart wallet using Solidity. We’ll cover the essential concepts such as mappings, structs, exceptions, and low-level calls in Solidity. We’ll also provide a comprehensive example to illustrate these concepts in action.

Solidity Mappings

Mappings in Solidity are a data structure that store key-value pairs. They are similar to hash tables or dictionaries in other programming languages. Mappings are useful for associating unique keys with specific values.

In our smart wallet, we use mappings to keep track of allowances and permissions for different addresses. The allowance mapping associates an address with the amount they are allowed to spend, while the isAllowedToSend mapping keeps track of which addresses are permitted to send transactions.

Structs

Structs in Solidity are custom data types that allow you to group variables. They are useful for modeling complex data structures.

In the example smart wallet, we do not explicitly define a struct for guardians, but the concept is illustrated. Structs can be used to store information about guardians, such as their address and whether they have approved a new owner.

Structs & Mapping

Combining structs and mappings allows us to create more sophisticated data models. For example, we could have a mapping of addresses to structs that contain multiple pieces of information.

This approach can help manage more complex data, such as keeping track of multiple pieces of information for each guardian.

Exceptions: Require

The require statement is used to validate conditions before executing further code. If the condition is not met, it reverts the transaction.

We use require to ensure that only authorized users can perform certain actions in the smart wallet, such as setting allowances or denying permissions.

Exceptions: Assert

The assert statement is used to test for conditions that should never be false. If an assert fails, it indicates a serious bug in the contract.

This ensures that the number of guardian confirmations is at least the required amount before proceeding with the owner change.

Try/Catch in Solidity

The try/catch statement is used to handle exceptions during external function calls or contract interactions. It helps to manage errors gracefully.

This allows the contract to handle potential failures in a controlled manner.

Low-Level Solidity Calls in Depth

Low-level calls provide a way to interact with contracts directly. They are more flexible but require careful handling of returned data and error management.

We use low-level calls to transfer funds and execute payloads in our smart wallet. This allows for sending ETH and invoking functions on other contracts in a flexible manner.

The Smart Contract Wallet Implementation

Below is the complete implementation of the smart wallet contract in Solidity. This contract allows the owner to manage allowances, permissions, and transfers, with built-in security features like guardian confirmations.

Explanation of the Smart Wallet Contract

  1. Owner Initialization:
  • The constructor sets the owner of the wallet to the address that deploys the contract.

2. Proposing a New Owner:

  • The proposeNewOwner function allows guardians to propose a new owner for the wallet.
  • A new owner can only be set if a minimum of 3 out of 5 guardians approve the change.
  • This mechanism ensures that the owner’s address can be updated securely in case of emergencies.

3. Setting and Denying Allowances:

  • The setAllowance function allows the owner to set spending limits for specific addresses.
  • The denySending function allows the owner to revoke spending permissions for specific addresses.
  • These functions ensure that only authorized addresses can spend up to a certain limit.

4. Transferring Funds:

  • The transfer function allows the owner or allowed addresses to transfer funds from the wallet.
  • It uses low-level calls to execute transactions and includes checks to ensure the transaction conditions are met.

5. Receiving Funds:

  • The receive function is a special function in Solidity that allows the contract to accept ETH sent to it.

Remix IDE Deployment and Interaction

To test and deploy this smart contract, we use Remix IDE, a powerful tool for developing, deploying, and managing smart contracts. Here’s how to interact with the smart wallet and consumer contracts in Remix IDE.

Steps to Deploy and Interact with the Contracts:

  1. Deploying the Contracts:
  • Deploy the above given code on remix. Below is the view on the remix:

2. Interacting with the Consumer Contract:

  • Once the Consumer contract is deployed, you will see options like deposit and getBalance.
  • You can use the deposit function to send ETH to the contract.
  • Use the getBalance function to check the current balance of the contract.

3. Interacting with the SampleWallet Contract:

  • After deploying the SampleWallet contract, you will see functions like denySending, proposeNewOwner, setAllowance, and transfer.
  • Set an allowance for a specific address using the setAllowance function.
  • Use the proposeNewOwner function to propose a new owner and get guardian approvals.
  • Transfer funds using the transfer function.

Workflow:

  1. Deposit Funds:
  • Use the deposit function in the Consumer contract to add funds.
  • Check the balance using getBalance.

2. Set Allowance and Permissions:

  • Set an allowance for an address with the setAllowance function.
  • Check the allowance using the allowance function.

3. Transfer Funds:

  • Use the transfer function in the SampleWallet contract to transfer funds to another address.
  • Ensure the sender has the required permissions and allowance.

4. Change Owner:

  • Guardians can propose a new owner using the proposeNewOwner function.
  • Collect confirmations from guardians and set the new owner.

This smart wallet contract demonstrates the use of mappings, structs, exceptions, low-level calls, and other Solidity features. It provides a secure and flexible way to manage funds and permissions, with built-in mechanisms for owner changes and guardian confirmations

--

--