Skip to content

Latest commit

 

History

History
242 lines (171 loc) · 5.92 KB

README.md

File metadata and controls

242 lines (171 loc) · 5.92 KB

Suave-std

Suave Standard library (suave-std) is a collection of helpful contracts and libraries to build Suapps.

Installation

To install with Foundry:

forge install flashbots/suave-std

Libraries

Transactions.sol

Helper library that defines types and utilities to interact with Ethereum transaction types.

Example usage

Encode an EIP155 transaction:

import "suave-std/Transactions.sol";

contract Example {
    function example() public {
        Transactions.EIP155 memory txn0;
        // fill the transaction fields
        // legacyTxn0.to = ...
        // legacyTxn0.gas = ...

        // Encode to RLP
        bytes memory rlp = Transactions.encodeRLP(txn0);

        // Decode from RLP
        Transactions.EIP155 memory txn = Transactions.decodeRLP_EIP155(rlp);
    }
}

Sign an EIP-1559 transaction:

import "suave-std/Transactions.sol";

contract Example {
    function example() public {
        string memory signingKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291";

        Transactions.EIP1559Request memory txnRequest;
        txnRequest.to = address(0x095E7BAea6a6c7c4c2DfeB977eFac326aF552d87);
        txnRequest.gas = 50000;
        txnRequest.maxPriorityFeePerGas = 10;
        // ...

        Transactions.EIP1559 memory signedTxn = Transactions.signTxn(txnRequest, signingKey);
    }
}

Context.sol

Helper library to interact with the Suave context in the MEVM.

Available functions:

  • confidentialInputs(): Returns the confidential inputs of the offchain request.
  • kettleAddress(): Address of the kettle that is executing the offchain request.

Example usage

import "suave-std/Context.sol";

contract Example {
    function example() public {
        bytes memory inputs = Context.confidentialInputs();
        address kettle = Context.kettleAddress();
    }
}

Gateway

Helper library to interact with contracts from other chains.

Example usage

import "suave-std/Gateway.sol";

contract Example {
    function example() public {
        // query the beacon chain deposit contract
        Gateway gateway = new Gateway("http://<jsonrpc endpoint>", address(0x00000000219ab540356cBB839Cbe05303d7705Fa));
        DepositContract depositContract = DepositContract(address(gateway));

        bytes memory count = depositContract.get_deposit_count();
    }
}

interface DepositContract {
    function get_deposit_count() external view returns (bytes memory);
}

protocols/MevShare.sol

Helper library to send bundle requests with the Mev-Share protocol.

Example usage

import "suave-std/protocols/MevShare.sol";
import "suave-std/Transactions.sol";

contract Example {
    function example() public {
        Transactions.EIP155 memory legacyTxn0;
        // fill the transaction fields
        // legacyTxn0.to = ...
        // legacyTxn0.gas = ...

        bytes memory rlp = Transactions.encodeRLP(legacyTxn0);

        MevShare.Bundle memory bundle;
        bundle.bodies = new bytes[](1);
        bundle.bodies[0] = rlp;
        // ...

        MevShare.sendBundle("http://<relayer-url>", bundle);
    }
}

protocols/EthJsonRPC.sol

Helper library to interact with the Ethereum JsonRPC protocol.

Example usage

import "suave-std/protocols/EthJsonRPC.sol";

contract Example {
    function example() public {
        EthJsonRPC jsonrpc = new EthJsonRPC("http://...");
        jsonrpc.nonce(address(this));
    }
}

protocols/ChatGPT.sol

Helper library to send completion requests to ChatGPT.

import "suave-std/protocols/ChatGPT.sol";

contract Example {
    function example() public {
        ChatGPT chatgpt = new ChatGPT("apikey");

        ChatGPT.Message[] memory messages = new ChatGPT.Message[](1);
        messages[0] = ChatGPT.Message(ChatGPT.Role.User, "How do I write a Suapp with suave-std?");

        chatgpt.complete(messages);
    }
}

crypto/Secp256k1.sol

Helper library to interact with the secp256k1 curve.

import "src/crypto/Secp256k1.sol";

contract Example {
    function example() public {
        // string memory privateKey = Suave.privateKeyGen(Suave.CryptoSignature.SECP256);
        string memory privateKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291";
        address found = Secp256k1.deriveAddress(privateKey);
    }
}

Forge integration

In order to use forge, you need to have a running Suave node and the suave binary in your path.

To run Suave in development mode, use the following command:

$ suave --suave.dev

Then, your forge scripts/test must import the SuaveEnabled contract from the suave-std/Test.sol file.

import "forge-std/Test.sol";
import "suave-std/Test.sol";
import "suave-std/suavelib/Suave.sol";

contract TestForge is Test, SuaveEnabled {
    address[] public addressList = [0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829];

    function testConfidentialStore() public {
        Suave.DataRecord memory record = Suave.newDataRecord(0, addressList, addressList, "namespace");

        bytes memory value = abi.encode("suave works with forge!");
        Suave.confidentialStore(record.id, "key1", value);

        bytes memory found = Suave.confidentialRetrieve(record.id, "key1");
        assertEq(keccak256(found), keccak256(value));
    }
}

Confidential inputs

Use the setConfidentialInputs function to set the confidential inputs during tests.

import "forge-std/Test.sol";
import "src/Test.sol";
import "src/suavelib/Suave.sol";
import "src/Context.sol";

contract TestForge is Test, SuaveEnabled {
    function testConfidentialInputs() public {
        bytes memory input = hex"abcd";
        ctx.setConfidentialInputs(input);

        bytes memory found2 = Context.confidentialInputs();
        assertEq0(input, found2);
    }
}

The value for the confidential inputs gets reset for each test.