Blockchain Blog Sol

Blockopoly - parte 1

Neste tutorial Blockchain dividido em 3 partes você vai aprender passo por passo como criar o jogo Blockopoly, uma divertida variação do famoso jogo de tabuleiro 'Monopoly', ou 'Banco imobiliário', no Brasil. Este tutorial foi inspirado em uma excelente iniciativa da Microsoft Reactor. Esta é a parte 1.

Este é uma divertida variação de um famoso jogo de tabuleiro em que propriedades como bairros, casas, hotéis ou empresas são compradas e vendidas, em que uns jogadores ficam "ricos" e outros vão à falência. No Brasil é conhecido como 'Banco imobiliário', ou 'Monopoly' no mundo. A ideia principal do jogo mapeia muito bem os sistemas Blockchain e vamos construir partes do jogo para demonstrar isto.

O jogo Blockopoly foi inspirado em uma excelente iniciativa da Microsoft Reactor. Nossas propriedades são os espaços Reactors espalhados pelo mundo:

reactors map

Nestes espaços é possível experimentar tecnologias líderes da indústria na Microsoft, parceiros e comunidades de código aberto, enquanto os profissionais da área se encontram, aprendem e criam conexões.

O tutorial está dividido em 3 partes.

Overview do tutorial

Aqui está um resumo das etapas que faremos neste tutorial (nas 3 partes):

  1. Pré requisitos;
  2. Arquitetura do jogo;
  3. Para cada smart contract, vamos:

    1. Criar o arquivo Solidity;
    2. Compilar;
    3. Publicar;
    4. Interagir com ele.
  4. Vamos jogar!

    1. Publicação do jogo;
    2. Entrada dos jogadores;
    3. Início do jogo;
    4. Saldos dos jogadores;
    5. Propriedades disponíveis;
    6. Comprando uma propriedade;
    7. Término do jogo;
    8. Ganhador.
  5. Próximos passos - upgrades;
  6. Publicando em Blockchain;
  7. Considerações finais.

Pré-requisitos

  1. Node.js e NPM (Node Package Manager)
  2. Visual Studio Code (VSCode)
  3. Truffle

Node.js e NPM

Uma das dependências é NPM, que é instalado com Node.js.

Pra verificar se Node.js e NPM já estão instalados, utilize os comandos abaixo no terminal:

node --version
npm --version

node and npm version

Se não estiverem instalados, erros serão apresentados. Vá em Node.js caso precise instalá-los.

Caso queira ter mais de uma versão do node instalada, utilize o gerenciador de versões para o node, chamado nvm.

Editor para código-fonte

Precisamos de algum editor de código, de preferência um que destaque as linguagens Solidity e Javascript.

VS Code é uma boa escolha.

Para instalar, faça o download.

Após a instalação do VS code, verifique se está ok consultando sua versão no terminal:

code -v

vscode version

Truffle

Truffle é um conhecido framework para desenvolvimento de smart contracts, que facilita a vida do desenvolvedor. Entre suas características, podemos citar o gerenciamento da "vida" de um smart contract (você pode fazer várias publicações e saber qual foi a última), desenvolvimento de scripts para deploy, testes automatizados e gerenciamento de rede simplificado.

Da mesma forma também facilita o desenvolvedor RSK porque podemos configurar as redes RSK no Truffle.

Para instalar Truffle, no terminal, digite o comando abaixo no terminal e pressione a tecla enter:

npm install -g truffle

truffle install

Quando a instalação finalizar, feche a janela do terminal e abra novamente para verificar a versão do Truffle:

truffle version

truffle version

Inicialize um projeto Truffle

Crie um novo diretório, por exemplo blockopoly, e navegue até ele no terminal.

mkdir blockopoly
cd blockopoly

Por exemplo, eu vou criar em C:\ETH\ (Estou utilizando Windows).

Meu projeto estará localizado no diretório C:\ETH\blockopoly.

blockopoly folder

Na pasta blockopoly, inicialize um projeto Truffle:

truffle init

truffle init

Abra a pasta no VSCode.

code .

Você verá uma estrutura de diretórios como esta:

truffle file structure

  • ./contracts: Todos os smart contracts serão salvos nesta pasta.
  • ./migrations: Os scripts para publicação ficarão armazenados aqui.
  • ./test: Aqui serão salvos os scripts para testes.
  • ./truffle-config.js: Este é o arquivo de configuração do Truffle. Aqui vamos configurar as redes, incluindo RSK.

Veja que os seguintes arquivos também foram criados:

  • Migrations.sol: Smart contract que registra todos as publicações realizadas em uma rede.
  • 1_initial_migration.js: Publicação do Migrations.sol.

Inicialize um projeto npm

Quando inicializamos um projeto Truffle a partir do template, também precisamos inicializar um projeto npm.

Podemos fazer isto diretamente no terminal do VS Code. Vá no menu Terminal e selecione New Terminal.

VS Code New Terminal

Para inicializar um projeto npm na pasta blockopoly, execute o comando abaixo no terminal:

npm init -y

npm init

Este comando cria um arquivo de configurações chamado package.json.

