remix-project mirror
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
remix-project/libs/remix-lib/src/execution/eventsDecoder.ts

111 lines
3.2 KiB

'use strict'
import { ethers } from 'ethers'
import { visitContracts } from './txHelper'
/**
* Register to txListener and extract events
*
*/
export class EventsDecoder {
resolveReceipt
constructor ({resolveReceipt}) {
this.resolveReceipt = resolveReceipt
}
/**
* use Transaction Receipt to decode logs. assume that the transaction as already been resolved by txListener.
* logs are decoded only if the contract if known by remix.
*
* @param {Object} tx - transaction object
* @param {Function} cb - callback
*/
parseLogs (tx, contractName, compiledContracts, cb) {
if (tx.isCall) return cb(null, { decoded: [], raw: [] })
this.resolveReceipt(tx, (error, receipt) => {
if (error) return cb(error)
this._decodeLogs(tx, receipt, contractName, compiledContracts, cb)
})
}
_decodeLogs (tx, receipt, contract, contracts, cb) {
if (!contract || !receipt) {
return cb('cannot decode logs - contract or receipt not resolved ')
}
if (!receipt.logs) {
return cb(null, { decoded: [], raw: [] })
}
this._decodeEvents(tx, receipt.logs, contract, contracts, cb)
}
_eventABI (contract) {
const eventABI = {}
const abi = new ethers.utils.Interface(contract.abi)
for (let e in abi.events) {
const event = abi.getEvent(e)
eventABI[abi.getEventTopic(e).replace('0x', '')] = { event: event.name, inputs: event.inputs, object: event, abi: abi }
}
return eventABI
}
_eventsABI (compiledContracts) {
const eventsABI = {}
visitContracts(compiledContracts, (contract) => {
eventsABI[contract.name] = this._eventABI(contract.object)
})
return eventsABI
}
_event (hash, eventsABI) {
for (let k in eventsABI) {
if (eventsABI[k][hash]) {
let event = eventsABI[k][hash]
for (let input of event.inputs) {
if (input.type === 'function') {
input.type = 'bytes24'
input.baseType = 'bytes24'
}
}
return event
}
}
return null
}
_stringifyBigNumber (value) {
return value._isBigNumber ? value.toString() : value
}
_stringifyEvent (value) {
if (value === null || value === undefined) return ' - '
if (value._ethersType) value.type = value._ethersType
if (Array.isArray(value)) {
// for struct && array
return value.map((item) => { return this._stringifyEvent(item) })
} else {
return this._stringifyBigNumber(value)
}
}
_decodeEvents (tx, logs, contractName, compiledContracts, cb) {
const eventsABI = this._eventsABI(compiledContracts)
const events = []
for (let i in logs) {
// [address, topics, mem]
const log = logs[i]
const topicId = log.topics[0]
const eventAbi = this._event(topicId.replace('0x', ''), eventsABI)
if (eventAbi) {
const decodedlog = eventAbi.abi.parseLog(log)
const decoded = {}
for (const v in decodedlog.args) {
decoded[v] = this._stringifyEvent(decodedlog.args[v])
}
events.push({ from: log.address, topic: topicId, event: eventAbi.event, args: decoded })
} else {
events.push({ from: log.address, data: log.data, topics: log.topics })
}
}
cb(null, { decoded: events, raw: logs })
}
}