Karma: an ERC20 compatible alternative currency on the Ethereum blockchain | by Laszlo Fazekas | September 2023

[ad_1]
Have you ever thought about how money is created? Well, usually banks make it from scratch. When a person takes out a loan, the bank adds the borrowed money to the amount already recorded in its bank account database. So if $100 was already present in the database entry for the bank account and someone takes out a loan for $10,000, the bank will rewrite the contents of the entry to $10,100. So the bank lends the money it doesn’t have. Of course, the loan must be repaid.
When the loan is repaid, the money created by the loan disappears. So this money comes out of nothing and disappears into nothingness (let’s not get into the subject of interest, which complicates things a little). This money therefore only exists temporarily. There is a parable about the usefulness of money that only exists temporarily.
A cowboy enters the bar. After a few drinks, the bartender asks him if he would lend him $10 to repair a hole in the roof. The cowboy agrees to lend the $10, on the condition that it be repaid within a week. The bartender calls a roofer, who repairs the roof, and the bartender pays the $10. Meanwhile, the roofer’s shoe falls apart and he goes to the shoemaker to buy a new one for an extra $10. The shoemaker is delighted with his unexpected windfall and quickly has the money spent in the same bar. The $10 thus goes to the bartender.
When a week passes, the cowboy returns and the bartender returns the $10. The cowboy thanks him, takes out a match and burns the money. The bartender, wide-eyed, asks, “Why did you do that?” ”, to which the cowboy replies: “It’s counterfeit money; it’s worthless.
In the parable, the cowboy is like a bank. He lends money he doesn’t have. He creates this money out of thin air, and it disappears like bank loans when it is burned. However, with this temporary money, the bar got a new roof, the roofer got a new pair of shoes, and the shoemaker had enough money for a few drinks. These are tangible results of money that only exists temporarily. What we use as money is therefore nothing other than someone’s debt. Money is debt!
The value of money is ultimately based on a form of trust. We are confident that others will appreciate it too. So when we do something for someone in return, we accept money because we are confident that it will be accepted when we demand something in return. This trust makes money a universal medium of exchange.
A good example is Bitcoin. Our Bitcoin balance is nothing more than an entry in a distributed ledger. There is nothing to prove it, but people all over the world are willing to pay real money for Bitcoin. The value of Bitcoin is therefore purely a question of trust. Money is trust!
These are the fundamental ideas that inspired the concept of karmic money. What if everyone operated like a bank? Instead of taking money on credit, they would create it themselves. Of course, such a system would only work if there was a limit to the amount of money that could be created. Everyone’s debt would therefore be public.
If I had to choose who to sell my products or services to, I would give it to the one with the least debt, as this gives the best chance of getting paid back quickly. Therefore, everyone has an interest in keeping their debt low by paying it off.
Let’s see what a cowboy parable would look like in this system. There is no need for a cowboy (bank), as the bartender can create the $10 for the roofer himself. This creates a $10 debt for the bartender, visible to all, but in exchange, his roof is repaired. The roofer passes that $10 to the cobbler, and when the cobbler returns it to the bartender, the $10 is destroyed along with the bartender’s debt. So the bartender’s debt is zero again.
So the transitional money creation process works well even without banks. All the roofer has to do is trust the money created by the bartender and believe that that money is as good as the $10 created by the bank.
I made this karma money on the Ethereum Blockchain with a simple Solidity smart contract. My implementation of karma is a ERC20 contract, which is great because it can easily be used with any Ethereum wallet. The peculiarity of karma is that, while in the case of other currencies we spend from our balance, here our balance starts from zero and increases with each expenditure (money creation). The larger our balance, the more debt we become, so the goal here is to reduce our balance.
Let’s look at a brief example. Alice wants to buy John some apples, so she pays John ten karma dollars for the apples. Alice’s balance thus increases to $10. Later, John buys oranges from Alice, so when he pays Alice $10, the debt is settled and Alice’s balance is reduced to $0.
After the theory, let’s take a look at the code (available here on GitHub):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
contract Karma is IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _debts;
mapping(address => mapping(address => uint256)) private _allowances;
string private _name;
string private _symbol;
uint private _cycleReward;
constructor(string memory name_, string memory symbol_, uint cycleReward) {
_name = name_;
_symbol = symbol_;
_cycleReward = cycleReward;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
// totalSupply is meaningless
function totalSupply() public view virtual override returns (uint256) {
return 0;
}
function balanceOf(
address account
) public view virtual override returns (uint256) {
return _balances(account);
}
function debtOf(
address debtor,
address creditor
) public view virtual returns (uint256) {
return _debts(debtor)(creditor);
}
function transfer(
address to,
uint256 amount
) public virtual override returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function allowance(
address owner,
address spender
) public view virtual override returns (uint256) {
return _allowances(owner)(spender);
}
function approve(
address spender,
uint256 amount
) public virtual override returns (bool) {
require(spender != address(0), "ERC20: approve to the zero address");
address owner = msg.sender;
_allowances(owner)(spender) = amount;
emit Approval(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
_spendAllowance(from, msg.sender, amount);
_transfer(from, to, amount);
return true;
}
function mineCycle(
address() memory nodes,
uint256 amount
) public virtual returns (bool) {
// checking debts in cycle from 0..n
for (uint i = 0; i < nodes.length - 1; i++) {
require(
_debts(nodes(i))(nodes(i + 1)) >= amount,
"Karma: Not enough debt for the cycle"
);
}
// checking the last debt (end of cycle)
require(
_debts(nodes(nodes.length - 1))(nodes(0)) >= amount,
"Karma: Not enough debt for the cycle"
);
// decreasing the debts and balances and pay cyleReward
for (uint i = 0; i < nodes.length - 1; i++) {
_debts(nodes(i))(nodes(i + 1)) -= amount;
_balances(nodes(i)) -= amount;
_transfer(nodes(i), msg.sender, _cycleReward);
}
_debts(nodes(nodes.length - 1))(nodes(0)) -= amount;
_balances(nodes(nodes.length - 1)) -= amount;
_transfer(nodes(nodes.length - 1), msg.sender, _cycleReward);
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(to != address(0), "ERC20: transfer to the zero address");
_balances(from) += amount;
_debts(from)(to) += amount;
emit Transfer(from, to, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(
currentAllowance >= amount,
"ERC20: insufficient allowance"
);
uint256 newAmount = currentAllowance - amount;
_allowances(owner)(spender) = newAmount;
emit Approval(owner, spender, newAmount);
}
}
}
As we can see, this is a completely standard ERC20 token. In the constructor we can specify the token name and symbol as well as a parameter called cycleReward
, which we will talk about later. Karma can be dollars, euros, any amount of money, but also time (for example, I will work for you for an hour in exchange for an hour of work) or anything. other. Karma is therefore a general loan system.
The ERC20 standard balanceOf
The method consists of querying the balance of any individual. It is important that each person is only tied to one Ethereum address. If that weren’t the case, if someone became very in debt, they would simply open a new account, rendering the whole system useless. Fortunately, there are solutions such as Proof of humanity Or World Coinwhich can ensure that each individual has a unique address.
I also introduced a debtOf
function, which can query precisely who owes how many points to whom.
The standard transfer
The function is used to move the scale. On the one hand, it increases the user’s balance; on the other hand, it records the debt owed to the beneficiary. Therefore, if Alice pays John $10, Alice’s balance will be increased by $10, and it will be noted that Alice owes John $10.
It may seem like the code doesn’t do exactly what I described earlier. For example, if John now pays Alice $10, instead of Alice and John having a balance of $0, Alice’s balance will remain at $10 and John’s balance will also become $10. Additionally, in the debt matrix, Alice will now owe John $10, and John will now owe Alice $10. Why doesn’t the smart contract resolve these debts?
The case of Alice and John is very simple, but much more complex chains of debt usually form. In the cowboy example, there were three people along the chain. However, it is conceivable that a channel contains ten or more people. Finding such channels is by no means trivial. This is why karma miners are needed.
Karma miners constantly monitor the debt graph; if they discover a cycle, they can submit it to the smart contract. This is what the mineCycle
the method is for. The method checks the submitted string; if it is valid, it will execute the balance changes. For this, the miner will receive a small karma from each member of the chain to reduce their balances (the amount of the reward is defined by the cycleReward
).
So karma mining is almost exactly the same as Bitcoin mining. The member runs a program on their machine, consuming electricity and computing power (looking for cycles in a graph), producing karma in return.
There are still some methods related to the ERC20 standard, but these are not of interest from a system point of view.
Karma can be an ideal solution for communities seeking an alternative to the traditional monetary system. But the members of such a system can also be companies or projects. For example, an open source project can accept donations and pay developers in karma, who can then exchange them for, say, locally grown vegetables and fruits in a karma-using community.
Of course, there is no legal framework supporting karma like there is with real money, but Bitcoin has shown that a currency can operate on trust alone – without any backing. Compared to Bitcoin, karma does not require enormous computing power, nor the energy consumption of a country. The system is built on trust and our identity supports money.
[ad_2]
Source link