package.json

Truffle development console

Truffle possui um console interativo que inclui um blockchain de desenvolvimento. Isso é muito útil para compilar, publicar e testar localmente.

Execute o console de desenvolvimento digitando o seguinte comando no terminal do VS Code:

truffle develop

O comando foi executado com sucesso se você visualizar uma lista de 10 contas / endereços, uma lista com as 10 chaves privadas correspondentes, um mnemônico e o prompt de comando mudar para truffle(develop)>

truffle develop

Os comando Truffle podem ser executados dentro ou fora do console de desenvolvimento.

Se estamos no console de desenvolvimento Truffle, não precisamos iniciar os comandos com truffle.

Por exemplo, se fora do console utilizamos truffle test, dentro do console usamos apenas test.

Quando quiser sair do Truffle console, digite:

.exit

O jogo

Nosso jogo é composto por 3 smart contracts:

  • Bank
  • AssetManager
  • Blockopoly

Bank

O banco é a entidade que controla o dinheiro, tanto a emissão dele quanto as transferências e os saldos de cada um.

Asset Manager

É um gerenciador de ativos, no nosso caso é o administrador das propriedades que serão negociadas.

Blockopoly

Este é o smart contract principal do jogo. Através dele são definidos jogadores, propriedades negociadas, início, final do jogo e o ganhador.

Então vamos lá!

Chegou o momento de criar e interagir com cada um deles.

Bank

Neste smart contract estarão as regras da entidade que controla o dinheiro, tanto a emissão dele quanto as transferências, além dos saldos de cada um.

Crie o smart contract Bank

Na pasta contracts, crie um novo arquivo chamado Bank.sol.

create Bank.sol

Copie o código fonte:

pragma solidity >=0.5.0 <0.7.0;

contract Bank {
    // The keyword "public" makes variables
    // accessible from other contracts
    address public minter;
    mapping (address => uint) private balances;

    // Events allow clients to react to specific
    // contract changes you declare
    event Sent(address from, address to, uint amount);

    // Constructor code is only run when the contract
    // is created
    constructor() public {
        minter = msg.sender;
    }

    // Sends an amount of newly created coins to an address
    // Can only be called by the contract creator
    function mint(address receiver, uint amount) public {
        require(msg.sender == minter, "Sender is not minter");
        require((amount < 1e60), "Amount isn't too big");

        balances[receiver] += amount;
    }

    // Sends an amount of existing coins
    // from any caller to an address
    function sendMoney(address receiver, address sender, uint amount) public {
        require(msg.sender == minter, "Only the banker can authorize transfers");
        require(amount <= balances[sender], "Insufficient balance.");
        balances[sender] -= amount;
        balances[receiver] += amount;
        emit Sent(sender, receiver, amount);
    }

    function getBalance(address account) public view returns (uint) {
        require(msg.sender == account || msg.sender == minter,
           "You cannot get a balance on someone else's account");
        return balances[account];
    }
}

E cole aqui:

VScode Bank.sol

Salve o arquivo.

Bank.sol

Este smart contract contém:

Variáveis

  • Uma variável pública minter para saber quem é o banqueiro, o emissor de dinheiro.
  • Um mapping (variável do tipo chave -> valor) chamada balances, privada, que armazena o saldo de cada endereço.

Eventos

  • Um evento Sent que avisa cada vez que alguém envia dinheiro para outra pessoa.

Construtor

O constructor (construtor), executado apenas no momento da criação do banco, define quem é o minter.

Funções

  • Uma função mint que faz a emissão de dinheiro.
  • Uma função sendMoney para enviar dinheiro de um endereço para outro.
  • Uma função getBalance que retorna o saldo de um determinado endereço.

Compile o smart contract

No Truffle development console, digite:

compile

Veja o resultado com a mensagem Compiled successfully:

Compile Bank.sol

Publique o smart contract

Primeiro precisamos criar um novo arquivo com instruções para publicação. Ao encontrá-lo, Truffle vai processá-lo no momento do deploy.

Crie o arquivo 2deploycontracts.js

O diretório migrations contém arquivos JavaScript para a publicação dos contratos na rede. Estes arquivos são responsáveis por preparar suas tarefas de publicação e são escritos pensado que sua publicação pode ser alterada com o tempo. O histórico das migrações executadas anteriormente é gravado no Blockchain a partir do smart contract Migrations. Fonte: truffle: running-migrations

Usualmente começamos o nome do arquivo com um número, dado que o Truffle faz o deploy dos arquivos em ordem alfabética e desta forma definimos a ordem de publicação dos smart contracts.

Na pasta migrations, crie o arquivo 2_deploy_contracts.js

Copie e cole:

var Bank = artifacts.require("Bank");

module.exports = function(deployer) {
  deployer.deploy(Bank);
};

Ficará desta forma:

2_deploy_contracts.js

Migrate

No Truffle development console, execute este comando:

migrate

Como este é um simulador, rapidamente as transações da publicação do smart contract são gravadas no Blockchain, não há necessidade de esperar para validação e inclusão da transação em um bloco.

Se for necessário, o comando migrate vai compilar os smart contracts novamente.

