How to Make Allowance based Smart Contracts on Ethereum

Posted By : Niraj

Aug 24, 2020

What is a Smart Contract

 

A smart contract is a PC program or an exchange convention that consequently executes, controls, or reports important occasions and activities as per the particulars of an agreement or an understanding legtimately. 


The thought of smart contracts was first proposed by Nick Szabo in 1994. Szabo is a legitimate researcher and cryptographer known for laying the preparation for computerized money. In those days, there was little intrigue or action in brilliant agreements because that there was no computerized stage for making contracts.

 

Blockchain is perfect for putting away keen agreements given its innovation, security, and unchangeble nature. A keen agreement information is encoded on a common record, making it difficult to lose the data put away in the blocks.

 

Developers can store practically any sort of information on blockchain, and they have a wide assortment of exchange alternatives to browse during savvy contract sending.

 

The code we will break down now makes an essential type of digital money. Any individual who has an Ethereum keypair can trade these coins. Be that as it may, just the agreement maker can give new ones.

 

Now, we will create smart contracts for allowance wallet.

 

Creation of Allowance Based Wallet

 

Step 1 – We Define the Basic Smart Contract

 

It is a very basic smart contract. It can receive Ether and it’s possible to withdraw Ether, but all in all, not very
useful quite yet. Let’s see if we can improve this a bit in the next step.

 

pragma solidity ^0.6.1;
contract SharedWallet {

 function withdrawMoney(address payable _to, uint _amount) public {
 _to.transfer(_amount);
 }

 //prior sol0.6 the receive function is the funciton() external payable
 receive() external payable {

 }
}

 

Also, Read | Solidity Smart Contract Vulnerabilities and Ways To Mitigate Them

Step 2 – Permissions: Allow only the Owner to Withdraw Ether

 

In this step, we restrict withdrawal to the owner of the wallet. How can we determine the owner? It’s the user who
deployed the smart contract.

 

pragma solidity ^0.6.1;
contract SharedWallet {
address owner;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "You are not allowed");
_;
}
function withdrawMoney(address payable _to, uint _amount) public onlyOwner {
_to.transfer(_amount);
}
receive() external payable {
}
}

 

 

Step 3 – Permissions: Use Re-Usable Smart Contracts from OpenZeppelin

 

Having the owner-logic directly in one smart contract isn’t very easy to audit. Let’s break it down into smaller parts
and re-use existing audited smart contracts from OpenZeppelin for that. The latest OpenZeppelin contract does not
have an owner () function anymore, so we have to create our own. Note that the owner () is a function from the
Ownable.sol contract.

 

pragma solidity ^0.6.1;
import " https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol ";
contract SharedWallet is Ownable {
function isOwner() internal view returns(bool) {
return owner() == msg.sender;
}
function withdrawMoney(address payable _to, uint _amount) public onlyOwner {
_to.transfer(_amount);
}
receive() external payable {
}
}

 

Also, read | Publishing a Smart Contract on Geth Console

Step 4 – Permissions: Add Allowances for External Roles


In this step, we are adding a mapping so we can store the address => uint amounts. This will be like an array that stores
[0x123546...] an address, to a specific number. So, we always know how much someone can be withdrawn. We also add
a new modifier that checks: Is it the owner itself or just someone with allowance?

 

pragma solidity ^0.6.1;
import " https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol ";
contract SharedWallet is Ownable {
function isOwner() internal view returns(bool) {
return owner() == msg.sender;
}
mapping(address => uint) public allowance;
function addAllowance(address _who, uint _amount) public onlyOwner {
allowance[_who] = _amount;
}
modifier ownerOrAllowed(uint _amount) {
require(isOwner() || allowance[msg.sender] >= _amount, "You are not allowed!");
_;
}
function withdrawMoney(address payable _to, uint _amount) public ownerOrAllowed(_amoun
t) {
require(_amount <= address(this).balance, "Contract doesn't own enough money");
_to.transfer(_amount);
}
receive() external payable {
}
}

 

 

Step 5 – Improve/Fix Allowance to avoid Double-Spending


Without reducing the allowance on withdrawal, someone can continuously withdraw the same amount over and
over again. We have to reduce the allowance for everyone other than the owner.

 

function reduceAllowance(address _who, uint _amount) internal ownerOrAllowed(_amount) {
allowance[_who] -= _amount;
}
function withdrawMoney(address payable _to, uint _amount) public ownerOrAllowed(_amoun
t) {
require(_amount <= address(this).balance, "Contract doesn't own enough money");
if(!isOwner()) {
reduceAllowance(msg.sender, _amount);
}
_to.transfer(_amount);
}

 

Step 6 – The Final Smart Contract

 

 

pragma solidity ^0.6.1;
import " https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol ";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/math/SafeMath.sol";
contract Allowance is Ownable {
using SafeMath for uint;
event AllowanceChanged(address indexed _forWho, address indexed _byWhom, uint _oldAmount
, uint _newAmount);
mapping(address => uint) public allowance;
function isOwner() internal view returns(bool) {
return owner() == msg.sender;
}
function setAllowance(address _who, uint _amount) public onlyOwner {
emit AllowanceChanged(_who, msg.sender, allowance[_who], _amount);
allowance[_who] = _amount;
}
modifier ownerOrAllowed(uint _amount) {
require(isOwner() || allowance[msg.sender] >= _amount, "You are not allowed!");
_;
}
function reduceAllowance(address _who, uint _amount) internal ownerOrAllowed(_amount) {
emit AllowanceChanged(_who, msg.sender, allowance[_who], allowance[_who].sub(_amount
));
allowance[_who] = allowance[_who].sub(_amount);
}
function renounceOwnership() public onlyOwner {
revert("can't renounceOwnership here"); //not possible with this smart contract
}
}

 

Leave a

Comment

Name is required

Invalid Name

Comment is required

Recaptcha is required.

blog-detail

March 6, 2024 at 10:05 am

Your comment is awaiting moderation.

By using this site, you allow our use of cookies. For more information on the cookies we use and how to delete or block them, please read our cookie notice.

Chat with Us
Contact Us

Oodles | Blockchain Development Company

Name is required

Please enter a valid Name

Please enter a valid Phone Number

Please remove URL from text