522 lines
17 KiB
Plaintext
522 lines
17 KiB
Plaintext
_section: Interface @<Interface> @SRC<abi/interface:class.Interface>
|
|
|
|
The **Interface** Class abstracts the encoding and decoding required
|
|
to interact with contracts on the Ethereum network.
|
|
|
|
Many of the standards organically evolved along side the [[link-solidity]]
|
|
language, which other languages have adopted to remain compatible with
|
|
existing deployed contracts.
|
|
|
|
The EVM itself does not understand what the ABI is. It is simply an agreed
|
|
upon set of formats to encode various types of data which each contract can
|
|
expect so they can interoperate with each other.
|
|
|
|
|
|
_subsection: Creating Instances @<Interface--creating>
|
|
|
|
_property: new ethers.utils.Interface(abi) @SRC<abi/interface:constructor.Interface>
|
|
Create a new **Interface** from a JSON string or object representing
|
|
//abi//.
|
|
|
|
The //abi// may be a JSON string or the parsed Object (using JSON.parse)
|
|
which is emitted by the [Solidity compiler](link-solc-output) (or compatible languages).
|
|
|
|
The //abi// may also be a [Human-Readable Abi](link-ricmoo-humanreadableabi),
|
|
which is a format the Ethers created to simplify manually typing the ABI
|
|
into the source and so that a Contract ABI can also be referenced easily
|
|
within the same source file.
|
|
|
|
_code: Creating an Interface instance @lang<javascript>
|
|
|
|
//_hide: const Interface = ethers.utils.Interface;
|
|
|
|
// This interface is used for the below examples
|
|
|
|
const iface = new Interface([
|
|
// Constructor
|
|
"constructor(string symbol, string name)",
|
|
|
|
// State mutating method
|
|
"function transferFrom(address from, address to, uint amount)",
|
|
|
|
// State mutating method, which is payable
|
|
"function mint(uint amount) payable",
|
|
|
|
// Constant method (i.e. "view" or "pure")
|
|
"function balanceOf(address owner) view returns (uint)",
|
|
|
|
// An Event
|
|
"event Transfer(address indexed from, address indexed to, uint256 amount)",
|
|
|
|
// A Custom Solidity Error
|
|
"error AccountLocked(address owner, uint256 balance)",
|
|
|
|
// Examples with structured types
|
|
"function addUser(tuple(string name, address addr) user) returns (uint id)",
|
|
"function addUsers(tuple(string name, address addr)[] user) returns (uint[] id)",
|
|
"function getUser(uint id) view returns (tuple(string name, address addr) user)"
|
|
]);
|
|
|
|
//_hide: _page.iface = iface;
|
|
|
|
_subsection: Properties @<Interface--properties>
|
|
|
|
_property: interface.fragments => Array<[[Fragment]]>
|
|
All the [Fragments](Fragment) in the interface.
|
|
|
|
_property: interface.errors => Array<[[ErrorFragment]]>
|
|
All the [Error Fragments](ErrorFragment) in the interface.
|
|
|
|
_property: interface.events => Array<[[EventFragment]]>
|
|
All the [Event Fragments](EventFragment) in the interface.
|
|
|
|
_property: interface.functions => Array<[[FunctionFragment]]>
|
|
All the [Function Fragments](FunctionFragment) in the interface.
|
|
|
|
_property: interface.deploy => [[ConstructorFragment]]
|
|
The [Constructor Fragments](ConstructorFragment) for the interface.
|
|
|
|
|
|
_subsection: Formatting @<Interface--formatting>
|
|
|
|
_property: interface.format( [ format ]) => string | Array<string> @SRC<abi/interface>
|
|
Return the formatted **Interface**. If the format type is ``json`` a
|
|
single string is returned, otherwise an Array of the human-readable
|
|
strings is returned.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
const FormatTypes = ethers.utils.FormatTypes;
|
|
|
|
//_result:
|
|
iface.format(FormatTypes.json)
|
|
//_log:
|
|
|
|
//_result:
|
|
iface.format(FormatTypes.full)
|
|
//_log:
|
|
|
|
//_result:
|
|
iface.format(FormatTypes.minimal)
|
|
//_log:
|
|
|
|
_subsection: Fragment Access @<Interface--fragments>
|
|
|
|
_property: interface.getFunction(fragment) => [[FunctionFragment]] @SRC<abi/interface>
|
|
Returns the [[FunctionFragment]] for //fragment// (see [[Interface--specifying-fragments]]).
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
// By method signature, which is normalized so whitespace
|
|
// and superfluous attributes are ignored
|
|
iface.getFunction("transferFrom(address, address, uint256)");
|
|
|
|
// By name; this ONLY works if the method is non-ambiguous
|
|
iface.getFunction("transferFrom");
|
|
|
|
// By method selector
|
|
iface.getFunction("0x23b872dd");
|
|
|
|
// Throws if the method does not exist
|
|
//_throws:
|
|
iface.getFunction("doesNotExist()");
|
|
//_log:
|
|
|
|
_property: interface.getError(fragment) => [[ErrorFragment]] @SRC<abi/interface>
|
|
Returns the [[ErrorFragment]] for //fragment// (see [[Interface--specifying-fragments]]).
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
// By error signature, which is normalized so whitespace
|
|
// and superfluous attributes are ignored
|
|
iface.getError("AccountLocked(address, uint256)");
|
|
|
|
// By name; this ONLY works if the error is non-ambiguous
|
|
iface.getError("AccountLocked");
|
|
|
|
// By error selector
|
|
iface.getError("0xf7c3865a");
|
|
|
|
// Throws if the error does not exist
|
|
//_throws:
|
|
iface.getError("DoesNotExist()");
|
|
//_log:
|
|
|
|
_property: interface.getEvent(fragment) => [[EventFragment]] @SRC<abi/interface>
|
|
Returns the [[EventFragment]] for //fragment// (see [[Interface--specifying-fragments]]).
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
// By event signature, which is normalized so whitespace
|
|
// and superfluous attributes are ignored
|
|
iface.getEvent("Transfer(address, address, uint256)");
|
|
|
|
// By name; this ONLY works if the event is non-ambiguous
|
|
iface.getEvent("Transfer");
|
|
|
|
// By event topic hash
|
|
iface.getEvent("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
|
|
|
|
// Throws if the event does not exist
|
|
//_throws:
|
|
iface.getEvent("DoesNotExist()");
|
|
//_log:
|
|
|
|
_subsection: Signature and Topic Hashes @<Interface--selectors>
|
|
|
|
_property: interface.getSighash(fragment) => string<[[DataHexString]]<4>> @SRC<abi/interface:method.Interface.getSighash>
|
|
Return the sighash (or Function Selector) for //fragment// (see [[Interface--specifying-fragments]]).
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
//_result:
|
|
iface.getSighash("balanceOf");
|
|
//_log:
|
|
|
|
//_result:
|
|
iface.getSighash("balanceOf(address)");
|
|
//_log:
|
|
|
|
const fragment = iface.getFunction("balanceOf")
|
|
//_result:
|
|
iface.getSighash(fragment);
|
|
//_log:
|
|
|
|
_property: interface.getEventTopic(fragment) => string<[[DataHexString]]<32>> @SRC<abi/interface:method.Interface.getEventTopic>
|
|
Return the topic hash for //fragment// (see [[Interface--specifying-fragments]]).
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
//_result:
|
|
iface.getEventTopic("Transfer");
|
|
//_log:
|
|
|
|
//_result:
|
|
iface.getEventTopic("Transfer(address, address, uint)");
|
|
//_log:
|
|
|
|
const fragment = iface.getEvent("Transfer")
|
|
//_result:
|
|
iface.getEventTopic(fragment);
|
|
//_log:
|
|
|
|
_subsection: Encoding Data @<Interface--encoding>
|
|
|
|
_property: interface.encodeDeploy([ values ]) => string<[[DataHexString]]> @SRC<abi/interface>
|
|
Return the encoded deployment data, which can be concatenated to the
|
|
deployment bytecode of a contract to pass //values// into the contract
|
|
constructor.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
//_hide: const parseEther = ethers.utils.parseEther;
|
|
|
|
// The data that should be appended to the bytecode to pass
|
|
// parameters to the constructor during deployment
|
|
//_result:
|
|
iface.encodeDeploy([ "SYM", "Some Name" ])
|
|
//_log:
|
|
|
|
_property: interface.encodeFilterTopics(fragment, values) => Array<topic | Array<topic>> @SRC<abi/interface>
|
|
Returns the encoded topic filter, which can be passed to getLogs for //fragment//
|
|
(see [[Interface--specifying-fragments]]) for the given //values//.
|
|
|
|
Each //topic// is a 32 byte (64 nibble) [[DataHexString]].
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
//_hide: const parseEther = ethers.utils.parseEther;
|
|
|
|
// Filter that matches all Transfer events
|
|
//_result:
|
|
iface.encodeFilterTopics("Transfer", [])
|
|
//_log:
|
|
|
|
// Filter that matches the sender
|
|
//_result:
|
|
iface.encodeFilterTopics("Transfer", [
|
|
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
|
])
|
|
//_log:
|
|
|
|
// Filter that matches the receiver
|
|
//_result:
|
|
iface.encodeFilterTopics("Transfer", [
|
|
null,
|
|
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
|
])
|
|
//_log:
|
|
|
|
_property: interface.encodeFunctionData(fragment [ , values ]) => string<[[DataHexString]]> @SRC<abi/interface>
|
|
Returns the encoded data, which can be used as the data for a transaction for
|
|
//fragment// (see [[Interface--specifying-fragments]]) for the given //values//.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
//_hide: const parseEther = ethers.utils.parseEther;
|
|
|
|
// Encoding data for the tx.data of a call or transaction
|
|
//_result:
|
|
iface.encodeFunctionData("transferFrom", [
|
|
"0x8ba1f109551bD432803012645Ac136ddd64DBA72",
|
|
"0xaB7C8803962c0f2F5BBBe3FA8bf41cd82AA1923C",
|
|
parseEther("1.0")
|
|
])
|
|
//_log:
|
|
|
|
// Encoding structured data (using positional Array)
|
|
user = [
|
|
"Richard Moore",
|
|
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
|
];
|
|
//_result:
|
|
iface.encodeFunctionData("addUser", [ user ]);
|
|
//_log:
|
|
|
|
// Encoding structured data, using objects. Only available
|
|
// if paramters are named.
|
|
user = {
|
|
name: "Richard Moore",
|
|
addr: "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
|
};
|
|
//_result:
|
|
iface.encodeFunctionData("addUser", [ user ]);
|
|
//_log:
|
|
|
|
_property: interface.encodeFunctionResult(fragment [ , values ]) => string<[[DataHexString]]> @SRC<abi/interface>
|
|
Returns the encoded result, which would normally be the response from a call for
|
|
//fragment// (see [[Interface--specifying-fragments]]) for the given //values//.
|
|
|
|
Most developers will not need this method, but may be useful for authors of a mock blockchain.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
//_hide: const parseEther = ethers.utils.parseEther;
|
|
|
|
// Encoding result data (like is returned by eth_call)
|
|
//_result:
|
|
iface.encodeFunctionResult("balanceOf", [
|
|
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
|
])
|
|
//_log:
|
|
|
|
|
|
_subsection: Decoding Data @<Interface--decoding>
|
|
|
|
_property: interface.decodeEventLog(fragment, data [ , topics ]) => [[Result]] @SRC<abi/interface>
|
|
Returns the decoded event values from an event log for
|
|
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//
|
|
with the optional //topics//.
|
|
|
|
If //topics// is not specified, placeholders will be inserted into the result.
|
|
|
|
Most develoeprs will find the [parsing methods](Interface--parsing) more
|
|
convenient for decoding event data, as they will automatically detect the
|
|
matching event.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
// Decoding log data and topics (the entries in a receipt)
|
|
const data = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
|
const topics = [
|
|
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
"0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72",
|
|
"0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c"
|
|
];
|
|
|
|
//_result:
|
|
iface.decodeEventLog("Transfer", data, topics);
|
|
//_log:
|
|
|
|
_property: interface.decodeFunctionData(fragment, data) => [[Result]] @SRC<abi/interface>
|
|
Returns the decoded values from transaction data for
|
|
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//.
|
|
|
|
Most developers will not need this method, but may be useful for debugging
|
|
or inspecting transactions.
|
|
|
|
Most develoeprs will also find the [parsing methods](Interface--parsing) more
|
|
convenient for decoding transation data, as they will automatically detect the
|
|
matching function.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
// Decoding function data (the value of tx.data)
|
|
const txData = "0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
|
//_result:
|
|
iface.decodeFunctionData("transferFrom", txData);
|
|
//_log:
|
|
|
|
_property: interface.decodeFunctionResult(fragment, data) => [[Result]] @SRC<abi/interface>
|
|
Returns the decoded values from the result of a call for
|
|
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//.
|
|
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
// Decoding result data (e.g. from an eth_call)
|
|
resultData = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
|
//_result:
|
|
iface.decodeFunctionResult("balanceOf", resultData)
|
|
//_log:
|
|
|
|
// Decoding result data which was caused by a revert
|
|
// Throws a CALL_EXCEPTION, with extra details
|
|
errorData = "0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
|
//_throws:
|
|
iface.decodeFunctionResult("balanceOf", errorData)
|
|
//_log:
|
|
|
|
// Decoding structured data returns a Result object, which
|
|
// will include all values positionally and if the ABI
|
|
// included names, values will additionally be available
|
|
// by their name.
|
|
resultData = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000000000000000000000000000000000000000000d52696368617264204d6f6f726500000000000000000000000000000000000000";
|
|
//_result:
|
|
result = iface.decodeFunctionResult("getUser", resultData);
|
|
//_log:
|
|
|
|
// Access positionally:
|
|
// The 0th output parameter, the 0th proerty of the structure
|
|
//_result:
|
|
result[0][0];
|
|
//_log:
|
|
|
|
// Access by name: (only avilable because parameters were named)
|
|
//_result:
|
|
result.user.name
|
|
//_log:
|
|
|
|
_subsection: Parsing @<Interface--parsing>
|
|
|
|
The functions are generally the most useful for most developers. They will
|
|
automatically search the ABI for a matching Event or Function and decode
|
|
the components as a fully specified description.
|
|
|
|
_property: interface.parseLog(log) => [[LogDescription]] @SRC<abi/interface>
|
|
Search the event that matches the //log// topic hash and parse the values
|
|
the log represents.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
|
|
const data = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
|
const topics = [
|
|
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
"0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72",
|
|
"0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c"
|
|
];
|
|
|
|
//_result:
|
|
iface.parseLog({ data, topics });
|
|
//_hide: _.eventFragment = createClass("EventFragment");
|
|
//_log:
|
|
|
|
_property: interface.parseTransaction(transaction) => [[TransactionDescription]] @SRC<abi/interface>
|
|
Search for the function that matches the //transaction// data sighash
|
|
and parse the transaction properties.
|
|
|
|
_code: @lang<javascript>
|
|
|
|
//_hide: const iface = _page.iface;
|
|
//_hide: const parseEther = ethers.utils.parseEther;
|
|
|
|
const data = "0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
|
const value = parseEther("1.0");
|
|
|
|
//_result:
|
|
iface.parseTransaction({ data, value });
|
|
//_hide: _.functionFragment = createClass("FunctionFragment");
|
|
//_log:
|
|
|
|
_subsection: Types @<Interface--types>
|
|
|
|
_heading: Result @<Result> @INHERIT<Array\<any\>>
|
|
|
|
A **Result** is an array, so each value can be accessed as a positional
|
|
argument.
|
|
|
|
Additionally, if values are named, the identical object as its positional
|
|
value can be accessed by its name.
|
|
|
|
The name ``length`` is however reserved as it is part of the Array, so
|
|
any named value for this key is renamed to ``_length``. If there is a
|
|
name collision, only the first is available by its key.
|
|
|
|
|
|
_heading: LogDescription @<LogDescription>
|
|
|
|
_property: logDescription.args => [[Result]]
|
|
The values of the input parameters of the event.
|
|
|
|
_property: logDescription.eventFragment => [[EventFragment]]
|
|
The [[EventFragment]] which matches the topic in the Log.
|
|
|
|
_property: logDescription.name => string
|
|
The event name. (e.g. ``Transfer``)
|
|
|
|
_property: logDescription.signature => string
|
|
The event signature. (e.g. ``Transfer(address,address,uint256)``)
|
|
|
|
_property: logDescription.topic => string
|
|
The topic hash.
|
|
|
|
|
|
_heading: TransactionDescription @<TransactionDescription>
|
|
|
|
_property: transactionDescription.args => [[Result]]
|
|
The decoded values from the transaction data which were passed
|
|
as the input parameters.
|
|
|
|
_property: transactionDescription.functionFragment => [[FunctionFragment]]
|
|
The [[FunctionFragment]] which matches the sighash in the transaction data.
|
|
|
|
_property: transactionDescription.name => string
|
|
The name of the function. (e.g. ``transfer``)
|
|
|
|
_property: transactionDescription.sighash => string
|
|
The sighash (or function selector) that matched the transaction data.
|
|
|
|
_property: transactionDescription.signature => string
|
|
The signature of the function. (e.g. ``transfer(address,uint256)``)
|
|
|
|
_property: transactionDescription.value => [[BigNumber]]
|
|
The value from the transaction.
|
|
|
|
|
|
_subsection: Specifying Fragments @<Interface--specifying-fragments>
|
|
|
|
When specifying a fragment to any of the functions in an **Interface**,
|
|
any of the following may be used:
|
|
|
|
- The **name** of the event or function, if it is unique and non-ambiguous
|
|
within the ABI (e.g. ``transfer``)
|
|
- The **signature** of the event or function. The signature is normalized,
|
|
so, for example, ``uint`` and ``uint256`` are equivalent (e.g. ``transfer(address, uint)``)
|
|
- The **sighash** or **topichash** of the function. The sighash is often referred
|
|
to the function selector in Solidity (e.g. ``0xa9059cbb``)
|
|
- A [[Fragment]]
|