From be59d8d4f7ea71fbba07102acce06df1ab7d3886 Mon Sep 17 00:00:00 2001 From: brock smedley <2791467+zeroXbrock@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:40:02 -0700 Subject: [PATCH] update examples (#44) * replace goerli w/ holesky in suave examples * replace goerli w/ holesky in suave examples * bun install * chore: format * update demos * updating suave-std * forge install: suave-std * update suave-std * update fn visibility in suave example to enable 'is Suapp' * improve suave-web-demo readme * fix comment * fix suave example; make buildEthBlock work on all eth providers (requires suave-std upgrade) * update suave-std (pin to commit da7ff46042139847cf32ba30afc1e24f4dc0bd86) --------- Co-authored-by: zeroXbrock --- examples/suave-web-demo/README.md | 14 +++++++--- examples/suave-web-demo/src/suave.ts | 2 +- examples/suave/.env.example | 2 +- examples/suave/bids.ts | 6 ++--- examples/suave/contracts/src/OFA.sol | 9 ++++--- examples/suave/index.ts | 38 ++++++++++++++++++---------- 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/examples/suave-web-demo/README.md b/examples/suave-web-demo/README.md index e23c581e..c38dfa4e 100644 --- a/examples/suave-web-demo/README.md +++ b/examples/suave-web-demo/README.md @@ -6,17 +6,25 @@ Simple Vanilla JS web app that sends a mev-share bid to suave. > This project requires a local suave-geth devnet to be running. See [instructions here](https://github.com/flashbots/suave-geth/tree/main?tab=readme-ov-file#starting-a-local-devnet) to spin one up. -Go to the [suave example](../suave/) and run `./deployContracts.sh`: +Start by building the library: ```sh -cd ../suave +# in project root (suave-viem/) +bun install +bun run build +``` + +Next, go to the [suave example](../suave/) and run `./deployContracts.sh`: + +```sh +cd examples/suave ./deployContracts.sh -cd - ``` Next, install the project's dependencies. ```sh +cd ../suave-web-demo bun install ``` diff --git a/examples/suave-web-demo/src/suave.ts b/examples/suave-web-demo/src/suave.ts index fc57f077..845931c4 100644 --- a/examples/suave-web-demo/src/suave.ts +++ b/examples/suave-web-demo/src/suave.ts @@ -82,7 +82,7 @@ export function setupSendBidButton( data: '0xf00ba7' as Hex, } const signedTx = await l1Wallet.signTransaction(sampleTx) - console.log('signed goerli tx', signedTx) + console.log('signed L1 tx', signedTx) // create bid & send ccr const decryptionCondition = 1n + (await l1Provider.getBlockNumber()) diff --git a/examples/suave/.env.example b/examples/suave/.env.example index eca09363..c273dd54 100644 --- a/examples/suave/.env.example +++ b/examples/suave/.env.example @@ -1,4 +1,4 @@ PRIVATE_KEY=0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12 KETTLE_ADDRESS=0xb5feafbdd752ad52afb7e1bd2e40432a485bbb7f SUAVE_RPC_URL_HTTP=http://localhost:8545 -GOERLI_RPC_URL_HTTP=https://ethereum-goerli.publicnode.com +L1_RPC_URL_HTTP=https://ethereum-holesky.publicnode.com diff --git a/examples/suave/bids.ts b/examples/suave/bids.ts index d497153d..8615ed6e 100644 --- a/examples/suave/bids.ts +++ b/examples/suave/bids.ts @@ -40,9 +40,9 @@ export class OFAOrder { return encodeAbiParameters([ { components: [ - { type: 'uint', name: 'blockNumber' }, - { type: 'uint', name: 'minTimestamp' }, - { type: 'uint', name: 'maxTimestamp' }, + { type: 'uint64', name: 'blockNumber' }, + { type: 'uint64', name: 'minTimestamp' }, + { type: 'uint64', name: 'maxTimestamp' }, { type: 'bytes[]', name: 'txns' }, ], name: 'BundleObj', diff --git a/examples/suave/contracts/src/OFA.sol b/examples/suave/contracts/src/OFA.sol index 01bdd97d..74fefd37 100644 --- a/examples/suave/contracts/src/OFA.sol +++ b/examples/suave/contracts/src/OFA.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.8; import "suave-std/suavelib/Suave.sol"; +import "suave-std/Suapp.sol"; import {Bundle} from "suave-std/protocols/Bundle.sol"; import "solady/src/utils/LibString.sol"; -contract OFAPrivate { +contract OFAPrivate is Suapp { // Struct to hold hint-related information for an order. struct HintOrder { Suave.DataId id; @@ -19,11 +20,11 @@ contract OFAPrivate { event Debug(string message, bytes data); // Internal function to save order details and generate a hint. - function saveOrder(uint64 decryptionCondition) internal view returns (HintOrder memory) { + function saveOrder(uint64 decryptionCondition) internal returns (HintOrder memory) { // Retrieve the bundle data from the confidential inputs bytes memory bundleData = Suave.confidentialInputs(); Bundle.BundleObj memory bundle = abi.decode(bundleData, (Bundle.BundleObj)); - bundleData = Bundle.encodeBundle(bundle).body; + bundleData = Bundle.encodeBundleParams(bundle); // Simulate the bundle and extract its score. uint64 egp = Suave.simulateBundle(bundleData); @@ -109,7 +110,7 @@ contract OFAPrivate { return abi.encodeWithSelector(this.emitMatchDataRecordAndHintCallback.selector, response); } - function submitBundle(string memory builderUrl, bytes memory bundleData) internal view returns (bytes memory) { + function submitBundle(string memory builderUrl, bytes memory bundleData) internal returns (bytes memory) { // encode the jsonrpc request in JSON format. bytes memory body = abi.encodePacked('{"jsonrpc":"2.0","method":"mev_sendBundle","params":[', bundleData, '],"id":1}'); diff --git a/examples/suave/index.ts b/examples/suave/index.ts index 37f09afa..26e7d5e3 100644 --- a/examples/suave/index.ts +++ b/examples/suave/index.ts @@ -1,6 +1,6 @@ import { sleep } from 'bun' import { http, Address, Hex, createPublicClient, formatEther, isHex } from 'viem' -import { goerli } from 'viem/chains' +import { holesky } from 'viem/chains' import { TransactionRequestSuave } from 'viem/chains/suave/types' import { OFAOrder } from './bids' import { SuaveProvider, SuaveWallet, getSuaveProvider, getSuaveWallet, parseTransactionSuave } from 'viem/chains/utils' @@ -19,15 +19,15 @@ if (!process.env.KETTLE_ADDRESS) { if (!process.env.SUAVE_RPC_URL_HTTP) { console.warn('SUAVE_RPC_URL_HTTP not set. Defaulting to localhost:8545') } -if (!process.env.GOERLI_RPC_URL_HTTP) { - console.warn('GOERLI_RPC_URL_HTTP not set. Defaulting to localhost:8545') +if (!process.env.L1_RPC_URL_HTTP) { + console.warn('L1_RPC_URL_HTTP not set. Defaulting to localhost:8545') } const KETTLE_ADDRESS: Address = process.env.KETTLE_ADDRESS as Address const PRIVATE_KEY: Hex = process.env.PRIVATE_KEY as Hex const SUAVE_RPC_URL_HTTP: string = process.env.SUAVE_RPC_URL_HTTP || 'http://localhost:8545' -const GOERLI_RPC_URL_HTTP: string = - process.env.GOERLI_RPC_URL_HTTP || 'http://localhost:8545' +const L1_RPC_URL_HTTP: string = + process.env.L1_RPC_URL_HTTP || 'http://localhost:8555' if (!BidContractDeployment.address) { console.error( @@ -42,9 +42,9 @@ if (!isHex(BidContractDeployment.address)) { const BID_CONTRACT_ADDRESS = BidContractDeployment.address as Hex const suaveProvider: SuaveProvider = getSuaveProvider(http(SUAVE_RPC_URL_HTTP)) -const goerliProvider = createPublicClient({ - chain: goerli, - transport: http(GOERLI_RPC_URL_HTTP), +const l1Provider = createPublicClient({ + chain: holesky, + transport: http(L1_RPC_URL_HTTP), }) const adminWallet: SuaveWallet = getSuaveWallet({ transport: http(SUAVE_RPC_URL_HTTP), @@ -52,7 +52,7 @@ const adminWallet: SuaveWallet = getSuaveWallet({ }) const wallet = getSuaveWallet({ transport: http(SUAVE_RPC_URL_HTTP), - privateKey: '0x01000070530220062104600650003002001814120800043ff33603df10300012', + privateKey: "0x6c45335a22461ccdb978b78ab61b238bad2fae4544fb55c14eb096c875ccfc52", }) console.log('admin', adminWallet.account.address) console.log('wallet', wallet.account.address) @@ -90,10 +90,19 @@ const fundAccount = async (wallet: Address, amount: bigint) => { } return await adminWallet.sendTransaction(tx) } else { - console.log(`wallet balance: ${formatEther(balance)} ETH`) + console.log(`SUAVE wallet balance: ${formatEther(balance)} ETH`) } } +async function checkL1Balance(minBalance?: bigint) { + const balance = await l1Provider.getBalance({ address: wallet.account.address }) + const absoluteMin = minBalance || 1n + if (balance < absoluteMin) { + throw new Error(`L1 balance too low: ${formatEther(balance)} ETH (needed ${formatEther(absoluteMin)}).\nPlease fund this account: ${wallet.account.address}`) + } + console.log(`L1 balance: ${formatEther(balance)} ETH`) +} + /** MEV-Share implementation on SUAVE. * * To run this, you'll need to deploy the contract first. @@ -107,18 +116,21 @@ async function testSuaveBids() { ) fundRes && console.log('fundRes', fundRes) - // a tx that should be landed on goerli + // a tx that should be landed on L1 const testTx = { to: '0x0000000000000000000000000000000000000000' as Address, data: '0x686f776479' as Hex, gas: 26000n, gasPrice: 10000000000n, - chainId: 5, + chainId: 17000, } + checkL1Balance(testTx.gas * testTx.gasPrice) const signedTx = await wallet.signTransaction(testTx) + console.log("signed tx", signedTx) + // create bid & send ccr - const block = await goerliProvider.getBlockNumber() + const block = await l1Provider.getBlockNumber() const bid = new OFAOrder( block + 1n, signedTx,