Truffle é uma ferramenta essencial para compilação e implantação em lote de contratos inteligentes, eliminando a necessidade de deploy manual como no Remix, aumenatndo significativamente a eficiência.
Comendos principais:
- truffle compile: gera arquivos JSON com bytecode e metadados
- trufffle migrate/deploy: executa implantações
- truffle exec: executa módulos JS no ambiente Truffle
Exemplo de script personalizado para coletar hashes de pares:
// contratos
// const UniswapV2Router02 = artifacts.require("UniswapV2Router02");
// const UniswapV2Library = artifacts.require("UniswapV2Library");
const Fábrica = artifacts.require("UniswapV2Factory");
const stripHexPrefix = require('strip-hex-prefix');
const enderecosFábrica = [
"0xcA976B7714f0b48088cCC959C2843Fe752A33855",
"0x7e65601AB5A90E2A04Ed4eAa0D91aa34082FdDd3",
"0xbBF29Fc64b9D5A90FE3cc75c696C6e542DEcEC35",
"0x0A4e77be8aC06F2B4A1f08Ce8006C0B6eC475920",
"0x402576A5Ffa4d6A1E6Deb2C3B7082759E3Be686B"
];
let hashes = [];
const tokenWETH = "";
module.exports = async function (deployer, rede, contas) {
for (var i = 0; i < enderecosFábrica.length; i++) {
const instanciaFábrica = await Fábrica.at(enderecosFábrica[i]);
const hash = await instanciaFábrica.pairCodeHash();
console.log('hash', enderecosFábrica[i], hash);
var conteudoSubstituido = "hex'" + stripHexPrefix(hash) + "'"
hashes.push(conteudoSubstituido);
}
console.log(hashes);
};
Implantação da fábrica de swaps:
const editJsonFile = require("edit-json-file");
const stripHexPrefix = require('strip-hex-prefix');
const fs = require('fs');
var REGEX = /hex'(.{64,})/g;
function substituir(caminho, regex, conteudoSubstituido) {
// carrega o arquivo
var conteudoArquivo = fs.readFileSync(caminho, 'utf8');
conteudoArquivo = conteudoArquivo.replace(regex, conteudoSubstituido);
// sobrescreve o arquivo original, altere o caminho para testes
fs.writeFileSync(caminho, conteudoArquivo);
}
// contratos
const Fábrica = artifacts.require("UniswapV2Factory");
const ERC20 = artifacts.require("MyERC20")
// contratos
const UniswapV2Router02 = artifacts.require("UniswapV2Router02");
const UniswapV2Library = artifacts.require("UniswapV2Library");
const SafeMath = artifacts.require("SafeMath");
const StakingRewards = artifacts.require("StakingRewards");
var ArquivoSaida = "./cList.json"
const json = require(ArquivoSaida)
const deadline = 1956981781
// implantação da fábrica de swaps
module.exports = async function(deployer, rede, contas) {
for (ts = 0; ts < 5; ts++) {
let mapa = new Map();
var nomesERC20 = new Array()
var listaERC20 = new Array()
for (i = 0; i < 4; i++) {
const nome = "Token" + i
await deployer.deploy(ERC20, nome, 9000000000000000)
const instanciaERC20 = await ERC20.deployed()
listaERC20[i] = instanciaERC20.endereço
mapa.set(nome, instanciaERC20.endereço)
}
await deployer.deploy(ERC20, "FakeWETH", 9000000000000000)
const instanciaWETH = await ERC20.deployed()
var enderecoWETH = instanciaWETH.endereço
mapa.set("EndereçoWETH", enderecoWETH)
await deployer.deploy(Fábrica, contas[0]);
const instanciaFábrica = await Fábrica.deployed();
const hash = await instanciaFábrica.pairCodeHash();
var enderecoFábrica = instanciaFábrica.endereço
var conteudoSubstituido = "hex'" + stripHexPrefix(hash) + "'"
substituir(`${__dirname}/../contracts/swap/router/libraries/UniswapV2Library.sol`, REGEX, conteudoSubstituido);
await deployer.deploy(UniswapV2Library);
await deployer.link(UniswapV2Library, UniswapV2Router02);
await deployer.deploy(SafeMath);
await deployer.link(SafeMath, UniswapV2Router02);
await deployer.deploy(UniswapV2Router02, enderecoFábrica, enderecoWETH);
const instanciaRouter = await UniswapV2Router02.deployed();
var enderecoRouter = instanciaRouter.endereço
mapa.set("Fábrica", enderecoFábrica)
mapa.set("Router", enderecoRouter)
var valorDepósito = 4000000000000000
for (i = 0; i < listaERC20.length; i++) {
const instanciaERC20 = await ERC20.at(listaERC20[i])
await instanciaERC20.approvar(enderecoRouter, valorDepósito)
}
await instanciaRouter.addLiquidity(listaERC20[0], listaERC20[1], 3000000000000000, 3000000000000000, 0, 0, contas[0], deadline)
await instanciaRouter.addLiquidity(listaERC20[2], listaERC20[3], 3000000000000000, 3000000000000000, 0, 0, contas[0], deadline)
var lp1 = await instanciaRouter.pairFor(listaERC20[0], listaERC20[1])
var lp2 = await instanciaRouter.pairFor(listaERC20[2], listaERC20[3])
mapa.set("LP1", lp1)
mapa.set("LP2", lp2)
await instanciaRouter.swapExactTokensForTokens(1000000000000000, 0, [listaERC20[0], listaERC20[1]], contas[0], deadline)
await instanciaRouter.swapExactTokensForTokens(1000000000000000, 0, [listaERC20[2], listaERC20[3]], contas[0], deadline)
// implantação de staking LP1
await deployer.deploy(StakingRewards, contas[0], listaERC20[0], lp1, 63072000);
var instanciaStaking = await StakingRewards.deployed();
mapa.set("Staking1", instanciaStaking.endereço);
var instanciaERC20 = await ERC20.at(lp1)
var saldo = await instanciaERC20.saldoDe(contas[0])
await instanciaERC20.approvar(instanciaStaking.endereço, saldo)
await instanciaStaking.stake(saldo)
instanciaERC20 = await ERC20.at(listaERC20[0])
saldo = await instanciaERC20.saldoDe(contas[0])
await instanciaERC20.transferir(instanciaStaking.endereço, saldo / 2)
await instanciaStaking.notificarPremio(saldo / 2)
await instanciaStaking.receberPremio()
// implantação de staking LP2
await deployer.deploy(StakingRewards, contas[0], listaERC20[2], lp2, 63072000);
var instanciaStaking = await StakingRewards.deployed();
mapa.set("Staking2", instanciaStaking.endereço);
var instanciaERC20 = await ERC20.at(lp2)
var saldo = await instanciaERC20.saldoDe(contas[0])
await instanciaERC20.approvar(instanciaStaking.endereço, saldo)
await instanciaStaking.stake(saldo)
instanciaERC20 = await ERC20.at(listaERC20[2])
saldo = await instanciaERC20.saldoDe(contas[0])
await instanciaERC20.transferir(instanciaStaking.endereço, saldo / 2)
await instanciaStaking.notificarPremio(saldo / 2)
await instanciaStaking.receberPremio()
json.push(Object.fromEntries(mapa))
fs.writeFile(ArquivoSaida,JSON.stringify(json),(err)=>{
if (err) console.log("err",err)
})
continue
console.log("índice", ts)
}
};
Implantação do router:
// contratos
const UniswapV2Router02 = artifacts.require("UniswapV2Router02");
const UniswapV2Library = artifacts.require("UniswapV2Library");
const SafeMath = artifacts.require("SafeMath");
const enderecoFábrica = "";
const enderecoWETH = "";
module.exports = async function (deployer, rede, contas) {
if (enderecoFábrica === "") {
throw new Error('endereço da fábrica não está definido');
}
await deployer.deploy(UniswapV2Library);
await deployer.link(UniswapV2Library, UniswapV2Router02);
await deployer.deploy(SafeMath);
await deployer.link(SafeMath, UniswapV2Router02);
await deployer.deploy(UniswapV2Router02, enderecoFábrica, enderecoWETH);
const instanciaRouter = await UniswapV2Router02.deployed();
console.log("endereço do router: " + instanciaRouter.endereço);
};
Como executar:
truffle exec seu_arquivo.js --network testnet
O método pairCodeHash() do contrato factory retorna type(c).creationCode que representa o bytecode gerado pelo Truffle (campo bytecode após compilação).
type(c).name: retorna o nome do contrato
type(c).creationCode: retorna o bytecode de criação
type(c).runtimeCode: retorna o bytecode de execução
Configuração do truffle-config.js
/**
* Use este arquivo para configurar seu projeto Truffle. Ele contém configurações
* comuns para diferentes redes e funcionalidades como migrações,
* compilação e testes. Descomente os que precisar ou os modifique
* para atender às necessidades do seu projeto.
*
* Mais informações sobre configuração estão disponíveis em:
*
* trufflesuite.com/docs/advanced/configuration
*
* Para implantar via Infura, será necessário um provedor de carteira (como @truffle/hdwallet-provider)
* para assinar transações antes de enviá-las para um nó público remoto. Contas Infura
* estão disponíveis gratuitamente em: infura.io/register.
*
* Também será necessário uma senha-mnemônica - a frase de 12 palavras que a carteira usa para gerar
* pares de chaves públicas/privadas. Se você estiver publicando seu código no GitHub, certifique-se de carregar essa
* frase de um arquivo que você tenha .gitignored para que não se torne acidentalmente público.
*/
const HDWalletProvider = require('@truffle/hdwallet-provider');
require('dotenv').config()
const MAINNET_URL = process.env.MAINNET_URL
module.exports = {
/**
* Redes definem como você se conecta ao cliente Ethereum e permite configurar os
* valores padrão web3 usa para enviar transações. Se você não especificar uma, truffle
* criará uma blockchain de desenvolvimento para você na porta 9545 quando você
* executar `develop` ou `test`. Você pode pedir a um comando truffle para usar uma específica
* rede da linha de comando, por exemplo
*
* $ truffle test --network <nome-da-rede>
*/
redes: {
// Útil para testes. O nome 'development' é especial - truffle o usa por padrão
// se estiver definido aqui e nenhuma outra rede for especificada na linha de comando.
// Você deve executar um cliente (como ganache-cli, geth ou parity) em uma aba separada
// se usar esta rede e deve definir as opções host, port e network_id
// abaixo para algum valor.
//
local: {
host: "127.0.0.1", // Hostlocal (padrão: nenhum)
porta: 8545, // Porta Ethereum padrão (padrão: nenhum)
network_id: "8", // Qualquer rede (padrão: nenhum)
},
testnet: {
//provedor: () => new HDWalletProvider("chave privada", "https://http-testnet.hecochain.com"),
provedor: () => new HDWalletProvider("chave privada", "https://exchaintestrpc.okex.org"),
network_id: 65,
gas: 30000000,
gasPrice: 1000000000,
networkCheckTimeout: 100000000,
timeoutBlocks: 2000,
intervaloPolingImplantação: 80000
},
mainnet: {
provedor: () => new HDWalletProvider(MNEMONIC, MAINNET_URL, 0, 2),
network_id: 66,
},
development: {
host: "127.0.0.1", // Hostlocal (padrão: nenhum)
porta: 8545, // Porta Ethereum padrão (padrão: nenhum)
network_id: "*", // Qualquer rede (padrão: nenhum)
},
},
// Defina opções padrão do mocha aqui, use relatores especiais etc.
mocha: {
// timeout: 100000
},
// Configure seus compiladores
compiladores: {
solc: {
versão: "^0.6.6", // Busca versão exata de solc-bin (padrão: versão do truffle)
configurações: {
otimizador: {
ativado: true,
runs: 1500
}
}
}
}
};