Fixed log decoding. Dynamic structures were not decoding properly. Now uses AbiEncoder from utils package.

This commit is contained in:
Greg Hysen 2020-01-14 12:25:24 -08:00
parent ebd08d9c63
commit b3c3ec16e5
8 changed files with 84 additions and 50 deletions

View File

@ -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";

View File

@ -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";

View File

@ -17,6 +17,7 @@
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
contract MixinNonFungibleToken {
@ -64,7 +65,7 @@ contract MixinNonFungibleToken {
// A base type has the NF bit but does has an index.
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
}
/// @dev returns owner of a non-fungible token
function ownerOf(uint256 id) public view returns (address) {
return nfOwners[id];

View File

@ -17,13 +17,14 @@
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
/// @title ERC-1155 Multi Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
interface IERC1155 {
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
/// including zero value transfers as well as minting or burning.
/// Operator will always be msg.sender.

View File

@ -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";

View File

@ -17,10 +17,11 @@
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
interface IERC1155Receiver {
/// @notice Handle the receipt of a single ERC1155 token type
/// @dev The smart contract calls this function on the recipient
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the

View File

@ -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

View File

@ -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,58 +53,53 @@ 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.
// 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) {
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];
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 {
return {
...log,
event: event.name,
args: decodedParams,
};
decodedArgs[param.name] = value;
}
// Decoding was successful. Return decoded log.
return {
...log,
event: event.name,
args: decodedArgs as ArgsType,
};
}
/**
* Decodes calldata for a known ABI.