diff --git a/pt/1/00-overview.md b/pt/1/00-overview.md index ae786d31a3..6c4a465085 100644 --- a/pt/1/00-overview.md +++ b/pt/1/00-overview.md @@ -2,6 +2,8 @@ title: Fazendo a Fábrica de Zumbi header: Bem vindo, humano! roadmap: roadmap.jpg +path: solidity +publishedOn: Cryptozombies --- Então, você acha que tem o que é preciso para se tornar um **CryptoZombie**, hein? diff --git a/pt/1/arrays.md b/pt/1/arrays.md index fee9e12c90..45729d4226 100644 --- a/pt/1/arrays.md +++ b/pt/1/arrays.md @@ -1,11 +1,12 @@ --- title: Listas actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -21,7 +22,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -45,10 +46,10 @@ Quando você quer uma lista de algo, você pode usar um **_array_** (lista). Exi // Array com tamanho fixo de 2 elementos: uint[2] fixedArray; -// Outro array fixo, pode conter 5 strings: +// outro array fixo, pode conter 5 strings: string[5] stringArray; -// Um array dinâmico - não tem tamanho fixo, e pode continuar aumentando: +// um array dinâmico - não tem tamanho fixo, e pode continuar aumentando: uint[] dynamicArray; ``` diff --git a/pt/1/arraysstructs2.md b/pt/1/arraysstructs2.md index bd486e94e3..334c5867f2 100644 --- a/pt/1/arraysstructs2.md +++ b/pt/1/arraysstructs2.md @@ -1,11 +1,12 @@ --- title: Trabalhando com Estruturas e Listas actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -19,13 +20,13 @@ material: Zombie[] public zombies; - function createZombie(string _name, uint _dna) { + function createZombie(string memory _name, uint _dna) public { // comece aqui } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -40,7 +41,7 @@ material: Zombie[] public zombies; - function createZombie(string _name, uint _dna) { + function createZombie(string memory _name, uint _dna) public { zombies.push(Zombie(_name, _dna)); } @@ -83,7 +84,7 @@ uint[] numbers; numbers.push(5); numbers.push(10); numbers.push(15); -// number agora é [5, 10, 15] +// O array `numbers` agora é igual a [5, 10, 15] ``` # Vamos testar diff --git a/pt/1/contracts.md b/pt/1/contracts.md index 213ed8e620..73c2ae05af 100644 --- a/pt/1/contracts.md +++ b/pt/1/contracts.md @@ -1,6 +1,7 @@ --- title: Contratos actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol @@ -9,7 +10,7 @@ material: // 2. Crie seu contract aqui answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -19,9 +20,9 @@ material: Começando pelo básico do básico: -O código em Solidity é encapsulado em **contratos**. Um `contract` (contrato) é um bloco de construção fundamental para aplicações em Ethereum — todas as variáveis e funções pertencem a um `contract`, e este será o ponto inicial de todos os seus projetos. +O código em Solidity é encapsulado em **contratos**. Um `contract` (contrato) é um bloco de construção fundamental para aplicações em Ethereum — todas as variáveis e funções pertencem a um contract, e este será o ponto inicial de todos os seus projetos. -Um `contract` vazio com o nome `HelloWorld` seria assim: +Um contract vazio com o nome `HelloWorld` seria assim: ``` contract HelloWorld { @@ -33,12 +34,12 @@ contract HelloWorld { Todo código fonte em Solidity deve começar com um "version pragma" - uma declaração da versão do compilador Solidity que deve ser usado. Isto é para evitar problemas com futuras versões do compilador, potencialmente apresentando mudanças que possam quebrar o seu código. -Irá ficar assim: `pragma solidity ^0.4.19;` (para a última versão do Solidity no momento que essa lição foi escrita, 0.4.19). +Irá ficar assim: `pragma solidity >=0.5.0 <0.6.0;` (para a última versão do Solidity no momento que essa lição foi escrita, 0.4.19). Juntando tudo, a versão mais simples para começar um `contract` - aqui vai a primeira coisa que você vai escrever toda vez que começar um novo projeto. ``` -pragma solidity ^0.4.19; +pragma solidity >=0.5.0 <0.6.0; contract HelloWorld { @@ -49,8 +50,8 @@ contract HelloWorld { Para começar o nosso exército Zumbi, vamos criar um contrato base chamado `ZombieFactory`. -1. Na caixa a direita, crie o nosso `contract` usando a versão do Solidity `0.4.19`. +1. Na caixa a direita, crie o nosso contract usando a versão do Solidity `>=0.5.0 <0.6.0`. -2. Crie um `contract` vazio chamado `ZombieFactory`. +2. Crie um contract vazio chamado `ZombieFactory`. Quando você terminar, clique em "Verificar Resposta" abaixo. Se você não souber como progredir, você pode clicar em "Dicas". diff --git a/pt/1/datatypes.md b/pt/1/datatypes.md index e8bd49906a..ed7ce7da8a 100644 --- a/pt/1/datatypes.md +++ b/pt/1/datatypes.md @@ -1,11 +1,12 @@ --- title: Variáveis de Estado & Inteiros actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -13,7 +14,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { diff --git a/pt/1/events.md b/pt/1/events.md index eb4f09d42e..8e4042f3b3 100644 --- a/pt/1/events.md +++ b/pt/1/events.md @@ -1,11 +1,12 @@ --- title: Eventos actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -21,24 +22,24 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); // dispare o evento aqui - } + } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -55,17 +56,17 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; - NewZombie(id, _name, _dna); - } + emit NewZombie(id, _name, _dna); + } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } @@ -75,18 +76,18 @@ material: Nosso contrato esta quase terminado! Agora vamos adicionar um **_evento_**. -**_Eventos_** são as maneiras dos seus contratos comunicarem que algo aconteceu na blockchain para o seu aplicativo em um frontend, que pode `ouvir` por certos tipos de eventos e tomar ações quando algo acontecer. +**_Eventos_** são as maneiras dos seus contratos comunicarem que algo aconteceu na blockchain para o seu aplicativo em um frontend, que pode 'ouvir' por certos tipos de eventos e tomar ações quando algo acontecer. Exemplo: ``` -// Declarando o evento +// declarando o evento event IntegersAdded(uint x, uint y, uint result); -function add(uint _x, uint _y) public { +function add(uint _x, uint _y) public returns (uint) { uint result = _x + _y; - // Dispare um evento e deixe o aplicativo saber que a função foi chamada: - IntegersAdded(_x, _y, result); + // dispare um evento e deixe o aplicativo saber que a função foi chamada: + emit IntegersAdded(_x, _y, result); return result; } ``` @@ -96,7 +97,7 @@ O seu aplicativo frontend poderá então ouvir o evento. Uma implementação em ``` YourContract.IntegersAdded(function(error, result) { // Faça algo com o resultado -} +}) ``` # Vamos testar diff --git a/pt/1/functions.md b/pt/1/functions.md index d88428c4fc..5b663165dc 100644 --- a/pt/1/functions.md +++ b/pt/1/functions.md @@ -1,11 +1,12 @@ --- title: Declarações de Funções actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -23,7 +24,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -38,7 +39,7 @@ material: Zombie[] public zombies; - function createZombie(string _name, uint _dna) { + function createZombie(string memory _name, uint _dna) public { } @@ -48,12 +49,19 @@ material: Uma declaração de função em Solidity parece o seguinte: ``` -function eatHamburgers(string _name, uint _amount) { +function eatHamburgers(string memory _name, uint _amount) public { } ``` -Esta é uma declaração de uma função chamada `eatHamburgers` que recebe dois parâmetros: uma `string` e um `uint`. Por enquanto o corpo da função esta vazio. +Esta é uma função chamada `eatHamburgers` que recebe 2 parâmetros: uma `string` e um `uint`. Por enquanto, o corpo da função está vazio. Note que estamos especificando a visibilidade da função como `public`. Também estamos fornecendo instruções sobre onde a variável `_name` deve ser armazenada — na `memory`. Isso é obrigatório para todos os tipos de referência, como arrays, structs, mappings e strings. + +O que é um tipo de referência, você pergunta? + +Bem, existem duas maneiras de passar um argumento para uma função Solidity: + + * Por valor, o que significa que o compilador Solidity cria uma nova cópia do valor do parâmetro e a passa para sua função. Isso permite que sua função modifique o valor sem se preocupar em alterar o valor do parâmetro original. + * Por referência, o que significa que sua função é chamada com uma referência à variável original. Assim, se sua função alterar o valor da variável que recebe, o valor da variável original também será alterado. > Nota: É uma convenção (mas não é requerido) iniciar os nomes das variáveis nos parâmetros das funções com sublinhado para diferenciá-los de variáveis globais. Nós iremos usar isso como convenção em todo o nosso tutorial. @@ -67,6 +75,6 @@ eatHamburgers("vitalik", 100); Em nossa aplicação, nós vamos precisar criar alguns zumbis. Vamos criar a função para isso: -1. Crie uma função chamada `createZombie`. Esta deve receber dois argumentos: **\_name** (uma `string`), e **\_dna** (uma `uint`). +1. Crie uma função `public` chamada `createZombie`. Ela deve receber dois parâmetros: **\_name** (uma `string`) e **\_dna** (um `uint`). Não se esqueça de passar o primeiro argumento por valor usando a palavra-chave `memory`. Deixe o corpo da função vazia por enquanto - nós vamos preenchê-lo mais tarde. diff --git a/pt/1/functions2.md b/pt/1/functions2.md index 78da13f503..766a05fccb 100644 --- a/pt/1/functions2.md +++ b/pt/1/functions2.md @@ -1,11 +1,12 @@ --- title: Funções Privadas / Públicas actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -19,13 +20,13 @@ material: Zombie[] public zombies; - function createZombie(string _name, uint _dna) { + function createZombie(string memory _name, uint _dna) public { zombies.push(Zombie(_name, _dna)); } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -40,7 +41,7 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); } diff --git a/pt/1/functions3.md b/pt/1/functions3.md index fe9f55e37c..5917aca596 100644 --- a/pt/1/functions3.md +++ b/pt/1/functions3.md @@ -1,11 +1,12 @@ --- title: Mais Sobre Funções actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -19,7 +20,7 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); } @@ -27,7 +28,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -42,11 +43,11 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } - function _generateRandomDna(string _str) private view returns (uint) { + function _generateRandomDna(string memory _str) private view returns (uint) { } @@ -62,7 +63,7 @@ Para retornar o valor de uma função, a declaração deve ser assim: ``` string greeting = "Olá cachorro!"; -function sayHello() public returns (string) { +function sayHello() public returns (string memory) { return greeting; } ``` @@ -73,13 +74,12 @@ Em Solidity, a declaração da função contém o tipo do valor de retorno (nest Na verdade a função acima não altera estado algum em Solidity - em outras palavras não altera qualquer valor ou escreve qualquer coisa. -Neste caso nós podemos declará-la como uma função com palavra reservada `view` (observa), que significa: somente uma observação do dado, mas nenhuma alteração de fato. +Neste caso nós podemos declará-la como uma função com palavra reservada **_view_** (observa), que significa: somente uma observação do dado, mas nenhuma alteração de fato. ``` -function sayHello() public view returns (string) { +function sayHello() public view returns (string memory) { ``` - -Em Solidity também existem funções **puras** usando a palavra reservada `pure`, que significa que nenhum dado será acessado na aplicação. Pense na seguinte situação: +Solidity também contém funções **_pure_**, o que significa que você nem está acessando nenhum dado no aplicativo. Considere o seguinte: ``` function _multiply(uint a, uint b) private pure returns (uint) { @@ -87,7 +87,7 @@ function _multiply(uint a, uint b) private pure returns (uint) { } ``` -Esta função nem mesmo lê um estado da aplicação - os seus valores retornados dependem somente dos parâmetros da função. Então neste caso nós podemos declarar a função como **_pura_** usando a palavra reservada `pure`. +Esta função nem sequer lê o estado do aplicativo — seu valor de retorno depende apenas dos parâmetros da função. Então, neste caso, declararíamos a função como **_pure_**. > Nota: Pode ser um tanto quanto complicado lembrar quando marcar a função como pura/observação (pure/view). Para a nossa sorte o compilador de Solidity faz um bom trabalho em avisar-nos quando devemos usar algum desses modificadores. @@ -95,7 +95,7 @@ Esta função nem mesmo lê um estado da aplicação - os seus valores retornado Nós vamos precisar de uma função de ajuda para gerar números de DNA aleatórios de uma string. -1. Crie uma função `private` chamada `_generateRandomDna`. Que receberá um parâmetro chamado `_str` (uma `string`), e retorna um `uint`. +1. Crie uma função `private` chamada `_generateRandomDna`. Que receberá um parâmetro chamado `_str` (uma `string`) e retornará um `uint`. Não esqueça de definir o local de dados do parâmetro `_str` para `memory`. 2. Esta função irá observar algumas das nossas variáveis no contrato, mas não irá modificá-las, então marque-a como `view`. diff --git a/pt/1/keccak256.md b/pt/1/keccak256.md index 7456b81d86..dc01f0aa2c 100644 --- a/pt/1/keccak256.md +++ b/pt/1/keccak256.md @@ -1,11 +1,12 @@ --- title: Keccak256 e Conversão de Tipos actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -19,17 +20,17 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } - function _generateRandomDna(string _str) private view returns (uint) { + function _generateRandomDna(string memory _str) private view returns (uint) { // comece aqui } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -44,12 +45,12 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } @@ -58,18 +59,19 @@ material: Nós queremos que a nossa função `_generateRandomDna` retorne um (semi) aleatório `uint`. Como podemos fazer isso ? -Ethereum tem uma função de hash `keccak256` interna, que é uma versão do SHA3. Uma função hash basicamente transforma uma string de entrada em um número hexadecimal aleatório de 256-bits. Qualquer pequena mudança na `string` irá causar uma total mudança em sua hash. +Ethereum tem uma função de hash `keccak256` interna, que é uma versão do SHA3. Uma função hash basicamente mapeia uma entrada em um número hexadecimal aleatório de 256 bits. Uma pequena mudança na entrada causará uma grande mudança no hash. É muito útil em diversos casos no Ethereum, mas por enquanto vamos usar somente para a geração de um número pseudo-aleatório. +Também importante, `keccak256` espera um único parâmetro do tipo `bytes`. Isso significa que temos que "empacotar" quaisquer parâmetros antes de chamar `keccak256`: + Exemplo: ``` //6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5 -keccak256("aaaab"); - +keccak256(abi.encodePacked("aaaab")); //b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9 -keccak256("aaaac"); +keccak256(abi.encodePacked("aaaac")); ``` Como você pode ver, os valores retornados são totalmente diferentes mesmo com a mudança de somente um caractere de entrada. @@ -83,21 +85,18 @@ Algumas vezes você precisa converter tipos diferentes. Pegue por exemplo o segu ``` uint8 a = 5; uint b = 6; - // lança um erro, porque a * b retorna um uint, não um uint8: uint8 c = a * b; - // nós temos de converter b em uint8 para isso funcionar: -uint8 c = a * uint8(b); +uint8 c = a * uint8(b); ``` Logo acima, `a * b` retorna um `uint`, mas nós estamos tentando guardar o seu valor em um `uint8`, que potencialmente pode causar problemas. Ao converter-lo como um `uint8`, a conversão irá funcionar e o compilador não irá reclamar. # Vamos testar -Vamos preencher o corpo da nossa função `_generateRandomDna`! -O que deve ser feito é: +Vamos preencher o corpo da nossa função `_generateRandomDna`! O que deve ser feito é: -1. Na primeira linha de código, pegue o hash de `_str` utilizando a função `keccak256` gerando um hexadecimal pseudo-aleatório, converta-o em um `uint`, e finalmente guarde o resultado em um `uint` chamado `rand`. +1. Na primeira linha de código deve pegar o hash `keccak256` de `abi.encodePacked(_str)` gerando um hexadecimal pseudo-aleatório, converta-o em um `uint`, e finalmente guarde o resultado em um `uint` chamado `rand`. 2. Nós queremos somente 16 dígitos de tamanho em nosso DNA (lembra do `dnaModulus`?). Então a segunda linha de código deve retornar `return` o módulo do valor acima (`%`) `dnaModulus`. diff --git a/pt/1/lessoncomplete.md b/pt/1/lessoncomplete.md index 6c2b3e8f33..f0d5b956bb 100644 --- a/pt/1/lessoncomplete.md +++ b/pt/1/lessoncomplete.md @@ -1,21 +1,22 @@ --- -title: Lição 1 Completa! -actions: ['verificarResposta', 'dicas'] +title: Lesson 1 Complete! +actions: ['checkAnswer', 'hints'] +requireLogin: true material: lessonComplete: answer: 1 --- -Parabéns! Você completou a lição 1, e você criou o primeiro zumbi do seu exército. +Congratulations! You have completed lesson 1, and you have created the first zombie in your army. -# Próximos Passos +# Next Steps -Isso é só o começo. Nós iremos lançar uma nova lição do CryptoZombies toda semana, para construir muito mais e continuar crescendo o nosso exército de zumbis. +This is just the beginning. We will be releasing a new CryptoZombies lesson each week, to build out the game further and further and keep growing your zombie army. -### 1. Cadastre-se para salvar o seu progresso +### 1. Sign in to save your progress -**_Cadastre-se_** para salvar o seu progresso clicando no link "Save Progress" no topo da página. Nós vamos avisar você logo que uma nova lição for adicionada. +**_Sign in_** to save your progress by clicking the "Save Progress" link at the top of the page. We'll let you know as soon as we add a new lesson. -### 2. Compartilhe o seu zumbi com os amigos +### 2. Share your zombie with your friends -**_Compartilhe_** seu zumbi no Twitter, blah blah, etc. (Need to insert images / links) +**_Share_** your zombie on Twitter, blah blah, etc. (Need to insert images / links) diff --git a/pt/1/lessonoverview.md b/pt/1/lessonoverview.md index a9b151c82d..c6d895f017 100644 --- a/pt/1/lessonoverview.md +++ b/pt/1/lessonoverview.md @@ -2,6 +2,7 @@ title: Visão Geral da Lição actions: ['verificarResposta', 'dicas'] skipCheckAnswer: true +requireLogin: true material: saveZombie: false zombieResult: diff --git a/pt/1/math.md b/pt/1/math.md index 40132a1296..715efdbe44 100644 --- a/pt/1/math.md +++ b/pt/1/math.md @@ -1,11 +1,12 @@ --- title: Operações Matemáticas actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -14,7 +15,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { diff --git a/pt/1/puttingittogether.md b/pt/1/puttingittogether.md index 887b40f260..1043a0c830 100644 --- a/pt/1/puttingittogether.md +++ b/pt/1/puttingittogether.md @@ -1,11 +1,12 @@ --- title: Juntando Tudo actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -19,12 +20,12 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } @@ -32,7 +33,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -47,16 +48,16 @@ material: Zombie[] public zombies; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } @@ -70,7 +71,7 @@ Nós vamos criar uma função pública que tem uma entrada, o nome do zumbi, e u # Vamos testar -1. Crie uma função `public` chamada `createRandomZombie`. Ela irá ter um parâmetro chamado `_name` (uma `string`). _(Nota: Declare esta função como `public` assim como você declarou as funções anteriores como `private`)_ +1. Crie uma função `public` chamada `createRandomZombie`. Ela irá ter um parâmetro chamado `_name` (uma `string` com o local dos dados definido como `memory`). _(Nota: Declare esta função como `public` assim como você declarou as funções anteriores como `private`)_ 2. A primeira linha desta função deve executar a função `_generateRandomDna` usando o parâmetro `_name`, e guardá-lo em um `uint` chamado `randDna`. diff --git a/pt/1/structs.md b/pt/1/structs.md index 8f19ab451a..ed6f6d776d 100644 --- a/pt/1/structs.md +++ b/pt/1/structs.md @@ -1,11 +1,12 @@ --- title: Estruturas actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -16,7 +17,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { diff --git a/pt/1/web3js.md b/pt/1/web3js.md index 2e6aa88a46..9e774cb22b 100644 --- a/pt/1/web3js.md +++ b/pt/1/web3js.md @@ -1,6 +1,7 @@ --- title: Web3.js actions: ['verificarResposta', 'dicas'] +requireLogin: true material: saveZombie: true zombieResult: diff --git a/pt/2/00-overview.md b/pt/2/00-overview.md index 62544f4058..9afbf9a813 100644 --- a/pt/2/00-overview.md +++ b/pt/2/00-overview.md @@ -2,6 +2,8 @@ title: Zumbis atacam suas vítimas header: Então, você chegou a Lição 2! roadmap: roadmap2.jpg +path: solidity +publishedOn: Cryptozombies --- Impressionante, humano! Você é melhor programador(a) do que pensei. diff --git a/pt/2/1-overview.md b/pt/2/1-overview.md index eab85bdc18..1d092a5a5f 100644 --- a/pt/2/1-overview.md +++ b/pt/2/1-overview.md @@ -1,6 +1,7 @@ --- title: Visão Geral da Lição 2 actions: ['verificarResposta', 'dicas'] +requireLogin: true material: saveZombie: false zombieBattle: diff --git a/pt/2/10-interactingcontracts.md b/pt/2/10-interactingcontracts.md index ad871a1655..720634784f 100644 --- a/pt/2/10-interactingcontracts.md +++ b/pt/2/10-interactingcontracts.md @@ -1,12 +1,13 @@ --- title: O Que Zumbis Comem? actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -24,7 +25,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -43,19 +44,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -63,7 +64,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; diff --git a/pt/2/11-interactingcontracts2.md b/pt/2/11-interactingcontracts2.md index 7028d4dca7..6bf670bde5 100644 --- a/pt/2/11-interactingcontracts2.md +++ b/pt/2/11-interactingcontracts2.md @@ -1,12 +1,13 @@ --- title: Usando a Interface actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -40,7 +41,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -59,19 +60,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -79,7 +80,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -128,7 +129,6 @@ Nós podemos usá-lo em um contrato conforme segue: contract MyContract { address NumberInterfaceAddress = 0xab38...; // ^ O endereço do contrato FavoriteNumber no Ethereum - NumberInterface numberContract = NumberInterface(NumberInterfaceAddress); // Agora `numberContract` esta apontando para outro contrato diff --git a/pt/2/12-multiplereturns.md b/pt/2/12-multiplereturns.md index c069c9268b..990bda0e3c 100644 --- a/pt/2/12-multiplereturns.md +++ b/pt/2/12-multiplereturns.md @@ -1,12 +1,13 @@ --- title: Manipulação de Múltiplos Retornos actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -42,7 +43,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -61,19 +62,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -81,7 +82,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -133,7 +134,6 @@ function processMultipleReturns() external { uint a; uint b; uint c; - // Esta é a forma como você faz múltiplas atribuições (a, b, c) = multipleReturns(); } diff --git a/pt/2/13-kittygenes.md b/pt/2/13-kittygenes.md index 33e482054e..f333328b1c 100644 --- a/pt/2/13-kittygenes.md +++ b/pt/2/13-kittygenes.md @@ -1,12 +1,13 @@ --- title: "Bônus: Genes de Gatinhos" actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -49,7 +50,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -68,19 +69,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -89,7 +90,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -113,12 +114,12 @@ material: address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; KittyInterface kittyContract = KittyInterface(ckAddress); - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -148,10 +149,10 @@ Digamos que o gato-zumbi tem `99` como seus últimos 2 dígitos de DNA (desde qu Declaração de condições em Solidity parecem com as de JavaScript: ``` -function eatBLT(string sandwich) public { +function eatBLT(string memory sandwich) public { // Lembre-se com strings, temos que comprar os seus hashes em keccak256 // para checar igualdade - if (keccak256(sandwich) == keccak256("BLT")) { + if (keccak256(abi.encodePacked(sandwich)) == keccak256(abi.encodePacked("BLT"))) { eat(); } } @@ -161,12 +162,12 @@ function eatBLT(string sandwich) public { Vamos implementar o genes dos gatos em nosso código zumbi. -1. Primeiro, vamos mudar a definição para a função `feedAndMultiply` então ela terá um terceiro argumento: uma `string` chamada `_species` +1. Primeiro, vamos mudar a definição para a função `feedAndMultiply` então ela terá um terceiro argumento: uma `string` chamada `_species` que vamos armazenar na `memory` -2. Próximo, após calcularmos o DNA do novo zumbi, vamos adicionar uma condição `if` comparando o hash `keccak256` da `_species` e a string `"kitty"`. +2. Próximo, após calcularmos o DNA do novo zumbi, vamos adicionar uma condição `if` comparando o hash `keccak256` da `_species` e a string `"kitty"`. Não podemos passar strings diretamente para `keccak256`. Em vez disso, vamos passar `abi.encodePacked(_species)` como um argumento no lado esquerdo e `abi.encodePacked("kitty")` como um argumento no lado direito. 3. Dentro da condição `if`, nós queremos substituir os dois últimos dígitos do DNA com `99`. Uma maneira de fazer isso é usando a lógica: `newDna = newDna - newDna % 100 + 99;`. > Explicação: Suponha que `newDna` é `334455`. Então `newDna % 100` é `55`, então `newDna - newDna % 100` é `334400`. Finalmente adicione `99` para ter `334499`. -4. Por último, nós precisamos mudar dentro da chamada da função `feedOnKitty`. Quando ela chamar `feedAndMultiply`, adicione o parâmetro `"Kitty"` no final. +4. Por último, nós precisamos mudar dentro da chamada da função `feedOnKitty`. Quando ela chamar `feedAndMultiply`, adicione o parâmetro `"kitty"` no final. diff --git a/pt/2/14-wrappingitup.md b/pt/2/14-wrappingitup.md index ee57434469..de486037cb 100644 --- a/pt/2/14-wrappingitup.md +++ b/pt/2/14-wrappingitup.md @@ -1,6 +1,7 @@ --- title: Finalizando actions: ['verificarResposta', 'dicas'] +requireLogin: true material: saveZombie: true zombieBattle: diff --git a/pt/2/15-lessoncomplete.md b/pt/2/15-lessoncomplete.md index d88de9e4d9..b42b17abc3 100644 --- a/pt/2/15-lessoncomplete.md +++ b/pt/2/15-lessoncomplete.md @@ -6,3 +6,4 @@ material: answer: 1 --- + diff --git a/pt/2/2-mappings.md b/pt/2/2-mappings.md index 8bb05ed505..90e064048b 100644 --- a/pt/2/2-mappings.md +++ b/pt/2/2-mappings.md @@ -1,11 +1,12 @@ --- title: Mapeamentos e Endereços (Mappings / Addresses) actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -23,24 +24,24 @@ material: // declare o mapeamento aqui - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; - NewZombie(id, _name, _dna); - } + emit NewZombie(id, _name, _dna); + } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -60,17 +61,17 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; - NewZombie(id, _name, _dna); - } + emit NewZombie(id, _name, _dna); + } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } diff --git a/pt/2/3-msgsender.md b/pt/2/3-msgsender.md index 488842f07e..950c2e1d6f 100644 --- a/pt/2/3-msgsender.md +++ b/pt/2/3-msgsender.md @@ -1,11 +1,12 @@ --- title: Msg.sender actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -24,25 +25,25 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; // comece aqui - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -62,19 +63,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); } diff --git a/pt/2/4-require.md b/pt/2/4-require.md index 56f72024d5..fbb44870e4 100644 --- a/pt/2/4-require.md +++ b/pt/2/4-require.md @@ -1,11 +1,12 @@ --- title: Requerer (Require) actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -24,19 +25,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { // comece aqui uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -44,7 +45,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -64,19 +65,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -94,12 +95,11 @@ Como podemos fazer esta função ser chamada somente uma vez por jogador? Para isso nós vamos usar o `require` (requerer). `require` faz com que a função lance um erro e pare a execução se alguma condição não for verdadeira: ``` -function sayHiToVitalik(string _name) public returns (string) { +function sayHiToVitalik(string memory _name) public returns (string memory) { // Compara se _name é igual à "Vitalik". Lança um erro e termina se não for verdade. // (Lembrete: Solidity não tem uma forma nativa de comparar strings, então // temos que comparar os hashes keccak256 para verificar a igualdade) - require(keccak256(_name) == keccak256("Vitalik")); - + require(keccak256(abi.encodePacked(_name)) == keccak256(abi.encodePacked("Vitalik"))); // Se é verdade, prossiga com a função: return "Olá!"; } diff --git a/pt/2/5-inheritance.md b/pt/2/5-inheritance.md index 3055003336..23eb8ea766 100644 --- a/pt/2/5-inheritance.md +++ b/pt/2/5-inheritance.md @@ -1,11 +1,12 @@ --- title: Herança actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -24,19 +25,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -47,7 +48,7 @@ material: // Comece aqui answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -67,19 +68,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -99,13 +100,13 @@ Umas característica que torna o Solidity mais gerenciável é a **_herança_** ``` contract Doge { - function catchphrase() public returns (string) { + function catchphrase() public returns (string memory) { return "Um papai CryptoDoge"; } } contract BabyDoge is Doge { - function anotherCatchphrase() public returns (string) { + function anotherCatchphrase() public returns (string memory) { return "Um lindo BabyDoge"; } } diff --git a/pt/2/6-importfiles.md b/pt/2/6-importfiles.md index 48a106e412..62a5fccb46 100644 --- a/pt/2/6-importfiles.md +++ b/pt/2/6-importfiles.md @@ -1,12 +1,13 @@ --- title: Importar (Import) actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; // declare a importação aqui @@ -14,7 +15,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -33,19 +34,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -53,7 +54,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; diff --git a/pt/2/7-storage.md b/pt/2/7-storage.md index 5aa22f6201..5375b314d7 100644 --- a/pt/2/7-storage.md +++ b/pt/2/7-storage.md @@ -1,12 +1,13 @@ --- title: Armazenamento vs Memória (Storage vs Memory) actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -16,7 +17,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -35,19 +36,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -55,7 +56,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -75,7 +76,7 @@ Em Solidity, existem dois lugares onde você pode guardar as variáveis - na `st Na maior parte do tempo você não precisa usar essas palavras-reservadas porque a Solidity cuida disso pra você por padrão. Variáveis de estado (variáveis declaradas fora das funções) são por padrão `storage` e são escritas permanentemente na blockchain, enquanto variáveis declaradas dentro das funções são `memory` e irão desaparecer quando a função terminar. -Porém, haverão momentos em que você precisará usar tais palavras-reservadas, por exemplo quando trabalhar com **_struct_** e **_arrays_** dentro das funções: +Porém, haverão momentos em que você precisará usar tais palavras-reservadas, por exemplo quando trabalhar com **_structs_** e **_arrays_** dentro das funções: ``` contract SandwichFactory { diff --git a/pt/2/8-feedandmultiply2.md b/pt/2/8-feedandmultiply2.md index fa8edbd1a0..91d9f5a6a1 100644 --- a/pt/2/8-feedandmultiply2.md +++ b/pt/2/8-feedandmultiply2.md @@ -1,12 +1,13 @@ --- title: DNA Zumbi actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -20,7 +21,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -39,19 +40,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -59,7 +60,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; diff --git a/pt/2/9-internalfunctions.md b/pt/2/9-internalfunctions.md index e2aa432734..e62d2acfa9 100644 --- a/pt/2/9-internalfunctions.md +++ b/pt/2/9-internalfunctions.md @@ -1,12 +1,13 @@ --- title: Mais sobre Funções e Visibilidades actions: ['verificarResposta', 'dicas'] +requireLogin: true material: editor: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -26,19 +27,19 @@ material: mapping (address => uint) ownerZombieCount; // edite a função abaixo - function _createZombie(string _name, uint _dna) private { + function _createZombie(string memory _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -46,7 +47,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -62,7 +63,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -81,19 +82,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); _createZombie(_name, randDna); @@ -130,7 +131,7 @@ contract Sandwich { contract BLT is Sandwich { uint private baconSandwichesEaten = 0; - function eatWithBacon() public returns (string) { + function eatWithBacon() public returns (string memory) { baconSandwichesEaten++; // Podemos chamar aqui porque é uma função `internal` eat(); diff --git a/pt/3/00-overview.md b/pt/3/00-overview.md index 60e4a955d2..20ec35502b 100644 --- a/pt/3/00-overview.md +++ b/pt/3/00-overview.md @@ -2,6 +2,8 @@ title: Conceitos Avançados de Solidity header: "Lição 3: Conceitos Avançados de Solidity" roadmap: roadmap3.png +path: solidity +publishedOn: Cryptozombies --- Grr... Eu não consigo parar você, consigo? Suas habilidades em Solidity são formidáveis, humano... diff --git a/pt/3/01-externaldependencies.md b/pt/3/01-externaldependencies.md index 5df9a4fd18..1794608b30 100644 --- a/pt/3/01-externaldependencies.md +++ b/pt/3/01-externaldependencies.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -35,12 +35,12 @@ material: // 3. Adicione o método setKittyContractAddress aqui - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -54,7 +54,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; contract ZombieFactory { @@ -73,19 +73,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -94,7 +94,7 @@ material: } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -121,12 +121,12 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); diff --git a/pt/3/02-ownable.md b/pt/3/02-ownable.md index 0d258466ee..f5a0da1d00 100644 --- a/pt/3/02-ownable.md +++ b/pt/3/02-ownable.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; // 1. Importe aqui @@ -29,19 +29,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -50,7 +50,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -77,12 +77,12 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -96,47 +96,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -157,19 +193,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -200,40 +236,78 @@ Leia com atenção o contrato abaixo. Você verá algumas coisas que nós já ap * que simplificam a implementação de "permissões de usuário". */ contract Ownable { - address public owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + address private _owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** * @dev O construtor Ownable define o `owner` (dono) original do contrato como o sender * da conta */ - function Ownable() public { - owner = msg.sender; + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); + } + + /** + * @return o endereço do dono. + */ + function owner() public view returns(address) { + return _owner; } /** - * @dev Lança um erro se chamado por outra conta que não seja o dono. + * @dev Lança se chamado por qualquer conta que não seja o dono. */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } /** - * @dev Permite que o atual dono transfira o controle do contrato para um novo dono. - * @param newOwner O endereço de transferência para o novo dono. + * @return true se `msg.sender` é o dono do contrato. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Permite que o dono atual renuncie ao controle do contrato. + * @notice Renunciar à propriedade deixará o contrato sem dono. + * Não será possível chamar as funções com o modificador `onlyOwner` + * mais. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Permite que o dono atual transfira o controle do contrato para um novo dono. + * @param newOwner O endereço para transferir a propriedade. */ function transferOwnership(address newOwner) public onlyOwner { + _transferOwnership(newOwner); + } + + /** + * @dev Transfere o controle do contrato para um novo dono. + * @param newOwner O endereço para transferir a propriedade. + */ + function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; } } ``` Um pouco de novas coisas que não vimos antes: -- Construtores: `function Ownable()` é um **_construtor_**, que é uma função opcional e especial que tem o mesmo nome do contrato. Esta será executada somente uma vez, quando o contrato é criado a primeira vez. +- Construtores: `constructor()` é um **_constructor_**, que é uma função especial opcional. Ele será executado apenas uma vez, quando o contrato for criado pela primeira vez. - Funções Modificadoras: `modifier onlyOwner()`. Modificadores são um tipo de meia-função que são usadas para modificar outras funções, normalmente usadas para checar algo requerido antes da execução. Neste caso, `onlyOwner` pode ser usada para limitar o acesso então **only** (somente) o **owner** (dono) do contrato pode executar esta função. Nós iremos falar mais sobre funções modificadoras no próximo capítulo, e o que esse `_;` faz. - Palavra-chave `indexed`: não se preocupe com isso, nós ainda não precisamos. @@ -245,7 +319,7 @@ Então o contrato `Ownable` basicamente faz o seguinte: 3. Também permite a transferência de um contrato para o novo `owner` (dono) -O `onlyOwner` é um requisito muito comum na maior parte dos contratos de DApps em Solidity que já começam com um copia/cola do contrato `Ownable`, e o primeiro contrato já o herda. +`onlyOwner` é um requisito muito comum na maior parte dos contratos de DApps em Solidity que já começam com um copia/cola do contrato `Ownable`, e o primeiro contrato já o herda. Já que nós queremos limitar o `setKittyContractAddress` para `onlyOwner`, teremos que fazer o mesmo para o nosso contrato. diff --git a/pt/3/03-onlyowner.md b/pt/3/03-onlyowner.md index 35ce2c5c51..fc8fe98605 100644 --- a/pt/3/03-onlyowner.md +++ b/pt/3/03-onlyowner.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -35,12 +35,12 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -54,7 +54,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -75,19 +75,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -96,47 +96,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -163,12 +199,12 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -201,29 +237,84 @@ Uma função modificadora se parece com uma função, mas usa a palavra reservad Vamos olhar de perto e examinar o `onlyOwner`: ``` +pragma solidity >=0.5.0 <0.6.0; + /** - * @dev Lança um erro se for chamada por outra conta que não seja o dono. - */ -modifier onlyOwner() { - require(msg.sender == owner); - _; -} -``` + * @title Ownable + * @dev O contrato Ownable tem um endereço de proprietário e fornece controle básico de autorização + * funções, isso simplifica a implementação de "permissões de usuário". + */ +contract Ownable { + address private _owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); + + /** + * @dev O construtor Ownable define o proprietário original do contrato como o remetente + * conta. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); + } -Podemos usar este modificar conforme segue: + /** + * @return o endereço do proprietário. + */ + function owner() public view returns(address) { + return _owner; + } -``` -contract MyContract is Ownable { - event LaughManiacally(string laughter); + /** + * @dev Lança se chamado por qualquer conta que não seja o proprietário. + */ + modifier onlyOwner() { + require(isOwner()); + _; + } + + /** + * @return true se `msg.sender` for o proprietário do contrato. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Permite que o proprietário atual renuncie ao controle do contrato. + * @notice Renunciar à propriedade deixará o contrato sem proprietário. + * Não será possível chamar as funções com o modificador `onlyOwner` + * mais. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Permite que o proprietário atual transfira o controle do contrato para um novo proprietário. + * @param newOwner O endereço para transferir a propriedade. + */ + function transferOwnership(address newOwner) public onlyOwner { + _transferOwnership(newOwner); + } - // Veja o uso de `onlyOwner` abaixo: - function likeABoss() external onlyOwner { - LaughManiacally("Muahahahaha"); + /** + * @dev Transfere o controle do contrato para um novo proprietário. + * @param newOwner O endereço para transferir a propriedade. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; } } ``` -Perceba que `onlyOwner` modifica a função `likeABoss`. Quando você chama `likeABoss`, o código dentro de `onlyOwner` executa **primeiro**. Depois quando chega na declaração `_;` em `onlyOwner`, volta e executa o código dentro de `likeABoss`. +Observe o modificador `onlyOwner` na função `renounceOwnership`. Quando você chama `renounceOwnership`, o código dentro de `onlyOwner` executa **primeiro**. Então, quando ele atinge a declaração `_;` em `onlyOwner`, ele volta e executa o código dentro de `renounceOwnership`. Enquanto há outras maneiras de usar os modificares, um dos casos mais comuns são os de adicionar rapidamente verificações de `require` antes de uma função executar. diff --git a/pt/3/04-gas.md b/pt/3/04-gas.md index a7d864e70d..30773b74fc 100644 --- a/pt/3/04-gas.md +++ b/pt/3/04-gas.md @@ -1,13 +1,13 @@ --- title: Gas -actions: ['verificarResposta', 'dicas'] +actions: ['checkAnswer', 'hints'] requireLogin: true material: editor: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -21,7 +21,7 @@ material: struct Zombie { string name; uint dna; - // Adicione o novo dado aqui + // Add new data here } Zombie[] public zombies; @@ -29,19 +29,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -50,7 +50,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -77,12 +77,12 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -96,45 +96,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); + } /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -157,19 +195,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -197,7 +235,7 @@ Ethereum é como um grande, lento, mas extremamente seguro computador. Quando vo Os criadores do Ethereum queriam ter certeza que ninguém poderia entupir a rede com laços infinitos, ou estragar todos os recursos da rede com computações realmente intensivas. Então eles fizeram com que as transações não fossem grátis, e os usuários tem que pagar pelo tempo de computação como também pela guarda dos dados -> Nota: Isto não é necessariamente verdade em sidechains, como a que os autores do CryptoZombies estão construindo na Loom Network. E provavelmente nunca irá fazer sentido rodar um jogo como World of Warcraft diretamente na rede mainnet do Ethereum - o custo em gas seria proibitivamente caro. Mas este pode rodar em uma sidechain com um algorítimo de consenso diferente. Iremos falar mais sobre os tipos de DApps que você poderia implantar em sidechains vs a mainnet do Ethereum em futuras lições. +> Nota: Isto não é necessariamente verdade para outras blockchain, como a que os autores do CryptoZombies estão construindo na Loom Network. E provavelmente nunca irá fazer sentido rodar um jogo como World of Warcraft diretamente na rede mainnet do Ethereum - o custo em gas seria proibitivamente caro. Mas este pode rodar em uma sidechain com um algorítimo de consenso diferente. Iremos falar mais sobre os tipos de DApps que você poderia implantar em sidechains vs a mainnet do Ethereum em futuras lições. ## Empacotamento da estrutura para economizar gas @@ -227,7 +265,9 @@ NormalStruct normal = NormalStruct(10, 20, 30); MiniMe mini = MiniMe(10, 20, 30); ``` -Por essa razão, dentro de uma estrutura você irá querer usar o menor subtipo de integer que você puder. Você também quer juntar tipos de dados idênticos (exemplo: colando um perto do outro dentro da estrutura) então Solidity pode minimizar o espaço requerido para guardar a estrutura. Por exemplo, a estrutura com campos `uint c; uint32 a; uint32 b;` irá custar menos gas que a estrutura com os campos `uint32 a; uint c; uint32 b;` porque o os campos `uint32` estão agrupados. +Por essa razão, dentro de uma estrutura você irá querer usar o menor subtipo de integer que você puder. + +Você também quer juntar tipos de dados idênticos (exemplo: colando um perto do outro dentro da estrutura) então Solidity pode minimizar o espaço requerido para guardar a estrutura. Por exemplo, a estrutura com campos `uint c; uint32 a; uint32 b;` irá custar menos gas que a estrutura com os campos `uint32 a; uint c; uint32 b;` porque o os campos `uint32` estão agrupados. ## Vamos testar diff --git a/pt/3/05-timeunits.md b/pt/3/05-timeunits.md index 382f05ebf8..b2ccc63617 100644 --- a/pt/3/05-timeunits.md +++ b/pt/3/05-timeunits.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -31,20 +31,20 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { // 2. Atualize a seguinte linha: uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -53,7 +53,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -80,12 +80,12 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -99,45 +99,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); + } /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -161,19 +199,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -189,7 +227,6 @@ A propriedade `readyTime` requer um pouco mais de explicação. A ideia é adici Para manter o registro de quanto tempo um zumbi precisa esperar até o poder atacar novamente, podemos usar as unidades tempo em Solidity. -## Time units ## Unidades de tempo Solidity fornece algumas unidades nativas para lidar com o tempo. diff --git a/pt/3/06-zombiecooldowns.md b/pt/3/06-zombiecooldowns.md index d6ce2c6c24..2e2eae6668 100644 --- a/pt/3/06-zombiecooldowns.md +++ b/pt/3/06-zombiecooldowns.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -38,12 +38,12 @@ material: // 2. Defina a função `_isReady` aqui - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -57,7 +57,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -81,19 +81,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -102,47 +102,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -177,12 +213,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -217,7 +253,7 @@ A sintaxe deverá se parecer com isso: ``` function _doStuff(Zombie storage _zombie) internal { - // faça algo com o zumbi aqui + // faça algo com _zombie aqui } ``` diff --git a/pt/3/07-zombiecooldowns2.md b/pt/3/07-zombiecooldowns2.md index a20e8c6c4c..ab20223978 100644 --- a/pt/3/07-zombiecooldowns2.md +++ b/pt/3/07-zombiecooldowns2.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -43,17 +43,17 @@ material: } // 1. Torne esta função internal - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; // 2. Adicione a checagem para `_isReady` aqui _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); - // 3. chame o `_triggerCooldown` + // 3. chame o `_triggerCooldown` aqui } function feedOnKitty(uint _zombieId, uint _kittyId) public { @@ -64,7 +64,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -88,19 +88,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -109,47 +109,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -184,13 +220,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); diff --git a/pt/3/08-functionmodifiers.md b/pt/3/08-functionmodifiers.md index eff1d2ac8b..6de3c4f488 100644 --- a/pt/3/08-functionmodifiers.md +++ b/pt/3/08-functionmodifiers.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -17,7 +17,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -52,13 +52,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -73,7 +73,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -97,19 +97,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -118,47 +118,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -189,7 +225,7 @@ mapping (uint => uint) public age; // Modificador que requer que o usuário seja mais velho que certa idade: modifier olderThan(uint _age, uint _userId) { - require (age[_userId] >= _age); + require(age[_userId] >= _age); _; } diff --git a/pt/3/09-zombiemodifiers.md b/pt/3/09-zombiemodifiers.md index 7c5dbf7b3d..658f1143ed 100644 --- a/pt/3/09-zombiemodifiers.md +++ b/pt/3/09-zombiemodifiers.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -22,7 +22,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -49,15 +49,20 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function _triggerCooldown(Zombie storage _zombie) internal { + _zombie.readyTime = uint32(now + cooldownTime); + } + + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); + _triggerCooldown(myZombie); } function feedOnKitty(uint _zombieId, uint _kittyId) public { @@ -68,7 +73,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -92,19 +97,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -113,47 +118,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -164,7 +205,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -204,7 +245,9 @@ function driveCar(uint _userId) public olderThan(16, _userId) { ## Vamos testar -1. Crie uma função chamada `changeName`. Esta irá receber 2 argumentos: `_zombieId` (um `uint`), e `_newName` (uma `string`), e faça-o um `external`. Este deve ter um modificador `aboveLevel`, e deve passar um `2` para o parâmetro `_level` (Não esqueça de também passar o `zombieId`). +1. Crie uma função chamada `changeName`. Esta irá receberá 2 argumentos: `_zombieId` (um `uint`) e `_newName` (uma `string` com o local dos dados definido como `calldata` ), e a tornará `external`. Ela deve ter o modificador `aboveLevel` e deve passar um `2` para o parâmetro `_level`. (Não se esqueça de passar também o `_zombieId`). + +> Nota: `calldata` é de alguma forma semelhante a `memory`, mas está disponível apenas para funções `external`. 2. Nesta função, primeiro nós precisamos verificar se `msg.sender` é igual a `zombieToOwner[_zombieId]`. Use a declaração de `require`. diff --git a/pt/3/10-savinggasview.md b/pt/3/10-savinggasview.md index ca1275632e..8226c499c3 100644 --- a/pt/3/10-savinggasview.md +++ b/pt/3/10-savinggasview.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -18,7 +18,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -33,7 +33,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -60,15 +60,20 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function _triggerCooldown(Zombie storage _zombie) internal { + _zombie.readyTime = uint32(now + cooldownTime); + } + + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); + _triggerCooldown(myZombie); } function feedOnKitty(uint _zombieId, uint _kittyId) public { @@ -79,7 +84,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -103,19 +108,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -124,47 +129,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -175,7 +216,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -185,7 +226,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { } diff --git a/pt/3/11-savinggasstorage.md b/pt/3/11-savinggasstorage.md index d6e42b6256..79037166f4 100644 --- a/pt/3/11-savinggasstorage.md +++ b/pt/3/11-savinggasstorage.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -18,7 +18,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -28,14 +28,14 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { // Comece aqui } } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -62,15 +62,20 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function _triggerCooldown(Zombie storage _zombie) internal { + _zombie.readyTime = uint32(now + cooldownTime); + } + + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); + _triggerCooldown(myZombie); } function feedOnKitty(uint _zombieId, uint _kittyId) public { @@ -81,7 +86,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -105,19 +110,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -126,47 +131,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -177,7 +218,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -187,7 +228,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); return result; @@ -200,7 +241,7 @@ Uma das operações mais caras em Solidity é usar o `storage` (armazenamento) - Isto porque toda vez que você escreve uma mudança em um pedaço de dado, ela escreve permanentemente na blockchain. Para sempre! Milhares de nós em todo o mundo precisam guardar esse dados em seus discos rígidos, e esta quantidade de dado continua crescendo continuamente com o tempo conforme o blockchain cresce. Então há um custo para isso. -E para manter os custos baixos, você precisa evitar escritas de dados no *storage* armazenamento exceto quando absolutamente necessário. Algumas vezes envolve uma lógica de programação ineficiente - como reconstruir um array em `memory` (memória) toda vez que a função é chamada ao invés de simplesmente salvar o array em uma variável para buscas rápidas. +E para manter os custos baixos, você precisa evitar escritas de dados no storage armazenamento exceto quando absolutamente necessário. Algumas vezes envolve uma lógica de programação ineficiente - como reconstruir um array em `memory` (memória) toda vez que a função é chamada ao invés de simplesmente salvar o array em uma variável para buscas rápidas. Na maioria das linguagens, percorrer grande quantidade de dados é caro. Mas em Solidity, esta é a maneira mais barata do que usar `storage` se estiver em uma função `external view`, uma vez que funções `view` não custam qualquer gas para os seus usuários. (E gas custa dinheiro real para os seus usuários!). @@ -213,16 +254,15 @@ Você pode usar a palavra reservada `memory`com arrays (litas) para criar um nov Aqui esta como declarar uma lista em memória: ``` -function getArray() external pure returns(uint[]) { +function getArray() external pure returns(uint[] memory) { // Estancia um novo array em memory com o tamanho de 3 uint[] memory values = new uint[](3); // Adiciona alguns valores - values.push(1); - values.push(2); - values.push(3); + values[0] = 1; + values[1] = 2; + values[2] = 3; - // Retorna o array return values; } ``` @@ -237,6 +277,6 @@ Em nossa função `getZombiesByOwner`, queremos retornar um array `uint[]` com t 1. Declare uma variável `uint[] memory` chamada `result` -2. Atribua a mesma igual a um novo array `uint`. O tamanho do array deve ser entretanto a quantidade de zumbis que este `_owner` possui, que podemos buscar olhando no mapeamento com: `ownerZombieCount[_owner]`. +2. Atribua a mesma igual a um novo array `uint`. O tamanho do array deve ser entretanto a quantidade de zumbis que este `_owner` possui, que podemos consultar em nosso `mapping` (mapeamento) com: `ownerZombieCount[_owner]`. 3. No final da função retorne o `result`. É somente um array vazio por enquanto, mas no próximo capítulo iremos preenchê-lo. diff --git a/pt/3/12-forloops.md b/pt/3/12-forloops.md index f804bea5b7..ce50c076c6 100644 --- a/pt/3/12-forloops.md +++ b/pt/3/12-forloops.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -18,7 +18,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -28,7 +28,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); // Comece aqui return result; @@ -37,7 +37,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -64,15 +64,20 @@ material: kittyContract = KittyInterface(_address); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { + function _triggerCooldown(Zombie storage _zombie) internal { + _zombie.readyTime = uint32(now + cooldownTime); + } + + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); + _triggerCooldown(myZombie); } function feedOnKitty(uint _zombieId, uint _kittyId) public { @@ -83,7 +88,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -107,19 +112,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -128,47 +133,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -179,7 +220,7 @@ material: _; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -189,7 +230,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -204,20 +245,20 @@ material: } --- -No capítulo anterior, mencionamos que algumas vezes você irá querer usar o laço `for` para construir os conteúdos de um array em uma função ao invés de simplesmente salvar esse array no storage. +In the previous chapter, we mentioned that sometimes you'll want to use a `for` loop to build the contents of an array in a function rather than simply saving that array to storage. -Veremos o por quê. +Let's look at why. -Para a nossa função `getZombiesByOwner`, uma implementação ingênua seria guardar os donos dos exércitos de zumbis em um storage (armazenamento) no contrato `ZombieFactory`: +For our `getZombiesByOwner` function, a naive implementation would be to store a `mapping` of owners to zombie armies in the `ZombieFactory` contract: ``` mapping (address => uint[]) public ownerToZombies ``` -Então toda vez que criamos um novo zumbi, seria simples usar `ownerToZombies[owner].push(zombieId)` para adicioná-lo no array do dono do zumbi. E `getZombiesByOwner` seria uma função bem simples: +Then every time we create a new zombie, we would simply use `ownerToZombies[owner].push(zombieId)` to add it to that owner's zombies array. And `getZombiesByOwner` would be a very straightforward function: ``` -function getZombiesByOwner(address _owner) external view returns (uint[]) { +function getZombiesByOwner(address _owner) external view returns (uint[] memory) { return ownerToZombies[_owner]; } ``` @@ -238,7 +279,7 @@ Um vez que escrever em storage (armazenamento) é uma das operações mais caras > Nota: É claro que poderíamos somente mover o último zumbi na lista e preencher um espaço vazio para reduzir o tamanho do array. Mas então mudaríamos a ordem dos nossos exército de zumbis toda vez que houvesse uma troca. -Desde que funções `view` não custam gas algum quando chamadas externamente, poderíamos simplesmente usar um laço `for` em `getZombiesByOwner` para iterar todos os zumbis na lista e construir um array de zumbis que pertencem a este usuário específico. Então nossa função `transfer` seria muito mais barata, um vez que não precisamos reordenar qualquer array em storage, e de certa maneira não intuitiva essa abordagem é mais barata de todas. +Desde que funções `view` não custam gás quando chamadas externamente, podemos simplesmente usar um for-loop em `getZombiesByOwner` para iterar todo o array zombies e construir um array dos zumbis que pertencem a esse dono específico. Então nossa função `transfer` será muito mais barata, já que não precisamos reordenar nenhum array no armazenamento, e um tanto contraintuitivamente essa abordagem é mais barata no geral. ## Usando laços `for` @@ -247,25 +288,20 @@ A sintaxe do laço `for` em Solidity é similar a de JavaScript. Vejamos um exemplo onde queremos fazer um array de números pares: ``` -function getEvens() pure external returns(uint[]) { +function getEvens() pure external returns(uint[] memory) { uint[] memory evens = new uint[](5); - // Mantêm o registro do índex do novo array: uint counter = 0; - // Itera 1 através de 10 com um laço for: for (uint i = 1; i <= 10; i++) { // Se `i` é par ... if (i % 2 == 0) { - // Adiciona em nosso array evens[counter] = i; - // Incrementa o contador para o próximo índex vazio em `evens`: counter++; } } - return evens; } ``` diff --git a/pt/4/00-overview.md b/pt/4/00-overview.md index 9a1ce67fc9..1e47afcd3d 100644 --- a/pt/4/00-overview.md +++ b/pt/4/00-overview.md @@ -1,7 +1,9 @@ --- title: Sistema de Batalha Zumbi -header: "Lesson 4: Sistema de Batalha Zumbi" +header: "Lição 4: Sistema de Batalha Zumbi" roadmap: roadmap4.jpg +path: solidity +publishedOn: Cryptozombies --- Chegou a hora, humano... diff --git a/pt/4/battle-01.md b/pt/4/battle-01.md index a37b13f832..693fbe95e7 100644 --- a/pt/4/battle-01.md +++ b/pt/4/battle-01.md @@ -8,7 +8,7 @@ material: startingCode: "zombieattack.sol": | "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -22,7 +22,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address payable _owner = address(uint160(owner())); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -34,7 +35,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -44,7 +45,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -58,7 +59,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -93,13 +94,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -113,7 +114,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -137,19 +138,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -158,56 +159,92 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { } --- -Agora que nós aprendemos sobre as funções `payable` e saldos em contratos, é hora de adicionar a funcionalidade para as batalhas zumbis! +Agora que nós aprendemos sobre as funções payable e saldos em contratos, é hora de adicionar a funcionalidade para as batalhas zumbis! Seguindo o formato dos capítulos anteriores, nós iremos organizar o nosso código criando um novo arquivo / contrato para a funcionalidade de ataque que importa o contrato anterior. @@ -217,8 +254,8 @@ Vamos revisar criando um novo contrato. Repetição leva ao domínio! Se você não conseguir lembrar da sintaxe, então de uma olhada na sintaxe do contrato `zombiehelper.sol` - mas tente fazer sem a referência primeiro para testar o seu conhecimento. -1. Declare no topo do arquivo que iremos usar a versão de Solidity `^0.4.19`. +1. Declare no topo do arquivo que iremos usar a versão de Solidity `>=0.5.0 <0.6.0`. 2. `import` o `zombiehelper.sol`. -3. Declare um novo `contract` chamado `ZombieBattle` que herda do `ZombieHelper`. Deixe o corpo do contrato vazio por enquanto. +3. Declare um novo `contract` chamado `ZombieAttack` que herda do `ZombieHelper`. Deixe o corpo do contrato vazio por enquanto. diff --git a/pt/4/battle-02.md b/pt/4/battle-02.md index 17e954b5e7..3a951da65b 100644 --- a/pt/4/battle-02.md +++ b/pt/4/battle-02.md @@ -7,13 +7,15 @@ material: language: sol startingCode: "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { // Comece aqui } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -27,7 +29,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address payable _owner = address(uint160(owner())); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -39,7 +42,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -49,7 +52,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -63,7 +66,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -98,13 +101,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -118,7 +121,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -142,19 +145,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -163,54 +166,92 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } } @@ -233,9 +274,9 @@ Podemos fazer algo como a seguir para gerar um número aleatório: ``` // Gera um número aleatório entre 1 e 100: uint randNonce = 0; -uint random = uint(keccak256(now, msg.sender, randNonce)) % 100; +uint random = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % 100; randNonce++; -uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100; +uint random2 = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % 100; ``` Que seria obter o timestamp de `now`, e `msg.sender`, e incrementar um `nonce` (um número que é usado somente uma vez, então nós não iremos rodar a mesma função de hash com os mesmos parâmetros duas vezes). @@ -250,7 +291,7 @@ Uma vez que o nó resolveu o PoW, os outros nós param de tentar resolver o PoW, **Isto torna a nossa função de números aleatórios explorável.** -Digamos que temos um contrato de jogo de moeda - se o resultado for "cara" você dobra o seu dinheiro, "coroa" você perde tudo. Digamos que utilizamos a função geradora de aleatórios acima para determinar "cara" ou "coroa". (`random >= 50`) é "cara", `random < 50` é "coroa"). +Digamos que temos um contrato de jogo de moeda - se o resultado for "cara" você dobra o seu dinheiro, "coroa" você perde tudo. Digamos que utilizamos a função geradora de aleatórios acima para determinar "cara" ou "coroa". (`random >= 50` é cara, `random < 50` é coroa). Se estivéssemos rodando um nó da rede, eu poderia publicar uma transação **somente para o meu nó** e não compartilhá-la. Eu poderia então rodar a função do jogo da moeda para ver se eu ganho - e se eu perco. Eu poderia fazer isso indefinidamente até eu finalmente ganhar o jogo da moeda e resolver o próximo bloco, e lucrar. @@ -258,7 +299,7 @@ Se estivéssemos rodando um nó da rede, eu poderia publicar uma transação **s Por que todos os conteúdos da blockchain são visíveis para todos os participantes, este é um problema difícil, e sua solução esta além do escopo deste tutorial. Você pode ler esta pergunta no StackOverflow para ter algumas ideias. Uma ideia seria usar um **_oracle_** (oráculo) para acessar uma função de número aleatório de fora da blockchain do Ethereum. -Claro que uma vez que milhares de nós na rede Ethereum estão competindo para resolver o próximo bloco, minhas chances de resolver o próximo bloco são extremamente baixas. E iria me tomar um monte de tempo ou recursos computacionais para tornar esse _exploit_ lucrativo - mas se as recompensas fossem altas o suficiente (algo do tipo ganhar uma aposta de $100,000,000 no jogo da moeda), então valeria a pena pra mim fazer este ataque. +Claro que uma vez que milhares de nós na rede Ethereum estão competindo para resolver o próximo bloco, minhas chances de resolver o próximo bloco são extremamente baixas. E iria me tomar um monte de tempo ou recursos computacionais para tornar esse exploit lucrativo - mas se as recompensas fossem altas o suficiente (algo do tipo ganhar uma aposta de $100,000,000 no jogo da moeda), então valeria a pena pra mim fazer este ataque. Então enquanto esta geração de número aleatório NÃO é segura no Ethereum, em prática ao menos que a nossa função de número aleatório tenha um monte de dinheiro em jogo, os usuários do jogo não usaram recursos o suficiente para atacá-la. @@ -276,4 +317,4 @@ Vamos implementar uma função de números aleatórios que podemos determinar os 3. A função deverá primeiro incrementar o `randNonce` (usando a sintaxe `randNonce++`). -4. Finalmente, esta deverá (em uma linha de código) calcular o `uint` convertendo o resultado do hash de `keccak256` para os valores de `now`, `msg.sender`, e `randNonce` e retornar o valor `% _modulus`. (Uffa! Essa foi difícil. Se você não entendeu, de uma olhada no exemplo acima onde geramos um número aleatório - a lógica é muito parecida). +4. Finalmente, esta deverá (em uma linha de código) calcular o `uint` convertendo o resultado do hash `keccak256` de `abi.encodePacked(now,msg.sender,randNonce)` — e `retornar` o valor `% _modulus`. (Ufa! Essa foi difícil. Se você não entendeu, dê uma olhada no exemplo acima, onde geramos um número aleatório — a lógica é muito parecida). diff --git a/pt/4/battle-03.md b/pt/4/battle-03.md index 335df71ba1..ce105a38bc 100644 --- a/pt/4/battle-03.md +++ b/pt/4/battle-03.md @@ -7,21 +7,23 @@ material: language: sol startingCode: "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; // Crie attackVictoryProbability aqui function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } // Crie a nova função aqui } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -35,7 +37,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address payable _owner = address(uint160(owner())); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -47,7 +50,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -57,7 +60,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -71,7 +74,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -106,13 +109,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -126,7 +129,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -150,19 +153,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -171,55 +174,93 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external { diff --git a/pt/4/battle-04.md b/pt/4/battle-04.md index ce0ca8383a..0b74e6266f 100644 --- a/pt/4/battle-04.md +++ b/pt/4/battle-04.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -45,14 +45,14 @@ material: } // 2. Adicione o modificador nesta função: - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { // 3. Remova esta linha require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -66,22 +66,24 @@ material: } } "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external { } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -95,7 +97,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -107,7 +110,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -117,7 +120,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -131,7 +134,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -155,19 +158,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -176,47 +179,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -256,12 +295,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -294,16 +333,15 @@ Fizemos esta mesma checagem várias vezes nas lições anteriores. Em `changeNam require(msg.sender == zombieToOwner[_zombieId]); ``` -Esta é mesma lógica que precisamos para nossa função `attack`. Uma vez que usamos a mesma lógica várias vezes, vamos mover esse código para uma função modificadora (`modifier`) para limpar o nosso código e evitar repetições de código. +Esta é mesma lógica que precisamos para nossa função `attack`. Uma vez que usamos a mesma lógica várias vezes, vamos mover esse código para uma função modificadora `modifier` para limpar o nosso código e evitar repetições de código. ## Vamos testar -Estamos de volta a `zombiefeeding.sol`, uma vez que este foi o primeiro lugar que usamos a lógica. Vamos refatorá-lo em seu próprio modificador (`modifier`). - +Estamos de volta a `zombiefeeding.sol`, uma vez que este foi o primeiro lugar que usamos a lógica. Vamos refatorá-lo em seu próprio modificador `modifier`. 1. Crie um `modifier` chamado `ownerOf`. Este terá 1 argumento, `_zombieId` (um `uint`). - O corpo da função modificadora deverá usar o `require` para o `msg.sender` ser igual a `zombieToOwner[_zombieId]`, então continue a função. Você pode usar como referência o `zombiehelper.sol` se você não lembrar da sintaxe do `modifier`. + O corpo da função modificadora deverá usar o `require` para o `msg.sender` ser igual a `zombieToOwner[_zombieId]`, então continue a função. Você pode usar como referência o `zombiehelper.sol` se você não lembrar da sintaxe do modificador. 2. Mude a definição da função de `feedAndMultiply` para que use o modificador `ownerOf`. diff --git a/pt/4/battle-05.md b/pt/4/battle-05.md index 12d5233c69..460cf4e319 100644 --- a/pt/4/battle-05.md +++ b/pt/4/battle-05.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -21,15 +21,21 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } + function levelUp(uint _zombieId) external payable { + require(msg.value == levelUpFee); + zombies[_zombieId].level++; + } + // 1. Modifique esta função para usar o `ownerOf`: - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -40,7 +46,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -54,22 +60,24 @@ material: } "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external { } } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -109,12 +117,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -128,7 +136,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -152,19 +160,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -173,47 +181,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -227,14 +271,20 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function levelUp(uint _zombieId) external payable { + require(msg.value == levelUpFee); + zombies[_zombieId].level++; + } + + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -242,7 +292,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { diff --git a/pt/4/battle-06.md b/pt/4/battle-06.md index bf7d6af6e4..d8f726bac2 100644 --- a/pt/4/battle-06.md +++ b/pt/4/battle-06.md @@ -7,15 +7,18 @@ material: language: sol startingCode: "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; + } // 1. Adicione o modificador aqui @@ -24,7 +27,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -38,14 +41,20 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function levelUp(uint _zombieId) external payable { + require(msg.value == levelUpFee); + zombies[_zombieId].level++; + } + + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -53,7 +62,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -67,7 +76,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -107,12 +116,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -126,7 +135,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -150,19 +159,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -171,55 +180,93 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { diff --git a/pt/4/battle-07.md b/pt/4/battle-07.md index 741ed503be..1b29b20b38 100644 --- a/pt/4/battle-07.md +++ b/pt/4/battle-07.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -32,20 +32,20 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { // 2. Modifique a criação do novo zumbi aqui: uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -54,15 +54,17 @@ material: } "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -72,7 +74,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -86,14 +88,20 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function levelUp(uint _zombieId) external payable { + require(msg.value == levelUpFee); + zombies[_zombieId].level++; + } + + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -101,7 +109,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -115,7 +123,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -155,12 +163,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -174,47 +182,83 @@ material: } } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -240,19 +284,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; diff --git a/pt/4/battle-08.md b/pt/4/battle-08.md index 70f45bce79..833f484a6a 100644 --- a/pt/4/battle-08.md +++ b/pt/4/battle-08.md @@ -7,15 +7,17 @@ material: language: sol startingCode: "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -26,7 +28,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -40,14 +42,20 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function levelUp(uint _zombieId) external payable { + require(msg.value == levelUpFee); + zombies[_zombieId].level++; + } + + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -55,7 +63,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -69,7 +77,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -109,12 +117,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -128,7 +136,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -154,19 +162,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -175,55 +183,93 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { diff --git a/pt/4/battle-09.md b/pt/4/battle-09.md index 5c27743590..5d1e8a9340 100644 --- a/pt/4/battle-09.md +++ b/pt/4/battle-09.md @@ -7,15 +7,17 @@ material: language: sol startingCode: "zombieattack.sol": | + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -31,7 +33,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -45,14 +47,20 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { levelUpFee = _fee; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function levelUp(uint _zombieId) external payable { + require(msg.value == levelUpFee); + zombies[_zombieId].level++; + } + + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -60,7 +68,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -74,7 +82,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -114,12 +122,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -133,7 +141,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -159,19 +167,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -180,55 +188,93 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > + pragma solidity >=0.5.0 <0.6.0; + import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -243,8 +289,8 @@ material: } else { myZombie.lossCount++; enemyZombie.winCount++; + _triggerCooldown(myZombie); } - _triggerCooldown(myZombie); } } --- diff --git a/pt/4/payable.md b/pt/4/payable.md index 7e28b51fa8..f5023a4847 100644 --- a/pt/4/payable.md +++ b/pt/4/payable.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -22,7 +22,7 @@ material: // 2. Crie a função levelUp aqui - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -32,7 +32,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -46,7 +46,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -81,13 +81,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -101,7 +101,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -125,19 +125,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -146,47 +146,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -204,7 +240,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -214,7 +250,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { diff --git a/pt/4/withdraw.md b/pt/4/withdraw.md index 5aee5b0465..ec6d19b401 100644 --- a/pt/4/withdraw.md +++ b/pt/4/withdraw.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -29,7 +29,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -39,7 +39,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -53,7 +53,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -88,13 +88,13 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -108,7 +108,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -132,19 +132,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -153,47 +153,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } answer: > - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -207,7 +243,9 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address payable _owner = address(uint160(owner())); + _owner.transfer(address(this).balance); + } function setLevelUpFee(uint _fee) external onlyOwner { @@ -219,7 +257,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) { require(msg.sender == zombieToOwner[_zombieId]); zombies[_zombieId].name = _newName; } @@ -229,7 +267,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -244,25 +282,28 @@ material: } --- -No capítulo anterior, aprendemos como enviar Ether para um contrato. Então o que acontece após o envio? +In the previous chapter, we learned how to send Ether to a contract. So what happens after you send it? -Após você enviar Ether para um contrato, este fica guardado na conta Ethereum do contrato, e ficará preso no contrato - ao menos que você adicione uma função para sacar o Ether do contrato. +After you send Ether to a contract, it gets stored in the contract's Ethereum account, and it will be trapped there — unless you add a function to withdraw the Ether from the contract. -Você pode escrever a função para sacar o Ether do contrato conforme exemplo: +You can write a function to withdraw Ether from the contract as follows: ``` contract GetPaid is Ownable { function withdraw() external onlyOwner { - owner.transfer(this.balance); + address payable _owner = address(uint160(owner())); + _owner.transfer(address(this).balance); } } ``` -Note que usamos `owner` e `onlyOwner` do contrato `Ownable`, assumindo que foi importado. +Note que usamos `owner()` e `onlyOwner` do contrato `Ownable`, assumindo que foi importado. + +É importante notar que você não pode transferir Ether para um endereço a menos que esse endereço seja do tipo `address payable`. Mas a variável `_owner` é do tipo `uint160`, o que significa que devemos convertê-la explicitamente para `address payable`. -Você pode transferir Ether para um endereço usando a função `transfer`, e `this.balance` irá retornar o saldo total guardado no contrato. Então se 100 usuários pagarem 1 Ether para nos contrato, `this.balance` irá ser igual a 100 Ether. +Depois de converter o endereço de `uint160` para `address payable`, você pode transferir Ether para esse endereço usando a função `transfer`, e `address(this).balance` retornará o saldo total armazenado no contrato. Então, se 100 usuários tivessem pago 1 Ether para o nosso contrato, `address(this).balance` seria igual a 100 Ether. -Você pode usar `transfer` para enviar fundos para qualquer endereço Ethereum. Por exemplo, você poderia ter uma função que transfere Ether de volta para o `msg.sender` se eles pagarem à mais por um item: +Você pode usar `transfer` para enviar fundos para qualquer endereço Ethereum. Por exemplo, você poderia ter uma função que transfere Ether de volta para o `msg.sender` se eles pagarem a mais por um item: ``` uint itemFee = 0.001 ether; diff --git a/pt/5/00-overview.md b/pt/5/00-overview.md index cc6cc72d21..b4b43909ce 100644 --- a/pt/5/00-overview.md +++ b/pt/5/00-overview.md @@ -2,6 +2,8 @@ title: ERC721 & Cripto-Colecionáveis header: "Lesson 5: ERC721 & Cripto-Colecionáveis" roadmap: roadmap5.jpg +path: solidity +publishedOn: Cryptozombies --- Ufa! As coisas estão começando a esquentar aqui... diff --git a/pt/5/01-erc721-1.md b/pt/5/01-erc721-1.md index fe2797f165..61a9cbe2a0 100644 --- a/pt/5/01-erc721-1.md +++ b/pt/5/01-erc721-1.md @@ -9,17 +9,17 @@ material: "zombieownership.sol": | // Comece aqui "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -38,8 +38,9 @@ material: } } } + "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -53,7 +54,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -65,7 +67,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -73,7 +75,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -86,8 +88,9 @@ material: } } + "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -127,12 +130,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -145,8 +148,9 @@ material: feedAndMultiply(_zombieId, kittyDna, "kitty"); } } + "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -172,19 +176,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -192,51 +196,89 @@ material: } } + "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } + answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; - + contract ZombieOwnership is ZombieAttack { } @@ -246,7 +288,7 @@ Vamos falar sobre **_tokens_**. Se você esteve acompanhando o Ethereum por período de tempo, você provavelmente ouviu pessoas falando sobre tokens - especificamente **_ERC20 tokens_**. -Um **_token_** no Ethereum é basicamente um smart contract (contrato inteligente) que segue algumas regras comuns — isto é, ele implementa um conjunto padrão de funções que todos os outros contratos de token compartilham, como o `transfer(address _to, uint256 _value)` e `balanceOf(address _owner)`. +Um **_token_** no Ethereum é basicamente um smart contract (contrato inteligente) que segue algumas regras comuns — isto é, ele implementa um conjunto padrão de funções que todos os outros contratos de token compartilham, como o `transferFrom(address _from, address _to, uint256 _amount)` e `balanceOf(address _owner)`. Internamente o smart contract normalmente tem um mapeamento, `mapping(address => uint256) balances`, que mantêm o registro de quanto em saldo cada endereço tem. diff --git a/pt/5/02-erc721-2.md b/pt/5/02-erc721-2.md index a4871aab66..f45fca60a4 100644 --- a/pt/5/02-erc721-2.md +++ b/pt/5/02-erc721-2.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; // Importe o arquivo aqui @@ -17,17 +17,17 @@ material: } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -46,8 +46,9 @@ material: } } } + "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -61,7 +62,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -73,7 +75,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -81,7 +83,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -94,8 +96,9 @@ material: } } + "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -135,12 +138,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -153,8 +156,9 @@ material: feedAndMultiply(_zombieId, kittyDna, "kitty"); } } + "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -180,19 +184,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -201,62 +205,99 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { } @@ -266,14 +307,13 @@ Vamos dar uma olhada no padrão ERC721: ``` contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } ``` @@ -281,7 +321,6 @@ Esta é a lista de métodos que precisamos implementar, que iremos fazer em part Isso parece um monte, mas sinta-se sobrecarregado! Estamos aqui para guiar você. -> Nota: O padrão ERC721 é atualmente um *rascunho*, e ainda não há oficialmente um acordo de implementação. Neste tutorial usamos a versão atual da biblioteca do OpenZeppelin, mas é possível que mude no futuro antes do lançamento oficial. Então considere esta **uma** possível implementação, mas não considere uma versão oficial dos tokens ERC721. ### Implementando um contrato de token @@ -299,7 +338,9 @@ contract SatoshiNakamoto is NickSzabo, HalFinney { Como você pode ver, quando usando a múltipla herança, você pode separar os múltiplos contrato que você estar herdando com um vírgula, `,`. Neste caso, nosso contrato esta herdando de `NickSzabo` e `HalFinney`. -## Vamos testar +Vamos tentar. + +## Colocando à prova Já criamos `erc721.sol` com as interfaces acima para você. diff --git a/pt/5/03-erc721-3.md b/pt/5/03-erc721-3.md index 271b8e040b..7f81933ddd 100644 --- a/pt/5/03-erc721-3.md +++ b/pt/5/03-erc721-3.md @@ -7,45 +7,41 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { // 1. Retorne o número de zumbis que o `_owner` tem aqui } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { // 2. Retorne o dono do `_tokenId` aqui } - function transfer(address _to, uint256 _tokenId) public { - - } - - function approve(address _to, uint256 _tokenId) public { + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external ownerOf(_zombieId) { @@ -64,8 +60,9 @@ material: } } } + "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -79,7 +76,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -91,7 +89,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) ownerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -99,7 +97,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -113,7 +111,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -153,12 +151,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -172,7 +170,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -198,19 +196,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -218,82 +216,115 @@ material: } } - "ownable.sol": | + "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + + /** + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ + contract Ownable { + address private _owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ - contract Ownable { - address public owner; - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; - } + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); + } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(msg.sender == owner); - _; - } + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(isOwner()); + _; + } + + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } - /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ - function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; - } + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function transferOwnership(address newOwner) public onlyOwner { + _transferOwnership(newOwner); + } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; } - "erc721.sol": | + } + "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } - function transfer(address _to, uint256 _tokenId) public { - - } - - function approve(address _to, uint256 _tokenId) public { + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } } @@ -308,7 +339,7 @@ Neste capítulos, iremos implementar os dois primeiros métodos: `balanceOf` e ` ### `balanceOf` ``` - function balanceOf(address _owner) public view returns (uint256 _balance); + function balanceOf(address _owner) external view returns (uint256 _balance); ``` Esta função simplesmente recebe um `address`, e retorna quantos tokens que o `address` tem. @@ -318,7 +349,7 @@ Em nosso caso, nossos "tokens" são Zumbis. Você lembra onde em nossa DApp nós ### `ownerOf` ``` - function ownerOf(uint256 _tokenId) public view returns (address _owner); + function ownerOf(uint256 _tokenId) external view returns (address _owner); ``` Esta função recebe um token ID (em nosso caso, um ID Zumbi), e retorna o `address` da pessoa que o possui. diff --git a/pt/5/04-erc721-4.md b/pt/5/04-erc721-4.md index 1efe3f9e95..a7d998ad75 100644 --- a/pt/5/04-erc721-4.md +++ b/pt/5/04-erc721-4.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -49,12 +49,12 @@ material: } // 2. Mude o nome do modificador aqui também - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal ownerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal ownerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -68,45 +68,42 @@ material: } } "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } - function transfer(address _to, uint256 _tokenId) public { + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { } - function approve(address _to, uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { - - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -126,7 +123,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -140,7 +137,9 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); + } function setLevelUpFee(uint _fee) external onlyOwner { @@ -152,7 +151,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -160,7 +159,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -174,7 +173,7 @@ material: } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -200,19 +199,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -221,58 +220,95 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -312,12 +348,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); diff --git a/pt/5/05-erc721-5.md b/pt/5/05-erc721-5.md index a65dd23e4a..160871fda1 100644 --- a/pt/5/05-erc721-5.md +++ b/pt/5/05-erc721-5.md @@ -7,47 +7,43 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } // Defina a função _transfer() aqui - function transfer(address _to, uint256 _tokenId) public { - - } - - function approve(address _to, uint256 _tokenId) public { + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -67,7 +63,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -81,7 +77,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -93,7 +90,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -101,7 +98,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -115,7 +112,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -155,12 +152,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -174,7 +171,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -200,19 +197,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -221,69 +218,105 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -291,20 +324,17 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public { + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { } - function approve(address _to, uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { - - } } --- @@ -314,19 +344,21 @@ Agora iremos continuar nossa implementação do ERC721 olhando na transferência Note que a especificação ERC721 tem duas maneiras diferentes de transferir tokens: -``` -function transfer(address _to, uint256 _tokenId) public; -function approve(address _to, uint256 _tokenId) public; -function takeOwnership(uint256 _tokenId) public; -``` +`function transferFrom(address _from, address _to, uint256 _tokenId) external payable;` + +e + +`function approve(address _approved, uint256 _tokenId) external payable;` + +`function transferFrom(address _from, address _to, uint256 _tokenId) external payable;` -1. A primeira forma é o dono do token chamar `transfer` com o `address` que ele quer transferir, e o `_tokenId` do token que ele quer transferir. +1. A primeira forma é o proprietário do token chamar `transferFrom` com seu `address` como o parâmetro `_from`, o `address` para o qual ele deseja transferir como o parâmetro `_to` e o `_tokenId` do token que ele deseja transferir. -2. A segunda forma é o dono do token primeiro chama `approve`, e envia a mesma informação acima. O contrato então guarda quem esta aprovado para pegar o token, normalmente um `mapping (uint256 => address)`. Então quando alguém chamar `takeOwnership`, o contrato checa se o `msg.sender` esta aprovado pelo dono para pegar o token, se estiver transfere o token para ele. +2. A segunda forma é o proprietário do token primeiro chamar `approve` com o endereço para o qual ele quer transferir, e o `_tokenID` . O contrato então armazena quem é aprovado para pegar um token, geralmente em um `mapping (uint256 => address)`. Então, quando o proprietário ou o endereço aprovado chamar `transferFrom`, o contrato verifica se `msg.sender` é o proprietário ou é aprovado pelo proprietário para pegar o token, e se for, ele transfere o token para ele. -Se você notar, ambos `transfer` e `takeOwnership` irão conter a mesma lógica de transferência, em ordem inversa. (Em um caso o remetente do token chama a função; na outra o destinatário do token a chama). +Observe que ambos os métodos contêm a mesma lógica de transferência. Em um caso, o remetente do token chama a função `transferFrom`; no outro, o proprietário ou o receptor aprovado do token a chama. -Então faz sentido abstrairmos esta lógica em uma função privada, `_transfer`, que então será chamada por ambas funções. Desta maneira não precisamos repetir o mesmo código duas vezes. +Portanto, faz sentido abstrairmos essa lógica em sua própria função privada, `_transfer`, que é então chamada por `transferFrom`. ## Vamos testar diff --git a/pt/5/06-erc721-6.md b/pt/5/06-erc721-6.md index d0de2b5ee8..4f5cbbd88c 100644 --- a/pt/5/06-erc721-6.md +++ b/pt/5/06-erc721-6.md @@ -1,5 +1,5 @@ --- -title: "ERC721: Ainda na Transferência" +title: "ERC721: Transferência (Continuação)" actions: ['verificarResposta', 'dicas'] requireLogin: true material: @@ -7,18 +7,20 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + // 1. Defina o mapeamento aqui + + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -26,34 +28,31 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - // 1. Adicione o modificador aqui - function transfer(address _to, uint256 _tokenId) public { - // 2. Defina a função aqui + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + // 2. Adicione a declaração require aqui + // 3. Chame _transfer } - function approve(address _to, uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { - - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -73,7 +72,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -87,7 +86,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -99,7 +99,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldaata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -107,7 +107,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -121,7 +121,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -161,12 +161,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -180,7 +180,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -206,19 +206,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -227,69 +227,108 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - function balanceOf(address _owner) public view returns (uint256 _balance) { + mapping (uint => address) zombieApprovals; + + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -297,31 +336,38 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public { + function approve(address _approved, uint256 _tokenId) external payable { } - function takeOwnership(uint256 _tokenId) public { - - } } --- -Ótimo! Esta foi a parte difícil – agora implementando a função pública `transfer` será fácil, uma vez que nossa função `_transfer` já faz quase toda a parte pesada. +Ótimo! Essa foi a parte difícil — agora implementar a função externa `transferFrom` será fácil, já que nossa função `_transfer` já faz quase todo o trabalho pesado. ## Vamos testar -1. Queremos ter certeza que somente o dono do token/zumbi pode transferi-lo. Lembra como podemos limitar o acesso a função para somente o dono? +1. Primeiro, queremos ter certeza de que somente o proprietário ou o endereço aprovado de um token/zumbi pode transferi-lo. Vamos definir um mapeamento chamado `zombieApprovals`. Ele deve mapear um `uint` para um `address`. +Dessa forma, quando alguém que não é o proprietário chama `transferFrom` com um `_tokenId`, podemos usar esse mapeamento para verificar rapidamente se ele está aprovado para receber esse token. + +2. Em seguida, vamos adicionar uma declaração `require` a `transferFrom`. Ela deve garantir que apenas o proprietário ou o endereço aprovado de um token/zumbi possa transferi-lo. + +3. Por fim, não esqueça de chamar `_transfer`. + +> Nota: Verificar se apenas o proprietário ou o endereço aprovado de um token/zumbi pode transferi-lo significa que pelo menos uma dessas condições deve ser verdadeira: + +>`zombieToOwner` para `_tokenId` é igual a `msg.sender` - Sim, isso mesmo, nós já temos um modificador que faz isso. Então vamos adicionar o modificador `onlyOwnerOf` para esta função. +>ou -2. Agora o corpo da função realmente somente precisa de uma linha... Só precisa chamar `_transfer`. +>`zombieApprovals` para `_tokenId` é igual a `msg.sender` - Tenha certeza de passar o `msg.sender` para o argumento `address _from`. +Não se preocupe em preencher dados no mapeamento `zombieApprovals`, faremos isso no próximo capítulo. diff --git a/pt/5/07-erc721-7.md b/pt/5/07-erc721-7.md index cf5a23f53b..fc36d197ce 100644 --- a/pt/5/07-erc721-7.md +++ b/pt/5/07-erc721-7.md @@ -7,20 +7,20 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { - // 1. Defina o mapeamento aqui + mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -28,34 +28,33 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - // 2. Adicione a função modificador aqui - function approve(address _to, uint256 _tokenId) public { - // 3. Defina a função aqui + // 1. Add function modifier here + function approve(address _approved, uint256 _tokenId) external payable { + // 2. Define function here } - function takeOwnership(uint256 _tokenId) public { - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -75,7 +74,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -89,7 +88,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -101,7 +101,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -109,7 +109,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -123,7 +123,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -163,12 +163,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -182,7 +182,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -208,19 +208,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -229,71 +229,108 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -301,42 +338,33 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; } - function takeOwnership(uint256 _tokenId) public { - - } } --- Agora, vamos implementar `approve`. -Lembre-se, com `approve` / `takeOwnership`, a transferência acontece em 2 passos: +Lembre-se, com `approve` a transferência acontece em 2 etapas: -1. Você, o dono, chama `approve` e informa o `address` do novo dono, e o `_tokenId` que você quer ele pegue +1. Você, o proprietário, chama `approve` e fornece o endereço `_approved` do novo proprietário e o `_tokenId` que você deseja que ele use. -2. O novo dono chama `takeOwnership` com o `_tokenId`, o contrato verifica para certeza que ele já foi aprovado, e então transfer a ele o token. +2. O novo proprietário chama `transferFrom` com o `_tokenId`. Em seguida, o contrato verifica para certificar-se de que o novo proprietário já foi aprovado e, em seguida, transfere o token a ele. -Por que isto acontece em 2 chamadas de funções, precisamos de uma estrutura de dados para guardar quem esta sendo aprovado para que entre as chamadas das funções. +Como isso acontece em duas chamadas de função, precisamos usar a estrutura de dados `zombieApprovals` para armazenar quem foi aprovado para quê entre as chamadas de função. ## Vamos testar -1. Primeiro, vamos definir uma mapeamento `zombieApprovals`. Este deve mapear um `uint` para um `address`. - - Desta maneira, quando alguém chamar `takeOwnership` com um `_tokenId`, podemos usar este mapeamento para rapidamente achar quem é aprovado para pegar o token. - -2. Na função `approve`, queremos ter certeza que somente o dono do token pode dar permissão para alguém obtê-lo. Então precisamos adicionar o modificador `onlyOwnerOf` em `approve` - -3. Para o corpo da função, atribua `zombieApprovals` para o `_tokenId` igual o endereço `_to`. +1. Na função `approve`, queremos ter certeza de que somente o dono do token pode dar aprovação a alguém para pegá-lo. Então, precisamos adicionar o modificador `onlyOwnerOf` para `approve` -4. Finalmente, há um evento `Approval` na especificação ERC721. Então devemos disparar este evento no final da função. Verifique o `erc721.sol` para os argumentos, e tenha certeza de usar `msg.sender` como o `_owner`. +2. Para o corpo da função, defina `zombieApprovals` para `_tokenId` igual ao endereço `_approved`. \ No newline at end of file diff --git a/pt/5/08-erc721-8.md b/pt/5/08-erc721-8.md index ac01bf5ee2..17b73e0964 100644 --- a/pt/5/08-erc721-8.md +++ b/pt/5/08-erc721-8.md @@ -1,5 +1,5 @@ --- -title: "ERC721: takeOwnership" +title: "ERC721: Approve" actions: ['verificarResposta', 'dicas'] requireLogin: true material: @@ -7,20 +7,20 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -28,34 +28,33 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + //Dispare o evento de aprovação aqui } - function takeOwnership(uint256 _tokenId) public { - // Comece aqui - } + } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -75,7 +74,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -89,7 +88,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -101,7 +101,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -109,7 +109,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -123,7 +123,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -168,7 +168,7 @@ material: require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -182,7 +182,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; @@ -208,19 +208,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -229,71 +229,108 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -301,40 +338,28 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } --- -Ótimo, agora vamos terminar a nossa implementação do ERC721 com a última função! (Não se preocupe, ainda há a mais para cobrir na Lição 5 após isso 😉) +Ótimo, estamos quase terminando! -A função final, `takeOwnership`, deve simplesmente verificar o `msg.sender` para ter certeza que foi aprovado para pegar este token / zumbi, e chamar `_transfer` se ok. +Há mais uma coisa a fazer - há um evento `Approval` na especificação ERC721. Então, devemos disparar esse evento no final da função `approve`. ## Vamos testar -1. Primeiro, queremos usar uma declaração de `require` para verificar que `zombieApprovals` para `_tokenId` é igual a `msg.sender`. - - Desta forma se `msg.sender` não for aprovado para pegar este token, este irá lançar um erro. - -2. Para chamar `_transfer`, precisamos saber o endereço da pessoa que é dono do token (isto requer `_from` como um argumento). Para a nossa sorte podemos ver isso em nossa função `ownerOf`. - - Então declare uma variável `address` chamada `owner`, e atribua igual a `ownerOf(_tokenId)`. - -3. Finalmente, chame `_transfer`, e passe-a toda a informação requerida. (Aqui você pode usar `msg.sender` para `_to`, uma vez que a pessoa chamando esta função é a escolhida para quem o token deve ser enviado). +1. Vamos disparar o evento `Approval`. Dê uma olhada no arquivo `erc721.sol` para os argumentos e certifique-se de usar `msg.sender` como `_owner`. -> Nota: Poderíamos ter feito os passos 2 e 3 em uma linha de código, mas separá-las deixa as coisas mais legíveis. Preferência pessoal. +Ótimo, finalizamos nossa implementação ERC721! diff --git a/pt/5/09-safemath-1.md b/pt/5/09-safemath-1.md index fdbe2dafe6..9cee80b9bf 100644 --- a/pt/5/09-safemath-1.md +++ b/pt/5/09-safemath-1.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; // 1. Importe aqui @@ -36,19 +36,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -57,20 +57,20 @@ material: } "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -78,36 +78,31 @@ material: ownerZombieCount[_to]++; ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); - } - - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -127,7 +122,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -141,7 +136,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -153,7 +149,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -161,7 +157,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -175,7 +171,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -215,12 +211,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -234,47 +230,83 @@ material: } } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -305,7 +337,7 @@ material: } /** - * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); @@ -322,18 +354,19 @@ material: } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -362,19 +395,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; diff --git a/pt/5/10-safemath-2.md b/pt/5/10-safemath-2.md index 3bffdd9e1e..120cc768e4 100644 --- a/pt/5/10-safemath-2.md +++ b/pt/5/10-safemath-2.md @@ -7,23 +7,23 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; import "./safemath.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { using SafeMath for uint256; mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -33,36 +33,32 @@ material: // 2. Substitua com o `sub` da SafeMath ownerZombieCount[_from]--; zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -82,7 +78,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -96,7 +92,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -108,7 +105,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -116,7 +113,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -130,7 +127,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -170,12 +167,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -189,7 +186,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -218,19 +215,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -239,47 +236,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -310,7 +343,7 @@ material: } /** - * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); @@ -327,34 +360,35 @@ material: } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; import "./safemath.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { using SafeMath for uint256; mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -362,23 +396,19 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[_from] = ownerZombieCount[_from].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } --- diff --git a/pt/5/11-safemath-3.md b/pt/5/11-safemath-3.md index 64512ff8b4..fa561a238e 100644 --- a/pt/5/11-safemath-3.md +++ b/pt/5/11-safemath-3.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -15,8 +15,8 @@ material: contract ZombieFactory is Ownable { using SafeMath for uint256; - // 1. Declare using SafeMath32 for uint32 - // 2. Declare using SafeMath16 for uint16 + // 1. Declarar usando SafeMath32 para uint32 + // 2. Declarar usando SafeMath16 para uint16 event NewZombie(uint zombieId, string name, uint dna); @@ -38,22 +38,22 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { // Nota: Nós escolhemos não prevenir o problema ano 2038...Então não precisa // se preocupar sobre overflow no readyTime. Nosso aplicativo será acabado em 2038 de qualquer forma ;) uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; // 3. Vamos usar o `add` do SafeMath aqui: ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -62,23 +62,23 @@ material: } "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; import "./safemath.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { using SafeMath for uint256; mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -86,36 +86,32 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -135,7 +131,7 @@ material: } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -149,7 +145,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -161,7 +158,7 @@ material: zombies[_zombieId].level++; } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -169,7 +166,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -183,7 +180,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -223,12 +220,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -242,47 +239,83 @@ material: } } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -313,7 +346,7 @@ material: } /** - * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); @@ -398,18 +431,19 @@ material: } } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -440,19 +474,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; diff --git a/pt/5/12-safemath-4.md b/pt/5/12-safemath-4.md index efe8b5e05a..1e29e2e476 100644 --- a/pt/5/12-safemath-4.md +++ b/pt/5/12-safemath-4.md @@ -7,18 +7,18 @@ material: language: sol startingCode: "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { // Aqui um! randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -40,23 +40,23 @@ material: } } "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; import "./safemath.sol"; - + contract ZombieOwnership is ZombieAttack, ERC721 { using SafeMath for uint256; mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -64,26 +64,22 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -97,7 +93,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -109,7 +106,7 @@ material: zombies[_zombieId].level = zombies[_zombieId].level.add(1); } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -117,7 +114,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -131,7 +128,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -171,12 +168,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -190,7 +187,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -221,19 +218,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); - NewZombie(id, _name, _dna); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -242,47 +239,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -313,7 +346,7 @@ material: } /** - * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); @@ -329,29 +362,98 @@ material: return c; } } + + /** + * @title SafeMath32 + * @dev SafeMath library implemented for uint32 + */ + library SafeMath32 { + + function mul(uint32 a, uint32 b) internal pure returns (uint32) { + if (a == 0) { + return 0; + } + uint32 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint32 a, uint32 b) internal pure returns (uint32) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint32 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint32 a, uint32 b) internal pure returns (uint32) { + assert(b <= a); + return a - b; + } + + function add(uint32 a, uint32 b) internal pure returns (uint32) { + uint32 c = a + b; + assert(c >= a); + return c; + } + } + + /** + * @title SafeMath16 + * @dev SafeMath library implemented for uint16 + */ + library SafeMath16 { + + function mul(uint16 a, uint16 b) internal pure returns (uint16) { + if (a == 0) { + return 0; + } + uint16 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint16 a, uint16 b) internal pure returns (uint16) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint16 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint16 a, uint16 b) internal pure returns (uint16) { + assert(b <= a); + return a - b; + } + + function add(uint16 a, uint16 b) internal pure returns (uint16) { + uint16 c = a + b; + assert(c >= a); + return c; + } + } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { randNonce = randNonce.add(1); - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { diff --git a/pt/5/13-comments.md b/pt/5/13-comments.md index 47447ebc0e..53a5a3a195 100644 --- a/pt/5/13-comments.md +++ b/pt/5/13-comments.md @@ -7,7 +7,7 @@ material: language: sol startingCode: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; @@ -20,11 +20,11 @@ material: mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -32,36 +32,32 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; - contract ZombieBattle is ZombieHelper { + contract ZombieAttack is ZombieHelper { uint randNonce = 0; uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { - randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + randNonce = randNonce.add(1); + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -69,19 +65,19 @@ material: Zombie storage enemyZombie = zombies[_targetId]; uint rand = randMod(100); if (rand <= attackVictoryProbability) { - myZombie.winCount++; - myZombie.level++; - enemyZombie.lossCount++; + myZombie.winCount = myZombie.winCount.add(1); + myZombie.level = myZombie.level.add(1); + enemyZombie.lossCount = enemyZombie.lossCount.add(1); feedAndMultiply(_zombieId, enemyZombie.dna, "zombie"); } else { - myZombie.lossCount++; - enemyZombie.winCount++; + myZombie.lossCount = myZombie.lossCount.add(1); + enemyZombie.winCount = enemyZombie.winCount.add(1); _triggerCooldown(myZombie); } } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -95,7 +91,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -104,10 +101,10 @@ material: function levelUp(uint _zombieId) external payable { require(msg.value == levelUpFee); - zombies[_zombieId].level++; + zombies[_zombieId].level = zombies[_zombieId].level.add(1); } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -115,7 +112,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -129,7 +126,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -169,12 +166,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -188,7 +185,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -196,6 +193,8 @@ material: contract ZombieFactory is Ownable { using SafeMath for uint256; + using SafeMath32 for uint32; + using SafeMath16 for uint16; event NewZombie(uint zombieId, string name, uint dna); @@ -217,19 +216,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; - ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -238,47 +237,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -309,7 +344,7 @@ material: } /** - * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); @@ -325,19 +360,88 @@ material: return c; } } + + /** + * @title SafeMath32 + * @dev SafeMath library implemented for uint32 + */ + library SafeMath32 { + + function mul(uint32 a, uint32 b) internal pure returns (uint32) { + if (a == 0) { + return 0; + } + uint32 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint32 a, uint32 b) internal pure returns (uint32) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint32 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint32 a, uint32 b) internal pure returns (uint32) { + assert(b <= a); + return a - b; + } + + function add(uint32 a, uint32 b) internal pure returns (uint32) { + uint32 c = a + b; + assert(c >= a); + return c; + } + } + + /** + * @title SafeMath16 + * @dev SafeMath library implemented for uint16 + */ + library SafeMath16 { + + function mul(uint16 a, uint16 b) internal pure returns (uint16) { + if (a == 0) { + return 0; + } + uint16 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint16 a, uint16 b) internal pure returns (uint16) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint16 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint16 a, uint16 b) internal pure returns (uint16) { + assert(b <= a); + return a - b; + } + + function add(uint16 a, uint16 b) internal pure returns (uint16) { + uint16 c = a + b; + assert(c >= a); + return c; + } + } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; @@ -349,11 +453,11 @@ material: mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -361,23 +465,19 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); - } + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); + } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); - } + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); + } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } --- diff --git a/pt/6/00-overview.md b/pt/6/00-overview.md index efab2428d0..5ded4bf4f3 100644 --- a/pt/6/00-overview.md +++ b/pt/6/00-overview.md @@ -2,6 +2,8 @@ title: Aplicativos Front-end & Web3.js header: "Lição 6: Aplicativos Front-end & Web3.js" roadmap: roadmap6.png +path: solidity +publishedOn: Cryptozombies --- Huh, você chegou até aqui ?! diff --git a/pt/6/01-intro-web3.md b/pt/6/01.md similarity index 62% rename from pt/6/01-intro-web3.md rename to pt/6/01.md index 18f6628c70..4af098edaa 100644 --- a/pt/6/01-intro-web3.md +++ b/pt/6/01.md @@ -20,7 +20,7 @@ material: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; @@ -32,11 +32,11 @@ material: mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -44,26 +44,22 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); - } + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); + } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); - } + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); + } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; @@ -72,8 +68,8 @@ material: uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { - randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + randNonce = randNonce.add(1); + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -81,19 +77,19 @@ material: Zombie storage enemyZombie = zombies[_targetId]; uint rand = randMod(100); if (rand <= attackVictoryProbability) { - myZombie.winCount++; - myZombie.level++; - enemyZombie.lossCount++; + myZombie.winCount = myZombie.winCount.add(1); + myZombie.level = myZombie.level.add(1); + enemyZombie.lossCount = enemyZombie.lossCount.add(1); feedAndMultiply(_zombieId, enemyZombie.dna, "zombie"); } else { - myZombie.lossCount++; - enemyZombie.winCount++; + myZombie.lossCount = myZombie.lossCount.add(1); + enemyZombie.winCount = enemyZombie.winCount.add(1); _triggerCooldown(myZombie); } } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -107,7 +103,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -116,10 +113,10 @@ material: function levelUp(uint _zombieId) external payable { require(msg.value == levelUpFee); - zombies[_zombieId].level++; + zombies[_zombieId].level = zombies[_zombieId].level.add(1); } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -127,7 +124,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -141,7 +138,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -181,12 +178,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -200,7 +197,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -208,6 +205,8 @@ material: contract ZombieFactory is Ownable { using SafeMath for uint256; + using SafeMath32 for uint32; + using SafeMath16 for uint16; event NewZombie(uint zombieId, string name, uint dna); @@ -229,19 +228,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; - ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -250,47 +249,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -337,16 +372,85 @@ material: return c; } } + + /** + * @title SafeMath32 + * @dev SafeMath library implemented for uint32 + */ + library SafeMath32 { + + function mul(uint32 a, uint32 b) internal pure returns (uint32) { + if (a == 0) { + return 0; + } + uint32 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint32 a, uint32 b) internal pure returns (uint32) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint32 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint32 a, uint32 b) internal pure returns (uint32) { + assert(b <= a); + return a - b; + } + + function add(uint32 a, uint32 b) internal pure returns (uint32) { + uint32 c = a + b; + assert(c >= a); + return c; + } + } + + /** + * @title SafeMath16 + * @dev SafeMath library implemented for uint16 + */ + library SafeMath16 { + + function mul(uint16 a, uint16 b) internal pure returns (uint16) { + if (a == 0) { + return 0; + } + uint16 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint16 a, uint16 b) internal pure returns (uint16) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint16 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint16 a, uint16 b) internal pure returns (uint16) { + assert(b <= a); + return a - b; + } + + function add(uint16 a, uint16 b) internal pure returns (uint16) { + uint16 c = a + b; + assert(c >= a); + return c; + } + } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | @@ -398,7 +502,7 @@ Vamos explicar a sintaxe em detalhes nos próximos capítulos, mas primeiro vamo Dependendo do fluxo de trabalho do seu projeto, você pode adicionar Web3.js ao seu projeto usando as gerenciador de pacotes mais conhecidos: -``` +```plaintext // Usando NPM npm install web3 @@ -413,7 +517,7 @@ bower install web3 Ou você pode simplesmente baixar o arquivo `.js` minificado do github e incluir no seu projeto: -``` +```html ``` diff --git a/pt/6/02-web3-providers.md b/pt/6/02.md similarity index 64% rename from pt/6/02-web3-providers.md rename to pt/6/02.md index 41296076a4..42c1e6df12 100644 --- a/pt/6/02-web3-providers.md +++ b/pt/6/02.md @@ -18,12 +18,12 @@ material: "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; @@ -35,11 +35,11 @@ material: mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -47,26 +47,22 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); - } + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); + } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); - } + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); + } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; @@ -75,8 +71,8 @@ material: uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { - randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + randNonce = randNonce.add(1); + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -84,19 +80,19 @@ material: Zombie storage enemyZombie = zombies[_targetId]; uint rand = randMod(100); if (rand <= attackVictoryProbability) { - myZombie.winCount++; - myZombie.level++; - enemyZombie.lossCount++; + myZombie.winCount = myZombie.winCount.add(1); + myZombie.level = myZombie.level.add(1); + enemyZombie.lossCount = enemyZombie.lossCount.add(1); feedAndMultiply(_zombieId, enemyZombie.dna, "zombie"); } else { - myZombie.lossCount++; - enemyZombie.winCount++; + myZombie.lossCount = myZombie.lossCount.add(1); + enemyZombie.winCount = enemyZombie.winCount.add(1); _triggerCooldown(myZombie); } } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -110,7 +106,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -119,10 +116,10 @@ material: function levelUp(uint _zombieId) external payable { require(msg.value == levelUpFee); - zombies[_zombieId].level++; + zombies[_zombieId].level = zombies[_zombieId].level.add(1); } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -130,7 +127,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -144,7 +141,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -184,12 +181,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -203,7 +200,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -211,6 +208,8 @@ material: contract ZombieFactory is Ownable { using SafeMath for uint256; + using SafeMath32 for uint32; + using SafeMath16 for uint16; event NewZombie(uint zombieId, string name, uint dna); @@ -232,19 +231,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; - ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -253,47 +252,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -340,16 +375,85 @@ material: return c; } } + + /** + * @title SafeMath32 + * @dev SafeMath library implemented for uint32 + */ + library SafeMath32 { + + function mul(uint32 a, uint32 b) internal pure returns (uint32) { + if (a == 0) { + return 0; + } + uint32 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint32 a, uint32 b) internal pure returns (uint32) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint32 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint32 a, uint32 b) internal pure returns (uint32) { + assert(b <= a); + return a - b; + } + + function add(uint32 a, uint32 b) internal pure returns (uint32) { + uint32 c = a + b; + assert(c >= a); + return c; + } + } + + /** + * @title SafeMath16 + * @dev SafeMath library implemented for uint16 + */ + library SafeMath16 { + + function mul(uint16 a, uint16 b) internal pure returns (uint16) { + if (a == 0) { + return 0; + } + uint16 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint16 a, uint16 b) internal pure returns (uint16) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint16 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint16 a, uint16 b) internal pure returns (uint16) { + assert(b <= a); + return a - b; + } + + function add(uint16 a, uint16 b) internal pure returns (uint16) { + uint16 c = a + b; + assert(c >= a); + return c; + } + } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | @@ -365,20 +469,19 @@ material: @@ -391,7 +494,6 @@ A primeira coisa que precisamos é de um **_Web3 Provider_**. Lembre-se, o Ethereum é composto de **_nodes_** (nós) que compartilham uma cópia dos mesmos dados. Definir um provedor Web3 em Web3.js informa ao nosso código **em que nó** devemos falar para lidar com nossas leituras e escritas. É como definir a URL do servidor da Web remoto para suas chamadas de API em um aplicativo da web tradicional. Você poderia hospedar seu próprio nó Ethereum como um provedor. No entanto, há um serviço de terceiros que facilita a sua vida, para que você não precise manter seu próprio nó Ethereum para fornecer um DApp para seus usuários — **_Infura_**. - ## Infura Infura é um serviço que mantém um conjunto de nós do Ethereum com uma camada de cache para leituras rápidas, que você pode acessar gratuitamente por meio de sua API. Usando o Infura como um provedor, você pode enviar e receber mensagens de forma confiável de/para o blockchain Ethereum sem precisar configurar e manter seu próprio nó. @@ -416,7 +518,7 @@ Mas, felizmente, você não precisa — já existem serviços que lidam com isso E como desenvolvedor, se você quer que os usuários interajam com o seu DApp através de um site em seu navegador (como estamos fazendo com o nosso jogo CryptoZombies), você definitivamente vai querer torná-lo compatível com o Metamask. -> **Note**: O Metamask usa os servidores da Infura por baixo dos panos como um provedor web3, assim como fizemos acima — mas também dá ao usuário a opção de escolher seu próprio provedor web3. Então, usando o provedor web3 do Metamask, você está dando ao usuário uma opção, e é uma coisa a menos com a qual você precisa se preocupar em seu aplicativo. +> **Nota**: O Metamask usa os servidores da Infura por baixo dos panos como um provedor web3, assim como fizemos acima — mas também dá ao usuário a opção de escolher seu próprio provedor web3. Então, usando o provedor web3 do Metamask, você está dando ao usuário uma opção, e é uma coisa a menos com a qual você precisa se preocupar em seu aplicativo. ## Usando o web3 do Metamask's @@ -445,7 +547,7 @@ window.addEventListener('load', function() { Você pode usar esse código pronto em todos os aplicativos criados para exigir que os usuários tenham o Metamask para usar seu DApp. -> Note: Existem outros programas de gerenciamento de chaves privadas que seus usuários podem usar além da MetaMask, como o navegador da Web **Mist**. No entanto, todos eles implementam um padrão comum de injeção da variável `web3`, então o método que descrevemos aqui para detectar o provedor web3 do usuário também funcionará para eles. +> Nota: Existem outros programas de gerenciamento de chaves privadas que seus usuários podem usar além da MetaMask, como o navegador da Web **Mist**. No entanto, todos eles implementam um padrão comum de injeção da variável `web3`, então o método que descrevemos aqui para detectar o provedor web3 do usuário também funcionará para eles. ## Vamos testar diff --git a/pt/6/03-talking-to-contracts.md b/pt/6/03.md similarity index 74% rename from pt/6/03-talking-to-contracts.md rename to pt/6/03.md index 3b05d50b6b..467321cf9c 100644 --- a/pt/6/03-talking-to-contracts.md +++ b/pt/6/03.md @@ -28,9 +28,8 @@ material: // Use o provedor de Mist/MetaMask web3js = new Web3(web3.currentProvider); } else { - // Caso o usuário não tem web3. Provavelmente - // mostre a ele uma mensagem dizendo-lhe para instalar o Metamask - // afim de usar nosso aplicativo. + // Lidar com o caso em que o usuário não tem o Metamask instalado + // Provavelmente mostrar a eles uma mensagem solicitando a instalação do Metamask } // Agora você pode iniciar seu aplicativo e acessar o web3js livremente: @@ -46,7 +45,7 @@ material: "constant": false, "inputs": [ { - "name": "_to", + "name": "_approved", "type": "address" }, { @@ -56,8 +55,8 @@ material: ], "name": "approve", "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "payable": true, + "stateMutability": "payable", "type": "function" }, { @@ -221,7 +220,7 @@ material: "name": "ownerOf", "outputs": [ { - "name": "_owner", + "name": "", "type": "address" } ], @@ -240,7 +239,7 @@ material: "name": "balanceOf", "outputs": [ { - "name": "_balance", + "name": "", "type": "uint256" } ], @@ -279,6 +278,10 @@ material: { "constant": false, "inputs": [ + { + "name": "_from", + "type": "address" + }, { "name": "_to", "type": "address" @@ -288,10 +291,10 @@ material: "type": "uint256" } ], - "name": "transfer", + "name": "transferFrom", "outputs": [], - "payable": false, - "stateMutability": "nonpayable", + "payable": true, + "stateMutability": "payable", "type": "function" }, { @@ -308,21 +311,6 @@ material: "stateMutability": "view", "type": "function" }, - { - "constant": false, - "inputs": [ - { - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "takeOwnership", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { "constant": false, "inputs": [ { @@ -493,7 +481,7 @@ material: } ] "zombieownership.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombieattack.sol"; import "./erc721.sol"; @@ -505,11 +493,11 @@ material: mapping (uint => address) zombieApprovals; - function balanceOf(address _owner) public view returns (uint256 _balance) { + function balanceOf(address _owner) external view returns (uint256) { return ownerZombieCount[_owner]; } - function ownerOf(uint256 _tokenId) public view returns (address _owner) { + function ownerOf(uint256 _tokenId) external view returns (address) { return zombieToOwner[_tokenId]; } @@ -517,26 +505,22 @@ material: ownerZombieCount[_to] = ownerZombieCount[_to].add(1); ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); zombieToOwner[_tokenId] = _to; - Transfer(_from, _to, _tokenId); + emit Transfer(_from, _to, _tokenId); } - function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - _transfer(msg.sender, _to, _tokenId); - } + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); + _transfer(_from, _to, _tokenId); + } - function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) { - zombieApprovals[_tokenId] = _to; - Approval(msg.sender, _to, _tokenId); - } + function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { + zombieApprovals[_tokenId] = _approved; + emit Approval(msg.sender, _approved, _tokenId); + } - function takeOwnership(uint256 _tokenId) public { - require(zombieApprovals[_tokenId] == msg.sender); - address owner = ownerOf(_tokenId); - _transfer(owner, msg.sender, _tokenId); - } } "zombieattack.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiehelper.sol"; @@ -545,8 +529,8 @@ material: uint attackVictoryProbability = 70; function randMod(uint _modulus) internal returns(uint) { - randNonce++; - return uint(keccak256(now, msg.sender, randNonce)) % _modulus; + randNonce = randNonce.add(1); + return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; } function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { @@ -554,19 +538,19 @@ material: Zombie storage enemyZombie = zombies[_targetId]; uint rand = randMod(100); if (rand <= attackVictoryProbability) { - myZombie.winCount++; - myZombie.level++; - enemyZombie.lossCount++; + myZombie.winCount = myZombie.winCount.add(1); + myZombie.level = myZombie.level.add(1); + enemyZombie.lossCount = enemyZombie.lossCount.add(1); feedAndMultiply(_zombieId, enemyZombie.dna, "zombie"); } else { - myZombie.lossCount++; - enemyZombie.winCount++; + myZombie.lossCount = myZombie.lossCount.add(1); + enemyZombie.winCount = enemyZombie.winCount.add(1); _triggerCooldown(myZombie); } } } "zombiehelper.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefeeding.sol"; @@ -580,7 +564,8 @@ material: } function withdraw() external onlyOwner { - owner.transfer(this.balance); + address _owner = owner(); + _owner.transfer(address(this).balance); } function setLevelUpFee(uint _fee) external onlyOwner { @@ -589,10 +574,10 @@ material: function levelUp(uint _zombieId) external payable { require(msg.value == levelUpFee); - zombies[_zombieId].level++; + zombies[_zombieId].level = zombies[_zombieId].level.add(1); } - function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { + function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { zombies[_zombieId].name = _newName; } @@ -600,7 +585,7 @@ material: zombies[_zombieId].dna = _newDna; } - function getZombiesByOwner(address _owner) external view returns(uint[]) { + function getZombiesByOwner(address _owner) external view returns(uint[] memory) { uint[] memory result = new uint[](ownerZombieCount[_owner]); uint counter = 0; for (uint i = 0; i < zombies.length; i++) { @@ -614,7 +599,7 @@ material: } "zombiefeeding.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./zombiefactory.sol"; @@ -654,12 +639,12 @@ material: return (_zombie.readyTime <= now); } - function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) { + function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - if (keccak256(_species) == keccak256("kitty")) { + if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { newDna = newDna - newDna % 100 + 99; } _createZombie("NoName", newDna); @@ -673,7 +658,7 @@ material: } } "zombiefactory.sol": | - pragma solidity ^0.4.19; + pragma solidity >=0.5.0 <0.6.0; import "./ownable.sol"; import "./safemath.sol"; @@ -681,6 +666,8 @@ material: contract ZombieFactory is Ownable { using SafeMath for uint256; + using SafeMath32 for uint32; + using SafeMath16 for uint16; event NewZombie(uint zombieId, string name, uint dna); @@ -702,19 +689,19 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - function _createZombie(string _name, uint _dna) internal { + function _createZombie(string memory _name, uint _dna) internal { uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; - ownerZombieCount[msg.sender]++; - NewZombie(id, _name, _dna); + ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); + emit NewZombie(id, _name, _dna); } - function _generateRandomDna(string _str) private view returns (uint) { - uint rand = uint(keccak256(_str)); + function _generateRandomDna(string memory _str) private view returns (uint) { + uint rand = uint(keccak256(abi.encodePacked(_str))); return rand % dnaModulus; } - function createRandomZombie(string _name) public { + function createRandomZombie(string memory _name) public { require(ownerZombieCount[msg.sender] == 0); uint randDna = _generateRandomDna(_name); randDna = randDna - randDna % 100; @@ -723,47 +710,83 @@ material: } "ownable.sol": | + pragma solidity >=0.5.0 <0.6.0; + /** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ contract Ownable { - address public owner; + address private _owner; - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - function Ownable() public { - owner = msg.sender; + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() internal { + _owner = msg.sender; + emit OwnershipTransferred(address(0), _owner); } + /** + * @return the address of the owner. + */ + function owner() public view returns(address) { + return _owner; + } /** - * @dev Throws if called by any account other than the owner. - */ + * @dev Throws if called by any account other than the owner. + */ modifier onlyOwner() { - require(msg.sender == owner); + require(isOwner()); _; } + /** + * @return true if `msg.sender` is the owner of the contract. + */ + function isOwner() public view returns(bool) { + return msg.sender == _owner; + } /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. - */ + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ function transferOwnership(address newOwner) public onlyOwner { - require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); - owner = newOwner; + _transferOwnership(newOwner); } + /** + * @dev Transfers control of the contract to a newOwner. + * @param newOwner The address to transfer ownership to. + */ + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0)); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } } "safemath.sol": | - pragma solidity ^0.4.18; + pragma solidity >=0.5.0 <0.6.0; /** * @title SafeMath @@ -810,16 +833,85 @@ material: return c; } } + + /** + * @title SafeMath32 + * @dev SafeMath library implemented for uint32 + */ + library SafeMath32 { + + function mul(uint32 a, uint32 b) internal pure returns (uint32) { + if (a == 0) { + return 0; + } + uint32 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint32 a, uint32 b) internal pure returns (uint32) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint32 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint32 a, uint32 b) internal pure returns (uint32) { + assert(b <= a); + return a - b; + } + + function add(uint32 a, uint32 b) internal pure returns (uint32) { + uint32 c = a + b; + assert(c >= a); + return c; + } + } + + /** + * @title SafeMath16 + * @dev SafeMath library implemented for uint16 + */ + library SafeMath16 { + + function mul(uint16 a, uint16 b) internal pure returns (uint16) { + if (a == 0) { + return 0; + } + uint16 c = a * b; + assert(c / a == b); + return c; + } + + function div(uint16 a, uint16 b) internal pure returns (uint16) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + uint16 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint16 a, uint16 b) internal pure returns (uint16) { + assert(b <= a); + return a - b; + } + + function add(uint16 a, uint16 b) internal pure returns (uint16) { + uint16 c = a + b; + assert(c >= a); + return c; + } + } "erc721.sol": | + pragma solidity >=0.5.0 <0.6.0; + contract ERC721 { - event Transfer(address indexed _from, address indexed _to, uint256 _tokenId); - event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - function transfer(address _to, uint256 _tokenId) public; - function approve(address _to, uint256 _tokenId) public; - function takeOwnership(uint256 _tokenId) public; + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + function balanceOf(address _owner) external view returns (uint256); + function ownerOf(uint256 _tokenId) external view returns (address); + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + function approve(address _approved, uint256 _tokenId) external payable; } answer: | @@ -843,17 +935,16 @@ material: window.addEventListener('load', function() { - // Verificando se o Web3 foi injetado pelo navegador (Mist/MetaMask) + // Checking if Web3 has been injected by the browser (Mist/MetaMask) if (typeof web3 !== 'undefined') { - // Use o provedor de Mist/MetaMask + // Use Mist/MetaMask's provider web3js = new Web3(web3.currentProvider); } else { - // Caso o usuário não tem web3. Provavelmente - // mostre a ele uma mensagem dizendo-lhe para instalar o Metamask - // afim de usar nosso aplicativo. + // Handle the case where the user doesn't have Metamask installed + // Probably show them a message prompting them to install Metamask } - // Agora você pode iniciar seu aplicativo e acessar o web3js livremente: + // Now you can start your app & access web3 freely: startApp() }) @@ -892,7 +983,7 @@ Depois de ter o endereço do contrato e a ABI, você pode instanciá-lo no Web3 ``` // Instanciando myContract -var myContract = new web3js.eth.Contract (myABI, myContractAddress); +var myContract = new web3js.eth.Contract(myABI, myContractAddress); ``` ## Vamos testar @@ -901,7 +992,7 @@ var myContract = new web3js.eth.Contract (myABI, myContractAddress); 2. No início de nossa tag `