aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/utils/src/abi_encoder/abstract_data_types/types/set.ts77
1 files changed, 35 insertions, 42 deletions
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
index 77fd7b3ea..427122ad6 100644
--- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
+++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts
@@ -49,18 +49,19 @@ export abstract class Set extends DataType {
public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
let members = this._members;
+ // Case 1: This is an array of undefined length, which means that `this._members` was not
+ // populated in the constructor. So, construct the set of members it now.
if (this._isArray && this._arrayLength === undefined) {
const arrayLengthBuf = calldata.popWord();
const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
- const hexBase = 16;
- const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
+ const arrayLength = new BigNumber(arrayLengthHex, Constants.HEX_BASE);
[members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
}
-
+ // Create a new scope in the calldata, before descending into the members of this set.
calldata.startScope();
let value: any[] | object;
if (rules.structsAsObjects && !this._isArray) {
+ // Construct an object with values for each member of the set.
value = {};
_.each(this._memberIndexByName, (idx: number, key: string) => {
const member = this._members[idx];
@@ -68,41 +69,33 @@ export abstract class Set extends DataType {
(value as { [key: string]: any })[key] = memberValue;
});
} else {
+ // Construct an array with values for each member of the set.
value = [];
_.each(members, (member: DataType, idx: number) => {
const memberValue = member.generateValue(calldata, rules);
(value as any[]).push(memberValue);
});
}
+ // Close this scope and return tetheh value.
calldata.endScope();
return value;
}
public isStatic(): boolean {
- /* For Tuple:
- const isStaticTuple = this.children.length === 0;
- return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
- For Array:
- if isLengthDefined = false then this is false
-
- Otherwise if the first element is a Pointer then false
- */
-
+ // An array with an undefined length is never static.
if (this._isArray && this._arrayLength === undefined) {
return false;
}
-
- // Search for dependent members
+ // If any member of the set is a pointer then the set is not static.
const dependentMember = _.find(this._members, (member: DataType) => {
return member instanceof Pointer;
});
- const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
+ const isStatic = dependentMember === undefined;
return isStatic;
}
protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): CalldataBlocks.Set {
- // Sanity check length
+ // Sanity check: if the set has a defined length then `value` must have the same length.
if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
throw new Error(
`Expected array of ${JSON.stringify(
@@ -110,41 +103,42 @@ export abstract class Set extends DataType {
)} elements, but got array of length ${JSON.stringify(value.length)}`,
);
}
-
+ // Create a new calldata block for this set.
const parentName = parentBlock === undefined ? '' : parentBlock.getName();
- const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set(
+ const block: CalldataBlocks.Set = new CalldataBlocks.Set(
this.getDataItem().name,
this.getSignature(),
parentName,
);
-
+ // If this set has an undefined length then set its header to be the number of elements.
let members = this._members;
if (this._isArray && this._arrayLength === undefined) {
[members] = this._createMembersWithLength(this.getDataItem(), value.length);
-
const lenBuf = ethUtil.setLengthLeft(
ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`),
Constants.EVM_WORD_WIDTH_IN_BYTES,
);
- methodBlock.setHeader(lenBuf);
+ block.setHeader(lenBuf);
}
-
+ // Create blocks for members of set.
const memberCalldataBlocks: CalldataBlock[] = [];
_.each(members, (member: DataType, idx: number) => {
- const block = member.generateCalldataBlock(value[idx], methodBlock);
- memberCalldataBlocks.push(block);
+ const memberBlock = member.generateCalldataBlock(value[idx], block);
+ memberCalldataBlocks.push(memberBlock);
});
- methodBlock.setMembers(memberCalldataBlocks);
- return methodBlock;
+ block.setMembers(memberCalldataBlocks);
+ return block;
}
protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): CalldataBlocks.Set {
+ // Create a new calldata block for this set.
const parentName = parentBlock === undefined ? '' : parentBlock.getName();
- const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set(
+ const block: CalldataBlocks.Set = new CalldataBlocks.Set(
this.getDataItem().name,
this.getSignature(),
parentName,
);
+ // Create blocks for members of set.
const memberCalldataBlocks: CalldataBlock[] = [];
const childMap = _.cloneDeep(this._memberIndexByName);
_.forOwn(obj, (value: any, key: string) => {
@@ -153,17 +147,17 @@ export abstract class Set extends DataType {
`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
);
}
- const block = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, methodBlock);
- memberCalldataBlocks.push(block);
+ const memberBlock = this._members[this._memberIndexByName[key]].generateCalldataBlock(value, block);
+ memberCalldataBlocks.push(memberBlock);
delete childMap[key];
});
-
+ // Sanity check that all members have been included.
if (Object.keys(childMap).length !== 0) {
throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`);
}
-
- methodBlock.setMembers(memberCalldataBlocks);
- return methodBlock;
+ // Associate member blocks with Set block.
+ block.setMembers(memberCalldataBlocks);
+ return block;
}
protected _computeSignatureOfMembers(): string {
@@ -184,7 +178,7 @@ export abstract class Set extends DataType {
if (dataItem.components === undefined) {
throw new Error(`Expected components`);
}
-
+ // Create one member for each component of `dataItem`
const members: DataType[] = [];
const memberIndexByName: MemberIndexByName = {};
_.each(dataItem.components, (memberItem: DataItem) => {
@@ -200,28 +194,27 @@ export abstract class Set extends DataType {
memberIndexByName[memberItem.name] = members.length;
members.push(child);
});
-
return [members, memberIndexByName];
}
private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] {
+ // Create `length` members, deriving the type from `dataItem`
const members: DataType[] = [];
const memberIndexByName: MemberIndexByName = {};
const range = _.range(length);
_.each(range, (idx: number) => {
- const childDataItem: DataItem = {
+ const memberDataItem: DataItem = {
type: this._arrayElementType ? this._arrayElementType : '',
name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
};
const components = dataItem.components;
if (components !== undefined) {
- childDataItem.components = components;
+ memberDataItem.components = components;
}
- const child = this.getFactory().create(childDataItem, this);
+ const memberType = this.getFactory().create(memberDataItem, this);
memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length;
- members.push(child);
+ members.push(memberType);
});
-
return [members, memberIndexByName];
}
}