ethers.js/docs/v5/concepts/events/index.html
2021-02-08 15:26:10 -05:00

193 lines
19 KiB
HTML

<!DOCTYPE html>
<html class="paged">
<head>
<title>Events</title>
<link rel="stylesheet" type="text/css" href="/v5/static/style.css">
<meta property="og:title" content="Events"/>
<meta property="og:description" content="Documentation for ethers, a complete, tiny and simple Ethereum library."/>
<meta property="og:image" content="/v5/static/social.jpg"/>
</head>
<body>
<div class="sidebar">
<div class="header">
<div class="logo"><a href="/v5/"><div class="image"></div><div class="name">ethers</div><div class="version">v5.0</div></a></div>
<div class="search"><form action="/v5/search/" method="GET"><input name="search" id="search" /></form><span class="search-icon">&#9906;</span></div>
</div>
<div class="toc"><div>
<div class="link title"><a href="/v5/">Documentation</a></div><div class="base show link depth-1"><a href="/v5/getting-started/">Getting Started</a></div><div class="base ancestor show link depth-1"><a href="/v5/concepts/">Ethereum Basics</a></div><div class="myself ancestor ancestor show link depth-2"><a href="/v5/concepts/events/">Events</a></div><div class="link show child depth-3"><a href="#events--logs-and-filtering">Logs and Filtering</a></div><div class="link show child depth-3"><a href="#events-solidity">Solidity Topics</a></div><div class="show link depth-2"><a href="/v5/concepts/gas/">Gas</a></div><div class="show link depth-2"><a href="/v5/concepts/security/">Security</a></div><div class="show link depth-2"><a href="/v5/concepts/best-practices/">Best Practices</a></div><div class="base show link depth-1"><a href="/v5/api-keys/">Provider API Keys</a></div><div class="base show link depth-1"><a href="/v5/api/">Application Programming Interface</a></div><div class="hide link depth-2"><a href="/v5/api/providers/">Providers</a></div><div class="hide link depth-3"><a href="/v5/api/providers/provider/">Provider</a></div><div class="hide link depth-3"><a href="/v5/api/providers/jsonrpc-provider/">JsonRpcProvider</a></div><div class="hide link depth-3"><a href="/v5/api/providers/api-providers/">API Providers</a></div><div class="hide link depth-3"><a href="/v5/api/providers/other/">Other Providers</a></div><div class="hide link depth-3"><a href="/v5/api/providers/types/">Types</a></div><div class="hide link depth-2"><a href="/v5/api/signer/">Signers</a></div><div class="hide link depth-2"><a href="/v5/api/contract/">Contract Interaction</a></div><div class="hide link depth-3"><a href="/v5/api/contract/contract/">Contract</a></div><div class="hide link depth-3"><a href="/v5/api/contract/contract-factory/">ContractFactory</a></div><div class="hide link depth-3"><a href="/v5/api/contract/example/">Example: ERC-20 Contract</a></div><div class="hide link depth-2"><a href="/v5/api/utils/">Utilities</a></div><div class="hide link depth-3"><a href="/v5/api/utils/abi/">Application Binary Interface</a></div><div class="hide link depth-4"><a href="/v5/api/utils/abi/coder/">AbiCoder</a></div><div class="hide link depth-4"><a href="/v5/api/utils/abi/formats/">ABI Formats</a></div><div class="hide link depth-4"><a href="/v5/api/utils/abi/fragments/">Fragments</a></div><div class="hide link depth-4"><a href="/v5/api/utils/abi/interface/">Interface</a></div><div class="hide link depth-3"><a href="/v5/api/utils/address/">Addresses</a></div><div class="hide link depth-3"><a href="/v5/api/utils/bignumber/">BigNumber</a></div><div class="hide link depth-3"><a href="/v5/api/utils/bytes/">Byte Manipulation</a></div><div class="hide link depth-3"><a href="/v5/api/utils/constants/">Constants</a></div><div class="hide link depth-3"><a href="/v5/api/utils/display-logic/">Display Logic and Input</a></div><div class="hide link depth-3"><a href="/v5/api/utils/encoding/">Encoding Utilities</a></div><div class="hide link depth-3"><a href="/v5/api/utils/fixednumber/">FixedNumber</a></div><div class="hide link depth-3"><a href="/v5/api/utils/hashing/">Hashing Algorithms</a></div><div class="hide link depth-3"><a href="/v5/api/utils/hdnode/">HD Wallet</a></div><div class="hide link depth-3"><a href="/v5/api/utils/logger/">Logging</a></div><div class="hide link depth-3"><a href="/v5/api/utils/properties/">Property Utilities</a></div><div class="hide link depth-3"><a href="/v5/api/utils/signing-key/">Signing Key</a></div><div class="hide link depth-3"><a href="/v5/api/utils/strings/">Strings</a></div><div class="hide link depth-3"><a href="/v5/api/utils/transactions/">Transactions</a></div><div class="hide link depth-3"><a href="/v5/api/utils/web/">Web Utilities</a></div><div class="hide link depth-3"><a href="/v5/api/utils/wordlists/">Wordlists</a></div><div class="hide link depth-2"><a href="/v5/api/other/">Other Libraries</a></div><div class="hide link depth-3"><a href="/v5/api/other/assembly/">Assembly</a></div><div class="hide link depth-4"><a href="/v5/api/other/assembly/dialect/">Ethers ASM Dialect</a></div><div class="hide link depth-4"><a href="/v5/api/other/assembly/api/">Utilities</a></div><div class="hide link depth-4"><a href="/v5/api/other/assembly/ast/">Abstract Syntax Tree</a></div><div class="hide link depth-3"><a href="/v5/api/other/hardware/">Hardware Wallets</a></div><div class="hide link depth-2"><a href="/v5/api/experimental/">Experimental</a></div><div class="base show link depth-1"><a href="/v5/cli/">Command Line Interfaces</a></div><div class="hide link depth-2"><a href="/v5/cli/ethers/">Sandbox Utility</a></div><div class="hide link depth-2"><a href="/v5/cli/asm/">Assembler</a></div><div class="hide link depth-2"><a href="/v5/cli/ens/">Ethereum Naming Service</a></div><div class="hide link depth-2"><a href="/v5/cli/typescript/">TypeScript</a></div><div class="hide link depth-2"><a href="/v5/cli/plugin/">Making Your Own</a></div><div class="base show link depth-1"><a href="/v5/cookbook/">Cookbook</a></div><div class="hide link depth-2"><a href="/v5/cookbook/react-native/">React Native (and ilk)</a></div><div class="base show link depth-1"><a href="/v5/migration/">Migration Guide</a></div><div class="hide link depth-2"><a href="/v5/migration/web3/">Migration: From Web3.js</a></div><div class="hide link depth-2"><a href="/v5/migration/ethers-v4/">Migration: From Ethers v4</a></div><div class="base show link depth-1"><a href="/v5/testing/">Testing</a></div><div class="base show link depth-1"><a href="/v5/contributing/">Contributing and Hacking</a></div><div class="base show link depth-1"><a href="/v5/other-resources/">Other Resources</a></div><div class="base show link depth-1"><a href="/v5/documentation/">Flatworm Docs</a></div><div class="base show link depth-1"><a href="/v5/license/">License and Copyright</a></div>
</div></div>
<div class="footer">
<a href="/v5/single-page/">Single Page</a>
</div>
</div>
<div class="content">
<div class="breadcrumbs"><a href="/v5/">Documentation</a>&nbsp;&nbsp;&raquo;&nbsp;&nbsp;<a href="/v5/concepts/">Ethereum Basics</a>&nbsp;&nbsp;&raquo;&nbsp;&nbsp;<span class="current">Events</span></div>
<a name="events"></a><a name="events"></a><h1 class="show-anchors"><div>Events<div class="anchors"><a class="self" href="/v5/concepts/events/#events"></a></div></div></h1>
<a name="events--logs-and-filtering"></a><h2 class="show-anchors"><div>Logs and Filtering<div class="anchors"><a class="self" href="/v5/concepts/events/#events--logs-and-filtering"></a></div></div></h2><p>Logs and filtering are used quite often in blockchain applications, since they allow for efficient queries of indexed data and provide lower-cost data storage when the data is not required to be accessed on-chain.</p>
<p>These can be used in conjunction with the <a href="/v5/api/providers/provider/#Provider--event-methods">Provider Events API</a> and with the <a href="/v5/api/contract/contract/#Contract--events">Contract Events API</a>.</p>
<p>The Contract Events API also provides <a href="/v5/api/contract/contract/#Contract--filters">higher-level methods</a> to compute and query this data, which should be preferred over the lower-level filter.</p>
<a name="events--filters"></a><a name="events--logs-and-filtering--events--filters"></a><h3 class="show-anchors"><div>Filters<div class="anchors"><a class="self" href="/v5/concepts/events/#events--filters"></a></div></div></h3><p>When a Contract creates a log, it can include up to 4 pieces of data to be indexed by. The indexed data is hashed and included in a <a href="https://en.wikipedia.org/wiki/Bloom_filter">Bloom Filter</a>, which is a data structure that allows for efficient filtering.</p>
<p>So, a filter may correspondingly have up to 4 topic-sets, where each topic-set refers to a condition that must match the indexed log topic in that position (i.e. each condition is <code class="inline">AND</code>-ed together).</p>
<p>If a topic-set is <code class="inline">null</code>, a log topic in that position is <b>not filtered</b> at all and <b>any value</b> matches.</p>
<p>If a topic-set is a single topic, a log topic in that position <b>must</b> match <b>that topic</b>.</p>
<p>If a topic-set is an array of topics, a log topic in that position must match <b>any one</b> of the topics (i.e. the topic in this position are <code class="inline">OR</code>-ed).</p>
<p>This may sound complicated at first, but is more easily understood with some examples.</p>
<table class="table full"><tr><td align="center" width="25%"><b>Topic-Sets</b></td><td align="center" colspan="3" width="75%"><b>Matching Logs</b></td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ A ]</td><td align="left" colspan="3" rowspan="2" width="75%">topic[0] = A</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ A, null ]</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ null, B ]</td><td align="left" colspan="3" rowspan="3" width="75%">topic[1] = B</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ null, [ B ] ]</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ null, [ B ], null ]</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ A, B ]</td><td align="left" colspan="3" rowspan="3" width="75%">(topic[0] = A) <b>AND</b> (topic[1] = B)</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ A, [ B ] ]</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ A, [ B ], null ]</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ [ A, B ] ]</td><td align="left" colspan="3" rowspan="2" width="75%">(topic[0] = A) <b>OR</b> (topic[0] = B)</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ [ A, B ], null ]</td><td class="fix">&nbsp;</td></tr><tr><td align="center" width="25%">[ [ A, B ], [ C, D ] ]</td><td align="left" colspan="3" width="75%"><b>[</b> (topic[0] = A) <b>OR</b> (topic[0] = B) <b>]</b> <b>AND</b> <b>[</b> (topic[1] = C) <b>OR</b> (topic[1] = D) <b>]</b></td><td class="fix">&nbsp;</td></tr><tr><td class="table-title" colspan="4">Example Log Matching</td><td class="fix">&nbsp;</td></tr></table><div class="code-title"><div>ERC-20 Transfer Filter Examples</div></div><div class="code"><span class="comment">// Short example of manually creating filters for an ERC-20
</span><span class="comment">// Transfer event.
</span>//
<span class="comment">// Most users should generally use the Contract API to
</span><span class="comment">// compute filters, as it is much simpler, but this is
</span><span class="comment">// provided as an illustration for those curious. See
</span><span class="comment">// below for examples of the equivalent Contract API.
</span>
<span class="comment">// ERC-20:
</span><span class="comment">// Transfer(address indexed src, address indexed dst, uint val)
</span>//
<span class="comment">// -------------------^
</span><span class="comment">// ----------------------------------------^
</span>//
<span class="comment">// Notice that only *src* and *dst* are *indexed*, so ONLY they
</span><span class="comment">// qualify for filtering.
</span>//
<span class="comment">// Also, note that in Solidity an Event uses the first topic to
</span><span class="comment">// identify the Event name; for Transfer this will be:
</span><span class="comment">// id("Transfer(address,address,uint256)")
</span>//
<span class="comment">// Other Notes:
</span><span class="comment">// - A topic must be 32 bytes; so shorter types must be padded
</span>
<span class="comment">// List all token transfers *from* myAddress
</span>filter = {
address: tokenAddress,
topics: [
id("Transfer(address,address,uint256)"),
hexZeroPad(myAddress, 32)
]
}
<span class="comment">// List all token transfers *to* myAddress:
</span>filter = {
address: tokenAddress,
topics: [
id("Transfer(address,address,uint256)"),
null,
hexZeroPad(myAddress, 32)
]
}
<span class="comment">// List all token transfers *to* myAddress or myOtherAddress:
</span>filter = {
address: tokenAddress,
topics: [
id("Transfer(address,address,uint256)"),
null,
[
hexZeroPad(myAddress, 32),
hexZeroPad(myOtherAddress, 32),
]
]
}
</div><p>To simplify life, ..., explain here, the contract API</p>
<div class="code-title"><div>ERC-20 Contract Filter Examples</div></div><div class="code">const abi = [
"event Transfer(address indexed src, address indexed dst, uint val)"
];
const contract = new Contract(tokenAddress, abi, provider);
<span class="comment">// List all token transfers *from* myAddress
</span>contract.filters.Transfer(myAddress)
<span class="result ok">// {
</span><span class="result ok">// address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
</span><span class="result ok">// topics: [
</span><span class="result ok">// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
</span><span class="result ok">// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72'
</span><span class="result ok">// ]
</span><span class="result ok">// }
</span>
<span class="comment">// List all token transfers *to* myAddress:
</span>contract.filters.Transfer(null, myAddress)
<span class="result ok">// {
</span><span class="result ok">// address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
</span><span class="result ok">// topics: [
</span><span class="result ok">// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
</span><span class="result ok">// null,
</span><span class="result ok">// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72'
</span><span class="result ok">// ]
</span><span class="result ok">// }
</span>
<span class="comment">// List all token transfers *from* myAddress *to* otherAddress:
</span>contract.filters.Transfer(myAddress, otherAddress)
<span class="result ok">// {
</span><span class="result ok">// address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
</span><span class="result ok">// topics: [
</span><span class="result ok">// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
</span><span class="result ok">// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72',
</span><span class="result ok">// '0x000000000000000000000000ea517d5a070e6705cc5467858681ed953d285eb9'
</span><span class="result ok">// ]
</span><span class="result ok">// }
</span>
<span class="comment">// List all token transfers *to* myAddress OR otherAddress:
</span>contract.filters.Transfer(null, [ myAddress, otherAddress ])
<span class="result ok">// {
</span><span class="result ok">// address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
</span><span class="result ok">// topics: [
</span><span class="result ok">// '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
</span><span class="result ok">// null,
</span><span class="result ok">// [
</span><span class="result ok">// '0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72',
</span><span class="result ok">// '0x000000000000000000000000ea517d5a070e6705cc5467858681ed953d285eb9'
</span><span class="result ok">// ]
</span><span class="result ok">// ]
</span><span class="result ok">// }
</span></div><a name="events-solidity"></a><a name="events--events-solidity"></a><h2 class="show-anchors"><div>Solidity Topics<div class="anchors"><a class="self" href="/v5/concepts/events/#events-solidity"></a></div></div></h2><p>This is a quick (and non-comprehensive) overview of how events are computed in Solidity.</p>
<p>This is likely out of the scope for most developers, but may be intersting to those who want to learn a bit more about the underlying technology.</p>
<p>Solidity provides two types of events, anonymous and non-anonymous. The default is non-anonymous, and most developers will not need to worry about anonymous events.</p>
<p>For non-anonymous events, up to 3 topics may be indexed (instead of 4), since the first topic is reserved to specify the event signature. This allows non-anonymous events to always be filtered by their event signature.</p>
<p>This topic hash is always in the first slot of the indexed data, and is computed by normalizing the Event signature and taking the keccak256 hash of it.</p>
<p>For anonymous events, up to 4 topics may be indexed, and there is no signature topic hash, so the events cannot be filtered by the event signature.</p>
<p>Each additional indexed property is processed depending on whether its length is fixed or dynamic.</p>
<p>For fixed length types (e.g. <code class="inline">uint</code>, <code class="inline">bytes5</code>), all of which are internally exactly 32 bytes (shorter types are padded with zeros; numeric values are padded on the left, data values padded on the right), these are included directly by their actual value, 32 bytes of data.</p>
<p>For dynamic types (e.g. <code class="inline">string</code>, <code class="inline">uint256[]</code>) , the value is hashed using keccak256 and this hash is used.</p>
<p>Because dynamic types are hashed, there are important consequences in parsing events that should be kept in mind. Mainly that the original value is lost in the event. So, it is possible to tell is a topic is equal to a given string, but if they do not match, there is no way to determine what the value was.</p>
<p>If a developer requires that a string value is required to be both able to be filtered and also able to be read, the value must be included in the signature twice, once indexed and once non-indexed (e.g. <code class="inline">someEvent(string indexed searchBy, string clearText)</code>).</p>
<p>For a more detailed description, please refer to the <a href="https://docs.soliditylang.org/en/v0.8.1/abi-spec.html#events">Solidity Event Documentation</a>.</p>
<a name="events--events-solidity--other-things-todo"></a><h3 class="show-anchors"><div>Other Things? TODO<div class="anchors"><a class="self" href="/v5/concepts/events/#events--events-solidity--other-things-todo"></a></div></div></h3><p>Explain what happens to strings and bytes, how to filter and retain the value</p>
<div class="footer">
<div class="nav previous"><a href="/v5/concepts/"><span class="arrow">&larr;</span>Ethereum Basics</a></div>
<div class="nav next"><a href="/v5/concepts/gas/">Gas<span class="arrow">&rarr;</span></a></div>
</div>
<div class="copyright">The content of this site is licensed under the <a href="https://choosealicense.com/licenses/cc-by-4.0/">Creative Commons License</a>. Generated on February 8, 2021, 3:25pm.</div>
</div>
<script src="/v5/static/script.js" type="text/javascript"></script>
<!--EXTRASCRIPT-->
</body>
</html>