18
"Hola mundo!" en Web3 [Blockchain]
Web3 es la librería que necesitamos para comunicarnos con smart contracts lanzados en cualquier blockchain compatible con la Ethereum Virtual Machine.
Antes de iniciar asegurate de instalar node (te recomiendo que lo instales via nvm) y creamos nuestra carpeta de proyecto e instalamos las dependencias.
Si luego de ver este tutorial desas profundizar un poco Truffle abre este post en otra pestaña.
Iniciemos creando un proyecto nuevo de Truffle.
mkdir MyProject
cd MyProject
npm install --save-dev truffle ganache-cli @truffle/hdwallet-provider
npm install --global lite-server
npx truffle init
Ahora creemos nuestro contrato de "Hola mundo!"
contracts/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.5;
contract MyContract {
string public hello = "Hola mundo!";
function setHello(string memory _hello) public {
hello = _hello;
}
}
En nuestro truffle config seteamos el contracts_build_directory
y la versión de solidity a 0.8.5
.
truffle-config.js
module.exports = {
contracts_build_directory: "./client/contracts",
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
},
compilers: {
solc: {
version: "0.8.5", // Fetch exact version from solc-bin (default: truffle's version)
}
},
db: {
enabled: false
}
};
Que no se nos olvide el script de la migración.
migrations/2_my_deploy.js
const MyContract = artifacts.require("MyContract");
module.exports = async function (deployer) {
await deployer.deploy(MyContract);
};
Lanzamos nuestro contrato en un blockchain local.
npx truffle compile
npx ganache-cli --deterministic #en otra consola
npx truffle migrate --network development
Agregamos un archivo de HTML para poder interactuar con el contrato.
client/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<h1>Ejemplo Web3</h1>
<input id="input_hello" /><br/>
<button onclick="setHello()">Set hello</button><br>
<button onclick="getHello()">Get hello</button><br/>
<p id="p_hello"></p>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js"></script>
<script type="text/javascript" src="src/utils.js"></script>
<script type="text/javascript" src ="src/index.js"></script>
</body>
</html>
Todo lo necesario para comunicarnos con el blockchain desde javascript. En este archivo nos conectamos a Metamask, leemos el account de nuestra wallet y leemos el contrato que está guardado en client/contracts/MyContract.json
. Finalmente todo quedará guardado en las variables web3
, accounts
y contract
.
client/src/utils.js
const getWeb3 = async () => {
return new Promise((resolve, reject) => {
console.log(document.readyState)
if(document.readyState=="complete")
{
if (window.ethereum) {
const web3 = new Web3(window.ethereum)
try {
// ask user permission to access his accounts
(async function(){
await window.ethereum.request({ method: "eth_requestAccounts" })
})()
resolve(web3)
} catch (error) {
reject(error)
}
} else {
reject("must install MetaMask")
}
}else
{
window.addEventListener("load", async () => {
if (window.ethereum) {
const web3 = new Web3(window.ethereum)
try {
// ask user permission to access his accounts
await window.ethereum.request({ method: "eth_requestAccounts" })
resolve(web3)
} catch (error) {
reject(error)
}
} else {
reject("must install MetaMask")
}
})
}
})
}
const getContract = async (web3) => {
const data = await getJSON("./contracts/MyContract.json")
const netId = await web3.eth.net.getId()
const deployedNetwork = data.networks[netId]
const contract = new web3.eth.Contract(
data.abi,
deployedNetwork && deployedNetwork.address
)
return contract
}
function getJSON(url) {
return new Promise(resolve => {
var xhr = new XMLHttpRequest()
xhr.open("GET", url, true)
xhr.responseType = "json"
xhr.onload = function () {
resolve(xhr.response)
}
xhr.send()
})
}
async function loadApp() {
var awaitWeb3 = async function () {
web3 = await getWeb3()
web3.eth.net.getId((err, netId) => {
var awaitContract = async function () {
contract = await getContract(web3)
var awaitAccounts = async function () {
accounts = await web3.eth.getAccounts()
console.log("Web3 loaded")
}
awaitAccounts()
}
awaitContract()
})
}
awaitWeb3()
}
loadApp()
Ahora podemos interactuar con el contrato desde javascript.
client/src/index.js
var contract
var accounts
var web3
const getHello = async () => {
hello = await contract.methods.hello().call()
document.getElementById("p_hello").innerHTML = hello
}
const setHello = async () => {
var hello = document.getElementById('input_hello').value
const result = await contract.methods.setHello(hello)
.send({ from: accounts[0], gas: 400000 })
}
Para interactuar vía Metamask debes configurar tu metamask a que apunte a http://127.0.0.1:8545
en el chain id 1337
con una llave privada listada en el resultado del comando npx ganache-cli --deterministic
. Una vez hecho esto levantamos un servidor web desde la carpeta ./client
.
cd client
lite-server
Gracias por ver este tutorial!
Sígueme en dev.to y en Youtube para todo lo relacionado al desarrollo en Blockchain en Español.
18