@getclave/permissionless
Version:
A utility library for working with ERC-4337
103 lines (90 loc) • 3.28 kB
text/typescript
import {
type Account,
type Address,
type Chain,
ChainNotFoundError,
type Client,
type GetChainParameter,
type Transport
} from "viem"
import type { EntryPointVersion, UserOperation } from "viem/account-abstraction"
import { getAction } from "viem/utils"
import type { PimlicoRpcSchema } from "../../types/pimlico"
import { getRequiredPrefund } from "../../utils/getRequiredPrefund"
import { getTokenQuotes } from "./getTokenQuotes"
/**
* @costInToken represents the max amount of token that will be charged for this user operation in token decimals
* @costInUsd represents the max amount of USD value of the token in 10^6 decimals
*/
export type EstimateErc20PaymasterCostReturnType = {
costInToken: bigint
costInUsd: bigint
}
export type EstimateErc20PaymasterCostParameters<
entryPointVersion extends EntryPointVersion,
TChain extends Chain | undefined,
TChainOverride extends Chain | undefined = Chain | undefined
> = {
entryPoint: { version: entryPointVersion; address: Address }
userOperation: UserOperation<entryPointVersion>
token: Address
} & GetChainParameter<TChain, TChainOverride>
/**
* Returns all related fields to calculate the potential cost of a userOperation in ERC-20 tokens.
*
* - Docs: https://docs.pimlico.io/permissionless/reference/pimlico-bundler-actions/EstimateErc20PaymasterCost
*
* @param client that you created using viem's createClient whose transport url is pointing to the Pimlico's bundler.
* @returns quotes, see {@link EstimateErc20PaymasterCostReturnType}
*
*/
export const estimateErc20PaymasterCost = async <
entryPointVersion extends EntryPointVersion,
TChain extends Chain | undefined,
TChainOverride extends Chain | undefined = Chain | undefined
>(
client: Client<
Transport,
TChain,
Account | undefined,
PimlicoRpcSchema<entryPointVersion>
>,
args: EstimateErc20PaymasterCostParameters<
entryPointVersion,
TChain,
TChainOverride
>
): Promise<EstimateErc20PaymasterCostReturnType> => {
const chain = args.chain ?? client.chain
if (!chain) {
throw new ChainNotFoundError()
}
const { entryPoint, userOperation, token } = args
const quotes = await getAction(
client,
getTokenQuotes,
"getTokenQuotes"
)({
tokens: [token],
entryPointAddress: entryPoint.address,
chain
})
const postOpGas = quotes[0].postOpGas
const exchangeRate = quotes[0].exchangeRate
const exchangeRateNativeToUsd = quotes[0].exchangeRateNativeToUsd
const userOperationMaxCost = getRequiredPrefund({
userOperation,
entryPointVersion: entryPoint.version
})
// represents the userOperation's max cost in denomination of wei
const maxCostInWei =
userOperationMaxCost + postOpGas * userOperation.maxFeePerGas
// represents the userOperation's max cost in token denomination (wei)
const costInToken = (maxCostInWei * exchangeRate) / BigInt(1e18)
// represents the userOperation's max cost in usd (with 6 decimals of precision)
const costInUsd = (maxCostInWei * exchangeRateNativeToUsd) / 10n ** 18n
return {
costInToken,
costInUsd
}
}