Utilizando truffle para desenvolvimento de smart contracts

Marcelo Morgado
3 min readMay 30, 2018

--

O truffle é um framework largamente utilizado por desenvolvedores de smart contracts Ethereum. Dentre seus recursos, irei abordar:

  • Compilação e implantação (deploy);
  • Interação com contratos via console;
  • Testes automatizados.

Instação

npm install -g truffle

Primeiros passos

Crie um diretório para seu projeto e em seguida inicialize-o como um projeto truffle:

mkdir myproject
cd myproject
truffle init

Com o projeto inicializado, vamos configurar o nó que ele irá utilizar, para isso, iremos editar o arquivo truffle.js que foi criado com o comando anterior.

module.exports = {
networks: {
development: {
host: “127.0.0.1”,
port: 8545,
network_id: “*” // Match any network id
}
}
};

É possível configurar mais de um nó para o mesmo projeto (ex.: development, testnet, mainnet e etc). Para desenvolvimento, recomendo o uso do ganache como nó (para saber mais clique aqui).

Para verificar se a configuração está correta, use o console do truffle:

truffle consoletruffle(development)> web3.eth.accounts
[ ‘0xf4c41d2efe13876076edc7b57bf99e64e03a0e76’,
‘0xdf439fa91b11284e43ccdd18dd2a4d51bb60e3dd’,
‘0xc527c89eaa042254376d55ee1e1b1547658f7d1a’,
‘0x104fc667dc1f8fd9b99afb0593d247f7e5bc7e43’,
‘0x887562666d0d19a322903ad7a1bd72c358f02ab2’,
‘0x165867ae592c39ee56a3752cc05101819ab3014a’,
‘0x43c3c0c477083dbf3e174a30244cc2500229f971’,
‘0x96a6db824cf61948c9b482256cfa60ee7065baa3’,
‘0x00cef398593e221c76692f6f885c0e642f85dbc5’,
‘0x5f3e9d6f60ea5505d9685f8dd0d2dbe285985acc’ ]
truffle(development)> .exit

Com o nosso projeto devidamente configurado e integrado ao nosso nó Ethereum, iremos agora compilar, implantar e testar um smart contract de exemplo.

Compilação e Implantação

Iremos utilizar como exemplo o contrato abaixo. Salve-o como Ownable.sol no diretório contracts.

pragma solidity ^0.4.23;contract Ownable {
address public owner;
uint256 changes_;
constructor() public {
owner = msg.sender;
changes_ = 0;
}
function transferOwnership(address newOwner) public {
require(msg.sender == owner);
require(newOwner != address(0));
owner = newOwner;
changes_ = changes_ + 1;
}
function getChanges() public view returns (uint256) {
return changes_;
}
}

Para compilar o projeto:

truffle compile

Após a compilação, o diretório build/contracts será criado. Nos arquivos deste diretório será possível encontrar bytecodes e ABIs dos contratos que compõem o projeto.

Para implantar o projeto, crie o arquivo migrations/2_ownable.js com o seguinte conteúdo:

var Ownable = artifacts.require(“./Ownable.sol”);module.exports = function(deployer) {
deployer.deploy(Ownable);
};

Para realizar a implantação (deploy) do contrato:

truffle migrate

Note que no output do console será exibido o address do account do contrato recém implantado. No meu caso o address é o 0x6293a24dc61f540777c7111fc462e5159a90a504.

Using network ‘development’.Running migration: 1_initial_migration.js
Replacing Migrations...
... 0x5117f63fe780e82431727d445374ae5e8692e88d958533092c8bf7fe4d4cfac5
Migrations: 0x9baffd23e8a337f487fafaba732495b26e2afb53
Saving successful migration to network...
... 0xcd60591b552d03a72d24989997a53c4ab006e707eeaf6e603651c81cd5c789be
Saving artifacts...
Running migration: 2_ownable.js
Deploying Ownable...
... 0xeed94c460362315297c664645945388ddbe9ed90aed72b015f16daee1c952646
Ownable: 0x6293a24dc61f540777c7111fc462e5159a90a504
Saving successful migration to network...
... 0x6b76cccd174cde86b63c28c9fdbfbaee9f20c687a31f581179dcbee1e9430335
Saving artifacts...

