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); + } +} +``` diff --git a/examples/tx-observability/main.go b/examples/tx-observability/main.go new file mode 100644 index 0000000..237c96e --- /dev/null +++ b/examples/tx-observability/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "log" + + "github.com/ethereum/go-ethereum/common" + "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") + } + + var event SentTransactionsEvent + err := suappContract.Abi.UnpackIntoInterface(&event, "SentTransactions", res.Logs[0].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)