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 solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibAddress.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 solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
import "./ERC1155.sol";
|
import "./ERC1155.sol";
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
contract MixinNonFungibleToken {
|
contract MixinNonFungibleToken {
|
||||||
@ -64,7 +65,7 @@ contract MixinNonFungibleToken {
|
|||||||
// A base type has the NF bit but does has an index.
|
// 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);
|
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev returns owner of a non-fungible token
|
/// @dev returns owner of a non-fungible token
|
||||||
function ownerOf(uint256 id) public view returns (address) {
|
function ownerOf(uint256 id) public view returns (address) {
|
||||||
return nfOwners[id];
|
return nfOwners[id];
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
/// @title ERC-1155 Multi Token Standard
|
/// @title ERC-1155 Multi Token Standard
|
||||||
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
|
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
|
||||||
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
|
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
|
||||||
interface IERC1155 {
|
interface IERC1155 {
|
||||||
|
|
||||||
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
|
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
|
||||||
/// including zero value transfers as well as minting or burning.
|
/// including zero value transfers as well as minting or burning.
|
||||||
/// Operator will always be msg.sender.
|
/// Operator will always be msg.sender.
|
||||||
|
@ -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 solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./IERC1155.sol";
|
import "./IERC1155.sol";
|
||||||
|
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
interface IERC1155Receiver {
|
interface IERC1155Receiver {
|
||||||
|
|
||||||
/// @notice Handle the receipt of a single ERC1155 token type
|
/// @notice Handle the receipt of a single ERC1155 token type
|
||||||
/// @dev The smart contract calls this function on the recipient
|
/// @dev The smart contract calls this function on the recipient
|
||||||
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||||
|
@ -139,8 +139,8 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
|||||||
expect(actual[13]).to.be.eq(expected.takerFeeAssetData);
|
expect(actual[13]).to.be.eq(expected.takerFeeAssetData);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('fillOrKillOrder', () => {
|
describe.only('fillOrKillOrder', () => {
|
||||||
it('works if the order is filled by exactly `takerAssetFillAmount`', async () => {
|
it.only('works if the order is filled by exactly `takerAssetFillAmount`', async () => {
|
||||||
const fillAmount = randomAmount();
|
const fillAmount = randomAmount();
|
||||||
const order = randomOrder({
|
const order = randomOrder({
|
||||||
// `_fillOrder()` is overridden to always return `order.takerAssetAmount` as
|
// `_fillOrder()` is overridden to always return `order.takerAssetAmount` as
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
import {
|
import {
|
||||||
AbiDefinition,
|
AbiDefinition,
|
||||||
AbiType,
|
AbiType,
|
||||||
|
DataItem,
|
||||||
DecodedLogArgs,
|
DecodedLogArgs,
|
||||||
EventAbi,
|
EventAbi,
|
||||||
EventParameter,
|
|
||||||
LogEntry,
|
LogEntry,
|
||||||
LogWithDecodedArgs,
|
LogWithDecodedArgs,
|
||||||
MethodAbi,
|
MethodAbi,
|
||||||
RawLog,
|
RawLog,
|
||||||
SolidityTypes,
|
|
||||||
} from 'ethereum-types';
|
} from 'ethereum-types';
|
||||||
import * as ethers from 'ethers';
|
import * as ethers from 'ethers';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { AbiEncoder } from '.';
|
import { AbiEncoder } from '.';
|
||||||
import { addressUtils } from './address_utils';
|
|
||||||
import { BigNumber } from './configured_bignumber';
|
|
||||||
import { DecodedCalldata, SelectorToFunctionInfo } from './types';
|
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.
|
* @return The decoded log if the requisite ABI was available. Otherwise the log unaltered.
|
||||||
*/
|
*/
|
||||||
public tryToDecodeLogOrNoop<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
|
public tryToDecodeLogOrNoop<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||||
|
// Lookup event corresponding to log
|
||||||
const eventId = log.topics[0];
|
const eventId = log.topics[0];
|
||||||
const numIndexedArgs = log.topics.length - 1;
|
const numIndexedArgs = log.topics.length - 1;
|
||||||
if (this._eventIds[eventId] === undefined || this._eventIds[eventId][numIndexedArgs] === undefined) {
|
if (this._eventIds[eventId] === undefined || this._eventIds[eventId][numIndexedArgs] === undefined) {
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
const event = this._eventIds[eventId][numIndexedArgs];
|
const event = this._eventIds[eventId][numIndexedArgs];
|
||||||
const ethersInterface = new ethers.utils.Interface([event]);
|
|
||||||
const decodedParams: DecodedLogArgs = {};
|
|
||||||
let topicsIndex = 1;
|
|
||||||
|
|
||||||
let decodedData: any[];
|
// Create decoders for indexed data
|
||||||
try {
|
const indexedDataDecoders = _.mapValues(_.filter(event.inputs, { indexed: true }), input =>
|
||||||
decodedData = ethersInterface.events[event.name].decode(log.data);
|
// tslint:disable:next-line no-unnecessary-type-assertion
|
||||||
} catch (error) {
|
AbiEncoder.create(input as DataItem),
|
||||||
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
|
// Decode indexed data
|
||||||
// does not match our ABI. If that's the case, then ethers will throw an error
|
const decodedIndexedData = _.map(
|
||||||
// when we try to parse the event. We handle that case here by returning the log rather
|
log.topics.slice(1), // ignore first topic, which is the event id.
|
||||||
// than throwing an error.
|
(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;
|
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) {
|
decodedArgs[param.name] = value;
|
||||||
return log;
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...log,
|
|
||||||
event: event.name,
|
|
||||||
args: decodedParams,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decoding was successful. Return decoded log.
|
||||||
|
return {
|
||||||
|
...log,
|
||||||
|
event: event.name,
|
||||||
|
args: decodedArgs as ArgsType,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Decodes calldata for a known ABI.
|
* Decodes calldata for a known ABI.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user