Anatomia dos contratos inteligentes
Última atualização da página: 23 de fevereiro de 2026
Um contrato inteligente (smart contract) é um programa executado em um endereço na Ethereum. Eles são compostos por dados e funções que podem ser executadas ao receber uma transação. Veja aqui uma visão geral do que compõe um contrato inteligente.
Pré-requisitos
Certifique-se de que leu sobre contratos inteligentes primeiro. Este documento presume que você já está familiarizado com linguagens de programação como JavaScript ou Python.
Dados
Quaisquer dados de contrato devem ser atribuídos a um local: storage ou memory. É caro modificar o armazenamento em um contrato inteligente, então você precisa considerar onde seus dados devem estar no ar.
Armazenamento
Dados persistentes são referidos como armazenamento e são representados por variáveis de estado. Esses valores são armazenados permanentemente na blockchain. É necessário declarar o tipo para que o contrato possa manter um registro de quanto espaço na blockchain será necessário quando ele compilar.
1// Exemplo de Solidity2contract SimpleStorage {3 uint storedData; // Variável de estado4 // ...5}1# Exemplo Vyper2storedData: int128Se você já programou linguagens orientadas a objetos, provavelmente você estará familiarizado com a maioria dos tipos. No entanto, address (endereço) deve ser novidade para você se você é novo no desenvolvimento para Ethereum.
Um tipo address pode conter um endereço Ethereum que equivale a 20 bytes ou 160 bits. Ele retorna em hexadecimal com um 0 à frente.
Outros tipos incluem:
- booleano
- inteiro
- números de ponto fixo
- arrays de bytes de tamanho fixo
- arrays de bytes de tamanho dinâmico
- literais racionais e inteiros
- literais de string
- literais hexadecimais
- enums
Para mais explicação, dê uma olhada na documentação:
Memória
Valores que são armazenados apenas para a duração da execução da função de contratos são chamadas de variáveis de memória. Como estes não são armazenados permanentemente na blockchain, são muito mais baratos de usar.
Saiba mais sobre como a EVM armazena dados (Storage, Memory e a Pilha) nos documentos do Solidity (opens in a new tab).
Variáveis de ambiente
Além das variáveis definidas no seu contrato, existem algumas variáveis globais especiais. Elas são usadas principalmente para fornecer informações sobre a blockchain (cadeia de blocos) ou transação atual.
Exemplos:
| Propriedade | Variável de estado | Descrição |
|---|---|---|
block.timestamp | uint256 | Data/hora de início do bloco atual |
msg.sender | endereço | Remetente da mensagem (chamada atual) |
Funções
Da forma mais simplista, funções podem obter informação ou um conjunto de informações em resposta a entrada de transações.
Existem dois tipos de chamadas de função:
internal– estas não criam uma chamada de EVM- As funções e variáveis de estado internas só podem ser acessadas internamente (ou seja, de dentro do contrato atual ou dos contratos que derivam dele)
external– estas criam uma chamada de EVM- Funções externas fazem parte da interface do contrato, o que significa que elas podem ser chamadas a partir de outros contratos e através de transações. Uma função externa
fnão pode ser chamada internamente (ou seja,f()não funciona, masthis.f()funciona).
- Funções externas fazem parte da interface do contrato, o que significa que elas podem ser chamadas a partir de outros contratos e através de transações. Uma função externa
Elas também podem ser public ou private
- As funções
publicpodem ser chamadas internamente de dentro do contrato ou externamente por meio de mensagens - As funções
privatesão visíveis apenas para o contrato em que são definidas e não em contratos derivados
Tanto funções quanto variáveis de estado podem ser tornadas públicas ou privadas
Aqui está uma função para atualizar uma variável de estado em um contrato:
1// Exemplo de Solidity2function update_name(string value) public {3 dapp_name = value;4}- O parâmetro
valuedo tipostringé passado para a função:update_name - Ela é declarada como
public, o que significa que qualquer pessoa pode acessá-la - Ela não é declarada como
view, portanto, pode modificar o estado do contrato
Funções de visualização
Essas funções prometem não modificar o estado dos dados do contrato. Exemplos comuns são funções "obter" – você pode usar isso para receber o saldo de um usuário, por exemplo.
1// Exemplo2function balanceOf(address _owner) public view return (uint256 _balance) {3 return ownerPizzaCount[_owner];4}1dappName: public(string)23@view4@public5def readName() -> string:6 return dappNameO que é considerado como modificar estado:
- Escrevendo variáveis de estado.
- Emitindo eventos (opens in a new tab).
- Criando outros contratos (opens in a new tab).
- Usando
selfdestruct. - Enviando ether por chamadas.
- Chamando qualquer função não marcada como
viewoupure. - Usando chamadas de baixo nível.
- Usando montagem em linha que contém certos códigos.
Funções de construtor
As funções constructor são executadas apenas uma vez quando o contrato é implantado pela primeira vez. Assim como o constructor em muitas linguagens de programação baseadas em classes, essas funções geralmente inicializam variáveis de estado para seus valores especificados.
1// Exemplo de Solidity2// Inicializa os dados do contrato, definindo o `owner`3// para o endereço do criador do contrato.4constructor() public {5 // Todos os contratos inteligentes dependem de transações externas para acionar suas funções.6 // `msg` é uma variável global que inclui dados relevantes sobre a transação em questão,7 // como o endereço do remetente e o valor de ETH incluído na transação.8 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties9 owner = msg.sender;10}Exibir tudo1# Exemplo Vyper23@external4def __init__(_beneficiary: endereço, _bidding_time: uint256):5 mesmo. eneficiário = _beneficiário6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeFunções incorporadas
Além das variáveis definidas no seu contrato, existem algumas variáveis globais especiais. O exemplo mais óbvio é:
address.send()– Soliditysend(address)– Vyper
Estes permitem contratos para enviar ETH para outras contas.
Escrevendo funções
Sua função precisa:
- variável e tipo de parâmetro (se aceitar parâmetros)
- declaração de interno/externo
- declaração de puro/visualização/pagável
- tipo de retorno (se ele retornar um valor)
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // variável de estado56 // Chamado quando o contrato é implantado e inicializa o valor7 constructor() public {8 dapp_name = "Meu dapp de Exemplo";9 }1011 // Função Get12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // Função Set17 function update_name(string value) public {18 dapp_name = value;19 }20}Exibir tudoUm contrato completo pode parecer algo assim. Aqui, a função constructor fornece um valor inicial para a variável dapp_name.
Eventos e logs
Os eventos permitem que seu contrato inteligente se comunique com seu front-end ou outros aplicativos que se inscrevem para recebê-los. Uma vez que uma transação é validada e adicionada a um bloco, os contratos inteligentes podem emitir eventos e registrar informações, que o front-end pode processar e utilizar.
Exemplos anotados
Estes são alguns exemplos escritos em Solidity. Se você quiser brincar com o código, pode interagir com eles no Remix (opens in a new tab).
Olá, mundo
1// Especifica a versão do Solidity, usando versionamento semântico.2// Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity ^0.5.10;45// Define um contrato chamado `HelloWorld`.6// Um contrato é um conjunto de funções e dados (seu estado).7// Uma vez implantado, um contrato reside em um endereço específico na blockchain Ethereum.8// Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // Declara uma variável de estado `message` do tipo `string`.12 // Variáveis de estado são variáveis cujos valores são armazenados permanentemente no armazenamento do contrato.13 // A palavra-chave `public` torna as variáveis acessíveis de fora de um contrato14 // e cria uma função que outros contratos ou clientes podem chamar para acessar o valor.15 string public message;1617 // Semelhante a muitas linguagens de programação orientadas a objetos baseadas em classes, um construtor é18 // uma função especial que é executada apenas na criação do contrato.19 // Construtores são usados para inicializar os dados do contrato.20 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // Aceita um argumento de string `initMessage` e define o valor23 // na variável de armazenamento `message` do contrato).24 message = initMessage;25 }2627 // Uma função pública que aceita um argumento de string28 // e atualiza a variável de armazenamento `message`.29 function update(string memory newMessage) public {30 message = newMessage;31 }32}Exibir tudoToken
1pragma solidity ^0.5.10;23contract Token {4 // Um `address` é comparável a um endereço de e-mail - ele é usado para identificar uma conta na Ethereum.5 // Endereços podem representar um contrato inteligente ou contas externas (de usuário).6 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // Um `mapping` é essencialmente uma estrutura de dados de tabela de hash.10 // Este `mapping` atribui um inteiro sem sinal (o saldo do token) a um endereço (o detentor do token).11 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // Eventos permitem o registro de atividades na blockchain.15 // Clientes Ethereum podem ouvir eventos para reagir a mudanças de estado do contrato.16 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // Inicializa os dados do contrato, definindo o `owner`20 // para o endereço do criador do contrato.21 constructor() public {22 // Todos os contratos inteligentes dependem de transações externas para acionar suas funções.23 // `msg` é uma variável global que inclui dados relevantes sobre a transação em questão,24 // como o endereço do remetente e o valor de ETH incluído na transação.25 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties26 owner = msg.sender;27 }2829 // Cria uma quantidade de novos tokens e os envia para um endereço.30 function mint(address receiver, uint amount) public {31 // `require` é uma estrutura de controle usada para impor certas condições.32 // Se uma instrução `require` for avaliada como `false`, uma exceção é acionada,33 // que reverte todas as alterações feitas no estado durante a chamada atual.34 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions3536 // Somente o proprietário do contrato pode chamar esta função37 require(msg.sender == owner, "Você não é o proprietário.");3839 // Impõe uma quantidade máxima de tokens40 require(amount < 1e60, "Emissão máxima excedida");4142 // Aumenta o saldo de `receiver` em `amount`43 balances[receiver] += amount;44 }4546 // Envia uma quantidade de tokens existentes de qualquer chamador para um endereço.47 function transfer(address receiver, uint amount) public {48 // O remetente deve ter tokens suficientes para enviar49 require(amount <= balances[msg.sender], "Saldo insuficiente.");5051 // Ajusta os saldos de token dos dois endereços52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // Emite o evento definido anteriormente56 emit Transfer(msg.sender, receiver, amount);57 }58}Exibir tudoAtivo digital exclusivo
1pragma solidity ^0.5.10;23// Importa símbolos de outros arquivos para o contrato atual.4// Neste caso, uma série de contratos de ajuda da OpenZeppelin.5// Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files67import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";1112// A palavra-chave `is` é usada para herdar funções e palavras-chave de contratos externos.13// Neste caso, `CryptoPizza` herda dos contratos `IERC721` e `ERC165`.14// Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // Usa a biblioteca SafeMath do OpenZeppelin para realizar operações aritméticas com segurança.17 // Saiba mais: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // Variáveis de estado constantes em Solidity são semelhantes a outras linguagens21 // mas você deve atribuir a partir de uma expressão que é constante em tempo de compilação.22 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // Tipos de estrutura permitem que você defina seu próprio tipo28 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // Cria uma matriz vazia de estruturas Pizza35 Pizza[] public pizzas;3637 // Mapeamento do ID da pizza para o endereço do seu proprietário38 mapping(uint256 => address) public pizzaToOwner;3940 // Mapeamento do endereço do proprietário para o número de tokens possuídos41 mapping(address => uint256) public ownerPizzaCount;4243 // Mapeamento do ID do token para o endereço aprovado44 mapping(uint256 => address) pizzaApprovals;4546 // Você pode aninhar mapeamentos, este exemplo mapeia o proprietário para as aprovações do operador47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // Função interna para criar uma Pizza aleatória a partir de uma string (nome) e DNA50 function _createPizza(string memory _name, uint256 _dna)51 // A palavra-chave `internal` significa que esta função só é visível52 // dentro deste contrato e dos contratos que derivam deste contrato53 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` é um modificador de função que verifica se a pizza já existe56 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // Adiciona a Pizza à matriz de Pizzas e obtém o id60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // Verifica se o proprietário da Pizza é o mesmo que o usuário atual63 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // note que address(0) é o endereço zero,66 // indicando que pizza[id] ainda não foi alocada para um usuário em particular.6768 assert(pizzaToOwner[id] == address(0));6970 // Mapeia a Pizza para o proprietário71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // Cria uma Pizza aleatória a partir de uma string (nome)79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // Gera DNA aleatório a partir de uma string (nome) e do endereço do proprietário (criador)85 function generateRandomDna(string memory _str, address _owner)86 public87 // As funções marcadas como `pure` prometem não ler ou modificar o estado88 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // Gera um uint aleatório a partir de uma string (nome) + endereço (proprietário)93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // Retorna uma matriz de Pizzas encontradas pelo proprietário100 function getPizzasByOwner(address _owner)101 public102 // Funções marcadas como `view` prometem não modificar o estado103 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // Usa o local de armazenamento `memory` para armazenar valores apenas para o108 // ciclo de vida desta chamada de função.109 // Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);111 uint256 counter = 0;112 for (uint256 i = 0; i < pizzas.length; i++) {113 if (pizzaToOwner[i] == _owner) {114 result[counter] = i;115 counter++;116 }117 }118 return result;119 }120121 // Transfere a Pizza e a propriedade para outro endereço122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {123 require(_from != address(0) && _to != address(0), "Endereço inválido.");124 require(_exists(_pizzaId), "A pizza não existe.");125 require(_from != _to, "Não é possível transferir para o mesmo endereço.");126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "O endereço não está aprovado.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // Emite evento definido no contrato IERC721 importado133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * Transfere com segurança a propriedade de um determinado ID de token para outro endereço139 * Se o endereço de destino for um contrato, ele deverá implementar `onERC721Received`,140 * que é chamado após uma transferência segura e retorna o valor mágico141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;142 * caso contrário, a transferência será revertida.143 */144 function safeTransferFrom(address from, address to, uint256 pizzaId)145 public146 {147 // solium-disable-next-line arg-overflow148 this.safeTransferFrom(from, to, pizzaId, "");149 }150151 /**152 * Transfere com segurança a propriedade de um determinado ID de token para outro endereço153 * Se o endereço de destino for um contrato, ele deverá implementar `onERC721Received`,154 * que é chamado após uma transferência segura e retorna o valor mágico155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;156 * caso contrário, a transferência será revertida.157 */158 function safeTransferFrom(159 address from,160 address to,161 uint256 pizzaId,162 bytes memory _data163 ) public {164 this.transferFrom(from, to, pizzaId);165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Deve implementar onERC721Received.");166 }167168 /**169 * Função interna para invocar `onERC721Received` em um endereço de destino170 * A chamada não é executada se o endereço de destino não for um contrato171 */172 function _checkOnERC721Received(173 address from,174 address to,175 uint256 pizzaId,176 bytes memory _data177 ) internal returns (bool) {178 if (!isContract(to)) {179 return true;180 }181182 bytes4 retval = IERC721Receiver(to).onERC721Received(183 msg.sender,184 from,185 pizzaId,186 _data187 );188 return (retval == _ERC721_RECEIVED);189 }190191 // Queima uma Pizza - destrói o Token completamente192 // O modificador de função `external` significa que esta função é193 // parte da interface do contrato e outros contratos podem chamá-la194 function burn(uint256 _pizzaId) external {195 require(msg.sender != address(0), "Endereço inválido.");196 require(_exists(_pizzaId), "A pizza não existe.");197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "O endereço não está aprovado.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // Retorna a contagem de Pizzas por endereço207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // Retorna o proprietário da Pizza encontrado por id212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "ID de pizza inválido.");215 return owner;216 }217218 // Aprova outro endereço para transferir a propriedade da Pizza219 function approve(address _to, uint256 _pizzaId) public {220 require(msg.sender == pizzaToOwner[_pizzaId], "Deve ser o proprietário da Pizza.");221 pizzaApprovals[_pizzaId] = _to;222 emit Approval(msg.sender, _to, _pizzaId);223 }224225 // Retorna o endereço aprovado para uma Pizza específica226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "A pizza não existe.");232 return pizzaApprovals[_pizzaId];233 }234235 /**236 * Função privada para limpar a aprovação atual de um determinado ID de token237 * Reverte se o endereço fornecido não for de fato o proprietário do token238 */239 function _clearApproval(address owner, uint256 _pizzaId) private {240 require(pizzaToOwner[_pizzaId] == owner, "Deve ser o proprietário da pizza.");241 require(_exists(_pizzaId), "A pizza não existe.");242 if (pizzaApprovals[_pizzaId] != address(0)) {243 pizzaApprovals[_pizzaId] = address(0);244 }245 }246247 /*248 * Define ou cancela a aprovação de um determinado operador249 * Um operador tem permissão para transferir todos os tokens do remetente em seu nome250 */251 function setApprovalForAll(address to, bool approved) public {252 require(to != msg.sender, "Não é possível aprovar o próprio endereço");253 operatorApprovals[msg.sender][to] = approved;254 emit ApprovalForAll(msg.sender, to, approved);255 }256257 // Informa se um operador é aprovado por um determinado proprietário258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // Assume a propriedade da Pizza - apenas para usuários aprovados267 function takeOwnership(uint256 _pizzaId) public {268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "O endereço não está aprovado.");269 address owner = this.ownerOf(_pizzaId);270 this.transferFrom(owner, msg.sender, _pizzaId);271 }272273 // Verifica se a Pizza existe274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // Verifica se o endereço é o proprietário ou se está aprovado para transferir a Pizza280 function _isApprovedOrOwner(address spender, uint256 pizzaId)281 internal282 view283 returns (bool)284 {285 address owner = pizzaToOwner[pizzaId];286 // Disable solium check because of287 // https://github.com/duaraghav8/Solium/issues/175288 // solium-disable-next-line operator-whitespace289 return (spender == owner ||290 this.getApproved(pizzaId) == spender ||291 this.isApprovedForAll(owner, spender));292 }293294 // Verifica se a Pizza é única e ainda não existe295 modifier isUnique(string memory _name, uint256 _dna) {296 bool result = true;297 for (uint256 i = 0; i < pizzas.length; i++) {298 if (299 keccak256(abi.encodePacked(pizzas[i].name)) ==300 keccak256(abi.encodePacked(_name)) &&301 pizzas[i].dna == _dna302 ) {303 result = false;304 }305 }306 require(result, "Uma pizza com esse nome já existe.");307 _;308 }309310 // Retorna se o endereço de destino é um contrato311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // Atualmente não há uma maneira melhor de verificar se há um contrato em um endereço314 // do que verificar o tamanho do código nesse endereço.315 // Veja https://ethereum.stackexchange.com/a/14016/36603316 // para mais detalhes sobre como isso funciona.317 // TODO Verificar isso novamente antes do lançamento do Serenity, porque todos os endereços serão318 // contratos então.319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}Exibir tudoLeitura adicional
Confira a documentação sobre Solidity e Vyper para ter uma visão geral mais completa dos contratos inteligentes:
Tópicos relacionados
Tutoriais relacionados
- Reduzindo o tamanho dos contratos para combater o limite de tamanho do contrato – Algumas dicas práticas para reduzir o tamanho do seu contrato inteligente.
- Registrando dados de contratos inteligentes com eventos – Uma introdução aos eventos de contratos inteligentes e como você pode usá-los para registrar dados.
- Interaja com outros contratos a partir do Solidity – Como implantar um contrato inteligente a partir de um contrato existente e interagir com ele.