Сумасшедший хайп вокруг криптовалют и всевозможных технологических стартапов подталкивает людей к тому, чтобы обращать на эти две темы повышенное внимание. Кого-то привлекает возможность кратно заработать в сжатые сроки, для других участие в венчурных проектах, использующих современные технологии – это возможность приобщиться к современным трендам и, возможно, даже похвастаться этим.
Но как и в истории с систематической ошибкой выжившего, нужно обращать внимание не только на истории успеха, которые постоянно приводят в пример, но и на истории, где люди потеряли кучу времени и денег, пытаясь развивать свой проект, написали тонны кода, а в итоге не получили ничего. Причем довольно часто потерянные деньги принадлежат инвесторам. Конечно, всем хотелось бы заработать на ранних инвестициях в компании типа facebook, но к сожалению 9 из 10 таких компаний прогорают.
Венчурное инвестирование — очень интересный вид бизнеса, но для большинства мелких частных инвесторов вход туда просто закрыт. Происходит это в основном потому, что ввиду колоссального риска при инвестициях в стартапы, инвестирование в один-два проекта смерти подобно. Поэтому даже самые маленькие венчурные фонды имеют в своем портфеле как минимум 20-30 проектов. Если хотя бы одна из их портфельных компаний выстрелит, это покроет расходы на остальные проекты. Но проекты не хотят брать от инвесторов 100 тысяч. Вложения в каждый из них составляют как минимум миллион. Простая арифметика показывает, что если у вас в кармане нет капитала в размере 15-20 миллионов, вы можете забыть об этом.
В то же время, есть и другая схема инвестирования в стартапы — краудфандинг. Вложить при этом вы можете сколько угодно, но разговаривать с вами как с инвестором никто не будет. Опять же, в большинстве случаев, стартап, собрав необходимое количество средств, расслабляется, так как не несет никакой ответственности перед мелкими инвесторами, которые вкладывают в него по сути на удачу. Стартапы рушатся не только из за лени и безответственности их начинателей, но и из за непредвиденных факторов, которые на старте предусмотреть практически невозможно.
С появлением эфириума и смарт-контрактов я заразился идеей написать систему, которая позволяла бы мелким инвесторам контролировать ход выполнения стартапов и тем самым повышать для себя процент прибыльных инвестиций. По сути это краудфандинговая платформа, но с одним существенным отличием — проект получает доступ не ко всем собранным средствам, а только к небольшой их части, а инвестор может в любой момент забрать неосвоенные средства, если проект не проходит заявленные на старте этапы. Гарантом этого будет выступать не система, а смарт-контракт.
Бизнес-модель самой платформы подразумевает, что она будет получать в качестве комиссии 5% собранного каждым проектом эфира (читай, живыми деньгами) и 5% акциями будущего предприятия. Сама платформа по сути является акционерным обществом, и вы можете стать ее владельцем, купив долю ее акций и получая в будущем эти самые 5+5 процентов, автоматическим становясь инвестором всех проектов, которые будут привлекать инвестиции на базе данной платформы.
Если бы такая система существовала, я бы сам с удовольствием вкладывался в нее саму, и в проекты, понимая, что я могу всегда выйти из них, если что-то по моему мнению пойдет не так. А раз такой системы нет, то я решил написать ее самостоятельно.
Далее в статье я буду разбирать «по косточкам» смарт-контракт на solidity, который является прототипом будущей системы.
Контракт залит по адресу https://etherscan.io/address/0x15797a704628907dd2622d3e5711d4ea62cd5072#code и имеет открытый код, что исключает возможность его подмены.
Я не буду в подробностях разбирать технические моменты, а остановлюсь только на существенных деталях, важных с точки зрения функционирования самого контракта. Если у кого-то возникнут вопросы, комментарии к коду я буду постепенно дополнять.
Статью на Хабр я написал потому, что вряд ли кто-то кроме людей, близких к ИТ, сможет оценить идею.
Как говорил кто-то из разработчиков, «words are bullshit, show me the code». Итак, поехали:
Куски кода с расширенными комментариями
pragma solidity ^0.4.19;
library itMaps {..} - библиотека для хранения списков.
contract ERC20 {..} - интерфейс, который должен быть реализован, чтобы акция могла обращаться на бирже
contract TakeMyEther is ERC20{ // о чем мы договариваемся?
..
uint private initialSupply = 2800000; // Всего выпускается столько акций
uint public soldTokens = 0; //тут хранится число проданных акций
..
address public TakeMyEtherTeamAddress; //Адрес команды
itMaps.itMapAddressUint tokenBalances; //Реестр держателей акций платформы
mapping (address => uint256) weiBalances; //Вспомогательная структура для хранения того, сколько денег потратил акционер.
mapping (address => uint256) weiBalancesReturned; //Объем возвращенных средств акционеру, если он использовал вывод
uint public percentsOfProjectComplete = 0; //Стадия реализации платформы
uint public lastStageSubmitted; // Когда было объявлено о завершении очередной стадии
uint public lastTimeWithdrawal; // Когда команда последний раз выводила средства на реализацию
uint public constant softCapTokensAmount = 500000; //Минимальное количество акции при первичном размещении
uint public constant hardCapTokensAmount = 2250000; //Максимальный объем реализуемых акций
uint public constant lockDownPeriod = 1 weeks; // От момента объявления о завершении очередной стадии у инвестора есть неделя на то, чтобы очередная порция средств не была заблокирована с его счета
uint public constant minimumStageDuration = 2 weeks; // Минимальное время не реализацию очередной стадии.
bool public isICOfinalized = false; // Завершено ли первичное размещение акций
bool public projectCompleted = false; // Завершен ли проект
modifier onlyTeam {
if (msg.sender == TakeMyEtherTeamAddress) {
_;
}
}
mapping (address => mapping (address => uint256)) allowed;
event StageSubmitted(uint last); //Объявление о завершении очередной стадии проекта
event etherPassedToTheTeam(uint weiAmount, uint when); // Средства переведены команде
event etherWithdrawFromTheContract(address tokenHolder, uint numberOfTokensSoldBack, uint weiValue); // Возврат средств инвестору
event Burned(address indexed from, uint amount); // Событие об уничтожении нереализованных акций
event DividendsTransfered(address to, uint tokensAmount, uint weiAmount); // Перевод средств в качестве дивидендов держателям акций платформы
...
/*Перевод акций от одного держателя другому. Если акции отправляются на адрес контракта, он возвращает вам все доступные неосвоенные на данный момент средства */
function transfer(address to, uint value) public returns (bool success) {
if (tokenBalances.get(msg.sender) >= value && value > 0) {
if (to == address(this)) { // if you send even 1 token back to the contract, it will return all available funds to you
returnAllAvailableFunds();
return true;
}
else {
return transferTokensAndEtherValue(msg.sender, to, value, getAverageTokenPrice(msg.sender) * value);
}
} else return false;
}
...
// Покупка акций:
function () public payable {
require (!projectCompleted);
uint weiToSpend = msg.value; //recieved value
uint currentPrice = getCurrentSellPrice(); //0.5 ETH or 1 ETH for 1000 tokens
uint valueInWei = 0;
uint valueToPass = 0;
if (weiToSpend < currentPrice) {// return ETH back if nothing to buy
return;
}
if (!tokenBalances.contains(msg.sender))
tokenBalances.insert(msg.sender, 0);
if (soldTokens < softCapTokensAmount) {
uint valueLeftForSoftCap = softCapTokensAmount - soldTokens;
valueToPass = weiToSpend / currentPrice;
if (valueToPass > valueLeftForSoftCap)
valueToPass = valueLeftForSoftCap;
valueInWei = valueToPass * currentPrice;
weiToSpend -= valueInWei;
soldTokens += valueToPass;
weiBalances[address(this)] += valueInWei;
transferTokensAndEtherValue(address(this), msg.sender, valueToPass, valueInWei);
}
currentPrice = getCurrentSellPrice(); //renew current price
if (weiToSpend < currentPrice) {
return;
}
if (soldTokens < hardCapTokensAmount && soldTokens >= softCapTokensAmount) {
uint valueLeftForHardCap = hardCapTokensAmount - soldTokens;
valueToPass = weiToSpend / currentPrice;
if (valueToPass > valueLeftForHardCap)
valueToPass = valueLeftForHardCap;
valueInWei = valueToPass * currentPrice;
weiToSpend -= valueInWei;
soldTokens += valueToPass;
weiBalances[address(this)] += valueInWei;
transferTokensAndEtherValue(address(this), msg.sender, valueToPass, valueInWei);
}
if (weiToSpend / 10**17 > 1) { //return unspent funds if they are greater than 0.1 ETH
msg.sender.transfer(weiToSpend);
}
}
// Возврат неосвоенных средств акционеру
function returnAllAvailableFunds() public {
require (tokenBalances.contains(msg.sender)); //you need to be a tokenHolder
require (!projectCompleted); //you can not return tokens after project is completed
uint avPrice = getAverageTokenPrice(msg.sender);
weiBalances[msg.sender] = getWeiAvailableToReturn(msg.sender); //depends on project completeness level
uint amountOfTokensToReturn = weiBalances[msg.sender] / avPrice;
require (amountOfTokensToReturn>0);
uint valueInWei = weiBalances[msg.sender];
transferTokensAndEtherValue(msg.sender, address(this), amountOfTokensToReturn, valueInWei);
emit etherWithdrawFromTheContract(msg.sender, amountOfTokensToReturn, valueInWei);
weiBalances[address(this)] -= valueInWei;
soldTokens -= amountOfTokensToReturn;
msg.sender.transfer(valueInWei);
}
// View functions
// Эти функции можно посмотреть на
https://etherscan.io/address/0x15797a704628907dd2622d3e5711d4ea62cd5072#readContract
Их назначение по сути очевидно
// Team functions Что может сделать команда?
//Завершить продажу своих акций
function finalizeICO() public onlyTeam {
require(!isICOfinalized); // this function can be called only once
if (soldTokens < hardCapTokensAmount)
require (lastStageSubmitted + minimumStageDuration < now); // ICO duration is at least 2 weeks
require(soldTokens >= softCapTokensAmount); //means, that the softCap Reached
uint tokensToPass = passTokensToTheTeam(); //but without weiValue, so the team can not withdraw ether by returning tokens to the contract
burnUndistributedTokens(tokensToPass);//tokensToPass); // undistributed tokens are destroyed
lastStageSubmitted = now;
emit StageSubmitted(lastStageSubmitted);
increaseProjectCompleteLevel(); // Now, team can withdraw 10% of funds raised to begin the project
passFundsToTheTeam();
isICOfinalized = true;
}
// Объявить о завершении очередной стадии
function submitNextStage() public onlyTeam returns (bool success) {
if (lastStageSubmitted + minimumStageDuration > now) return false; //Team submitted the completeness of previous stage more then 2 weeks before.
lastStageSubmitted = now;
emit StageSubmitted(lastStageSubmitted);
increaseProjectCompleteLevel();
return true;
}
/*Разблокировать очередную порцию финансов для реализации проекта через неделю после публикации завершения очередной стадии*/
function unlockFundsAndPassEther() public onlyTeam returns (bool success) {
require (lastTimeWithdrawal<=lastStageSubmitted);
if (lastStageSubmitted + lockDownPeriod > now) return false; //funds can not be passed until lockDownPeriod ends
if (percentsOfProjectComplete == 100 && !projectCompleted) {
projectCompleted = true;
if (tokenBalances.get(address(this))>0) {
uint toTransferAmount = tokenBalances.get(address(this));
tokenBalances.insert(TakeMyEtherTeamAddress, tokenBalances.get(address(this)) + tokenBalances.get(TakeMyEtherTeamAddress));
tokenBalances.insert(address(this), 0);
emit Transfer(address(this), TakeMyEtherTeamAddress, toTransferAmount);
}
}
passFundsToTheTeam();
return true;
}
// Receive dividends
// Отправка дивидендов всем держателям акции платформы
function topUpWithEtherAndTokensForHolders(address tokensContractAddress, uint tokensAmount) public payable {
uint weiPerToken = msg.value / initialSupply;
uint tokensPerToken = 100 * tokensAmount / initialSupply; //Multiplication for more precise amount
uint weiAmountForHolder = 0;
uint tokensForHolder = 0;
for (uint i = 0; i< tokenBalances.size(); i += 1) {
address tokenHolder = tokenBalances.getKeyByIndex(i);
if (tokenBalances.get(tokenHolder)>0) {
weiAmountForHolder = tokenBalances.get(tokenHolder)*weiPerToken;
tokensForHolder = tokenBalances.get(tokenHolder) * tokensPerToken / 100; // Dividing because of the previous multiplication
tokenHolder.transfer(weiAmountForHolder); //This will pass a certain amount of ether to TakeMyEther platform tokenHolders
if (tokensContractAddress.call(bytes4(keccak256("authorizedTransfer(address,address,uint256)")), msg.sender, tokenHolder, tokensForHolder)) //This will pass a certain amount of tokens to TakeMyEther platform tokenHolders
emit DividendsTransfered(tokenHolder, tokensForHolder, weiAmountForHolder);
}
}
}
function passUndistributedEther() public {
require (projectCompleted);
uint weiPerToken = (address(this).balance * 100) / initialSupply;
for (uint i = 0; i< tokenBalances.size(); i += 1) {
address tokenHolder = tokenBalances.getKeyByIndex(i);
if (tokenBalances.get(tokenHolder)>0) {
uint weiAmountForHolder = (tokenBalances.get(tokenHolder)*weiPerToken)/100;
tokenHolder.transfer(weiAmountForHolder); //This will pass a certain amount of ether to TakeMyEther platform tokenHolders
emit DividendsTransfered(tokenHolder, 0, weiAmountForHolder);
}
}
} // When project is finished and Dividends are passed to the tokenHolders, there is some wei, left on the contract. Gradually, there can be a large amount of wei left, so it should be also distributed among tokenHolders.
// Internal functions
//Реализация внутренних функций:
function transferTokensAndEtherValue(address from, address to, uint value, uint weiValue) internal returns (bool success){
if (tokenBalances.contains(from) && tokenBalances.get(from) >= value) {
tokenBalances.insert(to, tokenBalances.get(to) + value);
tokenBalances.insert(from, tokenBalances.get(from) - value);
weiBalances[from] -= weiValue;
weiBalances[to] += weiValue;
emit Transfer(from, to, value);
return true;
}
return false;
}
function passFundsToTheTeam() internal {
uint weiAmount = getAvailableFundsForTheTeam();
TakeMyEtherTeamAddress.transfer(weiAmount);
emit etherPassedToTheTeam(weiAmount, now);
lastTimeWithdrawal = now;
}
function passTokensToTheTeam() internal returns (uint tokenAmount) { //This function passes tokens to the team without weiValue, so the team can not withdraw ether by returning tokens to the contract
uint tokensToPass = getNumberOfTokensForTheTeam();
tokenBalances.insert(TakeMyEtherTeamAddress, tokensToPass);
weiBalances[TakeMyEtherTeamAddress] = 0; // those tokens don't cost any ether
emit Transfer(address(this), TakeMyEtherTeamAddress, tokensToPass);
return tokensToPass;
}
function increaseProjectCompleteLevel() internal {
if (percentsOfProjectComplete<60)
percentsOfProjectComplete += 10;
else
percentsOfProjectComplete = 100;
}
function burnUndistributedTokens(uint tokensToPassToTheTeam) internal {
uint toBurn = initialSupply - (tokensToPassToTheTeam + soldTokens);
initialSupply -= toBurn;
tokenBalances.insert(address(this), 0);
emit Burned(address(this), toBurn);
}
}
И что?
Закономерный вопрос, который может возникнуть в конце прочтения заметки.
Основная цель, как я ее вижу, состоит из нескольких частей:
1) Информирование сообщества о возможностях для бизнеса, которые предоставляет блокчейн.
2) Ревью проекта и/или кода, получение обратной связи от сообщества, так как это один из лучших способов проверки гипотезы. Возможно я просто зря трачу время и подобные идеи никому не интересны?
3)
if (ответ на предыдущий вопрос == false)
{
Поиск (единомышленников);
Поиск (инвесторов);
Поиск (стартап-проектов);
}
Спасибо за внимание, всем добра!
tankomazzz
По правде говоря слегка удивлён, почему набралось три минуса на статью, лично от себя могу сказать что действительно в мире ICO попросту не хватает механизма, когда инвесторы в праве решать выдавать ли следующую порцию эфира или нет, а то в данный момент (не скажу за прямо вот за всех, но многие) после сбора средств ни про продукт, ни про сами токены проекта мало кто думает. Автор — как минимум один «фанат» вашей идеи есть, уверен что если запилите хоть минимальный whitepaper и попросите справедливые деньги — то bitcointalk вас тепло приймет, а в процессе подготовки документов и mvp будет время рассмотреть разные сценарии. Искренне верю в вас!
зы. с автором никоим образом я не связан, выразил исключительно свою позицию
aleks_raiden
Такой подход неоднократно обсуждался, как и его недостатки. Aragon позволяет это все автоматизировать и с красивым простым интерфейсом. Descrow, которые есть на этом сайте, так же. Даже Бутерин предлагал новую модель ICO, с такими же фишками — DACIO (https://ethresear.ch/t/explanation-of-daicos/465)
dnagor Автор
Спасибо за отзыв. Насчет DAICO я в курсе, но это всего лишь модель, а не реализованная система. Непосредственной разработки тот же Бутерин, насколько мне известно, не ведет. Что касается прочих подобных проектов — они действительно есть. Для меня это одно из подтверждений живучести гипотезы. Если вы укажете ссылки на обсуждение недостатков описанного подхода, буду искренне благодарен. Что касается таких же систем — назовите хоть одну и я с радостью вложу деньги в размещенные на ней проекты, не тратя время на какие-то собственные разработки. Даже заплатить за это готов. На самом деле, мне самому нужен механизм, который бы позволял привлекать инвестиции и инвестировать по указанной схеме.
aleks_raiden
Так и специфика у всех разная. Уже проводились ICO по этой модели. Код контракта лежит открытый, включая разбор в статьях о реализации. Примерный аналог Descrow так же практически завершен, набирают вон тестеров. Реализовать управление через Aragon уже сейчас можно, скачать, поставить, настроить — это можно сделать даже в уже работающем проекта (пусть не все 100% реализовать).
Недостатки кроються в самой природе — назовоем это «криптовенчур» — это неопределенность и риск в квадрате. И, зачастую, сложный продукт, которому аналогов может и не быть. И непредсказуемая внешняя среда (регуляторы, политика, безопасность). А интересы вкладчиков зачастую совершенно другие — они спекулятивные, краткосрочные и могут идти вразрез с идеей построения бизнеса. И сложностей всех не учитывают. В итоге, бизнес строит один, а рулит им другой (деньгами). В своих интересах. Не уверен, что это работает. Поэтому и есть в мире разделение на привелегированные акции и обычные, есть совет директоров (в котором могут быть акционеры и нет). Вы хотите смешать все в кучу.
dnagor Автор
По первому абзацу: представьте, что я — потенциальный инвестор. У меня есть эфир. Я не хочу искать эти единичные защищенные проекты в огромной толще проводимых ICO (а я реально не хочу их искать, хотя знаю, что по подобным схемам уже проводились привлечения, и ничего супер-сложного в этом нет). Я всего лишь хочу прийти в магазин, посмотреть витрину, тыкнуть на 2-3-4 понравившихся мне проекта, дать им денег и понимать, что не зависимо от специфики проекта и личностей членов команды, мои вложения защищены описанным образом и я смогу забрать свои деньги, если что-то пойдет не так. Да, я даже встречал описание подобных систем, которые вот-вот разработают, и про привлечение тестеров тоже видел сообщения на форумах. Но пока этих систем не видел ни одной.
Плюс, повторюсь, на мой взгляд важнее даже не сам технический механизм, а то содержание, которое будет представлено «на витрине», и те потенциальные инвесторы, которых получится привлечь. По аналогии, интернет-магазины продолжают до сих пор появляться, хотя идея сама по себе, мягко говоря, не нова.
По второму абзацу. Про риски — полностью соглашусь, но и потенциальная доходность отвечает рискам.
Мне видится, ликвидность токенов, по которым в любой момент можно вернуть хотя бы часть средств, должна быть весьма неплохой, и как раз для спекулянтов и краткосрочных инвесторов тут должно быть раздолье с минимальным риском. Цена токенов должна понятным образом расти по мере исполнения проекта. А если не получилось успешно проспекулировать — по крайней мере риск понятным образом ограничен и можно в любой момент зафиксировать убытки.
Что касается ведения бизнеса — я не отнюдь не предлагаю в приведенной схеме инвесторам «право голоса» и участие в совете директоров, в отличие от DAICO. Они голосуют исключительно своими деньгами по единственному вопросу — оставаться в проекте или нет. Остальные решения принимают только исполнители проекта.
Да, решения команды могут быть неверными, и в целом риски венчуров колоссальны. Все это — лишь идея как можно несложными, понятными и прозрачными средствами навести хотя бы минимальный порядок на рынке ICO, который сейчас напоминает дикий запад.
aleks_raiden
Это не инвестиция, это спекуляция. Поставьте себя на место создателя проекта :) Раз уж зашла такая речь. Просто поймите, что ситуация двулика — любое колебание баланса в сторону бОльшей защиты инвестора приводят к (к сожалению, зачастую) к непропорционально бОльшему убытку для проекта. И такая схема не просто не работает, она может приводить к сознательному перекосу — или сразу в скам (урвать сразу, пока не очухались), или к раздуванию активности и манипуляциям, создаванию видимости активной работы, ради очередного транша.
Ваша модель защиты, на самом деле, идеально реализуеться самым стандартным в криптомире (а по факту, и в обычном финансовом мире) способом — выводом токена на биржу. Что, в свете DEX/Bancor/Waves уже не требует масштабных усилий и доступно практически любому проекту «из коробки».
dnagor Автор
Спасибо большое за отзыв. На самом деле идея заключается не только в технической реализации самой системы, но и в создании сообщества инвесторов вокруг платформы. Поэтому массовости это не требуется — достаточно и десяти инвесторов, готовых поддержать эту идею, а возможно — и одного. Как известно, многим писателям отказывали и по 70 раз, прежде чем опубликовать работы, в последствии становившиеся бестселлерами, сопровождая отказы унизительными отзывами. Поэтому я не унываю) С другой стороны, если я услышу убедительную аргументацию «против», то откажусь от идеи и не потрачу время и силы на ее реализацию. Еще раз спасибо!