Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Commit

Permalink
Use string argument encoding with new encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
hysz committed Dec 24, 2018
1 parent bd5bbec commit 99f0fcf
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 67 deletions.
7 changes: 0 additions & 7 deletions contracts/protocol/test/asset_proxy/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,46 +107,40 @@ describe('Asset Transfer Proxies', () => {
constants.AWAIT_TRANSACTION_MINED_MS,
);


// Configure ERC721Proxy
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);

await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);


// Configure MultiAssetProxy
await web3Wrapper.awaitTransactionSuccessAsync(
await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(authorized, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);

await web3Wrapper.awaitTransactionSuccessAsync(
await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);

await web3Wrapper.awaitTransactionSuccessAsync(
await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);


// Deploy and configure ERC20 tokens
const numDummyErc20ToDeploy = 2;
[erc20TokenA, erc20TokenB] = await erc20Wrapper.deployDummyTokensAsync(
Expand All @@ -172,7 +166,6 @@ describe('Asset Transfer Proxies', () => {
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
);


await erc20Wrapper.setBalancesAndAllowancesAsync();
await web3Wrapper.awaitTransactionSuccessAsync(
await noReturnErc20Token.setBalance.sendTransactionAsync(fromAddress, constants.INITIAL_ERC20_BALANCE),
Expand Down
20 changes: 10 additions & 10 deletions contracts/protocol/test/exchange/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.FILLABLE;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for a fully filled order', async () => {
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
Expand All @@ -1077,7 +1077,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.FULLY_FILLED;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for a partially filled order', async () => {
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
Expand All @@ -1088,7 +1088,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.FILLABLE;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for a cancelled and unfilled order', async () => {
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
Expand All @@ -1098,7 +1098,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.CANCELLED;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for a cancelled and partially filled order', async () => {
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
Expand All @@ -1110,7 +1110,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.CANCELLED;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for an expired and unfilled order', async () => {
const currentTimestamp = await getLatestBlockTimestampAsync();
Expand All @@ -1122,7 +1122,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.EXPIRED;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for an expired and partially filled order', async () => {
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
Expand All @@ -1136,7 +1136,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.EXPIRED;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for an expired and fully filled order', async () => {
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
Expand All @@ -1150,7 +1150,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.FULLY_FILLED;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for an order with a makerAssetAmount of 0', async () => {
signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: new BigNumber(0) });
Expand All @@ -1160,7 +1160,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.INVALID_MAKER_ASSET_AMOUNT;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
it('should return the correct orderInfo for an order with a takerAssetAmount of 0', async () => {
signedOrder = await orderFactory.newSignedOrderAsync({ takerAssetAmount: new BigNumber(0) });
Expand All @@ -1170,7 +1170,7 @@ describe('Exchange core', () => {
const expectedOrderStatus = OrderStatus.INVALID_TAKER_ASSET_AMOUNT;
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
expect(orderInfo.orderStatus).to.be.equal(expectedOrderStatus);
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
});
});
});
Expand Down
3 changes: 1 addition & 2 deletions contracts/protocol/test/exchange/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
testCombinatoriallyWithReferenceFuncAsync,
txDefaults,
uint256Values,
orderUtils,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
Expand Down Expand Up @@ -453,7 +452,7 @@ describe('Exchange core internal functions', () => {
};
await web3Wrapper.awaitTransactionSuccessAsync(
await testExchange.publicUpdateFilledState.sendTransactionAsync(
orderUtils.getOrderWithoutExchangeAddress(emptySignedOrder),
emptySignedOrder,
constants.NULL_ADDRESS,
orderHash,
orderTakerAssetFilledAmount,
Expand Down
1 change: 1 addition & 0 deletions packages/abi-gen-templates/contract.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class {{contractName}}Contract extends BaseContract {
);
const iface = new ethers.utils.Interface(abi);
const deployInfo = iface.deployFunction;
console.log('*'.repeat(50), `\n${JSON.stringify(deployInfo)}`);
const txData = deployInfo.encode(bytecode, [{{> params inputs=ctor.inputs}}]);
const web3Wrapper = new Web3Wrapper(provider);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
Expand Down
41 changes: 13 additions & 28 deletions packages/base-contract/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ export class BaseContract {
): any {
return _.map(values, (value: any, i: number) => formatABIDataItem(abis[i], value, formatter));
}
protected static _lowercaseAddress(type: string, value: string): string {
return type === 'address' ? value.toLowerCase() : value;
}
protected static _bigNumberToString(_type: string, value: any): any {
return _.isObject(value) && value.isBigNumber ? value.toString() : value;
}
protected static _lookupConstructorAbi(abi: ContractAbi): ConstructorAbi {
const constructorAbiIfExists = _.find(
abi,
Expand All @@ -67,9 +61,6 @@ export class BaseContract {
return defaultConstructorAbi;
}
}
protected static _bnToBigNumber(_type: string, value: any): any {
return _.isObject(value) && value._hex ? new BigNumber(value.toString()) : value;
}
protected static async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>(
txData: T,
txDefaults: Partial<TxData>,
Expand Down Expand Up @@ -99,11 +90,11 @@ export class BaseContract {
// the given inputAbi. An argument may not be considered safely encodeable
// if it overflows the corresponding Solidity type, there is a bug in the
// encoder, or the encoder performs unsafe type coercion.
public static strictArgumentEncodingCheck(inputAbi: DataItem[], args: any[]): void {
const coder = new ethers.utils.AbiCoder();
public static strictArgumentEncodingCheck(inputAbi: DataItem[], args: any[]): string {
const abiEncoder = AbiEncoder.create(inputAbi);
const params = abiUtils.parseEthersParams(inputAbi);
const rawEncoded = coder.encode(inputAbi, args);
const rawDecoded = coder.decode(inputAbi, rawEncoded);
const rawEncoded = abiEncoder.encode(args);
const rawDecoded = abiEncoder.decodeAsArray(rawEncoded);
for (let i = 0; i < rawDecoded.length; i++) {
const original = args[i];
const decoded = rawDecoded[i];
Expand All @@ -115,7 +106,14 @@ export class BaseContract {
);
}
}
return rawEncoded;
}
protected static _lowercaseAddress(type: string, value: string): string {
return type === 'address' ? value.toLowerCase() : value;
}
protected static _bigNumberToString(_type: string, value: any): any {
return _.isObject(value) && value.isBigNumber ? value.toString() : value;
}
protected _lookupAbiEncoder(functionSignature: string): AbiEncoder.Method {
const abiEncoder = this._abiEncoderByFunctionSignature[functionSignature];
if (_.isUndefined(abiEncoder)) {
Expand Down Expand Up @@ -143,21 +141,8 @@ export class BaseContract {
if (inputAbi === undefined) {
throw new Error(`Undefined Method Input ABI`);
}
const params = abiUtils.parseEthersParams(inputAbi);
const rawEncoded = abiEncoder.encode(functionArguments);
const rawDecoded = abiEncoder.decodeAsArray(rawEncoded);
for (let i = 0; i < rawDecoded.length; i++) {
const original = functionArguments[i];
const decoded = rawDecoded[i];
if (!abiUtils.isAbiDataEqual(params.names[i], params.types[i], original, decoded)) {
throw new Error(
`Cannot safely encode argument: ${params.names[i]} (${original}) of type ${
params.types[i]
}. (Possible type overflow or other encoding error)`,
);
}
}
return rawEncoded;
const abiEncodedArguments = abiEncoder.encode(functionArguments);////BaseContract.strictArgumentEncodingCheck(inputAbi, functionArguments);
return abiEncodedArguments;
}
constructor(
contractName: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export abstract class DataType {
return value;
}

public decodeAsArray(returndata: string, rules?: DecodingRules): any {
const value = this.decode(returndata, rules);
const valuesAsArray = _.isObject(value) ? _.values(value) : [value];
return valuesAsArray;
}

public getSignature(detailed?: boolean): string {
if (_.isEmpty(this._dataItem.name) || !detailed) return this.getSignatureType();
const name = this.getDataItem().name;
Expand Down
28 changes: 15 additions & 13 deletions packages/utils/src/abi_encoder/evm_data_type_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,23 @@ export class EvmDataTypeFactory implements DataTypeFactory {
// Convenience function
export function create(input: DataItem | DataItem[] | string): DataType {
// Handle different types of input
let dataItems: DataItem[] = [];
if (typeof(input) === 'string') {
dataItems = generateDataItemsFromSignature(input);
} else if(input instanceof Array) {
dataItems = input as DataItem[];
const isSignature = typeof(input) === 'string';
const isTupleSignature = isSignature && (input as string).startsWith('(');
const parseAsTuple = isTupleSignature || _.isArray(input);
// Create input `dataItem`
let dataItem: DataItem;
if(parseAsTuple) {
const dataItems = isSignature ? generateDataItemsFromSignature(input as string) : input as DataItem[];
dataItem = {
name: '',
type: 'tuple',
components: dataItems
};
} else {
dataItems = [input as DataItem];
dataItem = isSignature ? generateDataItemsFromSignature(input as string)[0] : input as DataItem;
}
// Create single data item from input
let dataItem: DataItem = dataItems.length === 1 ? dataItems[0] : {
name: '',
type: 'tuple',
components: dataItems
};
// Create data type
return EvmDataTypeFactory.getInstance().create(dataItem);
const dataType = EvmDataTypeFactory.getInstance().create(dataItem);
return dataType;
}
/* tslint:enable no-construct */
6 changes: 0 additions & 6 deletions packages/utils/src/abi_encoder/evm_data_types/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ export class MethodDataType extends AbstractSetDataType {
return value;
}

public decodeAsArray(returndata: string, rules?: DecodingRules): any {
const value = this.decode(returndata, rules);
const valuesAsArray = _.isObject(value) ? _.values(value) : [value];
return valuesAsArray;
}

public encodeReturnValues(value: any, rules?: EncodingRules): string {
const returnData = this._returnDataType.encode(value, rules);
return returnData;
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/abi_encoder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ export {
UInt,
create,
} from './evm_data_type_factory';
//export { fromSignature } from './utils/signatureParser';
export { DataType } from './abstract_data_types/data_type';

0 comments on commit 99f0fcf

Please sign in to comment.