Skip to content

Commit

Permalink
Add example of a suapp storing and using a private key (#48)
Browse files Browse the repository at this point in the history
* Add example of a suapp storing and using a private key

* Enable examples in integration
  • Loading branch information
ferranbt authored Apr 2, 2024
1 parent 3642764 commit e255f95
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,13 @@ devnet-down:
run-integration:
go run examples/build-eth-block/main.go
go run examples/mevm-confidential-store/main.go
go run examples/mevm-context/main.go
go run examples/mevm-is-confidential/main.go
go run examples/onchain-callback/main.go
go run examples/onchain-state/main.go
go run examples/offchain-logs/main.go
go run examples/mevm-context/main.go
go run examples/private-library/main.go
go run examples/private-library-confidential-store/main.go
go run examples/private-suapp-key/main.go
go run examples/std-transaction-signing/main.go
17 changes: 17 additions & 0 deletions examples/private-suapp-key/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Example Suapp with a stored private key

This example shows how Suapps can store private keys in the confidential storage to be used in multiple confidential requests.

## How to use

Run `Suave` in development mode:

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

Execute the deployment script:

```
$ go run main.go
```
33 changes: 33 additions & 0 deletions examples/private-suapp-key/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"encoding/hex"
"log"

"github.com/flashbots/suapp-examples/framework"
)

func main() {
fr := framework.New()

priv := "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"

contract := fr.Suave.DeployContract("private-suapp-key.sol/PublicSuapp.json")
contract.SendConfidentialRequest("registerPrivateKey", nil, []byte(priv))

receipt := contract.SendConfidentialRequest("example", nil, nil)

// validate the signature
txnSignatureEvent, err := contract.Abi.Events["TxnSignature"].ParseLog(receipt.Logs[0])
if err != nil {
log.Fatal(err)
}
var r, s = txnSignatureEvent["r"].([32]byte), txnSignatureEvent["s"].([32]byte)

if hex.EncodeToString(r[:]) != "eebcfac0def6db5649d0ae6b52ed3b8ba1f5c6c428588df125461113ba8c6749" {
log.Fatal("wrong r signature")
}
if hex.EncodeToString(s[:]) != "5d5e1aafa0c964b43c251b6a525d49572968f2cebc5868c58bcc9281b9a07505" {
log.Fatal("wrong s signature")
}
}
53 changes: 53 additions & 0 deletions examples/private-suapp-key/private-suapp-key.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.8;

import "suave-std/suavelib/Suave.sol";
import "suave-std/Context.sol";
import "suave-std/Suapp.sol";
import "suave-std/Transactions.sol";

contract PublicSuapp is Suapp {
Suave.DataId signingKeyBid;
string public KEY_PRIVATE_KEY = "KEY";

// onchain-offchain pattern to register the new private key in the Confidential storage
function updateKeyCallback(Suave.DataId _signingKeyBid) public {
signingKeyBid = _signingKeyBid;
}

function registerPrivateKey() public returns (bytes memory) {
bytes memory keyData = Context.confidentialInputs();

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

Suave.DataRecord memory bid = Suave.newDataRecord(10, peekers, peekers, "private_key");
Suave.confidentialStore(bid.id, KEY_PRIVATE_KEY, keyData);

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

// offchain-onchain pattern to sign a transaction using the private key stored in the Suapp
event TxnSignature(bytes32 r, bytes32 s);

function exampleCallback() public emitOffchainLogs {}

function example() public returns (bytes memory) {
bytes memory signingKey = Suave.confidentialRetrieve(signingKeyBid, KEY_PRIVATE_KEY);

Transactions.EIP155Request memory txnWithToAddress = Transactions.EIP155Request({
to: address(0x00000000000000000000000000000000DeaDBeef),
gas: 1000000,
gasPrice: 500,
value: 1,
nonce: 1,
data: bytes(""),
chainId: 1337
});

Transactions.EIP155 memory txn = Transactions.signTxn(txnWithToAddress, string(signingKey));
emit TxnSignature(txn.r, txn.s);

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

0 comments on commit e255f95

Please sign in to comment.