Introduction
In a world where digital assets and cryptocurrencies are fast becoming an integral part of our lives, ensuring the smooth transfer of these assets to loved ones after demise has become a crucial consideration. The decentralized and secure nature of blockchain technology opens up new possibilities for creating inheritance contracts that can automate and streamline asset transfers to next of kin.
Celo, with its focus on financial inclusion and mobile-first approach, provides a robust platform for implementing such inheritance contracts. By leveraging the power of smart contracts on Celo, individuals can establish a transparent and immutable mechanism to distribute their assets among their chosen beneficiaries.
In this practical guide, we will delve into the process of creating an inheritance smart contract on Celo. We will explore the fundamental concepts of smart contracts, address inheritance rules and considerations, and provide step-by-step instructions for implementing a secure and efficient asset transfer mechanism.
You can find the repository for this tutorial Here
Prerequisites
To follow this tutorial, you will need the following:
- Basic understanding of Solidity and smart contracts.
- A Development Environment Like Remix.
- The Celo Extension Wallet which can be downloaded here.
- To get testnest funds, go to Celo faucet
Contract Developement
The complete code contract look like this;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AssetTransfer {
address public owner;
bool public deceased;
uint256 public createdAt;
uint256 public celoBalance;
address[] familyWallets;
mapping(address => uint256) inheritance;
event InheritanceSet(address indexed wallet, uint256 amount);
event Payout(address indexed wallet, uint256 amount);
event Deceased();
constructor() payable {
owner = msg.sender;
createdAt = block.timestamp;
celoBalance = msg.value;
deceased = false;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can call this function");
_;
}
modifier mustBeDeceased() {
require(deceased == true, "The owner must be marked as deceased");
_;
}
function getTotalInheritance() public view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < familyWallets.length; i++) {
total += inheritance[familyWallets[i]];
}
return total;
}
function setInheritance(address wallet, uint256 amount) public onlyOwner {
require(wallet != address(0), "Invalid wallet address");
require(amount > 0, "Inheritance amount must be greater than zero");
require(
celoBalance >= getTotalInheritance() + amount,
"Total inheritance exceeds contract balance"
);
familyWallets.push(wallet);
inheritance[wallet] = amount;
emit InheritanceSet(wallet, amount);
}
function payout() private mustBeDeceased {
for (uint256 i = 0; i < familyWallets.length; i++) {
address payable wallet = payable(familyWallets[i]);
uint256 amount = inheritance[wallet];
wallet.transfer(amount);
emit Payout(wallet, amount);
}
}
function markAsDeceased() public onlyOwner {
deceased = true;
payout();
emit Deceased();
}
receive() external payable {
// Allow the contract to receive funds
}
}
Code Breakdown
Let’s look at our smart contract in detail.
State Variables
address public owner;
bool public deceased;
uint256 public createdAt;
uint256 public celoBalance;
address[] familyWallets;
mapping(address => uint256) inheritance;
owner
: Stores the address of the contract owner.deceased
: Indicates whether the owner is marked as deceased or not.createdAt
: Stores the timestamp when the contract was created.celoBalance
: Stores the balance of CELO tokens in the contract.familyWallets
: An array to store the addresses of the family wallets.inheritance
: A mapping to store the inheritance amount corresponding to each family wallet address.
Events
event InheritanceSet(address indexed wallet, uint256 amount);
event Payout(address indexed wallet, uint256 amount);
event Deceased();
InheritanceSet
: Triggered when an inheritance amount is set for a family wallet.Payout
: Triggered when a payout is made to a family wallet.Deceased
: Triggered when the owner is marked as deceased.
Constructor
constructor() payable {
owner = msg.sender;
createdAt = block.timestamp;
celoBalance = msg.value;
deceased = false;
}
The constructor is executed when the contract is deployed. It initializes the state variables:
- Sets the
owner
as the address of the contract deployer (sender). - Sets the
createdAt
timestamp as the current block timestamp. - Sets the
celoBalance
as the value (CELO tokens) sent along with the contract deployment transaction. - Sets
deceased
asfalse
initially.
Modifiers
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can call this function");
_;
}
modifier mustBeDeceased() {
require(deceased == true, "The owner must be marked as deceased");
_;
}
onlyOwner
: Ensures that a function can only be called by the contract owner.mustBeDeceased
: Ensures that a function can only be called if the value oddeceased
becometrue
.
The getTotalInheritance
Function
function getTotalInheritance() public view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < familyWallets.length; i++) {
total += inheritance[familyWallets[i]];
}
return total;
}
The getTotalInheritance
function iterates over the family wallets and adds up the corresponding asset value to calculate the total inheritance. This allows anyone to view the total amount of inheritance stored in the contract without modifying the contract state.
The setInheritance
Function
function setInheritance(address wallet, uint256 amount) public onlyOwner {
require(wallet != address(0), "Invalid wallet address");
require(amount > 0, "Inheritance amount must be greater than zero");
require(
celoBalance >= getTotalInheritance() + amount,
"Total inheritance exceeds contract balance"
);
familyWallets.push(wallet);
inheritance[wallet] = amount;
emit InheritanceSet(wallet, amount);
}
The setInheritance
function allows the contract owner to set the inheritance amount for a specific family wallet. It performs input validations, checks the total inheritance against the contract balance, stores the inheritance amount, and emits an event to record the update.
The payout
Function
function payout() private mustBeDeceased {
for (uint256 i = 0; i < familyWallets.length; i++) {
address payable wallet = payable(familyWallets[i]);
uint256 amount = inheritance[wallet];
wallet.transfer(amount);
emit Payout(wallet, amount);
}
}
The payout
function is responsible for distributing the inheritance to the designated family wallets. It loops through the family wallets, transfers the corresponding amount of CELO to each wallet, and emits a Payout
event for each successful transfer. The function can only be executed if the contract owner has been marked as deceased.
The markAsDeceased
Function
function markAsDeceased() public onlyOwner {
deceased = true;
payout();
emit Deceased();
}
The markAsDeceased
function allows the contract owner to trigger the inheritance payout process by marking themselves as deceased. It sets the deceased
flag, calls the payout function to distribute the inheritance, and emits a Deceased
event.
Deployment
To deploy our smart contract, go to Remix IDE.
Copy and paste the smart contract > Compile File > Then Deploy in an Injected Provider environment.
Conclusion
In conclusion, the above smart contract provides a practical solution for implementing an inheritance mechanism on Celo. The contract allows the contract owner to designate family wallets and assign inheritance amounts to each wallet. Upon marking the owner as deceased, the contract automatically distributes the inheritance to the designated family wallets.
By leveraging the capabilities on Celo and incorporating checks and balances within the smart contract, the Inheritance contract provides a secure and efficient solution for transferring assets to next of kin or family members, enabling individuals to plan and manage their inheritance in a decentralized and automated manner.
Next Step
You may consider adding functionalities such as multi-signature authorization for inheritance decisions or implementing additional security measures to protect the contract and assets.
Also, additional function which allows our contract to receive additional funds can also be added.
The functionality of the contract can also become fully automated by connecting to oracles that can monitor death records.
About the Author
Emiri Udogwu, a licensed medical doctor with a burning passion for technology and gifted with skills for spreading knowledge and propagating ideas. A web3 and frontend developer.