Skip to content

Commit eddf93b

Browse files
committed
Added named parameters to tuple encoding.
1 parent 9aeb309 commit eddf93b

File tree

3 files changed

+62
-36
lines changed

3 files changed

+62
-36
lines changed

contracts/interface.js

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,27 @@ function alignSize(size) {
262262
}
263263

264264
function pack(coders, values) {
265+
if (Array.isArray(values)) {
266+
if (coders.length !== values.length) {
267+
throwError('types/values mismatch', { type: type, values: values });
268+
}
269+
270+
} else if (values && typeof(values) === 'object') {
271+
var arrayValues = [];
272+
coders.forEach(function(coder) {
273+
arrayValues.push(values[coder.localName]);
274+
});
275+
values = arrayValues;
276+
277+
} else {
278+
throwError('invalid value', { type: 'tuple', values: values });
279+
}
280+
265281
var parts = [];
266282

267283
coders.forEach(function(coder, index) {
268284
parts.push({ dynamic: coder.dynamic, value: coder.encode(values[index]) });
269-
})
285+
});
270286

271287
var staticSize = 0, dynamicSize = 0;
272288
parts.forEach(function(part, index) {
@@ -414,17 +430,6 @@ function coderTuple(coders, localName) {
414430
name: 'tuple',
415431
type: type,
416432
encode: function(value) {
417-
if (Array.isArray(value)) {
418-
if (coders.length !== value.length) {
419-
throwError('types/values mismatch', { type: type, values: values });
420-
}
421-
422-
// @TODO: If receiving an object, and we have names, create the array
423-
424-
} else {
425-
throwError('invalid value', { type: types, values: values });
426-
}
427-
428433
return pack(coders, value);
429434
},
430435
decode: function(data, offset) {
@@ -572,29 +577,27 @@ function Interface(abi) {
572577
switch (method.type) {
573578
case 'constructor':
574579
var func = (function() {
575-
// @TODO: Move to parseParams
576-
var inputTypes = getKeys(method.inputs, 'type');
580+
var inputParams = parseParams(method.inputs);
577581
var func = function(bytecode) {
578582
if (!utils.isHexString(bytecode)) {
579-
throwError('invalid bytecode', {input: bytecode});
583+
throwError('invalid bytecode', { input: bytecode });
580584
}
581585

582586
var params = Array.prototype.slice.call(arguments, 1);
583-
if (params.length < inputTypes.length) {
587+
if (params.length < inputParams.types.length) {
584588
throwError('missing parameter');
585-
} else if (params.length > inputTypes.length) {
589+
} else if (params.length > inputParams.types.length) {
586590
throwError('too many parameters');
587591
}
588592

589593
var result = {
590-
bytecode: bytecode + Interface.encodeParams(inputTypes, params).substring(2),
594+
bytecode: bytecode + Interface.encodeParams(inputParams.names, inputParams.types, params).substring(2),
591595
}
592596

593597
return populateDescription(new DeployDescription(), result);
594598
}
595599

596-
// @TODO: Move to parseParams
597-
defineFrozen(func, 'inputs', getKeys(method.inputs, 'name'));
600+
defineFrozen(func, 'inputs', inputParams);
598601

599602
return func;
600603
})();
@@ -608,7 +611,6 @@ function Interface(abi) {
608611
var inputParams = parseParams(method.inputs);
609612
var outputParams = parseParams(method.outputs);
610613

611-
var inputTypes = inputParams.types;
612614
if (method.constant) {
613615
var outputTypes = outputParams.types;
614616
var outputNames = outputParams.names;
@@ -628,13 +630,13 @@ function Interface(abi) {
628630

629631
var params = Array.prototype.slice.call(arguments, 0);
630632

631-
if (params.length < inputTypes.length) {
633+
if (params.length < inputParams.types.length) {
632634
throwError('missing parameter');
633-
} else if (params.length > inputTypes.length) {
635+
} else if (params.length > inputParams.types.length) {
634636
throwError('too many parameters');
635637
}
636638

637-
result.data = sighash + Interface.encodeParams(inputTypes, params).substring(2);
639+
result.data = sighash + Interface.encodeParams(inputParams.names, inputParams.types, params).substring(2);
638640
if (method.constant) {
639641
result.parse = function(data) {
640642
return Interface.decodeParams(
@@ -649,9 +651,8 @@ function Interface(abi) {
649651
return populateDescription(new TransactionDescription(), result);
650652
}
651653

652-
// @TODO: Move the paraseParams
653-
defineFrozen(func, 'inputs', getKeys(method.inputs, 'name'));
654-
defineFrozen(func, 'outputs', getKeys(method.outputs, 'name'));
654+
defineFrozen(func, 'inputs', inputParams);
655+
defineFrozen(func, 'outputs', outputParams);
655656

656657
utils.defineProperty(func, 'signature', signature);
657658
utils.defineProperty(func, 'sighash', sighash);
@@ -803,12 +804,20 @@ function Interface(abi) {
803804
}
804805

805806

806-
utils.defineProperty(Interface, 'encodeParams', function(types, values) {
807+
utils.defineProperty(Interface, 'encodeParams', function(names, types, values) {
808+
809+
// Names is optional, so shift over all the parameters if not provided
810+
if (arguments.length < 3) {
811+
values = types;
812+
types = names;
813+
names = null;
814+
}
815+
807816
if (types.length !== values.length) { throwError('types/values mismatch', {types: types, values: values}); }
808817

809818
var coders = [];
810-
types.forEach(function(type) {
811-
coders.push(getParamCoder(type));
819+
types.forEach(function(type, index) {
820+
coders.push(getParamCoder(type, (names ? names[index]: undefined)));
812821
});
813822

814823
return utils.hexlify(coderTuple(coders).encode(values));

contracts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ethers-contracts",
3-
"version": "2.1.10",
3+
"version": "2.2.0",
44
"description": "Contract and Interface (ABI) library for Ethereum.",
55
"bugs": {
66
"url": "http://github.com/ethers-io/ethers.js/issues",

tests/test-contract-interface.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ function equals(actual, expected) {
9595
}
9696

9797

98-
function getValues(object, format) {
98+
function getValues(object, format, named) {
9999
if (Array.isArray(object)) {
100100
var result = [];
101101
object.forEach(function(object) {
102-
result.push(getValues(object, format));
102+
result.push(getValues(object, format, named));
103103
});
104104
return result;
105105
}
@@ -137,7 +137,15 @@ function getValues(object, format) {
137137
return utils.arrayify(object.value);
138138

139139
case 'tuple':
140-
return getValues(object.value, format);
140+
var result = getValues(object.value, format, named);
141+
if (named) {
142+
var namedResult = {};
143+
result.forEach(function(value, index) {
144+
namedResult['r' + String(index)] = value;
145+
});
146+
return namedResult;
147+
}
148+
return result;
141149

142150
default:
143151
throw new Error('invalid type - ' + object.type);
@@ -236,6 +244,7 @@ describe('Contract Interface ABI v2 Decoding', function() {
236244
var Interface = require('../contracts/index.js').Interface;
237245

238246
var tests = utils.loadTests('contract-interface-abi2');
247+
239248
tests.forEach(function(test) {
240249
var values = getValues(JSON.parse(test.values));
241250
var types = JSON.parse(test.types);
@@ -255,17 +264,24 @@ describe('Contract Interface ABI v2 Encoding', function() {
255264
var tests = utils.loadTests('contract-interface-abi2');
256265
tests.forEach(function(test) {
257266
var values = getValues(JSON.parse(test.values));
267+
var namedValues = getValues(JSON.parse(test.values), undefined, true);
258268
var types = JSON.parse(test.types);
259269
var expected = test.result;
260270
var title = test.name + ' => (' + test.types + ') = (' + test.value + ')';
261271

262-
it(('encodes parameters - ' + test.name + ' - ' + test.types), function() {
272+
it(('encodes ABIv2 parameters - ' + test.name + ' - ' + test.types), function() {
263273
var encoded = Interface.encodeParams(types, values);
264-
assert.equal(encoded, expected, 'decoded parameters - ' + title);
274+
assert.equal(encoded, expected, 'encoded positional parameters - ' + title);
275+
276+
var contractInterface = new Interface(test.interface);
277+
var outputNames = contractInterface.functions.test.outputs.names;
278+
var namedEncoded = Interface.encodeParams(outputNames, types, values);
279+
assert.equal(namedEncoded, expected, 'encoded named parameters - ' + title);
265280
});
266281
});
267282
});
268283

284+
/*
269285
describe('Contract Interface ABI v2 Named Decoding', function() {
270286
var Interface = require('../contracts').Interface;
271287
@@ -283,6 +299,7 @@ describe('Contract Interface ABI v2 Named Decoding', function() {
283299
//console.dir(decoded, { depth: null });
284300
});
285301
});
302+
*/
286303

287304
describe('Test Contract Events', function() {
288305
var Interface = require('../contracts').Interface;

0 commit comments

Comments
 (0)