From 10ecca85780f8a6444c1c690c373bb1c7456adaa Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Wed, 22 May 2024 16:13:34 -0700 Subject: [PATCH 1/3] add tx observability example --- examples/tx-observability/main.go | 35 +++++++++++++++++++++ examples/tx-observability/observability.sol | 29 +++++++++++++++++ framework/framework.go | 2 -- 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 examples/tx-observability/main.go create mode 100644 examples/tx-observability/observability.sol diff --git a/examples/tx-observability/main.go b/examples/tx-observability/main.go new file mode 100644 index 0000000..0d719df --- /dev/null +++ b/examples/tx-observability/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "log" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/flashbots/suapp-examples/framework" +) + +// SentTransactionsEvent is emitted by SUAPPs to indicate that the SUAPP sent some transactions to L1. +type SentTransactionsEvent struct { + TxHashes []common.Hash `abi:"txHashes"` +} + +func main() { + fr := framework.New(framework.WithL1()) + suappContract := fr.Suave.DeployContract("observability.sol/Suapp.json") + + res := suappContract.SendConfidentialRequest("doSomethingWithTxs", nil, nil) + if res.Status != 1 { + log.Fatal("confidential request failed") + } + + logEntry := types.Log{ + Data: res.Logs[0].Data, + Topics: res.Logs[0].Topics, + } + var event SentTransactionsEvent + err := suappContract.Abi.UnpackIntoInterface(&event, "SentTransactions", logEntry.Data) + if err != nil { + log.Fatalf("Failed to unpack log data: %v", err) + } + log.Printf("logged tx hashes: %v", event.TxHashes) +} diff --git a/examples/tx-observability/observability.sol b/examples/tx-observability/observability.sol new file mode 100644 index 0000000..6f9e642 --- /dev/null +++ b/examples/tx-observability/observability.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "suave-std/suavelib/Suave.sol"; + +// This could be added to suave-std so that all SUAPPs can use it. +abstract contract TxSender { + event SentTransactions(bytes32[] txHashes); +} + +contract Suapp is TxSender { + modifier confidential() { + require(Suave.isConfidential(), "must be called confidentially"); + _; + } + + function didSomethingWithTxs(bytes32[] memory txHashes) public confidential { + emit SentTransactions(txHashes); + } + + function doSomethingWithTxs() public confidential returns (bytes memory) { + // pretend these are tx hashes that we're handling in our SUAPP + bytes32[] memory txHashes = new bytes32[](3); + for (uint256 i = 0; i < txHashes.length; i++) { + txHashes[i] = keccak256(abi.encode("tx", i)); + } + return abi.encodeWithSelector(this.didSomethingWithTxs.selector, txHashes); + } +} diff --git a/framework/framework.go b/framework/framework.go index b11d995..f22a030 100644 --- a/framework/framework.go +++ b/framework/framework.go @@ -163,8 +163,6 @@ func (c *Contract) SendConfidentialRequest(method string, args []interface{}, co panic(err) } - log.Printf("transaction hash: %s", txnResult.Hash().Hex()) - receipt, err := txnResult.Wait() if err != nil { panic(err) From 7bf49e58ae4327158f6a5028cbc1cb68fc716192 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Wed, 22 May 2024 16:18:56 -0700 Subject: [PATCH 2/3] remove useless code --- examples/tx-observability/main.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/tx-observability/main.go b/examples/tx-observability/main.go index 0d719df..237c96e 100644 --- a/examples/tx-observability/main.go +++ b/examples/tx-observability/main.go @@ -4,7 +4,6 @@ import ( "log" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/flashbots/suapp-examples/framework" ) @@ -22,12 +21,8 @@ func main() { log.Fatal("confidential request failed") } - logEntry := types.Log{ - Data: res.Logs[0].Data, - Topics: res.Logs[0].Topics, - } var event SentTransactionsEvent - err := suappContract.Abi.UnpackIntoInterface(&event, "SentTransactions", logEntry.Data) + err := suappContract.Abi.UnpackIntoInterface(&event, "SentTransactions", res.Logs[0].Data) if err != nil { log.Fatalf("Failed to unpack log data: %v", err) } From 4a56b0c7273a5152263c937c9d1eb61d85fe95b0 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Wed, 22 May 2024 16:59:10 -0700 Subject: [PATCH 3/3] add readme --- examples/tx-observability/README.md | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 examples/tx-observability/README.md diff --git a/examples/tx-observability/README.md b/examples/tx-observability/README.md new file mode 100644 index 0000000..3cb3ab9 --- /dev/null +++ b/examples/tx-observability/README.md @@ -0,0 +1,38 @@ +# tx observability + +Opt into a standardized set of events ([TBD](https://github.com/flashbots/suave-std/pull/85)) to enable interoperability with other SUAPPS, block-builders, L2 networks, etc. + +Events are defined in an abstract contract (ideally in suave-std): + +```solidity +abstract contract ObservableOrderflow { + event SentTransaction(bytes32 txHash); +} +``` + +Then SUAPP developers import and emit those events in their own callbacks: + +```solidity +contract Suapp is ObservableOrderflow { + event MySuappEvent(uint256 x); + + modifier confidential() { + require(Suave.isConfidential(), "must be called confidentially"); + _; + } + + function didSomething(bytes32[] memory txHashes, uint256 x) public confidential { + emit MySuappEvent(x); + emit SentTransactions(txHashes); + } + + function doSomething() public confidential returns (bytes memory) { + // pretend these are tx hashes that we're handling in our SUAPP + bytes32[] memory txHashes = new bytes32[](3); + for (uint256 i = 0; i < txHashes.length; i++) { + txHashes[i] = keccak256(abi.encode("tx", i)); + } + return abi.encodeWithSelector(this.didSomethingWithTxs.selector, txHashes, 9001); + } +} +```