From a32aa32e6d2ec22fa5c4a807a61a1bdbe3cf6240 Mon Sep 17 00:00:00 2001 From: brock smedley <2791467+zeroXbrock@users.noreply.github.com> Date: Wed, 31 Jul 2024 04:40:24 -0700 Subject: [PATCH] Toliman chain details (#58) * add toliman definitions * linter * detect localhost in customRpc, use rigil/toliman chain defs accordingly * lint * require chainId for formatter, harden prepareTxRequest return type * lint * chore: format * tighten type type from prepareTxRequest * lint --------- Co-authored-by: zeroXbrock --- examples/suave-web-demo/src/main.ts | 6 +- examples/suave-web-demo/src/suave.ts | 12 +-- examples/suave/bids.ts | 5 +- examples/suave/deployContracts.sh | 2 +- examples/suave/index.ts | 29 +++----- src/README.md | 4 +- .../definitions/{suaveRigil.ts => suave.ts} | 60 +++++++++++---- src/chains/index.ts | 2 +- src/chains/suave/formatters.test.ts | 33 +++++---- src/chains/suave/formatters.ts | 6 +- src/chains/suave/parsers.test.ts | 6 +- src/chains/suave/wallet.ts | 73 ++++++++++++++----- 12 files changed, 146 insertions(+), 92 deletions(-) rename src/chains/definitions/{suaveRigil.ts => suave.ts} (63%) diff --git a/examples/suave-web-demo/src/main.ts b/examples/suave-web-demo/src/main.ts index 6c6af0c0..c9f29c70 100644 --- a/examples/suave-web-demo/src/main.ts +++ b/examples/suave-web-demo/src/main.ts @@ -40,15 +40,11 @@ setupConnectButton(document.querySelector('#connect')!, jsonRpcAccount: account, transport: custom(ethereum), customRpc: SUAVE_RPC_URL_HTTP, + chain: suaveRigil, }) console.log(suaveWallet) const suaveProvider = getSuaveProvider(http(SUAVE_RPC_URL_HTTP)) suaveProvider.getBalance({ address: account }).then((balance: any) => { - suaveProvider.getChainId().then((chainId: any) => { - if (chainId !== suaveRigil.id) { - alert(`wrong chain id. expected ${suaveRigil.id}, got ${chainId}`) - } - }) document.querySelector('#status-content')!.innerHTML = `

SUAVE-ETH balance: ${formatEther(balance)}

diff --git a/examples/suave-web-demo/src/suave.ts b/examples/suave-web-demo/src/suave.ts index 845931c4..0cab542e 100644 --- a/examples/suave-web-demo/src/suave.ts +++ b/examples/suave-web-demo/src/suave.ts @@ -6,7 +6,7 @@ import { http, } from 'viem' import { privateKeyToAccount } from 'viem/accounts' -import { suaveRigil, holesky } from 'viem/chains' +import { holesky as l1Chain, suaveRigil } from 'viem/chains' import { OFAOrder } from '../../suave/bids' import { getSuaveWallet } from 'viem/chains/utils' import BidContractDeployment from '../../suave/deployedAddress.json' @@ -15,23 +15,24 @@ import BidContractDeployment from '../../suave/deployedAddress.json' const KETTLE_ADDRESS: Address = '0xb5feafbdd752ad52afb7e1bd2e40432a485bbb7f' const ADMIN_KEY: Hex = '0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12' -export const L1_RPC_URL_HTTP: string = 'https://holesky.rigil.suave.flashbots.net' +export const L1_RPC_URL_HTTP: string = 'https://holesky.toliman.suave.flashbots.net' export const SUAVE_RPC_URL_HTTP: string = 'http://localhost:8545' const l1Wallet = createWalletClient({ account: privateKeyToAccount( '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', ), - chain: holesky, + chain: l1Chain, transport: http(L1_RPC_URL_HTTP), }) const l1Provider = createPublicClient({ - chain: holesky, + chain: l1Chain, transport: http(L1_RPC_URL_HTTP), }) const suaveAdminWallet = getSuaveWallet({ privateKey: ADMIN_KEY, transport: http(SUAVE_RPC_URL_HTTP), + chain: suaveRigil, }) /** Sets up "connect to wallet" button and holds wallet instance. */ @@ -43,7 +44,6 @@ export function setupConnectButton( let account = null element.innerHTML = 'connect to wallet' - console.log(suaveRigil.id) const setConnected = async (ethereum: any) => { if (connected) return element.innerHTML = `connecting to ${connected}` @@ -85,7 +85,7 @@ export function setupSendBidButton( console.log('signed L1 tx', signedTx) // create bid & send ccr - const decryptionCondition = 1n + (await l1Provider.getBlockNumber()) + const decryptionCondition = (await l1Provider.getBlockNumber()) console.log("decryptionCondition", decryptionCondition) const bid = new OFAOrder( decryptionCondition, diff --git a/examples/suave/bids.ts b/examples/suave/bids.ts index 8615ed6e..26cac976 100644 --- a/examples/suave/bids.ts +++ b/examples/suave/bids.ts @@ -3,8 +3,8 @@ import { Hex, encodeAbiParameters, encodeFunctionData, -} from 'viem' -import { TransactionRequestSuave } from 'viem/chains/suave/types' +} from '@flashbots/suave-viem' +import { TransactionRequestSuave } from '@flashbots/suave-viem/chains/utils' import OFAContract from './contracts/out/OFA.sol/OFAPrivate.json' /** Factory class to create MEV-Share bids on SUAVE. */ @@ -61,6 +61,7 @@ export class OFAOrder { to: this.OFAContract, data: this.newOrderCalldata(), isEIP712, + gas: 10000000n, kettleAddress: this.kettle, confidentialInputs: this.confidentialInputsBytes(), } diff --git a/examples/suave/deployContracts.sh b/examples/suave/deployContracts.sh index b7c920fe..19527dbb 100755 --- a/examples/suave/deployContracts.sh +++ b/examples/suave/deployContracts.sh @@ -4,7 +4,7 @@ FUNDED_PRV_KEY=0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce1 SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) cd $SCRIPT_DIR/contracts forge build -createOutput=$(forge create --legacy --private-key $FUNDED_PRV_KEY --chain-id 16813125 -r http://localhost:8545 src/OFA.sol:OFAPrivate) +createOutput=$(forge create --legacy --private-key $FUNDED_PRV_KEY -r http://localhost:8545 src/OFA.sol:OFAPrivate) deployedAddress=$(echo "$createOutput" | grep 'Deployed to:' | awk '{print $3}') echo "Deployed to: $deployedAddress" echo '{"address": ''"'$deployedAddress'"}' > $SCRIPT_DIR/deployedAddress.json diff --git a/examples/suave/index.ts b/examples/suave/index.ts index 26e7d5e3..5ed51c37 100644 --- a/examples/suave/index.ts +++ b/examples/suave/index.ts @@ -1,10 +1,10 @@ import { sleep } from 'bun' -import { http, Address, Hex, createPublicClient, formatEther, isHex } from 'viem' -import { holesky } from 'viem/chains' -import { TransactionRequestSuave } from 'viem/chains/suave/types' +import { http, Address, Hex, createPublicClient, formatEther, isHex } from '@flashbots/suave-viem' +import { holesky, 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 'viem/chains/utils' -import { HttpTransport } from 'viem' +import { SuaveProvider, SuaveWallet, getSuaveProvider, getSuaveWallet, parseTransactionSuave } from '@flashbots/suave-viem/chains/utils' +import { HttpTransport } from '@flashbots/suave-viem' import BidContractDeployment from './deployedAddress.json' const failEnv = (name: string) => { @@ -48,14 +48,17 @@ const l1Provider = createPublicClient({ }) const adminWallet: SuaveWallet = getSuaveWallet({ transport: http(SUAVE_RPC_URL_HTTP), - privateKey: PRIVATE_KEY, + privateKey: PRIVATE_KEY, + chain: suaveRigil, }) const wallet = getSuaveWallet({ transport: http(SUAVE_RPC_URL_HTTP), - privateKey: "0x6c45335a22461ccdb978b78ab61b238bad2fae4544fb55c14eb096c875ccfc52", + privateKey: PRIVATE_KEY, + chain: suaveRigil, }) console.log('admin', adminWallet.account.address) console.log('wallet', wallet.account.address) +console.log('wallet chain id', wallet.chain.id) const retryExceptionsWithTimeout = async ( timeout_ms: number, @@ -94,15 +97,6 @@ const fundAccount = async (wallet: Address, amount: bigint) => { } } -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. @@ -122,9 +116,8 @@ async function testSuaveBids() { data: '0x686f776479' as Hex, gas: 26000n, gasPrice: 10000000000n, - chainId: 17000, + type: '0x0' as const, } - checkL1Balance(testTx.gas * testTx.gasPrice) const signedTx = await wallet.signTransaction(testTx) console.log("signed tx", signedTx) diff --git a/src/README.md b/src/README.md index de19838e..21f95015 100644 --- a/src/README.md +++ b/src/README.md @@ -70,7 +70,7 @@ First, see these instructions for spinning up a local devnet. Then install **[@f ```ts import { http, type Hex } from '@flashbots/suave-viem'; -import { suaveRigil } from '@flashbots/suave-viem/chains'; +import { suaveToliman as suaveChain } from '@flashbots/suave-viem/chains'; import { getSuaveProvider, getSuaveWallet, @@ -115,7 +115,7 @@ const ccr: TransactionRequestSuave = { gasPrice: 10000000000n, // Gas price for the transaction gas: 420000n, // Gas limit for the transaction type: SuaveTxRequestTypes.ConfidentialRequest, // (0x43) - chainId: suaveRigil.id, + chainId: suaveChain.id, data: '0x236eb5a70000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008f21fdd6b4f4cacd33151777a46c122797c8bf170000000000000000000000000000000000000000000000000000000000000000', }; diff --git a/src/chains/definitions/suaveRigil.ts b/src/chains/definitions/suave.ts similarity index 63% rename from src/chains/definitions/suaveRigil.ts rename to src/chains/definitions/suave.ts index afe90303..8ff3cfda 100644 --- a/src/chains/definitions/suaveRigil.ts +++ b/src/chains/definitions/suave.ts @@ -2,34 +2,42 @@ import type { Address } from 'abitype' import { defineChain } from '../../utils/chain.js' import { formattersSuave } from '../suave/formatters.js' -const testnetUrlHttp = 'https://rpc.rigil.suave.flashbots.net' -const testnetUrlWs = 'wss://rpc.rigil.suave.flashbots.net' -const testnetExplorerUrl = 'https://rpc.rigil.suave.flashbots.net' +const suaveChainConfig = ({ + networkName, + chainId, + currencySymbol, +}: { networkName: string; chainId: number; currencySymbol: string }) => { + const networkNamePascal = `${networkName[0].toUpperCase()}${networkName.substring( + 1, + )}` + const networkRpc = `rpc.${networkName}.suave.flashbots.net` + const networkUrlHttp = `https://${networkRpc}` + const networkUrlWs = `wss://${networkRpc}` + const explorerUrl = `https://explorer.${networkName}.suave.flashbots.net/` -export const suaveRigil = /*#__PURE__*/ defineChain( - { - id: 16813125, - name: 'Suave Rigil Testnet', - network: 'rigil-testnet', + return { + id: chainId, + name: `Suave ${networkNamePascal} Testnet`, + network: `${networkName}-testnet`, nativeCurrency: { decimals: 18, - name: 'Suave Goerli', - symbol: 'ETH', + name: `${networkNamePascal} ETH`, + symbol: currencySymbol, }, rpcUrls: { default: { - http: [testnetUrlHttp], - webSocket: [testnetUrlWs], + http: [networkUrlHttp], + webSocket: [networkUrlWs], }, public: { - http: [testnetUrlHttp], - webSocket: [testnetUrlWs], + http: [networkUrlHttp], + webSocket: [networkUrlWs], }, }, blockExplorers: { default: { - name: 'SUAVE Rigil Explorer', - url: testnetExplorerUrl, + name: `SUAVE ${networkNamePascal} Explorer`, + url: explorerUrl, }, }, contracts: { @@ -80,7 +88,27 @@ export const suaveRigil = /*#__PURE__*/ defineChain( }, }, testnet: true, + } +} + +export const suaveToliman = /*#__PURE__*/ defineChain( + suaveChainConfig({ + networkName: 'toliman', + chainId: 33626250, + currencySymbol: 'TEETH', + }), + { + formatters: formattersSuave, + // serializers: serializersSuave, }, +) + +export const suaveRigil = /*#__PURE__*/ defineChain( + suaveChainConfig({ + networkName: 'rigil', + chainId: 16813125, + currencySymbol: 'RETH', + }), { formatters: formattersSuave, // serializers: serializersSuave, diff --git a/src/chains/index.ts b/src/chains/index.ts index 4570e384..b600e119 100644 --- a/src/chains/index.ts +++ b/src/chains/index.ts @@ -124,7 +124,7 @@ export { skaleTitanTestnet } from './definitions/skale/titanTestnet.js' export { songbird } from './definitions/songbird.js' export { songbirdTestnet } from './definitions/songbirdTestnet.js' export { shardeumSphinx } from './definitions/shardeumSphinx.js' -export { suaveRigil } from './definitions/suaveRigil.js' +export { suaveRigil, suaveToliman } from './definitions/suave.js' export { syscoin } from './definitions/syscoin.js' export { syscoinTestnet } from './definitions/syscoinTestnet.js' export { taraxa } from './definitions/taraxa.js' diff --git a/src/chains/suave/formatters.test.ts b/src/chains/suave/formatters.test.ts index 96e5be76..5f4977e2 100644 --- a/src/chains/suave/formatters.test.ts +++ b/src/chains/suave/formatters.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' import { type Hex, numberToHex, zeroAddress } from '~viem/index.js' -import { suaveRigil } from '../index.js' +import { suaveToliman as suaveChain } from '../index.js' import { type ConfidentialComputeRecordRpc, type RpcTransactionReceiptSuave, @@ -11,7 +11,7 @@ import { } from './types.js' describe('block', () => { - const { block } = suaveRigil.formatters! + const { block } = suaveChain.formatters! test('formatter (tx hashes)', () => { const inputBlock: SuaveRpcBlock = { @@ -115,11 +115,11 @@ describe('block', () => { value: '0x0', type: '0x50', typeHex: '0x50', - chainId: '0x1008c45', + chainId: '0x201188a', requestRecord: { type: '0x42' as any, typeHex: '0x42', - chainId: '0x1008c45', + chainId: '0x201188a', nonce: '0x3', to: '0x8f21fdd6b4f4cacd33151777a46c122797c8bf17', gas: '0xf4240', @@ -166,7 +166,7 @@ describe('block', () => { { "blockHash": "0xbe3e3c4205915e175df10e39a69d8dcbd4ca5b3e7dff2549a71edbc891a39e63", "blockNumber": 4n, - "chainId": 16813125, + "chainId": 33626250, "confidentialComputeResult": "0xc0b9d28700000000000000000000000000000000000000000000000000000000000000201518a916067557098f425aad1b1614f10000000000000000000000000000000011176998e3484c2d95582c916403a54100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008f21fdd6b4f4cacd33151777a46c122797c8bf170000000000000000000000000000000000000000000000000000000000000001000000000000000000000000b5feafbdd752ad52afb7e1bd2e40432a485bbb7f00000000000000000000000000000000000000000000000000000000000000156d657673686172653a76303a6d61746368426964730000000000000000000000", "from": "0xbe69d72ca5f88acba033a063df5dbe43a4148de0", "gas": 1000000n, @@ -176,7 +176,7 @@ describe('block', () => { "nonce": 3, "r": "0x38bda742051df0c9c3853f197533c3dbc7113c7ef1b91bcb7cc268228fad01c", "requestRecord": { - "chainId": "0x1008c45", + "chainId": "0x201188a", "confidentialInputsHash": "0xd890046400e66fc2ae1841fd630f4c2eab51d8f238bf20f9a6785a73ff113741", "gas": "0xf4240", "gasPrice": "0x3518320e", @@ -208,7 +208,7 @@ describe('block', () => { }) describe('transaction', () => { - const { transaction } = suaveRigil.formatters! + const { transaction } = suaveChain.formatters! test('formatter (RPC -> Transaction)', () => { const requestRecord = { @@ -233,7 +233,7 @@ describe('transaction', () => { const inputTransactionRpc = { blockHash: '0x8756d7614991fafffd2c788d7213122a2145629860575fb52be80cbef128fbb6', - chainId: numberToHex(suaveRigil.id), + chainId: numberToHex(suaveChain.id), requestRecord, confidentialComputeResult: '0x0' as Hex, blockNumber: '0x10' as Hex, @@ -259,7 +259,7 @@ describe('transaction', () => { "accessList": undefined, "blockHash": "0x8756d7614991fafffd2c788d7213122a2145629860575fb52be80cbef128fbb6", "blockNumber": 16n, - "chainId": 16813125, + "chainId": 33626250, "confidentialComputeResult": "0x0", "from": "0x0000000000000000000000000000000000000000", "gas": 19n, @@ -305,7 +305,7 @@ describe('transaction', () => { describe('transactionReceipt', () => { test('formatter', () => { - const { transactionReceipt } = suaveRigil.formatters! + const { transactionReceipt } = suaveChain.formatters! const inputReceipt: RpcTransactionReceiptSuave = { blockHash: @@ -409,7 +409,7 @@ describe('transactionReceipt', () => { }) describe('transactionRequest', () => { - const { transactionRequest } = suaveRigil.formatters! + const { transactionRequest } = suaveChain.formatters! test('formatter (confidential)', () => { const inputRequest: TransactionRequestSuave = { @@ -420,7 +420,7 @@ describe('transactionRequest', () => { value: 0n, kettleAddress: zeroAddress, confidentialInputs: '0x13131313', - chainId: suaveRigil.id, + chainId: suaveChain.id, nonce: 13, data: '0x0', type: '0x43', @@ -428,7 +428,7 @@ describe('transactionRequest', () => { const formattedRequest = transactionRequest.format(inputRequest) expect(formattedRequest).toMatchInlineSnapshot(` { - "chainId": "0x1008c45", + "chainId": "0x201188a", "confidentialInputs": "0x13131313", "data": "0x0", "from": "0x0000000000000000000000000000000000000000", @@ -456,11 +456,12 @@ describe('transactionRequest', () => { confidentialInputs: '0x13131313', nonce: 13, data: '0x0', + chainId: suaveChain.id, } const formattedRequest = transactionRequest.format(inputRequest) expect(formattedRequest).toMatchInlineSnapshot(` { - "chainId": "0x1008c45", + "chainId": "0x201188a", "confidentialInputs": "0x13131313", "data": "0x0", "from": "0x0000000000000000000000000000000000000000", @@ -479,7 +480,7 @@ describe('transactionRequest', () => { test('formatter (standard)', () => { const inputRequest: TransactionRequestSuave = { - chainId: suaveRigil.id, + chainId: suaveChain.id, from: zeroAddress, to: zeroAddress, gas: 1n, @@ -492,7 +493,7 @@ describe('transactionRequest', () => { const formattedRequest = transactionRequest.format(inputRequest) expect(formattedRequest).toMatchInlineSnapshot(` { - "chainId": 16813125, + "chainId": 33626250, "data": "0x0", "from": "0x0000000000000000000000000000000000000000", "gas": "0x1", diff --git a/src/chains/suave/formatters.ts b/src/chains/suave/formatters.ts index 455ba434..cccd3c6e 100644 --- a/src/chains/suave/formatters.ts +++ b/src/chains/suave/formatters.ts @@ -21,7 +21,6 @@ import { defineTransactionRequest, formatTransactionRequest, } from '../../utils/formatters/transactionRequest.js' -import { suaveRigil } from '../index.js' import type { ConfidentialComputeRecord, RpcTransactionReceiptSuave, @@ -129,6 +128,9 @@ export const formattersSuave = { if (!args.gasPrice) { throw new Error('gasPrice is required for confidential transactions') } + if (!args.chainId) { + throw new Error('chainId is required for confidential transactions') + } const { kettleAddress, confidentialInputs } = args return { ...formatTransactionRequest({ @@ -139,7 +141,7 @@ export const formattersSuave = { confidentialInputs, type: args.type || '0x43', gasPrice: toHex(args.gasPrice), - chainId: toHex(args.chainId || suaveRigil.id), + chainId: toHex(args.chainId), } as RpcTransactionRequestSuave } else { // handle as regular ethereum transaction diff --git a/src/chains/suave/parsers.test.ts b/src/chains/suave/parsers.test.ts index fdee6ccd..a03d7694 100644 --- a/src/chains/suave/parsers.test.ts +++ b/src/chains/suave/parsers.test.ts @@ -7,12 +7,12 @@ import { SuaveTxRequestTypes, } from './types.js' import { getSuaveWallet } from './wallet.js' -import { suaveRigil } from '../index.js' +import { suaveToliman as suaveChain } from '../index.js' const getWallet = () => { return getSuaveWallet( { - transport: http('https://rpc.rigil.suave.flashbots.net'), + transport: http(suaveChain.rpcUrls.public.http[0]), privateKey: accounts[0].privateKey, }, ) @@ -38,7 +38,7 @@ describe('Suave Transaction Parsers', () => { const parsedTx = parseTransactionSuave(signedTransaction as SuaveTxType) expect(parsedTx).toMatchInlineSnapshot(` { - "chainId": ${suaveRigil.id}, + "chainId": ${suaveChain.id}, "confidentialInputs": "${ccRequest.confidentialInputs}", "data": "${ccRequest.data}", "gas": 100n, diff --git a/src/chains/suave/wallet.ts b/src/chains/suave/wallet.ts index a20c72e6..238d09a5 100644 --- a/src/chains/suave/wallet.ts +++ b/src/chains/suave/wallet.ts @@ -2,9 +2,11 @@ import { sign } from '../../accounts/index.js' import { privateKeyToAccount } from '../../accounts/privateKeyToAccount.js' import { http, + Address, type JsonRpcAccount, type PrivateKeyAccount, type PublicClient, + TransactionRequest, TransactionType, type Transport, TransportConfig, @@ -13,9 +15,10 @@ import { createWalletClient, hexToSignature, keccak256, + zeroAddress, } from '../../index.js' import type { Hash, Hex } from '../../types/misc.js' -import { suaveRigil } from '../index.js' +import { suaveRigil, suaveToliman } from '../index.js' import { serializeConfidentialComputeRecord, serializeConfidentialComputeRequest, @@ -29,16 +32,18 @@ import { TransactionSerializableSuave, } from './types.js' +type SuaveChain = typeof suaveToliman | typeof suaveRigil + /// client types export type SuaveWallet = WalletClient< TTransport, - typeof suaveRigil, + SuaveChain, PrivateKeyAccount | JsonRpcAccount > export type SuaveProvider = PublicClient< TTransport, - typeof suaveRigil + SuaveChain > /// helper functions @@ -149,15 +154,19 @@ export function getSuaveWallet(params: { jsonRpcAccount?: Hex privateKey?: Hex customRpc?: string + chain?: SuaveChain }): SuaveWallet { return newSuaveWallet({ - transport: params.transport ?? http(suaveRigil.rpcUrls.public.http[0]), + transport: + params.transport ?? + http((params.chain || suaveToliman).rpcUrls.public.http[0]), privateKey: params.privateKey, jsonRpcAccount: params.jsonRpcAccount && { address: params.jsonRpcAccount, type: 'json-rpc', }, customRpc: params.customRpc, + chain: params.chain, }) } @@ -170,6 +179,8 @@ function newSuaveWallet(params: { customRpc?: string /** must set this for non-custom transports only. */ privateKey?: Hex + /** optional: set chain to suaveRigil for local devnet. */ + chain?: SuaveChain }): SuaveWallet { if (!params.jsonRpcAccount && !params.privateKey) { throw new Error("Must provide either 'jsonRpcAccount' or 'privateKey'") @@ -184,22 +195,37 @@ function newSuaveWallet(params: { : undefined const account = params.jsonRpcAccount || privateKeyAccount + const clientChain = + params.chain || params.customRpc?.includes('localhost') + ? suaveRigil + : suaveToliman + return createWalletClient({ account, transport: params.transport, - chain: suaveRigil, + chain: clientChain, }).extend((client) => ({ /** If `customRpc` is provided, this is used for some RPC requests instead of provided (custom) `transport`. * `transport` is still used for things that require the wallet's account (signing, etc). */ customProvider: getSuaveProvider( params.customRpc ? http(params.customRpc) : params.transport, + clientChain, ), /** Prepare any omitted fields in request. */ - async prepareTxRequest( - txRequest: TransactionRequestSuave, - ): Promise { + async prepareTxRequest(txRequest: TransactionRequestSuave): Promise< + TransactionRequestSuave & + Required<{ + chainId: number + gas: bigint + nonce: number + to: Address + value: bigint + gasPrice: bigint + type: SuaveTxType + }> + > { const gas = txRequest.gas ?? (() => { @@ -211,7 +237,14 @@ function newSuaveWallet(params: { const from = txRequest.from ?? client.account.address return { - ...txRequest, + // ...txRequest, + confidentialInputs: txRequest.confidentialInputs, + kettleAddress: txRequest.kettleAddress, + isEIP712: txRequest.isEIP712, + accessList: txRequest.accessList, + to: txRequest.to ?? zeroAddress, + data: txRequest.data ?? '0x', + value: txRequest.value ?? 0n, from, nonce: txRequest.nonce ?? @@ -219,7 +252,7 @@ function newSuaveWallet(params: { gas, gasPrice: txRequest.gasPrice ?? (await this.customProvider.getGasPrice()), - chainId: txRequest.chainId ?? suaveRigil.id, + chainId: txRequest.chainId ?? client.chain.id, type: txRequest.type ?? txRequest.kettleAddress ? SuaveTxRequestTypes.ConfidentialRequest @@ -269,14 +302,17 @@ function newSuaveWallet(params: { async sendTransaction(txRequest: TransactionRequestSuave): Promise { // signTransaction also invokes prepareTxRequest, but only for CCRs. this is still needed for standard txs. const payload = await this.prepareTxRequest(txRequest) - if (txRequest.type === SuaveTxRequestTypes.ConfidentialRequest) { + if (payload.type === SuaveTxRequestTypes.ConfidentialRequest) { const signedTx = await this.signTransaction(payload) return this.customProvider.request({ method: 'eth_sendRawTransaction', params: [signedTx as Hex], }) } else { - return client.sendTransaction(payload) + return client.sendTransaction({ + ...payload, + type: 'legacy', + } as TransactionRequest) } }, @@ -289,11 +325,6 @@ function newSuaveWallet(params: { txRequest.kettleAddress || txRequest.confidentialInputs ) { - if (!txRequest.confidentialInputs) { - throw new Error( - 'confidentialInputs is required for confidential requests', - ) - } if (!txRequest.kettleAddress) { throw new Error('kettleAddress is required for confidential requests') } @@ -311,7 +342,7 @@ function newSuaveWallet(params: { const value = txRequest.value ?? 0n const gas = txRequest.gas ?? (await ctxParams).gas const gasPrice = txRequest.gasPrice ?? (await ctxParams).gasPrice - const chainId = txRequest.chainId ?? suaveRigil.id + const chainId = txRequest.chainId ?? params.chain?.id ?? client.chain.id const isEIP712 = txRequest.isEIP712 ?? true // prepare and sign confidential compute request @@ -390,9 +421,11 @@ function newSuaveWallet(params: { */ export function getSuaveProvider( transport?: TTransport, + chain?: SuaveChain, ): SuaveProvider { + const theChain = chain || suaveToliman return createPublicClient({ - transport: transport ?? http(suaveRigil.rpcUrls.public.http[0]), - chain: suaveRigil, + transport: transport ?? http(theChain.rpcUrls.public.http[0]), + chain: theChain, }) }