diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index a6c7e6a0..10cc6706 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -123,4 +123,48 @@ jobs: - name: Run test vectors shell: bash - run: bun run vectors \ No newline at end of file + run: bun run vectors + + suave-examples: + name: Suave Examples + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Check out suave-geth + uses: actions/checkout@v3 + with: + repository: flashbots/suave-geth + path: suave-geth-clone + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run dev env + working-directory: suave-geth-clone + run: docker compose -f ./suave/e2e/docker-compose.yml up -d --build + + - name: Install JS dependencies + uses: ./.github/actions/install-dependencies + + - name: Build suave-viem + run: bun run build + + - name: Install suave contract dependencies + shell: bash + working-directory: examples/suave/contracts + run: forge install + + - name: Install suave example dependencies + working-directory: examples/suave + run: bun install + + - name: Run example + working-directory: examples/suave + shell: bash + run: | + ./deployContracts.sh + export PRIVATE_KEY=0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12 + export SUAVE_RPC_URL_HTTP=http://0.0.0.0:8545 + export L1_RPC_URL_HTTP=http://0.0.0.0:8555 + export L1_CHAIN_ID=1337 + bun run index.ts diff --git a/examples/suave/.env.example b/examples/suave/.env.example index c273dd54..315c1a1c 100644 --- a/examples/suave/.env.example +++ b/examples/suave/.env.example @@ -2,3 +2,4 @@ PRIVATE_KEY=0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12 KETTLE_ADDRESS=0xb5feafbdd752ad52afb7e1bd2e40432a485bbb7f SUAVE_RPC_URL_HTTP=http://localhost:8545 L1_RPC_URL_HTTP=https://ethereum-holesky.publicnode.com +L1_CHAIN_ID=17000 diff --git a/examples/suave/README.md b/examples/suave/README.md index 27d46b58..5c5819ed 100644 --- a/examples/suave/README.md +++ b/examples/suave/README.md @@ -1,6 +1,10 @@ # suave example -## setup .env +This example assumes you're running a suave-geth devnet instance locally. See [suave docs](https://suave-alpha.flashbots.net/tutorials/run-suave) for instructions. + +## setup environment + +Use a .env file or populate your shell's environment with the variables in `.env.example`. ```sh cp .env.example .env @@ -8,6 +12,12 @@ cp .env.example .env vim .env ``` +Note: a `.env` file will take precedence over variables set in your environment, such as this: + +```sh +export PRIVATE_KEY=0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12 +``` + ## deploy contracts We use a bash script to deploy our contracts and save the address for use in other examples. diff --git a/examples/suave/index.ts b/examples/suave/index.ts index 5ed51c37..df69f474 100644 --- a/examples/suave/index.ts +++ b/examples/suave/index.ts @@ -1,33 +1,45 @@ import { sleep } from 'bun' -import { http, Address, Hex, createPublicClient, formatEther, isHex } from '@flashbots/suave-viem' -import { holesky, suaveRigil } from '@flashbots/suave-viem/chains' +import { http, Address, Hex, createPublicClient, createWalletClient, Chain, formatEther, isHex } from '@flashbots/suave-viem' +import { privateKeyToAccount } from '@flashbots/suave-viem/accounts' +import { suaveRigil } from '@flashbots/suave-viem/chains' import { TransactionRequestSuave } from '@flashbots/suave-viem/chains/utils' import { OFAOrder } from './bids' import { SuaveProvider, SuaveWallet, getSuaveProvider, getSuaveWallet, parseTransactionSuave } from '@flashbots/suave-viem/chains/utils' import { HttpTransport } from '@flashbots/suave-viem' import BidContractDeployment from './deployedAddress.json' +const DEFAULT_KETTLE_ADDRESS = '0xb5feafbdd752ad52afb7e1bd2e40432a485bbb7f' as Address +const DEFAULT_SUAVE_RPC_URL_HTTP = 'http://localhost:8545' +const DEFAULT_L1_RPC_URL_HTTP = 'http://localhost:8555' +const DEFAULT_L1_CHAIN_ID = 17000 + const failEnv = (name: string) => { throw new Error(`missing env var ${name}`) } + if (!process.env.PRIVATE_KEY) { failEnv('PRIVATE_KEY') } + if (!process.env.KETTLE_ADDRESS) { - failEnv('KETTLE_ADDRESS') + console.warn(`KETTLE_ADDRESS not set. Defaulting to ${DEFAULT_KETTLE_ADDRESS}`) } + if (!process.env.SUAVE_RPC_URL_HTTP) { - console.warn('SUAVE_RPC_URL_HTTP not set. Defaulting to localhost:8545') + console.warn(`SUAVE_RPC_URL_HTTP not set. Defaulting to ${DEFAULT_SUAVE_RPC_URL_HTTP}`) } + if (!process.env.L1_RPC_URL_HTTP) { - console.warn('L1_RPC_URL_HTTP not set. Defaulting to localhost:8545') + console.warn(`L1_RPC_URL_HTTP not set. Defaulting to ${DEFAULT_L1_RPC_URL_HTTP}`) } -const KETTLE_ADDRESS: Address = process.env.KETTLE_ADDRESS as Address +const KETTLE_ADDRESS: Address = process.env.KETTLE_ADDRESS as Address || DEFAULT_KETTLE_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 L1_RPC_URL_HTTP: string = process.env.L1_RPC_URL_HTTP || 'http://localhost:8555' +const L1_PRIVATE_KEY: Hex = '0x6c45335a22461ccdb978b78ab61b238bad2fae4544fb55c14eb096c875ccfc52' +const L1_CHAIN_ID: number = process.env.L1_CHAIN_ID ? parseInt(process.env.L1_CHAIN_ID) : DEFAULT_L1_CHAIN_ID if (!BidContractDeployment.address) { console.error( @@ -41,9 +53,14 @@ if (!isHex(BidContractDeployment.address)) { } const BID_CONTRACT_ADDRESS = BidContractDeployment.address as Hex +const localhostChain = { + name: 'localhost', + id: L1_CHAIN_ID, // chainId suave expects (note this is not necessarily the actual chainId of the L1 chain; results may vary by testing environment) +} as Chain + const suaveProvider: SuaveProvider = getSuaveProvider(http(SUAVE_RPC_URL_HTTP)) const l1Provider = createPublicClient({ - chain: holesky, + chain: localhostChain, transport: http(L1_RPC_URL_HTTP), }) const adminWallet: SuaveWallet = getSuaveWallet({ @@ -56,6 +73,11 @@ const wallet = getSuaveWallet({ privateKey: PRIVATE_KEY, chain: suaveRigil, }) +const l1Wallet = createWalletClient({ + account: privateKeyToAccount(L1_PRIVATE_KEY), + transport: http(L1_RPC_URL_HTTP), + chain: localhostChain, +}) console.log('admin', adminWallet.account.address) console.log('wallet', wallet.account.address) console.log('wallet chain id', wallet.chain.id) @@ -90,6 +112,7 @@ const fundAccount = async (wallet: Address, amount: bigint) => { gasPrice: 10000000000n, gas: 21000n, to: wallet, + kettleAddress: KETTLE_ADDRESS, } return await adminWallet.sendTransaction(tx) } else { @@ -116,9 +139,8 @@ async function testSuaveBids() { data: '0x686f776479' as Hex, gas: 26000n, gasPrice: 10000000000n, - type: '0x0' as const, } - const signedTx = await wallet.signTransaction(testTx) + const signedTx = await l1Wallet.signTransaction(testTx) console.log("signed tx", signedTx)