Skip to content

Commit

Permalink
feat(public): add createAccessList
Browse files Browse the repository at this point in the history
  • Loading branch information
Rubilmax committed Oct 14, 2024
1 parent f81d497 commit e820a54
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 2 deletions.
12 changes: 10 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

157 changes: 157 additions & 0 deletions src/actions/public/createAccessList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import type { Address } from 'abitype'

import type { Account } from '../../accounts/types.js'
import {
type ParseAccountErrorType,
parseAccount,
} from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import type { RpcTransactionRequest } from '../../types/rpc.js'
import type { AccessList, TransactionRequest } from '../../types/transaction.js'
import type { ExactPartial, UnionOmit } from '../../types/utils.js'
import type { RequestErrorType } from '../../utils/buildRequest.js'
import {
type NumberToHexErrorType,
numberToHex,
} from '../../utils/encoding/toHex.js'
import { getCallError } from '../../utils/errors/getCallError.js'
import type { GetCreateAccessListErrorReturnType } from '../../utils/errors/getCreateAccessList.js'
import { extract } from '../../utils/formatters/extract.js'
import {
type FormatTransactionRequestErrorType,
type FormattedTransactionRequest,
formatTransactionRequest,
} from '../../utils/formatters/transactionRequest.js'
import { assertRequest } from '../../utils/transaction/assertRequest.js'
import type {
AssertRequestErrorType,
AssertRequestParameters,
} from '../../utils/transaction/assertRequest.js'

export type CreateAccessListParameters<
chain extends Chain | undefined = Chain | undefined,
> = UnionOmit<
FormattedTransactionRequest<chain>,
'from' | 'nonce' | 'accessList'
> & {
/** Account attached to the call (msg.sender). */
account?: Account | Address | undefined
} & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/**
* The balance of the account at a block tag.
* @default 'latest'
*/
blockTag?: BlockTag | undefined
}
)

export type CreateAccessListReturnType = {
accessList: AccessList
gasUsed: bigint
}

export type CreateAccessListErrorType = GetCreateAccessListErrorReturnType<
| ParseAccountErrorType
| AssertRequestErrorType
| NumberToHexErrorType
| FormatTransactionRequestErrorType
| RequestErrorType
>

