Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Integración y Desarrollo11 min de lectura

Foundry Solidity: un flujo de trabajo reproducible para compilar, probar y desplegar

Una guía práctica y reproducible para usar el kit de herramientas Foundry en el desarrollo de contratos inteligentes en Solidity, desde la estructura del proyecto y las pruebas de Forge hasta el forking con Anvil y el despliegue respaldado por RPC.

TL;DR

Foundry es un kit de herramientas basado en Rust para el desarrollo de aplicaciones Ethereum que compila Solidity, ejecuta pruebas unitarias y de fuzzing escritas en Solidity, despliega contratos e interactúa con cadenas desde la línea de comandos. Sus cuatro herramientas principales son Forge para compilar, probar y desplegar; Anvil para un nodo local con forking; Cast para la interacción con la cadena; y Chisel para un REPL de Solidity. Este artículo ofrece un flujo de trabajo reproducible: crear un proyecto, escribir una prueba de Forge, ejecutar un fork contra un endpoint RPC, desplegar con un script y verificar el resultado. También cubre modos de fallo comunes como remappings, errores de RPC en forks y problemas de nonce o gas, y explica dónde importa un proveedor de RPC confiable.

Qué aporta Foundry a un flujo de trabajo con Solidity

Foundry es un kit de herramientas rápido, portátil y modular para el desarrollo de aplicaciones Ethereum escrito en Rust. Gestiona dependencias, compila Solidity, ejecuta pruebas unitarias y de fuzzing, despliega contratos y controla la interacción con la cadena mediante scripts desde la terminal o desde scripts en Solidity. Las herramientas principales son Forge (compilar, probar, depurar, desplegar, verificar), Anvil (un nodo Ethereum local con forking), Cast (una CLI para interactuar con la cadena) y Chisel (un REPL de Solidity).

La diferencia práctica con los frameworks centrados en JavaScript es que las pruebas y los scripts de despliegue pueden escribirse en Solidity. Eso elimina el cambio de contexto entre Solidity y JavaScript para el trabajo a nivel de contrato, y hace que las pruebas de fuzzing y la depuración basada en trazas formen parte del ciclo predeterminado. Foundry no reemplaza la necesidad de un endpoint RPC cuando haces un fork de una red en vivo o transmites una transacción; consume uno. La calidad y la consistencia de ese endpoint afectan directamente las pruebas de fork y los despliegues.

  • Forge: compilar, probar, fuzz, depurar, desplegar, verificar.
  • Anvil: nodo local, forking, cuentas deterministas.
  • Cast: llamar, enviar, decodificar, inspeccionar el estado de la cadena.
  • Chisel: prototipado y depuración rápida en Solidity.

Requisitos previos y supuestos

Este flujo de trabajo asume un shell tipo Unix, Git y una instalación funcional de Foundry mediante foundryup. Asume que tienes un RPC_URL para la red a la que deseas hacer fork o desplegar, y una PRIVATE_KEY con fondos para cualquier paso de transmisión. Nunca confirmes una clave privada; usa variables de entorno o un keystore cifrado.

Los ejemplos usan marcadores como RPC_URL y PRIVATE_KEY en lugar de endpoints públicos. Para elegir un endpoint concreto, el Asistente de RPC cubre recomendaciones de proveedores y redes; este artículo se centra en la metodología de desarrollo y en las comprobaciones que debes ejecutar tú mismo.

curl -L https://foundry.paradigm.xyz | bash
foundryup
forge --version
anvil --version
cast --version

Estructura del proyecto y modelo mental de dependencias

Un proyecto Foundry separa contratos, pruebas, scripts y dependencias. El directorio src/ contiene las fuentes Solidity, test/ contiene las pruebas de Forge, script/ contiene los scripts de despliegue y lib/ contiene las dependencias instaladas con forge install. Los remappings asignan rutas de importación a esas dependencias, que es la parte con la que tropiezan la mayoría de los nuevos usuarios.

Las dependencias suelen ser repositorios Git o submódulos. Eso es ligero, pero significa que las rutas de importación deben coincidir con la estructura del repositorio instalado. Si una importación falla, inspecciona remappings.txt y ejecuta forge remappings antes de cambiar el código. Para los equipos que prefieren la semántica de un gestor de paquetes, las dependencias también pueden gestionarse mediante un package.json y remappings, pero la regla subyacente es la misma: el compilador debe resolver cada importación a un archivo real.

