Fixed log decoding. Dynamic structures were not decoding properly. Now uses AbiEncoder from utils
package.
This commit is contained in:
parent
ebd08d9c63
commit
b3c3ec16e5
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddress.sol";
|
||||
|
@ -1,4 +1,23 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./ERC1155.sol";
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract MixinNonFungibleToken {
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
/// @title ERC-1155 Multi Token Standard
|
||||
|
@ -1,4 +1,23 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./IERC1155.sol";
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
interface IERC1155Receiver {
|
||||
|
@ -139,8 +139,8 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
expect(actual[13]).to.be.eq(expected.takerFeeAssetData);
|
||||
}
|
||||
|
||||
describe('fillOrKillOrder', () => {
|
||||
it('works if the order is filled by exactly `takerAssetFillAmount`', async () => {
|
||||
describe.only('fillOrKillOrder', () => {
|
||||
it.only('works if the order is filled by exactly `takerAssetFillAmount`', async () => {
|
||||
const fillAmount = randomAmount();
|
||||
const order = randomOrder({
|
||||
// `_fillOrder()` is overridden to always return `order.takerAssetAmount` as
|
||||
|
@ -1,21 +1,18 @@
|
||||
import {
|
||||
AbiDefinition,
|
||||
AbiType,
|
||||
DataItem,
|
||||
DecodedLogArgs,
|
||||
EventAbi,
|
||||
EventParameter,
|
||||
LogEntry,
|
||||
LogWithDecodedArgs,
|
||||
MethodAbi,
|
||||
RawLog,
|
||||
SolidityTypes,
|
||||
} from 'ethereum-types';
|
||||
import * as ethers from 'ethers';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AbiEncoder } from '.';
|
||||
import { addressUtils } from './address_utils';
|
||||
import { BigNumber } from './configured_bignumber';
|
||||
import { DecodedCalldata, SelectorToFunctionInfo } from './types';
|
||||
|
||||
/**
|
||||
@ -56,59 +53,54 @@ export class AbiDecoder {
|
||||
* @return The decoded log if the requisite ABI was available. Otherwise the log unaltered.
|
||||
*/
|
||||
public tryToDecodeLogOrNoop<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||
// Lookup event corresponding to log
|
||||
const eventId = log.topics[0];
|
||||
const numIndexedArgs = log.topics.length - 1;
|
||||
if (this._eventIds[eventId] === undefined || this._eventIds[eventId][numIndexedArgs] === undefined) {
|
||||
return log;
|
||||
}
|
||||
const event = this._eventIds[eventId][numIndexedArgs];
|
||||
const ethersInterface = new ethers.utils.Interface([event]);
|
||||
const decodedParams: DecodedLogArgs = {};
|
||||
let topicsIndex = 1;
|
||||
|
||||
let decodedData: any[];
|
||||
try {
|
||||
decodedData = ethersInterface.events[event.name].decode(log.data);
|
||||
} catch (error) {
|
||||
if (error.code === ethers.errors.INVALID_ARGUMENT) {
|
||||
// Because we index events by Method ID, and Method IDs are derived from the method
|
||||
// name and the input parameters, it's possible that the return value of the event
|
||||
// does not match our ABI. If that's the case, then ethers will throw an error
|
||||
// when we try to parse the event. We handle that case here by returning the log rather
|
||||
// than throwing an error.
|
||||
return log;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
let didFailToDecode = false;
|
||||
_.forEach(event.inputs, (param: EventParameter, i: number) => {
|
||||
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
||||
let value: BigNumber | string | number = param.indexed ? log.topics[topicsIndex++] : decodedData[i];
|
||||
// Create decoders for indexed data
|
||||
const indexedDataDecoders = _.mapValues(_.filter(event.inputs, { indexed: true }), input =>
|
||||
// tslint:disable:next-line no-unnecessary-type-assertion
|
||||
AbiEncoder.create(input as DataItem),
|
||||
);
|
||||
|
||||
// Decode indexed data
|
||||
const decodedIndexedData = _.map(
|
||||
log.topics.slice(1), // ignore first topic, which is the event id.
|
||||
(input, i) => indexedDataDecoders[i].decode(input),
|
||||
);
|
||||
|
||||
// Decode non-indexed data
|
||||
const decodedNonIndexedData = AbiEncoder.create(_.filter(event.inputs, { indexed: false })).decodeAsArray(
|
||||
log.data,
|
||||
);
|
||||
|
||||
// Construct DecodedLogArgs struct by mapping event parameters to their respective decoded argument.
|
||||
const decodedArgs: DecodedLogArgs = {};
|
||||
let indexedOffset = 0;
|
||||
let nonIndexedOffset = 0;
|
||||
for (const param of event.inputs) {
|
||||
const value = param.indexed
|
||||
? decodedIndexedData[indexedOffset++]
|
||||
: decodedNonIndexedData[nonIndexedOffset++];
|
||||
|
||||
if (value === undefined) {
|
||||
didFailToDecode = true;
|
||||
return;
|
||||
}
|
||||
if (param.type === SolidityTypes.Address) {
|
||||
const baseHex = 16;
|
||||
value = addressUtils.padZeros(new BigNumber((value as string).toLowerCase()).toString(baseHex));
|
||||
} else if (param.type === SolidityTypes.Uint256 || param.type === SolidityTypes.Uint) {
|
||||
value = new BigNumber(value);
|
||||
} else if (param.type === SolidityTypes.Uint8) {
|
||||
value = new BigNumber(value).toNumber();
|
||||
}
|
||||
decodedParams[param.name] = value;
|
||||
});
|
||||
|
||||
if (didFailToDecode) {
|
||||
return log;
|
||||
} else {
|
||||
}
|
||||
|
||||
decodedArgs[param.name] = value;
|
||||
}
|
||||
|
||||
// Decoding was successful. Return decoded log.
|
||||
return {
|
||||
...log,
|
||||
event: event.name,
|
||||
args: decodedParams,
|
||||
args: decodedArgs as ArgsType,
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Decodes calldata for a known ABI.
|
||||
* @param calldata hex-encoded calldata.
|
||||
|
Loading…
x
Reference in New Issue
Block a user