From 8b860926f6a8e5a733c3d01321bf888a19b79f12 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 16 May 2024 16:47:18 +0100 Subject: [PATCH 1/4] feat: return `dynamicKeyName` and `dynamicKeyPart` for `getSchema` with Array --- src/lib/schemaParser.test.ts | 10 +++++++--- src/lib/schemaParser.ts | 11 +++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/lib/schemaParser.test.ts b/src/lib/schemaParser.test.ts index 58960c7a..65bdfd0e 100644 --- a/src/lib/schemaParser.test.ts +++ b/src/lib/schemaParser.test.ts @@ -34,7 +34,7 @@ describe('schemaParser getSchema', () => { }); }); - describe('Array', () => { + describe.only('Array', () => { it('finds initial key of type Array correctly', () => { const schema = getSchema( '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', @@ -56,15 +56,19 @@ describe('schemaParser getSchema', () => { assert.deepStrictEqual(schema, { '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001': { - name: 'LSP12IssuedAssets[1]', + name: 'LSP12IssuedAssets[]', key: '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', + dynamicName: 'LSP12IssuedAssets[1]', + dynamicKeyPart: '0x00000000000000000000000000000001', keyType: 'Singleton', valueContent: 'Address', valueType: 'address', }, '0xdf30dba06db6a30e65354d9a64c6098600000000000000000000000000000000': { - name: 'AddressPermissions[0]', + name: 'AddressPermissions[]', key: '0xdf30dba06db6a30e65354d9a64c6098600000000000000000000000000000000', + dynamicName: 'AddressPermissions[0]', + dynamicKeyPart: '0x00000000000000000000000000000000', keyType: 'Singleton', valueContent: 'Address', valueType: 'address', diff --git a/src/lib/schemaParser.ts b/src/lib/schemaParser.ts index fee9f607..ea49488d 100644 --- a/src/lib/schemaParser.ts +++ b/src/lib/schemaParser.ts @@ -102,7 +102,7 @@ const findSingletonSchemaForKey = ( const findArraySchemaForKey = ( key: string, schemas: ERC725JSONSchema[], -): ERC725JSONSchema | null => { +): ERC725JSONSchema | DynamicNameSchema | null => { // Should detect: // 1. Initial key @@ -132,7 +132,9 @@ const findArraySchemaForKey = ( return { ...arraySchema, key, - name: arraySchema.name.replace('[]', `[${elementIndex}]`), + dynamicName: arraySchema.name.replace('[]', `[${elementIndex}]`), + dynamicKeyPart: `0x${key.substring(34)}`, + name: arraySchema.name, keyType: 'Singleton', }; }; @@ -178,8 +180,9 @@ const findMappingWithGroupingSchemaForKey = ( const dynamicKeyPart = key.substring(26); if (isDynamicKeyName(keySchema.name)) { - (keySchema as DynamicNameSchema).dynamicName = - `${keyNameParts[0]}:${keyNameParts[1]}:0x${dynamicKeyPart}`; + ( + keySchema as DynamicNameSchema + ).dynamicName = `${keyNameParts[0]}:${keyNameParts[1]}:0x${dynamicKeyPart}`; (keySchema as DynamicNameSchema).dynamicKeyPart = `0x${dynamicKeyPart}`; } From 5217fba910295f3a66fb5a282054c38b47f4f669 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 16 May 2024 16:48:39 +0100 Subject: [PATCH 2/4] chore: replace incorrect reference `LSP3IssuedAssets[]` -> `LSP12IssuedAssets[]` --- src/lib/encodeKeyName.test.ts | 4 ++-- src/lib/utils.test.ts | 36 +++++++++++++++++------------------ test/mockSchema.ts | 4 ++-- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/lib/encodeKeyName.test.ts b/src/lib/encodeKeyName.test.ts index 31e44922..05dfa044 100644 --- a/src/lib/encodeKeyName.test.ts +++ b/src/lib/encodeKeyName.test.ts @@ -38,9 +38,9 @@ describe('encodeKeyName', () => { expectedKey: keccak256('MyKeyName'), }, { - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', expectedKey: - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', }, { keyName: 'SupportedStandards:LSP3Profile', diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index 3f994707..a84a7772 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -49,8 +49,8 @@ describe('utils', () => { // test encoding an array of address { schema: { - name: 'LSP3IssuedAssets[]', - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + name: 'LSP12IssuedAssets[]', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', keyType: 'Array', valueContent: 'Address', valueType: 'address', @@ -61,7 +61,7 @@ describe('utils', () => { ], encodedValue: [ { - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', value: '0x00000000000000000000000000000002', }, { @@ -239,8 +239,8 @@ describe('utils', () => { it('should encode the array length only if passing a number', async () => { const schema: ERC725JSONSchema = { - name: 'LSP3IssuedAssets[]', - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + name: 'LSP12IssuedAssets[]', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', keyType: 'Array', valueContent: 'Address', valueType: 'address', @@ -438,8 +438,8 @@ describe('utils', () => { describe('encodeArrayKey', () => { it('should encode the array length only if passing a number', async () => { const schema: ERC725JSONSchema = { - name: 'LSP3IssuedAssets[]', - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + name: 'LSP12IssuedAssets[]', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', keyType: 'Array', valueContent: 'Address', valueType: 'address', @@ -455,8 +455,8 @@ describe('utils', () => { describe('encodeData', () => { const schemas: ERC725JSONSchema[] = [ { - name: 'LSP3IssuedAssets[]', - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + name: 'LSP12IssuedAssets[]', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', keyType: 'Array', valueContent: 'Address', valueType: 'address', @@ -550,7 +550,7 @@ describe('utils', () => { const encodedDataWithMultipleKeys = encodeData( [ { - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', value: ['0xa3e6F38477D45727F6e6f853Cdb479b0D60c0aC9'], }, ], @@ -559,7 +559,7 @@ describe('utils', () => { assert.deepStrictEqual(encodedDataWithMultipleKeys, { keys: [ - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', ], values: [ @@ -586,7 +586,7 @@ describe('utils', () => { const encodedDataWithMultipleKeys = encodeData( [ { - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', value: addressArray, }, ], @@ -595,7 +595,7 @@ describe('utils', () => { assert.deepStrictEqual(encodedDataWithMultipleKeys, { keys: [ - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000002', @@ -618,7 +618,7 @@ describe('utils', () => { const encodedArrayLengthKey = encodeData( [ { - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', value: length, }, ], @@ -627,7 +627,7 @@ describe('utils', () => { assert.deepStrictEqual(encodedArrayLengthKey, { keys: [ - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', ], values: ['0x00000000000000000000000000000005'], }); @@ -647,7 +647,7 @@ describe('utils', () => { }, }, { - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', value: [ '0xD94353D9B005B3c0A9Da169b768a31C57844e490', '0xDaea594E385Fc724449E3118B2Db7E86dFBa1826', @@ -664,7 +664,7 @@ describe('utils', () => { assert.deepStrictEqual(encodedMultipleKeys, { keys: [ '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', '0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47', @@ -921,7 +921,7 @@ describe('utils', () => { }, { keyType: 'Array', - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', }, { keyType: 'Mapping', diff --git a/test/mockSchema.ts b/test/mockSchema.ts index 485b778e..52174495 100644 --- a/test/mockSchema.ts +++ b/test/mockSchema.ts @@ -181,8 +181,8 @@ export const mockSchema: (ERC725JSONSchema & { // Case 9 { - name: 'LSP3IssuedAssets[]', - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + name: 'LSP12IssuedAssets[]', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', keyType: 'Array', valueContent: 'Address', valueType: 'address', From a36f69478d7131ad33c2aedce876c92c6cb12a67 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 16 May 2024 20:54:56 +0100 Subject: [PATCH 3/4] test: add tests for encoding array index --- src/index.test.ts | 11 +++++++++++ src/lib/encodeKeyName.ts | 16 +++++++++++++--- src/lib/schemaParser.test.ts | 2 +- src/lib/utils.test.ts | 32 ++++++++++++++++---------------- src/types/dynamicKeys.ts | 2 +- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index 25e2c9ca..35e30eab 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1880,6 +1880,17 @@ describe('encodeKeyName', () => { '0x31145577efe228036af40000a4fbbfe353124e6fa6bb7f8e088a9269df552ea2', ); }); + + it('works for Array keys with index as `dynamicKeyParts', () => { + assert.deepStrictEqual( + encodeKeyName('MusicPlaylist[]', 2), + '0x03573598507fc76d82171baa336b7fd700000000000000000000000000000002', + ); + assert.deepStrictEqual( + erc725Instance.encodeKeyName('MusicPlaylist[]', 2), + '0x03573598507fc76d82171baa336b7fd700000000000000000000000000000002', + ); + }); }); describe('supportsInterface', () => { diff --git a/src/lib/encodeKeyName.ts b/src/lib/encodeKeyName.ts index 7cf4c0da..68c8543d 100644 --- a/src/lib/encodeKeyName.ts +++ b/src/lib/encodeKeyName.ts @@ -26,7 +26,7 @@ import { padLeft, } from 'web3-utils'; -import { guessKeyTypeFromKeyName } from './utils'; +import { encodeArrayKey, guessKeyTypeFromKeyName } from './utils'; import { DynamicKeyParts } from '../types/dynamicKeys'; // https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-2-ERC725YJSONSchema.md#mapping @@ -248,9 +248,12 @@ function encodeDynamicKeyName( switch (keyType) { case 'Mapping': - return encodeDynamicMapping(name, dynamicKeyPartsArray); + return encodeDynamicMapping(name, dynamicKeyPartsArray as string[]); case 'MappingWithGrouping': - return encodeDynamicMappingWithGrouping(name, dynamicKeyPartsArray); + return encodeDynamicMappingWithGrouping( + name, + dynamicKeyPartsArray as string[], + ); default: throw new Error( `Could not encode dynamic key: ${name} of type: ${keyType}`, @@ -295,6 +298,13 @@ export function encodeKeyName(name: string, dynamicKeyParts?: DynamicKeyParts) { ]); } case 'Array': // Warning: this can not correctly encode subsequent keys of array, only the initial Array key will work + // encode for array index + if (dynamicKeyParts && typeof dynamicKeyParts == 'number') { + return encodeArrayKey(keccak256(name), dynamicKeyParts); + } + + // encode for array length + return keccak256(name); case 'Singleton': return keccak256(name); default: diff --git a/src/lib/schemaParser.test.ts b/src/lib/schemaParser.test.ts index 65bdfd0e..dcd8d60f 100644 --- a/src/lib/schemaParser.test.ts +++ b/src/lib/schemaParser.test.ts @@ -34,7 +34,7 @@ describe('schemaParser getSchema', () => { }); }); - describe.only('Array', () => { + describe('Array', () => { it('finds initial key of type Array correctly', () => { const schema = getSchema( '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index a84a7772..50693904 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -65,11 +65,11 @@ describe('utils', () => { value: '0x00000000000000000000000000000002', }, { - key: '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', + key: '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', value: '0xc444009d38d3046bb0cf81fa2cd295ce46a67c78', }, { - key: '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', + key: '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', value: '0x4febc3491230571f6e1829e46602e3b110215a2e', }, ], @@ -560,7 +560,7 @@ describe('utils', () => { assert.deepStrictEqual(encodedDataWithMultipleKeys, { keys: [ '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', ], values: [ '0x00000000000000000000000000000001', @@ -596,17 +596,17 @@ describe('utils', () => { assert.deepStrictEqual(encodedDataWithMultipleKeys, { keys: [ '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000002', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000003', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000004', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000005', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000006', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000007', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000008', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000009', - '0x3a47ab5bd3a594c3a8995f8fa58d08760000000000000000000000000000000a', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000002', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000003', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000004', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000005', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000006', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000007', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000008', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000009', + '0x7c8c3416d6cda87cd42c71ea1843df280000000000000000000000000000000a', ], values: ['0x0000000000000000000000000000000b', ...addressArray], }); @@ -665,8 +665,8 @@ describe('utils', () => { keys: [ '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', '0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47', ], values: [ diff --git a/src/types/dynamicKeys.ts b/src/types/dynamicKeys.ts index 19db626e..a2ab4b9f 100644 --- a/src/types/dynamicKeys.ts +++ b/src/types/dynamicKeys.ts @@ -2,7 +2,7 @@ import { EncodeDataType } from './encodeData/JSONURL'; -export type DynamicKeyParts = string | string[]; +export type DynamicKeyParts = string | string[] | number; export interface DynamicKeyPartInput { dynamicKeyParts: DynamicKeyParts; From 5445222d2d235c67ffefabbcfbc5c02a40395edb Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 17 May 2024 09:27:55 +0200 Subject: [PATCH 4/4] chore: fix linter errors --- src/lib/encodeKeyName.ts | 2 +- src/lib/schemaParser.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib/encodeKeyName.ts b/src/lib/encodeKeyName.ts index 68c8543d..ebdabdf5 100644 --- a/src/lib/encodeKeyName.ts +++ b/src/lib/encodeKeyName.ts @@ -299,7 +299,7 @@ export function encodeKeyName(name: string, dynamicKeyParts?: DynamicKeyParts) { } case 'Array': // Warning: this can not correctly encode subsequent keys of array, only the initial Array key will work // encode for array index - if (dynamicKeyParts && typeof dynamicKeyParts == 'number') { + if (dynamicKeyParts && typeof dynamicKeyParts === 'number') { return encodeArrayKey(keccak256(name), dynamicKeyParts); } diff --git a/src/lib/schemaParser.ts b/src/lib/schemaParser.ts index ea49488d..3cdde5ec 100644 --- a/src/lib/schemaParser.ts +++ b/src/lib/schemaParser.ts @@ -180,9 +180,8 @@ const findMappingWithGroupingSchemaForKey = ( const dynamicKeyPart = key.substring(26); if (isDynamicKeyName(keySchema.name)) { - ( - keySchema as DynamicNameSchema - ).dynamicName = `${keyNameParts[0]}:${keyNameParts[1]}:0x${dynamicKeyPart}`; + (keySchema as DynamicNameSchema).dynamicName = + `${keyNameParts[0]}:${keyNameParts[1]}:0x${dynamicKeyPart}`; (keySchema as DynamicNameSchema).dynamicKeyPart = `0x${dynamicKeyPart}`; }