Como escrever um contrato inteligente para a ICO em 5 minutos



Olá pessoal! Neste artigo, mostrarei como iniciar um contrato inteligente de coleta de dinheiro para sua ICO no Ethereum em 5 minutos e vários comandos no terminal. Este ensaio potencialmente economizará dezenas de milhares de dólares, já que qualquer programador - e também não um programador - poderá lançar um contrato inteligente auditado e seguro (em vez de pagar US $ 15.000 a US $ 75.000 pelo desenvolvimento). Em resumo, você pode enviar dinheiro para este contrato inteligente e receber tokens ERC20 por ele. Pode-se dizer que este artigo é uma coleção de toda a experiência adquirida ao lançar uma OIC para o meu projeto.

Na Internet, esses já estão cheios de artigos sobre contratos inteligentes, mas assim que você começa a escrever um, você se depara com o fato de que as informações são repetidas em todos os lugares e simplesmente não há tutoriais sobre como enganar seu ERC20, ou eles já estão desatualizados. A propósito, para que este artigo permaneça relevante, tentarei indicar possíveis locais onde ele pode se tornar obsoleto (e como corrigi-lo). Vamos lá!

Solidez


Esse é o nome do idioma principal que a equipe de kefir desenvolveu para lançar contratos inteligentes. Se você é um programador, basta examinar a documentação da linguagem - é indecentemente simples. A propósito, eles simplificaram o processo, tornando mais difícil cometer um erro ao escrever um contrato inteligente. Portanto, absolutamente qualquer programador, pelo menos no nível júnior, será capaz de descobrir isso. Não há absolutamente nenhum sentido em pagar grandes quantias de dinheiro a desenvolvedores que conhecem solidez - será uma ordem de magnitude mais barata treinar um desenvolvedor existente.

Contratos inteligentes


... e tudo que você precisa saber sobre eles. Pule esta seção se você não for um programador. Um contrato inteligente é um pedaço de código. Em princípio, esta é uma classe de solidez (OOP, sim), que possui dois tipos de funções: mudança de estado e não mudança de estado. Bem, para executar funções em um contrato inteligente apenas enviando kefir, é necessário marcar esta função como payable .

State é um data warehouse, blockchain, EPT. Os contratos podem alterar a blockchain (estado, armazenamento) - mas para alterar a blockchain você precisa pagar kefir aos mineradores. Como eles compartilharão o kefir não será analisado na estrutura deste artigo. O pagamento aos mineradores pela execução do código de alteração de estado é chamado Gás. Se alguém de fora jogar kefir para o endereço de um contrato inteligente com uma chamada para uma função marcada como payable mas não marcada Constant , View ou Pure , a quantidade necessária de kefir para pagamento aos mineiros será deduzida do valor enviado. Normalmente, nos tokens do ERC20, essas são funções que fornecem o remetente de token para kefir ou transferem tokens de um detentor de token para outro.

E se você marcar uma função no contrato com as palavras Constant ou View (elas significam a mesma coisa, elas permitem apenas a leitura do estado) ou Pure (a mesma coisa, você nem lê o estado), não precisará gastar kefir na execução dessa função! Vou dizer ainda mais que essas funções não precisam ser chamadas pelas transações - afinal, qualquer cliente de iogurte pode teoricamente executá-lo em casa - e ninguém precisa mais saber sobre isso (afinal, nada está escrito no blockchain).

E há duas coisas importantes na solidez: herança múltipla e modificadores de função. Você também precisa saber sobre eles.

O primeiro - contratos justos podem ser herdados simultaneamente de várias classes, como TimedCrowdsale , CappedCrowdsale , MintedCrowdsale , Ownable - enquanto as funções dos construtores também são lançadas uma após a outra - mas vou explicar isso mais tarde, como exemplo.

A segunda é a capacidade de criar funções que serão inseridas em outras funções. É como um encapsulamento simples, apenas um pouco mais flexível - é literalmente um modelo de função. Ao criar um modificador, você escreve o caractere especial _ onde quer dizer o código de uma função usando esse modificador. Ou seja, modificadores não são apenas funcionalidades encapsuladas que retornam um valor; esse é um modelo de função quando o código de um modificador é literalmente inserido em uma função usando esse modificador.

