+
+**Starting Point**: A user sends "Confidential Compute Request" using `eth_sendRawTransaction`, which is received by the JSON RPC.
+
+
+
+**MEVM Execution**: Upon receiving the request, the JSON RPC triggers the MEVM (Modified Ethereum Virtual Machine) to run. MEVM execution can use multiple APIs depending on the context, with two possible paths:
+
+
+
+**Request to an External Domain**: The MEVM can make API requests to external domains: i.e. if you're running an Ethereum node, it can fetch state from there for simulations etc., or if the SUAPP uses the `doHttpRequest()` precompile, it can fetch arbitrary information required for the offchain compute.
+
+**Request to the Confidential Datastore**: The MEVM can make API requests directly to the "Confidential Datastore" to fetch or store data.
+
+
+
+
+
+**Broadcast results**: Eventually, after processing the request the MEVM can take the results and, depending on the SUAPP's logic, send a SUAVE transaction, which is a transaction object that contains the result of the CCR in its calldata (and the signature of the Kettle which computed said result), which enables other users or contracts to take action.
+
+**Transaction Hash Output**: A transaction hash for the Suave transaction above is produced and returned to the request's originator, just like Ethereum.
+
+
+
+### Computing over Confidential Data
+
+How to index, store, and use confidential data is left up to each SUAPP.
+
+For example, in the [Private OFA Suapp](https://github.com/flashbots/suapp-examples/tree/main/examples/app-ofa-private), to submit a valid backrun, a searcher must include the `recordId` of the user transaction in order for the Suapp to match them. Therefore, the Suapp emits the user transaction `recordId` as a log on chain, which searchers can listen for and use to construct valid backruns.
+
+However, the NFTEE example demonstrates how to store a private key in the confidential store. In order to get it to sign a transaction intended for Ethereum L1, we store the `recordId` associated with that private key in the contract's memory, which ends up onchain. In this context, this is not a concern, since it's gated, so only that Suapp can access the key for signing purposes.
+
+### Restricting Access
+
+You need not use confidential requests in the ways which our examples illustrate. For instance, if you wish to restrict access to methods with a modifier requiring some confidential secret, you can do so. This can be achieved by following the below steps, contributed by Miha:
+
+1. When you initialize a contract, pass it a secret key which is stored in confidential storage.
+2. Use this key with the local nonce to derive the next secret.
+3. The hash of the present secret is in public (evm) storage.
+4. Whenever a restricted method is accessed, the present secret needs to be provided.
+ 1. This is only accessible through confidential execution.
+
+You can find Miha's implementation of [ConfidentialControl here](https://github.com/halo3mic/suave-playground/blob/9afe269ab2da983ca7314b68fcad00134712f4c0/contracts/blockad/lib/ConfidentialControl.sol), along with a [good example which illustrates its use](https://github.com/halo3mic/suave-playground/blob/9afe269ab2da983ca7314b68fcad00134712f4c0/contracts/blockad/BlockAdV2.sol).
+
+This particular approach, and the reason it currently works in this manner, is being discussed in this [`suave-geth` issue](https://github.com/flashbots/suave-geth/issues/121).
\ No newline at end of file
diff --git a/docs/concepts/confidential-data-storage.mdx b/docs/concepts/confidential-data-storage.mdx
new file mode 100644
index 00000000..902a97d3
--- /dev/null
+++ b/docs/concepts/confidential-data-storage.mdx
@@ -0,0 +1,90 @@
+---
+title: Confidential Data Storage
+description: How to leverage confidential data to your advantage when building on SUAVE
+---
+
+import List from '@site/src/components/List/List.tsx';
+
+## Data Records
+
+Confidential storage works with opaque identifiers, which are generated by Kettles when data is put in storage during offchain/confidential computation. These identifiers are part of an object we call a `DataRecord`, which holds a reference to the data, its ID, who can store and retrieve it, and a few other pieces of metadata.
+
+This is what these DataRecords look like in the [`suave-std` library](https://github.com/flashbots/suave-std/blob/main/src/suavelib/Suave.sol):
+
+```solidity
+ type DataId is bytes16;
+
+ struct DataRecord {
+ DataId id;
+ DataId salt;
+ uint64 decryptionCondition;
+ address[] allowedPeekers;
+ address[] allowedStores;
+ string version;
+ }
+```
+
+## Practical Example
+
+Consider the same [Private OFA Suapp](https://github.com/flashbots/suapp-examples/blob/main/examples/app-ofa-private/ofa-private.sol) from the previous tutorial. The OFA contract needs to accept user transactions, store them, and emit a hint that searchers can use. It then needs to accept backruns from searchers and match those with the user transactions in storage: a task it achieves by means of the `recordId`.
+
+The end-to-end flow looks like this:
+
+
+
+A user submits a transaction they wish to be included in the orderflow auction, calling the `newOrder()` function.
+
+
+
+The contract defines logic which a Kettle can use to get the confidential data, simulate the results of including this transaction, and extract the hint to be shared with searchers.
+
+```solidity
+bytes memory bundleData = Suave.confidentialInputs();
+uint64 egp = Suave.simulateBundle(bundleData);
+bytes memory hint = Suave.extractHint(bundleData);
+```
+
+
+
+
+The contract then sets who can store and "peek" (i.e. retrieve) the data. In this case, both this Private OFA contract and the precompile contract deployed at the address `0x...43200001` are set as **allowedPeekers** and **allowedStores** (though you could have totally different addresses in these arrays in your own use case). If you consult the [`suave-std` library](https://github.com/flashbots/suave-std/blob/main/src/suavelib/Suave.sol), you'll see that the precompile deployed at that address is the `FILL_MEV_SHARE_BUNDLE`, which is what we require for this particular contract.
+
+```solidity
+address[] memory allowedList = new address[](2);
+allowedList[0] = address(this);
+allowedList[1] = 0x0000000000000000000000000000000043200001;
+```
+
+
+
+
+
+Then, we create the `dataRecord`. The `decryptionCondition` is passed in as an argument and can be anything (though `decryptionConditions` will be deprecated soon) and the version is left as a blank string. Then, we write both the transaction itself, and the results from its simulation (in this case, the effective gas price after it is included) into the confidential store at different keys, which we will later use to match bundles and backruns in order to build profitable blocks.
+
+```solidity
+Suave.DataRecord memory dataRecord = Suave.newDataRecord(decryptionCondition, allowedList, allowedList, "");
+Suave.confidentialStore(dataRecord.id, "mevshare:v0:ethBundles", bundleData);
+Suave.confidentialStore(dataRecord.id, "mevshare:v0:ethBundleSimResults", abi.encode(egp));
+```
+
+
+
+
+
+The hint is not directly emitted on chain, as Confidential Compute Requests cannot directly change state, but rather is emitted as a callback once the order has been saved and the hint returned:
+
+```solidity
+return abi.encodeWithSelector(this.emitHint.selector, hintOrder);
+```
+
+
+
+Searchers can then use the information in this event to construct and submit valid backruns, which are matched against the original transactions via the `hintId`.
+
+Matched transactions and backruns are bundled together via the `fillMevShareBundle()` precompile.
+
+These bundles are sent to predefined off chain builders via the `submitBundleJsonRPC()` precompile.
+
+
+
+In this manner, the Confidential Data Store enables you to create applications on chain that can provide features credible pre-trade privacy (and more!) while nevertheless exposing their business logic in a verifiable and contestable manner.
\ No newline at end of file
diff --git a/docs/concepts/index.mdx b/docs/concepts/index.mdx
new file mode 100644
index 00000000..23527758
--- /dev/null
+++ b/docs/concepts/index.mdx
@@ -0,0 +1,36 @@
+---
+title: How SUAVE Extends Solidity
+description: Understand more about SUAVE
+keywords:
+ - explanations
+ - suave
+ - concepts
+---
+
+import List from '@site/src/components/List/List.tsx';
+
+SUAVE gives you, an application developer, a way to:
+
+
Flashbots Suave Forum
-
- Discuss your thoughts and ideas with the community
-
+
Discuss your thoughts and ideas with the community
@@ -189,4 +187,4 @@ You can find us in our [Forum](https://collective.flashbots.net/c/suave/27) and
-
+
\ No newline at end of file
diff --git a/docs/resources/forge.mdx b/docs/resources/forge.mdx
index 6467ef9e..924363a7 100644
--- a/docs/resources/forge.mdx
+++ b/docs/resources/forge.mdx
@@ -3,135 +3,96 @@ title: Forge
description: Use Forge to help develop and test contracts with new precompiles on SUAVE
---
-:::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](/technical/specs/rigil/precompiles) available in any contract. While these are included as a [library](https://github.com/flashbots/suave-geth/blob/main/suave/sol/libraries/Suave.sol) 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.
+SUAVE makes an [extended set of precompiles](/technical/specs/rigil/precompiles) available in any contract.
-[`SuaveForge.sol`](https://github.com/flashbots/suave-geth/blob/main/suave/sol/libraries/SuaveForge.sol) is a Solidity library that implements the same precompiles as `Suave.sol`. The difference is this:
+In order to make interacting with these precompiles easier, we maintain a repository of contracts and libraries called [`suave-std`](https://github.com/flashbots/suave-std).
-- `Suave.sol` is used in the MEVM on the Kettle specified by any CCR
-- `SuaveForge.sol` uses the [ffi](https://book.getfoundry.sh/cheatcodes/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.
+## Suapp examples
-## 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:
+The easiest way to start creating your own contracts with Forge is to clone the [Suapp Examples repo](https://github.com/flashbots/suapp-examples/), as it comes with `suave-std` already set up as a submodule, as well as a series of examples that use both Forge and the Golang SDK.
```bash
-mkdir suave-forge
+git clone git@github.com:flashbots/suave-std.git && cd suapp-examples
```
```bash
-cd suave-forge
+git submodule init && git submodule update
```
-```bash
-forge init
-```
+## Encoding and Decoding Transactions
-```bash
-git submodule init
-```
-
-```bash
-git submodule add https://github.com/flashbots/suave-geth.git
-```
+`suave-std` is intended to implement core functionality that is likely to be used often by many different kinds of Suapps. One such example of this is encoding and decoding transactions from other chains, which you may need to do when matching different transactions in an order flow auction, or turning bundles into (partial) blocks in a block building contract, or weaving together different transactions on different chains for your unique use case.
-## 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:
+Having to encode and decode such transactions is a pain, which is exactly the sort of scenario where `suave-std` can help:
```solidity
-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.DataRecord memory record = SuaveForge.newDataRecord(
- 0,
- addressList,
- addressList,
- "default:v0:ethBundles"
- );
-
- Suave.DataRecord[] memory allShareMatchRecords = SuaveForge.fetchDataRecords(
- 0,
- "default:v0:ethBundles"
- );
- console.log(allShareMatchRecords.length);
-
- SuaveForge.confidentialStore(record.id, "a", abi.encodePacked("bbbbbb"));
- bytes memory result = SuaveForge.confidentialRetrieve(record.id, "a");
- console.logBytes(result);
+import "suave-std/Transactions.sol";
+
+contract Example {
+ function example() {
+ Transactions.Legacy memory legacyTxn0 = Transactions.Legacy({
+ to: address(0x095E7BAea6a6c7c4c2DfeB977eFac326aF552d87),
+ gas: 50000,
+ gasPrice: 10,
+ value: 10,
+ ...
+ });
+
+ // Encode to RLP
+ bytes memory rlp = Transactions.encodeRLP(legacyTxn0);
+
+ // Decode from RLP
+ Transactions.Legacy memory legacyTxn1 = Transactions.decodeRLP(rlp);
}
}
```
-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.
+It can also be difficult to test specific precompiles when using Forge. In order to make this possible, `suave-std` provides a "SUAVE-enabled" test contract, which you can import and use like this:
-In order to deploy this example contract, you need to have [SUAVE running locally](/tutorials/run-suave/), which can be done from your git submodule directory:
+```solidity
+// SPDX-License-Identifier: Unlicense
+pragma solidity ^0.8.13;
-```bash
-cd suave-geth
-```
+import "forge-std/Test.sol";
+import "suave-std/Test.sol";
+import "suave-std/Suave.sol";
-```bash
-make suave
-```
+contract TestForge is Test, SuaveEnabled {
+ address[] public addressList = [0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829];
-```bash
-suave --suave.dev
-```
+ function testConfidentialStore() public {
+ Suave.DataRecord memory record = Suave.newDataRecord(0, addressList, addressList, "namespace");
-Then, run the Forge script with the `ffi` flag enabled:
+ bytes memory value = abi.encode("suave works with forge!");
+ Suave.confidentialStore(record.id, "key1", value);
-```bash
-forge script Example.sol --ffi
+ bytes memory found = Suave.confidentialRetrieve(record.id, "key1");
+ assertEq(keccak256(found), keccak256(value));
+ }
+}
```
-