Skip to content

Commit

Permalink
refactor!: change ArrayLength value from uint256 to uint128 (#287)
Browse files Browse the repository at this point in the history
* refactor: change ArrayLength value from uint256 to uint128

* refactor: fix decoding for array length as `uint128`

* refactor!: encode value for `Array` length as `uint128` (16 bytes long)

* test: fix mock schemas for tests

* refactor: deprecate `ArrayLength` valueContent + use `encodeValueType` to encode Array length

* test: update mock schemas for array length as left padded not abi-encoded

* refactor: Update encoding/decoding for `uint128`

* test: add more tests

* chore: add sugested changes

* refactor: update the encoding for `uint128`

* chore: add spaces between `it` blocks

* test: improve tests

---------

Co-authored-by: CJ42 <31145285+CJ42@users.noreply.github.com>
Co-authored-by: CJ42 <cavallerajean@gmail.com>
  • Loading branch information
3 people authored Jul 24, 2023
1 parent 1ee2700 commit c95ee8a
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ describe('Running @erc725/erc725.js tests...', () => {
if (i === 0) {
// Push the array length into the first element of results array
results.push(
leftPad(numberToHex(schemaElement.expectedResult.length), 64),
leftPad(numberToHex(schemaElement.expectedResult.length), 32),
);
}

Expand Down
3 changes: 1 addition & 2 deletions src/lib/decodeData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ describe('decodeData', () => {
value: [
{
key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd',
value:
'0x0000000000000000000000000000000000000000000000000000000000000002',
value: '0x00000000000000000000000000000002',
},
{
key: '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000',
Expand Down
2 changes: 1 addition & 1 deletion src/lib/decodeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export function decodeKey(schema: ERC725JSONSchema, value) {
}

const arrayLength =
decodeKeyValue('Number', 'uint256', valueElement.value, schema.name) ||
decodeKeyValue('Number', 'uint128', valueElement.value, schema.name) ||
0;

// This will not run if no match or arrayLength
Expand Down
26 changes: 26 additions & 0 deletions src/lib/encoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ describe('encoder', () => {
encodedValue:
'0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7',
},
{
valueType: 'uint128',
decodedValue: 11,
encodedValue: '0x0000000000000000000000000000000b',
},
{
valueType: 'uint256',
decodedValue: '1337',
Expand Down Expand Up @@ -220,6 +225,27 @@ describe('encoder', () => {
});
});

it('throws when trying to encode a string as `uint128`', () => {
assert.throws(() => encodeValueType('uint128', 'helloWorld'));
});

it('throws when trying to encode a bytes17 as `uint128`', () => {
assert.throws(() =>
encodeValueType('uint128', '340282366920938463463374607431768211456'),
);
assert.throws(() =>
encodeValueType('uint128', '0x0100000000000000000000000000000000'),
);
});

it('throws when trying to decode a bytes17 as `uint128`', () => {
expect(() =>
decodeValueType('uint128', '0x000000000000000000000000000000ffff'),
).to.throw(
"Can't convert hex value 0x000000000000000000000000000000ffff to uint128. Too many bytes. 17 > 16",
);
});

describe('when encoding bytes[CompactBytesArray]', () => {
it('should encode `0x` elements as `0x0000`', async () => {
const testCase = {
Expand Down
36 changes: 27 additions & 9 deletions src/lib/encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@ import {
toChecksumAddress,
utf8ToHex,
stripHexPrefix,
hexToBytes,
bytesToHex,
} from 'web3-utils';

import BigNumber from 'bignumber.js';

import { JSONURLDataToEncode, URLDataWithHash } from '../types';
import { AssetURLEncode } from '../types/encodeData';

Expand Down Expand Up @@ -325,6 +329,28 @@ const valueTypeEncodingMap = {
decode: (value: string) => abiCoder.decodeParameter('address', value),
},
// NOTE: We could add conditional handling of numeric values here...
uint128: {
encode: (value: string | number) => {
const abiEncodedValue = abiCoder.encodeParameter('uint128', value);
const bytesArray = hexToBytes(abiEncodedValue);
return bytesToHex(bytesArray.slice(16));
},
decode: (value: string) => {
if (!isHex(value)) {
throw new Error(`Can't convert ${value} to uint128, value is not hex.`);
}

if (value.length > 34) {
throw new Error(
`Can't convert hex value ${value} to uint128. Too many bytes. ${
(value.length - 2) / 2
} > 16`,
);
}

return BigNumber(value).toNumber();
},
},
uint256: {
encode: (value: string | number) =>
abiCoder.encodeParameter('uint256', value),
Expand Down Expand Up @@ -402,14 +428,6 @@ export const valueContentEncodingMap = (valueContent: string) => {
decode: (value: string) => value,
};
}
// NOTE: Deprecated. For reference/testing in future
case 'ArrayLength': {
return {
type: 'uint256',
encode: (value: number | string) => padLeft(numberToHex(value), 64),
decode: (value: string) => hexToNumber(value),
};
}
case 'Number': {
return {
type: 'uint256',
Expand All @@ -424,7 +442,7 @@ export const valueContentEncodingMap = (valueContent: string) => {

return padLeft(numberToHex(parsedValue), 64);
},
decode: (value) => '' + hexToNumber(value),
decode: (value) => hexToNumber(value).toString(),
};
}
// NOTE: This is not symmetrical, and always returns a checksummed address
Expand Down
2 changes: 1 addition & 1 deletion src/lib/getData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const getArrayValues = async (

const arrayLength = await decodeKeyValue(
'Number',
'uint256',
'uint128',
value.value,
schema.name,
); // get the int array length
Expand Down
53 changes: 47 additions & 6 deletions src/lib/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ describe('utils', () => {
encodedValue: [
{
key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0',
value:
'0x0000000000000000000000000000000000000000000000000000000000000002',
value: '0x00000000000000000000000000000002',
},
{
key: '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000',
Expand Down Expand Up @@ -95,8 +94,7 @@ describe('utils', () => {
encodedValue: [
{
key: '0x9985edaf12cbacf5ac7d6ed54f0445cc0ea56075aee9b9942e4ab3bf4239f950',
value:
'0x0000000000000000000000000000000000000000000000000000000000000002',
value: '0x00000000000000000000000000000002',
},
{
key: '0x9985edaf12cbacf5ac7d6ed54f0445cc00000000000000000000000000000000',
Expand Down Expand Up @@ -512,12 +510,55 @@ describe('utils', () => {
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000',
],
values: [
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x00000000000000000000000000000001',
'0xa3e6f38477d45727f6e6f853cdb479b0d60c0ac9',
],
});
});

it('encodes array', () => {
const addressArray = [
'0x6413255d24b8fbf81d2d65214c485c694cb3d4b4',
'0xd6c68c2c94af899ce43ff1863693016a711ae7c7',
'0x79b698f4bc3051f18b5f94046f09d70823a8fd44',
'0x72bebf88546525a5888f188b390701bb0fd9b1a5',
'0x882aca051979e32e787e8815d9880759f91e7124',
'0x78827c8f8205072858a8cce39b8724d948327ba0',
'0xe27cd9c132677cdce2e9efa43b040de35ceff069',
'0x072616745957b45c8989e12b9563390fafac4ebe',
'0xfd5a7c50c0cf665a772407af3f05522784589c44',
'0x13de082cf8a499eee75b0681cfa0141a145f15d9',
'0xe3610d0eb167fe7a7b7c25d0aee8874eb8b113ef',
];
const encodedDataWithMultipleKeys = encodeData(
[
{
keyName: 'LSP3IssuedAssets[]',
value: addressArray,
},
],
schemas,
);

assert.deepStrictEqual(encodedDataWithMultipleKeys, {
keys: [
'0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000002',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000003',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000004',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000005',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000006',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000007',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000008',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000009',
'0x3a47ab5bd3a594c3a8995f8fa58d08760000000000000000000000000000000a',
],
values: ['0x0000000000000000000000000000000b', ...addressArray],
});
});

it('encodes multiple keys', () => {
const encodedMultipleKeys = encodeData(
[
Expand Down Expand Up @@ -554,7 +595,7 @@ describe('utils', () => {
],
values: [
'0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
'0x0000000000000000000000000000000000000000000000000000000000000002',
'0x00000000000000000000000000000002',
'0xd94353d9b005b3c0a9da169b768a31c57844e490',
'0xdaea594e385fc724449e3118b2db7e86dfba1826',
'0x1183790f29be3cdfd0a102862fea1a4a30b3adab',
Expand Down
8 changes: 2 additions & 6 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,10 @@ export function encodeKey(
const dataElement = value[index];
if (index === 0) {
// This is arrayLength as the first element in the raw array
// encoded as uint128
results.push({
key: schema.key,
value: encodeKeyValue(
'Number',
'uint256',
value.length.toString(),
schema.name,
) as string,
value: encodeValueType('uint128', value.length),
});
}

Expand Down
26 changes: 10 additions & 16 deletions test/mockSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// make one schema that tests every single type

import AbiCoder from 'web3-eth-abi';
import { utf8ToHex } from 'web3-utils';
import { leftPad, utf8ToHex } from 'web3-utils';

import { ERC725JSONSchema } from '../src/types/ERC725JSONSchema';

Expand Down Expand Up @@ -185,7 +185,7 @@ export const mockSchema: (ERC725JSONSchema & {
// testing data
// the full array of values
returnRawData: [
abiCoder.encodeParameter('bytes', abiCoder.encodeParameter('uint256', 2)), // array length
abiCoder.encodeParameter('bytes', leftPad(2, 32)), // array length
abiCoder.encodeParameter(
'bytes',
'0xc444009d38d3046bb0cf81fa2cd295ce46a67c78',
Expand All @@ -196,9 +196,7 @@ export const mockSchema: (ERC725JSONSchema & {
),
],
returnRawDataArray: [
abiCoder.encodeParameter('bytes[]', [
abiCoder.encodeParameter('uint256', 2),
]),
abiCoder.encodeParameter('bytes[]', [leftPad(2, 32)]), // array length
abiCoder.encodeParameter('bytes[]', [
'0xc444009d38d3046bb0cf81fa2cd295ce46a67c78',
]),
Expand All @@ -207,7 +205,7 @@ export const mockSchema: (ERC725JSONSchema & {
]),
],
returnGraphData: [
'0x0000000000000000000000000000000000000000000000000000000000000002', // array length
leftPad(2, 32), // array length
'0xc444009d38d3046bb0cf81fa2cd295ce46a67c78',
'0x4febc3491230571f6e1829e46602e3b110215a2e',
],
Expand All @@ -226,24 +224,22 @@ export const mockSchema: (ERC725JSONSchema & {
// testing data
// the full array of values
returnRawData: [
abiCoder.encodeParameter('bytes', abiCoder.encodeParameter('uint256', 2)), // array length
abiCoder.encodeParameter('bytes', leftPad(2, 32)), // array length
abiCoder.encodeParameter('bytes', '0x'),
abiCoder.encodeParameter(
'bytes',
'0x4febc3491230571f6e1829e46602e3b110215a2e',
),
],
returnRawDataArray: [
abiCoder.encodeParameter('bytes[]', [
abiCoder.encodeParameter('uint256', 2),
]),
abiCoder.encodeParameter('bytes[]', [leftPad(2, 32)]),
abiCoder.encodeParameter('bytes[]', ['0x']),
abiCoder.encodeParameter('bytes[]', [
'0x4febc3491230571f6e1829e46602e3b110215a2e',
]),
],
returnGraphData: [
'0x0000000000000000000000000000000000000000000000000000000000000002', // array length
leftPad(2, 32), // array length
'0x',
'0x4febc3491230571f6e1829e46602e3b110215a2e',
],
Expand All @@ -260,7 +256,7 @@ export const mockSchema: (ERC725JSONSchema & {
// testing data
// the full array of values
returnRawData: [
abiCoder.encodeParameter('bytes', abiCoder.encodeParameter('uint256', 2)), // array length
abiCoder.encodeParameter('bytes', leftPad(2, 32)), // array length
abiCoder.encodeParameter(
'bytes',
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
Expand All @@ -271,9 +267,7 @@ export const mockSchema: (ERC725JSONSchema & {
),
],
returnRawDataArray: [
abiCoder.encodeParameter('bytes[]', [
abiCoder.encodeParameter('uint256', 2),
]),
abiCoder.encodeParameter('bytes[]', [leftPad(2, 32)]),
abiCoder.encodeParameter('bytes[]', [
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
]),
Expand All @@ -282,7 +276,7 @@ export const mockSchema: (ERC725JSONSchema & {
]),
],
returnGraphData: [
'0x0000000000000000000000000000000000000000000000000000000000000002', // array length
leftPad(2, 32), // array length
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
],
Expand Down

0 comments on commit c95ee8a

Please sign in to comment.