Primeras aventuras en sway
Sergio Martinez Marin
Posted on April 3, 2023
Hola a todos:
Después de pasar por mi primera hackathon en modalidad física, me llevo muchas alegrías de ver una plataforma que promete mucho. Esta plataforma se llama Fuel.
Para no hechar una historia larga, se trata de una blockchain modular y está especializada en la capa de ejecución, esto quiere decir que esta capa de ejecución es una alternativa a todas las L2 que hay en sistemas etherum y puede estar en otras blockchain :)
Fuel network maneja su propia maquina virtual y lenguaje, y esto es algo positivo ya que solidity no ha podido dar avances más agresivos en su evolución como lenguaje por cuidar la retrocompatibilidad.
El lenguaje se llama sway, inspirado en Rust, diría que muy similar a rust, lo cual es tendencia ahora en las nuevas generaciones de soluciones de blockchain con todos sus beneficios y complejidades que esto implica.
A continuación vamos a realizar nuestro primer ejercicio paso a paso, desde un contrato básico, hasta llevarlo a interactuar con una interfaz web.
Antes que todo este tutorial se basa en este código
código fuente original:
https://github.com/FuelLabs/quickstart
La instalación:
funciona para cualquier solución linux compatible, Linux, mac y Windows( bajo wsl2)
Se baja y ejecuta esta instrucción
curl --proto '=https' --tlsv1.2 -sSf https://install.fuel.network/fuelup-init.sh | sh
Instrucciones completas acá:
https://install.fuel.network/master/installation/index.html
creamos un directorio, y dentro de este directorio ejecutamos la siguiente instrucción
forc new countersm
entramos al directorio countersm/src y cambiamos el código de main.sw por el siguiente código:
contract;
storage {
counter: u64 = 0,
}
abi Counter {
#[storage(read, write)]
fn increment();
#[storage(read)]
fn count() -> u64;
}
impl Counter for Contract {
#[storage(read)]
fn count() -> u64 {
storage.counter
}
#[storage(read, write)]
fn increment() {
storage.counter = storage.counter + 1;
}
}
Storage
Estructuras "globales" y de acceso a todo el contrato.
abixxx
Definiciones genéricas de todas las funciones
impl xxx for Contract
Implementación del abi
Que nos obliguen a tener una estructura clara, nos da orden en el código :)
Nota: para el diario transcurrir, se recomienda editar el código con VS-code más la extensión de sway
En este caso,estoy corriendo el vs-code en windows y todo el sway en ubuntu 22.04 LTS desde WSL 🤓
Esta extensión nos advierte si tenemos algún error en nuestra codificación.
Una vez tenemos el código, en la consola de linux o mac compilamos el programa.
forc compile
Una vez tenemos listo nuestro código vamos a desplegarlo, pero........vamos a desplegarlo localmente, esto con el fin de tener una experiencia más agradable.
fuel-core run --ip 127.0.0.1 --port 4000
Acá tenemos billeteras generadas con fondos, entonces nos ahorramos crear la billetera y ponerle fondos, esto es muy útil cuando estamos haciendo desarrollos internos, luego si desplegamos en la testnet.
Como paso final de la parte de contratos vamos a deplegar el contrato en la red local ubicados dentro de la carpeta raiz de los contratos
forc deploy --unsigned
Creando la aplicación web
Como es una aplicación react, debemos tener instalado nodejs
Nota:
Se intentó crear la aplicación web por NextJS, por Deno, o simplemente en consola, pero explota por un error en una libreria
https://www.npmjs.com/package/elliptic , la cual no permite hacer el uso de import o exports.
Para tener la interacción web-fuelnetwork, se usa la librería fuels, que es de typescript.
En este ejercicio vamos a usar vite, ya que no se recomienda usar create-react-app.
npm create vite@latest
React
Typescript+SWC
Ahora vamos al directorio web y ejecutamos npm install
e instalamos la libería de fuels
npm install fuels
Después de instalar la libería fuels, vamos a mirar que al compilar con forc build
se generó el abi en estructura json.
El código abi está generado en la siguiente carpeta
Si abrimos el archivo countersm-abi.json
, vemos lo siguiente
{
"types": [
{
"typeId": 0,
"type": "()",
"components": [],
"typeParameters": null
},
{
"typeId": 1,
"type": "u64",
"components": null,
"typeParameters": null
}
],
"functions": [
{
"inputs": [],
"name": "count",
"output": {
"name": "",
"type": 1,
"typeArguments": null
},
"attributes": [
{
"name": "storage",
"arguments": [
"read"
]
}
]
},
{
"inputs": [],
"name": "increment",
"output": {
"name": "",
"type": 0,
"typeArguments": null
},
"attributes": [
{
"name": "storage",
"arguments": [
"read",
"write"
]
}
]
}
],
"loggedTypes": [],
"messagesTypes": [],
"configurables": []
Nos ubicamos dentro de la carpeta web y ejecutamos el siguiente comando:
npx fuels typegen -i ../countersm/out/debug/*-abi.json -o ./src/types --contract
Con esto dejamos el abi listo para usar en web, pasamos el json a algo typescript!
En visual studio code, vamos modificar el archivo app.tsx y alteramos la funcionalidad del botón.
ponemos el siguiente código, lo que es contrato y llave secreta se cambia a sus datos respectivos.
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import { useEffect, useState } from "react";
import "./App.css";
//Liberria para cargar la wallet
import { Wallet } from "fuels";
// Import the contract factory -- you can find the name in index.ts.
// You can also do command + space and the compiler will suggest the correct name.
//Generado npx fuels typegen -i ../countersm/out/debug/*-abi.json -o ./src/types --contract
import { CountersmAbi__factory } from "./types/factories/CountersmAbi__factory";
// The address of the contract deployed the Fuel testnet
//dato obtenido al desplegar el contrato localmente forc deploy --unsigned
const CONTRACT_ID =
"0x3edb96c23766b8504caaff042994efa18460e7ba27f60191394a6bcf5be8d7d8";
//the private key from createWallet.js
//billetera generada al ejecutar el nodo localmente en memoria fuel-core run --ip 127.0.0.1 --port 4000
const WALLET_SECRET =
"0x37fa81c84ccd547c30c176b118d5cb892bdb113e8e80141f266519422ef9eefd";
// Create a Wallet from given secretKey in this case
// The one we configured at the chainConfig.json
//el segundo parámetro es el provider, en este caso es local
const wallet = Wallet.fromPrivateKey(
WALLET_SECRET, "http://127.0.01:4000/graphql"
);
// Connects out Contract instance to the deployed contract
// address using the given wallet.
const contract = CountersmAbi__factory.connect(CONTRACT_ID, wallet);
function App() {
const [count, setCount] = useState(0)
//función que hace incrementa en 1 y luego trae el valor de la blockchain local!! :)
async function fuel_power(){
await contract.functions.increment().txParams({ gasPrice: 1 }).call();
const { value } = await contract.functions.count().get();
setCount(Number(value));
}
return (
<div className="App">
<div>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://reactjs.org" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={fuel_power}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</div>
)
}
export default App
Finalmente activamos el vite
npm run dev
y abrimos el navegador en el puerto 5173
http://localhost:5173
Cómo es local, la interacción blockchain es a la velocidad del rayo :)
Felicitaciones!!
Tu primera implementación real y con interacción web
Repositorio github:
https://github.com/sergiotechx/counterReactFuel
Actualización
Un miembro de Fuel me indicó donde está el foro de la comunidad y allí ya resolvieron el problema con NEXTJS y funciona!
En el archivo next.config.js se agrega lo siguiente:
experimental: {
esmExternals: false,
}
Posted on April 3, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.