Vamos seguir praticando.

Ambiente de cozinha


Se você não souber o que é o Terminal, leia este artigo aqui . Se você estiver no Windows, configure um terminal via WLS. Se você já está familiarizado com o Terminal, vamos continuar. Além disso, coloque-se imediatamente Node.js - será necessário para as próximas etapas. É melhor instalar o LTS, mas, de fato, não faz diferença qual das versões modernas do nó instalar.

A primeira coisa que instalamos e iniciamos imediatamente o processo de sincronização do bloco é geth . Em resumo, este é um utilitário escrito em Go que nos permitirá executar o nó ether no computador local e conectar-se às redes reais e de teste. Você pode instalar via instaladores , mas eu recomendo que você geth imediatamente no Terminal, conforme descrito aqui . Você pode verificar se seus padrões geth estão geth executando o comando no Terminal:

 geth version 

Se você cuspir a versão geth - tudo está em aberto, continue o tutorial. Se não - ruim, correto; parece que você precisará fazer amor com o Terminal e o sistema operacional - mas não é a primeira vez que você descobre isso. Como instalar o geth, execute o comando no Terminal:

 geth --testnet console 

Isso iniciará o processo de sincronização do seu nó com o servidor de teste, cujos blocos podem ser visualizados aqui . Você pode verificar se sincronizou com a rede no console geth :

 eth.blockNumber #  0 —     eth.syncing #     false,     

O processo de sincronização levou de 1 a 4 horas - quando como. Além disso, além da sincronização de blocos, você também precisará aguardar a sincronização de estado - geralmente é mais longa que a sincronização de blocos. Você também pode usar geth com o sinalizador --light -, a sincronização dura de alguns segundos a um minuto e ainda é possível implantar contratos.

Ok, instalamos o primeiro utilitário - coloque o próximo. Precisamos colocar um análogo de geth , apenas uma simulação de blockchain muito local - testrpc . Sim, temos 3 blockchains :

  • testrpc - simulação local de blockchain; rápido, mas falso e armazenado apenas em sua máquina
  • geth --testnet já é um blockchain real, mas você não perde dinheiro onde pode obter kefir e testar todos os geth --testnet gratuitamente
  • geth - mainnet, principal, blockchain real, kefir real; tudo de uma maneira adulta, os erros aqui são as perdas de kefir real

Dessa forma, iniciaremos o contrato de teste com o testrpc , em seguida instalá-lo no geth --testnet e, em seguida, fazer o download diretamente no geth .

testrpc executando o seguinte comando:

 npm install -g ethereumjs-testrpc 

Bem, ou sobe imediatamente com uma trufa, já que agora o testrpc sob a asa da trufa e é chamado ganache-cli . Embora o diabo saiba, tudo funcionou testrpc com o testrpc baunilha. E se funcionar, não toque, como fui ensinado na academia intergaláctica. Você também pode executá-lo para verificar a instalação registrando truffle no console, mas o blockchain de teste já está sincronizado conosco - não vamos incomodar.

Bem, descobri as cadeias? Agora existem nós e o teste está sincronizado? Colocamos um utilitário conveniente para trabalhar com contratos inteligentes no kefir - truffle , com o seguinte comando:

 npm install -g truffle truffle version #  ,  ,   

O Truffle é uma ferramenta que permite manter contratos inteligentes em arquivos diferentes, importar outros arquivos e também compilar seu código de contrato inteligente em um bytecode grande (ilegível por uma pessoa); ele encontra automaticamente o geth execução local (teste e teste real). ) ou testrpc , implante seu contrato inteligente nessa rede. Além disso, verifica se há erros no código do contrato inteligente e as transações concluídas recentemente também ajudam a depurar . Masthead, em suma.

Nesse estágio, você deve ter instalado: testrpc , geth , truffle - se algo estiver faltando ou a versão não for enviada ao console mediante solicitação, corrija-o; caso contrário, você não terá sucesso.

