Crypto-Chama: The Management Smart Contract

Ibrahim Aziz
Coinmonks
4 min readSep 27, 2023

--

Part of the Crypto-Chama Savingspool project

Introduction

Welcome to the Crypto-Chama series, where we introduce you to the exciting world of blockchain-based savings pools. In this article, we will explore the Management Contract of the Crypto-Chama project, a decentralized platform designed to simplify savings and investment among groups of individuals.

Read more on what the project is about, and the contents of this 3-Part Series Here

Aim of the Article

The objective of this article is to introduce you to the pivotal role played by the Management Contract within the Crypto-Chama project. Our goal is to delve into its fundamental functions, offering comprehensive insights by providing code snippets for each.

While the potential functionalities of the management smart contract are diverse, in this instance, our focus will be primarily on three crucial aspects: blacklisting defaulters, reinstating previously blacklisted addresses, and facilitating the establishment of “friendlies,” effectively allowing you to whitelist addresses that you trust and wish to include in private chamas.

This exploration will provide you with a solid foundation for understanding the core operations of this integral component.

Intro to Mara Testnet

The Management Contract is deployed on the Mara Testnet, a Layer 2 network integrated with Ethereum and empowered by the native Mara token. Mara offers a fast and scalable solution meticulously tailored to the requirements of the African continent.

Read the Mara Documentation here

Into the Smart Contract

Variables, Structs and Mappings

/* For readability purposes (and in some instances gas saving), ensure you write
Your variables with the variable types following each other */

struct BlacklistVote {
address subject;
uint8 votesFor;
uint8 votesAgainst;
mapping (address => bool) hasVoted;
}

address public owner;
address[] public panel;
mapping (address => bool) public isPanel;
mapping (address => BlacklistVote) public blacklistedRedemption;
mapping (address => bool) public isBlacklisted;
mapping (address =>mapping(address => bool)) public userFriendlies;

1. BlacklistVote Struct

The BlacklistVote struct maintains voting records for decisions related to reinstating blacklisted users. It stores critical information, including the subject’s address, the number of votes in favor, the number of votes against, and a mapping of addresses that have cast their votes.

2. owner Variable

The ‘owner’ variable represents the address of the Management Contract’s owner.

3. panel Array

The ‘panel’ array contains addresses of panelists responsible for voting on the reinstatement of blacklisted users.

4. isPanel Mapping

The ‘isPanel’ mapping is used to verify whether an address is part of the panel of voters.

5. blacklistedRedemption Mapping

‘blacklistedRedemption’ is a mapping that associates each address with a BlacklistVote struct, tracking their voting history.

6. isBlacklisted Mapping

‘isBlacklisted’ is a mapping used to determine if an address is blacklisted.

7. userFriendlies Nested Mapping

‘userFriendlies’ is a nested mapping that establishes whether one address is a friend of another, allowing certain addresses to be whitelisted. This is useful in participating in private pools with people (or addresses in this case) the user is familiar with.

These components are essential for understanding how the Management Contract functions. Now, let’s explore the functions that interact with these variables and mappings in more detail.

Functions

  1. Setting User Friendlies: Users can set other addresses as their “friendlies”. In a chama setting, users may want to only participate in Chamas with people they are familiar with. We validate the parameter entered to ensure:
  • The address input is not invalid(i.e. not 0, or 0x0 in address terms)
  • The address input is not already a friendly of the caller. Why add an address as a friendly twice?
 function setFriendly(address _address) external {
require (_address != address(0), "Invalid Address");
require(!userFriendlies[msg.sender][_address], "Already A Friendly");


//A nested mapping has 2 pointers
userFriendlies[msg.sender][_address] = true;

}

2. Blacklisting an Address: This private function is called by the SavingsPool contract, in case a user defaults payment of their contributions.

function blacklistAddress(address _address) private {
require(msg.sender == SavingsPoolContract, "Unauthorized");
require(_address != address(0), "Invalid Address");
require(!isBlacklisted[_address], "The address is already blacklisted");
isBlacklisted[_address] = true;
}

3. Reinstating a Blacklisted User: Panel voters can vote on reinstating a previously blacklisted address based on the votes of the panel. If a majority of panelists vote in favor, the address can be reinstated. The address will only be reinstated if 60% vote towards their favor

We have a function that allows the Owner to add addresses to the panel of voters below. We need the voters to reinstate the address

function selectManagementVoter(address _address)  external 
{
//Add members to the Voter Panel
require(msg.sender == owner, "Unauthorized");
require(_address !=address(0), "Invalid Address");
require(panel.length < 10, "Too many panelists");
//Add to Array
panel.push(_address);
//Set the isPanel mapping to the input address to true
isPanel[_address] = true;

}

Function to reinstate the address

function reinstateBlacklistedUser(address _address, bool _vote) public {

require(isBlacklisted[_address], "The Address is not blacklisted");
require(_address != address(0), "Invalid Address");
require(isPanel[msg.sender], "Not Allowed to vote");

//Initialize vote as an instance of the Struct BlacklistVote
BlacklistVote storage vote = blacklistedRedemption[_address];


if(_vote == true){
vote.votesFor++;
vote.hasVoted[msg.sender] = true;
}else {
vote.votesAgainst++;
vote.hasVoted[msg.sender] = true;
}


uint totalvotes = vote.votesFor + vote.votesAgainst;


if(totalvotes == panel.length){
if(((vote.votesFor/totalvotes)*100) > 60){
//remove Address from blacklist
isBlacklisted[_address] = false;
}
}


}

Try it out on Mara Testnet: To experiment with the Management Contract and its functions on the Mara Testnet, you can access the contract’s address on the testnet explorer:

Management Contract on Mara Testnet Explorer

and the Github Repo for the code

Feel free to explore, test, and learn about the Crypto-Chama Management Contract. There is much more that can be added to the management contract, e.g. Identity Management, User Roles and more!

In the next articles of this series, we’ll delve into other aspects of Crypto-Chama, including the SavingsPool Contract and the ERC20 token.

Stay tuned for more insights into the world of decentralized savings and investment!

--

--

Ibrahim Aziz
Coinmonks

Solidity, Web3 Development| Digital Transformation and Tech Trends