forge init my-foundry-app
cd my-foundry-app
forge install foundry-rs/forge-std
forge remappings
forge build

Escribir una prueba de Forge en Solidity

Las pruebas de Forge son contratos Solidity que heredan del contrato Test de forge-std. Las funciones de prueba llevan el prefijo test, y las pruebas de fuzzing aceptan parámetros. El ejemplo siguiente prueba un contrato contador mínimo, incluido un caso de fuzzing que verifica un invariante tras incrementar.

Ejecuta la suite con forge test. Añade -vvvv para ver las trazas de ejecución cuando una prueba falla. El resultado de verificación esperado es una línea de resumen que muestra las pruebas aprobadas y cero fallos; si una prueba de fuzzing falla, Forge imprime la entrada del contraejemplo para que puedas reproducirla.

// src/Counter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Counter {
    uint256 public number;
    function increment() external { number += 1; }
}

// test/Counter.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Test} from "forge-std/Test.sol";
import {Counter} from "../src/Counter.sol";

contract CounterTest is Test {
    Counter counter;

    function setUp() public { counter = new Counter(); }

    function test_Increment() public {
        counter.increment();
        assertEq(counter.number(), 1);
    }

    function testFuzz_Increment(uint8 times) public {
        for (uint256 i = 0; i < times; i++) counter.increment();
        assertEq(counter.number(), times);
    }
}

Pruebas de fork con Anvil y un endpoint RPC

Las pruebas de fork ejecutan tus contratos contra una instantánea del estado de la cadena en vivo. Anvil inicia un nodo local que obtiene el estado de un endpoint RPC bajo demanda. Así es como se prueban las integraciones con protocolos desplegados sin gastar fondos reales.

Inicia Anvil con una URL de fork y luego apunta Forge al nodo local. El resultado de verificación esperado es que Anvil informe el número de bloque del fork y que las pruebas de Forge pasen contra el estado bifurcado. Si el fork falla, el error suele indicar la solicitud RPC que falló, lo cual es tu primera señal de diagnóstico.

anvil --fork-url $RPC_URL --fork-block-number 19000000

# In another terminal
forge test --fork-url http://127.0.0.1:8545 -vvv

Script de despliegue y verificación de la transmisión

Los scripts de despliegue de Foundry son contratos Solidity que heredan de Script. La función run despliega y devuelve el contrato. La transmisión es un paso separado: forge script con --broadcast envía las transacciones al endpoint RPC.

Después de la transmisión, verifica el resultado de forma independiente con Cast. El resultado de verificación esperado es que la dirección devuelta tenga código y que el estado del recibo de la transacción sea 1. No tomes la salida de consola de un script como prueba de despliegue; consulta la cadena.

// script/Deploy.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {Counter} from "../src/Counter.sol";

contract Deploy is Script {
    function run() external returns (Counter) {
        vm.startBroadcast();
        Counter counter = new Counter();
        vm.stopBroadcast();
        return counter;
    }
}

# Broadcast
forge script script/Deploy.s.sol:Deploy \
  --rpc-url $RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast

# Verify independently
cast code $CONTRACT_ADDRESS --rpc-url $RPC_URL
cast receipt $TX_HASH --rpc-url $RPC_URL

Procedimiento de diagnóstico para fallos de fork y RPC

Cuando falla una prueba de fork o un despliegue, aísla si el problema está en tu código, en tu configuración o en el endpoint. Ejecuta las comprobaciones a continuación en orden y registra el resultado. Esto produce una tabla de resultados que puedes comparar entre endpoints o ejecuciones.

El procedimiento: (1) confirma que el endpoint RPC responde a una solicitud básica de ID de cadena; (2) confirma que el bloque del fork está disponible; (3) ejecuta la prueba fallida con -vvvv; (4) repite contra un segundo endpoint si está disponible. Registra el ID de cadena, el bloque del fork, el resultado de la prueba y el mensaje de error. No inventes números; completa la tabla con tus observaciones reales.

  • Discrepancia de ID de cadena: el endpoint es para una red diferente a la de tu configuración.
  • Bloque faltante: el bloque del fork no está disponible en ese endpoint.
  • Límite de velocidad o tiempo de espera: el endpoint está limitando o es inaccesible.
  • Error de nonce: una transacción anterior está pendiente o la clave se reutilizó.
