aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Hysen <greg.hysen@gmail.com>2018-11-15 05:51:08 +0800
committerGreg Hysen <greg.hysen@gmail.com>2018-11-29 08:38:10 +0800
commit2d2255e9af42f6441ee620c4aa74bd1981dfe03a (patch)
treec94089561cd9fdf84600c49ca29ad8c6d8eda341
parent93e967c3b356f0081254946bbf8d6875fc791a09 (diff)
downloaddexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.tar
dexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.tar.gz
dexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.tar.bz2
dexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.tar.lz
dexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.tar.xz
dexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.tar.zst
dexon-sol-tools-2d2255e9af42f6441ee620c4aa74bd1981dfe03a.zip
Cleaner interface for encoding/decoding. Moved encode/decode parameters into a struct.
-rw-r--r--packages/order-utils/test/abi/calldata.ts43
-rw-r--r--packages/order-utils/test/abi/data_type.ts49
-rw-r--r--packages/order-utils/test/abi/evm_data_types.ts25
-rw-r--r--packages/order-utils/test/abi_encoder_test.ts25
4 files changed, 63 insertions, 79 deletions
diff --git a/packages/order-utils/test/abi/calldata.ts b/packages/order-utils/test/abi/calldata.ts
index 754d8f823..7eb4e0026 100644
--- a/packages/order-utils/test/abi/calldata.ts
+++ b/packages/order-utils/test/abi/calldata.ts
@@ -2,6 +2,15 @@ import ethUtil = require('ethereumjs-util');
import CommunicationChatBubbleOutline from 'material-ui/SvgIcon';
var _ = require('lodash');
+export interface DecodingRules {
+ structsAsObjects: boolean;
+}
+
+export interface EncodingRules {
+ optimize?: boolean;
+ annotate?: boolean;
+}
+
export abstract class CalldataBlock {
private name: string;
private signature: string;
@@ -237,11 +246,13 @@ class Queue<T> {
export class Calldata {
private selector: string;
+ private rules: EncodingRules;
private sizeInBytes: number;
private root: MemberCalldataBlock | undefined;
- constructor() {
- this.selector = '0x';
+ constructor(rules: EncodingRules) {
+ this.selector = '';
+ this.rules = rules;
this.sizeInBytes = 0;
this.root = undefined;
}
@@ -272,28 +283,6 @@ export class Calldata {
return blockQueue;
}
- /*
-
- // Basic optimize method that prunes duplicate branches of the tree
- // Notes:
- // 1. Pruning is at the calldata block level, so it is independent of type
- // 2.
- private optimize(blocks: CalldataBlock[]) {
- // Build hash table of blocks
- const blockLookupTable: { [key: string]: string } = {};
- _.each(blocks, (block: CalldataBlock) => {
- if (blocks instanceof DependentCalldataBlock === false) {
-
- return;
- }
-
- const leavesHash = block.hashLeaves();
- if (leavesHash in blockLookupTable) {
-
- }
- })
- }*/
-
private generateAnnotatedHexString(): string {
let hexValue = `${this.selector}`;
if (this.root === undefined) {
@@ -413,12 +402,12 @@ export class Calldata {
console.log('*'.repeat(100), ' FINISHED OPTIMIZING ', '*'.repeat(100));
}
- public toHexString(optimize: boolean = false, annotate: boolean = false): string {
+ public toHexString(): string {
if (this.root === undefined) {
throw new Error('expected root');
}
- if (optimize) this.optimize();
+ if (this.rules.optimize) this.optimize();
const offsetQueue = this.createQueue(this.root);
let block: CalldataBlock | undefined;
@@ -428,7 +417,7 @@ export class Calldata {
offset += block.getSizeInBytes();
}
- const hexValue = annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
+ const hexValue = this.rules.annotate ? this.generateAnnotatedHexString() : this.generateCondensedHexString();
return hexValue;
}
diff --git a/packages/order-utils/test/abi/data_type.ts b/packages/order-utils/test/abi/data_type.ts
index 25f792c7a..6ad0b2736 100644
--- a/packages/order-utils/test/abi/data_type.ts
+++ b/packages/order-utils/test/abi/data_type.ts
@@ -1,14 +1,14 @@
import { RawCalldata, Calldata, CalldataBlock, PayloadCalldataBlock, DependentCalldataBlock, MemberCalldataBlock } from "./calldata";
import { MethodAbi, DataItem } from 'ethereum-types';
+import { DecodingRules, EncodingRules } from './calldata';
import { BigNumber } from '@0x/utils';
import ethUtil = require('ethereumjs-util');
var _ = require('lodash');
-export interface GenerateValueRules {
- structsAsObjects: boolean;
-}
-
export abstract class DataType {
+ private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
+ private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
+
private dataItem: DataItem;
constructor(dataItem: DataItem) {
@@ -19,9 +19,25 @@ export abstract class DataType {
return this.dataItem;
}
+ public encode(value: any, rules?: EncodingRules, selector?: string): string {
+ const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
+ const calldata = new Calldata(rules_);
+ if (selector) calldata.setSelector(selector);
+ const block = this.generateCalldataBlock(value);
+ calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE
+ const calldataHex = calldata.toHexString();
+ return calldataHex;
+ }
+
+ public decode(calldata: string, rules?: DecodingRules): any {
+ const rawCalldata = new RawCalldata(calldata);
+ const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
+ const value = this.generateValue(rawCalldata, rules_);
+ return value;
+ }
+
public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock;
- public abstract generateValue(calldata: RawCalldata, rules: GenerateValueRules): any;
- public abstract encode(value: any, calldata: Calldata): void;
+ public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any;
public abstract getSignature(): string;
public abstract isStatic(): boolean;
}
@@ -44,12 +60,7 @@ export abstract class PayloadDataType extends DataType {
return block;
}
- public encode(value: any, calldata: Calldata): void {
- const block = this.generateCalldataBlock(value);
- // calldata.setRoot(block);
- }
-
- public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any {
+ public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
const value = this.decodeValue(calldata);
return value;
}
@@ -86,12 +97,7 @@ export abstract class DependentDataType extends DataType {
return block;
}
- public encode(value: any, calldata: Calldata = new Calldata()): void {
- const block = this.generateCalldataBlock(value);
- //calldata.setRoot(block);
- }
-
- public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any {
+ public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
const destinationOffsetBuf = calldata.popWord();
const currentOffset = calldata.getOffset();
const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
@@ -237,12 +243,7 @@ export abstract class MemberDataType extends DataType {
return block;
}
- public encode(value: any, calldata: Calldata = new Calldata()): void {
- const block = this.generateCalldataBlock(value);
- calldata.setRoot(block);
- }
-
- public generateValue(calldata: RawCalldata, rules: GenerateValueRules): any[] | object {
+ public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
let members = this.members;
if (this.isArray && this.arrayLength === undefined) {
const arrayLengthBuf = calldata.popWord();
diff --git a/packages/order-utils/test/abi/evm_data_types.ts b/packages/order-utils/test/abi/evm_data_types.ts
index a24046664..9504b1a10 100644
--- a/packages/order-utils/test/abi/evm_data_types.ts
+++ b/packages/order-utils/test/abi/evm_data_types.ts
@@ -1,4 +1,6 @@
-import { GenerateValueRules, DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+import { DataType, DataTypeFactory, DataTypeFactoryImpl, PayloadDataType, DependentDataType, MemberDataType } from './data_type';
+
+import { DecodingRules, EncodingRules } from './calldata';
import { MethodAbi, DataItem } from 'ethereum-types';
@@ -13,7 +15,7 @@ var _ = require('lodash');
export interface DataTypeStaticInterface {
matchGrammar: (type: string) => boolean;
encodeValue: (value: any) => Buffer;
- // decodeValue: (value: Buffer) => [any, Buffer];
+ decodeValue: (rawCalldata: RawCalldata) => any;
}
export class Address extends PayloadDataType {
@@ -489,21 +491,16 @@ export class Method extends MemberDataType {
return selector;
}
- public encode(value: any[] | object, calldata = new Calldata(), annotate: boolean = false, optimize: boolean = false): string {
- calldata.setSelector(this.methodSelector);
- super.encode(value, calldata);
- return calldata.toHexString(optimize, annotate);
+ public encode(value: any, rules?: EncodingRules): string {
+ const calldata = super.encode(value, rules, this.selector);
+ return calldata;
}
- public decode(calldata: string, decodeStructsAsObjects: boolean = false): any[] | object {
- const calldata_ = new RawCalldata(calldata);
- if (this.selector !== calldata_.getSelector()) {
- throw new Error(`Tried to decode calldata with mismatched selector. Expected '${this.selector}', got '${calldata_.getSelector()}'`);
+ public decode(calldata: string, rules?: DecodingRules): any[] | object {
+ if (!calldata.startsWith(this.selector)) {
+ throw new Error(`Tried to decode calldata, but it was missing the function selector. Expected '${this.selector}'.`);
}
- let rules: GenerateValueRules = {
- structsAsObjects: decodeStructsAsObjects
- };
- const value = super.generateValue(calldata_, rules);
+ const value = super.decode(calldata, rules);
return value;
}
diff --git a/packages/order-utils/test/abi_encoder_test.ts b/packages/order-utils/test/abi_encoder_test.ts
index 78e28015d..52b6bc067 100644
--- a/packages/order-utils/test/abi_encoder_test.ts
+++ b/packages/order-utils/test/abi_encoder_test.ts
@@ -27,7 +27,7 @@ const expect = chai.expect;
describe.only('ABI Encoder', () => {
describe.only('ABI Tests at Method Level', () => {
- it('Optimizer #1', async () => {
+ it('Should reuse duplicated strings in string array', async () => {
const method = new AbiEncoder.Method(AbiSamples.stringAbi);
const strings = [
"Test String",
@@ -37,7 +37,7 @@ describe.only('ABI Encoder', () => {
];
const args = [strings];
- const optimizedCalldata = method.encode(args, new Calldata(), true, true);
+ const optimizedCalldata = method.encode(args, { optimize: true, annotate: true });
console.log(optimizedCalldata);
});
@@ -53,10 +53,10 @@ describe.only('ABI Encoder', () => {
const args = [stringArray, string];
- const TEST = method.encode(args, new Calldata(), true, true);
+ const TEST = method.encode(args, { optimize: true, annotate: true });
console.log(TEST);
- const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+ const optimizedCalldata = method.encode(args, { optimize: true });
console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
const decodedArgs = method.decode(optimizedCalldata);
@@ -79,10 +79,10 @@ describe.only('ABI Encoder', () => {
const args = [uint8Array, uintTupleArray];
- const TEST = method.encode(args, new Calldata(), true, true);
+ const TEST = method.encode(args, { optimize: true, annotate: true });
console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
- const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+ const optimizedCalldata = method.encode(args, { optimize: true });
console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
const decodedArgs = method.decode(optimizedCalldata);
@@ -92,7 +92,7 @@ describe.only('ABI Encoder', () => {
expect(decodedArgsJson).to.be.equal(argsJson);
});
- it.only('Optimizer #4 (Expect no optimization)', async () => {
+ it('Optimizer #4 (Expect no optimization)', async () => {
const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4);
const uint8Array = [
new BigNumber(100),
@@ -104,10 +104,10 @@ describe.only('ABI Encoder', () => {
const args = [uint8Array, uintTupleArray];
- const TEST = method.encode(args, new Calldata(), true, true);
+ const TEST = method.encode(args, { optimize: true, annotate: true });
console.log('*'.repeat(50), ' ENCODED DATA ', TEST);
- const optimizedCalldata = method.encode(args, new Calldata(), false, true);
+ const optimizedCalldata = method.encode(args, { optimize: true });
console.log(`OPTIMIZED CALLDATA == '${optimizedCalldata}'`);
const decodedArgs = method.decode(optimizedCalldata);
@@ -179,12 +179,9 @@ describe.only('ABI Encoder', () => {
someArrayOfTuplesWithDynamicTypes: someArrayOfTuplesWithDynamicTypes
};
- const calldata = method.encode(args, new Calldata(), true);
+ const calldata = method.encode(args);
console.log(calldata);
-
- throw new Error(`done`);
-
console.log('*'.repeat(40));
console.log(JSON.stringify(args));
console.log(method.getSignature());
@@ -195,7 +192,7 @@ describe.only('ABI Encoder', () => {
// Test decoding
const expectedDecodedValueJson = JSON.stringify(args);
- const decodedValue = method.decode(calldata, true);
+ const decodedValue = method.decode(calldata, { structsAsObjects: true });
const decodedValueJson = JSON.stringify(decodedValue);
console.log(`DECODED`, '*'.repeat(200), '\n', decodedValueJson);
expect(decodedValueJson).to.be.equal(expectedDecodedValueJson);