import { defineProperties } from "../utils/properties.js"; import { assertArgument } from "../utils/index.js"; import type { FeeData, Provider } from "./provider.js"; import type { FetchRequest } from "../utils/fetch.js"; const EnsAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; /** * A **NetworkPlugin** provides additional functionality on a [[Network]]. */ export class NetworkPlugin { /** * The name of the plugin. * * It is recommended to use reverse-domain-notation, which permits * unique names with a known authority as well as hierarchal entries. */ readonly name!: string; /** * Creates a new **NetworkPlugin**. */ constructor(name: string) { defineProperties(this, { name }); } /** * Creates a copy of this plugin. */ clone(): NetworkPlugin { return new NetworkPlugin(this.name); } // validate(network: Network): NetworkPlugin { // return this; // } } /** * The gas cost parameters for a [[GasCostPlugin]]. */ export type GasCostParameters = { /** * The transactions base fee. */ txBase?: number; /** * The fee for creating a new account. */ txCreate?: number; /** * The fee per zero-byte in the data. */ txDataZero?: number; /** * The fee per non-zero-byte in the data. */ txDataNonzero?: number; /** * The fee per storage key in the [[link-eip-2930]] access list. */ txAccessListStorageKey?: number; /** * The fee per address in the [[link-eip-2930]] access list. */ txAccessListAddress?: number; }; /** * A **GasCostPlugin** allows a network to provide alternative values when * computing the intrinsic gas required for a transaction. */ export class GasCostPlugin extends NetworkPlugin implements GasCostParameters { /** * The block number to treat these values as valid from. * * This allows a hardfork to have updated values included as well as * mulutiple hardforks to be supported. */ readonly effectiveBlock!: number; /** * The transactions base fee. */ readonly txBase!: number; /** * The fee for creating a new account. */ readonly txCreate!: number; /** * The fee per zero-byte in the data. */ readonly txDataZero!: number; /** * The fee per non-zero-byte in the data. */ readonly txDataNonzero!: number; /** * The fee per storage key in the [[link-eip-2930]] access list. */ readonly txAccessListStorageKey!: number; /** * The fee per address in the [[link-eip-2930]] access list. */ readonly txAccessListAddress!: number; /** * Creates a new GasCostPlugin from %%effectiveBlock%% until the * latest block or another GasCostPlugin supercedes that block number, * with the associated %%costs%%. */ constructor(effectiveBlock?: number, costs?: GasCostParameters) { if (effectiveBlock == null) { effectiveBlock = 0; } super(`org.ethers.network.plugins.GasCost#${ (effectiveBlock || 0) }`); const props: Record = { effectiveBlock }; function set(name: keyof GasCostParameters, nullish: number): void { let value = (costs || { })[name]; if (value == null) { value = nullish; } assertArgument(typeof(value) === "number", `invalud value for ${ name }`, "costs", costs); props[name] = value; } set("txBase", 21000); set("txCreate", 32000); set("txDataZero", 4); set("txDataNonzero", 16); set("txAccessListStorageKey", 1900); set("txAccessListAddress", 2400); defineProperties(this, props); } clone(): GasCostPlugin { return new GasCostPlugin(this.effectiveBlock, this); } } /** * An **EnsPlugin** allows a [[Network]] to specify the ENS Registry * Contract address and the target network to use when using that * contract. * * Various testnets have their own instance of the contract to use, but * in general, the mainnet instance supports multi-chain addresses and * should be used. */ export class EnsPlugin extends NetworkPlugin { /** * The ENS Registrty Contract address. */ readonly address!: string; /** * The chain ID that the ENS contract lives on. */ readonly targetNetwork!: number; /** * Creates a new **EnsPlugin** connected to %%address%% on the * %%targetNetwork%%. The default ENS address and mainnet is used * if unspecified. */ constructor(address?: null | string, targetNetwork?: null | number) { super("org.ethers.plugins.network.Ens"); defineProperties(this, { address: (address || EnsAddress), targetNetwork: ((targetNetwork == null) ? 1: targetNetwork) }); } clone(): EnsPlugin { return new EnsPlugin(this.address, this.targetNetwork); } } /** * A **FeeDataNetworkPlugin** allows a network to provide and alternate * means to specify its fee data. * * For example, a network which does not support [[link-eip-1559]] may * choose to use a Gas Station site to approximate the gas price. */ export class FeeDataNetworkPlugin extends NetworkPlugin { readonly #feeDataFunc: (provider: Provider) => Promise; /** * The fee data function provided to the constructor. */ get feeDataFunc(): (provider: Provider) => Promise { return this.#feeDataFunc; } /** * Creates a new **FeeDataNetworkPlugin**. */ constructor(feeDataFunc: (provider: Provider) => Promise) { super("org.ethers.plugins.network.FeeData"); this.#feeDataFunc = feeDataFunc; } /** * Resolves to the fee data. */ async getFeeData(provider: Provider): Promise { return await this.#feeDataFunc(provider); } clone(): FeeDataNetworkPlugin { return new FeeDataNetworkPlugin(this.#feeDataFunc); } } export class FetchUrlFeeDataNetworkPlugin extends NetworkPlugin { readonly #url: string; readonly #processFunc: (f: () => Promise, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }>; get url() { return this.#url; } get processFunc() { return this.#processFunc; } constructor(url: string, processFunc: (f: () => Promise, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }>) { super("org.ethers.plugins.network.FetchUrlFeeDataPlugin"); this.#url = url; this.#processFunc = processFunc; } // We are immutable, so we can serve as our own clone clone(): FetchUrlFeeDataNetworkPlugin { return this; } } /* export class CustomBlockNetworkPlugin extends NetworkPlugin { readonly #blockFunc: (provider: Provider, block: BlockParams) => Block; readonly #blockWithTxsFunc: (provider: Provider, block: BlockParams) => Block; constructor(blockFunc: (provider: Provider, block: BlockParams) => Block, blockWithTxsFunc: (provider: Provider, block: BlockParams) => Block) { super("org.ethers.network-plugins.custom-block"); this.#blockFunc = blockFunc; this.#blockWithTxsFunc = blockWithTxsFunc; } async getBlock(provider: Provider, block: BlockParams): Promise> { return await this.#blockFunc(provider, block); } async getBlockions(provider: Provider, block: BlockParams): Promise> { return await this.#blockWithTxsFunc(provider, block); } clone(): CustomBlockNetworkPlugin { return new CustomBlockNetworkPlugin(this.#blockFunc, this.#blockWithTxsFunc); } } */