96 lines
3.1 KiB
JavaScript
96 lines
3.1 KiB
JavaScript
const BaseFilter = require('./base-filter')
|
|
const { bnToHex, hexToInt, incrementHexInt, minBlockRef, blockRefIsNumber } = require('./hexUtils')
|
|
|
|
class LogFilter extends BaseFilter {
|
|
|
|
constructor ({ ethQuery, params }) {
|
|
super()
|
|
this.type = 'log'
|
|
this.ethQuery = ethQuery
|
|
this.params = Object.assign({
|
|
fromBlock: 'latest',
|
|
toBlock: 'latest',
|
|
address: undefined,
|
|
topics: [],
|
|
}, params)
|
|
// normalize address
|
|
if (this.params.address) this.params.address = this.params.address.toLowerCase()
|
|
}
|
|
|
|
async initialize({ currentBlock }) {
|
|
// resolve params.fromBlock
|
|
let fromBlock = this.params.fromBlock
|
|
if (['latest', 'pending'].includes(fromBlock)) fromBlock = currentBlock
|
|
if ('earliest' === fromBlock) fromBlock = '0x0'
|
|
this.params.fromBlock = fromBlock
|
|
// set toBlock for initial lookup
|
|
const toBlock = minBlockRef(this.params.toBlock, currentBlock)
|
|
const params = Object.assign({}, this.params, { toBlock })
|
|
// fetch logs and add to results
|
|
const newLogs = await this._fetchLogs(params)
|
|
this.addInitialResults(newLogs)
|
|
}
|
|
|
|
async update ({ oldBlock, newBlock }) {
|
|
// configure params for this update
|
|
const toBlock = newBlock
|
|
let fromBlock
|
|
// oldBlock is empty on first sync
|
|
if (oldBlock) {
|
|
fromBlock = incrementHexInt(oldBlock)
|
|
} else {
|
|
fromBlock = newBlock
|
|
}
|
|
// fetch logs
|
|
const params = Object.assign({}, this.params, { fromBlock, toBlock })
|
|
const newLogs = await this._fetchLogs(params)
|
|
const matchingLogs = newLogs.filter(log => this.matchLog(log))
|
|
|
|
// add to results
|
|
this.addResults(matchingLogs)
|
|
}
|
|
|
|
async _fetchLogs (params) {
|
|
const newLogs = await this.ethQuery.getLogs(params)
|
|
// de-BN ethQuery results
|
|
newLogs.forEach((log) => {
|
|
log.blockNumber = bnToHex(log.blockNumber)
|
|
log.logIndex = bnToHex(log.logIndex)
|
|
log.transactionIndex = bnToHex(log.transactionIndex)
|
|
})
|
|
// add to results
|
|
return newLogs
|
|
}
|
|
|
|
matchLog(log) {
|
|
// check if block number in bounds:
|
|
if (hexToInt(this.params.fromBlock) >= hexToInt(log.blockNumber)) return false
|
|
if (blockRefIsNumber(this.params.toBlock) && hexToInt(this.params.toBlock) <= hexToInt(log.blockNumber)) return false
|
|
|
|
// address is correct:
|
|
if (this.params.address && this.params.address !== log.address) return false
|
|
|
|
// topics match:
|
|
// topics are position-dependant
|
|
// topics can be nested to represent `or` [[a || b], c]
|
|
// topics can be null, representing a wild card for that position
|
|
const topicsMatch = this.params.topics.every((topicPattern, index) => {
|
|
// pattern is longer than actual topics
|
|
const logTopic = log.topics[index]
|
|
if (!logTopic) return false
|
|
// wild card
|
|
const subtopicsToMatch = Array.isArray(topicPattern) ? topicPattern : [topicPattern]
|
|
const subtopicsIncludeWildcard = subtopicsToMatch.includes(null)
|
|
if (subtopicsIncludeWildcard) return true
|
|
// check each possible matching topic
|
|
const topicDoesMatch = subtopicsToMatch.includes(logTopic)
|
|
return topicDoesMatch
|
|
})
|
|
|
|
return topicsMatch
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = LogFilter
|