- Consolidated duplicate UndoManagers to single instance - Fixed connection promise to only resolve on 'connected' status - Fixed WebSocketProvider import (WebsocketProvider) - Added proper doc.destroy() cleanup - Renamed isPresenceInitialized property to avoid conflict Co-Authored-By: Paperclip <noreply@paperclip.ing>
230 lines
7.1 KiB
TypeScript
230 lines
7.1 KiB
TypeScript
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 { BaseError } from '../../errors/base.js'
|
|
import type { BlockTag } from '../../types/block.js'
|
|
import type { Chain } from '../../types/chain.js'
|
|
import type { StateOverride } from '../../types/stateOverride.js'
|
|
import type { TransactionRequest } from '../../types/transaction.js'
|
|
import type { UnionOmit } from '../../types/utils.js'
|
|
import {
|
|
type RecoverAuthorizationAddressErrorType,
|
|
recoverAuthorizationAddress,
|
|
} from '../../utils/authorization/recoverAuthorizationAddress.js'
|
|
import type { RequestErrorType } from '../../utils/buildRequest.js'
|
|
import {
|
|
type NumberToHexErrorType,
|
|
numberToHex,
|
|
} from '../../utils/encoding/toHex.js'
|
|
import {
|
|
type GetEstimateGasErrorReturnType,
|
|
getEstimateGasError,
|
|
} from '../../utils/errors/getEstimateGasError.js'
|
|
import { extract } from '../../utils/formatters/extract.js'
|
|
import {
|
|
type FormattedTransactionRequest,
|
|
formatTransactionRequest,
|
|
} from '../../utils/formatters/transactionRequest.js'
|
|
import { serializeStateOverride } from '../../utils/stateOverride.js'
|
|
import {
|
|
type AssertRequestErrorType,
|
|
type AssertRequestParameters,
|
|
assertRequest,
|
|
} from '../../utils/transaction/assertRequest.js'
|
|
import {
|
|
type PrepareTransactionRequestParameters,
|
|
type PrepareTransactionRequestParameterType,
|
|
prepareTransactionRequest,
|
|
} from '../wallet/prepareTransactionRequest.js'
|
|
|
|
export type EstimateGasParameters<
|
|
chain extends Chain | undefined = Chain | undefined,
|
|
> = UnionOmit<FormattedEstimateGas<chain>, 'from'> & {
|
|
account?: Account | Address | undefined
|
|
prepare?:
|
|
| boolean
|
|
| readonly PrepareTransactionRequestParameterType[]
|
|
| undefined
|
|
stateOverride?: StateOverride | 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
|
|
}
|
|
)
|
|
type FormattedEstimateGas<chain extends Chain | undefined = Chain | undefined> =
|
|
FormattedTransactionRequest<chain>
|
|
|
|
export type EstimateGasReturnType = bigint
|
|
|
|
export type EstimateGasErrorType = GetEstimateGasErrorReturnType<
|
|
| ParseAccountErrorType
|
|
| NumberToHexErrorType
|
|
| RequestErrorType
|
|
| RecoverAuthorizationAddressErrorType
|
|
| AssertRequestErrorType
|
|
>
|
|
|
|
/**
|
|
* Estimates the gas necessary to complete a transaction without submitting it to the network.
|
|
*
|
|
* - Docs: https://viem.sh/docs/actions/public/estimateGas
|
|
* - JSON-RPC Methods: [`eth_estimateGas`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas)
|
|
*
|
|
* @param client - Client to use
|
|
* @param parameters - {@link EstimateGasParameters}
|
|
* @returns The gas estimate (in gas units). {@link EstimateGasReturnType}
|
|
*
|
|
* @example
|
|
* import { createPublicClient, http, parseEther } from 'viem'
|
|
* import { mainnet } from 'viem/chains'
|
|
* import { estimateGas } from 'viem/public'
|
|
*
|
|
* const client = createPublicClient({
|
|
* chain: mainnet,
|
|
* transport: http(),
|
|
* })
|
|
* const gasEstimate = await estimateGas(client, {
|
|
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
|
|
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
|
|
* value: parseEther('1'),
|
|
* })
|
|
*/
|
|
export async function estimateGas<
|
|
chain extends Chain | undefined,
|
|
account extends Account | undefined = undefined,
|
|
>(
|
|
client: Client<Transport, chain, account>,
|
|
args: EstimateGasParameters<chain>,
|
|
): Promise<EstimateGasReturnType> {
|
|
const { account: account_ = client.account, prepare = true } = args
|
|
const account = account_ ? parseAccount(account_) : undefined
|
|
|
|
const parameters = (() => {
|
|
if (Array.isArray(prepare)) return prepare
|
|
// Some RPC Providers do not compute versioned hashes from blobs. We will need
|
|
// to compute them.
|
|
if (account?.type !== 'local') return ['blobVersionedHashes']
|
|
return undefined
|
|
})()
|
|
|
|
try {
|
|
const to = await (async () => {
|
|
// If `to` exists on the parameters, use that.
|
|
if (args.to) return args.to
|
|
|
|
// If no `to` exists, and we are sending a EIP-7702 transaction, use the
|
|
// address of the first authorization in the list.
|
|
if (args.authorizationList && args.authorizationList.length > 0)
|
|
return await recoverAuthorizationAddress({
|
|
authorization: args.authorizationList[0],
|
|
}).catch(() => {
|
|
throw new BaseError(
|
|
'`to` is required. Could not infer from `authorizationList`',
|
|
)
|
|
})
|
|
|
|
// Otherwise, we are sending a deployment transaction.
|
|
return undefined
|
|
})()
|
|
|
|
const {
|
|
accessList,
|
|
authorizationList,
|
|
blobs,
|
|
blobVersionedHashes,
|
|
blockNumber,
|
|
blockTag,
|
|
data,
|
|
gas,
|
|
gasPrice,
|
|
maxFeePerBlobGas,
|
|
maxFeePerGas,
|
|
maxPriorityFeePerGas,
|
|
nonce,
|
|
value,
|
|
stateOverride,
|
|
...rest
|
|
} = prepare
|
|
? ((await prepareTransactionRequest(client, {
|
|
...args,
|
|
parameters,
|
|
to,
|
|
} as PrepareTransactionRequestParameters)) as EstimateGasParameters)
|
|
: args
|
|
|
|
// If we get `gas` back from the prepared transaction request, which is
|
|
// different from the `gas` we provided, it was likely filled by other means
|
|
// during request preparation (e.g. `eth_fillTransaction` or `chain.transactionRequest.prepare`).
|
|
// (e.g. `eth_fillTransaction` or `chain.transactionRequest.prepare`).
|
|
if (gas && args.gas !== gas) return gas
|
|
|
|
const blockNumberHex =
|
|
typeof blockNumber === 'bigint' ? numberToHex(blockNumber) : undefined
|
|
const block = blockNumberHex || blockTag
|
|
|
|
const rpcStateOverride = serializeStateOverride(stateOverride)
|
|
|
|
assertRequest(args as AssertRequestParameters)
|
|
|
|
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 }),
|
|
account,
|
|
accessList,
|
|
authorizationList,
|
|
blobs,
|
|
blobVersionedHashes,
|
|
data,
|
|
gasPrice,
|
|
maxFeePerBlobGas,
|
|
maxFeePerGas,
|
|
maxPriorityFeePerGas,
|
|
nonce,
|
|
to,
|
|
value,
|
|
} as TransactionRequest,
|
|
'estimateGas',
|
|
)
|
|
|
|
return BigInt(
|
|
await client.request({
|
|
method: 'eth_estimateGas',
|
|
params: rpcStateOverride
|
|
? [
|
|
request,
|
|
block ?? client.experimental_blockTag ?? 'latest',
|
|
rpcStateOverride,
|
|
]
|
|
: block
|
|
? [request, block]
|
|
: [request],
|
|
}),
|
|
)
|
|
} catch (err) {
|
|
throw getEstimateGasError(err as BaseError, {
|
|
...args,
|
|
account,
|
|
chain: client.chain,
|
|
})
|
|
}
|
|
}
|