Além disso, joguei um script simples do bash que instalará tudo para você. Chamado assim:

 source <(curl -s https://raw.githubusercontent.com/backmeupplz/eth-installer/master/install.sh) 

- mas eu nunca testei ainda, então não tenho certeza do seu desempenho. No entanto, ficarei feliz em receber solicitações.

Contrato Figash


Tudo já foi inventado e escrito para você - isso é bom. Um pouco de estamenha será o mesmo - mas tentarei minimizá-lo para você. Usaremos contratos ERC20 já prontos do OpenZeppelin - esse é agora o padrão do setor, eles passaram na auditoria e, de fato, todos usam seu código. Muito obrigado por sua contribuição ao código aberto.

Faça do cd uma pasta segura e depois escreva:

 mkdir contract && cd contract 

Nesta pasta, vamos trabalhar. Crie um esboço aqui para o nosso contrato inteligente:

 truffle init 

Tropeçar, claramente. Agora temos duas pastas muito importantes nas quais escalaremos: contracts e migrations . O primeiro é o código para nossos contratos, o segundo é o código para as trufas saberem o que fazer ao implantar contratos na blockchain.

Em seguida, precisamos pegar o código atual do contrato inteligente a partir da NPM e, de fato, iniciar o próprio projeto:

 npm init -y #     ( -y) npm install -E openzeppelin-solidity #       ( -E) 

Bem, o código de contratos inteligentes do OpenZeppelin está no nosso bolso na pasta node_modules/openzeppelin-solidity/contracts . Agora vamos para a pasta principal dos contracts , MyToken.sol todos os arquivos e adicionamos os arquivos MyToken.sol e MyCrowdsale.sol - naturalmente, você MyCrowdsale.sol seus contratos de maneira diferente. O primeiro será um contrato para o nosso Token ERC20 e o segundo será um contrato da nossa OIC, que aceitará o kefir e distribuirá o MyToken pessoas. Este artigo pode estar desatualizado, mas você sempre pode ver como o OpenZeppelin sugere que você crie contratos em seu repositório . É assim que o MyToken.sol se parecerá MyToken.sol :

 pragma solidity ^0.4.23; // Imports import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol"; // Main token smart contract contract MyToken is MintableToken { string public constant name = "My Token"; string public constant symbol = "MTKN"; uint8 public constant decimals = 18; } 

Bom - você tem um contrato inteligente com seu próprio token (basta alterar os nomes nas constantes)! Você pode ver que MintableToken herança existe no MintableToken - mas tudo é o mais simples possível. É um token que pode ser emitido (do inglês “Mint” - para mint), e somente o proprietário tem o direito de emiti-lo, pois o MintableToken também herda do Ownable . Além disso, o MintableToken também herda das classes de tokens do ERC20 escritas pelo OpenZeppelin, nas quais a interface do ERC20 é implementada:

 contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } 

Sim, aqui você tem toda a interface do ERC20. Isso é difícil? Eu acho que não. Ele oferece a oportunidade de verificar quantos tokens foram emitidos, verificar o saldo do endereço e transferir tokens para outro endereço, divulgando um evento de transferência para clientes de kefir leve na rede. E tudo isso você ganha de graça no MyToken.sol graças ao trabalho do OpenZeppelin - eles são ótimos.

E agora vamos para a parte principal da nossa OIC - precisamos aceitar o kefir e distribuir o MyToken ! É assim que o seu MyCrowdsale.sol será:

 pragma solidity ^0.4.23; // Imports import "../node_modules/openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol"; import "../node_modules/openzeppelin-solidity/contracts/crowdsale/distribution/RefundableCrowdsale.sol"; import "../node_modules/openzeppelin-solidity/contracts/crowdsale/validation/CappedCrowdsale.sol"; import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol"; contract MyCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale { constructor( uint256 _openingTime, uint256 _closingTime, uint256 _rate, address _wallet, uint256 _cap, MintableToken _token, uint256 _goal ) public Crowdsale(_rate, _wallet, _token) CappedCrowdsale(_cap) TimedCrowdsale(_openingTime, _closingTime) RefundableCrowdsale(_goal) { //   ,  ,    // ,     require(_goal <= _cap); } } 