Testes Manuais

Agora com o nosso contrato implantando na blockchain, estamos aptos a interagir com ele e realizar alguns testes para verificar seu funcionamento.

$ truffle console
truffle(development)> Ownable.deployed().then(function(instance) { ownable = instance; });
truffle(development)> ownable.owner.call();
'0x21fd02619787526b33c6cfafb15fcda426e5c06a'
truffle(development)> ownable.getChanges().then(function(c) { return c.toString() } );
'0'

Com os comandos acima fizemos:

  1. Atribuímos à variável ownable uma instância do nosso contrato;
  2. Obtemos o valor do atributo owner do contrato;
  3. Realizamos chamada à função getChanges() para obter o valor do atributo changes (privado).

Iremos agora alterar o dono do contrato e verificar se a alteração foi efetivada corretamente:

truffle(development)> ownable.transferOwnership(web3.eth.accounts[1]);
{ tx: ‘0xfc68020dd10d42422b940362cc0a4d197155f326d536cbd4dac22debac0b54ff’,
receipt:
{ transactionHash: ‘0xfc68020dd10d42422b940362cc0a4d197155f326d536cbd4dac22debac0b54ff’,
transactionIndex: 0,
blockHash: ‘0x6299e07aed8c6c0fce3aa6db85b05b67745a5d7b400246171bbd30fc55f6ecc7’,
blockNumber: 11,
gasUsed: 48728,
cumulativeGasUsed: 48728,
contractAddress: null,
logs: [],
status: ‘0x01’,
logsBloom: ‘0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000’ },
logs: [] }

truffle(development)> ownable.owner.call().then(function(o) { return o == web3.eth.accounts[1]; });
true
truffle(development)> ownable.getChanges().then(function(c) { return c.toString() } );
'1'

Ao contrário da execução da função getChanges(), a função transferOwnership() realiza alteração no estado do contrato e por isso sua chamada é realizada através de uma transação.

Testes Automatizados

Um dos recursos mais interessantes do truffle é a possibilidade escrevermos scripts de testes para nossos contratos. Iremos basicamente realizar os mesmos testes que foram feitos via console agora através de scritps, que poderão ser executados sempre que quisermos.

Crie o arquivo test/Ownable.test.js com o seguinte conteúdo:

var Ownable = artifacts.require(‘Ownable.sol’);contract(‘Ownable’, function(accounts) {
let ownable;
before(async function() {
ownable = await Ownable.new();
});
it(‘should have an owner’, async function() {
let owner = await ownable.owner();
assert.isTrue(owner !== 0);
});
it(‘should have no changes’, async function() {
let changes = await ownable.getChanges();
assert.isTrue(changes == 0);
});
it(‘changes owner after transfer’, async function() {
let other = accounts[1];
await ownable.transferOwnership(other);
let owner = await ownable.owner();
assert.isTrue(owner === other);
});
it(‘should have a changes’, async function() {
let changes = await ownable.getChanges();
assert.isTrue(changes == 1);
});
});

O comando abaixo irá executar todos os scripts existentes no diretório test:

$ truffle test
Using network 'development'.
Contract: Ownable
✓ should have an owner
✓ should have no changes
✓ changes owner after transfer (42ms)
✓ should have a changes
4 passing (140ms)

Conclusão

O truffle é uma ferramenta muito útil para o desenvolvimento de smart contracts Ethereum. Seu uso juntamente com o ganache dentre outras vantagens, facilita o uso do método de desenvolvimento orientado a testes (TDD) em nossos projetos.

--

--