_section: Events Explain how topics and such work _subsection: Solidity Topics How to compute the topic... _subsection: Logs and Filtering Example hog logs are used. Link to provider.getLogs and contract.on _heading: Filters Filter are used as a way to query ... efficient, explain bloom filters lightly A filter may have up to 4 topic-sets, where each topic-set refers to a condition that must match the log topic in that position (i.e. each condition is ``AND``-ed together). If a topic-set is ``null``, a log topic in that position is not filtered at all and **any value** matches. If a topic-set is a single topic, a log topic in that position must match **that topic**. If a topic-set is an array of topics, a log topic in that position must match any **one** of the topics (i.e. the topic in this position are ``OR``-ed). _table: Example Log Matching @style $TopicABaCD: **[** (topic[0] = A) **OR** (topic[0] = B) **]** **AND** **[** (topic[1] = C) **OR** (topic[1] = D) **]** | **Topic-Sets** | **Matching Logs** <<| | [ A ] | topic[0] = A <<| | [ A, null ] | ^ | | [ null, B ] | topic[1] = B <<| | [ null, [ B ] ] | ^ | | [ null, [ B ], null ] | ^ | | [ A, B ] | (topic[0] = A) **AND** (topic[1] = B) <<| | [ A, [ B ] ] | ^ | | [ A, [ B ], null ] | ^ | | [ [ A, B ] ] | (topic[0] = A) **OR** (topic[0] = B) <<| | [ [ A, B ], null ] | ^ | | [ [ A, B ], [ C, D ] ] | $TopicABaCD <<| _code: ERC-20 Transfer Filter Examples @lang // const tokenAddress = ethers.constants.AddressZero; const myAddress = ethers.constants.AddressZero; const myOtherAddress = ethers.constants.AddressZero; const id = ethers.utils.id; const hexZeroPad = ethers.utils.hexZeroPad; // // Short example of manually creating filters for an ERC-20 // Transfer event. // // Most users should generally use the Contract API to // compute filters, as it is much simpler, but this is // provided as an illustration for those curious. See // below for examples of the equivalent Contract API. // ERC-20: // Transfer(address indexed src, address indexed dst, uint val) // // -------------------^ // ----------------------------------------^ // // Notice that only *src* and *dst* are *indexed*, so ONLY they // qualify for filtering. // // Also, note that in Solidity an Event uses the first topic to // identify the Event name; for Transfer this will be: // id("Transfer(address,address,uint256)") // // Other Notes: // - A topic must be 32 bytes; so shorter types must be padded // List all token transfers *from* myAddress filter = { address: tokenAddress, topics: [ id("Transfer(address,address,uint256)"), hexZeroPad(myAddress, 32) ] } // List all token transfers *to* myAddress: filter = { address: tokenAddress, topics: [ id("Transfer(address,address,uint256)"), null, hexZeroPad(myAddress, 32) ] } // List all token transfers *to* myAddress or myOtherAddress: filter = { address: tokenAddress, topics: [ id("Transfer(address,address,uint256)"), null, [ hexZeroPad(myAddress, 32), hexZeroPad(myOtherAddress, 32), ] ] } _null: To simplify life, ..., explain here, the contract API _code: ERC-20 Contract Filter Examples @lang // const tokenAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; // DAI const myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72"; const otherAddress = "0xEA517D5a070e6705Cc5467858681Ed953d285Eb9"; const provider = ethers.getDefaultProvider(); const Contract = ethers.Contract; // const abi = [ "event Transfer(address indexed src, address indexed dst, uint val)" ]; const contract = new Contract(tokenAddress, abi, provider); // List all token transfers *from* myAddress contract.filters.Transfer(myAddress) //! // List all token transfers *to* myAddress: contract.filters.Transfer(null, myAddress) //! // List all token transfers *from* myAddress *to* otherAddress: contract.filters.Transfer(myAddress, otherAddress) //! // List all token transfers *to* myAddress OR otherAddress: contract.filters.Transfer(null, [ myAddress, otherAddress ]) //! _heading: Other Things? TODO Explain what happens to strings and bytes, how to filter and retain the value