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.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/encodeKeyName.ts b/src/lib/encodeKeyName.ts index 7cf4c0da..ebdabdf5 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 58960c7a..dcd8d60f 100644 --- a/src/lib/schemaParser.test.ts +++ b/src/lib/schemaParser.test.ts @@ -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..3cdde5ec 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', }; }; diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index 3f994707..50693904 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,15 +61,15 @@ describe('utils', () => { ], encodedValue: [ { - key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', + key: '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', value: '0x00000000000000000000000000000002', }, { - key: '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', + key: '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', value: '0xc444009d38d3046bb0cf81fa2cd295ce46a67c78', }, { - key: '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', + key: '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', value: '0x4febc3491230571f6e1829e46602e3b110215a2e', }, ], @@ -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,8 +559,8 @@ describe('utils', () => { assert.deepStrictEqual(encodedDataWithMultipleKeys, { keys: [ - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', ], values: [ '0x00000000000000000000000000000001', @@ -586,7 +586,7 @@ describe('utils', () => { const encodedDataWithMultipleKeys = encodeData( [ { - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', value: addressArray, }, ], @@ -595,18 +595,18 @@ describe('utils', () => { assert.deepStrictEqual(encodedDataWithMultipleKeys, { keys: [ - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000002', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000003', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000004', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000005', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000006', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000007', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000008', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000009', - '0x3a47ab5bd3a594c3a8995f8fa58d08760000000000000000000000000000000a', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000002', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000003', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000004', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000005', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000006', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000007', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000008', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000009', + '0x7c8c3416d6cda87cd42c71ea1843df280000000000000000000000000000000a', ], values: ['0x0000000000000000000000000000000b', ...addressArray], }); @@ -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,9 +664,9 @@ describe('utils', () => { assert.deepStrictEqual(encodedMultipleKeys, { keys: [ '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', - '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000', - '0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001', + '0x7c8c3416d6cda87cd42c71ea1843df28ac4850354f988d55ee2eaa47b6dc05cd', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000000', + '0x7c8c3416d6cda87cd42c71ea1843df2800000000000000000000000000000001', '0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47', ], values: [ @@ -921,7 +921,7 @@ describe('utils', () => { }, { keyType: 'Array', - keyName: 'LSP3IssuedAssets[]', + keyName: 'LSP12IssuedAssets[]', }, { keyType: 'Mapping', 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; 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',