Skip to content

Commit

Permalink
fixup! eip-7795
Browse files Browse the repository at this point in the history
  • Loading branch information
attente committed Jan 20, 2025
1 parent cb8c280 commit f0fd1f4
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 116 deletions.
1 change: 1 addition & 0 deletions packages/account/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"dependencies": {
"@0xsequence/abi": "workspace:*",
"@0xsequence/api": "workspace:*",
"@0xsequence/core": "workspace:*",
"@0xsequence/migration": "workspace:*",
"@0xsequence/network": "workspace:*",
Expand Down
62 changes: 36 additions & 26 deletions packages/account/src/account.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { walletContracts } from '@0xsequence/abi'
import { Precondition } from '@0xsequence/api'
import { commons, universal } from '@0xsequence/core'
import { migrator, defaults, version } from '@0xsequence/migration'
import { ChainId, NetworkConfig } from '@0xsequence/network'
Expand Down Expand Up @@ -783,9 +784,9 @@ export class Account {
return this.buildBootstrapTransactions(status, chainId)
}

async doBootstrap(chainId: ethers.BigNumberish, feeQuote?: FeeQuote, prestatus?: AccountStatus) {
async doBootstrap(chainId: ethers.BigNumberish, prestatus?: AccountStatus) {
const bootstrapTxs = await this.bootstrapTransactions(chainId, prestatus)
return this.relayer(chainId).relay({ ...bootstrapTxs, chainId }, feeQuote)
return this.relayer(chainId).relay({ ...bootstrapTxs, chainId })
}

signMessage(
Expand Down Expand Up @@ -910,23 +911,28 @@ export class Account {
}

async sendSignedTransactions(
signedBundle: commons.transaction.IntendedTransactionBundle | commons.transaction.IntendedTransactionBundle[],
transactions: commons.transaction.IntendedTransactionBundle | commons.transaction.IntendedTransactionBundle[],
chainId: ethers.BigNumberish,
quote?: FeeQuote,
pstatus?: AccountStatus,
callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void,
projectAccessKey?: string
options?: {
projectAccessKey?: string
quote?: FeeQuote
preconditions?: Precondition[]
waitForReceipt?: boolean
status?: AccountStatus
callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void
}
): Promise<ethers.TransactionResponse> {
if (!Array.isArray(signedBundle)) {
return this.sendSignedTransactions([signedBundle], chainId, quote, pstatus, callback, projectAccessKey)
if (!Array.isArray(transactions)) {
return this.sendSignedTransactions([transactions], chainId, options)
}
const status = pstatus || (await this.status(chainId))

const status = options?.status ?? (await this.status(chainId))
this.mustBeFullyMigrated(status)

const decoratedBundle = await this.decorateTransactions(signedBundle, status, chainId)
callback?.(decoratedBundle)
const decorated = await this.decorateTransactions(transactions, status, chainId)
options?.callback?.(decorated)

return this.relayer(chainId).relay(decoratedBundle, quote, undefined, projectAccessKey)
return this.relayer(chainId).relay(decorated, options)
}

async fillGasLimits(
Expand Down Expand Up @@ -1008,32 +1014,36 @@ export class Account {
}

async sendTransaction(
txs: commons.transaction.Transactionish,
transactions: commons.transaction.Transactionish,
chainId: ethers.BigNumberish,
quote?: FeeQuote,
skipPreDecorate: boolean = false,
callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void,
options?: {
projectAccessKey?: string
quote?: FeeQuote
preconditions?: Precondition[]
waitForReceipt?: boolean
status?: AccountStatus
callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void
nonceSpace?: ethers.BigNumberish
serial?: boolean
projectAccessKey?: string
skipPredecorate?: boolean
}
): Promise<ethers.TransactionResponse | undefined> {
const status = await this.status(chainId)

const predecorated = skipPreDecorate ? txs : await this.predecorateTransactions(txs, status, chainId)
const hasTxs = commons.transaction.fromTransactionish(this.address, predecorated).length > 0
const signed = hasTxs ? await this.signTransactions(predecorated, chainId, undefined, options) : undefined
const status = options?.status ?? (await this.status(chainId))
const predecorated = options?.skipPredecorate
? transactions
: await this.predecorateTransactions(transactions, status, chainId)
const hasTransactions = commons.transaction.fromTransactionish(this.address, predecorated).length > 0
const signed = hasTransactions ? await this.signTransactions(predecorated, chainId, undefined, options) : undefined

const childBundles = await this.orchestrator.predecorateSignedTransactions({ chainId })

const bundles: commons.transaction.SignedTransactionBundle[] = []
if (signed !== undefined && signed.transactions.length > 0) {
if (signed && signed.transactions.length > 0) {
bundles.push(signed)
}
bundles.push(...childBundles.filter(b => b.transactions.length > 0))
bundles.push(...childBundles.filter(b => b.transactions.length))

return this.sendSignedTransactions(bundles, chainId, quote, undefined, callback, options?.projectAccessKey)
return this.sendSignedTransactions(bundles, chainId, options)
}

async signTypedData(
Expand Down
16 changes: 4 additions & 12 deletions packages/account/src/signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,10 @@ export class AccountSigner implements ethers.AbstractSigner<ethers.Provider> {

const finalTransactions = [...prepare.transactions, ...encodeGasRefundTransaction(feeOption)]

return this.account.sendTransaction(
finalTransactions,
this.chainId,
prepare.feeQuote,
undefined,
undefined,
this.options?.nonceSpace !== undefined
? {
nonceSpace: this.options.nonceSpace
}
: undefined
) as Promise<ethers.TransactionResponse> // Will always have a transaction response
return this.account.sendTransaction(finalTransactions, this.chainId, {
quote: prepare.feeQuote,
nonceSpace: this.options?.nonceSpace
}) as Promise<ethers.TransactionResponse> // Will always have a transaction response
}

getBalance(blockTag?: ethers.BlockTag | undefined): Promise<bigint> {
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export class Session {
// we could speed this up by sending the migration alongside the jwt request
// and letting the API validate it offchain.
if (status.onChain.version !== status.version) {
await account.doBootstrap(referenceChainId, undefined, status)
await account.doBootstrap(referenceChainId, status)
}

const prevConfig = status.config
Expand Down
18 changes: 12 additions & 6 deletions packages/provider/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Precondition, encodePrecondition } from '@0xsequence/api'
import { commons, VERSION } from '@0xsequence/core'
import { NetworkConfig } from '@0xsequence/network'
import { TypedData } from '@0xsequence/utils'
import { ethers } from 'ethers'
import {
ConnectDetails,
ConnectOptions,
Expand All @@ -15,11 +19,7 @@ import {
isProviderTransport,
messageToBytes
} from '.'
import { commons, VERSION } from '@0xsequence/core'
import { TypedData } from '@0xsequence/utils'
import { toExtended } from './extended'
import { Analytics, setupAnalytics } from './analytics'
import { ethers } from 'ethers'

/**
* This session class is meant to persist the state of the wallet connection
Expand Down Expand Up @@ -490,7 +490,10 @@ export class SequenceClient {
})
}

async sendTransaction(tx: ethers.TransactionRequest[] | ethers.TransactionRequest, options?: OptionalChainId): Promise<string> {
async sendTransaction(
tx: ethers.TransactionRequest[] | ethers.TransactionRequest,
options?: OptionalChainId & { preconditions?: Precondition[] }
): Promise<string> {
const transactions = Array.isArray(tx) ? tx : [tx]
const chainId = options?.chainId ?? this.getChainId()

Expand All @@ -508,7 +511,10 @@ export class SequenceClient {
value: value !== undefined && value !== null ? ethers.toQuantity(value) : undefined,
data: data || undefined,
chainId: ethers.toQuantity(chainId)
}))
})),
capabilities: {
...(options?.preconditions ? { preconditions: options.preconditions.map(encodePrecondition) } : undefined)
}
}
],
chainId
Expand Down
18 changes: 11 additions & 7 deletions packages/provider/src/signer.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Precondition } from '@0xsequence/api'
import { commons } from '@0xsequence/core'
import { ChainIdLike, NetworkConfig } from '@0xsequence/network'
import { ethers } from 'ethers'

import { SequenceProvider, SingleNetworkSequenceProvider } from './provider'
import { SequenceClient } from './client'
import { commons } from '@0xsequence/core'
import { ChainIdLike, NetworkConfig } from '@0xsequence/network'
import { SequenceProvider, SingleNetworkSequenceProvider } from './provider'
import { OptionalChainIdLike, OptionalEIP6492 } from './types'
import { resolveArrayProperties } from './utils'
import { WalletUtils } from './utils/index'
import { OptionalChainIdLike, OptionalEIP6492 } from './types'

export interface ISequenceSigner extends Omit<ethers.Signer, 'connect'> {
getProvider(): SequenceProvider
Expand Down Expand Up @@ -36,7 +37,7 @@ export interface ISequenceSigner extends Omit<ethers.Signer, 'connect'> {
// It supports any kind of transaction, including regular ethers transactions, and Sequence transactions.
sendTransaction(
transaction: ethers.TransactionRequest[] | ethers.TransactionRequest,
options?: OptionalChainIdLike
options?: OptionalChainIdLike & { preconditions?: Precondition[] }
): Promise<commons.transaction.TransactionResponse>

utils: WalletUtils
Expand Down Expand Up @@ -123,10 +124,13 @@ export class SequenceSigner implements ISequenceSigner {
return this.provider.getProvider(chainId)
}

async sendTransaction(transaction: ethers.TransactionRequest[] | ethers.TransactionRequest, options?: OptionalChainIdLike) {
async sendTransaction(
transaction: ethers.TransactionRequest[] | ethers.TransactionRequest,
options?: OptionalChainIdLike & { preconditions?: Precondition[] }
) {
const chainId = this.useChainId(options?.chainId)
const resolved = await resolveArrayProperties(transaction)
const txHash = await this.client.sendTransaction(resolved, { chainId })
const txHash = await this.client.sendTransaction(resolved, { chainId, preconditions: options?.preconditions })
const provider = this.getProvider(chainId)

try {
Expand Down
11 changes: 5 additions & 6 deletions packages/relayer/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { commons } from '@0xsequence/core'
import { ethers } from 'ethers'
import { proto } from './rpc-relayer'

import { commons } from '@0xsequence/core'
import { Precondition } from './precondition'
import { proto } from './rpc-relayer'

export interface Relayer {
// simulate returns the execution results for a list of transactions.
Expand Down Expand Up @@ -38,10 +39,8 @@ export interface Relayer {
// The quote should be the one returned from getFeeOptions, if any.
// waitForReceipt must default to true.
relay(
signedTxs: commons.transaction.IntendedTransactionBundle,
quote?: FeeQuote,
waitForReceipt?: boolean,
projectAccessKey?: string
transactions: commons.transaction.IntendedTransactionBundle,
options?: { projectAccessKey?: string; quote?: FeeQuote; preconditions?: Precondition[]; waitForReceipt?: boolean }
): Promise<commons.transaction.TransactionResponse>

// wait for transaction confirmation
Expand Down
21 changes: 10 additions & 11 deletions packages/relayer/src/local-relayer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ethers } from 'ethers'
import { logger } from '@0xsequence/utils'
import { FeeOption, FeeQuote, proto, Relayer } from '.'
import { ProviderRelayer, ProviderRelayerOptions } from './provider-relayer'
import { commons } from '@0xsequence/core'
import { logger } from '@0xsequence/utils'
import { ethers } from 'ethers'

import { FeeOption, FeeQuote, Precondition, ProviderRelayer, ProviderRelayerOptions, Relayer, proto } from '.'

export type LocalRelayerOptions = Omit<ProviderRelayerOptions, 'provider'> & {
signer: ethers.Signer
Expand Down Expand Up @@ -46,29 +46,28 @@ export class LocalRelayer extends ProviderRelayer implements Relayer {
}

async relay(
signedTxs: commons.transaction.IntendedTransactionBundle,
quote?: FeeQuote,
waitForReceipt: boolean = true
transactions: commons.transaction.IntendedTransactionBundle,
options?: { projectAccessKey?: string; quote?: FeeQuote; preconditions?: Precondition[]; waitForReceipt?: boolean }
): Promise<commons.transaction.TransactionResponse<ethers.TransactionReceipt>> {
if (quote !== undefined) {
if (options?.quote) {
logger.warn(`LocalRelayer doesn't accept fee quotes`)
}

const data = commons.transaction.encodeBundleExecData(signedTxs)
const data = commons.transaction.encodeBundleExecData(transactions)

// TODO: think about computing gas limit individually, summing together and passing across
// NOTE: we expect that all txns have set their gasLimit ahead of time through proper estimation
// const gasLimit = signedTxs.transactions.reduce((sum, tx) => sum + tx.gasLimit, 0n)
// txRequest.gasLimit = gasLimit

const responsePromise = this.signer.sendTransaction({
to: signedTxs.entrypoint,
to: transactions.entrypoint,
data,
...this.txnOptions,
gasLimit: 9000000
})

if (waitForReceipt) {
if (options?.waitForReceipt !== false) {
const response: commons.transaction.TransactionResponse = await responsePromise
response.receipt = await response.wait()
return response
Expand Down
12 changes: 6 additions & 6 deletions packages/relayer/src/provider-relayer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ethers } from 'ethers'
import { walletContracts } from '@0xsequence/abi'
import { FeeOption, FeeQuote, proto, Relayer, SimulateResult } from '.'
import { logger, Optionals } from '@0xsequence/utils'
import { commons } from '@0xsequence/core'
import { logger, Optionals } from '@0xsequence/utils'
import { ethers } from 'ethers'

import { FeeOption, FeeQuote, Precondition, proto, Relayer, SimulateResult } from '.'

const DEFAULT_GAS_LIMIT = 800000n

Expand Down Expand Up @@ -54,9 +55,8 @@ export abstract class ProviderRelayer implements Relayer {
abstract gasRefundOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<FeeOption[]>

abstract relay(
signedTxs: commons.transaction.IntendedTransactionBundle,
quote?: FeeQuote,
waitForReceipt?: boolean
transactions: commons.transaction.IntendedTransactionBundle,
options?: { projectAccessKey?: string; quote?: FeeQuote; preconditions?: Precondition[]; waitForReceipt?: boolean }
): Promise<commons.transaction.TransactionResponse>

abstract getTransactionCost(
Expand Down
Loading

0 comments on commit f0fd1f4

Please sign in to comment.