Added getABIDecodedTransactionData
and getABIDecodedReturnData
to contract wrappers + test cases
This commit is contained in:
parent
57318c0041
commit
db74db622e
@ -30,6 +30,7 @@
|
||||
"src/ReentrancyGuard.sol",
|
||||
"src/SafeMath.sol",
|
||||
"src/interfaces/IOwnable.sol",
|
||||
"test/TestAbi.sol",
|
||||
"test/TestConstants.sol",
|
||||
"test/TestLibAddressArray.sol",
|
||||
"test/TestLibBytes.sol",
|
||||
|
141
contracts/utils/contracts/test/TestAbi.sol
Normal file
141
contracts/utils/contracts/test/TestAbi.sol
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 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.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract TestAbi {
|
||||
|
||||
struct ComplexInput {
|
||||
uint256 foo;
|
||||
bytes bar;
|
||||
string car;
|
||||
}
|
||||
|
||||
struct ComplexOutput {
|
||||
ComplexInput input;
|
||||
bytes lorem;
|
||||
bytes ipsum;
|
||||
string dolor;
|
||||
}
|
||||
|
||||
function noInputNoOutput()
|
||||
public
|
||||
pure
|
||||
{
|
||||
// NOP
|
||||
require(true == true);
|
||||
}
|
||||
|
||||
function noInputSimpleOutput()
|
||||
public
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return 1991;
|
||||
}
|
||||
|
||||
function simpleInputNoOutput(uint256)
|
||||
public
|
||||
pure
|
||||
{
|
||||
// NOP
|
||||
require(true == true);
|
||||
}
|
||||
|
||||
function simpleInputSimpleOutput(uint256)
|
||||
public
|
||||
pure
|
||||
returns (uint256)
|
||||
{
|
||||
return 1991;
|
||||
}
|
||||
|
||||
function complexInputComplexOutput(ComplexInput memory complexInput)
|
||||
public
|
||||
pure
|
||||
returns (ComplexOutput memory)
|
||||
{
|
||||
return ComplexOutput({
|
||||
input: complexInput,
|
||||
lorem: hex'12345678',
|
||||
ipsum: hex'87654321',
|
||||
dolor: "amet"
|
||||
});
|
||||
}
|
||||
|
||||
function multiInputMultiOutput(
|
||||
uint256,
|
||||
bytes memory,
|
||||
string memory
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
bytes memory,
|
||||
bytes memory,
|
||||
string memory
|
||||
)
|
||||
{
|
||||
return (
|
||||
hex'12345678',
|
||||
hex'87654321',
|
||||
"amet"
|
||||
);
|
||||
}
|
||||
|
||||
function ()
|
||||
external
|
||||
{
|
||||
address addr = address(this);
|
||||
assembly {
|
||||
// copy calldata to memory
|
||||
calldatacopy(
|
||||
0x0,
|
||||
0x0,
|
||||
calldatasize()
|
||||
)
|
||||
// execute transaction
|
||||
let success := call(
|
||||
gas, // send all gas.
|
||||
addr, // call into this contract.
|
||||
0, // don't send any ether.
|
||||
0x0, // input is `txData`.
|
||||
calldatasize(), // input length is that of `txData`.
|
||||
0x0, // any return data goes at mem address 0x0.
|
||||
0 // there is no fixed return value size.
|
||||
)
|
||||
|
||||
// copy return data to memory
|
||||
returndatacopy(
|
||||
0x0,
|
||||
0x0,
|
||||
returndatasize()
|
||||
)
|
||||
|
||||
// rethrow any exceptions
|
||||
if iszero(success) {
|
||||
revert(0, returndatasize())
|
||||
}
|
||||
|
||||
// return call results
|
||||
return(0, returndatasize())
|
||||
}
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(Address|IOwnable|LibBytes|Ownable|ReentrancyGuard|SafeMath|TestConstants|TestLibAddressArray|TestLibBytes|TestLogDecoding|TestLogDecodingDownstream).json",
|
||||
"abis": "./generated-artifacts/@(Address|IOwnable|LibBytes|Ownable|ReentrancyGuard|SafeMath|TestAbi|TestConstants|TestLibAddressArray|TestLibBytes|TestLogDecoding|TestLogDecodingDownstream).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@ -11,6 +11,7 @@ import * as LibBytes from '../generated-artifacts/LibBytes.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as ReentrancyGuard from '../generated-artifacts/ReentrancyGuard.json';
|
||||
import * as SafeMath from '../generated-artifacts/SafeMath.json';
|
||||
import * as TestAbi from '../generated-artifacts/TestAbi.json';
|
||||
import * as TestConstants from '../generated-artifacts/TestConstants.json';
|
||||
import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray.json';
|
||||
import * as TestLibBytes from '../generated-artifacts/TestLibBytes.json';
|
||||
@ -28,4 +29,5 @@ export const artifacts = {
|
||||
TestLibBytes: TestLibBytes as ContractArtifact,
|
||||
TestLogDecoding: TestLogDecoding as ContractArtifact,
|
||||
TestLogDecodingDownstream: TestLogDecodingDownstream as ContractArtifact,
|
||||
TestAbi: TestAbi as ContractArtifact,
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ export * from '../generated-wrappers/lib_bytes';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/reentrancy_guard';
|
||||
export * from '../generated-wrappers/safe_math';
|
||||
export * from '../generated-wrappers/test_abi';
|
||||
export * from '../generated-wrappers/test_constants';
|
||||
export * from '../generated-wrappers/test_lib_address_array';
|
||||
export * from '../generated-wrappers/test_lib_bytes';
|
||||
|
95
contracts/utils/test/abi.ts
Normal file
95
contracts/utils/test/abi.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { chaiSetup, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { artifacts, TestAbiContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe.only('TestAbi', () => {
|
||||
let testAbi: TestAbiContract;
|
||||
const runTestAsync = async (contractMethod: any, input: any, output: any) => {
|
||||
const transaction = contractMethod.getABIEncodedTransactionData(input);
|
||||
// try decoding transaction
|
||||
const decodedInput = contractMethod.getABIDecodedTransactionData(transaction);
|
||||
expect(decodedInput, 'decoded input').to.be.deep.equal(input);
|
||||
// execute transaction
|
||||
const rawOutput = await web3Wrapper.callAsync({
|
||||
to: testAbi.address,
|
||||
data: transaction,
|
||||
});
|
||||
// try decoding output
|
||||
const decodedOutput = contractMethod.getABIDecodedReturnData(rawOutput);
|
||||
expect(decodedOutput, 'decoded output').to.be.deep.equal(output);
|
||||
};
|
||||
before(async () => {
|
||||
testAbi = await TestAbiContract.deployFrom0xArtifactAsync(artifacts.TestAbi, provider, txDefaults, artifacts);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('Encoding/Decoding Transaction Data and Return Values', () => {
|
||||
it('should successfully encode/decode (no input / no output)', async () => {
|
||||
const input = undefined;
|
||||
const output = undefined;
|
||||
await runTestAsync(testAbi.noInputNoOutput, input, output);
|
||||
});
|
||||
it('should successfully encode/decode (no input / simple output)', async () => {
|
||||
const input = undefined;
|
||||
const output = new BigNumber(1991);
|
||||
await runTestAsync(testAbi.noInputSimpleOutput, input, output);
|
||||
});
|
||||
it('should successfully encode/decode (simple input / no output)', async () => {
|
||||
const input = new BigNumber(1991);
|
||||
const output = undefined;
|
||||
await runTestAsync(testAbi.simpleInputNoOutput, input, output);
|
||||
});
|
||||
it('should successfully encode/decode (simple input / simple output)', async () => {
|
||||
const input = new BigNumber(16);
|
||||
const output = new BigNumber(1991);
|
||||
await runTestAsync(testAbi.simpleInputSimpleOutput, input, output);
|
||||
});
|
||||
it('should successfully encode/decode (complex input / complex output)', async () => {
|
||||
const input = {
|
||||
foo: new BigNumber(1991),
|
||||
bar: '0x1234',
|
||||
car: 'zoom zoom',
|
||||
};
|
||||
const output = {
|
||||
input: input,
|
||||
lorem: '0x12345678',
|
||||
ipsum: '0x87654321',
|
||||
dolor: 'amet',
|
||||
};
|
||||
await runTestAsync(testAbi.complexInputComplexOutput, input, output);
|
||||
});
|
||||
it('should successfully encode/decode (complex input / complex output)', async () => {
|
||||
const input = [new BigNumber(1991), '0x1234', 'zoom zoom'];
|
||||
const output = ['0x12345678', '0x87654321', 'amet'];
|
||||
const transaction = testAbi.multiInputMultiOutput.getABIEncodedTransactionData(
|
||||
input[0] as BigNumber,
|
||||
input[1] as string,
|
||||
input[2] as string,
|
||||
);
|
||||
// try decoding transaction
|
||||
const decodedInput = testAbi.multiInputMultiOutput.getABIDecodedTransactionData(transaction);
|
||||
expect(decodedInput, 'decoded input').to.be.deep.equal(input);
|
||||
// execute transaction
|
||||
const rawOutput = await web3Wrapper.callAsync({
|
||||
to: testAbi.address,
|
||||
data: transaction,
|
||||
});
|
||||
// try decoding output
|
||||
const decodedOutput = testAbi.multiInputMultiOutput.getABIDecodedReturnData(rawOutput);
|
||||
expect(decodedOutput, 'decoded output').to.be.deep.equal(output);
|
||||
});
|
||||
});
|
||||
});
|
@ -9,6 +9,7 @@
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/ReentrancyGuard.json",
|
||||
"generated-artifacts/SafeMath.json",
|
||||
"generated-artifacts/TestAbi.json",
|
||||
"generated-artifacts/TestConstants.json",
|
||||
"generated-artifacts/TestLibAddressArray.json",
|
||||
"generated-artifacts/TestLibBytes.json",
|
||||
|
@ -44,3 +44,21 @@ getABIEncodedTransactionData(
|
||||
const abiEncodedTransactionData = self._strictEncodeArguments('{{this.functionSignature}}', [{{> normalized_params inputs=inputs}}]);
|
||||
return abiEncodedTransactionData;
|
||||
},
|
||||
getABIDecodedTransactionData(
|
||||
returnData: string
|
||||
): ({{> return_type inputs=inputs ~}}) {
|
||||
const self = this as any as {{contractName}}Contract;
|
||||
const abiEncoder = self._lookupAbiEncoder('{{this.functionSignature}}');
|
||||
// tslint:disable boolean-naming
|
||||
const abiDecodedReturnData = abiEncoder.strictDecode<{{> return_type inputs=inputs}}>(returnData);
|
||||
return abiDecodedReturnData;
|
||||
},
|
||||
getABIDecodedReturnData(
|
||||
returnData: string
|
||||
): ({{> return_type outputs=outputs ~}}) {
|
||||
const self = this as any as {{contractName}}Contract;
|
||||
const abiEncoder = self._lookupAbiEncoder('{{this.functionSignature}}');
|
||||
// tslint:disable boolean-naming
|
||||
const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{{> return_type outputs=outputs}}>(returnData);
|
||||
return abiDecodedReturnData;
|
||||
},
|
||||
|
@ -34,6 +34,19 @@ export class MethodDataType extends AbstractSetDataType {
|
||||
return value;
|
||||
}
|
||||
|
||||
public strictDecode<T>(calldata: string, rules?: DecodingRules): T {
|
||||
const value = super.decode(calldata, rules, this._methodSelector);
|
||||
const valueAsArray: any = _.isObject(value) ? _.values(value) : [value];
|
||||
switch (valueAsArray.length) {
|
||||
case 0:
|
||||
return undefined as any;
|
||||
case 1:
|
||||
return valueAsArray[0];
|
||||
default:
|
||||
return valueAsArray;
|
||||
}
|
||||
}
|
||||
|
||||
public encodeReturnValues(value: any, rules?: EncodingRules): string {
|
||||
const returnData = this._returnDataType.encode(value, rules);
|
||||
return returnData;
|
||||
|
Loading…
x
Reference in New Issue
Block a user