Added named parameters to tuple encoding.
This commit is contained in:
parent
9aeb309d9d
commit
eddf93b200
@ -262,11 +262,27 @@ function alignSize(size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function pack(coders, values) {
|
function pack(coders, values) {
|
||||||
|
if (Array.isArray(values)) {
|
||||||
|
if (coders.length !== values.length) {
|
||||||
|
throwError('types/values mismatch', { type: type, values: values });
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (values && typeof(values) === 'object') {
|
||||||
|
var arrayValues = [];
|
||||||
|
coders.forEach(function(coder) {
|
||||||
|
arrayValues.push(values[coder.localName]);
|
||||||
|
});
|
||||||
|
values = arrayValues;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throwError('invalid value', { type: 'tuple', values: values });
|
||||||
|
}
|
||||||
|
|
||||||
var parts = [];
|
var parts = [];
|
||||||
|
|
||||||
coders.forEach(function(coder, index) {
|
coders.forEach(function(coder, index) {
|
||||||
parts.push({ dynamic: coder.dynamic, value: coder.encode(values[index]) });
|
parts.push({ dynamic: coder.dynamic, value: coder.encode(values[index]) });
|
||||||
})
|
});
|
||||||
|
|
||||||
var staticSize = 0, dynamicSize = 0;
|
var staticSize = 0, dynamicSize = 0;
|
||||||
parts.forEach(function(part, index) {
|
parts.forEach(function(part, index) {
|
||||||
@ -414,17 +430,6 @@ function coderTuple(coders, localName) {
|
|||||||
name: 'tuple',
|
name: 'tuple',
|
||||||
type: type,
|
type: type,
|
||||||
encode: function(value) {
|
encode: function(value) {
|
||||||
if (Array.isArray(value)) {
|
|
||||||
if (coders.length !== value.length) {
|
|
||||||
throwError('types/values mismatch', { type: type, values: values });
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TODO: If receiving an object, and we have names, create the array
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throwError('invalid value', { type: types, values: values });
|
|
||||||
}
|
|
||||||
|
|
||||||
return pack(coders, value);
|
return pack(coders, value);
|
||||||
},
|
},
|
||||||
decode: function(data, offset) {
|
decode: function(data, offset) {
|
||||||
@ -572,29 +577,27 @@ function Interface(abi) {
|
|||||||
switch (method.type) {
|
switch (method.type) {
|
||||||
case 'constructor':
|
case 'constructor':
|
||||||
var func = (function() {
|
var func = (function() {
|
||||||
// @TODO: Move to parseParams
|
var inputParams = parseParams(method.inputs);
|
||||||
var inputTypes = getKeys(method.inputs, 'type');
|
|
||||||
var func = function(bytecode) {
|
var func = function(bytecode) {
|
||||||
if (!utils.isHexString(bytecode)) {
|
if (!utils.isHexString(bytecode)) {
|
||||||
throwError('invalid bytecode', {input: bytecode});
|
throwError('invalid bytecode', { input: bytecode });
|
||||||
}
|
}
|
||||||
|
|
||||||
var params = Array.prototype.slice.call(arguments, 1);
|
var params = Array.prototype.slice.call(arguments, 1);
|
||||||
if (params.length < inputTypes.length) {
|
if (params.length < inputParams.types.length) {
|
||||||
throwError('missing parameter');
|
throwError('missing parameter');
|
||||||
} else if (params.length > inputTypes.length) {
|
} else if (params.length > inputParams.types.length) {
|
||||||
throwError('too many parameters');
|
throwError('too many parameters');
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = {
|
var result = {
|
||||||
bytecode: bytecode + Interface.encodeParams(inputTypes, params).substring(2),
|
bytecode: bytecode + Interface.encodeParams(inputParams.names, inputParams.types, params).substring(2),
|
||||||
}
|
}
|
||||||
|
|
||||||
return populateDescription(new DeployDescription(), result);
|
return populateDescription(new DeployDescription(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Move to parseParams
|
defineFrozen(func, 'inputs', inputParams);
|
||||||
defineFrozen(func, 'inputs', getKeys(method.inputs, 'name'));
|
|
||||||
|
|
||||||
return func;
|
return func;
|
||||||
})();
|
})();
|
||||||
@ -608,7 +611,6 @@ function Interface(abi) {
|
|||||||
var inputParams = parseParams(method.inputs);
|
var inputParams = parseParams(method.inputs);
|
||||||
var outputParams = parseParams(method.outputs);
|
var outputParams = parseParams(method.outputs);
|
||||||
|
|
||||||
var inputTypes = inputParams.types;
|
|
||||||
if (method.constant) {
|
if (method.constant) {
|
||||||
var outputTypes = outputParams.types;
|
var outputTypes = outputParams.types;
|
||||||
var outputNames = outputParams.names;
|
var outputNames = outputParams.names;
|
||||||
@ -628,13 +630,13 @@ function Interface(abi) {
|
|||||||
|
|
||||||
var params = Array.prototype.slice.call(arguments, 0);
|
var params = Array.prototype.slice.call(arguments, 0);
|
||||||
|
|
||||||
if (params.length < inputTypes.length) {
|
if (params.length < inputParams.types.length) {
|
||||||
throwError('missing parameter');
|
throwError('missing parameter');
|
||||||
} else if (params.length > inputTypes.length) {
|
} else if (params.length > inputParams.types.length) {
|
||||||
throwError('too many parameters');
|
throwError('too many parameters');
|
||||||
}
|
}
|
||||||
|
|
||||||
result.data = sighash + Interface.encodeParams(inputTypes, params).substring(2);
|
result.data = sighash + Interface.encodeParams(inputParams.names, inputParams.types, params).substring(2);
|
||||||
if (method.constant) {
|
if (method.constant) {
|
||||||
result.parse = function(data) {
|
result.parse = function(data) {
|
||||||
return Interface.decodeParams(
|
return Interface.decodeParams(
|
||||||
@ -649,9 +651,8 @@ function Interface(abi) {
|
|||||||
return populateDescription(new TransactionDescription(), result);
|
return populateDescription(new TransactionDescription(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Move the paraseParams
|
defineFrozen(func, 'inputs', inputParams);
|
||||||
defineFrozen(func, 'inputs', getKeys(method.inputs, 'name'));
|
defineFrozen(func, 'outputs', outputParams);
|
||||||
defineFrozen(func, 'outputs', getKeys(method.outputs, 'name'));
|
|
||||||
|
|
||||||
utils.defineProperty(func, 'signature', signature);
|
utils.defineProperty(func, 'signature', signature);
|
||||||
utils.defineProperty(func, 'sighash', sighash);
|
utils.defineProperty(func, 'sighash', sighash);
|
||||||
@ -803,12 +804,20 @@ function Interface(abi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
utils.defineProperty(Interface, 'encodeParams', function(types, values) {
|
utils.defineProperty(Interface, 'encodeParams', function(names, types, values) {
|
||||||
|
|
||||||
|
// Names is optional, so shift over all the parameters if not provided
|
||||||
|
if (arguments.length < 3) {
|
||||||
|
values = types;
|
||||||
|
types = names;
|
||||||
|
names = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (types.length !== values.length) { throwError('types/values mismatch', {types: types, values: values}); }
|
if (types.length !== values.length) { throwError('types/values mismatch', {types: types, values: values}); }
|
||||||
|
|
||||||
var coders = [];
|
var coders = [];
|
||||||
types.forEach(function(type) {
|
types.forEach(function(type, index) {
|
||||||
coders.push(getParamCoder(type));
|
coders.push(getParamCoder(type, (names ? names[index]: undefined)));
|
||||||
});
|
});
|
||||||
|
|
||||||
return utils.hexlify(coderTuple(coders).encode(values));
|
return utils.hexlify(coderTuple(coders).encode(values));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ethers-contracts",
|
"name": "ethers-contracts",
|
||||||
"version": "2.1.10",
|
"version": "2.2.0",
|
||||||
"description": "Contract and Interface (ABI) library for Ethereum.",
|
"description": "Contract and Interface (ABI) library for Ethereum.",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "http://github.com/ethers-io/ethers.js/issues",
|
"url": "http://github.com/ethers-io/ethers.js/issues",
|
||||||
|
@ -95,11 +95,11 @@ function equals(actual, expected) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getValues(object, format) {
|
function getValues(object, format, named) {
|
||||||
if (Array.isArray(object)) {
|
if (Array.isArray(object)) {
|
||||||
var result = [];
|
var result = [];
|
||||||
object.forEach(function(object) {
|
object.forEach(function(object) {
|
||||||
result.push(getValues(object, format));
|
result.push(getValues(object, format, named));
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -137,7 +137,15 @@ function getValues(object, format) {
|
|||||||
return utils.arrayify(object.value);
|
return utils.arrayify(object.value);
|
||||||
|
|
||||||
case 'tuple':
|
case 'tuple':
|
||||||
return getValues(object.value, format);
|
var result = getValues(object.value, format, named);
|
||||||
|
if (named) {
|
||||||
|
var namedResult = {};
|
||||||
|
result.forEach(function(value, index) {
|
||||||
|
namedResult['r' + String(index)] = value;
|
||||||
|
});
|
||||||
|
return namedResult;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error('invalid type - ' + object.type);
|
throw new Error('invalid type - ' + object.type);
|
||||||
@ -236,6 +244,7 @@ describe('Contract Interface ABI v2 Decoding', function() {
|
|||||||
var Interface = require('../contracts/index.js').Interface;
|
var Interface = require('../contracts/index.js').Interface;
|
||||||
|
|
||||||
var tests = utils.loadTests('contract-interface-abi2');
|
var tests = utils.loadTests('contract-interface-abi2');
|
||||||
|
|
||||||
tests.forEach(function(test) {
|
tests.forEach(function(test) {
|
||||||
var values = getValues(JSON.parse(test.values));
|
var values = getValues(JSON.parse(test.values));
|
||||||
var types = JSON.parse(test.types);
|
var types = JSON.parse(test.types);
|
||||||
@ -255,17 +264,24 @@ describe('Contract Interface ABI v2 Encoding', function() {
|
|||||||
var tests = utils.loadTests('contract-interface-abi2');
|
var tests = utils.loadTests('contract-interface-abi2');
|
||||||
tests.forEach(function(test) {
|
tests.forEach(function(test) {
|
||||||
var values = getValues(JSON.parse(test.values));
|
var values = getValues(JSON.parse(test.values));
|
||||||
|
var namedValues = getValues(JSON.parse(test.values), undefined, true);
|
||||||
var types = JSON.parse(test.types);
|
var types = JSON.parse(test.types);
|
||||||
var expected = test.result;
|
var expected = test.result;
|
||||||
var title = test.name + ' => (' + test.types + ') = (' + test.value + ')';
|
var title = test.name + ' => (' + test.types + ') = (' + test.value + ')';
|
||||||
|
|
||||||
it(('encodes parameters - ' + test.name + ' - ' + test.types), function() {
|
it(('encodes ABIv2 parameters - ' + test.name + ' - ' + test.types), function() {
|
||||||
var encoded = Interface.encodeParams(types, values);
|
var encoded = Interface.encodeParams(types, values);
|
||||||
assert.equal(encoded, expected, 'decoded parameters - ' + title);
|
assert.equal(encoded, expected, 'encoded positional parameters - ' + title);
|
||||||
|
|
||||||
|
var contractInterface = new Interface(test.interface);
|
||||||
|
var outputNames = contractInterface.functions.test.outputs.names;
|
||||||
|
var namedEncoded = Interface.encodeParams(outputNames, types, values);
|
||||||
|
assert.equal(namedEncoded, expected, 'encoded named parameters - ' + title);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
describe('Contract Interface ABI v2 Named Decoding', function() {
|
describe('Contract Interface ABI v2 Named Decoding', function() {
|
||||||
var Interface = require('../contracts').Interface;
|
var Interface = require('../contracts').Interface;
|
||||||
|
|
||||||
@ -283,6 +299,7 @@ describe('Contract Interface ABI v2 Named Decoding', function() {
|
|||||||
//console.dir(decoded, { depth: null });
|
//console.dir(decoded, { depth: null });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
describe('Test Contract Events', function() {
|
describe('Test Contract Events', function() {
|
||||||
var Interface = require('../contracts').Interface;
|
var Interface = require('../contracts').Interface;
|
||||||
|
Loading…
Reference in New Issue
Block a user