docs: added jsdocs and general documentation
This commit is contained in:
parent
c785c1e515
commit
bbcfb5f6b8
@ -1,26 +1,97 @@
|
||||
_section: ABI
|
||||
_section: Application Binary Interfaces @<docs-abi>
|
||||
|
||||
Explain about ABI here, what it does and does not do
|
||||
When interacting with any application, whether it is on Ethereum,
|
||||
over the internet or within a compiled application on a computer
|
||||
all information is stored and sent as binary data which is just a
|
||||
sequence of bytes.
|
||||
|
||||
- encodes arbitrary (but defined) data structures to raw bytes
|
||||
So every application must agree on how to encode and decode their
|
||||
information as a sequence of bytes.
|
||||
|
||||
_subsection: Call
|
||||
An **Application Binary Interface** (ABI) provides a way to describe
|
||||
the encoding and decoding process, in a generic way so that a variety
|
||||
of types and structures of types can be defined.
|
||||
|
||||
About encoding
|
||||
For example, a string is often encoded as a UTF-8 sequence of bytes,
|
||||
which uses specific bits within sub-sequences to indicate emoji and
|
||||
other special characters. Every implementation of UTF-8 must understand
|
||||
and operate under the same rules so that strings work universally. In
|
||||
this way, UTF-8 standard is itself an ABI.
|
||||
|
||||
_heading: selector or signature hash (sighash)
|
||||
When interacting with Ethereum, a contract received a sequence of bytes
|
||||
as input (provided by sending a transaction or through a call) and
|
||||
returns a result as a sequence of bytes. So, each Contract has its own
|
||||
ABI that helps specify how to encode the input and how to decode the output.
|
||||
|
||||
_heading: Results
|
||||
It is up to the contract developer to make this ABI available. Many
|
||||
Contracts implement a standard (such as ERC-20), in which case the
|
||||
ABI for that standard can be used. Many developers choose to verify their
|
||||
source code on Etherscan, in which case Etherscan computes the ABI and
|
||||
provides it through their website (which can be fetched using the ``getContract``
|
||||
method). Otherwise, beyond reverse engineering the Contract there is
|
||||
not a meaningful way to extract the contract ABI.
|
||||
|
||||
_subsection: Events
|
||||
_subsection: Call Data Representation
|
||||
|
||||
When calling a Contract on Ethereum, the input data must be encoded
|
||||
according to the ABI.
|
||||
|
||||
The first 4 bytes of the data are the **method selector**, which is
|
||||
the keccak256 hash of the normalized method signature.
|
||||
|
||||
Then the method parameters are encoded and concatenated to the selector.
|
||||
|
||||
All encoded data is made up of components padded to 32 bytes, so the length
|
||||
of input data will always be congruent to ``4 mod 32``.
|
||||
|
||||
The result of a successful call will be encoded values, whose components
|
||||
are padded to 32 bytes each as well, so the length of a result will always
|
||||
be congruent to ``0 mod 32``, on success.
|
||||
|
||||
The result of a reverted call will contain the **error selector** as the
|
||||
first 4 bytes, which is the keccak256 of the normalized error signature,
|
||||
followed by the encoded values, whose components are padded to 32 bytes
|
||||
each, so the length of a revert will be congruent to ``4 mod 32``.
|
||||
|
||||
The one exception to all this is that ``revert(false)`` will return a
|
||||
result or ``0x``.
|
||||
|
||||
|
||||
_subsection: Event Data Representation
|
||||
|
||||
When an Event is emitted from a contract, there are two places data is
|
||||
logged in a Log: the **topics** and the **data**.
|
||||
|
||||
An additonal fee is paid for each **topic**, but this affords a topic
|
||||
to be indexed in a bloom filter within the block, which allows efficient
|
||||
filtering.
|
||||
|
||||
The **topic hash** is always the first topic in a Log, which is the
|
||||
keccak256 of the normalized event signature. This allows a specific
|
||||
event to be efficiently filtered, finding the matching events in a block.
|
||||
|
||||
Each additional **indexed** parameter (i.e. parameters marked with
|
||||
``indexed`` in the signautre) are placed in the topics as well, but may be
|
||||
filtered to find matching values.
|
||||
|
||||
All non-indexed parameters are encoded and placed in the **data**. This
|
||||
is cheaper and more compact, but does not allow filtering on these values.
|
||||
|
||||
For example, the event ``Transfer(address indexed from, address indexed to, uint value)``
|
||||
would require 3 topics, which are the topic hash, the ``from`` address
|
||||
and the ``to`` address and the data would contain 32 bytes, which is
|
||||
the padded big-endian representation of ``value``. This allows for
|
||||
efficient filtering by the event (i.e. ``Transfer``) as well as the ``from``
|
||||
address and ``to`` address.
|
||||
|
||||
|
||||
_subsection: Deployment
|
||||
|
||||
About initcode
|
||||
When deploying a transaction, the data provided is treated as **initcode**,
|
||||
which executes the data as normal EVM bytecode, which returns a sequence
|
||||
of bytes, but instead of that sequence of bytes being treated as data that
|
||||
result is instead the bytecode to install as the bytecode of the contract.
|
||||
|
||||
Another paragraph [[link-bip-39]].
|
||||
|
||||
_heading: Foo?
|
||||
|
||||
Bar?
|
||||
The bytecode produced by Solidity is designed to have all constructor
|
||||
parameters encoded normally and concatenated to the bytecode and provided
|
||||
as the ``data`` to a transaction with no ``to`` address.
|
||||
|
@ -1,7 +1,8 @@
|
||||
_section: Ethereum Basics @priority<99>
|
||||
_section: Ethereum Basics @<docs-basics> @priority<99>
|
||||
|
||||
Prelude here...
|
||||
This section aims to cover some of the basics for those interested
|
||||
in a deeper understanding of the inner-workings of Ethereum.
|
||||
|
||||
_subsection: About stuff?
|
||||
_subsection: Topics
|
||||
|
||||
Some info
|
||||
- [Application Binary Interface](docs-abi)
|
||||
|
@ -1,6 +1,7 @@
|
||||
link-js-array [link-js-array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
|
||||
link-js-bigint [link-js-bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
|
||||
link-js-date [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
|
||||
link-js-fetch [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||
link-js-normalize [String.normalize](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize)
|
||||
link-js-maxsafe [link-js-maxsafe](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER#Description)
|
||||
link-js-proxy [link-js-proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
|
||||
|
@ -12,6 +12,7 @@ link-infura [INFURA](https://infura.io)
|
||||
link-javascriptcore [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore?language=objc)
|
||||
link-ledger [Ledger](https://www.ledger.com)
|
||||
link-metamask [MetaMask](https://metamask.io/)
|
||||
link-node [Node.js](https://nodejs.org/)
|
||||
link-otto [Otto](https://github.com/robertkrimen/otto)
|
||||
link-parity [Parity](https://www.parity.io)
|
||||
link-pocket [Pocket Network](https://pokt.network)
|
||||
|
@ -43,6 +43,7 @@ link-namehash [namehash](https://docs.ens.domains/contract-api-reference/name-pr
|
||||
link-rlp [Recursive-Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/)
|
||||
link-pbkdf2 [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2)
|
||||
link-solc-abi [ABI Specification](https://docs.soliditylang.org/en/v0.8.19/abi-spec.html#formal-specification-of-the-encoding)
|
||||
link-solc-jsonabi [ABI JSON Specification](https://docs.soliditylang.org/en/v0.8.19/abi-spec.html#json)
|
||||
link-solc-errors [Solidity Custom Errors](https://docs.soliditylang.org/en/v0.8.4/abi-spec.html#errors)
|
||||
link-solc-events [Solidity Events](https://docs.soliditylang.org/en/v0.8.4/abi-spec.html#events)
|
||||
link-solc-output [solc standard output](https://solidity.readthedocs.io/en/v0.6.0/using-the-compiler.html#output-description)
|
||||
|
@ -121,8 +121,9 @@ function getBuiltinCallException(action: CallExceptionAction, tx: { to?: null |
|
||||
}
|
||||
|
||||
/**
|
||||
* About AbiCoder
|
||||
*/
|
||||
* The **AbiCoder** is a low-level class responsible for encoding JavaScript
|
||||
* values into binary data and decoding binary data into JavaScript values.
|
||||
*/
|
||||
export class AbiCoder {
|
||||
|
||||
#getCoder(param: ParamType): Coder {
|
||||
|
@ -1,5 +1,11 @@
|
||||
/**
|
||||
* About frgaments...
|
||||
* A fragment is a single item from an ABI, which may represent any of:
|
||||
*
|
||||
* - [Functions](FunctionFragment)
|
||||
* - [Events](EventFragment)
|
||||
* - [Constructors](ConstructorFragment)
|
||||
* - Custom [Errors](ErrorFragment)
|
||||
* - [Fallback or Receive](FallbackFragment) functions
|
||||
*
|
||||
* @_subsection api/abi/abi-coder:Fragments [about-fragments]
|
||||
*/
|
||||
@ -11,7 +17,7 @@ import {
|
||||
import { id } from "../hash/index.js";
|
||||
|
||||
/**
|
||||
* A type description in a JSON API.
|
||||
* A Type description in a [JSON ABI format](link-solc-jsonabi).
|
||||
*/
|
||||
export interface JsonFragmentType {
|
||||
/**
|
||||
@ -41,7 +47,7 @@ export interface JsonFragmentType {
|
||||
}
|
||||
|
||||
/**
|
||||
* A fragment for a method, event or error in a JSON API.
|
||||
* A fragment for a method, event or error in a [JSON ABI format](link-solc-jsonabi).
|
||||
*/
|
||||
export interface JsonFragment {
|
||||
/**
|
||||
@ -92,19 +98,21 @@ export interface JsonFragment {
|
||||
|
||||
/**
|
||||
* The format to serialize the output as.
|
||||
*
|
||||
* **``"sighash"``** - the bare formatting, used to compute the selector
|
||||
* or topic hash; this format cannot be reversed (as it discards ``indexed``)
|
||||
* so cannot by used to export an [[Interface]].
|
||||
*
|
||||
* **``"minimal"``** - Human-Readable ABI with minimal spacing and without
|
||||
* names, so it is compact, but will result in Result objects that cannot
|
||||
* be accessed by name.
|
||||
*
|
||||
* **``"full"``** - Full Human-Readable ABI, with readable spacing and names
|
||||
* intact; this is generally the recommended format.
|
||||
*
|
||||
* **``"json"``** - The [JSON ABI format](link-solc-jsonabi).
|
||||
*/
|
||||
export type FormatType =
|
||||
// Bare formatting, as is needed for computing a sighash of an event or function
|
||||
"sighash" |
|
||||
|
||||
// Human-Readable with Minimal spacing and without names (compact human-readable)
|
||||
"minimal" |
|
||||
|
||||
// Human-Readable with nice spacing, including all names
|
||||
"full" |
|
||||
|
||||
// JSON-format a la Solidity
|
||||
"json";
|
||||
export type FormatType = "sighash" | "minimal" | "full" | "json";
|
||||
|
||||
// [ "a", "b" ] => { "a": 1, "b": 1 }
|
||||
function setify(items: Array<string>): ReadonlySet<string> {
|
||||
@ -513,7 +521,7 @@ const FunctionFragmentInternal = "_FunctionInternal";
|
||||
const StructFragmentInternal = "_StructInternal";
|
||||
|
||||
/**
|
||||
* Each input and output of a [[Fragment]] is an Array of **PAramType**.
|
||||
* Each input and output of a [[Fragment]] is an Array of **ParamType**.
|
||||
*/
|
||||
export class ParamType {
|
||||
|
||||
@ -642,16 +650,6 @@ export class ParamType {
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if %%value%% is an Array type.
|
||||
*
|
||||
* This provides a type gaurd ensuring that the
|
||||
* [[arrayChildren]] and [[arrayLength]] are non-null.
|
||||
*/
|
||||
//static isArray(value: any): value is { arrayChildren: ParamType, arrayLength: number } {
|
||||
// return value && (value.baseType === "array")
|
||||
//}
|
||||
|
||||
/**
|
||||
* Returns true if %%this%% is an Array type.
|
||||
*
|
||||
@ -913,7 +911,7 @@ export abstract class Fragment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this fragment.
|
||||
* Returns a string representation of this fragment as %%format%%.
|
||||
*/
|
||||
abstract format(format?: FormatType): string;
|
||||
|
||||
@ -1050,6 +1048,9 @@ export class ErrorFragment extends NamedFragment {
|
||||
return id(this.format("sighash")).substring(0, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this fragment as %%format%%.
|
||||
*/
|
||||
format(format?: FormatType): string {
|
||||
if (format == null) { format = "sighash"; }
|
||||
if (format === "json") {
|
||||
@ -1066,6 +1067,9 @@ export class ErrorFragment extends NamedFragment {
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **ErrorFragment** for %%obj%%.
|
||||
*/
|
||||
static from(obj: any): ErrorFragment {
|
||||
if (ErrorFragment.isFragment(obj)) { return obj; }
|
||||
|
||||
@ -1084,6 +1088,10 @@ export class ErrorFragment extends NamedFragment {
|
||||
obj.inputs ? obj.inputs.map(ParamType.from): [ ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard if %%value%% is an
|
||||
* **ErrorFragment**.
|
||||
*/
|
||||
static isFragment(value: any): value is ErrorFragment {
|
||||
return (value && value[internal] === ErrorFragmentInternal);
|
||||
}
|
||||
@ -1093,6 +1101,9 @@ export class ErrorFragment extends NamedFragment {
|
||||
* A Fragment which represents an Event.
|
||||
*/
|
||||
export class EventFragment extends NamedFragment {
|
||||
/**
|
||||
* Whether this event is anonymous.
|
||||
*/
|
||||
readonly anonymous!: boolean;
|
||||
|
||||
/**
|
||||
@ -1111,6 +1122,9 @@ export class EventFragment extends NamedFragment {
|
||||
return id(this.format("sighash"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this event as %%format%%.
|
||||
*/
|
||||
format(format?: FormatType): string {
|
||||
if (format == null) { format = "sighash"; }
|
||||
if (format === "json") {
|
||||
@ -1129,12 +1143,18 @@ export class EventFragment extends NamedFragment {
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the topic hash for an event with %%name%% and %%params%%.
|
||||
*/
|
||||
static getTopicHash(name: string, params?: Array<any>): string {
|
||||
params = (params || []).map((p) => ParamType.from(p));
|
||||
const fragment = new EventFragment(_guard, name, params, false);
|
||||
return fragment.topicHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **EventFragment** for %%obj%%.
|
||||
*/
|
||||
static from(obj: any): EventFragment {
|
||||
if (EventFragment.isFragment(obj)) { return obj; }
|
||||
|
||||
@ -1154,6 +1174,10 @@ export class EventFragment extends NamedFragment {
|
||||
obj.inputs ? obj.inputs.map((p: any) => ParamType.from(p, true)): [ ], !!obj.anonymous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard if %%value%% is an
|
||||
* **EventFragment**.
|
||||
*/
|
||||
static isFragment(value: any): value is EventFragment {
|
||||
return (value && value[internal] === EventFragmentInternal);
|
||||
}
|
||||
@ -1163,7 +1187,15 @@ export class EventFragment extends NamedFragment {
|
||||
* A Fragment which represents a constructor.
|
||||
*/
|
||||
export class ConstructorFragment extends Fragment {
|
||||
|
||||
/**
|
||||
* Whether the constructor can receive an endowment.
|
||||
*/
|
||||
readonly payable!: boolean;
|
||||
|
||||
/**
|
||||
* The recommended gas limit for deployment or ``null``.
|
||||
*/
|
||||
readonly gas!: null | bigint;
|
||||
|
||||
/**
|
||||
@ -1175,6 +1207,9 @@ export class ConstructorFragment extends Fragment {
|
||||
defineProperties<ConstructorFragment>(this, { payable, gas });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this constructor as %%format%%.
|
||||
*/
|
||||
format(format?: FormatType): string {
|
||||
assert(format != null && format !== "sighash", "cannot format a constructor for sighash",
|
||||
"UNSUPPORTED_OPERATION", { operation: "format(sighash)" });
|
||||
@ -1195,6 +1230,9 @@ export class ConstructorFragment extends Fragment {
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **ConstructorFragment** for %%obj%%.
|
||||
*/
|
||||
static from(obj: any): ConstructorFragment {
|
||||
if (ConstructorFragment.isFragment(obj)) { return obj; }
|
||||
|
||||
@ -1216,6 +1254,10 @@ export class ConstructorFragment extends Fragment {
|
||||
!!obj.payable, (obj.gas != null) ? obj.gas: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard if %%value%% is a
|
||||
* **ConstructorFragment**.
|
||||
*/
|
||||
static isFragment(value: any): value is ConstructorFragment {
|
||||
return (value && value[internal] === ConstructorFragmentInternal);
|
||||
}
|
||||
@ -1237,6 +1279,9 @@ export class FallbackFragment extends Fragment {
|
||||
defineProperties<FallbackFragment>(this, { payable });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this fallback as %%format%%.
|
||||
*/
|
||||
format(format?: FormatType): string {
|
||||
const type = ((this.inputs.length === 0) ? "receive": "fallback");
|
||||
|
||||
@ -1248,6 +1293,9 @@ export class FallbackFragment extends Fragment {
|
||||
return `${ type }()${ this.payable ? " payable": "" }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **FallbackFragment** for %%obj%%.
|
||||
*/
|
||||
static from(obj: any): FallbackFragment {
|
||||
if (FallbackFragment.isFragment(obj)) { return obj; }
|
||||
|
||||
@ -1310,6 +1358,10 @@ export class FallbackFragment extends Fragment {
|
||||
assertArgument(false, "invalid fallback description", "obj", obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard if %%value%% is a
|
||||
* **FallbackFragment**.
|
||||
*/
|
||||
static isFragment(value: any): value is FallbackFragment {
|
||||
return (value && value[internal] === FallbackFragmentInternal);
|
||||
}
|
||||
@ -1342,7 +1394,7 @@ export class FunctionFragment extends NamedFragment {
|
||||
readonly payable!: boolean;
|
||||
|
||||
/**
|
||||
* The amount of gas to send when calling this function
|
||||
* The recommended gas limit to send when calling this function.
|
||||
*/
|
||||
readonly gas!: null | bigint;
|
||||
|
||||
@ -1365,6 +1417,9 @@ export class FunctionFragment extends NamedFragment {
|
||||
return id(this.format("sighash")).substring(0, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this function as %%format%%.
|
||||
*/
|
||||
format(format?: FormatType): string {
|
||||
if (format == null) { format = "sighash"; }
|
||||
if (format === "json") {
|
||||
@ -1401,12 +1456,18 @@ export class FunctionFragment extends NamedFragment {
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the selector for a function with %%name%% and %%params%%.
|
||||
*/
|
||||
static getSelector(name: string, params?: Array<any>): string {
|
||||
params = (params || []).map((p) => ParamType.from(p));
|
||||
const fragment = new FunctionFragment(_guard, name, "view", params, [ ], null);
|
||||
return fragment.selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **FunctionFragment** for %%obj%%.
|
||||
*/
|
||||
static from(obj: any): FunctionFragment {
|
||||
if (FunctionFragment.isFragment(obj)) { return obj; }
|
||||
|
||||
@ -1458,6 +1519,10 @@ export class FunctionFragment extends NamedFragment {
|
||||
(obj.gas != null) ? obj.gas: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard if %%value%% is a
|
||||
* **FunctionFragment**.
|
||||
*/
|
||||
static isFragment(value: any): value is FunctionFragment {
|
||||
return (value && value[internal] === FunctionFragmentInternal);
|
||||
}
|
||||
@ -1476,10 +1541,16 @@ export class StructFragment extends NamedFragment {
|
||||
Object.defineProperty(this, internal, { value: StructFragmentInternal });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this struct as %%format%%.
|
||||
*/
|
||||
format(): string {
|
||||
throw new Error("@TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **StructFragment** for %%obj%%.
|
||||
*/
|
||||
static from(obj: any): StructFragment {
|
||||
if (typeof(obj) === "string") {
|
||||
return StructFragment.from(lex(obj));
|
||||
@ -1494,6 +1565,11 @@ export class StructFragment extends NamedFragment {
|
||||
return new StructFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.from): [ ]);
|
||||
}
|
||||
|
||||
// @TODO: fix this return type
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard if %%value%% is a
|
||||
* **StructFragment**.
|
||||
*/
|
||||
static isFragment(value: any): value is FunctionFragment {
|
||||
return (value && value[internal] === StructFragmentInternal);
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
/**
|
||||
* Explain about ABI here...
|
||||
* The Application Binary Interface (ABI) describes how method input
|
||||
* parameters should be encoded, their results decoded, and how to
|
||||
* decode events and errors.
|
||||
*
|
||||
* See [About ABIs](docs-abi) for more details how they are used.
|
||||
*
|
||||
* @_section api/abi:Application Binary Interface [about-abi]
|
||||
* @_navTitle: ABI
|
||||
|
@ -1,5 +1,11 @@
|
||||
/**
|
||||
* About Interface
|
||||
* The Interface class is a low-level class that accepts an
|
||||
* ABI and provides all the necessary functionality to encode
|
||||
* and decode paramaters to and results from methods, events
|
||||
* and errors.
|
||||
*
|
||||
* It also provides several convenience methods to automatically
|
||||
* search and find matching transactions and events to parse them.
|
||||
*
|
||||
* @_subsection api/abi:Interfaces [interfaces]
|
||||
*/
|
||||
@ -27,13 +33,39 @@ import type { JsonFragment } from "./fragments.js";
|
||||
|
||||
export { checkResultErrors, Result };
|
||||
|
||||
/**
|
||||
* When using the [[Interface-parseLog]] to automatically match a Log to its event
|
||||
* for parsing, a **LogDescription** is returned.
|
||||
*/
|
||||
export class LogDescription {
|
||||
/**
|
||||
* The matching fragment for the ``topic0``.
|
||||
*/
|
||||
readonly fragment!: EventFragment;
|
||||
|
||||
/**
|
||||
* The name of the Event.
|
||||
*/
|
||||
readonly name!: string;
|
||||
|
||||
/**
|
||||
* The full Event signature.
|
||||
*/
|
||||
readonly signature!: string;
|
||||
|
||||
/**
|
||||
* The topic hash for the Event.
|
||||
*/
|
||||
readonly topic!: string;
|
||||
|
||||
/**
|
||||
* The arguments passed into the Event with ``emit``.
|
||||
*/
|
||||
readonly args!: Result
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(fragment: EventFragment, topic: string, args: Result) {
|
||||
const name = fragment.name, signature = fragment.format();
|
||||
defineProperties<LogDescription>(this, {
|
||||
@ -42,14 +74,45 @@ export class LogDescription {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When using the [[Interface-parseTransaction]] to automatically match
|
||||
* a transaction data to its function for parsing,
|
||||
* a **TransactionDescription** is returned.
|
||||
*/
|
||||
export class TransactionDescription {
|
||||
/**
|
||||
* The matching fragment from the transaction ``data``.
|
||||
*/
|
||||
readonly fragment!: FunctionFragment;
|
||||
|
||||
/**
|
||||
* The name of the Function from the transaction ``data``.
|
||||
*/
|
||||
readonly name!: string;
|
||||
|
||||
/**
|
||||
* The arguments passed to the Function from the transaction ``data``.
|
||||
*/
|
||||
readonly args!: Result;
|
||||
|
||||
/**
|
||||
* The full Function signature from the transaction ``data``.
|
||||
*/
|
||||
readonly signature!: string;
|
||||
|
||||
/**
|
||||
* The selector for the Function from the transaction ``data``.
|
||||
*/
|
||||
readonly selector!: string;
|
||||
|
||||
/**
|
||||
* The ``value`` (in wei) from the transaction.
|
||||
*/
|
||||
readonly value!: bigint;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(fragment: FunctionFragment, selector: string, args: Result, value: bigint) {
|
||||
const name = fragment.name, signature = fragment.format();
|
||||
defineProperties<TransactionDescription>(this, {
|
||||
@ -58,13 +121,39 @@ export class TransactionDescription {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When using the [[Interface-parseError]] to automatically match an
|
||||
* error for a call result for parsing, an **ErrorDescription** is returned.
|
||||
*/
|
||||
export class ErrorDescription {
|
||||
/**
|
||||
* The matching fragment.
|
||||
*/
|
||||
readonly fragment!: ErrorFragment;
|
||||
|
||||
/**
|
||||
* The name of the Error.
|
||||
*/
|
||||
readonly name!: string;
|
||||
|
||||
/**
|
||||
* The arguments passed to the Error with ``revert``.
|
||||
*/
|
||||
readonly args!: Result;
|
||||
|
||||
/**
|
||||
* The full Error signature.
|
||||
*/
|
||||
readonly signature!: string;
|
||||
|
||||
/**
|
||||
* The selector for the Error.
|
||||
*/
|
||||
readonly selector!: string;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(fragment: ErrorFragment, selector: string, args: Result) {
|
||||
const name = fragment.name, signature = fragment.format();
|
||||
defineProperties<ErrorDescription>(this, {
|
||||
@ -73,14 +162,35 @@ export class ErrorDescription {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An **Indexed** is used as a value when a value that does not
|
||||
* fit within a topic (i.e. not a fixed-length, 32-byte type). It
|
||||
* is the ``keccak256`` of the value, and used for types such as
|
||||
* arrays, tuples, bytes and strings.
|
||||
*/
|
||||
export class Indexed {
|
||||
/**
|
||||
* The ``keccak256`` of the value logged.
|
||||
*/
|
||||
readonly hash!: null | string;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly _isIndexed!: boolean;
|
||||
|
||||
/**
|
||||
* Returns ``true`` if %%value%% is an **Indexed**.
|
||||
*
|
||||
* This provides a Type Guard for property access.
|
||||
*/
|
||||
static isIndexed(value: any): value is Indexed {
|
||||
return !!(value && value._isIndexed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(hash: null | string) {
|
||||
defineProperties<Indexed>(this, { hash, _isIndexed: true })
|
||||
}
|
||||
@ -152,7 +262,23 @@ function checkNames(fragment: Fragment, type: "input" | "output", params: Array<
|
||||
*/
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* An **InterfaceAbi** may be any supported ABI format.
|
||||
*
|
||||
* A string is expected to be a JSON string, which will be parsed
|
||||
* using ``JSON.parse``. This means that the value **must** be a valid
|
||||
* JSON string, with no stray commas, etc.
|
||||
*
|
||||
* An array may contain any combination of:
|
||||
* - Human-Readable fragments
|
||||
* - Parsed JSON fragment
|
||||
* - [[Fragment]] instances
|
||||
*
|
||||
* A **Human-Readable Fragment** is a string which resembles a Solidity
|
||||
* signature and is introduced in [this blog entry](link-ricmoo-humanreadableabi).
|
||||
* For example, ``function balanceOf(address) view returns (uint)``.
|
||||
*
|
||||
* A **Parsed JSON Fragment** is a JavaScript Object desribed in the
|
||||
* [Solidity documentation](link-solc-jsonabi).
|
||||
*/
|
||||
export type InterfaceAbi = string | ReadonlyArray<Fragment | JsonFragment | string>;
|
||||
|
||||
|
@ -38,6 +38,10 @@ function b(value: BytesLike, size?: number): Typed {
|
||||
return new Typed(_gaurd, `bytes${ (size) ? size: "" }`, value, { size });
|
||||
}
|
||||
|
||||
// @TODO: Remove this in v7, it was replaced by TypedBigInt
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
export interface TypedNumber extends Typed {
|
||||
value: number;
|
||||
defaultValue(): number;
|
||||
@ -45,33 +49,88 @@ export interface TypedNumber extends Typed {
|
||||
maxValue(): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Typed** that represents a numeric value.
|
||||
*/
|
||||
export interface TypedBigInt extends Typed {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
value: bigint;
|
||||
|
||||
/**
|
||||
* The default value for all numeric types is ``0``.
|
||||
*/
|
||||
defaultValue(): bigint;
|
||||
|
||||
/**
|
||||
* The minimum value for this type, accounting for bit-width and signed-ness.
|
||||
*/
|
||||
minValue(): bigint;
|
||||
|
||||
/**
|
||||
* The minimum value for this type, accounting for bit-width.
|
||||
*/
|
||||
maxValue(): bigint;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Typed** that represents a binary sequence of data as bytes.
|
||||
*/
|
||||
export interface TypedData extends Typed {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
/**
|
||||
* The default value for this type.
|
||||
*/
|
||||
defaultValue(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Typed** that represents a UTF-8 sequence of bytes.
|
||||
*/
|
||||
export interface TypedString extends Typed {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
/**
|
||||
* The default value for the string type is the empty string (i.e. ``""``).
|
||||
*/
|
||||
defaultValue(): string;
|
||||
}
|
||||
|
||||
const _typedSymbol = Symbol.for("_ethers_typed");
|
||||
|
||||
/**
|
||||
* The **Typed** class to wrap values providing explicit type information.
|
||||
*/
|
||||
export class Typed {
|
||||
|
||||
/**
|
||||
* The type, as a Solidity-compatible type.
|
||||
*/
|
||||
readonly type!: string;
|
||||
|
||||
/**
|
||||
* The actual value.
|
||||
*/
|
||||
readonly value!: any;
|
||||
|
||||
readonly #options: any;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly _typedSymbol!: Symbol;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(gaurd: any, type: string, value: any, options?: any) {
|
||||
if (options == null) { options = null; }
|
||||
assertPrivate(_gaurd, gaurd, "Typed");
|
||||
@ -82,6 +141,9 @@ export class Typed {
|
||||
this.format();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the type as a Human-Readable type.
|
||||
*/
|
||||
format(): string {
|
||||
if (this.type === "array") {
|
||||
throw new Error("");
|
||||
@ -94,30 +156,51 @@ export class Typed {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value returned by this type.
|
||||
*/
|
||||
defaultValue(): string | number | bigint | Result {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum value for numeric types.
|
||||
*/
|
||||
minValue(): string | number | bigint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum value for numeric types.
|
||||
*/
|
||||
maxValue(): string | number | bigint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard is this is a [[TypedBigInt]].
|
||||
*/
|
||||
isBigInt(): this is TypedBigInt {
|
||||
return !!(this.type.match(/^u?int[0-9]+$/));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard is this is a [[TypedData]].
|
||||
*/
|
||||
isData(): this is TypedData {
|
||||
return this.type.startsWith("bytes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard is this is a [[TypedString]].
|
||||
*/
|
||||
isString(): this is TypedString {
|
||||
return (this.type === "string");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuple name, if this is a tuple. Throws otherwise.
|
||||
*/
|
||||
get tupleName(): null | string {
|
||||
if (this.type !== "tuple") { throw TypeError("not a tuple"); }
|
||||
return this.#options;
|
||||
@ -127,6 +210,12 @@ export class Typed {
|
||||
// - `null` indicates the length is unforced, it could be dynamic
|
||||
// - `-1` indicates the length is dynamic
|
||||
// - any other value indicates it is a static array and is its length
|
||||
|
||||
/**
|
||||
* Returns the length of the array type or ``-1`` if it is dynamic.
|
||||
*
|
||||
* Throws if the type is not an array.
|
||||
*/
|
||||
get arrayLength(): null | number {
|
||||
if (this.type !== "array") { throw TypeError("not an array"); }
|
||||
if (this.#options === true) { return -1; }
|
||||
@ -134,126 +223,546 @@ export class Typed {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **Typed** of %%type%% with the %%value%%.
|
||||
*/
|
||||
static from(type: string, value: any): Typed {
|
||||
return new Typed(_gaurd, type, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new ``uint8`` type for %%v%%.
|
||||
*/
|
||||
static uint8(v: BigNumberish): Typed { return n(v, 8); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint16`` type for %%v%%.
|
||||
*/
|
||||
static uint16(v: BigNumberish): Typed { return n(v, 16); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint24`` type for %%v%%.
|
||||
*/
|
||||
static uint24(v: BigNumberish): Typed { return n(v, 24); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint32`` type for %%v%%.
|
||||
*/
|
||||
static uint32(v: BigNumberish): Typed { return n(v, 32); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint40`` type for %%v%%.
|
||||
*/
|
||||
static uint40(v: BigNumberish): Typed { return n(v, 40); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint48`` type for %%v%%.
|
||||
*/
|
||||
static uint48(v: BigNumberish): Typed { return n(v, 48); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint56`` type for %%v%%.
|
||||
*/
|
||||
static uint56(v: BigNumberish): Typed { return n(v, 56); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint64`` type for %%v%%.
|
||||
*/
|
||||
static uint64(v: BigNumberish): Typed { return n(v, 64); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint72`` type for %%v%%.
|
||||
*/
|
||||
static uint72(v: BigNumberish): Typed { return n(v, 72); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint80`` type for %%v%%.
|
||||
*/
|
||||
static uint80(v: BigNumberish): Typed { return n(v, 80); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint88`` type for %%v%%.
|
||||
*/
|
||||
static uint88(v: BigNumberish): Typed { return n(v, 88); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint96`` type for %%v%%.
|
||||
*/
|
||||
static uint96(v: BigNumberish): Typed { return n(v, 96); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint104`` type for %%v%%.
|
||||
*/
|
||||
static uint104(v: BigNumberish): Typed { return n(v, 104); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint112`` type for %%v%%.
|
||||
*/
|
||||
static uint112(v: BigNumberish): Typed { return n(v, 112); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint120`` type for %%v%%.
|
||||
*/
|
||||
static uint120(v: BigNumberish): Typed { return n(v, 120); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint128`` type for %%v%%.
|
||||
*/
|
||||
static uint128(v: BigNumberish): Typed { return n(v, 128); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint136`` type for %%v%%.
|
||||
*/
|
||||
static uint136(v: BigNumberish): Typed { return n(v, 136); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint144`` type for %%v%%.
|
||||
*/
|
||||
static uint144(v: BigNumberish): Typed { return n(v, 144); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint152`` type for %%v%%.
|
||||
*/
|
||||
static uint152(v: BigNumberish): Typed { return n(v, 152); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint160`` type for %%v%%.
|
||||
*/
|
||||
static uint160(v: BigNumberish): Typed { return n(v, 160); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint168`` type for %%v%%.
|
||||
*/
|
||||
static uint168(v: BigNumberish): Typed { return n(v, 168); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint176`` type for %%v%%.
|
||||
*/
|
||||
static uint176(v: BigNumberish): Typed { return n(v, 176); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint184`` type for %%v%%.
|
||||
*/
|
||||
static uint184(v: BigNumberish): Typed { return n(v, 184); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint192`` type for %%v%%.
|
||||
*/
|
||||
static uint192(v: BigNumberish): Typed { return n(v, 192); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint200`` type for %%v%%.
|
||||
*/
|
||||
static uint200(v: BigNumberish): Typed { return n(v, 200); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint208`` type for %%v%%.
|
||||
*/
|
||||
static uint208(v: BigNumberish): Typed { return n(v, 208); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint216`` type for %%v%%.
|
||||
*/
|
||||
static uint216(v: BigNumberish): Typed { return n(v, 216); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint224`` type for %%v%%.
|
||||
*/
|
||||
static uint224(v: BigNumberish): Typed { return n(v, 224); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint232`` type for %%v%%.
|
||||
*/
|
||||
static uint232(v: BigNumberish): Typed { return n(v, 232); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint240`` type for %%v%%.
|
||||
*/
|
||||
static uint240(v: BigNumberish): Typed { return n(v, 240); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint248`` type for %%v%%.
|
||||
*/
|
||||
static uint248(v: BigNumberish): Typed { return n(v, 248); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint256`` type for %%v%%.
|
||||
*/
|
||||
static uint256(v: BigNumberish): Typed { return n(v, 256); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint256`` type for %%v%%.
|
||||
*/
|
||||
static uint(v: BigNumberish): Typed { return n(v, 256); }
|
||||
|
||||
/**
|
||||
* Return a new ``int8`` type for %%v%%.
|
||||
*/
|
||||
static int8(v: BigNumberish): Typed { return n(v, -8); }
|
||||
|
||||
/**
|
||||
* Return a new ``int16`` type for %%v%%.
|
||||
*/
|
||||
static int16(v: BigNumberish): Typed { return n(v, -16); }
|
||||
|
||||
/**
|
||||
* Return a new ``int24`` type for %%v%%.
|
||||
*/
|
||||
static int24(v: BigNumberish): Typed { return n(v, -24); }
|
||||
|
||||
/**
|
||||
* Return a new ``int32`` type for %%v%%.
|
||||
*/
|
||||
static int32(v: BigNumberish): Typed { return n(v, -32); }
|
||||
|
||||
/**
|
||||
* Return a new ``int40`` type for %%v%%.
|
||||
*/
|
||||
static int40(v: BigNumberish): Typed { return n(v, -40); }
|
||||
|
||||
/**
|
||||
* Return a new ``int48`` type for %%v%%.
|
||||
*/
|
||||
static int48(v: BigNumberish): Typed { return n(v, -48); }
|
||||
|
||||
/**
|
||||
* Return a new ``int56`` type for %%v%%.
|
||||
*/
|
||||
static int56(v: BigNumberish): Typed { return n(v, -56); }
|
||||
|
||||
/**
|
||||
* Return a new ``int64`` type for %%v%%.
|
||||
*/
|
||||
static int64(v: BigNumberish): Typed { return n(v, -64); }
|
||||
|
||||
/**
|
||||
* Return a new ``int72`` type for %%v%%.
|
||||
*/
|
||||
static int72(v: BigNumberish): Typed { return n(v, -72); }
|
||||
|
||||
/**
|
||||
* Return a new ``int80`` type for %%v%%.
|
||||
*/
|
||||
static int80(v: BigNumberish): Typed { return n(v, -80); }
|
||||
|
||||
/**
|
||||
* Return a new ``int88`` type for %%v%%.
|
||||
*/
|
||||
static int88(v: BigNumberish): Typed { return n(v, -88); }
|
||||
|
||||
/**
|
||||
* Return a new ``int96`` type for %%v%%.
|
||||
*/
|
||||
static int96(v: BigNumberish): Typed { return n(v, -96); }
|
||||
|
||||
/**
|
||||
* Return a new ``int104`` type for %%v%%.
|
||||
*/
|
||||
static int104(v: BigNumberish): Typed { return n(v, -104); }
|
||||
|
||||
/**
|
||||
* Return a new ``int112`` type for %%v%%.
|
||||
*/
|
||||
static int112(v: BigNumberish): Typed { return n(v, -112); }
|
||||
|
||||
/**
|
||||
* Return a new ``int120`` type for %%v%%.
|
||||
*/
|
||||
static int120(v: BigNumberish): Typed { return n(v, -120); }
|
||||
|
||||
/**
|
||||
* Return a new ``int128`` type for %%v%%.
|
||||
*/
|
||||
static int128(v: BigNumberish): Typed { return n(v, -128); }
|
||||
|
||||
/**
|
||||
* Return a new ``int136`` type for %%v%%.
|
||||
*/
|
||||
static int136(v: BigNumberish): Typed { return n(v, -136); }
|
||||
|
||||
/**
|
||||
* Return a new ``int144`` type for %%v%%.
|
||||
*/
|
||||
static int144(v: BigNumberish): Typed { return n(v, -144); }
|
||||
|
||||
/**
|
||||
* Return a new ``int52`` type for %%v%%.
|
||||
*/
|
||||
static int152(v: BigNumberish): Typed { return n(v, -152); }
|
||||
|
||||
/**
|
||||
* Return a new ``int160`` type for %%v%%.
|
||||
*/
|
||||
static int160(v: BigNumberish): Typed { return n(v, -160); }
|
||||
|
||||
/**
|
||||
* Return a new ``int168`` type for %%v%%.
|
||||
*/
|
||||
static int168(v: BigNumberish): Typed { return n(v, -168); }
|
||||
|
||||
/**
|
||||
* Return a new ``int176`` type for %%v%%.
|
||||
*/
|
||||
static int176(v: BigNumberish): Typed { return n(v, -176); }
|
||||
|
||||
/**
|
||||
* Return a new ``int184`` type for %%v%%.
|
||||
*/
|
||||
static int184(v: BigNumberish): Typed { return n(v, -184); }
|
||||
|
||||
/**
|
||||
* Return a new ``int92`` type for %%v%%.
|
||||
*/
|
||||
static int192(v: BigNumberish): Typed { return n(v, -192); }
|
||||
|
||||
/**
|
||||
* Return a new ``int200`` type for %%v%%.
|
||||
*/
|
||||
static int200(v: BigNumberish): Typed { return n(v, -200); }
|
||||
|
||||
/**
|
||||
* Return a new ``int208`` type for %%v%%.
|
||||
*/
|
||||
static int208(v: BigNumberish): Typed { return n(v, -208); }
|
||||
|
||||
/**
|
||||
* Return a new ``int216`` type for %%v%%.
|
||||
*/
|
||||
static int216(v: BigNumberish): Typed { return n(v, -216); }
|
||||
|
||||
/**
|
||||
* Return a new ``int224`` type for %%v%%.
|
||||
*/
|
||||
static int224(v: BigNumberish): Typed { return n(v, -224); }
|
||||
|
||||
/**
|
||||
* Return a new ``int232`` type for %%v%%.
|
||||
*/
|
||||
static int232(v: BigNumberish): Typed { return n(v, -232); }
|
||||
|
||||
/**
|
||||
* Return a new ``int240`` type for %%v%%.
|
||||
*/
|
||||
static int240(v: BigNumberish): Typed { return n(v, -240); }
|
||||
|
||||
/**
|
||||
* Return a new ``int248`` type for %%v%%.
|
||||
*/
|
||||
static int248(v: BigNumberish): Typed { return n(v, -248); }
|
||||
|
||||
/**
|
||||
* Return a new ``int256`` type for %%v%%.
|
||||
*/
|
||||
static int256(v: BigNumberish): Typed { return n(v, -256); }
|
||||
|
||||
/**
|
||||
* Return a new ``int256`` type for %%v%%.
|
||||
*/
|
||||
static int(v: BigNumberish): Typed { return n(v, -256); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes1`` type for %%v%%.
|
||||
*/
|
||||
static bytes1(v: BytesLike): Typed { return b(v, 1); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes2`` type for %%v%%.
|
||||
*/
|
||||
static bytes2(v: BytesLike): Typed { return b(v, 2); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes3`` type for %%v%%.
|
||||
*/
|
||||
static bytes3(v: BytesLike): Typed { return b(v, 3); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes4`` type for %%v%%.
|
||||
*/
|
||||
static bytes4(v: BytesLike): Typed { return b(v, 4); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes5`` type for %%v%%.
|
||||
*/
|
||||
static bytes5(v: BytesLike): Typed { return b(v, 5); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes6`` type for %%v%%.
|
||||
*/
|
||||
static bytes6(v: BytesLike): Typed { return b(v, 6); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes7`` type for %%v%%.
|
||||
*/
|
||||
static bytes7(v: BytesLike): Typed { return b(v, 7); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes8`` type for %%v%%.
|
||||
*/
|
||||
static bytes8(v: BytesLike): Typed { return b(v, 8); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes9`` type for %%v%%.
|
||||
*/
|
||||
static bytes9(v: BytesLike): Typed { return b(v, 9); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes10`` type for %%v%%.
|
||||
*/
|
||||
static bytes10(v: BytesLike): Typed { return b(v, 10); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes11`` type for %%v%%.
|
||||
*/
|
||||
static bytes11(v: BytesLike): Typed { return b(v, 11); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes12`` type for %%v%%.
|
||||
*/
|
||||
static bytes12(v: BytesLike): Typed { return b(v, 12); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes13`` type for %%v%%.
|
||||
*/
|
||||
static bytes13(v: BytesLike): Typed { return b(v, 13); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes14`` type for %%v%%.
|
||||
*/
|
||||
static bytes14(v: BytesLike): Typed { return b(v, 14); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes15`` type for %%v%%.
|
||||
*/
|
||||
static bytes15(v: BytesLike): Typed { return b(v, 15); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes16`` type for %%v%%.
|
||||
*/
|
||||
static bytes16(v: BytesLike): Typed { return b(v, 16); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes17`` type for %%v%%.
|
||||
*/
|
||||
static bytes17(v: BytesLike): Typed { return b(v, 17); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes18`` type for %%v%%.
|
||||
*/
|
||||
static bytes18(v: BytesLike): Typed { return b(v, 18); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes19`` type for %%v%%.
|
||||
*/
|
||||
static bytes19(v: BytesLike): Typed { return b(v, 19); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes20`` type for %%v%%.
|
||||
*/
|
||||
static bytes20(v: BytesLike): Typed { return b(v, 20); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes21`` type for %%v%%.
|
||||
*/
|
||||
static bytes21(v: BytesLike): Typed { return b(v, 21); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes22`` type for %%v%%.
|
||||
*/
|
||||
static bytes22(v: BytesLike): Typed { return b(v, 22); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes23`` type for %%v%%.
|
||||
*/
|
||||
static bytes23(v: BytesLike): Typed { return b(v, 23); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes24`` type for %%v%%.
|
||||
*/
|
||||
static bytes24(v: BytesLike): Typed { return b(v, 24); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes25`` type for %%v%%.
|
||||
*/
|
||||
static bytes25(v: BytesLike): Typed { return b(v, 25); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes26`` type for %%v%%.
|
||||
*/
|
||||
static bytes26(v: BytesLike): Typed { return b(v, 26); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes27`` type for %%v%%.
|
||||
*/
|
||||
static bytes27(v: BytesLike): Typed { return b(v, 27); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes28`` type for %%v%%.
|
||||
*/
|
||||
static bytes28(v: BytesLike): Typed { return b(v, 28); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes29`` type for %%v%%.
|
||||
*/
|
||||
static bytes29(v: BytesLike): Typed { return b(v, 29); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes30`` type for %%v%%.
|
||||
*/
|
||||
static bytes30(v: BytesLike): Typed { return b(v, 30); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes31`` type for %%v%%.
|
||||
*/
|
||||
static bytes31(v: BytesLike): Typed { return b(v, 31); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes32`` type for %%v%%.
|
||||
*/
|
||||
static bytes32(v: BytesLike): Typed { return b(v, 32); }
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``address`` type for %%v%%.
|
||||
*/
|
||||
static address(v: string | Addressable): Typed { return new Typed(_gaurd, "address", v); }
|
||||
|
||||
/**
|
||||
* Return a new ``bool`` type for %%v%%.
|
||||
*/
|
||||
static bool(v: any): Typed { return new Typed(_gaurd, "bool", !!v); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes`` type for %%v%%.
|
||||
*/
|
||||
static bytes(v: BytesLike): Typed { return new Typed(_gaurd, "bytes", v); }
|
||||
|
||||
/**
|
||||
* Return a new ``string`` type for %%v%%.
|
||||
*/
|
||||
static string(v: string): Typed { return new Typed(_gaurd, "string", v); }
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``array`` type for %%v%%, allowing %%dynamic%% length.
|
||||
*/
|
||||
static array(v: Array<any | Typed>, dynamic?: null | boolean): Typed {
|
||||
throw new Error("not implemented yet");
|
||||
return new Typed(_gaurd, "array", v, dynamic);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``tuple`` type for %%v%%, with the optional %%name%%.
|
||||
*/
|
||||
static tuple(v: Array<any | Typed> | Record<string, any | Typed>, name?: string): Typed {
|
||||
throw new Error("not implemented yet");
|
||||
return new Typed(_gaurd, "tuple", v, name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``uint8`` type for %%v%%.
|
||||
*/
|
||||
static overrides(v: Record<string, any>): Typed {
|
||||
return new Typed(_gaurd, "overrides", Object.assign({ }, v));
|
||||
}
|
||||
|
@ -608,16 +608,49 @@ async function emit(contract: BaseContract, event: ContractEventName, args: Arra
|
||||
|
||||
const passProperties = [ "then" ];
|
||||
export class BaseContract implements Addressable, EventEmitterable<ContractEventName> {
|
||||
/**
|
||||
* The target to connect to.
|
||||
*
|
||||
* This can be an address, ENS name or any [[Addressable]], such as
|
||||
* another contract. To get the resovled address, use the ``getAddress``
|
||||
* method.
|
||||
*/
|
||||
readonly target!: string | Addressable;
|
||||
|
||||
/**
|
||||
* The contract Interface.
|
||||
*/
|
||||
readonly interface!: Interface;
|
||||
|
||||
/**
|
||||
* The connected runner. This is generally a [[Provider]] or a
|
||||
* [[Signer]], which dictates what operations are supported.
|
||||
*
|
||||
* For example, a **Contract** connected to a [[Provider]] may
|
||||
* only execute read-only operations.
|
||||
*/
|
||||
readonly runner!: null | ContractRunner;
|
||||
|
||||
/**
|
||||
* All the Events available on this contract.
|
||||
*/
|
||||
readonly filters!: Record<string, ContractEvent>;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly [internal]: any;
|
||||
|
||||
/**
|
||||
* The fallback or receive function if any.
|
||||
*/
|
||||
readonly fallback!: null | WrappedFallback;
|
||||
|
||||
/**
|
||||
* Creates a new contract connected to %%target%% with the %%abi%% and
|
||||
* optionally connected to a %%runner%% to perform operations on behalf
|
||||
* of.
|
||||
*/
|
||||
constructor(target: string | Addressable, abi: Interface | InterfaceAbi, runner?: null | ContractRunner, _deployTx?: null | TransactionResponse) {
|
||||
assertArgument(typeof(target) === "string" || isAddressable(target),
|
||||
"invalid value for Contract target", "target", target);
|
||||
@ -727,12 +760,22 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new Contract instance with the same target and ABI, but
|
||||
* a different %%runner%%.
|
||||
*/
|
||||
connect(runner: null | ContractRunner): BaseContract {
|
||||
return new BaseContract(this.target, this.interface, runner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved address of this Contract.
|
||||
*/
|
||||
async getAddress(): Promise<string> { return await getInternal(this).addrPromise; }
|
||||
|
||||
/**
|
||||
* Return the dedployed bytecode or null if no bytecode is found.
|
||||
*/
|
||||
async getDeployedCode(): Promise<null | string> {
|
||||
const provider = getProvider(this.runner);
|
||||
assert(provider, "runner does not support .provider",
|
||||
@ -743,6 +786,10 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve to this Contract once the bytecode has been deployed, or
|
||||
* resolve immediately if already deployed.
|
||||
*/
|
||||
async waitForDeployment(): Promise<this> {
|
||||
// We have the deployement transaction; just use that (throws if deployement fails)
|
||||
const deployTx = this.deploymentTransaction();
|
||||
@ -774,26 +821,50 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction used to deploy this contract.
|
||||
*
|
||||
* This is only available if this instance was returned from a
|
||||
* [[ContractFactory]].
|
||||
*/
|
||||
deploymentTransaction(): null | ContractTransactionResponse {
|
||||
return getInternal(this).deployTx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the function for a given name. This is useful when a contract
|
||||
* method name conflicts with a JavaScript name such as ``prototype`` or
|
||||
* when using a Contract programatically.
|
||||
*/
|
||||
getFunction<T extends ContractMethod = ContractMethod>(key: string | FunctionFragment): T {
|
||||
if (typeof(key) !== "string") { key = key.format(); }
|
||||
const func = buildWrappedMethod(this, key);
|
||||
return <T>func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event for a given name. This is useful when a contract
|
||||
* event name conflicts with a JavaScript name such as ``prototype`` or
|
||||
* when using a Contract programatically.
|
||||
*/
|
||||
getEvent(key: string | EventFragment): ContractEvent {
|
||||
if (typeof(key) !== "string") { key = key.format(); }
|
||||
return buildWrappedEvent(this, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
async queryTransaction(hash: string): Promise<Array<EventLog>> {
|
||||
// Is this useful?
|
||||
throw new Error("@TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide historic access to event data for %%event%% in the range
|
||||
* %%fromBlock%% (default: ``0``) to %%toBlock%% (default: ``"latest"``)
|
||||
* inclusive.
|
||||
*/
|
||||
async queryFilter(event: ContractEventName, fromBlock?: BlockTag, toBlock?: BlockTag): Promise<Array<EventLog | Log>> {
|
||||
if (fromBlock == null) { fromBlock = 0; }
|
||||
if (toBlock == null) { toBlock = "latest"; }
|
||||
@ -822,6 +893,9 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event %%listener%% for the %%event%%.
|
||||
*/
|
||||
async on(event: ContractEventName, listener: Listener): Promise<this> {
|
||||
const sub = await getSub(this, "on", event);
|
||||
sub.listeners.push({ listener, once: false });
|
||||
@ -829,6 +903,10 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event %%listener%% for the %%event%%, but remove the listener
|
||||
* after it is fired once.
|
||||
*/
|
||||
async once(event: ContractEventName, listener: Listener): Promise<this> {
|
||||
const sub = await getSub(this, "once", event);
|
||||
sub.listeners.push({ listener, once: true });
|
||||
@ -836,10 +914,19 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit an %%event%% calling all listeners with %%args%%.
|
||||
*
|
||||
* Resolves to ``true`` if any listeners were called.
|
||||
*/
|
||||
async emit(event: ContractEventName, ...args: Array<any>): Promise<boolean> {
|
||||
return await emit(this, event, args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the number of listeners of %%event%% or the total number
|
||||
* of listeners if unspecified.
|
||||
*/
|
||||
async listenerCount(event?: ContractEventName): Promise<number> {
|
||||
if (event) {
|
||||
const sub = await hasSub(this, event);
|
||||
@ -856,6 +943,10 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the listeners subscribed to %%event%% or all listeners
|
||||
* if unspecified.
|
||||
*/
|
||||
async listeners(event?: ContractEventName): Promise<Array<Listener>> {
|
||||
if (event) {
|
||||
const sub = await hasSub(this, event);
|
||||
@ -872,6 +963,10 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the %%listener%% from the listeners for %%event%% or remove
|
||||
* all listeners if unspecified.
|
||||
*/
|
||||
async off(event: ContractEventName, listener?: Listener): Promise<this> {
|
||||
const sub = await hasSub(this, event);
|
||||
if (!sub) { return this; }
|
||||
@ -889,6 +984,10 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all the listeners for %%event%% or remove all listeners if
|
||||
* unspecified.
|
||||
*/
|
||||
async removeAllListeners(event?: ContractEventName): Promise<this> {
|
||||
if (event) {
|
||||
const sub = await hasSub(this, event);
|
||||
@ -906,16 +1005,23 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return this;
|
||||
}
|
||||
|
||||
// Alias for "on"
|
||||
/**
|
||||
* Alias for [on].
|
||||
*/
|
||||
async addListener(event: ContractEventName, listener: Listener): Promise<this> {
|
||||
return await this.on(event, listener);
|
||||
}
|
||||
|
||||
// Alias for "off"
|
||||
/**
|
||||
* Alias for [off].
|
||||
*/
|
||||
async removeListener(event: ContractEventName, listener: Listener): Promise<this> {
|
||||
return await this.off(event, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Class for the %%abi%%.
|
||||
*/
|
||||
static buildClass<T = ContractInterface>(abi: InterfaceAbi): new (target: string, runner?: null | ContractRunner) => BaseContract & Omit<T, keyof BaseContract> {
|
||||
class CustomContract extends BaseContract {
|
||||
constructor(address: string, runner: null | ContractRunner = null) {
|
||||
@ -925,6 +1031,9 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
return CustomContract as any;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new BaseContract with a specified Interface.
|
||||
*/
|
||||
static from<T = ContractInterface>(target: string, abi: InterfaceAbi, runner?: null | ContractRunner): BaseContract & Omit<T, keyof BaseContract> {
|
||||
if (runner == null) { runner = null; }
|
||||
const contract = new this(target, abi, runner );
|
||||
@ -936,4 +1045,7 @@ function _ContractBase(): new (target: string, abi: InterfaceAbi, runner?: null
|
||||
return BaseContract as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* A [[BaseContract]] with no type guards on its methods or events.
|
||||
*/
|
||||
export class Contract extends _ContractBase() { }
|
||||
|
@ -20,11 +20,34 @@ import type { ContractTransactionResponse } from "./wrappers.js";
|
||||
|
||||
// A = Arguments to the constructor
|
||||
// I = Interface of deployed contracts
|
||||
|
||||
/**
|
||||
* A **ContractFactory** is used to deploy a Contract to the blockchain.
|
||||
*/
|
||||
export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract> {
|
||||
|
||||
/**
|
||||
* The Contract Interface.
|
||||
*/
|
||||
readonly interface!: Interface;
|
||||
|
||||
/**
|
||||
* The Contract deployment bytecode. Often called the initcode.
|
||||
*/
|
||||
readonly bytecode!: string;
|
||||
|
||||
/**
|
||||
* The ContractRunner to deploy the Contract as.
|
||||
*/
|
||||
readonly runner!: null | ContractRunner;
|
||||
|
||||
/**
|
||||
* Create a new **ContractFactory** with %%abi%% and %%bytecode%%,
|
||||
* optionally connected to %%runner%%.
|
||||
*
|
||||
* The %%bytecode%% may be the ``bytecode`` property within the
|
||||
* standard Solidity JSON output.
|
||||
*/
|
||||
constructor(abi: Interface | InterfaceAbi, bytecode: BytesLike | { object: string }, runner?: null | ContractRunner) {
|
||||
const iface = Interface.from(abi);
|
||||
|
||||
@ -42,6 +65,10 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction to deploy the contract, passing %%args%%
|
||||
* into the constructor.
|
||||
*/
|
||||
async getDeployTransaction(...args: ContractMethodArgs<A>): Promise<ContractDeployTransaction> {
|
||||
let overrides: Omit<ContractDeployTransaction, "data"> = { };
|
||||
|
||||
@ -61,6 +88,14 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
||||
return Object.assign({ }, overrides, { data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the Contract deployed by passing %%args%% into the
|
||||
* constructor.
|
||||
*
|
||||
* This will resovle to the Contract before it has been deployed to the
|
||||
* network, so the [[BaseContract-waitForDeployment]] should be used before
|
||||
* sending any transactions to it.
|
||||
*/
|
||||
async deploy(...args: ContractMethodArgs<A>): Promise<BaseContract & { deploymentTransaction(): ContractTransactionResponse } & Omit<I, keyof BaseContract>> {
|
||||
const tx = await this.getDeployTransaction(...args);
|
||||
|
||||
@ -73,10 +108,17 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
||||
return new (<any>BaseContract)(address, this.interface, this.runner, sentTx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new **ContractFactory** with the same ABI and bytecode,
|
||||
* but connected to %%runner%%.
|
||||
*/
|
||||
connect(runner: null | ContractRunner): ContractFactory<A, I> {
|
||||
return new ContractFactory(this.interface, this.bytecode, runner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new **ContractFactory** from the standard Solidity JSON output.
|
||||
*/
|
||||
static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
|
||||
assertArgument(output != null, "bad compiler output", "output", output);
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
/**
|
||||
* About contracts...
|
||||
* A **Contract** object is a meta-class (a class whose definition is
|
||||
* defined at runtime), which communicates with a deployed smart contract
|
||||
* on the blockchain and provides a simple JavaScript interface to call
|
||||
* methods, send transaction, query historic logs and listen for its events.
|
||||
*
|
||||
* @_section: api/contract:Contracts [about-contracts]
|
||||
*/
|
||||
|
@ -8,36 +8,89 @@ import type {
|
||||
import type { ContractTransactionResponse } from "./wrappers.js";
|
||||
|
||||
|
||||
// The types of events a Contract can listen for
|
||||
/**
|
||||
* The name for an event used for subscribing to Contract events.
|
||||
*
|
||||
* **``string``** - An event by name. The event must be non-ambiguous.
|
||||
* The parameters will be dereferenced when passed into the listener.
|
||||
*
|
||||
* [[ContractEvent]] - A filter from the ``contract.filters``, which will
|
||||
* pass only the EventPayload as a single parameter, which includes a
|
||||
* ``.signature`` property that can be used to further filter the event.
|
||||
*
|
||||
* [[TopicFilter]] - A filter defined using the standard Ethereum API
|
||||
* which provides the specific topic hash or topic hashes to watch for along
|
||||
* with any additional values to filter by. This will only pass a single
|
||||
* parameter to the listener, the EventPayload which will include additional
|
||||
* details to refine by, such as the event name and signature.
|
||||
*
|
||||
* [[DeferredTopicFilter]] - A filter created by calling a [[ContractEvent]]
|
||||
* with parameters, which will create a filter for a specific event
|
||||
* signautre and dereference each parameter when calling the listener.
|
||||
*/
|
||||
export type ContractEventName = string | ContractEvent | TopicFilter | DeferredTopicFilter;
|
||||
|
||||
/**
|
||||
* A Contract with no method constraints.
|
||||
*/
|
||||
export interface ContractInterface {
|
||||
[ name: string ]: BaseContractMethod;
|
||||
};
|
||||
|
||||
/**
|
||||
* When creating a filter using the ``contract.filters``, this is returned.
|
||||
*/
|
||||
export interface DeferredTopicFilter {
|
||||
getTopicFilter(): Promise<TopicFilter>;
|
||||
fragment: EventFragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* When populating a transaction this type is returned.
|
||||
*/
|
||||
export interface ContractTransaction extends PreparedTransactionRequest {
|
||||
// These are populated by contract methods and cannot bu null
|
||||
/**
|
||||
* The target address.
|
||||
*/
|
||||
to: string;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data: string;
|
||||
|
||||
// These are resolved
|
||||
/**
|
||||
* The from address, if any.
|
||||
*/
|
||||
from?: string;
|
||||
}
|
||||
|
||||
// Deployment Transactions have no `to`
|
||||
/**
|
||||
* A deployment transaction for a contract.
|
||||
*/
|
||||
export interface ContractDeployTransaction extends Omit<ContractTransaction, "to"> { }
|
||||
|
||||
// Overrides; cannot override `to` or `data` as Contract populates these
|
||||
/**
|
||||
* The overrides for a contract transaction.
|
||||
*/
|
||||
export interface Overrides extends Omit<TransactionRequest, "to" | "data"> { };
|
||||
|
||||
|
||||
// Arguments for methods; with an optional (n+1)th Override
|
||||
/**
|
||||
* Arguments to a Contract method can always include an additional and
|
||||
* optional overrides parameter.
|
||||
*
|
||||
* @_ignore:
|
||||
*/
|
||||
export type PostfixOverrides<A extends Array<any>> = A | [ ...A, Overrides ];
|
||||
|
||||
/**
|
||||
* Arguments to a Contract method can always include an additional and
|
||||
* optional overrides parameter, and each parameter can optionally be
|
||||
* [[Typed]].
|
||||
*
|
||||
* @_ignore:
|
||||
*/
|
||||
export type ContractMethodArgs<A extends Array<any>> = PostfixOverrides<{ [ I in keyof A ]-?: A[I] | Typed }>;
|
||||
|
||||
// A = Arguments passed in as a tuple
|
||||
@ -45,51 +98,139 @@ export type ContractMethodArgs<A extends Array<any>> = PostfixOverrides<{ [ I in
|
||||
// the qualified type, otherwise Result)
|
||||
// D = The type the default call will return (i.e. R for view/pure,
|
||||
// TransactionResponse otherwise)
|
||||
|
||||
/**
|
||||
* A Contract method can be called directly, or used in various ways.
|
||||
*/
|
||||
export interface BaseContractMethod<A extends Array<any> = Array<any>, R = any, D extends R | ContractTransactionResponse = R | ContractTransactionResponse> {
|
||||
(...args: ContractMethodArgs<A>): Promise<D>;
|
||||
|
||||
/**
|
||||
* The name of the Contract method.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The fragment of the Contract method. This will throw on ambiguous
|
||||
* method names.
|
||||
*/
|
||||
fragment: FunctionFragment;
|
||||
|
||||
/**
|
||||
* Returns the fragment constrained by %%args%%. This can be used to
|
||||
* resolve ambiguous method names.
|
||||
*/
|
||||
getFragment(...args: ContractMethodArgs<A>): FunctionFragment;
|
||||
|
||||
/**
|
||||
* Returns a populated transaction that can be used to perform the
|
||||
* contract method with %%args%%.
|
||||
*/
|
||||
populateTransaction(...args: ContractMethodArgs<A>): Promise<ContractTransaction>;
|
||||
|
||||
/**
|
||||
* Call the contract method with %%args%% and return the value.
|
||||
*
|
||||
* If the return value is a single type, it will be dereferenced and
|
||||
* returned directly, otherwise the full Result will be returned.
|
||||
*/
|
||||
staticCall(...args: ContractMethodArgs<A>): Promise<R>;
|
||||
|
||||
/**
|
||||
* Send a transaction for the contract method with %%args%%.
|
||||
*/
|
||||
send(...args: ContractMethodArgs<A>): Promise<ContractTransactionResponse>;
|
||||
|
||||
/**
|
||||
* Estimate the gas to send the contract method with %%args%%.
|
||||
*/
|
||||
estimateGas(...args: ContractMethodArgs<A>): Promise<bigint>;
|
||||
|
||||
/**
|
||||
* Call the contract method with %%args%% and return the Result
|
||||
* without any dereferencing.
|
||||
*/
|
||||
staticCallResult(...args: ContractMethodArgs<A>): Promise<Result>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A contract method on a Contract.
|
||||
*/
|
||||
export interface ContractMethod<
|
||||
A extends Array<any> = Array<any>,
|
||||
R = any,
|
||||
D extends R | ContractTransactionResponse = R | ContractTransactionResponse
|
||||
> extends BaseContractMethod<A, R, D> { }
|
||||
|
||||
/**
|
||||
* A pure of view method on a Contract.
|
||||
*/
|
||||
export interface ConstantContractMethod<
|
||||
A extends Array<any>,
|
||||
R = any
|
||||
> extends ContractMethod<A, R, R> { }
|
||||
|
||||
|
||||
// Arguments for events; with each element optional and/or nullable
|
||||
/**
|
||||
* Each argument of an event is nullable (to indicate matching //any//.
|
||||
*
|
||||
* @_ignore:
|
||||
*/
|
||||
export type ContractEventArgs<A extends Array<any>> = { [ I in keyof A ]?: A[I] | Typed | null };
|
||||
|
||||
export interface ContractEvent<A extends Array<any> = Array<any>> {
|
||||
(...args: ContractEventArgs<A>): DeferredTopicFilter;
|
||||
|
||||
/**
|
||||
* The name of the Contract event.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The fragment of the Contract event. This will throw on ambiguous
|
||||
* method names.
|
||||
*/
|
||||
fragment: EventFragment;
|
||||
|
||||
/**
|
||||
* Returns the fragment constrained by %%args%%. This can be used to
|
||||
* resolve ambiguous event names.
|
||||
*/
|
||||
getFragment(...args: ContractEventArgs<A>): EventFragment;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Fallback or Receive function on a Contract.
|
||||
*/
|
||||
export interface WrappedFallback {
|
||||
(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransactionResponse>;
|
||||
|
||||
/**
|
||||
* Returns a populated transaction that can be used to perform the
|
||||
* fallback method.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
populateTransaction(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransaction>;
|
||||
|
||||
/**
|
||||
* Call the contract fallback and return the result.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
staticCall(overrides?: Omit<TransactionRequest, "to">): Promise<string>;
|
||||
|
||||
/**
|
||||
* Send a transaction to the contract fallback.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
send(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransactionResponse>;
|
||||
|
||||
/**
|
||||
* Estimate the gas to send a transaction to the contract fallback.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
estimateGas(overrides?: Omit<TransactionRequest, "to">): Promise<bigint>;
|
||||
}
|
||||
|
@ -14,30 +14,64 @@ import type {
|
||||
import type { BaseContract } from "./contract.js";
|
||||
import type { ContractEventName } from "./types.js";
|
||||
|
||||
|
||||
/**
|
||||
* An **EventLog** contains additional properties parsed from the [[Log]].
|
||||
*/
|
||||
export class EventLog extends Log {
|
||||
/**
|
||||
* The Contract Interface.
|
||||
*/
|
||||
readonly interface!: Interface;
|
||||
|
||||
/**
|
||||
* The matching event.
|
||||
*/
|
||||
readonly fragment!: EventFragment;
|
||||
|
||||
/**
|
||||
* The parsed arguments passed to the event by ``emit``.
|
||||
*/
|
||||
readonly args!: Result;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(log: Log, iface: Interface, fragment: EventFragment) {
|
||||
super(log, log.provider);
|
||||
const args = iface.decodeEventLog(fragment, log.data, log.topics);
|
||||
defineProperties<EventLog>(this, { args, fragment, interface: iface });
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the event.
|
||||
*/
|
||||
get eventName(): string { return this.fragment.name; }
|
||||
|
||||
/**
|
||||
* The signature of the event.
|
||||
*/
|
||||
get eventSignature(): string { return this.fragment.format(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractTransactionReceipt** includes the parsed logs from a
|
||||
* [[TransactionReceipt]].
|
||||
*/
|
||||
export class ContractTransactionReceipt extends TransactionReceipt {
|
||||
readonly #iface: Interface;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(iface: Interface, provider: Provider, tx: TransactionReceipt) {
|
||||
super(tx, provider);
|
||||
this.#iface = iface;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parsed logs for any [[Log]] which has a matching event in the
|
||||
* Contract ABI.
|
||||
*/
|
||||
get logs(): Array<EventLog | Log> {
|
||||
return super.logs.map((log) => {
|
||||
const fragment = log.topics.length ? this.#iface.getEvent(log.topics[0]): null;
|
||||
@ -51,14 +85,30 @@ export class ContractTransactionReceipt extends TransactionReceipt {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractTransactionResponse** will return a
|
||||
* [[ContractTransactionReceipt]] when waited on.
|
||||
*/
|
||||
export class ContractTransactionResponse extends TransactionResponse {
|
||||
readonly #iface: Interface;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(iface: Interface, provider: Provider, tx: TransactionResponse) {
|
||||
super(tx, provider);
|
||||
this.#iface = iface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves once this transaction has been mined and has
|
||||
* %%confirms%% blocks including it (default: ``1``) with an
|
||||
* optional %%timeout%%.
|
||||
*
|
||||
* This can resolve to ``null`` only if %%confirms%% is ``0``
|
||||
* and the transaction has not been mined, otherwise this will
|
||||
* wait until enough confirmations have completed.
|
||||
*/
|
||||
async wait(confirms?: number): Promise<null | ContractTransactionReceipt> {
|
||||
const receipt = await super.wait();
|
||||
if (receipt == null) { return null; }
|
||||
@ -66,43 +116,86 @@ export class ContractTransactionResponse extends TransactionResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractUnknownEventPayload** is included as the last parameter to
|
||||
* Contract Events when the event does not match any events in the ABI.
|
||||
*/
|
||||
export class ContractUnknownEventPayload extends EventPayload<ContractEventName> {
|
||||
/**
|
||||
* The log with no matching events.
|
||||
*/
|
||||
readonly log!: Log;
|
||||
|
||||
/**
|
||||
* @_event:
|
||||
*/
|
||||
constructor(contract: BaseContract, listener: null | Listener, filter: ContractEventName, log: Log) {
|
||||
super(contract, listener, filter);
|
||||
defineProperties<ContractUnknownEventPayload>(this, { log });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the block the event occured in.
|
||||
*/
|
||||
async getBlock(): Promise<Block> {
|
||||
return await this.log.getBlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction the event occured in.
|
||||
*/
|
||||
async getTransaction(): Promise<TransactionResponse> {
|
||||
return await this.log.getTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction receipt the event occured in.
|
||||
*/
|
||||
async getTransactionReceipt(): Promise<TransactionReceipt> {
|
||||
return await this.log.getTransactionReceipt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractEventPayload** is included as the last parameter to
|
||||
* Contract Events when the event is known.
|
||||
*/
|
||||
export class ContractEventPayload extends ContractUnknownEventPayload {
|
||||
|
||||
/**
|
||||
* The matching event.
|
||||
*/
|
||||
declare readonly fragment: EventFragment;
|
||||
|
||||
/**
|
||||
* The log, with parsed properties.
|
||||
*/
|
||||
declare readonly log: EventLog;
|
||||
|
||||
/**
|
||||
* The parsed arguments passed to the event by ``emit``.
|
||||
*/
|
||||
declare readonly args: Result;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(contract: BaseContract, listener: null | Listener, filter: ContractEventName, fragment: EventFragment, _log: Log) {
|
||||
super(contract, listener, filter, new EventLog(_log, contract.interface, fragment));
|
||||
const args = contract.interface.decodeEventLog(fragment, this.log.data, this.log.topics);
|
||||
defineProperties<ContractEventPayload>(this, { args, fragment });
|
||||
}
|
||||
|
||||
/**
|
||||
* The event name.
|
||||
*/
|
||||
get eventName(): string {
|
||||
return this.fragment.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event signature.
|
||||
*/
|
||||
get eventSignature(): string {
|
||||
return this.fragment.format();
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ export {
|
||||
export { SigningKey } from "./signing-key.js";
|
||||
export { Signature } from "./signature.js";
|
||||
|
||||
/**
|
||||
* Once called, prevents any future change to the underlying cryptographic
|
||||
* primitives using the ``.register`` feature for hooks.
|
||||
*/
|
||||
function lock(): void {
|
||||
computeHmac.lock();
|
||||
keccak256.lock();
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* About hashing here...
|
||||
* Utilities for common tasks involving hashing. Also see
|
||||
* [cryptographic hashing](about-crypto-hashing).
|
||||
*
|
||||
* @_section: api/hashing:Hashing Utilities [about-hashing]
|
||||
*/
|
||||
|
@ -21,16 +21,50 @@ const BN_0 = BigInt(0);
|
||||
const BN_1 = BigInt(1);
|
||||
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
|
||||
// @TODO: in v7, verifyingContract should be an AddressLike and use resolveAddress
|
||||
|
||||
/**
|
||||
* The domain for an [[link-eip-712]] payload.
|
||||
*/
|
||||
export interface TypedDataDomain {
|
||||
/**
|
||||
* The human-readable name of the signing domain.
|
||||
*/
|
||||
name?: null | string;
|
||||
|
||||
/**
|
||||
* The major version of the signing domain.
|
||||
*/
|
||||
version?: null | string;
|
||||
|
||||
/**
|
||||
* The chain ID of the signing domain.
|
||||
*/
|
||||
chainId?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The the address of the contract that will verify the signature.
|
||||
*/
|
||||
verifyingContract?: null | string;
|
||||
|
||||
/**
|
||||
* A salt used for purposes decided by the specific domain.
|
||||
*/
|
||||
salt?: null | BytesLike;
|
||||
};
|
||||
|
||||
/**
|
||||
* A specific field of a structured [[link-eip-712]] type.
|
||||
*/
|
||||
export interface TypedDataField {
|
||||
/**
|
||||
* The field name.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The type of the field.
|
||||
*/
|
||||
type: string;
|
||||
};
|
||||
|
||||
@ -147,10 +181,30 @@ function encodeType(name: string, fields: Array<TypedDataField>): string {
|
||||
return `${ name }(${ fields.map(({ name, type }) => (type + " " + name)).join(",") })`;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **TypedDataEncode** prepares and encodes [[link-eip-712]] payloads
|
||||
* for signed typed data.
|
||||
*
|
||||
* This is useful for those that wish to compute various components of a
|
||||
* typed data hash, primary types, or sub-components, but generally the
|
||||
* higher level [[Signer-signTypedData]] is more useful.
|
||||
*/
|
||||
export class TypedDataEncoder {
|
||||
/**
|
||||
* The primary type for the structured [[types]].
|
||||
*
|
||||
* This is derived automatically from the [[types]], since no
|
||||
* recursion is possible, once the DAG for the types is consturcted
|
||||
* internally, the primary type must be the only remaining type with
|
||||
* no parent nodes.
|
||||
*/
|
||||
readonly primaryType!: string;
|
||||
|
||||
readonly #types: string;
|
||||
|
||||
/**
|
||||
* The types.
|
||||
*/
|
||||
get types(): Record<string, Array<TypedDataField>> {
|
||||
return JSON.parse(this.#types);
|
||||
}
|
||||
@ -159,6 +213,13 @@ export class TypedDataEncoder {
|
||||
|
||||
readonly #encoderCache: Map<string, (value: any) => string>;
|
||||
|
||||
/**
|
||||
* Create a new **TypedDataEncoder** for %%types%%.
|
||||
*
|
||||
* This performs all necessary checking that types are valid and
|
||||
* do not violate the [[link-eip-712]] structural constraints as
|
||||
* well as computes the [[primaryType]].
|
||||
*/
|
||||
constructor(types: Record<string, Array<TypedDataField>>) {
|
||||
this.#types = JSON.stringify(types);
|
||||
this.#fullTypes = new Map();
|
||||
@ -241,6 +302,9 @@ export class TypedDataEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returnthe encoder for the specific %%type%%.
|
||||
*/
|
||||
getEncoder(type: string): (value: any) => string {
|
||||
let encoder = this.#encoderCache.get(type);
|
||||
if (!encoder) {
|
||||
@ -293,28 +357,46 @@ export class TypedDataEncoder {
|
||||
assertArgument(false, `unknown type: ${ type }`, "type", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full type for %%name%%.
|
||||
*/
|
||||
encodeType(name: string): string {
|
||||
const result = this.#fullTypes.get(name);
|
||||
assertArgument(result, `unknown type: ${ JSON.stringify(name) }`, "name", name);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encoded %%value%% for the %%type%%.
|
||||
*/
|
||||
encodeData(type: string, value: any): string {
|
||||
return this.getEncoder(type)(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash of %%value%% for the type of %%name%%.
|
||||
*/
|
||||
hashStruct(name: string, value: Record<string, any>): string {
|
||||
return keccak256(this.encodeData(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fulled encoded %%value%% for the [[types]].
|
||||
*/
|
||||
encode(value: Record<string, any>): string {
|
||||
return this.encodeData(this.primaryType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash of the fully encoded %%value%% for the [[types]].
|
||||
*/
|
||||
hash(value: Record<string, any>): string {
|
||||
return this.hashStruct(this.primaryType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
_visit(type: string, value: any, callback: (type: string, data: any) => any): any {
|
||||
// Basic encoder type (address, bool, uint256, etc)
|
||||
{
|
||||
@ -341,22 +423,41 @@ export class TypedDataEncoder {
|
||||
assertArgument(false, `unknown type: ${ type }`, "type", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call %%calback%% for each value in %%value%%, passing the type and
|
||||
* component within %%value%%.
|
||||
*
|
||||
* This is useful for replacing addresses or other transformation that
|
||||
* may be desired on each component, based on its type.
|
||||
*/
|
||||
visit(value: Record<string, any>, callback: (type: string, data: any) => any): any {
|
||||
return this._visit(this.primaryType, value, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new **TypedDataEncoder** for %%types%%.
|
||||
*/
|
||||
static from(types: Record<string, Array<TypedDataField>>): TypedDataEncoder {
|
||||
return new TypedDataEncoder(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary type for %%types%%.
|
||||
*/
|
||||
static getPrimaryType(types: Record<string, Array<TypedDataField>>): string {
|
||||
return TypedDataEncoder.from(types).primaryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hashed struct for %%value%% using %%types%% and %%name%%.
|
||||
*/
|
||||
static hashStruct(name: string, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string {
|
||||
return TypedDataEncoder.from(types).hashStruct(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the domain hash for %%domain%%.
|
||||
*/
|
||||
static hashDomain(domain: TypedDataDomain): string {
|
||||
const domainFields: Array<TypedDataField> = [ ];
|
||||
for (const name in domain) {
|
||||
@ -373,6 +474,9 @@ export class TypedDataEncoder {
|
||||
return TypedDataEncoder.hashStruct("EIP712Domain", { EIP712Domain: domainFields }, domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fully encoded [[link-eip-712]] %%value%% for %%types%% with %%domain%%.
|
||||
*/
|
||||
static encode(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string {
|
||||
return concat([
|
||||
"0x1901",
|
||||
@ -381,11 +485,18 @@ export class TypedDataEncoder {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash of the fully encoded [[link-eip-712]] %%value%% for %%types%% with %%domain%%.
|
||||
*/
|
||||
static hash(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string {
|
||||
return keccak256(TypedDataEncoder.encode(domain, types, value));
|
||||
}
|
||||
|
||||
// Replaces all address types with ENS names with their looked up address
|
||||
/**
|
||||
* Resolves to the value from resolving all addresses in %%value%% for
|
||||
* %%types%% and the %%domain%%.
|
||||
*/
|
||||
static async resolveNames(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>, resolveName: (name: string) => Promise<string>): Promise<{ domain: TypedDataDomain, value: any }> {
|
||||
// Make a copy to isolate it from the object passed in
|
||||
domain = Object.assign({ }, domain);
|
||||
@ -435,6 +546,10 @@ export class TypedDataEncoder {
|
||||
return { domain, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON-encoded payload expected by nodes which implement
|
||||
* the JSON-RPC [[link-eip-712]] method.
|
||||
*/
|
||||
static getPayload(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): any {
|
||||
// Validate the domain fields
|
||||
TypedDataEncoder.hashDomain(domain);
|
||||
|
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* About Subclassing the Provider...
|
||||
* The available providers should suffice for most developers purposes,
|
||||
* but the [[AbstractProvider]] class has many features which enable
|
||||
* sub-classing it for specific purposes.
|
||||
*
|
||||
* @_section: api/providers/abstract-provider: Subclassing Provider [abstract-provider]
|
||||
*/
|
||||
@ -86,6 +88,10 @@ function getTag(prefix: string, value: any): string {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The types of additional event values that can be emitted for the
|
||||
* ``"debug"`` event.
|
||||
*/
|
||||
export type DebugEventAbstractProvider = {
|
||||
action: "sendCcipReadFetchRequest",
|
||||
request: FetchRequest
|
||||
@ -113,7 +119,12 @@ export type DebugEventAbstractProvider = {
|
||||
};
|
||||
|
||||
|
||||
// Only sub-classes overriding the _getSubscription method will care about this
|
||||
/**
|
||||
* The value passed to the [[AbstractProvider-_getSubscriber]] method.
|
||||
*
|
||||
* Only developers sub-classing [[AbstractProvider[[ will care about this,
|
||||
* if they are modifying a low-level feature of how subscriptions operate.
|
||||
*/
|
||||
export type Subscription = {
|
||||
type: "block" | "close" | "debug" | "error" | "network" | "pending",
|
||||
tag: string
|
||||
@ -131,22 +142,59 @@ export type Subscription = {
|
||||
filter: OrphanFilter
|
||||
};
|
||||
|
||||
/**
|
||||
* A **Subscriber** manages a subscription.
|
||||
*
|
||||
* Only developers sub-classing [[AbstractProvider[[ will care about this,
|
||||
* if they are modifying a low-level feature of how subscriptions operate.
|
||||
*/
|
||||
export interface Subscriber {
|
||||
/**
|
||||
* Called initially when a subscriber is added the first time.
|
||||
*/
|
||||
start(): void;
|
||||
|
||||
/**
|
||||
* Called when there are no more subscribers to the event.
|
||||
*/
|
||||
stop(): void;
|
||||
|
||||
/**
|
||||
* Called when the subscription should pause.
|
||||
*
|
||||
* If %%dropWhilePaused%%, events that occur while paused should not
|
||||
* be emitted [[resume]].
|
||||
*/
|
||||
pause(dropWhilePaused?: boolean): void;
|
||||
|
||||
/**
|
||||
* Resume a paused subscriber.
|
||||
*/
|
||||
resume(): void;
|
||||
|
||||
// Subscribers which use polling should implement this to allow
|
||||
// Providers the ability to update underlying polling intervals
|
||||
// If not supported, accessing this property should return undefined
|
||||
/**
|
||||
* The frequency (in ms) to poll for events, if polling is used by
|
||||
* the subscriber.
|
||||
*
|
||||
* For non-polling subscribers, this must return ``undefined``.
|
||||
*/
|
||||
pollingInterval?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* An **UnmanagedSubscriber** is useful for events which do not require
|
||||
* any additional management, such as ``"debug"`` which only requires
|
||||
* emit in synchronous event loop triggered calls.
|
||||
*/
|
||||
export class UnmanagedSubscriber implements Subscriber {
|
||||
/**
|
||||
* The name fof the event.
|
||||
*/
|
||||
name!: string;
|
||||
|
||||
/**
|
||||
* Create a new UnmanagedSubscriber with %%name%%.
|
||||
*/
|
||||
constructor(name: string) { defineProperties<UnmanagedSubscriber>(this, { name }); }
|
||||
|
||||
start(): void { }
|
||||
@ -247,11 +295,26 @@ async function getSubscription(_event: ProviderEvent, provider: AbstractProvider
|
||||
|
||||
function getTime(): number { return (new Date()).getTime(); }
|
||||
|
||||
/**
|
||||
* An **AbstractPlugin** is used to provide additional internal services
|
||||
* to an [[AbstractProvider]] without adding backwards-incompatible changes
|
||||
* to method signatures or other internal and complex logic.
|
||||
*/
|
||||
export interface AbstractProviderPlugin {
|
||||
/**
|
||||
* The reverse domain notation of the plugin.
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the plugin, connected to %%provider%%.
|
||||
*/
|
||||
connect(provider: AbstractProvider): AbstractProviderPlugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* A normalized filter used for [[PerformActionRequest]] objects.
|
||||
*/
|
||||
export type PerformActionFilter = {
|
||||
address?: string | Array<string>;
|
||||
topics?: Array<null | string | Array<string>>;
|
||||
@ -263,11 +326,25 @@ export type PerformActionFilter = {
|
||||
blockHash?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A normalized transactions used for [[PerformActionRequest]] objects.
|
||||
*/
|
||||
export interface PerformActionTransaction extends PreparedTransactionRequest {
|
||||
/**
|
||||
* The ``to`` address of the transaction.
|
||||
*/
|
||||
to?: string;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The [[AbstractProvider]] methods will normalize all values and pass this
|
||||
* type to [[AbstractProvider-_perform]].
|
||||
*/
|
||||
export type PerformActionRequest = {
|
||||
method: "broadcastTransaction",
|
||||
signedTransaction: string
|
||||
@ -330,7 +407,12 @@ type CcipArgs = {
|
||||
errorArgs: Array<any>
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An **AbstractProvider** provides a base class for other sub-classes to
|
||||
* implement the [[Provider]] API by normalizing input arguments and
|
||||
* formatting output results as well as tracking events for consistent
|
||||
* behaviour on an eventually-consistent network.
|
||||
*/
|
||||
export class AbstractProvider implements Provider {
|
||||
|
||||
#subs: Map<string, Sub>;
|
||||
@ -352,8 +434,11 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
#disableCcipRead: boolean;
|
||||
|
||||
// @TODO: This should be a () => Promise<Network> so network can be
|
||||
// done when needed; or rely entirely on _detectNetwork?
|
||||
/**
|
||||
* Create a new **AbstractProvider** connected to %%network%%, or
|
||||
* use the various network detection capabilities to discover the
|
||||
* [[Network]] if necessary.
|
||||
*/
|
||||
constructor(_network?: "any" | Networkish) {
|
||||
|
||||
if (_network === "any") {
|
||||
@ -383,12 +468,22 @@ export class AbstractProvider implements Provider {
|
||||
this.#disableCcipRead = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``this``, to allow an **AbstractProvider** to implement
|
||||
* the [[ContractRunner]] interface.
|
||||
*/
|
||||
get provider(): this { return this; }
|
||||
|
||||
/**
|
||||
* Returns all the registered plug-ins.
|
||||
*/
|
||||
get plugins(): Array<AbstractProviderPlugin> {
|
||||
return Array.from(this.#plugins.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a new plug-in.
|
||||
*/
|
||||
attachPlugin(plugin: AbstractProviderPlugin): this {
|
||||
if (this.#plugins.get(plugin.name)) {
|
||||
throw new Error(`cannot replace existing plugin: ${ plugin.name } `);
|
||||
@ -397,10 +492,17 @@ export class AbstractProvider implements Provider {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plugin by name.
|
||||
*/
|
||||
getPlugin<T extends AbstractProviderPlugin = AbstractProviderPlugin>(name: string): null | T {
|
||||
return <T>(this.#plugins.get(name)) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent any CCIP-read operation, regardless of whether requested
|
||||
* in a [[call]] using ``enableCcipRead``.
|
||||
*/
|
||||
get disableCcipRead(): boolean { return this.#disableCcipRead; }
|
||||
set disableCcipRead(value: boolean) { this.#disableCcipRead = !!value; }
|
||||
|
||||
@ -424,6 +526,9 @@ export class AbstractProvider implements Provider {
|
||||
return await perform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the data for executing the CCIP-read operations.
|
||||
*/
|
||||
async ccipReadFetch(tx: PerformActionTransaction, calldata: string, urls: Array<string>): Promise<null | string> {
|
||||
if (this.disableCcipRead || urls.length === 0 || tx.to == null) { return null; }
|
||||
|
||||
@ -479,30 +584,60 @@ export class AbstractProvider implements Provider {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the opportunity for a sub-class to wrap a block before
|
||||
* returning it, to add additional properties or an alternate
|
||||
* sub-class of [[Block]].
|
||||
*/
|
||||
_wrapBlock(value: BlockParams, network: Network): Block {
|
||||
return new Block(formatBlock(value), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the opportunity for a sub-class to wrap a log before
|
||||
* returning it, to add additional properties or an alternate
|
||||
* sub-class of [[Log]].
|
||||
*/
|
||||
_wrapLog(value: LogParams, network: Network): Log {
|
||||
return new Log(formatLog(value), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the opportunity for a sub-class to wrap a transaction
|
||||
* receipt before returning it, to add additional properties or an
|
||||
* alternate sub-class of [[TransactionReceipt]].
|
||||
*/
|
||||
_wrapTransactionReceipt(value: TransactionReceiptParams, network: Network): TransactionReceipt {
|
||||
return new TransactionReceipt(formatTransactionReceipt(value), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the opportunity for a sub-class to wrap a transaction
|
||||
* response before returning it, to add additional properties or an
|
||||
* alternate sub-class of [[TransactionResponse]].
|
||||
*/
|
||||
_wrapTransactionResponse(tx: TransactionResponseParams, network: Network): TransactionResponse {
|
||||
return new TransactionResponse(formatTransactionResponse(tx), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the Network, forcing a network detection using whatever
|
||||
* technique the sub-class requires.
|
||||
*
|
||||
* Sub-classes **must** override this.
|
||||
*/
|
||||
_detectNetwork(): Promise<Network> {
|
||||
assert(false, "sub-classes must implement this", "UNSUPPORTED_OPERATION", {
|
||||
operation: "_detectNetwork"
|
||||
});
|
||||
}
|
||||
|
||||
// Sub-classes should override this and handle PerformActionRequest requests, calling
|
||||
// the super for any unhandled actions.
|
||||
/**
|
||||
* Sub-classes should use this to perform all built-in operations. All
|
||||
* methods sanitizes and normalizes the values passed into this.
|
||||
*
|
||||
* Sub-classes **must** override this.
|
||||
*/
|
||||
async _perform<T = any>(req: PerformActionRequest): Promise<T> {
|
||||
assert(false, `unsupported method: ${ req.method }`, "UNSUPPORTED_OPERATION", {
|
||||
operation: req.method,
|
||||
@ -511,16 +646,26 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
|
||||
// State
|
||||
|
||||
async getBlockNumber(): Promise<number> {
|
||||
const blockNumber = getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
|
||||
if (this.#lastBlockNumber >= 0) { this.#lastBlockNumber = blockNumber; }
|
||||
return blockNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or resolves to the address for %%address%%, resolving ENS
|
||||
* names and [[Addressable]] objects and returning if already an
|
||||
* address.
|
||||
*/
|
||||
_getAddress(address: AddressLike): string | Promise<string> {
|
||||
return resolveAddress(address, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or resolves to a valid block tag for %%blockTag%%, resolving
|
||||
* negative values and returning if already a valid block tag.
|
||||
*/
|
||||
_getBlockTag(blockTag?: BlockTag): string | Promise<string> {
|
||||
if (blockTag == null) { return "latest"; }
|
||||
|
||||
@ -550,6 +695,11 @@ export class AbstractProvider implements Provider {
|
||||
assertArgument(false, "invalid blockTag", "blockTag", blockTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or resolves to a filter for %%filter%%, resolving any ENS
|
||||
* names or [[Addressable]] object and returning if already a valid
|
||||
* filter.
|
||||
*/
|
||||
_getFilter(filter: Filter | FilterByBlockHash): PerformActionFilter | Promise<PerformActionFilter> {
|
||||
|
||||
// Create a canonical representation of the topics
|
||||
@ -619,6 +769,11 @@ export class AbstractProvider implements Provider {
|
||||
return resolve(<Array<string>>address, fromBlock, toBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns or resovles to a transaction for %%request%%, resolving
|
||||
* any ENS names or [[Addressable]] and returning if already a valid
|
||||
* transaction.
|
||||
*/
|
||||
_getTransactionRequest(_request: TransactionRequest): PerformActionTransaction | Promise<PerformActionTransaction> {
|
||||
const request = <PerformActionTransaction>copyRequest(_request);
|
||||
|
||||
@ -1059,6 +1214,9 @@ export class AbstractProvider implements Provider {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a timer created using the [[_setTimeout]] method.
|
||||
*/
|
||||
_clearTimeout(timerId: number): void {
|
||||
const timer = this.#timers.get(timerId);
|
||||
if (!timer) { return; }
|
||||
@ -1066,6 +1224,14 @@ export class AbstractProvider implements Provider {
|
||||
this.#timers.delete(timerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a timer that will execute %%func%% after at least %%timeout%%
|
||||
* (in ms). If %%timeout%% is unspecified, then %%func%% will execute
|
||||
* in the next event loop.
|
||||
*
|
||||
* [Pausing](AbstractProvider-paused) the provider will pause any
|
||||
* associated timers.
|
||||
*/
|
||||
_setTimeout(_func: () => void, timeout?: number): number {
|
||||
if (timeout == null) { timeout = 0; }
|
||||
const timerId = this.#nextTimer++;
|
||||
@ -1084,14 +1250,19 @@ export class AbstractProvider implements Provider {
|
||||
return timerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform %%func%% on each subscriber.
|
||||
*/
|
||||
_forEachSubscriber(func: (s: Subscriber) => void): void {
|
||||
for (const sub of this.#subs.values()) {
|
||||
func(sub.subscriber);
|
||||
}
|
||||
}
|
||||
|
||||
// Event API; sub-classes should override this; any supported
|
||||
// event filter will have been munged into an EventFilter
|
||||
/**
|
||||
* Sub-classes may override this to customize subscription
|
||||
* implementations.
|
||||
*/
|
||||
_getSubscriber(sub: Subscription): Subscriber {
|
||||
switch (sub.type) {
|
||||
case "debug":
|
||||
@ -1111,6 +1282,15 @@ export class AbstractProvider implements Provider {
|
||||
throw new Error(`unsupported event: ${ sub.type }`);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a [[Subscriber]] fails and needs to replace itself, this
|
||||
* method may be used.
|
||||
*
|
||||
* For example, this is used for providers when using the
|
||||
* ``eth_getFilterChanges`` method, which can return null if state
|
||||
* filters are not supported by the backend, allowing the Subscriber
|
||||
* to swap in a [[PollingEventSubscriber]].
|
||||
*/
|
||||
_recoverSubscriber(oldSub: Subscriber, newSub: Subscriber): void {
|
||||
for (const sub of this.#subs.values()) {
|
||||
if (sub.subscriber === oldSub) {
|
||||
@ -1265,8 +1445,12 @@ export class AbstractProvider implements Provider {
|
||||
return this.off(event, listener);
|
||||
}
|
||||
|
||||
// Sub-classes should override this to shutdown any sockets, etc.
|
||||
// but MUST call this super.shutdown.
|
||||
/**
|
||||
* Sub-classes may use this to shutdown any sockets or release their
|
||||
* resources.
|
||||
*
|
||||
* Sub-classes **must** call ``super.destroy()``.
|
||||
*/
|
||||
destroy(): void {
|
||||
// Stop all listeners
|
||||
this.removeAllListeners();
|
||||
@ -1277,6 +1461,17 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the provider is currently paused.
|
||||
*
|
||||
* A paused provider will not emit any events, and generally should
|
||||
* not make any requests to the network, but that is up to sub-classes
|
||||
* to manage.
|
||||
*
|
||||
* Setting ``paused = true`` is identical to calling ``.pause(false)``,
|
||||
* which will buffer any events that occur while paused until the
|
||||
* provider is unpaused.
|
||||
*/
|
||||
get paused(): boolean { return (this.#pausedState != null); }
|
||||
set paused(pause: boolean) {
|
||||
if (!!pause === this.paused) { return; }
|
||||
@ -1288,6 +1483,11 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the provider. If %%dropWhilePaused%%, any events that occur
|
||||
* while paused are dropped, otherwise all events will be emitted once
|
||||
* the provider is unpaused.
|
||||
*/
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
this.#lastBlockNumber = -1;
|
||||
|
||||
@ -1310,6 +1510,9 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume the provider.
|
||||
*/
|
||||
resume(): void {
|
||||
if (this.#pausedState == null) { return; }
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* About Abstract Signer and subclassing
|
||||
* Generally the [[Wallet]] and [[JsonRpcSigner]] and their sub-classes
|
||||
* are sufficent for most developers, but this is provided to
|
||||
* fascilitate more complex Signers.
|
||||
*
|
||||
* @_section: api/providers/abstract-signer: Subclassing Signer [abstract-signer]
|
||||
*/
|
||||
@ -49,14 +51,36 @@ async function populate(signer: AbstractSigner, tx: TransactionRequest): Promise
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An **AbstractSigner** includes most of teh functionality required
|
||||
* to get a [[Signer]] working as expected, but requires a few
|
||||
* Signer-specific methods be overridden.
|
||||
*
|
||||
*/
|
||||
export abstract class AbstractSigner<P extends null | Provider = null | Provider> implements Signer {
|
||||
/**
|
||||
* The provider this signer is connected to.
|
||||
*/
|
||||
readonly provider!: P;
|
||||
|
||||
/**
|
||||
* Creates a new Signer connected to %%provider%%.
|
||||
*/
|
||||
constructor(provider?: P) {
|
||||
defineProperties<AbstractSigner>(this, { provider: (provider || null) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the Signer address.
|
||||
*/
|
||||
abstract getAddress(): Promise<string>;
|
||||
|
||||
/**
|
||||
* Returns the signer connected to %%provider%%.
|
||||
*
|
||||
* This may throw, for example, a Signer connected over a Socket or
|
||||
* to a specific instance of a node may not be transferrable.
|
||||
*/
|
||||
abstract connect(provider: null | Provider): Signer;
|
||||
|
||||
async getNonce(blockTag?: BlockTag): Promise<number> {
|
||||
@ -216,9 +240,24 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
|
||||
abstract signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **VoidSigner** is a class deisgned to allow an address to be used
|
||||
* in any API which accepts a Signer, but for which there are no
|
||||
* credentials available to perform any actual signing.
|
||||
*
|
||||
* This for example allow impersonating an account for the purpose of
|
||||
* static calls or estimating gas, but does not allow sending transactions.
|
||||
*/
|
||||
export class VoidSigner extends AbstractSigner {
|
||||
/**
|
||||
* The signer address.
|
||||
*/
|
||||
readonly address!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **VoidSigner** with %%address%% attached to
|
||||
* %%provider%%.
|
||||
*/
|
||||
constructor(address: string, provider?: null | Provider) {
|
||||
super(provider);
|
||||
defineProperties<VoidSigner>(this, { address });
|
||||
|
@ -2,20 +2,41 @@ import type {
|
||||
Provider, TransactionRequest, TransactionResponse
|
||||
} from "./provider.js";
|
||||
|
||||
// The object that will be used to run Contracts. The Signer and Provider
|
||||
// both adhere to this, but other types of objects may wish to as well.
|
||||
/**
|
||||
* A **ContractRunner** is a generic interface which defines an object
|
||||
* capable of interacting with a Contract on the network.
|
||||
*
|
||||
* The more operations supported, the more utility it is capable of.
|
||||
*
|
||||
* The most common ContractRunners are [Providers](Provider) which enable
|
||||
* read-only access and [Signers](Signer) which enable write-access.
|
||||
*/
|
||||
export interface ContractRunner {
|
||||
/**
|
||||
* The provider used for necessary state querying operations.
|
||||
*
|
||||
* This can also point to the **ContractRunner** itself, in the
|
||||
* case of an [[AbstractProvider]].
|
||||
*/
|
||||
provider: null | Provider;
|
||||
|
||||
// Required to estimate gas; usually a Signer or Provider
|
||||
/**
|
||||
* Required to estimate gas.
|
||||
*/
|
||||
estimateGas?: (tx: TransactionRequest) => Promise<bigint>;
|
||||
|
||||
// Required for pure, view or static calls to contracts; usually a Signer or Provider
|
||||
/**
|
||||
* Required for pure, view or static calls to contracts.
|
||||
*/
|
||||
call?: (tx: TransactionRequest) => Promise<string>;
|
||||
|
||||
// Required to support ENS names; usually a Signer or Provider
|
||||
/**
|
||||
* Required to support ENS names
|
||||
*/
|
||||
resolveName?: (name: string) => Promise<null | string>;
|
||||
|
||||
// Required for mutating calls; usually a Signer
|
||||
/**
|
||||
* Required for state mutating calls
|
||||
*/
|
||||
sendTransaction?: (tx: TransactionRequest) => Promise<TransactionResponse>;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* About ENS Resolver
|
||||
* ENS is a service which allows easy-to-remember names to map to
|
||||
* network addresses.
|
||||
*
|
||||
* @_section: api/providers/ens-resolver:ENS Resolver [about-ens-rsolver]
|
||||
*/
|
||||
@ -50,7 +51,14 @@ export type AvatarLinkageType = "name" | "avatar" | "!avatar" | "url" | "data" |
|
||||
* An individual record for each step during avatar resolution.
|
||||
*/
|
||||
export interface AvatarLinkage {
|
||||
/**
|
||||
* The type of linkage.
|
||||
*/
|
||||
type: AvatarLinkageType;
|
||||
|
||||
/**
|
||||
* The linkage value.
|
||||
*/
|
||||
value: string;
|
||||
};
|
||||
|
||||
@ -63,7 +71,17 @@ export interface AvatarLinkage {
|
||||
* each completed step during avatar resolution.
|
||||
*/
|
||||
export interface AvatarResult {
|
||||
/**
|
||||
* How the [[url]] was arrived at, resolving the many steps required
|
||||
* for an avatar URL.
|
||||
*/
|
||||
linkage: Array<AvatarLinkage>;
|
||||
|
||||
/**
|
||||
* The avatar URL or null if the avatar was not set, or there was
|
||||
* an issue during validation (such as the address not owning the
|
||||
* avatar or a metadata error).
|
||||
*/
|
||||
url: null | string;
|
||||
};
|
||||
|
||||
@ -71,8 +89,14 @@ export interface AvatarResult {
|
||||
* A provider plugin super-class for processing multicoin address types.
|
||||
*/
|
||||
export abstract class MulticoinProviderPlugin implements AbstractProviderPlugin {
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
readonly name!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **MulticoinProviderPluing** for %%name%%.
|
||||
*/
|
||||
constructor(name: string) {
|
||||
defineProperties<MulticoinProviderPlugin>(this, { name });
|
||||
}
|
||||
@ -81,14 +105,23 @@ export abstract class MulticoinProviderPlugin implements AbstractProviderPlugin
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` if %%coinType%% is supported by this plugin.
|
||||
*/
|
||||
supportsCoinType(coinType: number): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resovles to the encoded %%address%% for %%coinType%%.
|
||||
*/
|
||||
async encodeAddress(coinType: number, address: string): Promise<string> {
|
||||
throw new Error("unsupported coin");
|
||||
}
|
||||
|
||||
/**
|
||||
* Resovles to the decoded %%data%% for %%coinType%%.
|
||||
*/
|
||||
async decodeAddress(coinType: number, data: BytesLike): Promise<string> {
|
||||
throw new Error("unsupported coin");
|
||||
}
|
||||
@ -97,9 +130,14 @@ export abstract class MulticoinProviderPlugin implements AbstractProviderPlugin
|
||||
const BasicMulticoinPluginId = "org.ethers.plugins.provider.BasicMulticoin";
|
||||
|
||||
/**
|
||||
* A basic multicoin provider plugin.
|
||||
* A **BasicMulticoinProviderPlugin** provides service for common
|
||||
* coin types, which do not require additional libraries to encode or
|
||||
* decode.
|
||||
*/
|
||||
export class BasicMulticoinProviderPlugin extends MulticoinProviderPlugin {
|
||||
/**
|
||||
* Creates a new **BasicMulticoinProviderPlugin**.
|
||||
*/
|
||||
constructor() {
|
||||
super(BasicMulticoinPluginId);
|
||||
}
|
||||
|
@ -7,86 +7,78 @@
|
||||
import type { Signature } from "../crypto/index.js";
|
||||
import type { AccessList } from "../transaction/index.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
|
||||
|
||||
/**
|
||||
* a **BlockParams** encodes the minimal required properties for a
|
||||
* formatted block.
|
||||
*/
|
||||
export interface BlockParams {
|
||||
/**
|
||||
* The block hash.
|
||||
*/
|
||||
hash?: null | string;
|
||||
|
||||
/**
|
||||
* The block number.
|
||||
*/
|
||||
number: number;
|
||||
|
||||
/**
|
||||
* The timestamp for this block, which is the number of seconds
|
||||
* since epoch that this block was included.
|
||||
*/
|
||||
timestamp: number;
|
||||
|
||||
/**
|
||||
* The hash of the previous block in the blockchain. The genesis block
|
||||
* has the parentHash of the [[ZeroHash]].
|
||||
*/
|
||||
parentHash: string;
|
||||
|
||||
/**
|
||||
* A random sequence provided during the mining process for
|
||||
* proof-of-work networks.
|
||||
*/
|
||||
nonce: string;
|
||||
|
||||
/**
|
||||
* For proof-of-work networks, the difficulty target is used to
|
||||
* adjust the difficulty in mining to ensure a expected block rate.
|
||||
*/
|
||||
difficulty: bigint;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas a block can consume.
|
||||
*/
|
||||
gasLimit: bigint;
|
||||
|
||||
/**
|
||||
* The amount of gas a block consumed.
|
||||
*/
|
||||
gasUsed: bigint;
|
||||
|
||||
/**
|
||||
* The miner (or author) of a block.
|
||||
*/
|
||||
miner: string;
|
||||
|
||||
/**
|
||||
* Additional data the miner choose to include.
|
||||
*/
|
||||
extraData: string;
|
||||
|
||||
/**
|
||||
* The protocol-defined base fee per gas in an [[link-eip-1559]]
|
||||
* block.
|
||||
*/
|
||||
baseFeePerGas: null | bigint;
|
||||
|
||||
/**
|
||||
* The list of transactions in the block.
|
||||
*/
|
||||
transactions: ReadonlyArray<string | TransactionResponseParams>;
|
||||
};
|
||||
|
||||
@ -94,19 +86,57 @@ export interface BlockParams {
|
||||
//////////////////////
|
||||
// Log
|
||||
|
||||
/**
|
||||
* a **LogParams** encodes the minimal required properties for a
|
||||
* formatted log.
|
||||
*/
|
||||
export interface LogParams {
|
||||
/**
|
||||
* The transaction hash for the transaxction the log occurred in.
|
||||
*/
|
||||
transactionHash: string;
|
||||
|
||||
/**
|
||||
* The block hash of the block that included the transaction for this
|
||||
* log.
|
||||
*/
|
||||
blockHash: string;
|
||||
|
||||
/**
|
||||
* The block number of the block that included the transaction for this
|
||||
* log.
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
/**
|
||||
* Whether this log was removed due to the transaction it was included
|
||||
* in being removed dur to an orphaned block.
|
||||
*/
|
||||
removed: boolean;
|
||||
|
||||
/**
|
||||
* The address of the contract that emitted this log.
|
||||
*/
|
||||
address: string;
|
||||
|
||||
/**
|
||||
* The data emitted with this log.
|
||||
*/
|
||||
data: string;
|
||||
|
||||
/**
|
||||
* The topics emitted with this log.
|
||||
*/
|
||||
topics: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The index of this log.
|
||||
*/
|
||||
index: number;
|
||||
|
||||
/**
|
||||
* The transaction index of this log.
|
||||
*/
|
||||
transactionIndex: number;
|
||||
}
|
||||
|
||||
@ -114,28 +144,99 @@ export interface LogParams {
|
||||
//////////////////////
|
||||
// Transaction Receipt
|
||||
|
||||
/**
|
||||
* a **TransactionReceiptParams** encodes the minimal required properties
|
||||
* for a formatted transaction receipt.
|
||||
*/
|
||||
export interface TransactionReceiptParams {
|
||||
/**
|
||||
* The target of the transaction. If null, the transaction was trying
|
||||
* to deploy a transaction with the ``data`` as the initi=code.
|
||||
*/
|
||||
to: null | string;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from: string;
|
||||
|
||||
/**
|
||||
* If the transaction was directly deploying a contract, the [[to]]
|
||||
* will be null, the ``data`` will be initcode and if successful, this
|
||||
* will be the address of the contract deployed.
|
||||
*/
|
||||
contractAddress: null | string;
|
||||
|
||||
/**
|
||||
* The transaction hash.
|
||||
*/
|
||||
hash: string;
|
||||
|
||||
/**
|
||||
* The transaction index.
|
||||
*/
|
||||
index: number;
|
||||
|
||||
/**
|
||||
* The block hash of the block that included this transaction.
|
||||
*/
|
||||
blockHash: string;
|
||||
|
||||
/**
|
||||
* The block number of the block that included this transaction.
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
/**
|
||||
* The bloom filter for the logs emitted during execution of this
|
||||
* transaction.
|
||||
*/
|
||||
logsBloom: string;
|
||||
|
||||
/**
|
||||
* The logs emitted during the execution of this transaction.
|
||||
*/
|
||||
logs: ReadonlyArray<LogParams>;
|
||||
|
||||
/**
|
||||
* The amount of gas consumed executing this transaciton.
|
||||
*/
|
||||
gasUsed: bigint;
|
||||
|
||||
/**
|
||||
* The total amount of gas consumed during the entire block up to
|
||||
* and including this transaction.
|
||||
*/
|
||||
cumulativeGasUsed: bigint;
|
||||
|
||||
/**
|
||||
* The actual gas price per gas charged for this transaction.
|
||||
*/
|
||||
gasPrice?: null | bigint;
|
||||
|
||||
/**
|
||||
* The actual gas price per gas charged for this transaction.
|
||||
*/
|
||||
effectiveGasPrice?: null | bigint;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2718]] envelope type.
|
||||
*/
|
||||
type: number;
|
||||
//byzantium: boolean;
|
||||
|
||||
/**
|
||||
* The status of the transaction execution. If ``1`` then the
|
||||
* the transaction returned success, if ``0`` then the transaction
|
||||
* was reverted. For pre-byzantium blocks, this is usually null, but
|
||||
* some nodes may have backfilled this data.
|
||||
*/
|
||||
status: null | number;
|
||||
|
||||
/**
|
||||
* The root of this transaction in a pre-bazatium block. In
|
||||
* post-byzantium blocks this is null.
|
||||
*/
|
||||
root: null | string;
|
||||
}
|
||||
|
||||
@ -158,33 +259,97 @@ export interface ByzantiumTransactionReceipt {
|
||||
//////////////////////
|
||||
// Transaction Response
|
||||
|
||||
/**
|
||||
* a **TransactionResponseParams** encodes the minimal required properties
|
||||
* for a formatted transaction response.
|
||||
*/
|
||||
export interface TransactionResponseParams {
|
||||
/**
|
||||
* The block number of the block that included this transaction.
|
||||
*/
|
||||
blockNumber: null | number;
|
||||
|
||||
/**
|
||||
* The block hash of the block that included this transaction.
|
||||
*/
|
||||
blockHash: null | string;
|
||||
|
||||
/**
|
||||
* The transaction hash.
|
||||
*/
|
||||
hash: string;
|
||||
|
||||
/**
|
||||
* The transaction index.
|
||||
*/
|
||||
index: number;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2718]] transaction type.
|
||||
*/
|
||||
type: number;
|
||||
|
||||
/**
|
||||
* The target of the transaction. If ``null``, the ``data`` is initcode
|
||||
* and this transaction is a deployment transaction.
|
||||
*/
|
||||
to: null | string;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from: string;
|
||||
|
||||
/**
|
||||
* The nonce of the transaction, used for replay protection.
|
||||
*/
|
||||
nonce: number;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas this transaction is authorized to consume.
|
||||
*/
|
||||
gasLimit: bigint;
|
||||
|
||||
/**
|
||||
* For legacy transactions, this is the gas price per gas to pay.
|
||||
*/
|
||||
gasPrice: bigint;
|
||||
|
||||
/**
|
||||
* For [[link-eip-1559]] transactions, this is the maximum priority
|
||||
* fee to allow a producer to claim.
|
||||
*/
|
||||
maxPriorityFeePerGas: null | bigint;
|
||||
|
||||
/**
|
||||
* For [[link-eip-1559]] transactions, this is the maximum fee that
|
||||
* will be paid.
|
||||
*/
|
||||
maxFeePerGas: null | bigint;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data: string;
|
||||
|
||||
/**
|
||||
* The transaction value (in wei).
|
||||
*/
|
||||
value: bigint;
|
||||
|
||||
/**
|
||||
* The chain ID this transaction is valid on.
|
||||
*/
|
||||
chainId: bigint;
|
||||
|
||||
/**
|
||||
* The signature of the transaction.
|
||||
*/
|
||||
signature: Signature;
|
||||
|
||||
/**
|
||||
* The transaction access list.
|
||||
*/
|
||||
accessList: null | AccessList;
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,16 @@
|
||||
/**
|
||||
* About providers.
|
||||
* A **Provider** provides a connection to the blockchain, whch can be
|
||||
* used to query its current state, simulate execution and send transactions
|
||||
* to update the state.
|
||||
*
|
||||
* It is one of the most fundamental components of interacting with a
|
||||
* blockchain application, and there are many ways to connect, such as over
|
||||
* HTTP, WebSockets or injected providers such as [MetaMask](link-metamask).
|
||||
*
|
||||
* @_section: api/providers:Providers [about-providers]
|
||||
*/
|
||||
|
||||
|
||||
|
||||
export {
|
||||
AbstractProvider, UnmanagedSubscriber
|
||||
} from "./abstract-provider.js";
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* About networks
|
||||
* A **Network** encapsulates the various properties required to
|
||||
* interact with a specific chain.
|
||||
*
|
||||
* @_subsection: api/providers:Networks [networks]
|
||||
*/
|
||||
@ -91,18 +92,28 @@ const Networks: Map<string | bigint, () => Network> = new Map();
|
||||
|
||||
// @TODO: Add a _ethersNetworkObj variable to better detect network ovjects
|
||||
|
||||
/**
|
||||
* A **Network** provides access to a chain's properties and allows
|
||||
* for plug-ins to extend functionality.
|
||||
*/
|
||||
export class Network {
|
||||
#name: string;
|
||||
#chainId: bigint;
|
||||
|
||||
#plugins: Map<string, NetworkPlugin>;
|
||||
|
||||
/**
|
||||
* Creates a new **Network** for %%name%% and %%chainId%%.
|
||||
*/
|
||||
constructor(name: string, chainId: BigNumberish) {
|
||||
this.#name = name;
|
||||
this.#chainId = getBigInt(chainId);
|
||||
this.#plugins = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON-compatible representation of a Network.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return { name: this.name, chainId: String(this.chainId) };
|
||||
}
|
||||
|
@ -10,13 +10,28 @@ import type {
|
||||
|
||||
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<NetworkPlugin>(this, { name });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this plugin.
|
||||
*/
|
||||
clone(): NetworkPlugin {
|
||||
return new NetworkPlugin(this.name);
|
||||
}
|
||||
@ -26,28 +41,91 @@ export class NetworkPlugin {
|
||||
// }
|
||||
}
|
||||
|
||||
// Networks can use this plugin to override calculations for the
|
||||
// intrinsic gas cost of a transaction for networks that differ
|
||||
// from the latest hardfork on Ethereum mainnet.
|
||||
|
||||
/**
|
||||
* 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) }`);
|
||||
@ -75,16 +153,32 @@ export class GasCostPlugin extends NetworkPlugin implements GasCostParameters {
|
||||
}
|
||||
}
|
||||
|
||||
// Networks shoudl use this plugin to specify the contract address
|
||||
// and network necessary to resolve ENS names.
|
||||
/**
|
||||
* 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 contract address
|
||||
/**
|
||||
* The ENS Registrty Contract address.
|
||||
*/
|
||||
readonly address!: string;
|
||||
|
||||
// The network ID that the ENS contract lives on
|
||||
/**
|
||||
* 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<EnsPlugin>(this, {
|
||||
@ -98,18 +192,34 @@ export class EnsPlugin extends NetworkPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<FeeData>;
|
||||
|
||||
/**
|
||||
* The fee data function provided to the constructor.
|
||||
*/
|
||||
get feeDataFunc(): (provider: Provider) => Promise<FeeData> {
|
||||
return this.#feeDataFunc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new **FeeDataNetworkPlugin**.
|
||||
*/
|
||||
constructor(feeDataFunc: (provider: Provider) => Promise<FeeData>) {
|
||||
super("org.ethers.plugins.network.FeeData");
|
||||
this.#feeDataFunc = feeDataFunc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the fee data.
|
||||
*/
|
||||
async getFeeData(provider: Provider): Promise<FeeData> {
|
||||
return await this.#feeDataFunc(provider);
|
||||
}
|
||||
|
@ -8,11 +8,22 @@ import type {
|
||||
} from "./provider-jsonrpc.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
/**
|
||||
* The interface to an [[link-eip-1193]] provider, which is a standard
|
||||
* used by most injected providers, which the [[BrowserProvider]] accepts
|
||||
* and exposes the API of.
|
||||
*/
|
||||
export interface Eip1193Provider {
|
||||
/**
|
||||
* See [[link-eip-1193]] for details on this method.
|
||||
*/
|
||||
request(request: { method: string, params?: Array<any> | Record<string, any> }): Promise<any>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible additional events dispatched when using the ``"debug"``
|
||||
* event on a [[BrowserProvider]].
|
||||
*/
|
||||
export type DebugEventBrowserProvider = {
|
||||
action: "sendEip1193Payload",
|
||||
payload: { method: string, params: Array<any> }
|
||||
@ -25,10 +36,18 @@ export type DebugEventBrowserProvider = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A **BrowserProvider** is intended to wrap an injected provider which
|
||||
* adheres to the [[link-eip-1193]] standard, which most (if not all)
|
||||
* currently do.
|
||||
*/
|
||||
export class BrowserProvider extends JsonRpcApiPollingProvider {
|
||||
#request: (method: string, params: Array<any> | Record<string, any>) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Connnect to the %%ethereum%% provider, optionally forcing the
|
||||
* %%network%%.
|
||||
*/
|
||||
constructor(ethereum: Eip1193Provider, network?: Networkish) {
|
||||
super(network, { batchMaxCount: 1 });
|
||||
|
||||
@ -88,6 +107,9 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
|
||||
return super.getRpcError(payload, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to ``true`` if the provider manages the %%address%%.
|
||||
*/
|
||||
async hasSigner(address: number | string): Promise<boolean> {
|
||||
if (address == null) { address = 0; }
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Explain all the nitty-gritty about the **FallbackProvider**.
|
||||
* A **FallbackProvider** providers resiliance, security and performatnce
|
||||
* in a way that is customizable and configurable.
|
||||
*
|
||||
* @_section: api/providers/fallback-provider:Fallback Provider [about-fallback-provider]
|
||||
*/
|
||||
@ -45,17 +46,27 @@ function stringify(value: any): string {
|
||||
*/
|
||||
export interface FallbackProviderConfig {
|
||||
|
||||
// The provider
|
||||
/**
|
||||
* The provider.
|
||||
*/
|
||||
provider: AbstractProvider;
|
||||
|
||||
// How long to wait for a response before getting impatient
|
||||
// and ispatching the next provider
|
||||
/**
|
||||
* The amount of time to wait before kicking off the next provider.
|
||||
*
|
||||
* Any providers that have not responded can still respond and be
|
||||
* counted, but this ensures new providers start.
|
||||
*/
|
||||
stallTimeout?: number;
|
||||
|
||||
// Lower values are dispatched first
|
||||
/**
|
||||
* The priority. Lower priority providers are dispatched first.
|
||||
*/
|
||||
priority?: number;
|
||||
|
||||
// How much this provider contributes to the quorum
|
||||
/**
|
||||
* The amount of weight a provider is given against the quorum.
|
||||
*/
|
||||
weight?: number;
|
||||
};
|
||||
|
||||
@ -68,28 +79,44 @@ const defaultConfig = { stallTimeout: 400, priority: 1, weight: 1 };
|
||||
*/
|
||||
export interface FallbackProviderState extends Required<FallbackProviderConfig> {
|
||||
|
||||
// The most recent blockNumber this provider has reported (-2 if none)
|
||||
/**
|
||||
* The most recent blockNumber this provider has reported (-2 if none).
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
// The number of total requests ever sent to this provider
|
||||
/**
|
||||
* The number of total requests ever sent to this provider.
|
||||
*/
|
||||
requests: number;
|
||||
|
||||
// The number of responses that errored
|
||||
/**
|
||||
* The number of responses that errored.
|
||||
*/
|
||||
errorResponses: number;
|
||||
|
||||
// The number of responses that occured after the result resolved
|
||||
/**
|
||||
* The number of responses that occured after the result resolved.
|
||||
*/
|
||||
lateResponses: number;
|
||||
|
||||
// How many times syncing was required to catch up the expected block
|
||||
/**
|
||||
* How many times syncing was required to catch up the expected block.
|
||||
*/
|
||||
outOfSync: number;
|
||||
|
||||
// The number of requests which reported unsupported operation
|
||||
/**
|
||||
* The number of requests which reported unsupported operation.
|
||||
*/
|
||||
unsupportedEvents: number;
|
||||
|
||||
// A rolling average (5% current duration) for response time
|
||||
/**
|
||||
* A rolling average (5% current duration) for response time.
|
||||
*/
|
||||
rollingDuration: number;
|
||||
|
||||
// The ratio of quorum-agreed results to total
|
||||
/**
|
||||
* The ratio of quorum-agreed results to total.
|
||||
*/
|
||||
score: number;
|
||||
}
|
||||
|
||||
@ -317,13 +344,28 @@ function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined |
|
||||
}
|
||||
|
||||
/**
|
||||
* A Fallback Provider.
|
||||
* A **FallbackProvider** manages several [[Providers]] providing
|
||||
* resiliance by switching between slow or misbehaving nodes, security
|
||||
* by requiring multiple backends to aggree and performance by allowing
|
||||
* faster backends to respond earlier.
|
||||
*
|
||||
*/
|
||||
export class FallbackProvider extends AbstractProvider {
|
||||
|
||||
/**
|
||||
* The number of backends that must agree on a value before it is
|
||||
* accpeted.
|
||||
*/
|
||||
readonly quorum: number;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly eventQuorum: number;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly eventWorkers: number;
|
||||
|
||||
readonly #configs: Array<Config>;
|
||||
@ -331,6 +373,13 @@ export class FallbackProvider extends AbstractProvider {
|
||||
#height: number;
|
||||
#initialSyncPromise: null | Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a new **FallbackProvider** with %%providers%% connected to
|
||||
* %%network%%.
|
||||
*
|
||||
* If a [[Provider]] is included in %%providers%%, defaults are used
|
||||
* for the configuration.
|
||||
*/
|
||||
constructor(providers: Array<AbstractProvider | FallbackProviderConfig>, network?: Networkish) {
|
||||
super(network);
|
||||
this.#configs = providers.map((p) => {
|
||||
@ -371,6 +420,9 @@ export class FallbackProvider extends AbstractProvider {
|
||||
// throw new Error("@TODO");
|
||||
//}
|
||||
|
||||
/**
|
||||
* Transforms a %%req%% into the correct method call on %%provider%%.
|
||||
*/
|
||||
async _translatePerform(provider: AbstractProvider, req: PerformActionRequest): Promise<any> {
|
||||
switch (req.method) {
|
||||
case "broadcastTransaction":
|
||||
|
@ -22,8 +22,17 @@ function splitBuffer(data: Buffer): { messages: Array<string>, remaining: Buffer
|
||||
return { messages, remaining: data.subarray(lastStart) };
|
||||
}
|
||||
|
||||
/**
|
||||
* An **IpcSocketProvider** connects over an IPC socket on the host
|
||||
* which provides fast access to the node, but requires the node and
|
||||
* the script run on the same machine.
|
||||
*/
|
||||
export class IpcSocketProvider extends SocketProvider {
|
||||
#socket: Socket;
|
||||
|
||||
/**
|
||||
* The connected socket.
|
||||
*/
|
||||
get socket(): Socket { return this.#socket; }
|
||||
|
||||
constructor(path: string, network?: Networkish) {
|
||||
|
@ -1,5 +1,11 @@
|
||||
/**
|
||||
* About JSON-RPC...
|
||||
* One of the most common ways to interact with the blockchain is
|
||||
* by a node running a JSON-RPC interface which can be connected to,
|
||||
* based on the transport, using:
|
||||
*
|
||||
* - HTTP or HTTPS - [[JsonRpcProvider]]
|
||||
* - WebSocket - [[WebSocketProvider]]
|
||||
* - IPC - [[IpcSocketProvider]]
|
||||
*
|
||||
* @_section: api/providers/jsonrpc:JSON-RPC Provider [about-jsonrpcProvider]
|
||||
*/
|
||||
@ -81,9 +87,24 @@ function isPollable(value: any): value is Pollable {
|
||||
* A JSON-RPC payload, which are sent to a JSON-RPC server.
|
||||
*/
|
||||
export type JsonRpcPayload = {
|
||||
/**
|
||||
* The JSON-RPC request ID.
|
||||
*/
|
||||
id: number;
|
||||
|
||||
/**
|
||||
* The JSON-RPC request method.
|
||||
*/
|
||||
method: string;
|
||||
|
||||
/**
|
||||
* The JSON-RPC request parameters.
|
||||
*/
|
||||
params: Array<any> | Record<string, any>;
|
||||
|
||||
/**
|
||||
* A required constant in the JSON-RPC specification.
|
||||
*/
|
||||
jsonrpc: "2.0";
|
||||
};
|
||||
|
||||
@ -91,7 +112,14 @@ export type JsonRpcPayload = {
|
||||
* A JSON-RPC result, which are returned on success from a JSON-RPC server.
|
||||
*/
|
||||
export type JsonRpcResult = {
|
||||
/**
|
||||
* The response ID to match it to the relevant request.
|
||||
*/
|
||||
id: number;
|
||||
|
||||
/**
|
||||
* The response result.
|
||||
*/
|
||||
result: any;
|
||||
};
|
||||
|
||||
@ -99,7 +127,14 @@ export type JsonRpcResult = {
|
||||
* A JSON-RPC error, which are returned on failure from a JSON-RPC server.
|
||||
*/
|
||||
export type JsonRpcError = {
|
||||
/**
|
||||
* The response ID to match it to the relevant request.
|
||||
*/
|
||||
id: number;
|
||||
|
||||
/**
|
||||
* The response error.
|
||||
*/
|
||||
error: {
|
||||
code: number;
|
||||
message?: string;
|
||||
@ -168,22 +203,72 @@ const defaultOptions = {
|
||||
batchMaxCount: 100 // 100 requests
|
||||
}
|
||||
|
||||
/**
|
||||
* A **JsonRpcTransactionRequest** is formatted as needed by the JSON-RPC
|
||||
* Ethereum API specification.
|
||||
*/
|
||||
export interface JsonRpcTransactionRequest {
|
||||
/**
|
||||
* The sender address to use when signing.
|
||||
*/
|
||||
from?: string;
|
||||
|
||||
/**
|
||||
* The target address.
|
||||
*/
|
||||
to?: string;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data?: string;
|
||||
|
||||
/**
|
||||
* The chain ID the transaction is valid on.
|
||||
*/
|
||||
chainId?: string;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2718]] transaction type.
|
||||
*/
|
||||
type?: string;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas to allow a transaction to consume.
|
||||
*
|
||||
* In most other places in ethers, this is called ``gasLimit`` which
|
||||
* differs from the JSON-RPC Ethereum API specification.
|
||||
*/
|
||||
gas?: string;
|
||||
|
||||
/**
|
||||
* The gas price per wei for transactions prior to [[link-eip-1559]].
|
||||
*/
|
||||
gasPrice?: string;
|
||||
|
||||
/**
|
||||
* The maximum fee per gas for [[link-eip-1559]] transactions.
|
||||
*/
|
||||
maxFeePerGas?: string;
|
||||
|
||||
/**
|
||||
* The maximum priority fee per gas for [[link-eip-1559]] transactions.
|
||||
*/
|
||||
maxPriorityFeePerGas?: string;
|
||||
|
||||
/**
|
||||
* The nonce for the transaction.
|
||||
*/
|
||||
nonce?: string;
|
||||
|
||||
/**
|
||||
* The transaction value (in wei).
|
||||
*/
|
||||
value?: string;
|
||||
|
||||
/**
|
||||
* The transaction access list.
|
||||
*/
|
||||
accessList?: Array<{ address: string, storageKeys: Array<string> }>;
|
||||
}
|
||||
|
||||
|
@ -27,10 +27,18 @@ type JsonRpcSubscription = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A **SocketSubscriber** uses a socket transport to handle events and
|
||||
* should use [[_emit]] to manage the events.
|
||||
*/
|
||||
export class SocketSubscriber implements Subscriber {
|
||||
#provider: SocketProvider;
|
||||
|
||||
#filter: string;
|
||||
|
||||
/**
|
||||
* The filter.
|
||||
*/
|
||||
get filter(): Array<any> { return JSON.parse(this.#filter); }
|
||||
|
||||
#filterId: null | Promise<string |number>;
|
||||
@ -38,6 +46,10 @@ export class SocketSubscriber implements Subscriber {
|
||||
|
||||
#emitPromise: null | Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a new **SocketSubscriber** attached to %%provider%% listening
|
||||
* to %%filter%%.
|
||||
*/
|
||||
constructor(provider: SocketProvider, filter: Array<any>) {
|
||||
this.#provider = provider;
|
||||
this.#filter = JSON.stringify(filter);
|
||||
@ -72,6 +84,9 @@ export class SocketSubscriber implements Subscriber {
|
||||
this.#paused = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
_handleMessage(message: any): void {
|
||||
if (this.#filterId == null) { return; }
|
||||
if (this.#paused === null) {
|
||||
@ -91,12 +106,23 @@ export class SocketSubscriber implements Subscriber {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this to emit the events on the
|
||||
* provider.
|
||||
*/
|
||||
async _emit(provider: SocketProvider, message: any): Promise<void> {
|
||||
throw new Error("sub-classes must implemente this; _emit");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketBlockSubscriber** listens for ``newHeads`` events and emits
|
||||
* ``"block"`` events.
|
||||
*/
|
||||
export class SocketBlockSubscriber extends SocketSubscriber {
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(provider: SocketProvider) {
|
||||
super(provider, [ "newHeads" ]);
|
||||
}
|
||||
@ -106,7 +132,15 @@ export class SocketBlockSubscriber extends SocketSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketPendingSubscriber** listens for pending transacitons and emits
|
||||
* ``"pending"`` events.
|
||||
*/
|
||||
export class SocketPendingSubscriber extends SocketSubscriber {
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(provider: SocketProvider) {
|
||||
super(provider, [ "newPendingTransactions" ]);
|
||||
}
|
||||
@ -116,10 +150,20 @@ export class SocketPendingSubscriber extends SocketSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketEventSubscriber** listens for event logs.
|
||||
*/
|
||||
export class SocketEventSubscriber extends SocketSubscriber {
|
||||
#logFilter: string;
|
||||
|
||||
/**
|
||||
* The filter.
|
||||
*/
|
||||
get logFilter(): EventFilter { return JSON.parse(this.#logFilter); }
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(provider: SocketProvider, filter: EventFilter) {
|
||||
super(provider, [ "logs", filter ]);
|
||||
this.#logFilter = JSON.stringify(filter);
|
||||
@ -131,8 +175,9 @@ export class SocketEventSubscriber extends SocketSubscriber {
|
||||
}
|
||||
|
||||
/**
|
||||
* SocketProvider...
|
||||
*
|
||||
* A **SocketProvider** is backed by a long-lived connection over a
|
||||
* socket, which can subscribe and receive real-time messages over
|
||||
* its communication channel.
|
||||
*/
|
||||
export class SocketProvider extends JsonRpcApiProvider {
|
||||
#callbacks: Map<number, { payload: JsonRpcPayload, resolve: (r: any) => void, reject: (e: Error) => void }>;
|
||||
@ -144,6 +189,11 @@ export class SocketProvider extends JsonRpcApiProvider {
|
||||
// registering, queue them
|
||||
#pending: Map<number | string, Array<any>>;
|
||||
|
||||
/**
|
||||
* Creates a new **SocketProvider** connected to %%network%%.
|
||||
*
|
||||
* If unspecified, the network will be discovered.
|
||||
*/
|
||||
constructor(network?: Networkish) {
|
||||
super(network, { batchMaxCount: 1 });
|
||||
this.#callbacks = new Map();
|
||||
@ -181,6 +231,10 @@ export class SocketProvider extends JsonRpcApiProvider {
|
||||
return super._getSubscriber(sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new subscriber. This is used internalled by Subscribers
|
||||
* and generally is unecessary unless extending capabilities.
|
||||
*/
|
||||
_register(filterId: number | string, subscriber: SocketSubscriber): void {
|
||||
this.#subs.set(filterId, subscriber);
|
||||
const pending = this.#pending.get(filterId);
|
||||
@ -227,7 +281,10 @@ export class SocketProvider extends JsonRpcApiProvider {
|
||||
}
|
||||
*/
|
||||
|
||||
// Sub-classes must call this for each message
|
||||
/**
|
||||
* Sub-classes **must** call this with messages received over their
|
||||
* transport to be processed and dispatched.
|
||||
*/
|
||||
async _processMessage(message: string): Promise<void> {
|
||||
const result = <JsonRpcResult | JsonRpcError | JsonRpcSubscription>(JSON.parse(message));
|
||||
|
||||
@ -267,6 +324,10 @@ export class SocketProvider extends JsonRpcApiProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this to send %%message%% over their
|
||||
* transport.
|
||||
*/
|
||||
async _write(message: string): Promise<void> {
|
||||
throw new Error("sub-classes must override this");
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import { SocketProvider } from "./provider-socket.js";
|
||||
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
/**
|
||||
* A generic interface to a Websocket-like object.
|
||||
*/
|
||||
export interface WebSocketLike {
|
||||
onopen: null | ((...args: Array<any>) => any);
|
||||
onmessage: null | ((...args: Array<any>) => any);
|
||||
@ -17,8 +20,22 @@ export interface WebSocketLike {
|
||||
close(code?: number, reason?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function which can be used to re-create a WebSocket connection
|
||||
* on disconnect.
|
||||
*/
|
||||
export type WebSocketCreator = () => WebSocketLike;
|
||||
|
||||
/**
|
||||
* A JSON-RPC provider which is backed by a WebSocket.
|
||||
*
|
||||
* WebSockets are often preferred because they retain a live connection
|
||||
* to a server, which permits more instant access to events.
|
||||
*
|
||||
* However, this incurs higher server infrasturture costs, so additional
|
||||
* resources may be required to host your own WebSocket nodes and many
|
||||
* third-party services charge additional fees for WebSocket endpoints.
|
||||
*/
|
||||
export class WebSocketProvider extends SocketProvider {
|
||||
#connect: null | WebSocketCreator;
|
||||
|
||||
|
@ -16,6 +16,19 @@ import type { Network } from "./network.js";
|
||||
|
||||
const BN_0 = BigInt(0);
|
||||
|
||||
/**
|
||||
* A **BlockTag** specifies a specific block.
|
||||
*
|
||||
* **numeric value** - specifies the block height, where
|
||||
* the genesis block is block 0; many operations accept a negative
|
||||
* value which indicates the block number should be deducted from
|
||||
* the most recent block. A numeric value may be a ``number``, ``bigint``,
|
||||
* or a decimal of hex string.
|
||||
*
|
||||
* **blockhash** - specifies a specific block by its blockhash; this allows
|
||||
* potentially orphaned blocks to be specifed, without ambiguity, but many
|
||||
* backends do not support this for some operations.
|
||||
*/
|
||||
export type BlockTag = BigNumberish | string;
|
||||
|
||||
import {
|
||||
@ -101,62 +114,215 @@ export class FeeData {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A **TransactionRequest** is a transactions with potentially various
|
||||
* properties not defined, or with less strict types for its values.
|
||||
*
|
||||
* This is used to pass to various operations, which will internally
|
||||
* coerce any types and populate any necessary values.
|
||||
*/
|
||||
export interface TransactionRequest {
|
||||
/**
|
||||
* The transaction type.
|
||||
*/
|
||||
type?: null | number;
|
||||
|
||||
/**
|
||||
* The target of the transaction.
|
||||
*/
|
||||
to?: null | AddressLike;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from?: null | AddressLike;
|
||||
|
||||
/**
|
||||
* The nonce of the transaction, used to prevent replay attacks.
|
||||
*/
|
||||
nonce?: null | number;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas to allow this transaction to consime.
|
||||
*/
|
||||
gasLimit?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The gas price to use for legacy transactions or transactions on
|
||||
* legacy networks.
|
||||
*
|
||||
* Most of the time the ``max*FeePerGas`` is preferred.
|
||||
*/
|
||||
gasPrice?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The [[link-eip-1559]] maximum priority fee to pay per gas.
|
||||
*/
|
||||
maxPriorityFeePerGas?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The [[link-eip-1559]] maximum total fee to pay per gas. The actual
|
||||
* value used is protocol enforced to be the block's base fee.
|
||||
*/
|
||||
maxFeePerGas?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data?: null | string;
|
||||
|
||||
/**
|
||||
* The transaction value (in wei).
|
||||
*/
|
||||
value?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The chain ID for the network this transaction is valid on.
|
||||
*/
|
||||
chainId?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2930]] access list. Storage slots included in the access
|
||||
* list are //warmed// by pre-loading them, so their initial cost to
|
||||
* fetch is guaranteed, but then each additional access is cheaper.
|
||||
*/
|
||||
accessList?: null | AccessListish;
|
||||
|
||||
/**
|
||||
* A custom object, which can be passed along for network-specific
|
||||
* values.
|
||||
*/
|
||||
customData?: any;
|
||||
|
||||
// Only meaningful when used for call
|
||||
|
||||
/**
|
||||
* When using ``call`` or ``estimateGas``, this allows a specific
|
||||
* block to be queried. Many backends do not support this and when
|
||||
* unsupported errors are silently squelched and ``"latest"`` is used.
|
||||
*/
|
||||
blockTag?: BlockTag;
|
||||
|
||||
/**
|
||||
* When using ``call``, this enables CCIP-read, which permits the
|
||||
* provider to be redirected to web-based content during execution,
|
||||
* which is then further validated by the contract.
|
||||
*
|
||||
* There are potential security implications allowing CCIP-read, as
|
||||
* it could be used to expose the IP address or user activity during
|
||||
* the fetch to unexpected parties.
|
||||
*/
|
||||
enableCcipRead?: boolean;
|
||||
|
||||
// Todo?
|
||||
//gasMultiplier?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* A **PreparedTransactionRequest** is identical to a [[TransactionRequest]]
|
||||
* except all the property types are strictly enforced.
|
||||
*/
|
||||
export interface PreparedTransactionRequest {
|
||||
/**
|
||||
* The transaction type.
|
||||
*/
|
||||
type?: number;
|
||||
|
||||
|
||||
/**
|
||||
* The target of the transaction.
|
||||
*/
|
||||
to?: AddressLike;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from?: AddressLike;
|
||||
|
||||
/**
|
||||
* The nonce of the transaction, used to prevent replay attacks.
|
||||
*/
|
||||
|
||||
nonce?: number;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas to allow this transaction to consime.
|
||||
*/
|
||||
gasLimit?: bigint;
|
||||
|
||||
/**
|
||||
* The gas price to use for legacy transactions or transactions on
|
||||
* legacy networks.
|
||||
*
|
||||
* Most of the time the ``max*FeePerGas`` is preferred.
|
||||
*/
|
||||
gasPrice?: bigint;
|
||||
|
||||
/**
|
||||
* The [[link-eip-1559]] maximum priority fee to pay per gas.
|
||||
*/
|
||||
maxPriorityFeePerGas?: bigint;
|
||||
|
||||
/**
|
||||
* The [[link-eip-1559]] maximum total fee to pay per gas. The actual
|
||||
* value used is protocol enforced to be the block's base fee.
|
||||
*/
|
||||
maxFeePerGas?: bigint;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data?: string;
|
||||
|
||||
|
||||
/**
|
||||
* The transaction value (in wei).
|
||||
*/
|
||||
value?: bigint;
|
||||
|
||||
/**
|
||||
* The chain ID for the network this transaction is valid on.
|
||||
*/
|
||||
chainId?: bigint;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2930]] access list. Storage slots included in the access
|
||||
* list are //warmed// by pre-loading them, so their initial cost to
|
||||
* fetch is guaranteed, but then each additional access is cheaper.
|
||||
*/
|
||||
accessList?: AccessList;
|
||||
|
||||
/**
|
||||
* A custom object, which can be passed along for network-specific
|
||||
* values.
|
||||
*/
|
||||
customData?: any;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* When using ``call`` or ``estimateGas``, this allows a specific
|
||||
* block to be queried. Many backends do not support this and when
|
||||
* unsupported errors are silently squelched and ``"latest"`` is used.
|
||||
*/
|
||||
blockTag?: BlockTag;
|
||||
|
||||
/**
|
||||
* When using ``call``, this enables CCIP-read, which permits the
|
||||
* provider to be redirected to web-based content during execution,
|
||||
* which is then further validated by the contract.
|
||||
*
|
||||
* There are potential security implications allowing CCIP-read, as
|
||||
* it could be used to expose the IP address or user activity during
|
||||
* the fetch to unexpected parties.
|
||||
*/
|
||||
enableCcipRead?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of %%req%% with all properties coerced to their strict
|
||||
* types.
|
||||
*/
|
||||
export function copyRequest(req: TransactionRequest): PreparedTransactionRequest {
|
||||
const result: any = { };
|
||||
|
||||
@ -206,10 +372,30 @@ export function copyRequest(req: TransactionRequest): PreparedTransactionRequest
|
||||
* Before a block is included, it is a //pending// block.
|
||||
*/
|
||||
export interface MinedBlock extends Block {
|
||||
/**
|
||||
* The block number also known as the block height.
|
||||
*/
|
||||
readonly number: number;
|
||||
|
||||
/**
|
||||
* The block hash.
|
||||
*/
|
||||
readonly hash: string;
|
||||
|
||||
/**
|
||||
* The block timestamp, in seconds from epoch.
|
||||
*/
|
||||
readonly timestamp: number;
|
||||
|
||||
/**
|
||||
* The block date, created from the [[timestamp]].
|
||||
*/
|
||||
readonly date: Date;
|
||||
|
||||
/**
|
||||
* The miner of the block, also known as the ``author`` or
|
||||
* block ``producer``.
|
||||
*/
|
||||
readonly miner: string;
|
||||
}
|
||||
|
||||
@ -218,6 +404,7 @@ export interface MinedBlock extends Block {
|
||||
* Ethereum.
|
||||
*/
|
||||
export class Block implements BlockParams, Iterable<string> {
|
||||
|
||||
/**
|
||||
* The provider connected to the block used to fetch additional details
|
||||
* if necessary.
|
||||
@ -232,6 +419,9 @@ export class Block implements BlockParams, Iterable<string> {
|
||||
|
||||
/**
|
||||
* The block hash.
|
||||
*
|
||||
* This hash includes all properties, so can be safely used to identify
|
||||
* an exact set of block properties.
|
||||
*/
|
||||
readonly hash!: null | string;
|
||||
|
||||
@ -348,7 +538,7 @@ export class Block implements BlockParams, Iterable<string> {
|
||||
/**
|
||||
* Returns the complete transactions for blocks which
|
||||
* prefetched them, by passing ``true`` to %%prefetchTxs%%
|
||||
* into [[provider_getBlock]].
|
||||
* into [[Provider-getBlock]].
|
||||
*/
|
||||
get prefetchedTransactions(): Array<TransactionResponse> {
|
||||
const txs = this.#transactions.slice();
|
||||
@ -445,6 +635,12 @@ export class Block implements BlockParams, Iterable<string> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a **Block** was fetched with a request to include the transactions
|
||||
* this will allow synchronous access to those transactions.
|
||||
*
|
||||
* If the transactions were not prefetched, this will throw.
|
||||
*/
|
||||
getPrefetchedTransaction(indexOrHash: number | string): TransactionResponse {
|
||||
const txs = this.prefetchedTransactions;
|
||||
if (typeof(indexOrHash) === "number") {
|
||||
@ -460,20 +656,21 @@ export class Block implements BlockParams, Iterable<string> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this block been mined.
|
||||
*
|
||||
* If true, the block has been typed-gaurded that all mined
|
||||
* properties are non-null.
|
||||
* Returns true if this block been mined. This provides a type guard
|
||||
* for all properties on a [[MinedBlock]].
|
||||
*/
|
||||
isMined(): this is MinedBlock { return !!this.hash; }
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns true if this block is an [[link-eip-2930]] block.
|
||||
*/
|
||||
isLondon(): this is (Block & { baseFeePerGas: bigint }) {
|
||||
return !!this.baseFeePerGas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
orphanedEvent(): OrphanFilter {
|
||||
if (!this.isMined()) { throw new Error(""); }
|
||||
return createOrphanedBlockFilter(this);
|
||||
@ -483,24 +680,80 @@ export class Block implements BlockParams, Iterable<string> {
|
||||
//////////////////////
|
||||
// Log
|
||||
|
||||
/**
|
||||
* A **Log** in Ethereum represents an event that has been included in a
|
||||
* transaction using the ``LOG*`` opcodes, which are most commonly used by
|
||||
* Solidity's emit for announcing events.
|
||||
*/
|
||||
export class Log implements LogParams {
|
||||
|
||||
/**
|
||||
* The provider connected to the log used to fetch additional details
|
||||
* if necessary.
|
||||
*/
|
||||
readonly provider: Provider;
|
||||
|
||||
/**
|
||||
* The transaction hash of the transaction this log occurred in. Use the
|
||||
* [[Log-getTransaction]] to get the [[TransactionResponse]].
|
||||
*/
|
||||
readonly transactionHash!: string;
|
||||
|
||||
/**
|
||||
* The block hash of the block this log occurred in. Use the
|
||||
* [[Log-getBlock]] to get the [[Block]].
|
||||
*/
|
||||
readonly blockHash!: string;
|
||||
|
||||
/**
|
||||
* The block number of the block this log occurred in. It is preferred
|
||||
* to use the [[Block-hash]] when fetching the related [[Block]],
|
||||
* since in the case of an orphaned block, the block at that height may
|
||||
* have changed.
|
||||
*/
|
||||
readonly blockNumber!: number;
|
||||
|
||||
/**
|
||||
* If the **Log** represents a block that was removed due to an orphaned
|
||||
* block, this will be true.
|
||||
*
|
||||
* This can only happen within an orphan event listener.
|
||||
*/
|
||||
readonly removed!: boolean;
|
||||
|
||||
/**
|
||||
* The address of the contract that emitted this log.
|
||||
*/
|
||||
readonly address!: string;
|
||||
|
||||
/**
|
||||
* The data included in this log when it was emitted.
|
||||
*/
|
||||
readonly data!: string;
|
||||
|
||||
/**
|
||||
* The indexed topics included in this log when it was emitted.
|
||||
*
|
||||
* All topics are included in the bloom filters, so they can be
|
||||
* efficiently filtered using the [[Provider-getLogs]] method.
|
||||
*/
|
||||
readonly topics!: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The index within the block this log occurred at. This is generally
|
||||
* not useful to developers, but can be used with the various roots
|
||||
* to proof inclusion within a block.
|
||||
*/
|
||||
readonly index!: number;
|
||||
|
||||
/**
|
||||
* The index within the transaction of this log.
|
||||
*/
|
||||
readonly transactionIndex!: number;
|
||||
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(log: LogParams, provider: Provider) {
|
||||
this.provider = provider;
|
||||
|
||||
@ -522,6 +775,9 @@ export class Log implements LogParams {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON-compatible object.
|
||||
*/
|
||||
toJSON(): any {
|
||||
const {
|
||||
address, blockHash, blockNumber, data, index,
|
||||
@ -535,24 +791,37 @@ export class Log implements LogParams {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block that this log occurred in.
|
||||
*/
|
||||
async getBlock(): Promise<Block> {
|
||||
const block = await this.provider.getBlock(this.blockHash);
|
||||
assert(!!block, "failed to find transaction", "UNKNOWN_ERROR", { });
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction that this log occurred in.
|
||||
*/
|
||||
async getTransaction(): Promise<TransactionResponse> {
|
||||
const tx = await this.provider.getTransaction(this.transactionHash);
|
||||
assert(!!tx, "failed to find transaction", "UNKNOWN_ERROR", { });
|
||||
return tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction receipt fot the transaction that this
|
||||
* log occurred in.
|
||||
*/
|
||||
async getTransactionReceipt(): Promise<TransactionReceipt> {
|
||||
const receipt = await this.provider.getTransactionReceipt(this.transactionHash);
|
||||
assert(!!receipt, "failed to find transaction receipt", "UNKNOWN_ERROR", { });
|
||||
return receipt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
removedEvent(): OrphanFilter {
|
||||
return createRemovedLogFilter(this);
|
||||
}
|
||||
@ -575,32 +844,118 @@ export interface ByzantiumTransactionReceipt {
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* A **TransactionReceipt** includes additional information about a
|
||||
* transaction that is only available after it has been mined.
|
||||
*/
|
||||
export class TransactionReceipt implements TransactionReceiptParams, Iterable<Log> {
|
||||
/**
|
||||
* The provider connected to the log used to fetch additional details
|
||||
* if necessary.
|
||||
*/
|
||||
readonly provider!: Provider;
|
||||
|
||||
/**
|
||||
* The address the transaction was send to.
|
||||
*/
|
||||
readonly to!: null | string;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
readonly from!: string;
|
||||
|
||||
/**
|
||||
* The address of the contract if the transaction was directly
|
||||
* responsible for deploying one.
|
||||
*
|
||||
* This is non-null **only** if the ``to`` is empty and the ``data``
|
||||
* was successfully executed as initcode.
|
||||
*/
|
||||
readonly contractAddress!: null | string;
|
||||
|
||||
/**
|
||||
* The transaction hash.
|
||||
*/
|
||||
readonly hash!: string;
|
||||
|
||||
/**
|
||||
* The index of this transaction within the block transactions.
|
||||
*/
|
||||
readonly index!: number;
|
||||
|
||||
/**
|
||||
* The block hash of the [[Block]] this transaction was included in.
|
||||
*/
|
||||
readonly blockHash!: string;
|
||||
|
||||
/**
|
||||
* The block number of the [[Block]] this transaction was included in.
|
||||
*/
|
||||
readonly blockNumber!: number;
|
||||
|
||||
/**
|
||||
* The bloom filter bytes that represent all logs that occurred within
|
||||
* this transaction. This is generally not useful for most developers,
|
||||
* but can be used to validate the included logs.
|
||||
*/
|
||||
readonly logsBloom!: string;
|
||||
|
||||
/**
|
||||
* The actual amount of gas used by this transaction.
|
||||
*
|
||||
* When creating a transaction, the amount of gas that will be used can
|
||||
* only be approximated, but the sender must pay the gas fee for the
|
||||
* entire gas limit. After the transaction, the difference is refunded.
|
||||
*/
|
||||
readonly gasUsed!: bigint;
|
||||
|
||||
/**
|
||||
* The amount of gas used by all transactions within the block for this
|
||||
* and all transactions with a lower ``index``.
|
||||
*
|
||||
* This is generally not useful for developers but can be used to
|
||||
* validate certain aspects of execution.
|
||||
*/
|
||||
readonly cumulativeGasUsed!: bigint;
|
||||
|
||||
/**
|
||||
* The actual gas price used during execution.
|
||||
*
|
||||
* Due to the complexity of [[link-eip-1559]] this value can only
|
||||
* be caluclated after the transaction has been mined, snce the base
|
||||
* fee is protocol-enforced.
|
||||
*/
|
||||
readonly gasPrice!: bigint;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2718]] transaction type.
|
||||
*/
|
||||
readonly type!: number;
|
||||
//readonly byzantium!: boolean;
|
||||
|
||||
/**
|
||||
* The status of this transaction, indicating success (i.e. ``1``) or
|
||||
* a revert (i.e. ``0``).
|
||||
*
|
||||
* This is available in post-byzantium blocks, but some backends may
|
||||
* backfill this value.
|
||||
*/
|
||||
readonly status!: null | number;
|
||||
|
||||
/**
|
||||
* The root hash of this transaction.
|
||||
*
|
||||
* This is no present and was only included in pre-byzantium blocks, but
|
||||
* could be used to validate certain parts of the receipt.
|
||||
*/
|
||||
readonly root!: null | string;
|
||||
|
||||
readonly #logs: ReadonlyArray<Log>;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(tx: TransactionReceiptParams, provider: Provider) {
|
||||
this.#logs = Object.freeze(tx.logs.map((log) => {
|
||||
return new Log(log, provider);
|
||||
@ -639,8 +994,14 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The logs for this transaction.
|
||||
*/
|
||||
get logs(): ReadonlyArray<Log> { return this.#logs; }
|
||||
|
||||
/**
|
||||
* Returns a JSON-compatible representation.
|
||||
*/
|
||||
toJSON(): any {
|
||||
const {
|
||||
to, from, contractAddress, hash, index, blockHash, blockNumber, logsBloom,
|
||||
@ -661,6 +1022,9 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
get length(): number { return this.logs.length; }
|
||||
|
||||
[Symbol.iterator](): Iterator<Log> {
|
||||
@ -675,34 +1039,58 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The total fee for this transaction, in wei.
|
||||
*/
|
||||
get fee(): bigint {
|
||||
return this.gasUsed * this.gasPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the block this transaction occurred in.
|
||||
*/
|
||||
async getBlock(): Promise<Block> {
|
||||
const block = await this.provider.getBlock(this.blockHash);
|
||||
if (block == null) { throw new Error("TODO"); }
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction this transaction occurred in.
|
||||
*/
|
||||
async getTransaction(): Promise<TransactionResponse> {
|
||||
const tx = await this.provider.getTransaction(this.hash);
|
||||
if (tx == null) { throw new Error("TODO"); }
|
||||
return tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the return value of the execution of this transaction.
|
||||
*
|
||||
* Support for this feature is limited, as it requires an archive node
|
||||
* with the ``debug_`` or ``trace_`` API enabled.
|
||||
*/
|
||||
async getResult(): Promise<string> {
|
||||
return <string>(await this.provider.getTransactionResult(this.hash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the number of confirmations this transaction has.
|
||||
*/
|
||||
async confirmations(): Promise<number> {
|
||||
return (await this.provider.getBlockNumber()) - this.blockNumber + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
removedEvent(): OrphanFilter {
|
||||
return createRemovedTransactionFilter(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
||||
assert(!other || other.isMined(), "unmined 'other' transction cannot be orphaned",
|
||||
"UNSUPPORTED_OPERATION", { operation: "reorderedEvent(other)" });
|
||||
@ -714,22 +1102,38 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
|
||||
//////////////////////
|
||||
// Transaction Response
|
||||
|
||||
/**
|
||||
* A **MinedTransactionResponse** is an interface representing a
|
||||
* transaction which has been mined and allows for a type guard for its
|
||||
* property values being defined.
|
||||
*/
|
||||
export interface MinedTransactionResponse extends TransactionResponse {
|
||||
/**
|
||||
* The block number this transaction occurred in.
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
/**
|
||||
* The block hash this transaction occurred in.
|
||||
*/
|
||||
blockHash: string;
|
||||
|
||||
/**
|
||||
* The date this transaction occurred on.
|
||||
*/
|
||||
date: Date;
|
||||
}
|
||||
|
||||
/*
|
||||
export type ReplacementDetectionSetup = {
|
||||
to: string;
|
||||
from: string;
|
||||
value: bigint;
|
||||
data: string;
|
||||
nonce: number;
|
||||
block: number;
|
||||
};
|
||||
*/
|
||||
|
||||
/**
|
||||
* A **TransactionResponse** includes all properties about a transaction
|
||||
* that was sent to the network, which may or may not be included in a
|
||||
* block.
|
||||
*
|
||||
* The [[TransactionResponse-isMined]] can be used to check if the
|
||||
* transaction has been mined as well as type guard that the otherwise
|
||||
* possibly ``null`` properties are defined.
|
||||
*/
|
||||
export class TransactionResponse implements TransactionLike<string>, TransactionResponseParams {
|
||||
/**
|
||||
* The provider this is connected to, which will influence how its
|
||||
@ -858,8 +1262,7 @@ export class TransactionResponse implements TransactionLike<string>, Transaction
|
||||
#startBlock: number;
|
||||
|
||||
/**
|
||||
* Create a new TransactionResponse with %%tx%% parameters
|
||||
* connected to %%provider%%.
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(tx: TransactionResponseParams, provider: Provider) {
|
||||
this.provider = provider;
|
||||
@ -893,7 +1296,7 @@ export class TransactionResponse implements TransactionLike<string>, Transaction
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON representation of this transaction.
|
||||
* Returns a JSON-compatible representation of this transaction.
|
||||
*/
|
||||
toJSON(): any {
|
||||
const {
|
||||
@ -1272,17 +1675,40 @@ export type TopicFilter = Array<null | string | Array<string>>;
|
||||
// @TODO:
|
||||
//export type DeferableTopicFilter = Array<null | string | Promise<string> | Array<string | Promise<string>>>;
|
||||
|
||||
/**
|
||||
* An **EventFilter** allows efficiently filtering logs (also known as
|
||||
* events) using bloom filters included within blocks.
|
||||
*/
|
||||
export interface EventFilter {
|
||||
address?: AddressLike | Array<AddressLike>;
|
||||
topics?: TopicFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Filter** allows searching a specific range of blocks for mathcing
|
||||
* logs.
|
||||
*/
|
||||
export interface Filter extends EventFilter {
|
||||
|
||||
/**
|
||||
* The start block for the filter (inclusive).
|
||||
*/
|
||||
fromBlock?: BlockTag;
|
||||
|
||||
/**
|
||||
* The end block for the filter (inclusive).
|
||||
*/
|
||||
toBlock?: BlockTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **FilterByBlockHash** allows searching a specific block for mathcing
|
||||
* logs.
|
||||
*/
|
||||
export interface FilterByBlockHash extends EventFilter {
|
||||
/**
|
||||
* The blockhash of the specific block for the filter.
|
||||
*/
|
||||
blockHash?: string;
|
||||
}
|
||||
|
||||
@ -1290,6 +1716,30 @@ export interface FilterByBlockHash extends EventFilter {
|
||||
//////////////////////
|
||||
// ProviderEvent
|
||||
|
||||
/**
|
||||
* A **ProviderEvent** provides the types of events that can be subscribed
|
||||
* to on a [[Provider]].
|
||||
*
|
||||
* Each provider may include additional possible events it supports, but
|
||||
* the most commonly supported are:
|
||||
*
|
||||
* **``"block"``** - calls the listener with the current block number on each
|
||||
* new block.
|
||||
*
|
||||
* **``"error"``** - calls the listener on each async error that occurs during
|
||||
* the event loop, with the error.
|
||||
*
|
||||
* **``"debug"``** - calls the listener on debug events, which can be used to
|
||||
* troubleshoot network errors, provider problems, etc.
|
||||
*
|
||||
* **``transaction hash``** - calls the listener on each block after the
|
||||
* transaction has been mined; generally ``.once`` is more appropriate for
|
||||
* this event.
|
||||
*
|
||||
* **``Array``** - calls the listener on each log that matches the filter.
|
||||
*
|
||||
* [[EventFilter]] - calls the listener with each matching log
|
||||
*/
|
||||
export type ProviderEvent = string | Array<string | Array<string>> | EventFilter | OrphanFilter;
|
||||
|
||||
|
||||
|
@ -9,12 +9,23 @@ import type {
|
||||
import type { Signer } from "./signer.js";
|
||||
|
||||
|
||||
/**
|
||||
* A **NonceManager** wraps another [[Signer]] and automatically manages
|
||||
* the nonce, ensuring serialized and sequential nonces are used during
|
||||
* transaction.
|
||||
*/
|
||||
export class NonceManager extends AbstractSigner {
|
||||
/**
|
||||
* The Signer being managed.
|
||||
*/
|
||||
signer!: Signer;
|
||||
|
||||
#noncePromise: null | Promise<number>;
|
||||
#delta: number;
|
||||
|
||||
/**
|
||||
* Creates a new **NonceManager** to manage %%signer%%.
|
||||
*/
|
||||
constructor(signer: Signer) {
|
||||
super(signer.provider);
|
||||
defineProperties<NonceManager>(this, { signer });
|
||||
@ -44,10 +55,18 @@ export class NonceManager extends AbstractSigner {
|
||||
return super.getNonce(blockTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually increment the nonce. This may be useful when managng
|
||||
* offline transactions.
|
||||
*/
|
||||
increment(): void {
|
||||
this.#delta++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the nonce, causing the **NonceManager** to reload the current
|
||||
* nonce from the blockchain on the next transaction.
|
||||
*/
|
||||
reset(): void {
|
||||
this.#delta = 0;
|
||||
this.#noncePromise = null;
|
||||
|
@ -33,6 +33,11 @@ export class FilterIdSubscriber implements Subscriber {
|
||||
|
||||
#hault: boolean;
|
||||
|
||||
/**
|
||||
* Creates a new **FilterIdSubscriber** which will used [[_subscribe]]
|
||||
* and [[_emitResults]] to setup the subscription and provide the event
|
||||
* to the %%provider%%.
|
||||
*/
|
||||
constructor(provider: JsonRpcApiProvider) {
|
||||
this.#provider = provider;
|
||||
|
||||
@ -46,14 +51,23 @@ export class FilterIdSubscriber implements Subscriber {
|
||||
this.#hault = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this to begin the subscription.
|
||||
*/
|
||||
_subscribe(provider: JsonRpcApiProvider): Promise<string> {
|
||||
throw new Error("subclasses must override this");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this handle the events.
|
||||
*/
|
||||
_emitResults(provider: AbstractProvider, result: Array<any>): Promise<void> {
|
||||
throw new Error("subclasses must override this");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this handle recovery on errors.
|
||||
*/
|
||||
_recover(provider: AbstractProvider): Subscriber {
|
||||
throw new Error("subclasses must override this");
|
||||
}
|
||||
@ -141,6 +155,10 @@ export class FilterIdSubscriber implements Subscriber {
|
||||
export class FilterIdEventSubscriber extends FilterIdSubscriber {
|
||||
#event: EventFilter;
|
||||
|
||||
/**
|
||||
* Creates a new **FilterIdEventSubscriber** attached to %%provider%%
|
||||
* listening for %%filter%%.
|
||||
*/
|
||||
constructor(provider: JsonRpcApiProvider, filter: EventFilter) {
|
||||
super(provider);
|
||||
this.#event = copy(filter);
|
||||
|
@ -8,7 +8,7 @@ function copy(obj: any): any {
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* Return the polling subscriber for common events.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
@ -24,7 +24,8 @@ export function getPollingSubscriber(provider: AbstractProvider, event: Provider
|
||||
// @TODO: refactor this
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* A **PollingBlockSubscriber** polls at a regular interval for a change
|
||||
* in the block number.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
@ -38,6 +39,9 @@ export class PollingBlockSubscriber implements Subscriber {
|
||||
// indicates we still need to fetch an initial block number
|
||||
#blockNumber: number;
|
||||
|
||||
/**
|
||||
* Create a new **PollingBlockSubscriber** attached to %%provider%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider) {
|
||||
this.#provider = provider;
|
||||
this.#poller = null;
|
||||
@ -46,6 +50,9 @@ export class PollingBlockSubscriber implements Subscriber {
|
||||
this.#blockNumber = -2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The polling interval.
|
||||
*/
|
||||
get pollingInterval(): number { return this.#interval; }
|
||||
set pollingInterval(value: number) { this.#interval = value; }
|
||||
|
||||
@ -107,7 +114,8 @@ export class PollingBlockSubscriber implements Subscriber {
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* An **OnBlockSubscriber** can be sub-classed, with a [[_poll]]
|
||||
* implmentation which will be called on every new block.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
@ -116,6 +124,9 @@ export class OnBlockSubscriber implements Subscriber {
|
||||
#poll: (b: number) => void;
|
||||
#running: boolean;
|
||||
|
||||
/**
|
||||
* Create a new **OnBlockSubscriber** attached to %%provider%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider) {
|
||||
this.#provider = provider;
|
||||
this.#running = false;
|
||||
@ -124,6 +135,9 @@ export class OnBlockSubscriber implements Subscriber {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every new block.
|
||||
*/
|
||||
async _poll(blockNumber: number, provider: AbstractProvider): Promise<void> {
|
||||
throw new Error("sub-classes must override this");
|
||||
}
|
||||
@ -148,7 +162,7 @@ export class OnBlockSubscriber implements Subscriber {
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* @_ignore:
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
@ -167,13 +181,18 @@ export class PollingOrphanSubscriber extends OnBlockSubscriber {
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* A **PollingTransactionSubscriber** will poll for a given transaction
|
||||
* hash for its receipt.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class PollingTransactionSubscriber extends OnBlockSubscriber {
|
||||
#hash: string;
|
||||
|
||||
/**
|
||||
* Create a new **PollingTransactionSubscriber** attached to
|
||||
* %%provider%%, listening for %%hash%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider, hash: string) {
|
||||
super(provider);
|
||||
this.#hash = hash;
|
||||
@ -186,7 +205,7 @@ export class PollingTransactionSubscriber extends OnBlockSubscriber {
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* A **PollingEventSubscriber** will poll for a given filter for its logs.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
@ -201,6 +220,10 @@ export class PollingEventSubscriber implements Subscriber {
|
||||
// indicates we still need to fetch an initial block number
|
||||
#blockNumber: number;
|
||||
|
||||
/**
|
||||
* Create a new **PollingTransactionSubscriber** attached to
|
||||
* %%provider%%, listening for %%filter%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider, filter: EventFilter) {
|
||||
this.#provider = provider;
|
||||
this.#filter = copy(filter);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Transactions..
|
||||
* Each state-changing operation on Ethereum requires a transaction.
|
||||
*
|
||||
* @_section api/transaction:Transactions [about-transactions]
|
||||
*/
|
||||
|
@ -22,6 +22,11 @@ const BN_28 = BigInt(28)
|
||||
const BN_35 = BigInt(35);
|
||||
const BN_MAX_UINT = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
|
||||
/**
|
||||
* A **TransactionLike** is an object which is appropriate as a loose
|
||||
* input for many operations which will populate missing properties of
|
||||
* a transaction.
|
||||
*/
|
||||
export interface TransactionLike<A = string> {
|
||||
/**
|
||||
* The type.
|
||||
|
@ -1,5 +1,9 @@
|
||||
/**
|
||||
* About Errors.
|
||||
* All errors in ethers include properties to ensure they are both
|
||||
* human-readable (i.e. ``.message``) and machine-readable (i.e. ``.code``).
|
||||
*
|
||||
* The [[isError]] function can be used to check the error ``code`` and
|
||||
* provide a type guard for the properties present on that error interface.
|
||||
*
|
||||
* @_section: api/utils/errors:Errors [about-errors]
|
||||
*/
|
||||
@ -14,6 +18,10 @@ import type {
|
||||
|
||||
import type { FetchRequest, FetchResponse } from "./fetch.js";
|
||||
|
||||
/**
|
||||
* An error may contain additional properties, but those must not
|
||||
* conflict with any impliciat properties.
|
||||
*/
|
||||
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
||||
|
||||
|
||||
@ -202,6 +210,9 @@ export interface UnsupportedOperationError extends EthersError<"UNSUPPORTED_OPER
|
||||
operation: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This Error indicates a proplem connecting to a network.
|
||||
*/
|
||||
export interface NetworkError extends EthersError<"NETWORK_ERROR"> {
|
||||
event: string;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Explain events...
|
||||
* Events allow for applications to use the observer pattern, which
|
||||
* allows subscribing and publishing events, outside the normal
|
||||
* execution paths.
|
||||
*
|
||||
* @_section api/utils/events:Events [about-events]
|
||||
*/
|
||||
|
@ -1,5 +1,19 @@
|
||||
/**
|
||||
* Explain fetching here...
|
||||
* Fetching content from the web is environment-specific, so Ethers
|
||||
* provides an abstraction the each environment can implement to provide
|
||||
* this service.
|
||||
*
|
||||
* On [Node.js](link-node), the ``http`` and ``https`` libs are used to
|
||||
* create a request object, register event listeners and process data
|
||||
* and populate the [[FetchResponse]].
|
||||
*
|
||||
* In a browser, the [DOM fetch](link-js-fetch) is used, and the resulting
|
||||
* ``Promise`` is waited on to retreive the payload.
|
||||
*
|
||||
* The [[FetchRequest]] is responsible for handling many common situations,
|
||||
* such as redirects, server throttling, authentcation, etc.
|
||||
*
|
||||
* It also handles common gateways, such as IPFS and data URIs.
|
||||
*
|
||||
* @_section api/utils/fetching:Fetching Web Content [about-fetch]
|
||||
*/
|
||||
@ -11,7 +25,9 @@ import { toUtf8Bytes, toUtf8String } from "./utf8.js"
|
||||
|
||||
import { getUrl } from "./geturl.js";
|
||||
|
||||
|
||||
/**
|
||||
* An environments implementation of ``getUrl`` must return this type.
|
||||
*/
|
||||
export type GetUrlResponse = {
|
||||
statusCode: number,
|
||||
statusMessage: string,
|
||||
@ -19,10 +35,15 @@ export type GetUrlResponse = {
|
||||
body: null | Uint8Array
|
||||
};
|
||||
|
||||
/**
|
||||
* This can be used to control how throttling is handled in
|
||||
* [[FetchRequest-setThrottleParams]].
|
||||
*/
|
||||
export type FetchThrottleParams = {
|
||||
maxAttempts?: number;
|
||||
slotInterval?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called before any network request, allowing updated headers (e.g. Bearer tokens), etc.
|
||||
*/
|
||||
|
@ -1,5 +1,10 @@
|
||||
/**
|
||||
* About fixed-point math...
|
||||
* The **FixedNumber** class permits using values with decimal places,
|
||||
* using fixed-pont math.
|
||||
*
|
||||
* Fixed-point math is still based on integers under-the-hood, but uses an
|
||||
* internal offset to store fractional components below, and each operation
|
||||
* corrects for this after each operation.
|
||||
*
|
||||
* @_section: api/utils/fixed-point-math:Fixed-Point Maths [about-fixed-point-math]
|
||||
*/
|
||||
|
@ -113,6 +113,10 @@ export function getBigInt(value: BigNumberish, name?: string): bigint {
|
||||
assertArgument(false, "invalid BigNumberish value", name || "value", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns %%value%% as a bigint, validating it is valid as a bigint
|
||||
* value and that it is positive.
|
||||
*/
|
||||
export function getUint(value: BigNumberish, name?: string): bigint {
|
||||
const result = getBigInt(value, name);
|
||||
assert(result >= BN_0, "unsigned value cannot be negative", "NUMERIC_FAULT", {
|
||||
|
@ -18,7 +18,7 @@ import { Wordlist } from "./wordlist.js";
|
||||
* based on ASCII-7 small.
|
||||
*
|
||||
* If necessary, there are tools within the ``generation/`` folder
|
||||
* to create these necessary data.
|
||||
* to create the necessary data.
|
||||
*/
|
||||
export class WordlistOwl extends Wordlist {
|
||||
#data: string;
|
||||
@ -35,8 +35,14 @@ export class WordlistOwl extends Wordlist {
|
||||
this.#words = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The OWL-encoded data.
|
||||
*/
|
||||
get _data(): string { return this.#data; }
|
||||
|
||||
/**
|
||||
* Decode all the words for the wordlist.
|
||||
*/
|
||||
_decodeWords(): Array<string> {
|
||||
return decodeOwl(this.#data);
|
||||
}
|
||||
|
@ -12,18 +12,29 @@ import { decodeOwlA } from "./decode-owla.js";
|
||||
* based on latin-1 small.
|
||||
*
|
||||
* If necessary, there are tools within the ``generation/`` folder
|
||||
* to create these necessary data.
|
||||
* to create the necessary data.
|
||||
*/
|
||||
export class WordlistOwlA extends WordlistOwl {
|
||||
#accent: string;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Wordlist for %%locale%% using the OWLA %%data%%
|
||||
* and %%accent%% data and validated against the %%checksum%%.
|
||||
*/
|
||||
constructor(locale: string, data: string, accent: string, checksum: string) {
|
||||
super(locale, data, checksum);
|
||||
this.#accent = accent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The OWLA-encoded accent data.
|
||||
*/
|
||||
get _accent(): string { return this.#accent; }
|
||||
|
||||
/**
|
||||
* Decode all the words for the wordlist.
|
||||
*/
|
||||
_decodeWords(): Array<string> {
|
||||
return decodeOwlA(this._data, this._accent);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user