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

[DO NOT MERGE]: EIP-7795 #650

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
12 changes: 9 additions & 3 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@
"test": "echo",
"typecheck": "tsc --noEmit"
},
"dependencies": {},
"peerDependencies": {},
"devDependencies": {},
"dependencies": {
"@0xsequence/relayer": "workspace:*"
},
"peerDependencies": {
"ethers": ">=6"
},
"devDependencies": {
"ethers": "6.13.4"
},
"files": [
"src",
"dist"
Expand Down
50 changes: 47 additions & 3 deletions packages/api/src/api.gen.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable */
// sequence-api v0.4.0 24814ebb88457c0545aa80e8388cb0f08ec59bec
// sequence-api v0.4.0 41111b03b412959cee78aeeaa326584819b68a62
// --
// Code generated by [email protected] with typescript generator. DO NOT EDIT.
//
Expand All @@ -12,7 +12,7 @@ export const WebRPCVersion = 'v1'
export const WebRPCSchemaVersion = 'v0.4.0'

// Schema hash generated from your RIDL schema
export const WebRPCSchemaHash = '24814ebb88457c0545aa80e8388cb0f08ec59bec'
export const WebRPCSchemaHash = '41111b03b412959cee78aeeaa326584819b68a62'

//
// Types
Expand Down Expand Up @@ -148,14 +148,34 @@ export interface TupleComponent {
value: any
}

export interface Precondition {
type: string
chainID: string
precondition: any
}

export interface Solution {
transactions: Array<Transactions>
}

export interface Transactions {
chainID: string
transactions: Array<Transaction>
preconditions?: Array<SolutionPrecondition>
}

export interface Transaction {
delegateCall: boolean
revertOnError: boolean
gasLimit: string
target: string
value: string
data: string
call?: ContractCall
}

export interface SolutionPrecondition {
type: string
precondition: any
}

export interface UserStorage {
Expand Down Expand Up @@ -555,6 +575,7 @@ export interface API {
getSwapPrice(args: GetSwapPriceArgs, headers?: object, signal?: AbortSignal): Promise<GetSwapPriceReturn>
getSwapPrices(args: GetSwapPricesArgs, headers?: object, signal?: AbortSignal): Promise<GetSwapPricesReturn>
getSwapQuote(args: GetSwapQuoteArgs, headers?: object, signal?: AbortSignal): Promise<GetSwapQuoteReturn>
satisfy(args: SatisfyArgs, headers?: object, signal?: AbortSignal): Promise<SatisfyReturn>
listCurrencyGroups(headers?: object, signal?: AbortSignal): Promise<ListCurrencyGroupsReturn>
addOffchainInventory(
args: AddOffchainInventoryArgs,
Expand Down Expand Up @@ -1066,6 +1087,14 @@ export interface GetSwapQuoteArgs {
export interface GetSwapQuoteReturn {
swapQuote: SwapQuote
}
export interface SatisfyArgs {
wallet: string
preconditions: Array<Precondition>
}

export interface SatisfyReturn {
solutions: Array<Solution>
}
export interface ListCurrencyGroupsArgs {}

export interface ListCurrencyGroupsReturn {
Expand Down Expand Up @@ -2141,6 +2170,21 @@ export class API implements API {
)
}

satisfy = (args: SatisfyArgs, headers?: object, signal?: AbortSignal): Promise<SatisfyReturn> => {
return this.fetch(this.url('Satisfy'), createHTTPRequest(args, headers, signal)).then(
res => {
return buildResponse(res).then(_data => {
return {
solutions: <Array<Solution>>_data.solutions
}
})
},
error => {
throw WebrpcRequestFailedError.new({ cause: `fetch(): ${error.message || ''}` })
}
)
}

listCurrencyGroups = (headers?: object, signal?: AbortSignal): Promise<ListCurrencyGroupsReturn> => {
return this.fetch(this.url('ListCurrencyGroups'), createHTTPRequest({}, headers, signal)).then(
res => {
Expand Down
42 changes: 39 additions & 3 deletions packages/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
export * from './api.gen'
import {
Precondition as ChainPrecondition,
encodePrecondition as encodeChainPrecondition,
isPrecondition as isChainPrecondition
} from '@0xsequence/relayer'
import { ethers } from 'ethers'

import { API as ApiRpc } from './api.gen'
import * as proto from './api.gen'

export class SequenceAPIClient extends ApiRpc {
export class SequenceAPIClient extends proto.API {
constructor(
hostname: string,
public projectAccessKey?: string,
Expand Down Expand Up @@ -34,3 +39,34 @@ export class SequenceAPIClient extends ApiRpc {
return fetch(input, init)
}
}

export * from './api.gen'

export type Precondition = { chainId: ethers.BigNumberish } & ChainPrecondition

export function isPrecondition(precondition: any): precondition is Precondition {
return (
typeof precondition === 'object' && precondition && isBigNumberish(precondition.chainId) && isChainPrecondition(precondition)
)
}

export function encodePrecondition(precondition: Precondition): proto.Precondition {
const { type, precondition: args } = encodeChainPrecondition(precondition)
delete args.chainId
return { type, chainID: encodeBigNumberish(precondition.chainId), precondition: args }
}

function isBigNumberish(value: any): value is ethers.BigNumberish {
try {
ethers.toBigInt(value)
return true
} catch {
return false
}
}

function encodeBigNumberish<T extends ethers.BigNumberish | undefined>(
value: T
): T extends ethers.BigNumberish ? string : undefined {
return value !== undefined ? ethers.toBigInt(value).toString() : (undefined as any)
}
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export const SignerJsonRpcMethods = [
'wallet_switchEthereumChain',
'wallet_registerOnboarding',
'wallet_watchAsset',
'wallet_scanQRCode'
'wallet_scanQRCode',

// EIP-5792
'wallet_sendCalls',
'wallet_getCallsStatus',
'wallet_showCallsStatus',
'wallet_getCapabilities'
]

export class SigningProvider implements JsonRpcMiddlewareHandler {
Expand Down
1 change: 1 addition & 0 deletions packages/provider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"dependencies": {
"@0xsequence/abi": "workspace:*",
"@0xsequence/account": "workspace:*",
"@0xsequence/api": "workspace:*",
"@0xsequence/auth": "workspace:*",
"@0xsequence/core": "workspace:*",
"@0xsequence/migration": "workspace:*",
Expand Down
Loading
Loading