plugins-network.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import { defineProperties } from "../utils/properties.js";
  2. import { assertArgument } from "../utils/index.js";
  3. import type { FeeData, Provider } from "./provider.js";
  4. import type { FetchRequest } from "../utils/fetch.js";
  5. const EnsAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
  6. /**
  7. * A **NetworkPlugin** provides additional functionality on a [[Network]].
  8. */
  9. export class NetworkPlugin {
  10. /**
  11. * The name of the plugin.
  12. *
  13. * It is recommended to use reverse-domain-notation, which permits
  14. * unique names with a known authority as well as hierarchal entries.
  15. */
  16. readonly name!: string;
  17. /**
  18. * Creates a new **NetworkPlugin**.
  19. */
  20. constructor(name: string) {
  21. defineProperties<NetworkPlugin>(this, { name });
  22. }
  23. /**
  24. * Creates a copy of this plugin.
  25. */
  26. clone(): NetworkPlugin {
  27. return new NetworkPlugin(this.name);
  28. }
  29. // validate(network: Network): NetworkPlugin {
  30. // return this;
  31. // }
  32. }
  33. /**
  34. * The gas cost parameters for a [[GasCostPlugin]].
  35. */
  36. export type GasCostParameters = {
  37. /**
  38. * The transactions base fee.
  39. */
  40. txBase?: number;
  41. /**
  42. * The fee for creating a new account.
  43. */
  44. txCreate?: number;
  45. /**
  46. * The fee per zero-byte in the data.
  47. */
  48. txDataZero?: number;
  49. /**
  50. * The fee per non-zero-byte in the data.
  51. */
  52. txDataNonzero?: number;
  53. /**
  54. * The fee per storage key in the [[link-eip-2930]] access list.
  55. */
  56. txAccessListStorageKey?: number;
  57. /**
  58. * The fee per address in the [[link-eip-2930]] access list.
  59. */
  60. txAccessListAddress?: number;
  61. };
  62. /**
  63. * A **GasCostPlugin** allows a network to provide alternative values when
  64. * computing the intrinsic gas required for a transaction.
  65. */
  66. export class GasCostPlugin extends NetworkPlugin implements GasCostParameters {
  67. /**
  68. * The block number to treat these values as valid from.
  69. *
  70. * This allows a hardfork to have updated values included as well as
  71. * mulutiple hardforks to be supported.
  72. */
  73. readonly effectiveBlock!: number;
  74. /**
  75. * The transactions base fee.
  76. */
  77. readonly txBase!: number;
  78. /**
  79. * The fee for creating a new account.
  80. */
  81. readonly txCreate!: number;
  82. /**
  83. * The fee per zero-byte in the data.
  84. */
  85. readonly txDataZero!: number;
  86. /**
  87. * The fee per non-zero-byte in the data.
  88. */
  89. readonly txDataNonzero!: number;
  90. /**
  91. * The fee per storage key in the [[link-eip-2930]] access list.
  92. */
  93. readonly txAccessListStorageKey!: number;
  94. /**
  95. * The fee per address in the [[link-eip-2930]] access list.
  96. */
  97. readonly txAccessListAddress!: number;
  98. /**
  99. * Creates a new GasCostPlugin from %%effectiveBlock%% until the
  100. * latest block or another GasCostPlugin supercedes that block number,
  101. * with the associated %%costs%%.
  102. */
  103. constructor(effectiveBlock?: number, costs?: GasCostParameters) {
  104. if (effectiveBlock == null) { effectiveBlock = 0; }
  105. super(`org.ethers.network.plugins.GasCost#${ (effectiveBlock || 0) }`);
  106. const props: Record<string, number> = { effectiveBlock };
  107. function set(name: keyof GasCostParameters, nullish: number): void {
  108. let value = (costs || { })[name];
  109. if (value == null) { value = nullish; }
  110. assertArgument(typeof(value) === "number", `invalud value for ${ name }`, "costs", costs);
  111. props[name] = value;
  112. }
  113. set("txBase", 21000);
  114. set("txCreate", 32000);
  115. set("txDataZero", 4);
  116. set("txDataNonzero", 16);
  117. set("txAccessListStorageKey", 1900);
  118. set("txAccessListAddress", 2400);
  119. defineProperties<GasCostPlugin>(this, props);
  120. }
  121. clone(): GasCostPlugin {
  122. return new GasCostPlugin(this.effectiveBlock, this);
  123. }
  124. }
  125. /**
  126. * An **EnsPlugin** allows a [[Network]] to specify the ENS Registry
  127. * Contract address and the target network to use when using that
  128. * contract.
  129. *
  130. * Various testnets have their own instance of the contract to use, but
  131. * in general, the mainnet instance supports multi-chain addresses and
  132. * should be used.
  133. */
  134. export class EnsPlugin extends NetworkPlugin {
  135. /**
  136. * The ENS Registrty Contract address.
  137. */
  138. readonly address!: string;
  139. /**
  140. * The chain ID that the ENS contract lives on.
  141. */
  142. readonly targetNetwork!: number;
  143. /**
  144. * Creates a new **EnsPlugin** connected to %%address%% on the
  145. * %%targetNetwork%%. The default ENS address and mainnet is used
  146. * if unspecified.
  147. */
  148. constructor(address?: null | string, targetNetwork?: null | number) {
  149. super("org.ethers.plugins.network.Ens");
  150. defineProperties<EnsPlugin>(this, {
  151. address: (address || EnsAddress),
  152. targetNetwork: ((targetNetwork == null) ? 1: targetNetwork)
  153. });
  154. }
  155. clone(): EnsPlugin {
  156. return new EnsPlugin(this.address, this.targetNetwork);
  157. }
  158. }
  159. /**
  160. * A **FeeDataNetworkPlugin** allows a network to provide and alternate
  161. * means to specify its fee data.
  162. *
  163. * For example, a network which does not support [[link-eip-1559]] may
  164. * choose to use a Gas Station site to approximate the gas price.
  165. */
  166. export class FeeDataNetworkPlugin extends NetworkPlugin {
  167. readonly #feeDataFunc: (provider: Provider) => Promise<FeeData>;
  168. /**
  169. * The fee data function provided to the constructor.
  170. */
  171. get feeDataFunc(): (provider: Provider) => Promise<FeeData> {
  172. return this.#feeDataFunc;
  173. }
  174. /**
  175. * Creates a new **FeeDataNetworkPlugin**.
  176. */
  177. constructor(feeDataFunc: (provider: Provider) => Promise<FeeData>) {
  178. super("org.ethers.plugins.network.FeeData");
  179. this.#feeDataFunc = feeDataFunc;
  180. }
  181. /**
  182. * Resolves to the fee data.
  183. */
  184. async getFeeData(provider: Provider): Promise<FeeData> {
  185. return await this.#feeDataFunc(provider);
  186. }
  187. clone(): FeeDataNetworkPlugin {
  188. return new FeeDataNetworkPlugin(this.#feeDataFunc);
  189. }
  190. }
  191. export class FetchUrlFeeDataNetworkPlugin extends NetworkPlugin {
  192. readonly #url: string;
  193. readonly #processFunc: (f: () => Promise<FeeData>, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }>;
  194. /**
  195. * The URL to initialize the FetchRequest with in %%processFunc%%.
  196. */
  197. get url(): string { return this.#url; }
  198. /**
  199. * The callback to use when computing the FeeData.
  200. */
  201. get processFunc(): (f: () => Promise<FeeData>, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }> { return this.#processFunc; }
  202. /**
  203. * Creates a new **FetchUrlFeeDataNetworkPlugin** which will
  204. * be used when computing the fee data for the network.
  205. */
  206. constructor(url: string, processFunc: (f: () => Promise<FeeData>, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }>) {
  207. super("org.ethers.plugins.network.FetchUrlFeeDataPlugin");
  208. this.#url = url;
  209. this.#processFunc = processFunc;
  210. }
  211. // We are immutable, so we can serve as our own clone
  212. clone(): FetchUrlFeeDataNetworkPlugin { return this; }
  213. }
  214. /*
  215. export class CustomBlockNetworkPlugin extends NetworkPlugin {
  216. readonly #blockFunc: (provider: Provider, block: BlockParams<string>) => Block<string>;
  217. readonly #blockWithTxsFunc: (provider: Provider, block: BlockParams<TransactionResponseParams>) => Block<TransactionResponse>;
  218. constructor(blockFunc: (provider: Provider, block: BlockParams<string>) => Block<string>, blockWithTxsFunc: (provider: Provider, block: BlockParams<TransactionResponseParams>) => Block<TransactionResponse>) {
  219. super("org.ethers.network-plugins.custom-block");
  220. this.#blockFunc = blockFunc;
  221. this.#blockWithTxsFunc = blockWithTxsFunc;
  222. }
  223. async getBlock(provider: Provider, block: BlockParams<string>): Promise<Block<string>> {
  224. return await this.#blockFunc(provider, block);
  225. }
  226. async getBlockions(provider: Provider, block: BlockParams<TransactionResponseParams>): Promise<Block<TransactionResponse>> {
  227. return await this.#blockWithTxsFunc(provider, block);
  228. }
  229. clone(): CustomBlockNetworkPlugin {
  230. return new CustomBlockNetworkPlugin(this.#blockFunc, this.#blockWithTxsFunc);
  231. }
  232. }
  233. */