Skip to content

Commit

Permalink
Add private library from confidential store
Browse files Browse the repository at this point in the history
  • Loading branch information
ferranbt committed Dec 12, 2023
1 parent 6c99c68 commit 02f68c4
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
20 changes: 20 additions & 0 deletions examples/private-library-confidential-store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

# Example Suapp with a Private library

This example shows how Suapps can use private libraries stored in the confidential store that are not public in the Suave chain.

The private code is saved in the confidential store with the `registerContract` function. The function receives the bytecode as confidential inputs such that the code is not leaked. Then, when the `example` function is called, it retrieves the library from the confidential stores and deploys it on-runtime. Note that this library is volatile and only visible as part of the confidential request, its bytecode and changes in the storage variables are never saved on-chain.

## How to use

Run `Suave` in development mode:

```
$ suave --suave.dev
```

Execute the deployment script:

```
$ go run main.go
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
pragma solidity ^0.8.8;

import "../../suave-geth/suave/sol/libraries/Suave.sol";

contract PublicSuapp {
event ContractRegistered (
Suave.BidId bidId
);

function registerContractCallback(Suave.BidId bidId) public payable {
emit ContractRegistered(bidId);
}

function registerContract() public payable returns (bytes memory) {
bytes memory bytecode = Suave.confidentialInputs();

address[] memory allowedList = new address[](1);
allowedList[0] = address(this);

Suave.Bid memory bid = Suave.newBid(0, allowedList, allowedList, "contract");
Suave.confidentialStore(bid.id, "bytecode", bytecode);

return abi.encodeWithSelector(this.registerContractCallback.selector, bid.id);
}

function exampleCallback() public {
}

function example(Suave.BidId bidId) public payable returns (bytes memory) {
bytes memory bytecode = Suave.confidentialRetrieve(bidId, "bytecode");
address addr = deploy(bytecode);

PrivateLibraryI c = PrivateLibraryI(addr);
uint256 result = c.add(1, 2);
require(result == 3);

return abi.encodeWithSelector(this.exampleCallback.selector);
}

function deploy(bytes memory _code) internal returns (address addr) {
assembly {
// create(v, p, n)
// v = amount of ETH to send
// p = pointer in memory to start of code
// n = size of code
addr := create(callvalue(), add(_code, 0x20), mload(_code))
}
// return address 0 on error
require(addr != address(0), "deploy failed");
}
}

interface PrivateLibraryI {
function add(uint256 a, uint256 b) external pure returns (uint256);
}

contract PrivateLibrary {
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a+b;
}
}
28 changes: 28 additions & 0 deletions examples/private-library-confidential-store/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/flashbots/suapp-examples/framework"
)

func main() {
privateLibrary, _ := framework.ReadArtifact("lib-confidential-store.sol/PrivateLibrary.json")

fr := framework.New()
suapp := fr.DeployContract("lib-confidential-store.sol/PublicSuapp.json")

// Deploy the contract and get the bid id
receipt := suapp.SendTransaction("registerContract", nil, privateLibrary.Code)
event, _ := contractRegisteredABI.Inputs.Unpack(receipt.Logs[0].Data)
privateContractBidId := event[0].([16]byte)

// Use the private contract
suapp.SendTransaction("example", []interface{}{privateContractBidId}, nil)
}

var contractRegisteredABI abi.Event

func init() {
artifact, _ := framework.ReadArtifact("lib-confidential-store.sol/PublicSuapp.json")
contractRegisteredABI = artifact.Abi.Events["ContractRegistered"]
}

0 comments on commit 02f68c4

Please sign in to comment.