truffle migrate

Primeiro é executada a publicação do smart contract Migrations.sol, que foi gerado pelo Truffle:

deploy Migrations.sol

E depois faz publicação do nosso smart contract Bank.sol:

deploy Bank.sol

Interagindo com o smart contract

Vamos interagir com nosso Bank através do Truffle console.

Suas contas / endereços

No Truffle console:

const accounts = await web3.eth.getAccounts()

Para listar todas as contas depois:

accounts

Para olhar uma conta, por exemplo, a primeira da lista, accounts[0]:

accounts[0]

Accounts

Faça a conexão com seu Bank

Vamos atribuir a variável bank a instância do smart contract Bank já publicado:

const bank = await Bank.deployed()

Verifique se a instância está OK.

Escreva o nome da variável: bank, tecle . e depois aperte a tecla TAB duas vezes para acionar o recurso autocompletar. Será apresentado o endereço e hash da transação na publicação, além de outras coisas, incluindo todas as váriaveis e métodos públicos disponíveis.

bank. [TAB] [TAB]

bank tab tab

Emissor

No Truffle console:

bank.minter()

Perceba que o emissor é a conta que fez a publicação do smart contract. Dado que nenhuma conta foi especificada no arquivo 2_deploy_contracts.js, é utilizada como default a primeira conta da lista, que é a accounts[0]

minter

Saldos

Para consultar o saldo de uma conta, utilize a função getBalance passando como parâmetro a conta a ser consultada:

Por exemplo, vou consultar o saldo da accounts[0], que é 0x1056F747cf4bC7710E178B2aeED4Eb8c8506c728:

(await bank.getBalance(accounts[0])).toString()

getBalance account 0

O saldo é zero! Então vamos ao próximo passo para emitir moedas.

Emissão de moedas

Apenas a conta do emissor (minter) pode emitir moedas. Emitirei 1000 moedas para ela mesma.

Passe como parâmetros a conta que receberá as moedas, e a quantidade:

bank.mint(accounts[0], 1000, {from: accounts[0]})

Perceba que existe um parâmetro a mais do que o especificado na definição da função. São as informações de quem está enviando a transação, que, no nosso caso, também é accounts[0], dado que ela é a conta emissora.

Foi enviada uma transação para a emissão de 100,00 tokens para a conta 0.

Você pode acompanhar os detalhes da transação no terminal:

mint transaction

Verifique o saldo novamente

Após a emissão de moedas, vou consultar novamente o saldo da accounts[0], mas agora vamos especificar o endereço, ao invés de usar a posição na lista:

(await bank.getBalance("0x1056F747cf4bC7710E178B2aeED4Eb8c8506c728")).toString()

getBalance again

Que maravilha! Agora temos 1000 moedas.

Somente o dono do banco ou a própria conta consegue consultar seu saldo!

Envie dinheiro

A conta accounts[0] vai enviar 300 moedas para a segunda conta da lista, accounts[1]:

0x45a71c00382C2898b5d6Fae69A6F7bfE6EDAB80C

Apenas o banqueiro tem autorização para enviar dinheiro de uma conta para outra.

let transaction = await bank.sendMoney(accounts[1], accounts[0], 300, {from: accounts[0]})

Guardamos os detalhes da transação na variável transaction.

Veja os detalhes:

transaction

sendMoney

Evento Sent

Veja a parte de logs da transação sendMoney. Você encontrará o evento Sent, com os detalhes da transferência de moedas:

  • '0': From - quem enviou
  • '1': To - destinatário
  • '2': Amount - quantidade
transaction.logs

event sent

Amount está representado como BN, que é o tipo BigNumber. '12c' é o número hexadecimal, que corresponde a 300.

Saldos após a transferência

Consulte os saldos das contas novamente.

(await bank.getBalance(accounts[0])).toString()

(await bank.getBalance(accounts[1])).toString()

A conta accounts[1] agora tem 300 moedas.

O valor foi subtraído no saldo da conta accounts[0], que tem 700 moedas neste momento.

getBalance accounts

Próximos passos

Nesta parte do tutorial do jogo Blockopoly foi ensinado como criar o smart contract Bank, utilizando a linguagem Solidity. Ele controla o dinheiro, os saldos de cada um, a emissão e as transferências entre contas.

Lembre-se que nosso jogo é composto de 3 smart contracts:

  • Bank
  • AssetManager
  • Blockopoly

Na próxima parte do tutorial continuaremos com o gerenciador de ativos, o smart contract AssetManager, que é o administrador das propriedades que serão negociadas.

Continue em Blockopoly - parte 2.

Esta versão do jogo Blockopoly foi inspirada em uma excelente iniciativa da Microsoft Reactor e o código original encontra-se no Github Reactors, sob licença MIT.

Aguarde um vídeo sobre o assunto em meu canal: youtube Solange Gueiros. Se quiser ser avisado quando a publicação acontecer, é só assinar o canal.

Espero que esse tutorial tenha sido útil e agradeço caso tenha algum feedback. Compartilhe o artigo caso tenha gostado :)

© 2020, Solange Gueiros