So-so-so-so, o que há conosco? Meninos, contratos inteligentes? Nossa venda pública de tokens herda três das propriedades mais populares: possui um limite máximo, que não pode mais ser coletado; tampa macia, não coletando quais ésteres são devolvidos; horário de início e término da venda do token. De fato, o que mais é necessário para a felicidade?

Programadores, observe como os construtores de várias classes de herança são organizados em uma linha e obtém argumentos do construtor principal de MyCrowdsale . Além disso, verificamos que a hardkey é maior que a softkey - Ales Gut! Além disso, não se MyCrowdsale parâmetros MyCrowdsale no construtor MyCrowdsale - nós os transmitiremos no estágio de implantação do contrato na trufa.

Isso é tudo - você tem contratos prontos de seu próprio token ERC20 e até mesmo um contrato inteligente da OIC, configurado de acordo com o seu desejo e distribuindo seus tokens para kefir. Além disso, é suportado por todas as carteiras ERC20 - um erro! Vamos passar para testes manuais e implantação.

Migrações


Como eu disse anteriormente, testaremos sequencialmente em três redes blockchain, mas o processo de teste com canetas será sempre o mesmo. Vamos começar com testrpc , depois seguir para geth --testnet e continuar com geth . Sou faróis, acabamos de escrever o código, vamos tentar compilá-lo. Na pasta do projeto, escreva:

 truffle compile 