cast chain-id --rpc-url $RPC_URL
cast block-number --rpc-url $RPC_URL
cast block 19000000 --rpc-url $RPC_URL
forge test --fork-url $RPC_URL --fork-block-number 19000000 -vvvv

Plantilla de tabla de resultados

Usa una tabla Markdown como la siguiente para registrar tus propias mediciones. Las columnas son sugerencias; lo importante es separar el comportamiento documentado de lo que observaste. Reemplaza las filas de marcador de posición con tus ejecuciones reales.

ComprobaciónComandoEsperadoObservado
ID de cadenacast chain-idCoincide con la red objetivo(completar)
Bloque del forkcast block 19000000El bloque existe(completar)
Pruebas unitariasforge testTodas pasan(completar)
Pruebas de forkforge test --fork-urlTodas pasan(completar)
Recibo de desplieguecast receiptestado 1(completar)

Solución de errores comunes de Foundry

La mayoría de los errores tempranos de Foundry se agrupan en unas pocas categorías. Los fallos de resolución de importaciones suelen indicar una dependencia faltante o un remapping incorrecto. Los fallos de fork suelen indicar que el endpoint RPC no puede servir el bloque solicitado o que está limitado por tasa. Los fallos de transmisión suelen indicar un problema de nonce, gas o configuración de clave.

Para errores de importación, ejecuta forge remappings y compara la salida con tus declaraciones de importación. Para errores de fork, prueba el mismo bloque con Cast. Para errores de transmisión, verifica el saldo del remitente y el nonce pendiente con cast balance y cast nonce. Si el endpoint es la variable, compara el comportamiento entre proveedores; el Asistente de RPC puede ayudarte a elegir uno, mientras que las guías de Learn sobre endpoints RPC explican los patrones de solicitud subyacentes.

  • Importación no encontrada: verifica el contenido de lib/ y remappings.txt.
  • Error de RPC en fork: confirma la disponibilidad del bloque y los límites de tasa del endpoint.
  • Nonce demasiado bajo: revisa las transacciones pendientes para la misma clave.
  • Falló la estimación de gas: simula con cast call antes de enviar.

Limitaciones y compensaciones

Las pruebas centradas en Solidity de Foundry son excelentes para la lógica de contratos, el fuzzing y las trazas, pero no son un reemplazo completo para todas las necesidades de integración. Los equipos que prueban interacciones de frontend en JavaScript o plugins complejos de despliegue multicadena a veces mantienen una herramienta basada en JavaScript junto a Foundry. La gestión de dependencias mediante submódulos Git puede parecer ligera en comparación con los gestores de paquetes, y los remappings requieren disciplina.

Las pruebas de fork dependen de la capacidad del endpoint RPC para servir estado histórico. Un endpoint lento o limitado por tasa hará que las pruebas de fork sean inestables, lo que puede parecer un error de código. Trata la fiabilidad del endpoint como parte de tu infraestructura de pruebas, no como una idea de último momento. Para despliegues en producción, usa un endpoint dedicado y verifica las transacciones de forma independiente.

Próximos pasos

Una vez que el ciclo básico funcione, amplíalo: añade pruebas de invariantes, integra informes de cobertura y ejecuta la suite en CI con un bloque de fork fijado. Para la selección de endpoints, consulta la guía del Asistente de RPC sobre API RPC de Ethereum y compara precios y cobertura de red antes de comprometerte con un proveedor.

Lecturas relacionadas útiles: la guía de Learn sobre endpoints RPC, la guía de endpoints RPC multicadena y la descripción general de nodos dedicados para cargas de trabajo en producción. Si vas a desplegar en una red específica, consulta la lista de redes compatibles y la página de precios de los planes de RPC.

  • Añade pruebas de invariantes y fuzzing para invariantes críticos.
  • Fija los bloques de fork en CI para lograr reproducibilidad.
  • Verifica cada despliegue con Cast, no solo con la salida del script.
  • Elige un endpoint que se ajuste a tus necesidades de fork y despliegue.

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar