diff --git a/package-lock.json b/package-lock.json index 9e7ba26a..317f5e5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gridplus-sdk", - "version": "0.7.26", + "version": "0.7.27", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c64a677d..c44f136d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gridplus-sdk", - "version": "0.7.26", + "version": "0.7.27", "description": "SDK to interact with GridPlus Lattice1 device", "scripts": { "commit": "git-cz", diff --git a/src/constants.js b/src/constants.js index 3a435344..637e65ab 100644 --- a/src/constants.js +++ b/src/constants.js @@ -113,66 +113,6 @@ const signingSchema = { EXTRA_DATA: 4, } -const ethMsgProtocol = { - SIGN_PERSONAL: { - str: 'signPersonal', - enumIdx: 0, // Enum index of this protocol in Lattice firmware - }, - TYPED_DATA: { - str: 'typedData', - enumIdx: 1, - rawDataMaxLen: 1629, // Max size of raw data payload in bytes - typeCodes: { // Enum indices of data types in Lattice firmware - 'bytes1': 1, - 'bytes2': 2, - 'bytes3': 3, - 'bytes4': 4, - 'bytes5': 5, - 'bytes6': 6, - 'bytes7': 7, - 'bytes8': 8, - 'bytes9': 9, - 'bytes10': 10, - 'bytes11': 11, - 'bytes12': 12, - 'bytes13': 13, - 'bytes14': 14, - 'bytes15': 15, - 'bytes16': 16, - 'bytes17': 17, - 'bytes18': 18, - 'bytes19': 19, - 'bytes20': 20, - 'bytes21': 21, - 'bytes22': 22, - 'bytes23': 23, - 'bytes24': 24, - 'bytes25': 25, - 'bytes26': 27, - 'bytes27': 28, - 'bytes28': 29, - 'bytes29': 30, - 'bytes30': 31, - 'bytes31': 32, - 'bytes32': 33, - 'uint8': 34, - 'uint16': 35, - 'uint32': 36, - 'uint64': 37, - 'uint256': 38, - // 'int8': 39, // We do not support signed typed right now - // 'int16': 40, - // 'int32': 41, - // 'int64': 42, - // 'int256': 43, - 'bool': 44, - 'address': 45, - 'bytes': 47, - 'string': 48, - } - }, -} - const REQUEST_TYPE_BYTE = 0x02; // For all HSM-bound requests const VERSION_BYTE = 1; const HARDENED_OFFSET = 0x80000000; // Hardened offset @@ -181,7 +121,7 @@ const MAX_CHAIN_ID_BYTES = 8; // Max number of bytes to contain larger chainID i const BASE_URL = 'https://signing.gridpl.us'; -const ETH_ABI_LATTICE_FW_TYPE_MAP = { +const EIP712_ABI_LATTICE_FW_TYPE_MAP = { 'address': 1, 'bool': 2, 'uint8': 3, @@ -283,6 +223,10 @@ const ETH_ABI_LATTICE_FW_TYPE_MAP = { 'bytes32': 100, 'bytes': 101, 'string': 102, +} + +const ETH_ABI_LATTICE_FW_TYPE_MAP = { + ...EIP712_ABI_LATTICE_FW_TYPE_MAP, 'tuple1': 103, 'tuple2': 104, 'tuple3': 105, @@ -302,6 +246,19 @@ const ETH_ABI_LATTICE_FW_TYPE_MAP = { 'tuple17': 119, // Firmware currently cannot support tuples larger than this }; +const ethMsgProtocol = { + SIGN_PERSONAL: { + str: 'signPersonal', + enumIdx: 0, // Enum index of this protocol in Lattice firmware + }, + TYPED_DATA: { + str: 'typedData', + enumIdx: 1, + rawDataMaxLen: 1629, // Max size of raw data payload in bytes + typeCodes: EIP712_ABI_LATTICE_FW_TYPE_MAP // Enum indices of data types in Lattice firmware + }, +} + function getFwVersionConst(v) { const c = { extraDataFrameSz: 0, diff --git a/src/ethereum.js b/src/ethereum.js index 0c99150c..6cfda817 100644 --- a/src/ethereum.js +++ b/src/ethereum.js @@ -668,10 +668,8 @@ function parseEIP712Item(data, type, isEthers=false) { if (isEthers === true) { data = `0x${data.toString('hex')}` } - } else if (type === 'uint8' || type === 'uint16' || type === 'uint32' || type === 'uint64') { - // In this case we want the hex buffer to represent `0` as a 1-byte buffer (`00`) - data = parseInt(ensureHexBuffer(data, false).toString('hex'), 16) - } else if (type === 'uint256') { + } else if ( (constants.ethMsgProtocol.TYPED_DATA.typeCodes[type]) && + (type.indexOf('uint') > -1 || type.indexOf('int') > -1)) { let b = ensureHexBuffer(data); // Edge case to handle 0-value bignums if (b.length === 0) { diff --git a/test/testEthMsg.js b/test/testEthMsg.js index 576e70c8..25ce32f0 100644 --- a/test/testEthMsg.js +++ b/test/testEthMsg.js @@ -289,6 +289,57 @@ describe('Test ETH EIP712', function() { } }) + it('Should test a Loopring message with non-standard numerical type', async () => { + const msg = { + 'types':{ + 'EIP712Domain':[ + {'name':'name','type':'string'}, + {'name':'version','type':'string'}, + {'name':'chainId','type':'uint256'}, + {'name':'verifyingContract','type':'address'} + ], + 'AccountUpdate':[ + {'name':'owner','type':'address'}, + {'name':'accountID','type':'uint32'}, + {'name':'feeTokenID','type':'uint16'}, + {'name':'maxFee','type':'uint96'}, + {'name':'publicKey','type':'uint256'}, + {'name':'validUntil','type':'uint32'}, + {'name':'nonce','type':'uint32'} + ] + }, + 'primaryType':'AccountUpdate', + 'domain':{ + 'name':'Loopring Protocol', + 'version':'3.6.0', + 'chainId':1, + 'verifyingContract':'0x0BABA1Ad5bE3a5C0a66E7ac838a129Bf948f1eA4' + }, + 'message':{ + 'owner':'0x8c3b776bdac9a7a4facc3cc20cdb40832bff9005', + 'accountID':32494, + 'feeTokenID':0, + 'maxFee':100, + 'publicKey':'11413934541425201845815969801249874136651857829494005371571206042985258823663', + 'validUntil':1631655383, + 'nonce':0 + } + } + const req = { + currency: 'ETH_MSG', + data: { + signerPath: [helpers.BTC_LEGACY_PURPOSE, helpers.ETH_COIN, HARDENED_OFFSET, 0, 0], + protocol: 'eip712', + payload: msg, + } + } + try { + await helpers.sign(client, req); + } catch (err) { + expect(err).to.equal(null) + } + }) + it('Should test an example with 0 values', async () => { const msg = { 'types': { diff --git a/test/testUtil/helpers.js b/test/testUtil/helpers.js index 4d2dd684..066161b7 100644 --- a/test/testUtil/helpers.js +++ b/test/testUtil/helpers.js @@ -661,23 +661,20 @@ exports.buildRandomEip712Object = function(randInt) { } } function getRandomEIP712Val(type) { - if (type !== 'bytes' && type.slice(0, 5) === 'bytes') + if (type !== 'bytes' && type.slice(0, 5) === 'bytes') { return `0x${crypto.randomBytes(parseInt(type.slice(5))).toString('hex')}` + } else if (type === 'uint' || type === 'int') { + return `0x${crypto.randomBytes(32).toString('hex')}` + } else if (type.indexOf('uint') > -1) { + return `0x${crypto.randomBytes(parseInt(type.slice(4)))}`; + } else if (type.indexOf('int') > -1) { + return `0x${crypto.randomBytes(parseInt(type.slice(3)))}`; + } switch (type) { case 'bytes': return `0x${crypto.randomBytes(1+randInt(50)).toString('hex')}`; case 'string': return randStr(100); - case 'uint8': - return `0x${crypto.randomBytes(1).toString('hex')}` - case 'uint16': - return `0x${crypto.randomBytes(2).toString('hex')}` - case 'uint32': - return `0x${crypto.randomBytes(3).toString('hex')}` - case 'uint64': - return `0x${crypto.randomBytes(4).toString('hex')}` - case 'uint256': - return `0x${crypto.randomBytes(32).toString('hex')}` case 'bool': return randInt(1) > 0 ? true : false; case 'address':