Open Dexaran opened 6 months ago
@Dexaran и все члены сообщества
Предлагаю для начала определиться с основным контрактом Казначейства. Так как долей сообщества будет распоряжаться другой контракт, на основе голосования, с ним мы можем определиться немного позднее, когда утвердим контракт Казначейства.
Мое предложение следующее, мне бы не хотелось чтобы контракт Казначейства был перегружен логикой, хотелось бы чтобы он был прост и его код легко воспринимался читающими. Основная задача которую должен исполнять контракт Казначейства, это хранить и распределять свой баланс между получателями, а именно Callisto Network (50%) и контрактом Сообщества (50%) и давать им распоряжаться своим балансом. Отмечу, что контракт казначейства не должен делать выплаты на адреса Callisto Network и на контракт Сообщества по умолчанию, вместо этого он должен делать выплаты на те адреса что требуют от него доливики.
Callisto Network и контракт Сообщества - далее "получатели"
Предлагаю следующие требования к контракту Казначейства:
Данный контракт я уже написал и развернул его в Callisto Mainnet, для вашего дальнейшего ознакомления с его кодом. Контракт полностью верифицирован.
https://02.callisto.network/address/0xbD62acE2BC78B7ABdEb84E00fdBCa54544929d0b/contracts
На тот случай если обозреватель перестанет работать или не работает, я опубликую код контракта еще и здесь для ознакомления. Разумеется адреса callistoNetwork и callistoCommunity должны быть изменены!
`// All rights reserved. // SPDX-License-Identifier: No License (None) // Разработчик: Upaut
pragma solidity ^0.8.16;
interface IERC20 { function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 value) external returns (bool); }
contract Treasury {
struct RecipientData { // структура описывающая данные каждого получателя
uint256 percent; // установленный процент получателя
uint256 balance; // баланс получателя
}
address public callistoNetwork = 0xeBE894814554c8382EA6a24CcDdf1527407A24f6; // Первый получатель
address public callistoCommunity = 0xfc8f3324B6D71d14BfD625ECdbD18f3bc29A9935; // Второй получатель
mapping(address => RecipientData) private recipients; // связь получателей с их структурой данных
event ChangeRecipient(address indexed _old, address indexed _new);
event TransferPercent(address indexed _sender, uint _percent);
event TransferCLO(address indexed _sender, address indexed _recipient, uint _value);
modifier onlyRecipients() {
require((msg.sender == callistoNetwork) || (msg.sender == callistoCommunity), "Only recipient");
_;
}
constructor()
{
// Проценты имеют decimal = 18
recipients[callistoNetwork].percent = 50 * 1e18; // 50% от трежери для CallistoNetwork
recipients[callistoCommunity].percent = 50 * 1e18; // 50% от трежери для сообщества Callisto
}
function changeRecepient(address _newRecepient) external onlyRecipients // изменение адреса получателя. Новый получатель сохраняет за собой право на проценты и баланс старого получателя
{
uint256 _percent = recipients[msg.sender].percent; // процент старого получателя
uint256 _balance = recipients[msg.sender].balance; // баланс старого получателя
delete recipients[msg.sender]; // удаляем данные старого получателя
// Инициализируем данные нового получателя
recipients[_newRecepient] = RecipientData(_percent, _balance);
(callistoNetwork, callistoCommunity) = msg.sender == callistoNetwork ? (_newRecepient, callistoCommunity) : (callistoNetwork, _newRecepient);
emit ChangeRecipient(msg.sender, _newRecepient); // логируем изменение получателя
}
function transferPercent(uint256 _percent) external onlyRecipients // передача части процента под управление второго получателя
{
uint256 _tekPercent = recipients[msg.sender].percent; // текущий процент получателя
require(_percent <= _tekPercent); // проверяем что отправитель имеет в распоряжении передаваемые проценты
_balanceDistribution(); // получатели делят нераспределенный баланс трежери
// передаем управление процентом второму получателю
(recipients[callistoNetwork].percent, recipients[callistoCommunity].percent) = msg.sender == callistoNetwork ? (_tekPercent - _percent, recipients[callistoCommunity].percent + _percent) : (recipients[callistoNetwork].percent + _percent, _tekPercent - _percent);
emit TransferPercent(msg.sender, _percent); // логируем передачу процента отправителем
}
function transferCLO(address _recipient, uint256 _value) external onlyRecipients // отправка CLO
{
require((_recipient != address(0x00)) && (_recipient != address(this))); // получателем не может быть нулевой адрес, или контракт трежери
_balanceDistribution(); // получатели делят нераспределенный баланс трежери
uint256 _tekBalance = recipients[msg.sender].balance; // текущий баланс отправителя
require(_value <= _tekBalance); // проверяем что отправитель имеет в распоряжении достаточный баланс
recipients[msg.sender].balance = _tekBalance - _value; // корректировка баланса отправителя
payable(_recipient).transfer(_value); // отправляем CLO получателю
emit TransferCLO(msg.sender, _recipient, _value); // логируем отправку CLO
}
function transferToken(address _token, address _recipient, uint256 _value) external // отправка токена
{
require(msg.sender == callistoCommunity); // Распоряжаться любыми токенами разрешено только сообществу
require((_recipient != address(0x00)) && (_recipient != address(this))); // получателем не может быть нулевой адрес, или контракт трежери
IERC20(_token).transfer(_recipient, _value); // отправляем токен получателю
}
function _balanceDistribution() private { // распределение CLO в трежери, между получателями
uint256 _cn = recipients[callistoNetwork].balance; // текущий баланс callistoNetwork
uint256 _cc = recipients[callistoCommunity].balance; // текущий баланс callistoCommunity
uint256 _contractBalance = address(this).balance - (_cn + _cc); // получаем нераспределенный баланс нативной монеты у контракта трежери
uint256 _cnShare = recipients[callistoNetwork].percent * _contractBalance / (100 * 1e18); // рассчитываем долю callistoNetwork в свободных CLO у контракта
recipients[callistoNetwork].balance = _cn + _cnShare; // передаем эту долю в распоряжение callistoNetwork
recipients[callistoCommunity].balance = _cc + (_contractBalance - _cnShare); // остаток переходит под управление callistoCommunity
}
function getRecipientData(address _recipient) public view returns (RecipientData memory) // Возвращаем текущий процент и текущий баланс CLO у получателя
{
RecipientData memory _result;
uint256 _cn = recipients[callistoNetwork].balance; // текущий баланс callistoNetwork
uint256 _cc = recipients[callistoCommunity].balance; // текущий баланс callistoCommunity
uint256 _contractBalance = address(this).balance - (_cn + _cc); // получаем нераспределенный баланс нативной монеты у контракта трежери
uint256 _share = recipients[_recipient].percent * _contractBalance / (100 * 1e18); // рассчитываем долю запрошенного получателя
_result = RecipientData(recipients[_recipient].percent, recipients[_recipient].balance + _share); // получаем текущий процент и весь доступный баланс для запрошенного получателя
return (_result); // возвращаем массив с инфой по токенам
}
function getBalanceToken(address _token) public view returns (uint256) // Возвращаем текущий процент и текущий баланс CLO у получателя
{
uint _balance = IERC20(_token).balanceOf(address(this)); // получаем баланс этого контракта в запрошенном токене
return (_balance);
}
// Контракт принимает пожертвования в нативной монете, любые токены ERC223 и ERC20
// Любые пожертвования в токенах ERC223 и ERC20 переходят под управление сообществом в полном объеме
receive() external payable {} // принимаем CLO. Он будет распределен между получателями согласно установленным процентам
function tokenReceived(address _from, uint _value, bytes memory _data) public returns (bytes4) { // принимаем токены ERC223
return this.tokenReceived.selector; // возвращаем селектор этой функции
}
}`
Предлагаю для начала определиться с основным контрактом Казначейства. Так как долей сообщества будет распоряжаться другой контракт, на основе голосования, с ним мы можем определиться немного позднее, когда утвердим контракт Казначейства.
I have no objections against this Treasury contract except the token donations. Why would community gain 100% of the donated tokens and not the other recipients?
I would like this CLOIP to host a discussion for the community Treasury share primarily. Updating the Treasury to make it a smart-contract is a cumbersome process, it will require a hardfork and it will happen (or not happen) in September most likely.
Community Treasury however can get funds right now. As soon as we finalize the community Treasury contract and discuss the proposal I'll be able to manually deposit the funds from the current Treasury balance to the community Treasury without any further delays.
I have no objections against this Treasury contract except the token donations. Why would community gain 100% of the donated tokens and not the other recipients?
Считаю что другие получатели для пожертвований должны иметь свои собственные адреса, чтобы иметь возможность единолично получать и распоряжаться тем, что конкретно им дали. Но если средства поступают на контракт Казначейства, то распоряжаться этими средствами должно сообщество!
Во первых это могут быть ошибочно поступившие токены, которые пользователь хочет вернуть (что скорее всего и будет происходить), в этом случае пользователь может обратиться в чат телеграмм или поставить данный вопрос о возврате средств обратно на адрес отправителя, на голосование. Сообщество проверить информацию и принять решение может быстрее чем другие получатели. Согласитесь что при такой ситуации очень не удобно если токены поделятся среди получателей и отправителю придется инициировать голосование на возврат средств в контракте сообщества, да еще и решать вопрос с другими получателями.
Во вторых, если это реальный донат, то сразу становится понятно что отправитель желает отдать данные токены для дальнейшего распределения именно сообществу.
В третьих, и наверное самое главное для понимания, никто не запрещает другим получателям состоять в сообществе и иметь право голоса для управления этими токенами.
I would like this CLOIP to host a discussion for the community Treasury share primarily. Updating the Treasury to make it a smart-contract is a cumbersome process, it will require a hardfork and it will happen (or not happen) in September most likely.
Community Treasury however can get funds right now. As soon as we finalize the community Treasury contract and discuss the proposal I'll be able to manually deposit the funds from the current Treasury balance to the community Treasury without any further delays.
Прекрасно тебя понимаю, но хардфорк в любом случае нужен обязательно, так как текущим ключом от Казначейства могут владеть третьи лица.
Что касается контракта DAO Governance, то общие мысли пока следующие:
Контракт должен иметь: 1) Общее количество добавленных участников 2) Общее количество проведенных голосований (меняется транзакцией исполнения решения по голосованию) 3) Время отведенное на голосование (может изменяться через голосование, полагаю в диапазоне 3-7 дней достаточно) 4) Количество нативной монеты. Плата за выставления вопроса на голосование (может изменяться через голосование). Если вопрос на голосование выдвигает адрес не являющийся участником данного контракта, он платит цену увеличенную в 10 раз. 5) Мэппинг с доверенными контрактами, в которых сообщество принимает решение (первоначально 2 адреса это контракт Казначейства и контракт ДАО) 5) Мэппинг на структуру данных участника (адрес, имя, количество_участий_в_голосованиях) 6) Мэппинг на структуру данных Proposal (IDhash, Количество нативной монеты (4), Общее количество добавленных участников (1), контракт, селектор_функции, данные). ...
Наверное я зря это описываю, проще просто идею высказать
Изначально в контракте DAO Governance инициализирован первый участник. Он начнет создавать предложения на голосования по добавлению новых участников (новые участники должны сделать запрос о входе в ДАО в телеграм чатах и подтвердить свой адрес транзакцией). Каждый раз при добавлении нового участника ему присваивается "Количество_участий_в_голосованиях" = "Общее количество проведенных голосований". Каждый раз когда участник голосует за какое-либо предложение он увеличивает свое "Количество_участий_в_голосованиях" на 2, но не более чем текущее "Общее количество проведенных голосований". Объясняю почему на 2, 1 - за текущее голосование и 1 - чтобы снять с себя 1 очко штрафа за голосования что он пропускал. Если разница между "Общее количество проведенных голосований" и "Количество_участий_в_голосованиях" составит 100 и более, то такого участника можно удалить из контракта ДАО без голосования. Все голосующие участники, после проведения голосования запрашивают награду, за свой голос. Это значение равное "Плата за выставления вопроса на голосование" деленная на количество голосовавших. Так сказать система поощрения голосующих. Не голосовавшие в место поощрения "из коробки" получат +1 штрафа, что приближает их к удалению из контракта ДАО (очки штрафа начинают сниматься если участник начинает голосовать).
Само предложение на голосование должно:
Я еще обдумываю детали, но думаю общую суть уже понять можно
I would like this CLOIP to host a discussion for the community Treasury share primarily. Updating the Treasury to make it a smart-contract is a cumbersome process, it will require a hardfork and it will happen (or not happen) in September most likely.
Итак, в общем предложение по контракту сообщества (далее GovernanceDAO) следующее:
GovernanceDAO должен:
управлять любым сторонним контрактом, при помощи низкоуровнего вызова call, на основании решения по завершению голосования (1 участник = 1 голос). Если большинство за исполнение предложения, то оно исполняется.
Уметь принимать предложения на голосование, от любого человека, не зависимо от того состоит он в DAO или нет.
Брать оплату за добавление предложения на голосование. Причем таких расценок две, первая для тех кто состоит в DAO, вторая для тех кто не состоит в DAO (они разумеется платят намного больше). Такие оплаты это мотивация всем голосующим, по завершению голосования эта оплата будет распределена среди проголосовавших (не важно как голосовали "за" или "против"). Установка расценок меняется при помощи голосования.
Новые участники DAO добавляются при помощи голосования. Первоначально добавляться будут проверенные люди из телеграм чатов Callisto, которые имеют в чате высокую активность. При добавлении участника в DAO, контракт сохранит его адрес кошелька и имя взятое из телеграма.
Голосования не анонимны, у каждого предложения будет фиксироваться кто голосует и как голосует. Любой человек через UI голосования будет видеть всех участников DAO и их статистики по голосованиям
Каждый участник имеет данные по своей активности в голосованиях (сколько было голосований после его добавление в DAO и сколько раз он голосовал). Исключать участников из DAO также возможно через голосование.
Каждое предложение должно иметь deadline (крайний срок принятия голосов). Сколько времени отводить на голосование решают члены DAO при помощи голосования. Допустимые сроки отводимые на голосование, которые можно установить от 3 до 14 дней. Если за предложение досрочно проголосовали все существующие участники DAO, оно завершается досрочно и переходит к принятию решения об исполнении.
Каждый участник DAO может 1 раз голосовать за каждое предложение.
контракт должен уметь возвращать список всех (либо часть списка) участников DAO с их данными по голосованиям
контракт должен уметь возвращать список всех (либо часть списка) выставленных предложений с их данными
контракт должен обладать функцией определяющей в каких предложениях у конкретного участника остались награды за голосования.
Я написал данный контракт, развернул и верифицировал его, для более детального ознакомления https://02.callisto.network/address/0x23DAA8d59dE6C07c38F0E8B27E709851135dC651/contracts
На тот случай если обозреватель перестанет работать или не работает, я опубликую код контракта еще и здесь для ознакомления
`// All rights reserved. // SPDX-License-Identifier: No License (None) // Разработчик: Upaut
pragma solidity ^0.8.16;
contract GovernanceDAO {
struct UserData { // структура описывающая данные каждого участника
uint256 index; // индекс участника
uint256 votes; // сколько раз всего голосовал участник
uint256 entered; // после какого голосования добавился участник
address userAddr; // адрес участника (упростит задачу frontend)
string name; // имя участника
}
struct ProposalData { // структура описывающая данные каждого предложения для голосования
uint256 id; // уникальный номер предложения (упростит задачу frontend)
uint256 time; // Дата создания предложения
uint256 reward; // награда для участников голосования
uint256 deadLine; // крайний срок голосования
address owner; // адрес инициатора предложения
uint8 status; // текущий статус предложения (1 - голосование, 2 - завершено, 3 - исполнено)
string comment; // комментарий к предложению
address[] vocesYes; // сколько участников проголосовало за предложение
address[] vocesNo; // сколько участников проголосовало против предложения
address to; // вызываемый контракт при исполнении данного предложения
bytes data; // данные транзакции
}
uint256 public total_voting; // всего голосований
uint256 public total_close_voting; // всего завершенных голосований
uint256 public total_user; // всего пользователей в DAO
uint256 public expire_period = 3 days; // сколько дней отведено на голосование (возможное значение от 3 до 14 дней)
uint256 public min_payment_DAO = 100 * 1e18; // минимальная оплата за вынесение предложения на голосование для членов DAO.
uint256 public min_payment_other = 10000 * 1e18; // минимальная оплата за вынесение предложения на голосование для не членов DAO.
mapping(uint256 => address) private indexes; // адреса участников по индексу
mapping(address => UserData) private users; // связь пользователей с их структурой данных
mapping(uint256 => ProposalData) private proposals; // список всех предложений
mapping(uint256 => mapping(address => bool)) private rewards; // награды за голосование
event CreateProposal(uint indexed _id, uint _reward); // ID предложения и награда за голосование
event Vote(address indexed _sender, uint indexed _id, bool _answer); // Участник, ID предложения, решение
event ChangeStatus(uint indexed _id, uint8 _status); // ID предложения, новый статус
event Claim(address indexed _sender, uint indexed _id, uint _pay); // Участник, ID предложения, сколько было выплачено
modifier onlyThis() {
require(address(this) == msg.sender, "Only GovernanceDAO");
_;
}
constructor(address _firstUser, string memory _name)
{
++total_user; // увеличиваем количество участников
indexes[total_user] = _firstUser; // привязываем адрес участника к индексу
users[_firstUser] = UserData(total_user, 0, 0, _firstUser, _name); // инициализация данных участника
}
function setExpirePeriod(uint256 _period) external onlyThis { // установить новый период голосования
if((_period >= 3 days) && (_period <= 14 days)) expire_period = _period; // новый период должен быть в диапазоне от 3 до 14 дней (включительно)
}
function setMinPayments(uint256 _min_payment_DAO, uint256 _min_payment_other) external onlyThis { // установить новые минимальные сборы за вынесение предложения на голосование
min_payment_DAO = _min_payment_DAO; // минимальная оплата за вынесение предложения на голосование для членов DAO.
min_payment_other = _min_payment_other; // минимальная оплата за вынесение предложения на голосование для не членов DAO.
}
function addUserInDAO(address _user, string calldata _name) external onlyThis { // добавить нового участника
if(_user == address(0)) return; // участник не может иметь нулевой адрес
if (users[_user].index == 0){ // только новый участник
++total_user; // увеличиваем количество участников
indexes[total_user] = _user; // привязываем адрес участника к индексу
users[_user] = UserData(total_user, 0, total_close_voting, _user, _name); // инициализация данных участника
}
}
function delUserInDAO(address _user) external onlyThis { // удалить участника из DAO
uint256 _ind = users[_user].index; // индекс удаляемого участника
if (_ind > 0){ // только существующий участник
if(_ind != total_user){ // индекс участника непоследний
indexes[_ind] = indexes[total_user]; // привязываем адрес последнего участника к новому индексу
users[indexes[_ind]].index = _ind; // меняем индекс в данных последнего участника
}
delete indexes[total_user]; // обнуляем последний индекс
delete users[_user]; // удаляем данные участника
--total_user; // уменьшаем количество участников
}
}
function createProposal(address _contract, bytes calldata _data, string calldata _comment) payable external { // создание предложения
// _contract - адрес контракта, который будет вызван при принятии этого предложения
// _data - данные вызова (функция и аргументы), закодированные через encodeABI()
// _comment - краткий комментарий к предложению, возможно ссылка на github с proposal
if(users[msg.sender].index > 0){ // адрес который выдвигает предложение состоит в DAO
require(msg.value >= min_payment_DAO, "small payment"); // проверка оплаты предложения
}
else{ // адрес который выдвигает предложение не состоит в DAO
require(msg.value >= min_payment_other, "small payment"); // проверка оплаты предложения
}
++total_voting; // идентификатор нового голосования
proposals[total_voting].id = total_voting; // уникальный номер предложения
proposals[total_voting].time = block.timestamp; // Дата создания предложения
proposals[total_voting].reward = msg.value; // награда для участников голосования
proposals[total_voting].deadLine = block.timestamp + expire_period; // крайний срок голосования
proposals[total_voting].owner = msg.sender; // адрес инициатора предложения
proposals[total_voting].status = 1; // текущий статус предложения
proposals[total_voting].comment = _comment; // комментарий к предложению
proposals[total_voting].to = _contract; // вызываемый контракт при исполнении данного предложения
proposals[total_voting].data = _data; // данные транзакции
emit CreateProposal(total_voting, msg.value); // логируем ID предложения и награду за голосование
}
function vote(uint _id, bool _answer) external { // голосование
// _id - идентификатор предложения
// _answer - ваш ответ (0 - отклонить предложение, 1 - одобрить предложение)
require(proposals[_id].time > 0, "proposal does not exist"); // проверяем что предложение существует
if(proposals[_id].status > 1) return; // голосование по данному предложению завершено
if(block.timestamp > proposals[_id].deadLine){ // время голосования истекло
proposals[_id].status = 2; // голосование завершено
++total_close_voting; // увеличиваем количество завершенных голосований
emit ChangeStatus(_id, 2); // ID предложения, новый статус
return;
}
uint _index = users[msg.sender].index; // получим индекс голосующего в списке DAO
require(_index > 0, "you are not a member"); // проверяем что голосующий состоит в DAO
require(!rewards[_id][msg.sender], "you have already voted"); // проверяем что голосующий, ранее не голосовал за это предложение
rewards[_id][msg.sender] = true; // подтверждаем принятие голоса c фиксацией выплаты за это голосование
users[msg.sender].votes++; // увеличиваем количество всех голосований участника
emit Vote(msg.sender, _id, _answer); // логируем участника, ID предложения, принятое решение
if(_answer){ // голос отдан за принятие предложения
proposals[_id].vocesYes.push(msg.sender);
}
else{ // голос отдан за отклонение предложения
proposals[_id].vocesNo.push(msg.sender);
}
uint _amount_votes = proposals[_id].vocesYes.length + proposals[_id].vocesNo.length; // количество проголосовавших
if(_amount_votes == total_user){ // если все участники DAO проголосовали, то голосование досрочно завершаем
proposals[_id].status = 2; // голосование завершено
++total_close_voting; // увеличиваем количество завершенных голосований
emit ChangeStatus(_id, 2); // ID предложения, новый статус
}
}
function execute(uint _id) external { // Исполнение предложения
// _id - идентификатор предложения
require(proposals[_id].status == 2, "proposal is not completed"); // только завершенное предложение можно привести к исполнению
proposals[_id].status = 3; // меняем статус на состояние "Исполнено"
if(proposals[_id].vocesYes.length > proposals[_id].vocesNo.length){ // если большинство проголосовало за принятия предложения, то приводим его в исполнение
_execute(proposals[_id].to, proposals[_id].data);
}
emit ChangeStatus(_id, 3); // ID предложения, новый статус
}
function _execute(address _to, bytes memory _data) private {
(bool success,) = _to.call(_data);
require(success, "Execute error");
}
function claim(uint _id) external { // Получить вознаграждение за проведенное голосование
// _id - идентификатор предложения
require(proposals[_id].status > 1, "proposal is not completed"); // награду можно требовать только когда голосование завершено
require(rewards[_id][msg.sender], "no payment"); // проверяем имеет ли отправитель право на выплату
rewards[_id][msg.sender] = false; // фиксируем выплату отправителю
uint _amount_votes = proposals[_id].vocesYes.length + proposals[_id].vocesNo.length; // количество проголосовавших
uint _pay = proposals[_id].reward / _amount_votes; // расчет выплаты для каждого участника
payable(msg.sender).transfer(_pay); // выплата
emit Claim(msg.sender, _id, _pay); // Участник, ID предложения, сколько было выплачено
}
// ФУНКЦИИ ЧТЕНИЯ
function getUser(address _user) public view returns (UserData memory) { // Возвращаем данные конкретного пользователя по его адресу
return (users[_user]);
}
function getUsersList(uint _start_index, uint _amount) public view returns (UserData[] memory) { // Возвращаем данные нескольких пользователей из списка
UserData[] memory _result = new UserData[](_amount);
for(uint i; i < _amount; i++) _result[i] = getUser(indexes[_start_index++]);
return (_result);
}
function getProposal(uint _id) public view returns (ProposalData memory) { // Возвращаем данные конкретного предложения по его ID
return (proposals[_id]);
}
function getProposalsList(uint _start_ID, uint _amount) public view returns (ProposalData[] memory) { // Возвращаем данные нескольких предложений из списка
ProposalData[] memory _result = new ProposalData[](_amount);
for(uint i; i < _amount; i++) _result[i] = getProposal(_start_ID++);
return (_result);
}
function checkClaim(uint _id, address _user) public view returns (bool) { // Проверяет наличие вознаграждения для указанного адреса, в указанном предложении
return (rewards[_id][_user]);
}
function getClaimList(address _user, uint _start_ID, uint _amount) public view returns (uint [] memory, bool [] memory) { // Возвращаем массив предложений и массив наград для указанного адреса
// _user - адрес для которого смотрим награды
// _start_ID - с какого предложения начинать вести поиск наград
// _amount - количество просматриваемых предложений
uint[] memory _proposalID = new uint[](_amount);
bool[] memory _claim = new bool[](_amount);
for(uint i; i < _amount; i++){
_proposalID[i] = _start_ID;
_claim[i] = rewards[_start_ID][_user];
++_start_ID;
}
return (_proposalID, _claim);
}
} `
Here is a copy of the code provided by @Upaut1 https://gist.github.com/Dexaran/ade3480b4717a3c94816957bfbdb4872
My last concern is to agree on a list of the initial community contract members. While it is clear that they will be added one by one according to the rules of the smart-contract (by the initial creator) it would be good to nominate at least three or four existing members of the community.
@Dexaran На разработку UI для контракта DAO требуются средства в количестве 1500 USDT, предпочтительно в сети Polygon, адрес получателя 0xeBE894814554c8382EA6a24CcDdf1527407A24f6
Контракты Treasury, GovernanceDAO, а также UI будут с лицензией GPLv3.
@Dexaran На разработку UI для контракта DAO требуются средства в количестве 1500 USDT, предпочтительно в сети Polygon, адрес получателя 0xeBE894814554c8382EA6a24CcDdf1527407A24f6
Контракты Treasury, GovernanceDAO, а также UI будут с лицензией GPLv3.
@Dexaran To develop a UI for the DAO contract, funds in the amount of 1500 USDT are required, preferably on the Polygon network, recipient address 0xeBE894814554c8382EA6a24CcDdf1527407A24f6
Treasury, GovernanceDAO, and UI contracts will be licensed under GPLv3.
Alright, this proposal will be funded.
Unfortunately I'm unable to process the transfer of USDT via Polygon at the moment, the USDT will be delivered via BSC as soon as Bybit will approve my withdrawal.
@Upaut1 the proposal was funded https://bscscan.com/tx/0x8306e901e4b20067b32db86cae7eeff274797f9c1a8ea422c7bc33ebb89605e8
@Dexaran Рад сообщить что создание DAO успешно завершено.
Контракты Treasury, GovernanceDAO, а также UI с открытым исходным кодом и имеют лицензии GPLv3 https://github.com/YaStaer/CallistoDAO_UI
Мы также хорошо протестировали взаимодействие контракта GovernanceDAO со всеми возможными функциями контрактов Treasury и GovernanceDAO, а также взаимодействие со сторонними контрактами. Все тесты были проведены в Callisto Testnet. Адреса развернутых тестовых контрактов, в которых производились тесты, следующие: Treasury - https://testnet-explorer.callisto.network/address/0xf82533EC6F73C56549e21B24a93B9f1612A99C67/contracts GovernanceDAO - https://testnet-explorer.callisto.network/address/0xb356A5a5710Cac1677854f1b95608D1d4B4B417d/contracts
В настоящее время контракты Treasury и GovernanceDAO развернуты в сети Callisto Network по следующим адресам: Treasury - https://02.callisto.network/address/0x5633F30748A435322030fB02F1097CFe9D311bA4/contracts GovernanceDAO - https://02.callisto.network/address/0x810059e1406dEDAFd1BdCa4E0137CbA306c0Ce36/contracts Пользовательский интерфейс DAO доступен по следующему адресу: https://callisto-dao.2bears.exchange/ Со всеми действующими членами DAO можно ознакомиться через пользовательский интерфейс. Несмотря на то, что DAO было запущено всего несколько часов назад, к нему уже подключилось 8 проверенных членов сообщества. Мы продолжаем его формировать из активных и проверенных членов сообщества Callisto Network.
Теперь о ВАЖНОМ:
Контракт Treasury распределяет казну следующим образом 50% - управляются действующим DAO 50% - второй получатель, в настоящее время это я. @Dexaran мне необходимо получить от тебя адрес, которому я передам права на второго получателя. После чего контракт Treasury будет готов принимать казну
Когда человек выдвигает предложение на голосование, то он может оставлять комментарий к своему предложению. Такие комментарии сохраняются в блокчейне. Если у человека имеется предложение, которое требует значительного пояснения, то логично чтобы он его описал на github и в комментарий создаваемого предложения просто указал ссылку на него. Прощу тебя определить такое место где будут создаваться подобные описания к создаваемым предложениям.
The Callisto DAO codes are now located here: https://github.com/EthereumCommonwealth/CallistoDAO
Please send your pull requests to the repo in EthereumCommonwealth and lets keep Callisto core contracts there from now on. I'm ready to transfer the Community Treasury share to the Callisto Community DAO contract.
@Upaut1
@Dexaran мне необходимо получить от тебя адрес, которому я передам права на второго получателя. После чего контракт Treasury будет готов принимать казну
@Dexaran I need to get an address from you to which I will transfer the rights to the second recipient. After which the Treasury contract will be ready to accept treasury
Please use the New Treasury address: 0x3264Fb22a50ecadc6DFd0F0e1938a0eef965C491
@Upaut1
Когда человек выдвигает предложение на голосование, то он может оставлять комментарий к своему предложению. Такие комментарии сохраняются в блокчейне. Если у человека имеется предложение, которое требует значительного пояснения, то логично чтобы он его описал на github и в комментарий создаваемого предложения просто указал ссылку на него. Прощу тебя определить такое место где будут создаваться подобные описания к создаваемым предложениям.
When someone creates a new proposal there is a possibility to attach a comment there. Such comments will be stored on-chain. If the proposal requires a long explanation/description then it would be a good idea to place these descriptions somewhere on github and put a link to the proposal in the github comment. I'm proposing to create such a github space for proposal descriptions.
Let's use the original "Proposals" repo and create github issues for each new proposal https://github.com/EthereumCommonwealth/Proposals/issues
Please use the New Treasury address: 0x3264Fb22a50ecadc6DFd0F0e1938a0eef965C491
В контракте "Treasury" права второго получателя переданы адресу 0x3264Fb22a50ecadc6DFd0F0e1938a0eef965C491, теперь он распоряжается 50% поступающего CLO. Так что контракт "Treasury" полностью готов к приему казны
cloip: 9 title: Trustless Treasury model for Callisto Network author: Dexaran (@Dexaran) dexaran@callisto.network status: Draft category: Meta created: 22 February, 2024
Abstract
This CLOIP supersedes CLOIP-7: Trustless Treasury model as the previous Treasury keyholders resigned from their rights. In this proposal we will host a discussion to allocate a share of Treasury that previously belonged to Callisto Enterprise to the community.
Proposal
@Upaut1 proposed to create a community-governed smart-contract that will receive payments from Treasury in CLOIP-7 https://github.com/EthereumCommonwealth/CLOIP/issues/7#issuecomment-1953210593
I propose to redirect up to 50% Treasury (previously Callisto Enterprise's share) to the community contract. However few points have to be addressed first: