A smart contract Wallet can be defined as a device or application that lets users customise the way they would prefer to manage their digital assets.
One very important skill of a smart contract developer is understanding a understanding transactions in the EVM, having a sound knowledge of gas use and optimisation, harnessing the power of low level calls, understanding the security risks and sticking to safe smart contract writing patterns. All this principles are covered in this simple solidity project.
Overview
The projects implementation is broken into 4 sections:
Implementing a smart contract owner and restricting certain functionalities to the owner only.
Allowing the smart contract to receive funds from EOA and other contracts.
The funds transfer functionality
The change of owner voting system implementation.
Implementing a smart contract owner
The nature of a smart contract that makes it not modifiable after deployment necessitates very important functionalities to be "Authorised" before access is granted. The lowest level of access grant in a smart contract is the implementation of a smart contract owner.
The owner of a smart contract is the address that deploys the smart contract to the blockchain. The solidity contract allows for the implementation of constructor. The constructor enables a black of code to be implemented first in the creation of the smart contract and only once. A variable owner of type address is created, this is a state variable and of type address. The owner is assigned the value msg.sender using the global variables available in a smart contract.
The Funds Receive functionality
A smart contract has an address , hence can receive funds and make transactions. There are a few ways a smart contract can be made to receive funds. One is by creating a "depositFund" function that is labelled payable, the other is by using a payable fall back function. One other option which was utilised in this smart contract is to use a receive functionality. The receive function differs from a fallback in that it cannot receive data, and is the first default function called when a low level payment to the smart contract is triggered.
The receive function does not access storage or make a function call, hence the 2300 gas stipend would be sufficient for the transaction. None the less, it is a better practice to use low level function call where the transaction sender attaches more gas to the send function in a contract to cater for additional cost on fund transfer to a contract.
The funds transfer functionality
the transfer functionality is a function that utilizes many require statement to ensure proper checks are made before funds are transfers.
Three require checks are made: the first ensures that the amount to be transferred is less or at most equal to the funds in the smart contract.
The second require statement checks the mapping created that allows specific addresses to be recipients of the smart contract funds. The mapping "isAllowedToSend" is used to grant permission to withdraw funds by the smart contract owner.
The third require statement ensures that the amount to be transferred to an account is less than or equals the amount the owner has previously set.
To prevent the re-entrancy attack where, as a result of excess gas provided for transactions with external contracts they can still access the source contract and try to change state variables. Following the best practice the transfer functionality interacts last with external contracts.
Firstly we deduct the amount to be transferred from the smart contract before the actual transfer transaction is made.
Transfers can be done using at leat three methods:
- _address.transfer()
- _address.send()
- _to.call{value: _amount, gas: 100000}(payload);
The third methods is referred to as a low level call. This method is usually used when ever you have no knowledge of what address the recipients of your funds transfer. When the transfer is done to other EOA(Externally owned Addresses) then any of the methods above is safe, if the transfer is to a smart contract, then the transaction would fail if the receive or fallback functionality interacts with the contract. The reason for this failure is that basic transfer functionalities only make the stipend gas available for transactions, only low level calls can be used to include a stipulated gas cost with the transaction.
The response of a low level call, must be assigned to check if the transaction was successful.
The change of owner voting system implementation.
The smart contract implements a simple voting system that allows for change of ownership. This could easily be a useful feature when the governance of a smart contract need to be changed, or owner demise.
The voting system ensures the owner of a smart contract selects at least three guardians who have the ability to elect the next address as the smart contract owner.
As soon as an address has 3 guardians selection, then the address becomes the new smart contract owner and perform functions restricted to the smart contract owner.
There is the link to the smart contract code on Github. Feel free to reach out to me on LinkedIn.
Further articles to this would be published, deploying a smart contract to a local blockchian, deploying to a test net such as Sepolia, deploying to a layer 2 solution (ZK SNARK).
Top comments (3)
Feel free to leave comments, i'd make sure to respond to them.
What are some security best practices for using a smart contract wallet?
hey @parth51199 , one very important step is auditing. The web3 space is has some projects dedicated to security like the Openzeppilin and a few others. Always make sure you test ant audit your smart contract before deployment.