Improvements and conventions in utils package + abi decoder
This commit is contained in:
parent
6d0dc47157
commit
500b4940a3
@ -1,6 +1,12 @@
|
|||||||
export { ContractAddresses } from '@0x/contract-addresses';
|
export { ContractAddresses } from '@0x/contract-addresses';
|
||||||
|
|
||||||
export { assetDataUtils, signatureUtils, generatePseudoRandomSalt, orderHashUtils } from '@0x/order-utils';
|
export {
|
||||||
|
assetDataUtils,
|
||||||
|
signatureUtils,
|
||||||
|
generatePseudoRandomSalt,
|
||||||
|
orderHashUtils,
|
||||||
|
transactionHashUtils,
|
||||||
|
} from '@0x/order-utils';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ContractWrappers,
|
ContractWrappers,
|
||||||
@ -68,7 +74,7 @@ export {
|
|||||||
MetamaskSubprovider,
|
MetamaskSubprovider,
|
||||||
} from '@0x/subproviders';
|
} from '@0x/subproviders';
|
||||||
|
|
||||||
export { AbiDecoder, TransactionData } from '@0x/utils';
|
export { AbiDecoder, DecodedCalldata } from '@0x/utils';
|
||||||
|
|
||||||
export { BigNumber } from '@0x/utils';
|
export { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
@ -92,6 +98,8 @@ export {
|
|||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
Stats,
|
Stats,
|
||||||
DutchAuctionDetails,
|
DutchAuctionDetails,
|
||||||
|
ZeroExTransaction,
|
||||||
|
SignedZeroExTransaction,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -172,8 +172,8 @@ export class ContractWrappers {
|
|||||||
return this._web3Wrapper.getProvider();
|
return this._web3Wrapper.getProvider();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the provider instance currently used by contract-wrappers
|
* Get the abi decoder instance currently used by contract-wrappers
|
||||||
* @return Web3 provider instance
|
* @return AbiDecoder instance
|
||||||
*/
|
*/
|
||||||
public getAbiDecoder(): AbiDecoder {
|
public getAbiDecoder(): AbiDecoder {
|
||||||
return this._web3Wrapper.abiDecoder;
|
return this._web3Wrapper.abiDecoder;
|
||||||
|
@ -38,7 +38,7 @@ export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper';
|
|||||||
|
|
||||||
export { TransactionEncoder } from './utils/transaction_encoder';
|
export { TransactionEncoder } from './utils/transaction_encoder';
|
||||||
|
|
||||||
export { AbiDecoder, TransactionData } from '@0x/utils';
|
export { AbiDecoder, DecodedCalldata } from '@0x/utils';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ContractWrappersError,
|
ContractWrappersError,
|
||||||
|
@ -248,8 +248,8 @@ export class TransactionEncoder {
|
|||||||
* @return Hex encoded abi of the function call.
|
* @return Hex encoded abi of the function call.
|
||||||
*/
|
*/
|
||||||
public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string {
|
public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string {
|
||||||
assert.doesConformToSchema('order', leftOrder, schemas.orderSchema);
|
assert.doesConformToSchema('leftOrder', leftOrder, schemas.orderSchema);
|
||||||
assert.doesConformToSchema('order', rightOrder, schemas.orderSchema);
|
assert.doesConformToSchema('rightOrder', rightOrder, schemas.orderSchema);
|
||||||
const abiEncodedData = this._getExchangeContract().matchOrders.getABIEncodedTransactionData(
|
const abiEncodedData = this._getExchangeContract().matchOrders.getABIEncodedTransactionData(
|
||||||
leftOrder,
|
leftOrder,
|
||||||
rightOrder,
|
rightOrder,
|
||||||
|
@ -33,12 +33,12 @@ describe('ABI Decoding Calldata', () => {
|
|||||||
before(async () => {
|
before(async () => {
|
||||||
// Create accounts
|
// Create accounts
|
||||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
const [makerAddressLeft, makerAddressRight] = accounts.slice(0, 2);
|
const [makerAddressLeft, makerAddressRight] = accounts;
|
||||||
|
const [privateKeyLeft, privateKeyRight] = constants.TESTRPC_PRIVATE_KEYS;
|
||||||
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
|
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
|
||||||
const feeRecipientAddress = addressUtils.generatePseudoRandomAddress();
|
const feeRecipientAddress = addressUtils.generatePseudoRandomAddress();
|
||||||
const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
|
// Create orders to match.
|
||||||
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
|
// Values are arbitrary, with the exception of maker addresses (generated above).
|
||||||
// Create orders to match
|
|
||||||
orderLeft = {
|
orderLeft = {
|
||||||
makerAddress: makerAddressLeft,
|
makerAddress: makerAddressLeft,
|
||||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||||
@ -87,7 +87,9 @@ describe('ABI Decoding Calldata', () => {
|
|||||||
describe('decode', () => {
|
describe('decode', () => {
|
||||||
it('should successfully decode DutchAuction.matchOrders calldata', async () => {
|
it('should successfully decode DutchAuction.matchOrders calldata', async () => {
|
||||||
const contractName = 'DutchAuction';
|
const contractName = 'DutchAuction';
|
||||||
const decodedTxData = contractWrappers.getAbiDecoder().tryDecodeCalldata(matchOrdersTxData, contractName);
|
const decodedTxData = contractWrappers
|
||||||
|
.getAbiDecoder()
|
||||||
|
.decodeCalldataOrThrow(matchOrdersTxData, contractName);
|
||||||
const expectedFunctionName = 'matchOrders';
|
const expectedFunctionName = 'matchOrders';
|
||||||
const expectedFunctionArguments = {
|
const expectedFunctionArguments = {
|
||||||
buyOrder: orderLeft,
|
buyOrder: orderLeft,
|
||||||
@ -101,7 +103,9 @@ describe('ABI Decoding Calldata', () => {
|
|||||||
});
|
});
|
||||||
it('should successfully decode Exchange.matchOrders calldata (and distinguish from DutchAuction.matchOrders)', async () => {
|
it('should successfully decode Exchange.matchOrders calldata (and distinguish from DutchAuction.matchOrders)', async () => {
|
||||||
const contractName = 'Exchange';
|
const contractName = 'Exchange';
|
||||||
const decodedTxData = contractWrappers.getAbiDecoder().tryDecodeCalldata(matchOrdersTxData, contractName);
|
const decodedTxData = contractWrappers
|
||||||
|
.getAbiDecoder()
|
||||||
|
.decodeCalldataOrThrow(matchOrdersTxData, contractName);
|
||||||
const expectedFunctionName = 'matchOrders';
|
const expectedFunctionName = 'matchOrders';
|
||||||
const expectedFunctionArguments = {
|
const expectedFunctionArguments = {
|
||||||
leftOrder: orderLeft,
|
leftOrder: orderLeft,
|
||||||
@ -116,7 +120,7 @@ describe('ABI Decoding Calldata', () => {
|
|||||||
it('should throw if cannot decode calldata', async () => {
|
it('should throw if cannot decode calldata', async () => {
|
||||||
const badTxData = '0x01020304';
|
const badTxData = '0x01020304';
|
||||||
expect(() => {
|
expect(() => {
|
||||||
contractWrappers.getAbiDecoder().tryDecodeCalldata(badTxData);
|
contractWrappers.getAbiDecoder().decodeCalldataOrThrow(badTxData);
|
||||||
}).to.throw("No functions registered for selector '0x01020304'");
|
}).to.throw("No functions registered for selector '0x01020304'");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -16,7 +16,7 @@ import * as _ from 'lodash';
|
|||||||
import { AbiEncoder } from '.';
|
import { AbiEncoder } from '.';
|
||||||
import { addressUtils } from './address_utils';
|
import { addressUtils } from './address_utils';
|
||||||
import { BigNumber } from './configured_bignumber';
|
import { BigNumber } from './configured_bignumber';
|
||||||
import { FunctionInfoBySelector, TransactionData } from './types';
|
import { DecodedCalldata, SelectorToFunctionInfo } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AbiDecoder allows you to decode event logs given a set of supplied contract ABI's. It takes the contract's event
|
* AbiDecoder allows you to decode event logs given a set of supplied contract ABI's. It takes the contract's event
|
||||||
@ -24,17 +24,17 @@ import { FunctionInfoBySelector, TransactionData } from './types';
|
|||||||
*/
|
*/
|
||||||
export class AbiDecoder {
|
export class AbiDecoder {
|
||||||
private readonly _eventIds: { [signatureHash: string]: { [numIndexedArgs: number]: EventAbi } } = {};
|
private readonly _eventIds: { [signatureHash: string]: { [numIndexedArgs: number]: EventAbi } } = {};
|
||||||
private readonly _functionInfoBySelector: FunctionInfoBySelector = {};
|
private readonly _selectorToFunctionInfo: SelectorToFunctionInfo = {};
|
||||||
/**
|
/**
|
||||||
* Retrieves the function selector from tranasction data.
|
* Retrieves the function selector from calldata.
|
||||||
* @param calldata hex-encoded transaction data.
|
* @param calldata hex-encoded calldata.
|
||||||
* @return hex-encoded function selector.
|
* @return hex-encoded function selector.
|
||||||
*/
|
*/
|
||||||
private static _getFunctionSelector(calldata: string): string {
|
private static _getFunctionSelector(calldata: string): string {
|
||||||
const functionSelectorLength = 10;
|
const functionSelectorLength = 10;
|
||||||
if (!calldata.startsWith('0x') || calldata.length < functionSelectorLength) {
|
if (!calldata.startsWith('0x') || calldata.length < functionSelectorLength) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Malformed transaction data. Must include a hex prefix '0x' and 4-byte function selector. Got '${calldata}'`,
|
`Malformed calldata. Must include a hex prefix '0x' and 4-byte function selector. Got '${calldata}'`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const functionSelector = calldata.substr(0, functionSelectorLength);
|
const functionSelector = calldata.substr(0, functionSelectorLength);
|
||||||
@ -56,12 +56,12 @@ 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 {
|
||||||
const methodId = log.topics[0];
|
const eventId = log.topics[0];
|
||||||
const numIndexedArgs = log.topics.length - 1;
|
const numIndexedArgs = log.topics.length - 1;
|
||||||
if (_.isUndefined(this._eventIds[methodId]) || _.isUndefined(this._eventIds[methodId][numIndexedArgs])) {
|
if (_.isUndefined(this._eventIds[eventId]) || _.isUndefined(this._eventIds[eventId][numIndexedArgs])) {
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
const event = this._eventIds[methodId][numIndexedArgs];
|
const event = this._eventIds[eventId][numIndexedArgs];
|
||||||
const ethersInterface = new ethers.utils.Interface([event]);
|
const ethersInterface = new ethers.utils.Interface([event]);
|
||||||
const decodedParams: DecodedLogArgs = {};
|
const decodedParams: DecodedLogArgs = {};
|
||||||
let topicsIndex = 1;
|
let topicsIndex = 1;
|
||||||
@ -110,19 +110,21 @@ export class AbiDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Decodes transaction data for a known ABI.
|
* Decodes calldata for a known ABI.
|
||||||
* @param calldata hex-encoded transaction data.
|
* @param calldata hex-encoded calldata.
|
||||||
* @param contractName used to disambiguate similar ABI's (optional).
|
* @param contractName used to disambiguate similar ABI's (optional).
|
||||||
* @return Decoded transaction data. Includes: function name and signature, along with the decoded arguments.
|
* @return Decoded calldata. Includes: function name and signature, along with the decoded arguments.
|
||||||
*/
|
*/
|
||||||
public tryDecodeCalldata(calldata: string, contractName?: string): TransactionData {
|
public decodeCalldataOrThrow(calldata: string, contractName?: string): DecodedCalldata {
|
||||||
const functionSelector = AbiDecoder._getFunctionSelector(calldata);
|
const functionSelector = AbiDecoder._getFunctionSelector(calldata);
|
||||||
const candidateFunctionInfos = this._functionInfoBySelector[functionSelector];
|
const candidateFunctionInfos = this._selectorToFunctionInfo[functionSelector];
|
||||||
if (_.isUndefined(candidateFunctionInfos)) {
|
if (_.isUndefined(candidateFunctionInfos)) {
|
||||||
throw new Error(`No functions registered for selector '${functionSelector}'`);
|
throw new Error(`No functions registered for selector '${functionSelector}'`);
|
||||||
}
|
}
|
||||||
const functionInfo = _.find(candidateFunctionInfos, txDecoder => {
|
const functionInfo = _.find(candidateFunctionInfos, candidateFunctionInfo => {
|
||||||
return _.isUndefined(contractName) || _.toLower(txDecoder.contractName) === _.toLower(contractName);
|
return (
|
||||||
|
_.isUndefined(contractName) || _.toLower(contractName) === _.toLower(candidateFunctionInfo.contractName)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
if (_.isUndefined(functionInfo)) {
|
if (_.isUndefined(functionInfo)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -144,12 +146,14 @@ export class AbiDecoder {
|
|||||||
return decodedCalldata;
|
return decodedCalldata;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Adds a set of ABI definitions, after which transaction data targeting these ABI's can be decoded.
|
* Adds a set of ABI definitions, after which calldata and logs targeting these ABI's can be decoded.
|
||||||
* Additional properties can be included to disambiguate similar ABI's. For example, if two functions
|
* Additional properties can be included to disambiguate similar ABI's. For example, if two functions
|
||||||
* have the same signature but different parameter names, then their ABI definitions can be disambiguated
|
* have the same signature but different parameter names, then their ABI definitions can be disambiguated
|
||||||
* by specifying a contract name.
|
* by specifying a contract name.
|
||||||
* @param abiDefinitions ABI definitions for a given contract.
|
* @param abiDefinitions ABI definitions for a given contract.
|
||||||
* @param contractName Name of contract that encapsulates the ABI definitions (optional).
|
* @param contractName Name of contract that encapsulates the ABI definitions (optional).
|
||||||
|
* This can be used when decoding calldata to disambiguate methods with
|
||||||
|
* the same signature but different parameter names.
|
||||||
*/
|
*/
|
||||||
public addABI(abiArray: AbiDefinition[], contractName?: string): void {
|
public addABI(abiArray: AbiDefinition[], contractName?: string): void {
|
||||||
if (_.isUndefined(abiArray)) {
|
if (_.isUndefined(abiArray)) {
|
||||||
@ -159,15 +163,13 @@ export class AbiDecoder {
|
|||||||
_.map(abiArray, (abi: AbiDefinition) => {
|
_.map(abiArray, (abi: AbiDefinition) => {
|
||||||
switch (abi.type) {
|
switch (abi.type) {
|
||||||
case AbiType.Event:
|
case AbiType.Event:
|
||||||
// tslint:disable no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
this._addEventABI(abi as EventAbi, ethersInterface);
|
this._addEventABI(abi as EventAbi, ethersInterface);
|
||||||
// tslint:enable no-unnecessary-type-assertion
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AbiType.Function:
|
case AbiType.Function:
|
||||||
// tslint:disable no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
this._addMethodABI(abi as MethodAbi, contractName);
|
this._addMethodABI(abi as MethodAbi, contractName);
|
||||||
// tslint:enable no-unnecessary-type-assertion
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -176,9 +178,7 @@ export class AbiDecoder {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private _addEventABI(abi: EventAbi, ethersInterface: ethers.utils.Interface): void {
|
private _addEventABI(eventAbi: EventAbi, ethersInterface: ethers.utils.Interface): void {
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
|
||||||
const eventAbi = abi as EventAbi;
|
|
||||||
const topic = ethersInterface.events[eventAbi.name].topic;
|
const topic = ethersInterface.events[eventAbi.name].topic;
|
||||||
const numIndexedArgs = _.reduce(eventAbi.inputs, (sum, input) => (input.indexed ? sum + 1 : sum), 0);
|
const numIndexedArgs = _.reduce(eventAbi.inputs, (sum, input) => (input.indexed ? sum + 1 : sum), 0);
|
||||||
this._eventIds[topic] = {
|
this._eventIds[topic] = {
|
||||||
@ -189,12 +189,12 @@ export class AbiDecoder {
|
|||||||
private _addMethodABI(methodAbi: MethodAbi, contractName?: string): void {
|
private _addMethodABI(methodAbi: MethodAbi, contractName?: string): void {
|
||||||
const abiEncoder = new AbiEncoder.Method(methodAbi);
|
const abiEncoder = new AbiEncoder.Method(methodAbi);
|
||||||
const functionSelector = abiEncoder.getSelector();
|
const functionSelector = abiEncoder.getSelector();
|
||||||
if (!(functionSelector in this._functionInfoBySelector)) {
|
if (!(functionSelector in this._selectorToFunctionInfo)) {
|
||||||
this._functionInfoBySelector[functionSelector] = [];
|
this._selectorToFunctionInfo[functionSelector] = [];
|
||||||
}
|
}
|
||||||
// Recored a copy of this ABI for each deployment
|
// Recored a copy of this ABI for each deployment
|
||||||
const functionSignature = abiEncoder.getSignature();
|
const functionSignature = abiEncoder.getSignature();
|
||||||
this._functionInfoBySelector[functionSelector].push({
|
this._selectorToFunctionInfo[functionSelector].push({
|
||||||
functionSignature,
|
functionSignature,
|
||||||
abiEncoder,
|
abiEncoder,
|
||||||
contractName,
|
contractName,
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import { addHexPrefix, sha3, stripHexPrefix } from 'ethereumjs-util';
|
import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util';
|
||||||
import * as jsSHA3 from 'js-sha3';
|
import * as jsSHA3 from 'js-sha3';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { BigNumber } from './configured_bignumber';
|
|
||||||
|
|
||||||
const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i;
|
const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i;
|
||||||
const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/;
|
const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/;
|
||||||
const ADDRESS_LENGTH = 40;
|
const ADDRESS_LENGTH = 40;
|
||||||
const MAX_DIGITS_IN_UNSIGNED_256_INT = 78;
|
|
||||||
|
|
||||||
export const addressUtils = {
|
export const addressUtils = {
|
||||||
isChecksumAddress(address: string): boolean {
|
isChecksumAddress(address: string): boolean {
|
||||||
@ -46,25 +43,4 @@ export const addressUtils = {
|
|||||||
padZeros(address: string): string {
|
padZeros(address: string): string {
|
||||||
return addHexPrefix(_.padStart(stripHexPrefix(address), ADDRESS_LENGTH, '0'));
|
return addHexPrefix(_.padStart(stripHexPrefix(address), ADDRESS_LENGTH, '0'));
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Generates a pseudo-random 256-bit salt.
|
|
||||||
* The salt can be included in a 0x order, ensuring that the order generates a unique orderHash
|
|
||||||
* and will not collide with other outstanding orders that are identical in all other parameters.
|
|
||||||
* @return A pseudo-random 256-bit number that can be used as a salt.
|
|
||||||
*/
|
|
||||||
generatePseudoRandomSalt(): BigNumber {
|
|
||||||
// BigNumber.random returns a pseudo-random number between 0 & 1 with a passed in number of decimal places.
|
|
||||||
// Source: https://mikemcl.github.io/bignumber.js/#random
|
|
||||||
const randomNumber = BigNumber.random(MAX_DIGITS_IN_UNSIGNED_256_INT);
|
|
||||||
const factor = new BigNumber(10).pow(MAX_DIGITS_IN_UNSIGNED_256_INT - 1);
|
|
||||||
const salt = randomNumber.times(factor);
|
|
||||||
return salt;
|
|
||||||
},
|
|
||||||
generatePseudoRandomAddress(): string {
|
|
||||||
const randomBigNum = addressUtils.generatePseudoRandomSalt();
|
|
||||||
const randomBuff = sha3(randomBigNum.toString());
|
|
||||||
const addressLengthInBytes = 20;
|
|
||||||
const randomAddress = `0x${randomBuff.slice(0, addressLengthInBytes).toString('hex')}`;
|
|
||||||
return randomAddress;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -8,11 +8,11 @@ export interface FunctionInfo {
|
|||||||
abiEncoder?: AbiEncoder.Method;
|
abiEncoder?: AbiEncoder.Method;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FunctionInfoBySelector {
|
export interface SelectorToFunctionInfo {
|
||||||
[index: string]: FunctionInfo[];
|
[index: string]: FunctionInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransactionData {
|
export interface DecodedCalldata {
|
||||||
functionName: string;
|
functionName: string;
|
||||||
functionSignature: string;
|
functionSignature: string;
|
||||||
functionArguments: any;
|
functionArguments: any;
|
||||||
|
@ -40,7 +40,7 @@ describe('AbiDecoder', () => {
|
|||||||
const foobarSignature = foobarEncoder.getSignature();
|
const foobarSignature = foobarEncoder.getSignature();
|
||||||
const foobarTxData = foobarEncoder.encode([testAddress]);
|
const foobarTxData = foobarEncoder.encode([testAddress]);
|
||||||
// Decode tx data using contract name
|
// Decode tx data using contract name
|
||||||
const decodedTxData = abiDecoder.tryDecodeCalldata(foobarTxData, contractName);
|
const decodedTxData = abiDecoder.decodeCalldataOrThrow(foobarTxData, contractName);
|
||||||
const expectedFunctionName = abi.name;
|
const expectedFunctionName = abi.name;
|
||||||
const expectedFunctionArguments = { testAddress };
|
const expectedFunctionArguments = { testAddress };
|
||||||
expect(decodedTxData.functionName).to.be.equal(expectedFunctionName);
|
expect(decodedTxData.functionName).to.be.equal(expectedFunctionName);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export { Web3Wrapper } from './web3_wrapper';
|
export { Web3Wrapper } from './web3_wrapper';
|
||||||
export { marshaller } from './marshaller';
|
export { marshaller } from './marshaller';
|
||||||
|
|
||||||
export { AbiDecoder, TransactionData } from '@0x/utils';
|
export { AbiDecoder, DecodedCalldata } from '@0x/utils';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
BlockParam,
|
BlockParam,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user