From f5281a03426ccd3fb4a61968d99746c1de5e400e Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Wed, 30 Nov 2022 13:44:47 -0500 Subject: [PATCH] docs: added more jsdocs for providers --- src.ts/providers/abstract-provider.ts | 15 +- src.ts/providers/abstract-signer.ts | 5 + src.ts/providers/community.ts | 8 +- src.ts/providers/format.ts | 3 + src.ts/providers/formatting.ts | 195 +++++++++++++ src.ts/providers/index.ts | 20 +- src.ts/providers/network.ts | 2 +- src.ts/providers/plugins-network.ts | 9 +- src.ts/providers/provider-alchemy.ts | 2 + src.ts/providers/provider-ankr.ts | 5 + src.ts/providers/provider-cloudflare.ts | 6 +- src.ts/providers/provider-etherscan-base.ts | 15 + src.ts/providers/provider-etherscan.ts | 9 + src.ts/providers/provider-infura.ts | 11 + src.ts/providers/provider-jsonrpc.ts | 52 ++-- src.ts/providers/provider-socket.ts | 8 +- src.ts/providers/provider.ts | 291 +++++++++++++++++--- src.ts/providers/subscriber-connection.ts | 11 + src.ts/providers/subscriber-filterid.ts | 20 ++ src.ts/providers/subscriber-hotswap.ts | 41 --- src.ts/providers/subscriber-polling.ts | 30 ++ src.ts/providers/thirdparty.ts | 15 - 22 files changed, 632 insertions(+), 141 deletions(-) create mode 100644 src.ts/providers/formatting.ts delete mode 100644 src.ts/providers/subscriber-hotswap.ts delete mode 100644 src.ts/providers/thirdparty.ts diff --git a/src.ts/providers/abstract-provider.ts b/src.ts/providers/abstract-provider.ts index f764fe551..452f897f0 100644 --- a/src.ts/providers/abstract-provider.ts +++ b/src.ts/providers/abstract-provider.ts @@ -1,3 +1,9 @@ +/** + * About Subclassing the Provider... + * + * @_section: api/providers/abstract-provider: Subclassing Provider [abstract-provider] + */ + // @TODO // Event coalescence // When we register an event with an async value (e.g. address is a Signer @@ -36,9 +42,14 @@ import type { Listener } from "../utils/index.js"; import type { Networkish } from "./network.js"; //import type { MaxPriorityFeePlugin } from "./plugins-network.js"; import type { - BlockParams, BlockTag, EventFilter, Filter, FilterByBlockHash, LogParams, OrphanFilter, + BlockParams, LogParams, TransactionReceiptParams, + TransactionResponseParams +} from "./formatting.js"; + +import type { + BlockTag, EventFilter, Filter, FilterByBlockHash, OrphanFilter, PreparedTransactionRequest, Provider, ProviderEvent, - TransactionReceiptParams, TransactionRequest, TransactionResponseParams + TransactionRequest } from "./provider.js"; diff --git a/src.ts/providers/abstract-signer.ts b/src.ts/providers/abstract-signer.ts index 553c5f1dd..7ea95b132 100644 --- a/src.ts/providers/abstract-signer.ts +++ b/src.ts/providers/abstract-signer.ts @@ -1,3 +1,8 @@ +/** + * About Abstract Signer and subclassing + * + * @_section: api/providers/abstract-signer: Subclassing Signer [abstract-signer] + */ import { Transaction } from "../transaction/index.js"; import { defineProperties, getBigInt, resolveProperties, diff --git a/src.ts/providers/community.ts b/src.ts/providers/community.ts index 4a1da4df0..2a5d33033 100644 --- a/src.ts/providers/community.ts +++ b/src.ts/providers/community.ts @@ -1,4 +1,10 @@ - +/** + * There are many awesome community services that provide Ethereum + * nodes both for developers just starting out and for large-scale + * communities. + * + * @_section: api/providers/thirdparty: Community Providers [thirdparty] + */ export interface CommunityResourcable { isCommunityResource(): boolean; } diff --git a/src.ts/providers/format.ts b/src.ts/providers/format.ts index 5fedc92b0..31e0e1495 100644 --- a/src.ts/providers/format.ts +++ b/src.ts/providers/format.ts @@ -12,6 +12,9 @@ import { import type { BlockParams, LogParams, TransactionReceiptParams, TransactionResponseParams, +} from "./formatting.js"; + +import type { TransactionResponse } from "./provider.js"; diff --git a/src.ts/providers/formatting.ts b/src.ts/providers/formatting.ts new file mode 100644 index 000000000..931b548a1 --- /dev/null +++ b/src.ts/providers/formatting.ts @@ -0,0 +1,195 @@ +/** + * About provider formatting? + * + * @_section: api/providers/formatting:Formatting [provider-formatting] + */ + +import type { Signature } from "../crypto/index.js"; +import type { AccessList, AccessListish } from "../transaction/index.js"; +import type { BigNumberish } from "../utils/index.js"; +import type { AddressLike } from "../address/index.js"; + +import type { BlockTag } from "./provider.js"; + + +export interface TransactionRequest { + type?: null | number; + + to?: null | AddressLike; + from?: null | AddressLike; + + nonce?: null | number; + + gasLimit?: null | BigNumberish; + gasPrice?: null | BigNumberish; + + maxPriorityFeePerGas?: null | BigNumberish; + maxFeePerGas?: null | BigNumberish; + + data?: null | string; + value?: null | BigNumberish; + chainId?: null | BigNumberish; + + accessList?: null | AccessListish; + + customData?: any; + + // Only meaningful when used for call + blockTag?: BlockTag; + enableCcipRead?: boolean; + + // Todo? + //gasMultiplier?: number; +}; + +export interface PreparedTransactionRequest { + type?: number; + + to?: AddressLike; + from?: AddressLike; + + nonce?: number; + + gasLimit?: bigint; + gasPrice?: bigint; + + maxPriorityFeePerGas?: bigint; + maxFeePerGas?: bigint; + + data?: string; + value?: bigint; + chainId?: bigint; + + accessList?: AccessList; + + customData?: any; + + blockTag?: BlockTag; + enableCcipRead?: boolean; +} + + +////////////////////// +// Block + +export interface BlockParams { + hash?: null | string; + + number: number; + timestamp: number; + + parentHash: string; + + nonce: string; + difficulty: bigint; + + gasLimit: bigint; + gasUsed: bigint; + + miner: string; + extraData: string; + + baseFeePerGas: null | bigint; + + transactions: ReadonlyArray; +}; + + +////////////////////// +// Log + +export interface LogParams { + transactionHash: string; + blockHash: string; + blockNumber: number; + + removed: boolean; + + address: string; + data: string; + + topics: ReadonlyArray; + + index: number; + transactionIndex: number; +} + + +////////////////////// +// Transaction Receipt + +export interface TransactionReceiptParams { + to: null | string; + from: string; + contractAddress: null | string; + + hash: string; + index: number; + + blockHash: string; + blockNumber: number; + + logsBloom: string; + logs: ReadonlyArray; + + gasUsed: bigint; + cumulativeGasUsed: bigint; + gasPrice?: null | bigint; + effectiveGasPrice?: null | bigint; + + type: number; + //byzantium: boolean; + status: null | number; + root: null | string; +} + +/* +export interface LegacyTransactionReceipt { + byzantium: false; + status: null; + root: string; +} + +export interface ByzantiumTransactionReceipt { + byzantium: true; + status: number; + root: null; +} +*/ + + + +////////////////////// +// Transaction Response + +export interface TransactionResponseParams { + blockNumber: null | number; + blockHash: null | string; + + hash: string; + index: number; + + type: number; + + to: null | string; + from: string; + + nonce: number; + + gasLimit: bigint; + + gasPrice: bigint; + + maxPriorityFeePerGas: null | bigint; + maxFeePerGas: null | bigint; + + data: string; + value: bigint; + chainId: bigint; + + signature: Signature; + + accessList: null | AccessList; +}; + + diff --git a/src.ts/providers/index.ts b/src.ts/providers/index.ts index 74712936e..5cc308691 100644 --- a/src.ts/providers/index.ts +++ b/src.ts/providers/index.ts @@ -52,14 +52,12 @@ export { JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner } from "./provider-j export { BrowserProvider } from "./provider-browser.js"; -export { - AlchemyProvider, - AnkrProvider, - CloudflareProvider, - BaseEtherscanProvider, EtherscanPlugin, EtherscanProvider, - InfuraProvider -// PocketProvider -} from "./thirdparty.js"; +export { AlchemyProvider } from "./provider-alchemy.js"; +export { AnkrProvider } from "./provider-ankr.js"; +export { CloudflareProvider } from "./provider-cloudflare.js"; +export { BaseEtherscanProvider, EtherscanPlugin } from "./provider-etherscan-base.js"; +export { EtherscanProvider } from "./provider-etherscan.js"; +export { InfuraProvider, InfuraWebSocketProvider } from "./provider-infura.js"; import { IpcSocketProvider } from "./provider-ipcsocket.js"; /*-browser*/ export { IpcSocketProvider }; @@ -90,9 +88,13 @@ export type { Networkish } from "./network.js"; export type { GasCostParameters } from "./plugins-network.js"; +export type { + BlockParams, LogParams, TransactionReceiptParams, + TransactionResponseParams, +} from "./formatting.js"; + export type { BlockTag, - BlockParams, LogParams, TransactionReceiptParams, TransactionResponseParams, TransactionRequest, PreparedTransactionRequest, EventFilter, Filter, FilterByBlockHash, OrphanFilter, ProviderEvent, TopicFilter, diff --git a/src.ts/providers/network.ts b/src.ts/providers/network.ts index 93d670403..5f39f7204 100644 --- a/src.ts/providers/network.ts +++ b/src.ts/providers/network.ts @@ -1,7 +1,7 @@ /** * About networks * - * @_subsection: api/providers:Networks + * @_subsection: api/providers:Networks [networks] */ import { accessListify } from "../transaction/index.js"; diff --git a/src.ts/providers/plugins-network.ts b/src.ts/providers/plugins-network.ts index 5bcb52bbc..aecccf0bf 100644 --- a/src.ts/providers/plugins-network.ts +++ b/src.ts/providers/plugins-network.ts @@ -2,7 +2,12 @@ import { defineProperties } from "../utils/properties.js"; import { assertArgument } from "../utils/index.js"; -import type { FeeData, Provider } from "./provider.js"; +import type { BlockParams, TransactionResponseParams } from "./formatting.js"; + +import type { + Block, FeeData, Provider, TransactionResponse +} from "./provider.js"; + const EnsAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; @@ -138,8 +143,6 @@ export class FeeDataNetworkPlugin extends NetworkPlugin { } } -import type { Block, BlockParams, TransactionResponse, TransactionResponseParams } from "./provider.js"; - export class CustomBlockNetworkPlugin extends NetworkPlugin { readonly #blockFunc: (provider: Provider, block: BlockParams) => Block; readonly #blockWithTxsFunc: (provider: Provider, block: BlockParams) => Block; diff --git a/src.ts/providers/provider-alchemy.ts b/src.ts/providers/provider-alchemy.ts index fc5f5ad4a..5f27947de 100644 --- a/src.ts/providers/provider-alchemy.ts +++ b/src.ts/providers/provider-alchemy.ts @@ -41,6 +41,8 @@ function getHost(name: string): string { /** * The AlchemyProvider is backed by the [[alchemyapu]] API. + * + * @_docloc: api/providers/thirdparty */ export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable { readonly apiKey!: string; diff --git a/src.ts/providers/provider-ankr.ts b/src.ts/providers/provider-ankr.ts index 252bf623b..dabff2af2 100644 --- a/src.ts/providers/provider-ankr.ts +++ b/src.ts/providers/provider-ankr.ts @@ -29,6 +29,11 @@ function getHost(name: string): string { } +/** + * About Ankr... + * + * @_docloc: api/providers/thirdparty + */ export class AnkrProvider extends JsonRpcProvider implements CommunityResourcable { readonly apiKey!: string; diff --git a/src.ts/providers/provider-cloudflare.ts b/src.ts/providers/provider-cloudflare.ts index 0d760a7f8..c8de01dfb 100644 --- a/src.ts/providers/provider-cloudflare.ts +++ b/src.ts/providers/provider-cloudflare.ts @@ -5,7 +5,11 @@ import { JsonRpcProvider } from "./provider-jsonrpc.js"; import type { Networkish } from "./network.js"; - +/** + * Aboud Cloudflare... + * + * @_docloc: api/providers/thirdparty + */ export class CloudflareProvider extends JsonRpcProvider { constructor(_network?: Networkish) { if (_network == null) { _network = "mainnet"; } diff --git a/src.ts/providers/provider-etherscan-base.ts b/src.ts/providers/provider-etherscan-base.ts index 42f09500f..57963e1cf 100644 --- a/src.ts/providers/provider-etherscan-base.ts +++ b/src.ts/providers/provider-etherscan-base.ts @@ -20,6 +20,11 @@ import type { TransactionRequest } from "./provider.js"; const THROTTLE = 2000; +/** + * Aboud Etherscan Debug... + * + * @_docloc: api/providers/thirdparty:Etherscan + */ export type DebugEventEtherscanProvider = { action: "sendRequest", id: number, @@ -37,6 +42,11 @@ export type DebugEventEtherscanProvider = { const EtherscanPluginId = "org.ethers.plugins.Etherscan"; +/** + * Aboud Cloudflare... + * + * @_docloc: api/providers/thirdparty:Etherscan + */ export class EtherscanPlugin extends NetworkPlugin { readonly baseUrl!: string; readonly communityApiKey!: string; @@ -54,6 +64,11 @@ export class EtherscanPlugin extends NetworkPlugin { let nextId = 1; +/** + * Aboud Etherscan... + * + * @_docloc: api/providers/thirdparty:Etherscan + */ export class BaseEtherscanProvider extends AbstractProvider { readonly network!: Network; readonly apiKey!: string; diff --git a/src.ts/providers/provider-etherscan.ts b/src.ts/providers/provider-etherscan.ts index 7946be040..0e03aaf32 100644 --- a/src.ts/providers/provider-etherscan.ts +++ b/src.ts/providers/provider-etherscan.ts @@ -1,3 +1,9 @@ +/** + * Aboud Etherscan... + * + * @_subsection api/providers/thirdparty:Etherscan [etherscan] + */ + import { BaseEtherscanProvider } from "./provider-etherscan-base.js"; import { Contract } from "../contract/index.js"; @@ -5,6 +11,9 @@ function isPromise(value: any): value is Promise { return (value && typeof(value.then) === "function"); } +/** + * Aboud EtherscanProvider... + */ export class EtherscanProvider extends BaseEtherscanProvider { async getContract(_address: string): Promise { let address = this._getAddress(_address); diff --git a/src.ts/providers/provider-infura.ts b/src.ts/providers/provider-infura.ts index f6772f68b..beba2da2e 100644 --- a/src.ts/providers/provider-infura.ts +++ b/src.ts/providers/provider-infura.ts @@ -1,3 +1,8 @@ +/** + * About INFURA + * + * @_subsection: api/providers/thirdparty:INFURA [infura] + */ import { defineProperties, FetchRequest, assert, assertArgument } from "../utils/index.js"; @@ -40,6 +45,9 @@ function getHost(name: string): string { assertArgument(false, "unsupported network", "network", name); } +/** + * INFURA... + */ export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable { readonly projectId!: string; readonly projectSecret!: null | string; @@ -65,6 +73,9 @@ export class InfuraWebSocketProvider extends WebSocketProvider implements Commun } } +/** + * Aboud Cloudflare... + */ export class InfuraProvider extends JsonRpcProvider implements CommunityResourcable { readonly projectId!: string; readonly projectSecret!: null | string; diff --git a/src.ts/providers/provider-jsonrpc.ts b/src.ts/providers/provider-jsonrpc.ts index 320c7b5fd..bb162476d 100644 --- a/src.ts/providers/provider-jsonrpc.ts +++ b/src.ts/providers/provider-jsonrpc.ts @@ -1,3 +1,9 @@ +/** + * About JSON-RPC... + * + * @_section: api/providers/jsonrpc:JSON-RPC Provider [about-jsonrpcProvider] + */ + // @TODO: // - Add the batching API @@ -98,6 +104,10 @@ export type JsonRpcError = { } }; +/** + * When subscribing to the ``"debug"`` event, the [[Listener]] will + * receive this object as the first parameter. + */ export type DebugEventJsonRpcApiProvider = { action: "sendRpcPayload", payload: JsonRpcPayload | Array @@ -114,16 +124,13 @@ export type DebugEventJsonRpcApiProvider = { * is targetted towards sub-classes, which often will not expose * any of these options to their consumers. * - * _property: options.polling? => boolean - * If true, the polling strategy is used immediately for events. - * Otherwise, an attempt to use filters is made and on failure - * polling is used for that and all future events. (default: ``false``) + * **``polling``** - use the polling strategy is used immediately + * for events; otherwise, attempt to use filters and fall back onto + * polling (default: ``false``) * - * _property: options.staticNetwork => [[Network]] - * If this is set, then there are no requests made for the chainId. - * (default: ``null``) + * **``staticNetwork``** - do not request chain ID on requests to + * validate the underlying chain has not changed (default: ``null``) * - * _warning: * This should **ONLY** be used if it is **certain** that the network * cannot change, such as when using INFURA (since the URL dictates the * network). If the network is assumed static and it does change, this @@ -131,21 +138,15 @@ export type DebugEventJsonRpcApiProvider = { * with MetaMask, since the used can select a new network from the * drop-down at any time. * - * _property: option.batchStallTime? => number - * The amount of time (in ms) to wait, allowing requests to be batched, - * before making the request. If ``0``, then batching will only occur - * within the same event loop. If the batchSize is ``1``, then this is - * ignored. (default: ``10``) + * **``batchStallTime``** - how long (ms) to aggregate requests into a + * single batch. ``0`` indicates batching will only encompass the current + * event loop. If ``batchMaxCount = 1``, this is ignored. (default: ``10``) * - * _property: options.batchMaxSize? => number - * The target maximum size (in bytes) to allow a payload within a single - * batch. At least one request will be made per request, which may - * violate this constraint if it is set too small or a large request is - * present. (default: 1Mb) + * **``batchMaxSize``** - target maximum size (bytes) to allow per batch + * request (default: 1Mb) * - * _property: options.bstchMaxCount? => number - * The maximum number of payloads to allow in a single batch. Set this to - * ``1`` to disable batching entirely. (default: ``100``) + * **``batchMaxCount``** - maximum number of requests to allow in a batch. + * If ``batchMaxCount = 1``, then batching is disabled. (default: ``100``) */ export type JsonRpcApiProviderOptions = { polling?: boolean; @@ -348,7 +349,7 @@ type Payload = { payload: JsonRpcPayload, resolve: ResolveFunc, reject: RejectFu * - a sub-class MUST override _send * - a sub-class MUST call the `_start()` method once connected */ -export class JsonRpcApiProvider extends AbstractProvider { +export abstract class JsonRpcApiProvider extends AbstractProvider { #options: Required; @@ -487,11 +488,14 @@ export class JsonRpcApiProvider extends AbstractProvider { * * Sub-classes **MUST** override this. */ - _send(payload: JsonRpcPayload | Array): Promise> { + abstract _send(payload: JsonRpcPayload | Array): Promise>; + /* + { assert(false, "sub-classes must override _send", "UNSUPPORTED_OPERATION", { operation: "jsonRpcApiProvider._send" }); } + */ /** @@ -991,7 +995,7 @@ export class JsonRpcApiProvider extends AbstractProvider { } } -export class JsonRpcApiPollingProvider extends JsonRpcApiProvider { +export abstract class JsonRpcApiPollingProvider extends JsonRpcApiProvider { #pollingInterval: number; constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) { super(network, options); diff --git a/src.ts/providers/provider-socket.ts b/src.ts/providers/provider-socket.ts index 81c3beb4e..61f108370 100644 --- a/src.ts/providers/provider-socket.ts +++ b/src.ts/providers/provider-socket.ts @@ -1,12 +1,12 @@ /** - * SocketProvider - * * Generic long-lived socket provider. * * Sub-classing notes * - a sub-class MUST call the `_start()` method once connected * - a sub-class MUST override the `_write(string)` method * - a sub-class MUST call `_processMessage(string)` for each message + * + * @_subsection: api/providers/abstract-provider */ import { UnmanagedSubscriber } from "./abstract-provider.js"; @@ -130,6 +130,10 @@ export class SocketEventSubscriber extends SocketSubscriber { } } +/** + * SocketProvider... + * + */ export class SocketProvider extends JsonRpcApiProvider { #callbacks: Map void, reject: (e: Error) => void }>; diff --git a/src.ts/providers/provider.ts b/src.ts/providers/provider.ts index 134df80dd..0fdb49590 100644 --- a/src.ts/providers/provider.ts +++ b/src.ts/providers/provider.ts @@ -18,6 +18,11 @@ const BN_0 = BigInt(0); export type BlockTag = number | string; +import { + BlockParams, LogParams, TransactionReceiptParams, + TransactionResponseParams +} from "./formatting.js"; + // ----------------------- function getValue(value: undefined | null | T): null | T { @@ -31,11 +36,46 @@ function toJson(value: null | bigint): null | string { } // @TODO? implements Required + +/** + * A **FeeData** wraps all the fee-related values associated with + * the network. + */ export class FeeData { + /** + * The gas price for legacy networks. + */ readonly gasPrice!: null | bigint; + + /** + * The maximum fee to pay per gas. + * + * The base fee per gas is defined by the network and based on + * congestion, increasing the cost during times of heavy load + * and lowering when less busy. + * + * The actual fee per gas will be the base fee for the block + * and the priority fee, up to the max fee per gas. + * + * This will be ``null`` on legacy networks (i.e. [pre-EIP-1559](link-eip-1559)) + */ readonly maxFeePerGas!: null | bigint; + + /** + * The additional amout to pay per gas to encourage a validator + * to include the transaction. + * + * The purpose of this is to compensate the validator for the + * adjusted risk for including a given transaction. + * + * This will be ``null`` on legacy networks (i.e. [pre-EIP-1559](link-eip-1559)) + */ readonly maxPriorityFeePerGas!: null | bigint; + /** + * Creates a new FeeData for %%gasPrice%%, %%maxFeePerGas%% and + * %%maxPriorityFeePerGas%%. + */ constructor(gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint) { defineProperties(this, { gasPrice: getValue(gasPrice), @@ -44,6 +84,9 @@ export class FeeData { }); } + /** + * Returns a JSON-friendly value. + */ toJSON(): any { const { gasPrice, maxFeePerGas, maxPriorityFeePerGas @@ -175,7 +218,7 @@ export async function resolveTransactionRequest(tx: TransactionRequest, provider ////////////////////// // Block - +/* export interface BlockParams { hash?: null | string; @@ -197,6 +240,7 @@ export interface BlockParams { transactions: ReadonlyArray; }; +*/ export interface MinedBlock extends Block { readonly number: number; @@ -206,28 +250,97 @@ export interface MinedBlock ext readonly miner: string; } +/** + * A **Block** represents the data associated with a full block on + * Ethereum. + */ export class Block implements BlockParams, Iterable { + /** + * The provider connected to the block used to fetch additional details + * if necessary. + */ readonly provider!: Provider; + /** + * The block number, sometimes called the block height. This is a + * sequential number that is one higher than the parent block. + */ readonly number!: number; + + /** + * The block hash. + */ readonly hash!: null | string; + + /** + * The timestamp for this block, which is the number of seconds since + * epoch that this block was included. + */ readonly timestamp!: number; + /** + * The block hash of the parent block. + */ readonly parentHash!: string; + /** + * The nonce. + * + * On legacy networks, this is the random number inserted which + * permitted the difficulty target to be reached. + */ readonly nonce!: string; + + /** + * The difficulty target. + * + * On legacy networks, this is the proof-of-work target required + * for a block to meet the protocol rules to be included. + * + * On modern networks, this is a random number arrived at using + * randao. @TODO: Find links? + */ readonly difficulty!: bigint; + + /** + * The total gas limit for this block. + */ readonly gasLimit!: bigint; + + /** + * The total gas used in this block. + */ readonly gasUsed!: bigint; + /** + * The miner coinbase address, wihch receives any subsidies for + * including this block. + */ readonly miner!: string; + + /** + * Any extra data the validator wished to include. + */ readonly extraData!: string; + /** + * The base fee per gas that all transactions in this block were + * charged. + * + * This adjusts after each block, depending on how congested the network + * is. + */ readonly baseFeePerGas!: null | bigint; readonly #transactions: ReadonlyArray; + /** + * Create a new **Block** object. + * + * This should generally not be necessary as the unless implementing a + * low-level library. + */ constructor(block: BlockParams, provider: Provider) { this.#transactions = Object.freeze(block.transactions.map((tx) => { @@ -259,12 +372,14 @@ export class Block implements BlockParam }); } + /** + * Returns the list of transactions. + */ get transactions(): ReadonlyArray { return this.#transactions; } - //connect(provider: Provider): Block { - // return new Block(this, provider); - //} - + /** + * Returns a JSON-friendly value. + */ toJSON(): any { const { baseFeePerGas, difficulty, extraData, gasLimit, gasUsed, hash, @@ -297,13 +412,23 @@ export class Block implements BlockParam }; } + /** + * The number of transactions in this block. + */ get length(): number { return this.transactions.length; } + /** + * The [date](link-js-data) this block was included at. + */ get date(): null | Date { if (this.timestamp == null) { return null; } return new Date(this.timestamp * 1000); } - +// @TODO: Don't have 2 block types? +// just populate this with all the values? simplifies provider + /** + * Get the transaction at %%indexe%% within this block. + */ async getTransaction(index: number): Promise { const tx = this.transactions[index]; if (tx == null) { throw new Error("no such tx"); } @@ -314,7 +439,17 @@ export class Block implements BlockParam } } + /** + * Has this block been mined. + * + * If true, the block has been typed-gaurded that all mined + * properties are non-null. + */ isMined(): this is MinedBlock { return !!this.hash; } + + /** + * + */ isLondon(): this is (Block & { baseFeePerGas: bigint }) { return !!this.baseFeePerGas; } @@ -328,6 +463,7 @@ export class Block implements BlockParam ////////////////////// // Log +/* export interface LogParams { transactionHash: string; blockHash: string; @@ -343,7 +479,7 @@ export interface LogParams { index: number; transactionIndex: number; } - +*/ export class Log implements LogParams { readonly provider: Provider; @@ -420,7 +556,7 @@ export class Log implements LogParams { ////////////////////// // Transaction Receipt - +/* export interface TransactionReceiptParams { to: null | string; from: string; @@ -445,7 +581,7 @@ export interface TransactionReceiptParams { status: null | number; root: null | string; } - +*/ /* export interface LegacyTransactionReceipt { byzantium: false; @@ -595,7 +731,7 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable> | EventFilter ////////////////////// // Provider +/** + * A **Provider** is the primary method to interact with the read-only + * content on Ethereum. + * + * It allows access to details about accounts, blocks and transactions + * and the ability to query event logs and simulate contract execution. + * + * Account data includes the [balance](getBalance), + * [transaction count](getTransactionCount), [code](getCode) and + * [state trie storage](getStorage). + * + * Simulating execution can be used to [call](call), + * [estimate gas](estimateGas) and + * [get transaction results](getTransactionResult). + * + * The [[broadcastTransaction]] is the only method which allows updating + * the blockchain, but it is usually accessed by a [[Signer]], since a + * private key must be used to sign the transaction before it can be + * broadcast. + */ export interface Provider extends ContractRunner, EventEmitterable, NameResolver { + + /** + * The provider iteself. + * + * This is part of the necessary API for executing a contract, as + * it provides a common property on any [[ContractRunner]] that + * can be used to access the read-only portion of the runner. + */ provider: this; @@ -1055,11 +1219,9 @@ export interface Provider extends ContractRunner, EventEmitterable; /** - * Get the number of transactions ever sent for %%address%%, which is used as - * the ``nonce`` when sending a transaction. If %%blockTag%% is specified and - * the node supports archive access, the transaction count is as of that [[BlockTag]]. - * - * @param {Address | Addressable} address - The account to lookup the transaction count of - * @param blockTag - The block tag to use for historic archive access. [default: ``"latest"``] + * Get the number of transactions ever sent for %%address%%, which + * is used as the ``nonce`` when sending a transaction. If + * %%blockTag%% is specified and the node supports archive access + * for that %%blockTag%%, the transaction count is as of that + * [[BlockTag]]. * * @note On nodes without archive access enabled, the %%blockTag%% may be * **silently ignored** by the node, which may cause issues if relied on. @@ -1080,10 +1241,7 @@ export interface Provider extends ContractRunner, EventEmitterable; /** - * Get the bytecode for //address//. - * - * @param {Address | Addressable} address - The account to lookup the bytecode of - * @param blockTag - The block tag to use for historic archive access. [default: ``"latest"``] + * Get the bytecode for %%address%%. * * @note On nodes without archive access enabled, the %%blockTag%% may be * **silently ignored** by the node, which may cause issues if relied on. @@ -1091,11 +1249,7 @@ export interface Provider extends ContractRunner, EventEmitterable /** - * Get the storage slot value for a given //address// and slot //position//. - * - * @param {Address | Addressable} address - The account to lookup the storage of - * @param position - The storage slot to fetch the value of - * @param blockTag - The block tag to use for historic archive access. [default: ``"latest"``] + * Get the storage slot value for %%address%% at slot %%position%%. * * @note On nodes without archive access enabled, the %%blockTag%% may be * **silently ignored** by the node, which may cause issues if relied on. @@ -1108,24 +1262,19 @@ export interface Provider extends ContractRunner, EventEmitterable; - // If call fails, throws CALL_EXCEPTION { data: string, error, errorString?, panicReason? } /** - * Uses call to simulate execution of %%tx%%. - * - * @param tx - The transaction to simulate + * Simulate the execution of %%tx%%. If the call reverts, it will + * throw a [[CallExceptionError]] which includes the revert data. */ call(tx: TransactionRequest): Promise /** - * Broadcasts the %%signedTx%% to the network, adding it to the memory pool - * of any node for which the transaction meets the rebroadcast requirements. - * - * @param signedTx - The transaction to broadcast + * Broadcasts the %%signedTx%% to the network, adding it to the + * memory pool of any node for which the transaction meets the + * rebroadcast requirements. */ broadcastTransaction(signedTx: string): Promise; @@ -1133,25 +1282,83 @@ export interface Provider extends ContractRunner, EventEmitterable>; + + /** + * Resolves to the block for %%blockHashOrBlockTag%%, including each + * full transaction. + * + * If a block is unknonw, this resolved to ``null``. + */ getBlockWithTransactions(blockHashOrBlockTag: BlockTag | string): Promise> + + /** + * Resolves to the transaction for %%hash%%. + * + * If the transaction is unknown or on pruning nodes which + * discard old transactions this resolves to ``null``. + */ getTransaction(hash: string): Promise; + + /** + * Resolves to the transaction receipt for %%hash%%, if mined. + * + * If the transaction has not been mined, is unknown or on + * pruning nodes which discard old transactions this resolves to + * ``null``. + */ getTransactionReceipt(hash: string): Promise; + + /** + * Resolves to the result returned by the executions of %%hash%%. + * + * This is only supported on nodes with archive access and with + * the necessary debug APIs enabled. + */ getTransactionResult(hash: string): Promise; //////////////////// // Bloom-filter Queries + /** + * Resolves to the list of Logs that match %%filter%% + */ getLogs(filter: Filter | FilterByBlockHash): Promise>; //////////////////// // ENS - resolveName(name: string): Promise; + /** + * Resolves to the address configured for the %%ensName%% or + * ``null`` if unconfigured. + */ + resolveName(ensName: string): Promise; + + /** + * Resolves to the ENS name associated for the %%address%% or + * ``null`` if the //primary name// is not configured. + * + * Users must perform additional steps to configure a //primary name//, + * which is not currently common. + */ lookupAddress(address: string): Promise; + /** + * Waits until the transaction %%hash%% is mined and has %%confirms%% + * confirmations. + */ waitForTransaction(hash: string, confirms?: number, timeout?: number): Promise; + + /** + * Resolves to the block at %%blockTag%% once it has been mined. + * + * This can be useful for waiting some number of blocks by using + * the ``currentBlockNumber + N``. + */ waitForBlock(blockTag?: BlockTag): Promise>; } diff --git a/src.ts/providers/subscriber-connection.ts b/src.ts/providers/subscriber-connection.ts index 9fdce83e7..239134f90 100644 --- a/src.ts/providers/subscriber-connection.ts +++ b/src.ts/providers/subscriber-connection.ts @@ -6,12 +6,23 @@ import type { Subscriber } from "./abstract-provider.js"; //#TODO: Temp import type { Provider } from "./provider.js"; + +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export interface ConnectionRpcProvider extends Provider { //send(method: string, params: Array): Promise; _subscribe(param: Array, processFunc: (result: any) => void): number; _unsubscribe(filterId: number): void; } +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export class BlockConnectionSubscriber implements Subscriber { #provider: ConnectionRpcProvider; #blockNumber: number; diff --git a/src.ts/providers/subscriber-filterid.ts b/src.ts/providers/subscriber-filterid.ts index 3f9202f76..5cd74751d 100644 --- a/src.ts/providers/subscriber-filterid.ts +++ b/src.ts/providers/subscriber-filterid.ts @@ -10,6 +10,16 @@ function copy(obj: any): any { return JSON.parse(JSON.stringify(obj)); } +/** + * Some backends support subscribing to events using a Filter ID. + * + * When subscribing with this technique, the node issues a unique + * //Filter ID//. At this point the node dedicates resources to + * the filter, so that periodic calls to follow up on the //Filter ID// + * will receive any events since the last call. + * + * @_docloc: api/providers/abstract-provider + */ export class FilterIdSubscriber implements Subscriber { #provider: JsonRpcApiProvider; @@ -90,6 +100,11 @@ export class FilterIdSubscriber implements Subscriber { resume(): void { this.start(); } } +/** + * A **FilterIdSubscriber** for receiving contract events. + * + * @_docloc: api/providers/abstract-provider + */ export class FilterIdEventSubscriber extends FilterIdSubscriber { #event: EventFilter; @@ -114,6 +129,11 @@ export class FilterIdEventSubscriber extends FilterIdSubscriber { } } +/** + * A **FilterIdSubscriber** for receiving pending transactions events. + * + * @_docloc: api/providers/abstract-provider + */ export class FilterIdPendingSubscriber extends FilterIdSubscriber { async _subscribe(provider: JsonRpcApiProvider): Promise { return await provider.send("eth_newPendingTransactionFilter", [ ]); diff --git a/src.ts/providers/subscriber-hotswap.ts b/src.ts/providers/subscriber-hotswap.ts deleted file mode 100644 index 7a897352d..000000000 --- a/src.ts/providers/subscriber-hotswap.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* -import { Subscriber } from "./abstract-provider.js"; - -export class HotSwapSubscriber implements Subscriber { - #target?: Subscriber; - - _switchSubscriber(subscriber: Subscriber): void { - this.#target = subscriber; - } - - start(): void { - if (this.#target) { return this.#target.start(); } - return super.start(); - } - - stop(): void { - if (this.#target) { return this.#target.stop(); } - return super.stop(); - } - - pause(dropWhilePaused?: boolean): void { - if (this.#target) { return this.#target.pause(dropWhilePaused); } - return super.pause(dropWhilePaused); - } - - resume(): void { - if (this.#target) { return this.#target.resume(); } - return super.resume(); - } - - set pollingInterval(value: number) { - if (this.#target) { return this.#target.pollingInterval = value; } - return super.pollingInterval = value; - } - - get pollingInterval(): number { - if (this.#target) { return this.#target.pollingInterval; } - return super.pollingInterval; - } -} -*/ diff --git a/src.ts/providers/subscriber-polling.ts b/src.ts/providers/subscriber-polling.ts index 5db3821af..4f6fa362b 100644 --- a/src.ts/providers/subscriber-polling.ts +++ b/src.ts/providers/subscriber-polling.ts @@ -7,6 +7,11 @@ function copy(obj: any): any { return JSON.parse(JSON.stringify(obj)); } +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export function getPollingSubscriber(provider: AbstractProvider, event: ProviderEvent): Subscriber { if (event === "block") { return new PollingBlockSubscriber(provider); } if (isHexString(event, 32)) { return new PollingTransactionSubscriber(provider, event); } @@ -18,6 +23,11 @@ export function getPollingSubscriber(provider: AbstractProvider, event: Provider // @TODO: refactor this +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export class PollingBlockSubscriber implements Subscriber{ #provider: AbstractProvider; #poller: null | number; @@ -81,6 +91,11 @@ export class PollingBlockSubscriber implements Subscriber{ } } +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export class OnBlockSubscriber implements Subscriber { #provider: AbstractProvider; #poll: (b: number) => void; @@ -109,6 +124,11 @@ export class OnBlockSubscriber implements Subscriber { resume(): void { this.start(); } } +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export class PollingOrphanSubscriber extends OnBlockSubscriber { #filter: OrphanFilter; @@ -123,6 +143,11 @@ export class PollingOrphanSubscriber extends OnBlockSubscriber { } } +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export class PollingTransactionSubscriber extends OnBlockSubscriber { #hash: string; @@ -137,6 +162,11 @@ export class PollingTransactionSubscriber extends OnBlockSubscriber { } } +/** + * @TODO + * + * @_docloc: api/providers/abstract-provider + */ export class PollingEventSubscriber implements Subscriber { #provider: AbstractProvider; #filter: EventFilter; diff --git a/src.ts/providers/thirdparty.ts b/src.ts/providers/thirdparty.ts deleted file mode 100644 index ad500715f..000000000 --- a/src.ts/providers/thirdparty.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * About thirdparty... - * - * @_section: api/providers/third-party:Third Party Providers [third-party] - */ - -/** - * - */ -export { AlchemyProvider } from "./provider-alchemy.js"; -export { AnkrProvider } from "./provider-ankr.js"; -export { CloudflareProvider } from "./provider-cloudflare.js"; -export { BaseEtherscanProvider, EtherscanPlugin } from "./provider-etherscan-base.js"; -export { EtherscanProvider } from "./provider-etherscan.js"; -export { InfuraProvider } from "./provider-infura.js";