/**
* Creates an EIP-2930 access list that you can include in a transaction.
*
* - Docs: https://viem.sh/docs/actions/public/call
* - JSON-RPC Methods: [`eth_createAccessList`](https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_createaccesslist)
*
* @param client - Client to use
* @param parameters - {@link CreateAccessListParameters}
* @returns The access list. {@link CreateAccessListReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
* import { createAccessList } from 'viem/public'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const data = await createAccessList(client, {
* account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* })
*/
export async function createAccessList<chain extends Chain | undefined>(
client: Client<Transport, chain>,
args: CreateAccessListParameters<chain>,
): Promise<CreateAccessListReturnType> {
const {
account: account_ = client.account,
blockNumber,
blockTag = 'latest',
blobs,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
to,
value,
...rest
} = args
const account = account_ ? parseAccount(account_) : undefined

try {
assertRequest(args as AssertRequestParameters)

const blockNumberHex = blockNumber ? numberToHex(blockNumber) : undefined
const block = blockNumberHex || blockTag

const chainFormat = client.chain?.formatters?.transactionRequest?.format
const format = chainFormat || formatTransactionRequest

const request = format({
// Pick out extra data that might exist on the chain's transaction request type.
...extract(rest, { format: chainFormat }),
from: account?.address,
blobs,
data,
gas,
gasPrice,
maxFeePerBlobGas,
maxFeePerGas,
maxPriorityFeePerGas,
to,
value,
} as TransactionRequest) as TransactionRequest

const response = await client.request({
method: 'eth_createAccessList',
params: [request as ExactPartial<RpcTransactionRequest>, block],
})
return {
accessList: response.accessList,
gasUsed: BigInt(response.gasUsed),
}
} catch (err) {
throw getCallError(err as ErrorType, {
...args,
account,
chain: client.chain,
})
}
}
32 changes: 32 additions & 0 deletions src/clients/decorators/public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import {
type CallReturnType,
call,
} from '../../actions/public/call.js'
import {
type CreateAccessListParameters,
type CreateAccessListReturnType,
createAccessList,
} from '../../actions/public/createAccessList.js'
import {
type CreateBlockFilterReturnType,
createBlockFilter,
Expand Down Expand Up @@ -285,6 +290,32 @@ export type PublicActions<
* })
*/
call: (parameters: CallParameters<chain>) => Promise<CallReturnType>
/**
* Creates an EIP-2930 access list that you can include in a transaction.
*
* - Docs: https://viem.sh/docs/actions/public/createAccessList
* - JSON-RPC Methods: [`eth_createAccessList`](https://docs.infura.io/api/networks/ethereum/json-rpc-methods/eth_createaccesslist)
*
* @param args - {@link CreateAccessListParameters}
* @returns The call data. {@link CreateAccessListReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const data = await client.createAccessList({
* account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* })
*/
createAccessList: (
parameters: CreateAccessListParameters<chain>,
) => Promise<CreateAccessListReturnType>
/**
* Creates a Filter to listen for new block hashes that can be used with [`getFilterChanges`](https://viem.sh/docs/actions/public/getFilterChanges).
*
Expand Down Expand Up @@ -1833,6 +1864,7 @@ export function publicActions<
): PublicActions<transport, chain, account> {
return {
call: (args) => call(client, args),
createAccessList: (args) => createAccessList(client, args),
createBlockFilter: () => createBlockFilter(client),
createContractEventFilter: (args) =>
createContractEventFilter(client, args),
Expand Down
21 changes: 21 additions & 0 deletions src/types/eip1193.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
RpcTransactionRequest as TransactionRequest,
RpcUncle as Uncle,
} from './rpc.js'
import type { AccessList } from './transaction.js'
import type { ExactPartial, OneOf, PartialBy, Prettify } from './utils.js'

//////////////////////////////////////////////////
Expand Down Expand Up @@ -644,6 +645,26 @@ export type PublicRpcSchema = [
]
ReturnType: Hex
},
/**
* @description Executes a new message call immediately without submitting a transaction to the network
*
* @example
* provider.request({ method: 'eth_call', params: [{ to: '0x...', data: '0x...' }] })
* // => '0x...'
*/
{
Method: 'eth_createAccessList'
Parameters:
| [transaction: ExactPartial<TransactionRequest>]
| [
transaction: ExactPartial<TransactionRequest>,
block: BlockNumber | BlockTag | BlockIdentifier,
]
ReturnType: {
accessList: AccessList
gasUsed: Quantity
}
},
/**
* @description Returns the chain ID associated with the current network
* @example
Expand Down
46 changes: 46 additions & 0 deletions src/utils/errors/getCreateAccessList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { CreateAccessListParameters } from '../../actions/public/createAccessList.js'
import type { BaseError } from '../../errors/base.js'
import {
CallExecutionError,
type CallExecutionErrorType,
} from '../../errors/contract.js'
import { UnknownNodeError } from '../../errors/node.js'
import type { ErrorType } from '../../errors/utils.js'
import type { Chain } from '../../types/chain.js'

import {
type GetNodeErrorParameters,
type GetNodeErrorReturnType,
getNodeError,
} from './getNodeError.js'

export type GetCreateAccessListErrorReturnType<cause = ErrorType> = Omit<
CallExecutionErrorType,
'cause'
> & {
cause: cause | GetNodeErrorReturnType
}

export function getCreateAccessListError<err extends ErrorType<string>>(
err: err,
{
docsPath,
...args
}: CreateAccessListParameters & {
chain?: Chain | undefined
docsPath?: string | undefined
},
): GetCreateAccessListErrorReturnType<err> {
const cause = (() => {
const cause = getNodeError(
err as {} as BaseError,
args as GetNodeErrorParameters,
)
if (cause instanceof UnknownNodeError) return err as {} as BaseError
return cause
})()
return new CallExecutionError(cause, {
docsPath,
...args,
}) as GetCreateAccessListErrorReturnType<err>
}

0 comments on commit e820a54

Please sign in to comment.