Skip to main content

Forge

info

There is limited support for Forge in SUAVE. We recommend that you use it only for writing contracts intended to test precompiles.

Writing and compiling contracts for SUAVE is similar to Ethereum, and can be done with familiar local tools like Forge, or even IDEs like Remix. Deploying those contracts to SUAVE is done using the same transaction type as Ethereum, and so can also be achieved from those tools without modifying anything other than the RPC endpoint.

However, SUAVE makes an extended set of precompiles available in any contract. While these are included as a library to keep compilation easy, you can't use Forge (or Remix) to interact with any method in those contracts which uses any of the new precompiles once the contracts are deployed.

Methods which use new precompiles can only be executed through a Kettle as a Confidential Compute Request (CCR). Foundry supports neither precompiles nor CCRs. This limits the current use cases for Forge.

SuaveForge.sol is a Solidity library that implements the same precompiles as Suave.sol. The difference is this:

  • Suave.sol is used in the MEVM on the Kettle specified by any CCR
  • SuaveForge.sol uses the ffi cheatcode in an environment external to Forge (i.e. the instance of SUAVE you are running locally). The ffi cheatcode uses the suave forge command from the suave binary to make remote calls.

Install

Let's start a new, empty repo and set suave-geth as a submodule so that we can easily import the SuaveForge.sol library:

mkdir suave-forge
cd suave-forge
forge init
git submodule init
git submodule add https://github.com/flashbots/suave-geth.git

Write and run a Forge script

Here is an example Forge script that uses the SuaveForge.sol library to create a new bid. Copy and paste it into a file called Example.sol in the src directory:

pragma solidity ^0.8.8;

import "../suave-geth/suave/sol/libraries/SuaveForge.sol";
import "forge-std/Script.sol";

contract Example is Script {
address[] public addressList = [Suave.ANYALLOWED];

function run() public {
Suave.Bid memory bid = SuaveForge.newBid(
0,
addressList,
addressList,
"namespace"
);
}
}

The same precompile functions available in Suave.sol are also implemented in SuaveForge.sol, though the struct types are still imported from Suave.sol. It is not required to import Suave.sol in your scripts since SuaveForge.sol already does it.

In order to deploy this example contract, you need to have SUAVE running locally, which can be done from your git submodule directory:

cd suave-geth
make suave
suave --suave.dev

Then, run the Forge script with the ffi flag enabled:

forge script Example.sol --ffi
Having issues?

Typically, building SUAVE yourself places the binary in the $GOPATH/bin directory. If it didn't happen, ensure that path is added to your PATH environment variable:


export PATH=$PATH:$GOPATH/bin

The Forge script should print the gas used to run the specified function in your console. If you check the logs of your SUAVE devnet, you should see a message like this:

INFO [timestamp] confidential engine: refusing to send writes based on unsigned transaction

Due to the limitations described above (no native support for precompiles or CCRs in Forge) and having to rely on your local environment, rather than Foundry's built-in network or forks, we recommend that you only use Forge for testing new precompiles you are writing.

Deploy your contract

That said, you can use Forge to deploy contracts to SUAVE (though we recommend that you then use the Golang SDK to send transactions).

If you wanted to deploy Example.sol, there are three steps you need to take:

  1. Replace SuaveForge.sol with Suave.sol and update all references in your contract.
  2. Get Rigil ETH from the faucet.
  3. Run the following command:
forge create --rpc-url https://rpc.rigil.suave.flashbots.net --legacy \
--private-key <your_funded_private_key> src/Example.sol:Example