Se tudo for compilado sem problemas, você verá a build , que conterá o krakozyab da trufa para que possa incorporar o bytecode de seus contratos inteligentes na blockchain. Antes de implantar contratos inteligentes, precisamos dizer à trufa o que fazer. A implantação de trufas de contratos inteligentes é chamada migração - bem, vamos nos ater a essa terminologia. Vá para migrations/1_initial_migration.js e altere-o da seguinte maneira:

 const token = artifacts.require("../contracts/MyToken.sol"); const crowdsale = artifacts.require("../contracts/MyCrowdsale.sol"); module.exports = function(deployer, network, accounts) { const openingTime = 1514764800; // 15  2018 const closingTime = 1561939200; // 1  2019 const rate = new web3.BigNumber(1); // 1   1  const wallet = '0x281055afc982d96fab65b3a49cac8b878184cb16'; // - const cap = 200 * 1000000; //  const goal = 100 * 1000000; //  return deployer .then(() => { return deployer.deploy(token); }) .then(() => { return deployer.deploy( crowdsale, openingTime, closingTime, rate, wallet, cap, token.address, goal ); }) .then(() => { // Crowdsale    var tokenContract = web3.eth.contract(token.abi).at(token.address); web3.eth.defaultAccount = web3.eth.accounts[0]; tokenContract.transferOwnership(crowdsale.address); }); }; 

Este é o mesmo arquivo que será usado pela trufa para implantar contratos. Então, o que estamos fazendo aqui? Primeiro, solicitamos o MyToken e o MyToken compilados. Depois, definimos as constantes com todos os argumentos da nossa OIC - definimos os horários de início e término; quantos tokens as pessoas receberão por 1 vey de kefir (0,000000000000000001 eth = 1 wei; definir decimals indica quantos pedidos wei são necessários para obter 1 de seus tokens recém-criados); carteira, de onde virá o kefir obtido com a venda; tampa dura e tampa macia. Observe que o openingTime sempre deve ser posterior ao horário do bloco atual na blockchain - caso contrário, seu contrato inteligente não será bloqueado devido à verificação da condição no TimedCrowdsale . Eu entrei nesse rake e transações com falha não podem ser debitadas. Mude essas constantes como desejar.

O próximo passo é precisamente a implantação de contratos inteligentes. Nada de interessante aqui: temos um objeto deployer que implementa artefatos de contrato inteligentes e passa argumentos para lá. Observe que o MyToken é MyToken primeiro e somente depois o MyCrowdsale - e o endereço do primeiro é passado no segundo como argumento.

Então, o mais interessante é sobre o que eles não escrevem na documentação ou nos livros. Quando você cria um MyToken partir de uma carteira, essa carteira se torna o proprietário do MyToken na superclasse Ownable - o mesmo acontece com o MyCrowdsale . Se você se aprofundar no MintableToken , poderá ver que apenas o Owner pode cunhar moedas! E quem é o proprietário do MyToken ? É isso mesmo: o endereço que o aborreceu. E quem enviará pedidos de cunhagem de moedas? Correto: contrato inteligente MyCrowdsale . Deixe-me lembrá-lo de que o endereço que criou o MyToken e o MyCrowdsale são dois endereços diferentes.

Portanto, estamos adicionando a terceira etapa de implantação não-ortodoxa, em que o endereço que desafiou os contratos ( web3.eth.accounts[0] ) chama a função transferOwnership no contrato MyToken , MyToken que o MyCrowdsale dono do MyToken e possa cunhar moedas. E o MyCrowdsale ainda está sob propriedade de web3.eth.accounts[0] - então tudo está incluído.

Observação sobre web3.eth.accounts[0] : ao implantar um contrato inteligente, verifique se geth ou testrpc possui a carteira correta em web3.eth.accounts[0] - não perca a chave privada, embora isso não o prejudique, mas de repente o proprietário precisará fazer algo mais tarde, mas a chave não está mais lá?
No testrpc , como regra, as contas são criadas imediatamente na inicialização e são desbloqueadas imediatamente; no entanto, em um blockchain de teste e de ar real, vale a pena criar uma conta por meio do personal.newAccount() - reabasteça esse endereço via Faucet no blockchain de teste ou kefir real no blockchain real. Não perca sua senha e chaves privadas.
Além disso, você pode adicionar uma carteira existente às suas contas chamando web3.personal.importRawKey('pvt_key', 'password') , mas para isso é necessário chamar geth com o parâmetro adicional --rpcapi="db,eth,net,web3,personal,web3" . Eu acho que você vai descobrir.

Teste e implantação


Sim, os contratos estão prontos, as migrações são escritas, resta apenas implantar e verificar. Ambos, geth (test e real) e testrpc gerenciados da mesma maneira no truffle console - portanto, descreverei o método de verificação do testrpc e testrpc como habilitar o geth after. E assim, lançamos o blockchain de kefir local de teste:

 testrpc 

Hum ... isso é tudo. Você simula o blockchain de kefir localmente.

E para implantar no blockchain ether de teste, em vez deste comando, você obterá geth --testnet --rpc . E para implantar no verdadeiro blockchain do éter, você simplesmente geth --rpc . O sinalizador --rpc necessário para que a trufa possa se conectar. As etapas de implantação e teste a seguir são mais ou menos as mesmas para todos os três tipos de blockchain. A única coisa é que depois de executar o teste ou o blockchain real via geth , ele começará a sincronizar os blocos - e isso pode levar de quatro a cinco horas em uma boa conexão com a Internet. Uma observação sobre isso estava no começo do artigo. Antes de implantar contratos inteligentes, recomendo aguardar a sincronização completa. Além disso, o blockchain pesa na região de 60 a 100 gigabytes, portanto, prepare o espaço em disco para isso.
Além disso, verifique também se web3.eth.accounts[0] desbloqueado. Geralmente, você pode registrar o testrpc no console, que é aberto imediatamente, ou em uma janela Terminal separada no console, que é aberta via geth console : eth.unlockAccount(eth.accounts[0], ", ", 24*3600) - isso desbloqueará sua conta, o que deve criar um contrato inteligente

Agora abra uma nova janela do Terminal (não fechamos o testrpc - deve funcionar) e escreva-o na pasta do projeto:

 truffle migrate --reset 

Esse comando mágico compila um contrato inteligente (ou seja, você não precisa escrever uma truffle compile todas as vezes) e o implementa no micro servidor blockchain encontrado localmente aberto. Vale ressaltar que, se testrpc fizer isso instantaneamente, o teste e as cadeias reais incluirão a transação nos próximos blocos por muito mais tempo. Depois disso, você deve cuspir algo assim no console:

 Using network 'development'. Running migration: 1_initial_migration.js Running step... Replacing MyToken... ... 0x86a7090b0a279f8befc95b38fa8bee6918df30928dda0a3c48416454e2082b65 MyToken: 0x2dc35f255e56f06bd2935f5a49a0033548d85477 Replacing MyCrowdsale... ... 0xf0aab5d550f363478ac426dc2aff570302a576282c6c2c4e91205a7a3dea5d72 MyCrowdsale: 0xaac611907f12d5ebe89648d6459c1c81eca78151 ... 0x459303aa0b79be2dc2c8041dd48493f2d0e109fac19588f50c0ac664f34c7e30 Saving artifacts... 

Acho que você já percebeu que o console forneceu os endereços dos contratos inteligentes MyToken e MyCrowdsale . Isso é tudo! O contrato inteligente está incorporado na blockchain cujo microsservidor você abriu. Resta apenas verificar se os tokens são realmente distribuídos aos usuários que enviam kefir ao contrato inteligente MyCrowdsale . Escrevemos o seguinte no Terminal para entrar no console de trufas:

 truffle console 

Escrevemos o seguinte na trufa agora (sem comentários):

 //   - t="0x2dc35f255e56f06bd2935f5a49a0033548d85477" //     MyToken ="0xaac611907f12d5ebe89648d6459c1c81eca78151" //     MyCrowdsale //   - token=MyToken.at(t) crowdsale=MyCrowdsale.at(c) //       account=web3.eth.accounts[0] // ,      token.balanceOf(account) //   0 //    - web3.eth.sendTransaction({from: account, to:c, value: web3.toWei(0.1, 'ether'), gas: 900000}) 

No caso de, testrpcvocê pode verificar imediatamente o saldo de nossa carteira novamente, mas no caso de teste e blockchain real, é necessário aguardar até que nossa transação seja incluída no bloco - geralmente quando isso acontece, a trufa fornece o número da transação. Você já esperou? Verifique novamente nosso saldo em MyToken:

 // ,      token.balanceOf(account) //     

Isso é tudo!Primeiro a massa sobre o seu contrato testrpc, então geth --testnet, em seguida, deployte on geth. Então você lançou seu próprio ICO! E você não precisou gastar dezenas de kilobaks para auditoria e lançamento. Estragar tudo o que os caras do OpenZeppelin nos forneceram é realmente muito difícil. E quando você o usa truffle- é assim que o desenvolvimento solidário geralmente se transforma em um conto de fadas. Bem, exceto nos casos em que as transações são revertidas durante a execução de um contrato inteligente - estréia no inferno. Mas a depuração de contratos inteligentes é realmente digna de um artigo separado.

Conclusão


Muito obrigado pela leitura até o final deste artigo! Se eu consegui economizar tempo ou dinheiro, ou se você aprendeu algo novo com este artigo, ficarei muito feliz com isso. Também ficaria muito grato se você compartilhar este artigo com seus amigos ou conhecidos que desejam realizar uma ICO - economize US $ 75.000 para sub-programadores que sugam dinheiro do mercado de criptografia como parasitas, copiando e colando as mesmas 25 linhas de código .

Boa sorte no desenvolvimento de contratos inteligentes! Ainda tem dúvidas? Peço-lhe nos comentários. Ficarei feliz em responder a tudo e tentar ajudar com problemas.

Bônus


Mas e se você quiser alterar a lógica pela qual o preço de compra dos tokens é considerado? Claro, você pode alterá-lo corretamente rateou usar uma das classes de contratos do OpenZeppelin, mas e se você quiser algo ainda mais pervertido? Em um contrato inteligente, você pode substituir a função da getTokenAmountseguinte maneira:

 function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) { if (block.timestamp < 1533081600) { // August 1st, 2018 rate = rate * 4; } else if (block.timestamp < 1546300800) { // January 1st, 2019 rate = rate * 2; } return _weiAmount.mul(rate); } 

Em geral, isso pode tornar o preço do token dependente do momento da compra - quanto mais longe na floresta, mais caros os tokens. Não tenha medo de experimentar e reescrever alguns dos recursos de contratos inteligentes - é divertido!

Source: https://habr.com/ru/post/pt414493/


All Articles