Esse é o segundo post da série Meu primeiro smart contract, que tem a intenção de ensinar ao longo de sete semanas alguns conceitos do solidity até construirmos um token baseado no ERC-20 com alguns testes unitários.
Nesse post vamos criar um contrato básico de um banco, onde você vai conseguir depositar uma quantidade de "dinheiro" e mudar o dono do contrato.
Ferramentas
Vamos continuar usando Remix IDE para criação dos nossos contratos.
Criando um novo arquivo
Vamos criar um novo arquivo dentro da pasta contracts
chamado 01-bank.sol
Dentro do arquivo 01-bank.sol
, vamos declarar as licenças do nosso contrato, a versão do solidity e dar um nome para o contrato.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Bank {
}
Organização do código
Não existe uma forma certa de estruturar o código dos nossos contratos, mas para facilitar o entendimento vamos utilizar o seguinte padrão:
- Properties: Onde definimos nossas variáveis;
- Modifiers: Onde definimos nossos modificadores, (nesse post vamos entender para que serve);
- Events: Onde definimos nossos eventos, (nesse post vamos entender como funciona);
- Constructor: Onde definimos nosso construtor;
- Public Functions: Onde definimos nossas funções públicas;
Variáveis
Vamos começar criando uma a variável privada chamada owner
que vai ser do tipo address
, e uma variável pública chamada addressToBalance
que vai ser do tipo mapping
, essa variável recebe um address
como chave e armazena um uint
como valor.
O mapping
é usado para armazenar dados na forma de pares chave-valor, a chave pode ser qualquer um dos tipos de dados do solidity. mapping
parece muito com um objeto, onde você pode criar uma chave e definir um valor para ele.
//Properties
address private owner;
mapping(address => uint) public addressToBalance;
Caso queira entender um pouco mais sobre os tipos de dados que exite no solidity clique aqui
Modificadores
O modifier
é usado para modificar o comportamento de uma função.
Por exemplo, vamos criar um modifier
chamado isOwner
que dentro dele vai ter um require
, que basicamente vai exigir que o msg.sender
(já vamos ver o que é isso) seja igual o endereço do dono do contrato (owner).
//Modifiers
modifier isOwner() {
require(msg.sender == owner , "Sender is not owner!");
_; // {1}
}
Na linha {1} se a instrução
require
retornar um true então será executado o código_;
que significa: execute o que vem depois.
Isso quer dizer que se o código quebrar no require não irá executar a instrução, logo, não irá executar o código da função que vem depois.
Eventos
Agora vamos criar os eventos BalanceIncreased
passando como
parâmetros target
que vai ser do tipo address
e balance
que vai ser do tipo uint256
, que vai ser chamado quando depositamos uma quantidade de "dinheiro" para um endereço.
E no OwnerChanged
vamos passar como parâmetros oldOwner
que vai ser do tipo address
e newOwner
que também vai ser do tipo address
, que vai ser chamado quando mudarmos o dono do nosso contrato.
Quando um event
é emitido ele armazena os argumentos passados e realiza uma ação.
Um evento gerado não é acessível dentro dos contratos, nem mesmo aqueles que os criou ou chamou. Os eventos no solidity servem para enviarmos alguma resposta para o nosso front-end, por exemplo depois que acontecer alguma ação no contrato.
//Events
event BalanceIncreased(address target, uint256 balance);
event OwnerChanged(address oldOwner, address newOwner);
Construtor
Vamos agora criar o nosso construtor, que vai definir que o owner
vai receber o msg.sender
, resumidamente o msg.sender
é sempre o endereço de quem chamou a função. Nesse caso estamos definindo que quem fez o deploy do contrato vai ser o owner
do contrato.
Caso queira entender um pouco mais sobre
msg.sender
clique aqui
//Constructor
constructor() {
owner = msg.sender;
}
Funções
Adicionar saldo à um endereço
Vamos criar uma função pública chamada addBalance
que vai nos permitir adicionar uma quantia de "dinheiro" há uma conta. Para conseguirmos fazer isso addBalance
irá ter alguns parâmetros como to
que vai ser do tipo address
e value
que vai ser do tipo uint
.
//Public functions
function addBalance(address to, uint value) public {
}
E por questão de segurança queremos que somente o dono (owner) do contrato possa adicionar "dinheiro" há um endereço. Para isso vamos colocar na frente da nossa função o nosso modificador isOwner
, assim antes de executar nossa função ele vai executar o nosso modificador isOwner
e verificar se quem está chamando a função é o owner
, se não for vai retornar uma mensagem de erro.
//Public functions
function addBalance(address to, uint value) public isOwner {
}
Dentro da nossa função addBalance
vamos escrever a lógica para adicionar uma quantidade de "dinheiro" há uma conta.
Usando o nosso mapping addressToBalance
vamos pegar a quantidade de "dinheiro" do endereço do parâmetro to
e adicionamos uma quantidade de "dinheiro" que vamos passar no parâmetro value
, depois vamos chamar o evento BalanceIncreased
passando como parâmetros o endereço (to
) e a quantidade (value
) de "dinheiro" que queremos enviar.
//Public functions
function addBalance(address to, uint value) public isOwner {
addressToBalance[address(to)] = addressToBalance[address(to)] + value;
emit BalanceIncreased(to, value);
}
Alterando dono do contrato
As regras da nossa função para trocar o dono do contrato é bem parecida com a da função addBalance
.
Vamos criar uma função pública chamada changeOwner
que somente o dono do contrato (owner
) vai conseguir chamar essa função, que seja possível passar um endereço (newOwnerContract
) como parâmetro.
function changeOwner(address newOwnerContract) public isOwner{
}
Dentro da nossa função changeOwner
vamos redefinir o valor da variável owner
para o endereço do novo dono (newOwnerContract
), e chamar nosso evento OwnerChanged
passando o endereço do atual dono (owner
) do contrato e o endereço do novo dono (newOwnerContract
) como parâmetros.
function changeOwner(address newOwnerContract) public isOwner{
owner = newOwnerContract;
emit OwnerChanged(owner, newOwnerContract);
}
Como ficou nosso código
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Bank {
//Properties
address private owner;
mapping(address => uint) public addressToBalance;
//Modifiers
modifier isOwner() {
require(msg.sender == owner , "Sender is not owner!");
_;
}
//Events
event BalanceIncreased(address target, uint256 balance);
event OwnerChanged(address oldOwner, address newOwner);
//Constructor
constructor() {
owner = msg.sender;
}
//Public functions
function addBalance(address to, uint value) public isOwner {
addressToBalance[address(to)] = addressToBalance[address(to)] + value;
emit BalanceIncreased(to, value);
}
function changeOwner(address newOwnerContract) public isOwner{
owner = newOwnerContract;
emit OwnerChanged(owner, newOwnerContract);
}
}
Mão na massa
Agora vamos compilar e realizar o deploy do nosso contrato 01-bank.sol
.
No menu lateral esquerdo clique em "Deploy & run transactions".
Clique em "addressToBalance" para verificar o salto do endereço que passamos.
Informe o endereço da nossa carteira no primeiro campo e informe a quantidade de "dinheiro" que quer depositar.
Clique em "addressToBalance" para verificar o salto do endereço após o depósito do "dinheiro".
Podemos ver que o saldo do nosso endereço tem a mesma quantidade de "dinheiro" que passamos na função addBalance.
Agora vamos pegar o endereço de outra carteira, para isso só clica em cima do endereço que irá aparecer uma lista de endereços.
Agora vamos voltar para o endereço da primeira carteira, e informe o endereço da carteira do owner (a carteira que utilizamos para fazer o deploy) e clique na função "changeOwner".
Se tudo estiver certo quando clicarmos para executar novamente a função "changeOwner" vai dar um erro no console.
Conclusão
Esse foi o segundo post da série de posts "Meu primeiro smart contract".
Se você realizou todas as etapas acima, agora você tem um smart contract simples de um banco, onde você consegue depositar uma quantia de "dinheiro" e mudar o dono do contrato.
Se você gostou do conteúdo e te ajudou de alguma forma, deixe um like para ajudar o conteúdo a chegar para mais pessoas.
Link do repositório
https://github.com/viniblack/meu-primeiro-smart-contract
Vamos trocar uma ideia ?
Fique a vontade para me chamar para trocarmos uma ideia, aqui embaixo está meu contato.
Latest comments (1)
Legal também mencionar que colocando o primeiro endereço (do owner original que criou o contrato) a função changeOwner funciona.. ;)