Карма: альтернативные деньги, совместимые с ERC20, на блокчейне Ethereum
12 сентября 2023 г.Вы когда-нибудь задумывались о том, как создаются деньги? Ну, обычно банки делают его из ничего. Когда кто-то берет кредит, банк просто добавляет заемные деньги к сумме, уже записанной в его базе данных по банковскому счету. Таким образом, если 100$ уже присутствовали в записи базы данных для банковского счета и кто-то берет кредит в размере 10000$, банк просто перепишет цифру на 10100$. Таким образом, банк выдает в долг деньги, которых у него нет. Разумеется, кредит необходимо погасить. Когда кредит погашен, деньги, созданные за счет кредита, исчезают. Вот и эти деньги возникают из ничего и исчезают в ничто (не будем вдаваться в интересующую нас тему, которая несколько усложняет дело). Таким образом, эти деньги существуют лишь временно. Есть притча о деньгах, которые существуют лишь временно.
Ковбой заходит в бар. После нескольких выпивок бармен спрашивает его, одолжит ли он ему 10 долларов, чтобы заделать дыру в крыше. Ковбой соглашается одолжить 10 долларов с условием, что они будут возвращены через неделю. Бармен вызывает кровельщика, который чинит крышу, и бармен платит 10 долларов. Тем временем у кровельщика разваливается ботинок, и он идет к сапожнику, чтобы купить новый еще за 10 долларов. Сапожник обрадован неожиданной удачей и быстро тратит деньги в том же баре. Таким образом, 10 долларов возвращаются бармену. По прошествии недели ковбой возвращается, а бармен возвращает 10 долларов. Ковбой благодарит его, затем вытаскивает спичку и сжигает деньги. Бармен с широко раскрытыми глазами спрашивает: «Зачем ты это сделал?», на что ковбой отвечает: «Это фальшивые деньги, они ничего не стоят».
В притче ковбой подобен банку. Он дает взаймы деньги, которых у него нет. Он создает эти деньги из воздуха, а когда они сжигаются, они исчезают, как банковские кредиты. Тем не менее на эти временные деньги бар получил новую крышу, кровельщик получил новую пару обуви, а у сапожника хватило денег, чтобы выпить несколько стаканчиков. Это ощутимые результаты денег, которые существуют лишь временно. Итак, то, что мы используем в качестве денег, — это не что иное, как чей-то долг. Деньги — это долг!
Ценность денег в конечном итоге основана на форме доверия. Мы верим, что другие тоже это ценят, поэтому, когда мы делаем что-то для кого-то взамен, мы принимаем деньги, потому что верим, что они будут приняты, когда мы потребуем что-то взамен. Это доверие делает деньги универсальным средством обмена. Хорошим примером этого является Биткойн. Наш биткойн-баланс — это не что иное, как запись в распределенном реестре. Это ничем не подкреплено, однако люди во всем мире готовы платить за Биткойн реальные деньги. Таким образом, ценность Биткойна — это исключительно вопрос доверия. Деньги – это доверие!
Это были основные идеи, которые вдохновили концепцию кармических денег. Что, если бы все работали как банк? Вместо того, чтобы брать деньги в кредит, они создавали бы их сами. Конечно, такая система работала бы только в том случае, если бы существовал предел количества денег, которые можно было создать. Таким образом, долг каждого будет государственным. Если бы мне пришлось выбирать, кому продавать мои продукты или услуги, я бы отдал их тому, у кого наименьшая задолженность, поскольку это дает наилучшие шансы на быструю выплату долга. Поэтому каждый заинтересован в том, чтобы сохранить свой долг на низком уровне, погашая его.
Давайте посмотрим, как бы выглядела ковбойская притча в этой системе. Нет необходимости в ковбое (банке), поскольку бармен сам может заработать 10 долларов для кровельщика. Это создает долг в 10 долларов для бармена, которого видят все, но взамен ему починят крышу. Кровельщик передает эти 10 долларов сапожнику, а когда сапожник передает их обратно бармену, эти 10 долларов уничтожаются вместе с долгом бармена. Таким образом, долг бармена снова равен нулю. Таким образом, очевидно, что процесс создания временных денег работает хорошо даже без банков. Все, что нужно, — это чтобы кровельщик доверял деньгам, созданным барменом, и верил, что это такие же хорошие деньги, как и 10 долларов, созданные банком.
Я реализовал эти деньги кармы на блокчейне Ethereum с помощью простого смарт-контракта Solidity. Моя реализация кармы — это контракт ERC20, и это здорово, потому что его можно легко использовать с любым кошельком Ethereum. Особенность кармы в том, что если в случае с другими валютами мы тратим со своего баланса, то здесь наш баланс начинается с 0 и увеличивается с каждой тратой (созданием денег). Чем больше наш баланс, тем большей задолженностью мы становимся, поэтому здесь цель состоит в том, чтобы уменьшить наш баланс.
Давайте рассмотрим краткий пример. Алиса хочет купить яблоки у Джона, поэтому она платит Джону 10 долларов кармы за яблоки. Баланс Алисы таким образом увеличивается до 10$. Позже Джон покупает апельсины у Алисы, поэтому, когда он платит Алисе 10 долларов, долг погашается, и баланс Алисы уменьшается до 0 долларов.
После теории давайте взглянем на код (доступен здесь, на 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);
}
}
}
Как видно, это совершенно стандартный токен ERC20. В конструкторе мы можем указать имя и символ токена, а также параметр CycleReward, который мы обсудим позже. Карма может представлять собой доллары, евро, любые деньги, а также время (например, я буду работать на вас 1 час в обмен на 1 час работы) или что-то еще. Итак, карма — это общая система кредитования.
Метод balanceOf стандарта ERC20 предназначен для запроса баланса любого человека. Очень важно, чтобы каждый человек был связан только с одним адресом Ethereum. Если бы это было не так, то если бы кто-то оказался в большой задолженности, он бы просто открыл новую учетную запись, таким образом, вся система была бы бессмысленной. К счастью, есть такие решения, как Proof of Humanity или WorldCoin. , которые могут гарантировать, что у каждого человека будет уникальный адрес.
Я также представил функцию debtOf, которая может точно узнать, кто кому сколько баллов должен.
Для перемещения весов используется стандартная передаточная функция. С одной стороны, это увеличивает баланс пользователя, а с другой – записывает задолженность перед принимающей стороной. Следовательно, если Алиса заплатит Джону 10 долларов, баланс Алисы увеличится на 10 долларов, и будет отмечено, что Алиса должна Джону 10 долларов.
Может показаться, что код делает не совсем то, что я описал ранее. Например, если Джон теперь платит Алисе 10 долларов, вместо того, чтобы баланс Алисы и Джона составлял 0 долларов, баланс Алисы останется на уровне 10 долларов, а баланс Джона также станет 10 долларов. Кроме того, в матрице долга Алиса теперь должна Джону 10 долларов, а Джон будет должен Алисе 10 долларов. Почему смарт-контракт не покрывает эти долги?
Случай Алисы и Джона очень прост, но обычно образуются гораздо более сложные долговые цепочки. Например, в примере с ковбоем в цепочке было 3 человека, однако вполне возможно, что цепочка будет содержать 10 или более человек. Найти такие цепочки отнюдь не тривиально. Вот почему нужны майнеры кармы. Майнеры кармы постоянно следят за графиком долга и, если обнаружат цикл, могут передать его в смарт-контракт. Для этого и нужен метод mineCycle. Метод проверяет отправленную цепочку и, если она действительна, выполняет изменения в балансах. За это майнер получит небольшую карму от каждого участника цепочки, за уменьшение их балансов. Таким образом, майнинг кармы практически ничем не отличается от майнинга биткойнов. Участник запускает программу на своей машине, потребляя электроэнергию и вычислительную мощность (находя циклы на графике), что в свою очередь производит карму.
Есть еще несколько методов, связанных со стандартом ERC20, но они не представляют интереса с точки зрения системы.
Карма может стать идеальным решением для сообществ, ищущих альтернативу традиционной денежной системе. Но участниками такой системы также могут быть компании или проекты. Например, проект с открытым исходным кодом может принимать пожертвования в виде кармы и аналогичным образом платить разработчикам в виде кармы, которые затем могут обменять это, скажем, на местные овощи и фрукты, выращенные в сообществе, используя карму. Конечно, не существует правовой базы, поддерживающей карму, как в случае с реальными деньгами, но Биткойн показал, что валюта может работать исключительно на доверии, без какой-либо поддержки. По сравнению с Биткойном, карма не требует огромных вычислительных мощностей и не требует потребления энергии в стране. Система опирается на доверие, а деньги подкреплены нашей собственной личностью.
Оригинал