Skip to content

Commit

Permalink
Merge pull request #4 from decentraliser/multiple
Browse files Browse the repository at this point in the history
handle multiple events with the same normalized form
  • Loading branch information
decentraliser authored Apr 26, 2021
2 parents ce30d91 + 5dd3808 commit 0b8325f
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 66 deletions.
144 changes: 78 additions & 66 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class LogsDecoder {
")"
);
if (abi.type === "event") {
this.methodIDs[signature.slice(2)] = abi;
if(!this.methodIDs[signature.slice(2)]){
this.methodIDs[signature.slice(2)] = [];
}
this.methodIDs[signature.slice(2)].push(abi);
} else {
this.methodIDs[signature.slice(2, 10)] = abi;
}
Expand Down Expand Up @@ -131,82 +134,91 @@ class LogsDecoder {
decodeLogs(logs) {
return logs.filter(log => log.topics.length > 0).map((logItem) => {
const methodID = logItem.topics[0].slice(2);
const method = this.methodIDs[methodID];
if (method) {
const logData = logItem.data;
let decodedParams = [];
let dataIndex = 0;
let topicsIndex = 1;

let dataTypes = [];
method.inputs.map((input) => {
if (!input.indexed) {
if(input.type === "tuple") {
dataTypes.push("tuple" + this.typeToString(input) );
} else {
dataTypes.push(input);
}
}
});
const methods = this.methodIDs[methodID];

const decodedData = abiCoder.decodeParameters(
dataTypes,
logData.slice(2)
);

// Loop topic and data to get the params
method.inputs.map(function(param) {
let decodedP = {
name: param.name,
type: param.type,
};

if (param.indexed) {
decodedP.value = logItem.topics[topicsIndex];
topicsIndex++;
if (methods) {
return methods.map(method=>this.tryDecodeLogs(method, logItem)).filter(data=>data!==null)[0];
}
});
}

tryDecodeLogs(method, logItem) {
try {
const logData = logItem.data;
let decodedParams = [];
let dataIndex = 0;
let topicsIndex = 1;

let dataTypes = [];
method.inputs.map((input) => {
if (!input.indexed) {
if(input.type === "tuple") {
dataTypes.push("tuple" + this.typeToString(input) );
} else {
decodedP.value = decodedData[dataIndex];
dataIndex++;
dataTypes.push(input);
}
}
});

const decodedData = abiCoder.decodeParameters(
dataTypes,
logData.slice(2)
);

// Loop topic and data to get the params
method.inputs.map(function(param) {
let decodedP = {
name: param.name,
type: param.type,
};

if (param.type === "address") {
decodedP.value = decodedP.value.toLowerCase();
// 42 because len(0x) + 40
if (decodedP.value.length > 42) {
let toRemove = decodedP.value.length - 42;
let temp = decodedP.value.split("");
temp.splice(2, toRemove);
decodedP.value = temp.join("");
}
if (param.indexed) {
decodedP.value = logItem.topics[topicsIndex];
topicsIndex++;
} else {
decodedP.value = decodedData[dataIndex];
dataIndex++;
}

if (param.type === "address") {
decodedP.value = decodedP.value.toLowerCase();
// 42 because len(0x) + 40
if (decodedP.value.length > 42) {
let toRemove = decodedP.value.length - 42;
let temp = decodedP.value.split("");
temp.splice(2, toRemove);
decodedP.value = temp.join("");
}
}

if (
param.type === "uint256" ||
if (
param.type === "uint256" ||
param.type === "uint8" ||
param.type === "int"
) {
// ensure to remove leading 0x for hex numbers
if (typeof decodedP.value === "string" && decodedP.value.startsWith("0x")) {
decodedP.value = new BN(decodedP.value.slice(2), 16).toString(10);
} else {
decodedP.value = new BN(decodedP.value).toString(10);
}

) {
// ensure to remove leading 0x for hex numbers
if (typeof decodedP.value === "string" && decodedP.value.startsWith("0x")) {
decodedP.value = new BN(decodedP.value.slice(2), 16).toString(10);
} else {
decodedP.value = new BN(decodedP.value).toString(10);
}

decodedParams.push(decodedP);
});
}

return {
name: method.name,
events: decodedParams,
address: logItem.address,
transactionHash: logItem.transactionHash,
blockNumber: String(hexToNumber(logItem.blockNumber)),
blockHash: logItem.blockHash,
};
}
});
decodedParams.push(decodedP);
});

return {
name: method.name,
events: decodedParams,
address: logItem.address,
transactionHash: logItem.transactionHash,
blockNumber: String(hexToNumber(logItem.blockNumber)),
blockHash: logItem.blockHash,
};
} catch (error) {
return null;
}
}

typeToString(input) {
Expand Down
42 changes: 42 additions & 0 deletions test/mocks/transferWithAllIndexed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const logs = [{
address: "0xecf7ef42b57ee37a959bf507183c5dd6bf182081",
topics: [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000c24d112c58a87c17a0484b2a7d8fd69e1b625ccf",
"0x0000000000000000000000004bbb41f61fffc1bbe65a2aa192c65281e16ea758",
"0x000000000000000000000000000000000000000000000000000000000000006e",
],
data: "0x",
blockNumber: "0xba6a96",
transactionHash: "0xe4c14eeb82e9274c41b3cc70aa8563faa8fe070c82ba2bbff25a8aeeaeaf96eb",
transactionIndex: "0x80",
blockHash: "0x9142c80814a627cee5e7f8cae044ae020e1c756fd83c3cee92fdfeec958f2f5d",
logIndex: "0xc2",
removed: false,
}];

const expectedDecodedLogs = [
{
name: "Transfer",
events: [
{
name: "from",
type: "address",
value: "0xc24d112c58a87c17a0484b2a7d8fd69e1b625ccf",
},
{
name: "to",
type: "address",
value: "0x4bbb41f61fffc1bbe65a2aa192c65281e16ea758",
},
{ name: "tokenId", type: "uint256", value: "110" },
],
address: "0xecf7ef42b57ee37a959bf507183c5dd6bf182081",
blockNumber: "12216982",
transactionHash: "0xe4c14eeb82e9274c41b3cc70aa8563faa8fe070c82ba2bbff25a8aeeaeaf96eb",
blockHash: "0x9142c80814a627cee5e7f8cae044ae020e1c756fd83c3cee92fdfeec958f2f5d",
}

];

module.exports = { logs, expectedDecodedLogs };
39 changes: 39 additions & 0 deletions test/mocks/transferWithNothingIndexed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const logs = [
{
address: "0x7fdcd2a1e52f10c28cb7732f46393e297ecadda1",
topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
data:
"0x000000000000000000000000e8a3137e1d499797ea5a520a98b1b4af753f3ca80000000000000000000000000239769a1adf4def9f07da824b80b9c4fcb595930000000000000000000000000000000000000000000000000000000000000508",
blockNumber: "0x5b7d9c",
transactionHash: "0x0d541dce966c0f7ff8148f3d6ccda542d0c4ffbc61827d2f4097716189675073",
transactionIndex: "0x6d",
blockHash: "0x73ea90f3ddb9e20d93e77063419836fd7e34619aecac1ab6d1cf21763f2168a1",
logIndex: "0x3d",
removed: false,
}
];

const expectedDecodedLogs = [
{
name: "Transfer",
events: [
{
name: "from",
type: "address",
value: "0xe8a3137e1d499797ea5a520a98b1b4af753f3ca8"
},
{
name: "to",
type: "address",
value: "0x0239769a1adf4def9f07da824b80b9c4fcb59593"
},
{ name: "tokenId", type: "uint256", value: "1288" }
],
address: "0x7fdcd2a1e52f10c28cb7732f46393e297ecadda1",
transactionHash: "0x0d541dce966c0f7ff8148f3d6ccda542d0c4ffbc61827d2f4097716189675073",
blockNumber: "5995932",
blockHash: "0x73ea90f3ddb9e20d93e77063419836fd7e34619aecac1ab6d1cf21763f2168a1"
}
];

module.exports = { logs, expectedDecodedLogs };
43 changes: 43 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const testABI = [{"inputs": [{"type": "address", "name": ""}], "constant": true,
const testArrNumbersABI = [{"constant":false,"inputs":[{"name":"n","type":"uint256[]"}],"name":"numbers","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}];
const abiV2 = [{"constant":false,"inputs":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"bytes","name":"encodedFunction","type":"bytes"}],"internalType":"struct EIP712Sig.CallData","name":"callData","type":"tuple"},{"components":[{"internalType":"address","name":"senderAccount","type":"address"},{"internalType":"uint256","name":"senderNonce","type":"uint256"},{"internalType":"address","name":"relayAddress","type":"address"},{"internalType":"uint256","name":"pctRelayFee","type":"uint256"}],"internalType":"struct EIP712Sig.RelayData","name":"relayData","type":"tuple"}],"internalType":"struct EIP712Sig.RelayRequest","name":"relayRequest","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"approvalData","type":"bytes"}],"name":"relayCall","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}];

// Mocks
const transferWithAllIndexed = require("./mocks/transferWithAllIndexed");
const transferWithNothingIndexed = require("./mocks/transferWithNothingIndexed");

// Instantiate a decoder
const logsDecoder = LogsDecoder.create();

describe("abi decoder", function () {
Expand Down Expand Up @@ -202,4 +207,42 @@ describe("abi decoder", function () {
expect(decodedLogs[0].events[0].value[1]).to.be.equal("fire-event");
expect(decodedLogs[0].events[0].type).to.equal("tuple");
});

it("Can decode events with same signatures but different indexed values", function() {
const decoder = LogsDecoder.create();

decoder.addABI([ {
anonymous: false,
inputs: [
{ indexed: true, name: "from", type: "address" },
{ indexed: true, name: "to", type: "address" },
{ indexed: true, name: "tokenId", type: "uint256" },
],
name: "Transfer",
type: "event",
}]);

const abis = decoder.getABIs();
expect(abis).to.be.an("array");
expect(abis).to.have.length(1);
expect(decoder.decodeLogs(transferWithAllIndexed.logs)).to.deep.equal(transferWithAllIndexed.expectedDecodedLogs);
expect(decoder.decodeLogs(transferWithNothingIndexed.logs)).to.deep.equal([ undefined ]);

decoder.addABI([{
anonymous: false,
inputs: [
{ indexed: false, name: "from", type: "address" },
{ indexed: false, name: "to", type: "address" },
{ indexed: false, name: "tokenId", type: "uint256" },
],
name: "Transfer",
type: "event",
}]);

const updatedAbis = decoder.getABIs();
expect(updatedAbis).to.be.an("array");
expect(updatedAbis).to.have.length(2);
expect(decoder.decodeLogs(transferWithAllIndexed.logs)).to.deep.equal(transferWithAllIndexed.expectedDecodedLogs);
expect(decoder.decodeLogs(transferWithNothingIndexed.logs)).to.deep.equal(transferWithNothingIndexed.expectedDecodedLogs);
});
});

0 comments on commit 0b8325f

Please sign in to comment.