Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eip712 signature for CCR #43

Merged
merged 11 commits into from
Jun 29, 2024
4 changes: 2 additions & 2 deletions examples/suave-web-demo/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import typescriptLogo from './typescript.svg'
import flashbotsLogo from './flashbots_icon.svg'
import { setupConnectButton, setupDripFaucetButton, setupSendBidButton } from './suave'
import { Logo } from './components'
import { custom, formatEther } from 'viem'
import { custom, formatEther, http } from 'viem'
import { getSuaveWallet, getSuaveProvider } from 'viem/chains/utils'
import { suaveRigil } from 'viem/chains'

Expand Down Expand Up @@ -38,7 +38,7 @@ setupConnectButton(document.querySelector<HTMLButtonElement>('#connect')!,
}
const suaveWallet = getSuaveWallet({jsonRpcAccount: account, transport: custom(ethereum)})
console.log(suaveWallet)
const suaveProvider = getSuaveProvider(custom(ethereum))
const suaveProvider = getSuaveProvider(http("http://localhost:8545"))
suaveProvider.getBalance({ address: account }).then((balance: any) => {
suaveProvider.getChainId().then((chainId: any) => {
if (chainId !== suaveRigil.id) {
Expand Down
12 changes: 6 additions & 6 deletions examples/suave-web-demo/src/suave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
http,
} from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { suaveRigil, goerli } from 'viem/chains'
import { suaveRigil, holesky } from 'viem/chains'
import { OFAOrder } from '../../suave/bids'
import { getSuaveWallet } from 'viem/chains/utils'
import BidContractDeployment from '../../suave/deployedAddress.json'
Expand All @@ -16,18 +16,18 @@ const KETTLE_ADDRESS: Address = '0xb5feafbdd752ad52afb7e1bd2e40432a485bbb7f'
const ADMIN_KEY: Hex =
'0x91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12'
// public goerli node, may need to change if it goes down:
const GOERLI_RPC_URL_HTTP: string = 'https://goerli.rigil.suave.flashbots.net'
const L1_RPC_URL_HTTP: string = 'https://holesky.rigil.suave.flashbots.net'

const goerliWallet = createWalletClient({
account: privateKeyToAccount(
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
),
chain: goerli,
transport: http(GOERLI_RPC_URL_HTTP),
chain: holesky,
transport: http(L1_RPC_URL_HTTP),
})
const goerliProvider = createPublicClient({
transport: http(GOERLI_RPC_URL_HTTP),
chain: goerli,
transport: http(L1_RPC_URL_HTTP),
chain: holesky,
})
const suaveAdminWallet = getSuaveWallet({
privateKey: ADMIN_KEY,
Expand Down
3 changes: 2 additions & 1 deletion examples/suave/bids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ export class OFAOrder {
}

/** Encodes this bid as a ConfidentialComputeRequest, which can be sent to SUAVE. */
toConfidentialRequest(): TransactionRequestSuave {
toConfidentialRequest(isEIP712?: boolean): TransactionRequestSuave {
return {
to: this.OFAContract,
data: this.newOrderCalldata(),
type: '0x43',
gas: 500000n,
gasPrice: 1000000000n,
isEIP712,
kettleAddress: this.kettle,
confidentialInputs: this.confidentialInputsBytes(),
}
Expand Down
7 changes: 3 additions & 4 deletions examples/suave/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { http, Address, Hex, createPublicClient, formatEther, isHex } from 'viem
import { goerli } from 'viem/chains'
import { TransactionRequestSuave } from 'viem/chains/suave/types'
import { OFAOrder } from './bids'
import { SuaveProvider, SuaveWallet, getSuaveProvider, getSuaveWallet } from 'viem/chains/utils'
import { SuaveProvider, SuaveWallet, getSuaveProvider, getSuaveWallet, parseTransactionSuave } from 'viem/chains/utils'
import { HttpTransport } from 'viem'
import BidContractDeployment from './deployedAddress.json'
import { parseSignedComputeRequest } from 'viem/chains/suave/parsers'

const failEnv = (name: string) => {
throw new Error(`missing env var ${name}`)
Expand Down Expand Up @@ -126,12 +125,12 @@ async function testSuaveBids() {
KETTLE_ADDRESS,
BID_CONTRACT_ADDRESS,
)
const ccr = bid.toConfidentialRequest()
const ccr = bid.toConfidentialRequest() // signs w/ EIP712 by default; pass `false` to use legacy CCR
console.log('ccr', ccr)

const signedCcr = await wallet.signTransaction(ccr)
const deserCcr = await parseSignedComputeRequest(signedCcr)
console.log("signedCcr", signedCcr)
const deserCcr = await parseTransactionSuave(signedCcr)
console.log("deserialized signed ccr", deserCcr)

// deserCcr should be the same as ccr, but with any missing fields filled in, such as gasPrice & nonce
Expand Down
8 changes: 5 additions & 3 deletions src/chains/suave/parsers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('Suave Transaction Parsers', () => {
gas: 100n,
gasPrice: 100n,
nonce: 0,
// isEIP712: true,
type: SuaveTxRequestTypes.ConfidentialRequest,
kettleAddress: accounts[1].address,
confidentialInputs: '0x42424242424242424242424242424242' as Hex,
Expand All @@ -42,10 +43,11 @@ describe('Suave Transaction Parsers', () => {
"data": "${ccRequest.data}",
"gas": 100n,
"gasPrice": 100n,
"isEIP712": true,
"kettleAddress": "${ccRequest.kettleAddress}",
"nonce": 0,
"r": "0xaf44e7e1c628554f85a8bba6a6ced571e87f5996f195d5e3c97a8c03d4ee61e1",
"s": "0x779bcc8d321f21118ce7682028fcac78123a1d2fcbc40b18866b54ac343c2cf8",
"r": "0xae3d9c09d56078e22d4b9747c988f71d086bb24ab42dc15ea431b7bd10e67a99",
"s": "0x6976c6aaaddec226a56ccb0001935397c68d16f58945769fd855121b7e542863",
"to": "${ccRequest.to}",
"type": "0x43",
"v": 0n,
Expand All @@ -58,7 +60,7 @@ describe('Suave Transaction Parsers', () => {
test('parseTransactionSuave parses all SUAVE tx types', async () => {
const wallet = getWallet()
const serializedTx =
'0x43f902aaf90184098412504db4830f4240949a151aa453329f3cdf04d8e4e81585a423f7fc2580b8e4d8f55db90000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c012e8eff6ead85d9d948631a18c41afb60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000009a151aa453329f3cdf04d8e4e81585a423f7fc25000000000000000000000000000000000000000000000000000000000000000094b5feafbdd752ad52afb7e1bd2e40432a485bbb7fa0249c92db3766bc250ffe17682d363e78dbd3aa1fff59a3b5ca242c872910effa8401008c4580a04a0e49a3711af960c5e76d10a21ae318912702b4cfdb37e6baf087edc84feedca02304c28a2a6cb07efa0643e4e2a78bdd2980ccc1d23b359c9cc67543461eb98ab90120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000dc7b22747873223a5b2230786638363538303064383235336163393431633638353738353161333737633866613736343130396435353933383261393235376334393962383230336538383038343032303131386164613037613861313734613333643136353432363938616538353061303965303530333262373865353934616164613061343164313137376136383333636266633630613031633465663334313031626161363665376338393438376365353062343239653138623733663535323064366130656633396630366234386362343862373064225d7d00000000'
'0x43f8acf8998064649470997970c51812dc3a010c7d01b50e0d17dc79c880139470997970c51812dc3a010c7d01b50e0d17dc79c8a0a71e488c022df32f3b11c11282cf8c6f6b1d7c1d8b3bc3dc921cb6c2c5c0aae7018401008c4580a0ae3d9c09d56078e22d4b9747c988f71d086bb24ab42dc15ea431b7bd10e67a99a06976c6aaaddec226a56ccb0001935397c68d16f58945769fd855121b7e5428639042424242424242424242424242424242'
const parsedTx = parseTransactionSuave(serializedTx)
expect(parsedTx.type).toBe(SuaveTxRequestTypes.ConfidentialRequest)

Expand Down
18 changes: 15 additions & 3 deletions src/chains/suave/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ const safeHexToNumber = (hex: Hex) => {
return hexToNumber(hex)
}

export const parseSignedComputeRequest = (signedComputeRequest: Hex) => {
export const parseSignedComputeRequest = (
signedComputeRequest: Hex,
): Partial<TransactionSerializableSuave> => {
const serializedType = signedComputeRequest.slice(0, 4)
if (serializedType !== SuaveTxRequestTypes.ConfidentialRequest) {
throw new InvalidSerializedTransactionTypeError({
Expand All @@ -43,14 +45,15 @@ export const parseSignedComputeRequest = (signedComputeRequest: Hex) => {
data,
kettleAddress,
confidentialInputsHash,
isEIP712,
chainId,
v,
r,
s,
],
confidentialInputs,
] = txArray
if (txArray.length !== 2 || txArray[0].length !== 12) {
if (txArray.length !== 2 || txArray[0].length !== 13) {
throw new InvalidSerializedTransactionError({
attributes: {
nonce,
Expand All @@ -59,6 +62,7 @@ export const parseSignedComputeRequest = (signedComputeRequest: Hex) => {
gas,
kettleAddress,
confidentialInputsHash,
isEIP712,
value,
gasPrice,
chainId,
Expand All @@ -78,6 +82,7 @@ export const parseSignedComputeRequest = (signedComputeRequest: Hex) => {
gas: hexToBigInt(gas as Hex),
kettleAddress: kettleAddress as Hex,
confidentialInputs: confidentialInputs as Hex,
isEIP712: isEIP712 === '0x01',
value: safeHexToBigInt(value as Hex),
gasPrice: safeHexToBigInt(gasPrice as Hex),
chainId: hexToNumber(chainId as Hex),
Expand All @@ -100,7 +105,7 @@ export type ParseTransactionSuaveReturnType<TType extends SuaveTxType> =

/** Parse a serialized transaction into a SUAVE Transaction object. */
export function parseTransactionSuave(
serializedTransaction: TransactionSerializedSuave,
serializedTransaction: TransactionSerializedSuave | Hex,
): ParseTransactionSuaveReturnType<SuaveTxType> {
const serializedType = serializedTransaction.slice(0, 4)
const parsedTx =
Expand Down Expand Up @@ -130,12 +135,19 @@ export function assertTransactionSuave(
maxFeePerGas,
confidentialInputs,
confidentialInputsHash,
isEIP712,
kettleAddress,
type,
to,
r,
s,
v,
} = transaction
if (
type === SuaveTxRequestTypes.ConfidentialRequest &&
isEIP712 === undefined
)
throw new Error("must encode 'isEIP712' for confidential requests")
if (chainId && chainId <= 0) throw new Error('invalid chain ID')
if (to && !isAddress(to)) throw new Error('invalid to address')
if (!gasPrice) throw new Error('gasPrice is required')
Expand Down
5 changes: 4 additions & 1 deletion src/chains/suave/serializers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InvalidSerializedTransactionTypeError } from '../../index.js'
import type { Hex } from '../../types/misc.js'
import { concatHex } from '../../utils/data/concat.js'
import { numberToHex, toHex } from '../../utils/encoding/toHex.js'
import { boolToHex, numberToHex, toHex } from '../../utils/encoding/toHex.js'
import { toRlp } from '../../utils/encoding/toRlp.js'
import {
InvalidConfidentialRecordError,
Expand Down Expand Up @@ -166,6 +166,9 @@ export const serializeConfidentialComputeRequest = (
transaction.kettleAddress,
transaction.confidentialInputsHash,

// envelope
boolToHex(transaction.isEIP712 ?? true),

numberToHex(transaction.chainId),
toHex(transaction.v),
transaction.r,
Expand Down
31 changes: 14 additions & 17 deletions src/chains/suave/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type SuaveTxRequestType =

type ConfidentialOverrides = {
kettleAddress?: Address
isEIP712?: boolean
}

type ConfidentialComputeRequestOverrides = ConfidentialOverrides & {
Expand Down Expand Up @@ -136,22 +137,8 @@ export type ConfidentialComputeRecord<
TQuantity = bigint,
TIndex = number,
> = Omit<
Omit<
Omit<
Omit<
TransactionBase<
TQuantity,
TIndex,
SuaveTxTypes.ConfidentialRecord,
TPending
>,
'blockHash'
>,
'transactionIndex'
>,
'blockNumber'
>,
'from'
TransactionBase<TQuantity, TIndex, SuaveTxTypes.ConfidentialRecord, TPending>,
'blockHash' | 'transactionIndex' | 'blockNumber' | 'from'
> &
ConfidentialComputeRecordOverrides

Expand All @@ -167,6 +154,17 @@ export type TransactionRequestSuave<
from?: Address
}

export type PreparedConfidentialRecord = Omit<
ConfidentialComputeRecord,
'input' | 'typeHex' | 'hash' | 'r' | 's' | 'v'
> & {
data: Hex
to: Address
gasPrice: bigint
kettleAddress: Address
confidentialInputsHash: Hash
}

export type RpcTransactionRequestSuave<TType = SuaveTxType> =
TransactionRequestSuave<Hex, Hex> & {
type: TType
Expand Down Expand Up @@ -195,7 +193,6 @@ export type TransactionSerializableSuave<
> = TransactionSerializableEIP2930<TQuantity, TIndex> &
ConfidentialComputeRecordOverrides &
ConfidentialComputeRequestOverrides & {
signedComputeRecord?: Hex
type: TType
}

Expand Down
Loading
Loading