Ejercicios resueltos — Capítulo 30¶
Volver al índice · Capítulo original
Ejercicio 1: Instalar MetaMask en testnet¶
Instala MetaMask y crea una wallet en testnet.
Solución¶
- Instala la extensión MetaMask en Chrome/Firefox/Brave.
- Crea una wallet nueva (guarda la frase semilla en un sitio seguro).
- Cambia la red a Sepolia (testnet):
- Red: Sepolia
- RPC URL:
https://rpc.sepolia.org - Chain ID:
11155111 - Símbolo:
SepoliaETH - Pide ETH de prueba gratis en Sepolia Faucet.
Ejercicio 2: Conectar la web a MetaMask¶
Conecta tu web a MetaMask con
eth_requestAccounts.
Solución¶
<button id="conectar">Conectar wallet</button>
<p id="estado"></p>
<script>
const btn = document.getElementById('conectar');
const estado = document.getElementById('estado');
btn.addEventListener('click', async () => {
if (!window.ethereum) {
estado.textContent = 'Instala MetaMask';
return;
}
try {
const cuentas = await window.ethereum.request({
method: 'eth_requestAccounts',
});
estado.textContent = `Conectado: ${cuentas[0].slice(0, 6)}...${cuentas[0].slice(-4)}`;
} catch (err) {
estado.textContent = 'Rechazado por el usuario';
}
});
</script>
Ejercicio 3: Leer balance con ethers¶
Lee el balance de una dirección.
Solución¶
npm install ethers
import { BrowserProvider, formatEther } from 'ethers';
async function leerBalance(direccion) {
const provider = new BrowserProvider(window.ethereum);
const balance = await provider.getBalance(direccion);
return formatEther(balance); // convierte de wei a ETH
}
const saldo = await leerBalance('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
console.log('Balance:', saldo, 'ETH');
Desde una wallet conectada:
const provider = new BrowserProvider(window.ethereum);
const cuentas = await provider.send('eth_requestAccounts', []);
const saldo = await provider.getBalance(cuentas[0]);
console.log('Tu balance:', formatEther(saldo), 'ETH');
Ejercicio 4: Contrato Contador en Sepolia¶
Despliega un contrato Contador en Sepolia y úsalo desde el frontend.
Solución¶
Contrato Contador.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Contador {
uint256 public cuenta;
function incrementar() public {
cuenta += 1;
}
function reiniciar() public {
cuenta = 0;
}
}
Compilar y desplegar:
- Usa Remix IDE o Hardhat.
- Conecta MetaMask a Sepolia.
- Deploy → copia la dirección.
Frontend:
import { BrowserProvider, Contract } from 'ethers';
const ABI = [
'function cuenta() view returns (uint256)',
'function incrementar()',
'function reiniciar()',
];
const DIRECCION = '0x...'; // dirección del contrato
async function incrementar() {
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const contrato = new Contract(DIRECCION, ABI, signer);
const tx = await contrato.incrementar();
console.log('Transacción enviada:', tx.hash);
await tx.wait();
console.log('Confirmada');
}
async function leer() {
const provider = new BrowserProvider(window.ethereum);
const contrato = new Contract(DIRECCION, ABI, provider);
const cuenta = await contrato.cuenta();
console.log('Cuenta:', cuenta.toString());
}
Ejercicio 5: Información de un NFT¶
Muestra información de un NFT desde OpenSea API.
Solución¶
const API_KEY = 'tu-api-key-opensea';
const CONTRATO = '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D'; // BAYC
const TOKEN_ID = '1';
async function obtenerNFT() {
const res = await fetch(
`https://api.opensea.io/api/v2/chain/ethereum/contract/${CONTRATO}/nfts/${TOKEN_ID}`,
{
headers: {
'X-API-KEY': API_KEY,
},
}
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data.nft;
}
const nft = await obtenerNFT();
console.log('Nombre:', nft.name);
console.log('Imagen:', nft.image_url);
Ejercicio 6: Subir a IPFS¶
Sube un archivo a IPFS y accede vía gateway.
Solución¶
npm install ipfs-http-client
import { create } from 'ipfs-http-client';
const ipfs = create({ url: 'https://ipfs.infura.io:5001/api/v0' });
async function subir(texto) {
const { path } = await ipfs.add(texto);
return `https://ipfs.io/ipfs/${path}`;
}
const url = await subir('Hola desde IPFS');
console.log('Disponible en:', url);
Consideraciones: - IPFS público → el archivo se replica entre nodos. - Si nadie lo pide, puede desaparecer (no es almacenamiento permanente). - Para persistencia, usa Pinata, NFT.storage o web3.storage.
Ejercicio 7: Comparar Web2 vs Web3¶
Escribe el mismo formulario con Web2 y con Web3.
Web2: Login tradicional¶
<form id="login">
<input type="email" placeholder="Email" required>
<input type="password" placeholder="Contraseña" required>
<button>Entrar</button>
</form>
<script>
document.getElementById('login').addEventListener('submit', async (e) => {
e.preventDefault();
const form = new FormData(e.target);
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(Object.fromEntries(form)),
headers: { 'Content-Type': 'application/json' },
});
const { token } = await res.json();
localStorage.setItem('token', token);
});
</script>
Ventajas: - UX familiar. - Recuperación de contraseña posible. - Sin gas fees.
Desventajas: - Servidor central puede caer. - Datos en el servidor.
Web3: Conectar wallet¶
<button id="conectar">Conectar wallet</button>
<script>
document.getElementById('conectar').addEventListener('click', async () => {
if (!window.ethereum) return alert('Instala MetaMask');
const cuentas = await window.ethereum.request({
method: 'eth_requestAccounts',
});
console.log('Conectado como:', cuentas[0]);
});
</script>
Ventajas: - Sin contraseñas ni emails. - Identidad soberana. - Login con una sola acción.
Desventajas: - Si pierdes la clave, pierdes la cuenta. - Curva de aprendizaje alta. - Requiere instalar una extensión.
Conclusión
No todo debe ser Web3. Web2 sigue siendo la mejor opción para el 99% de casos. Usa Web3 solo cuando la descentralización sea un requisito real.