18.10.17 - 01-15
CROWDSALE
ПРИВЛЕЧЕНИЕ СРЕДСТВ У ДРУЗЕЙ БЕЗ ТРЕТЬЕЙ СТОРОНЫ
Что делать, если фолс-саунд превысит свою цель?
Неограниченное количество людей
https://www.ethereum.org/crowdsale
CROWDSALE
ПРИВЛЕЧЕНИЕ СРЕДСТВ У ДРУЗЕЙ БЕЗ ТРЕТЬЕЙ СТОРОНЫ
Иногда хорошая идея требует больших средств и коллективных усилий. Вы можете попросить о пожертвованиях, но доноры предпочитают отдавать проекты, которые они более уверены, получат тягу и надлежащее финансирование. Это пример, когда фокусное изображение было бы идеальным: вы создали цель и срок для ее достижения. Если вы пропустите свою цель, пожертвования возвращаются, что снижает риск для доноров. Поскольку код открыт и проверен, нет необходимости в централизованной, надежной платформе, и поэтому единственная плата, которую каждый будет платить, - это всего лишь плата за газ.
ТОКЕНЫ И DAO
В этом примере мы сделаем лучшее обратное преобразование, решая две важные проблемы: как вознаграждение управляется и хранится, и как деньги расходуются после того, как средства будут подняты.
Вознаграждения в crowdfundings обычно обрабатываются центральной неизменной базой данных, которая отслеживает всех доноров: любой, кто пропустил крайний срок для кампании, больше не может попасть, и любой донор, который передумал, не может выбраться. Вместо этого мы собираемся сделать это децентрализованным способом и просто создать токен, чтобы отслеживать вознаграждения, каждый, кто вносит вклад, получает токен, который они могут торговать, продавать или хранить на потом. Когда придет время, чтобы дать физическую награду, продюсер должен только обменять токены на настоящие продукты. Доноры получают свои жетоны, даже если проект не достигает своих целей, как сувенир.
Кроме того, как правило, те, кто финансирует, не могут сказать, как деньги расходуются после того, как средства были привлечены, а плохое управление часто заставляет проекты никогда ничего не доставлять. В этом проекте мы будем использовать Демократическую организацию, которая должна будет утвердить любые деньги, выходящие из системы. Это часто называют толпой или толпой капитала и настолько фундаментальным, что в некоторых случаях токен может быть самой наградой, особенно в проектах, где группа людей собирается вместе, чтобы построить общее общественное благо.
Если вы просто тестируете, переключите кошелек на тестовую сеть и начните добычу.
Прежде всего, создайте токен фиксированной подачи . В этом примере мы собираемся создать запас 100 , использовать гаджеты имен , поле emoji (📦) в качестве символа и 0 знаков после запятой. Разверните его и сохраните адрес.
Теперь создайте ассоциацию акционеров . В этом примере мы будем использовать адрес токена, который мы только что создали, в качестве адреса акций , минимальный кворум 10 и 1500 минут (25 часов) в качестве времени голосования. Разверните этот контракт и сохраните адрес.
КОД
Теперь скопируйте этот код и создайте фолдсаль:
pragma solidity ^0.4.16; interface token { function transfer(address receiver, uint amount); } contract Crowdsale { address public beneficiary; uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price; token public tokenReward; mapping(address => uint256) public balanceOf; bool fundingGoalReached = false; bool crowdsaleClosed = false; event GoalReached(address beneficiary, uint amountRaised); event FundTransfer(address backer, uint amount, bool isContribution); /** * Constrctor function * * Setup the owner */ function Crowdsale( address ifSuccessfulSendTo, uint fundingGoalInEthers, uint durationInMinutes, uint etherCostOfEachToken, address addressOfTokenUsedAsReward ) { beneficiary = ifSuccessfulSendTo; fundingGoal = fundingGoalInEthers * 1 ether; deadline = now + durationInMinutes * 1 minutes; price = etherCostOfEachToken * 1 ether; tokenReward = token(addressOfTokenUsedAsReward); } /** * Fallback function * * The function without name is the default function that is called whenever anyone sends funds to a contract */ function () payable { require(!crowdsaleClosed); uint amount = msg.value; balanceOf[msg.sender] += amount; amountRaised += amount; tokenReward.transfer(msg.sender, amount / price); FundTransfer(msg.sender, amount, true); } modifier afterDeadline() { if (now >= deadline) _; } /** * Check if goal was reached * * Checks if the goal or time limit has been reached and ends the campaign */ function checkGoalReached() afterDeadline { if (amountRaised >= fundingGoal){ fundingGoalReached = true; GoalReached(beneficiary, amountRaised); } crowdsaleClosed = true; } /** * Withdraw the funds * * Checks to see if goal or time limit has been reached, and if so, and the funding goal was reached, * sends the entire amount to the beneficiary. If goal was not reached, each contributor can withdraw * the amount they contributed. */ function safeWithdrawal() afterDeadline { if (!fundingGoalReached) { uint amount = balanceOf[msg.sender]; balanceOf[msg.sender] = 0; if (amount > 0) { if (msg.sender.send(amount)) { FundTransfer(msg.sender, amount, false); } else { balanceOf[msg.sender] = amount; } } } if (fundingGoalReached && beneficiary == msg.sender) { if (beneficiary.send(amountRaised)) { FundTransfer(beneficiary, amountRaised, false); } else { //If we fail to send the funds to beneficiary, unlock funders balance fundingGoalReached = false; } } } }
ОСНОВНЫЕ МОМЕНТЫ КОДА
Обратите внимание, что в функции Crowdsale (той, которая называется созданием контракта), как устанавливаются конечные сроки переменных и financeGoal :
fundingGoal = fundingGoalInEthers * 1 ether;deadline = now + durationInMinutes * 1 minutes;price = etherCostOfEachToken * 1 ether;
Это некоторые из специальных ключевых слов в прочности, которые помогают вам кодировать, позволяя вам оценивать некоторые вещи, такие как 1 эфир == 1000 финней или 2 дня == 48 часов . Внутри системы все эфирные количества отслеживаются в wei , наименьшей делимой единице эфира. Приведенный выше код преобразует цель финансирования в Wei, умножая его на 1 000 000 000 000 000 000 (это то, к чему преобразует специальный эфир словаря). Следующая строка создает метку, которая ровно X минут с сегодняшнего дня также при помощи комбинации специальных ключевых слов в настоящее время и минут . Для получения более глобальных ключевых слов проверьте документацию о надежности для доступных глобальных переменных,
Следующая строка будет конкретизировать контракт по указанному адресу:
Обратите внимание, что контракт понимает, что означает токен , потому что мы определили его раньше, запустив код:
tokenReward = token(addressOfTokenUsedAsReward);
contract token { function transfer(address receiver, uint amount){ } }
Это не полностью описывает, как работает контракт или все функции, которые он имеет, но описывает только те, которые требуются для этого контракта: токен - это контракт с передаточной функцией, и у нас есть один по этому адресу.
КАК ИСПОЛЬЗОВАТЬ
Перейдите к контрактам, а затем разверните контракт :
Поместите адрес организации, которую вы только что создали в поле, в случае успеха, отправьте .
Положить 250 эфиров в качестве цели финансирования
Если вы просто делаете это для теста или демонстрации, ставьте длительность фолссала как 3-10 минут, но если вы действительно собираете средства, вы можете поместить большую сумму, например 45 000 (31 день).
Стоимость эфира каждого токена должна рассчитываться на основе того, сколько токенов вы выставили на продажу (максимум того, сколько вы добавили в качестве «начального предложения» вашего токена на предыдущем шаге). В этом примере добавьте 5 эфиров.
Адрес маркера, который вы создали, должен быть добавлен в адрес награды маркера
Положите цену на газ, нажмите «Развернуть» и дождитесь, когда будет создан ваш форекс. После того, как страница crowdsale создана, вам теперь нужно наложить достаточно вознаграждений, чтобы она могла выплатить вознаграждение обратно. Щелкните по адресу crowdsale, затем отложите и отправьте 50 гаджетов в куклу.
У меня есть 100 гаджетов. Почему бы не продать их все?
Это очень важный момент. Толпа, которую мы строим, будет полностью контролироваться держателями токенов. Это создает опасность того, что кто-то, кто контролирует 50% + 1 всех токенов, сможет отправить все средства себе. Вы можете попытаться создать специальный код в договоре ассоциации, чтобы предотвратить эти враждебные поглощения, или вместо этого вы можете получить все средства, отправленные на простой адрес. Для упрощения мы просто продаем половину всех гаджетов: если вы хотите еще больше децентрализовать это, разделите оставшуюся половину между доверенными организациями.
ПОДНИМИТЕ СРЕДСТВА
Как только у толпы есть все необходимые маркеры, внести свой вклад в это легко, и вы можете сделать это из любого эфирного кошелька: просто отправьте ему средства. Вы можете увидеть соответствующий бит кода здесь:
function () { require(!crowdsaleClosed); uint amount = msg.value; // ...
Безымянная функция является функцией по умолчанию выполняется каждый раз , когда контракт получает эфир. Эта функция будет автоматически проверять, активен ли файл crowdsale, рассчитать, сколько жетонов выкупит вызывающий и отправил эквивалент. Если фолсусаль закончился или если контракт не соответствует токенам, контракт будет означать, что исполнение будет прекращено, и эфир отправлен будет возвращен (но весь газ будет потрачен).
Это имеет то преимущество, что контракт предотвращает попадание в ситуацию, когда кто-то останется без эфира или жетонов. В предыдущей версии этого контракта мы также сами могли бы разрушить контракт после окончания фолдсала: это означало бы, что любая транзакция, отправленная после этого момента, потеряет свои средства. Создавая резервную функцию, которая бросается, когда продажа закончена, мы не позволяем никому терять деньги.
Контракт имеет функцию safeWithdrawl () без каких-либо параметров, которые могут быть выполнены бенефициаром для доступа к поднятой сумме или спонсорам, чтобы вернуть свои средства в случае неудачного сбора средств.
ЧТО ДЕЛАТЬ, ЕСЛИ ФОЛС-САУНД ПРЕВЫСИТ СВОЮ ЦЕЛЬ?
В нашем коде могут произойти только две вещи: либо толпа достигает своей цели, либо нет. Поскольку количество токенов ограничено, это означает, что после достижения цели никто другой не может внести свой вклад. Но история crowdfunding полна проектов, которые превышают их цели за гораздо меньшее время, чем прогнозировалось или которые поднимались много раз по сравнению с требуемой суммой.
НЕОГРАНИЧЕННОЕ КОЛИЧЕСТВО ЛЮДЕЙ
Поэтому мы немного изменим наш проект, чтобы вместо отправки ограниченного набора токенов проект фактически создавал новый токен из тонкого воздуха, когда кто-то посылал им эфир. Прежде всего, нам нужно создать маркерный токен .
Затем измените команду crowdsale, чтобы переименовать все упоминания о передаче в mintToken :
contract token { function mintToken(address receiver, uint amount){ } } // ... function () { // ... tokenReward.mintToken(msg.sender, amount / price); // ... }
После того, как вы опубликовали crowdsale контракт, получить свой адрес и перейдите в ваш маркеров контракта выполнить изменение структуры собственности функции. Это позволит вашему crowdsale называть функцию маркера монетного двора столько, сколько захочет.
Предупреждение: Это открывает вам опасность враждебного захвата. В любой момент во время толпы людей каждый, кто жертвует больше, чем уже собрано, сможет контролировать весь пирог и украсть его. Есть много стратегий, чтобы предотвратить это, но реализация будет оставлена в качестве упражнения для читателя:
Измените так называемый «фолд», что, когда купленный токен купит, также отправьте столько жетонов на счет учредителя, чтобы они всегда контролировали 50% проекта
Измените Организацию, чтобы создать право вето какой-либо доверенной третьей стороне, которая может остановить любое враждебное предложение
Измените токен, чтобы позволить центральной доверенной стороне замораживать учетные записи токенов, чтобы потребовать проверки того, что нет ни одной сущности, контролирующей большинство из них
ПЛАНИРОВАНИЕ ВЫЗОВА
Контракты Ethereum пассивны, поскольку они могут делать что-то только после их активации. К счастью, существуют некоторые сторонние сервисы сообщества, которые предоставляют вам эту услугу: будильник Ethereum является открытым рынком, где каждый может получать эфир для выполнения запланированных вызовов или оплаты эфира, чтобы запланировать их. В этом руководстве будет использоваться версия службы оповещений 0.6.0 . Документация для этой версии доступна здесь .
Во-первых, вам нужно добавить контракт в свой список наблюдения. Перейдите на вкладку « Контракты », а затем « Наблюдайте за контрактом» ( не разворачивайте контракт ): укажите имя «Alarm Clock» Ethereum, используйте 0xe109EcB193841aF9dA3110c80FDd365D1C23Be2a в качестве адреса (значок должен выглядеть как зеленое глазное существо) и добавьте этот код в качестве интерфейса Json :
[{"constant":false,"inputs":[{"name":"contractAddress","type":"address"},{"name":"abiSignature","type":"bytes4"},{"name":"targetBlock","type":"uint256"}],"name":"scheduleCall","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"contractAddress","type":"address"},{"name":"abiSignature","type":"bytes4"},{"name":"targetBlock","type":"uint256"},{"name":"suggestedGas","type":"uint256"},{"name":"gracePeriod","type":"uint8"}],"name":"scheduleCall","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"getDefaultPayment","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"getDefaultFee","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"contractAddress","type":"address"},{"name":"abiSignature","type":"bytes4"},{"name":"targetBlock","type":"uint256"},{"name":"suggestedGas","type":"uint256"}],"name":"scheduleCall","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"callAddress","type":"address"}],"name":"getNextCallSibling","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"callAddress","type":"address"}],"name":"isKnownCall","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"basePayment","type":"uint256"}],"name":"getMinimumCallCost","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"contractAddress","type":"address"},{"name":"abiSignature","type":"bytes4"},{"name":"targetBlock","type":"uint256"},{"name":"suggestedGas","type":"uint256"},{"name":"gracePeriod","type":"uint8"},{"name":"basePayment","type":"uint256"}],"name":"scheduleCall","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMinimumCallCost","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"contractAddress","type":"address"},{"name":"abiSignature","type":"bytes4"},{"name":"targetBlock","type":"uint256"},{"name":"suggestedGas","type":"uint256"},{"name":"gracePeriod","type":"uint8"},{"name":"basePayment","type":"uint256"},{"name":"baseFee","type":"uint256"}],"name":"scheduleCall","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"basePayment","type":"uint256"},{"name":"baseFee","type":"uint256"}],"name":"getMinimumCallCost","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMinimumCallGas","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"getCallWindowSize","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"blockNumber","type":"uint256"}],"name":"getNextCall","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMinimumGracePeriod","outputs":[{"name":"","type":"uint256"}],"type":"function"}]
Совет. Если вы находитесь в тестовой сети, используйте вместо этого адрес 0xb8Da699d7FB01289D4EF718A55C3174971092BEf
Нажмите на зеленый значок, который вы только что добавили, а затем выберите вызов функции под заголовком « Write to contract» . Будет несколько функций Schedule Call , выберите первый, который имеет только три поля:
contractAddress будет адресом развернутого контракта с куклом.
abiSignature будет 0x01cb3b20 . Вы можете определить подпись для любой функции, пытаясь выполнить их, но в окне подтверждения вместо ввода пароля скопируйте код в поле « Данные» . Подпись функции - это первые 10 символов, выделенные жирным шрифтом.
targetBlock - это номер блока, в котором вы хотите, чтобы функция выполнялась, читайте ниже, чтобы рассчитать оценку.
Контракт crowdsale определяет предельный срок, используя временную метку, но будильник в настоящее время расписывает вызовы на основе номеров блоков. Поскольку ethereum имеет блок-время приблизительно 17 секунд, нам нужно вычислить номер блока, который будет вероятностно пройденный крайний срок. Мы можем сделать это с помощью формулы current_block_number + duration_in_minutes * 60/17 + buffer, где buffer - это количество блоков, которое достаточно велико, чтобы вы могли положиться на него, возникающее после крайнего срока. Для короткого толчка, превышающего один день, должен быть достаточным буфер из 200 блоков. При длительности до 30 дней вам, вероятно, следует выбрать число ближе к 5000.
Вы можете использовать следующую таблицу для приблизительных оценок того, сколько блоков нужно добавить к текущему блоку для вычисления targetBlock .
Продолжительность 1 час (60 минут): 212 блоков
Продолжительность 1 дня (1440 минут): 5082 блока
1 неделя (10 800 минут): 38 117 блоков
Продолжительность 1 месяц (44 640 минут): 157 553 блока
В поле « Отправить» вам нужно отправить достаточно эфира, чтобы оплатить транзакционную плату, а также еще немного заплатить планировщик. Любые дополнительные деньги, которые будут отправлены, будут возвращены, поэтому отправка не менее 0,25 эфира, вероятно, приведет вас в безопасное место.
После этого просто нажмите «выполнить», и ваш вызов будет запланирован. Нет никаких гарантий того, что кто-то действительно его выполнит, поэтому вы должны проверить, после того, как крайний срок прошел, чтобы быть уверенным.