Skip to content

Commit

Permalink
fix: Repair encode/decode dynamic keys of type string/bytesN
Browse files Browse the repository at this point in the history
  • Loading branch information
richtera committed Feb 25, 2024
1 parent 980d553 commit 798f0b9
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 25 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 23 additions & 5 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { leftPad, numberToHex, toNumber } from 'web3-utils';
// examples of schemas to load (for testing)
import { LSP1Schema, LSP12Schema, LSP3Schema, LSP6Schema } from './schemas';

import ERC725 from '.';
import ERC725, { decodeMappingKey, encodeKeyName } from '.';
import {
decodeKeyValue,
encodeKey,
Expand Down Expand Up @@ -1597,11 +1597,9 @@ describe('checkPermissions', () => {
});

describe('decodeMappingKey', () => {
const erc725Instance = new ERC725([]);

it('is available on instance and class', () => {
assert.deepStrictEqual(
ERC725.decodeMappingKey(
decodeMappingKey(
'0x35e6950bc8d21a1699e50000cafecafecafecafecafecafecafecafecafecafe',
'MyKeyName:<address>',
),
Expand All @@ -1613,7 +1611,19 @@ describe('decodeMappingKey', () => {
],
);
assert.deepStrictEqual(
erc725Instance.decodeMappingKey(
decodeMappingKey(
encodeKeyName('MyKeyName:<bytes16>', ['0x12345678']),
'MyKeyName:<bytes16>',
),
[
{
type: 'bytes16',
value: '00000000000000000000000012345678',
},
],
);
assert.deepStrictEqual(
decodeMappingKey(
'0x35e6950bc8d21a1699e50000cafecafecafecafecafecafecafecafecafecafe',
'MyKeyName:<address>',
),
Expand All @@ -1624,5 +1634,13 @@ describe('decodeMappingKey', () => {
},
],
);
assert.throws(() => {
decodeMappingKey(
encodeKeyName('LSP8MetadataTokenURI:<string>', ['hello there']),
// '0x1339e76a390b7b9ec9010000e753904c77f5a07e628eff190bbddad936aaffb2',
// '0x6c2a998f88b72c27017768656c6c6f20776f726c640000000000000000000000',
'LSP8MetadataTokenURI:<string>',
);
}, /String dynamic key parts cannot be decoded/);
});
});
11 changes: 9 additions & 2 deletions src/lib/decodeMappingKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
* @date 2022
*/

import { isHex, padLeft } from 'web3-utils';
import { padLeft } from 'web3-utils';
import { isHex } from 'web3-validator';
import { decodeValueType } from './encoder';
import { ERC725JSONSchema } from '../types/ERC725JSONSchema';
import { DynamicKeyPart } from '../types/dynamicKeys';
Expand Down Expand Up @@ -85,7 +86,7 @@ export function decodeMappingKey(
throw new Error(
`Invalid encodedKey length, key must be 32 bytes long hexadecimal value`,
);
if (!isHex(hashedKey.slice(2)))
if (!isHex(hashedKey))
throw new Error(`Invalid encodedKey, must be a hexadecimal value`);

let keyParts: string[];
Expand All @@ -94,6 +95,12 @@ export function decodeMappingKey(
keyParts = keyNameOrSchema.split(':');
else keyParts = keyNameOrSchema.name.split(':');

if (keyParts.some((p) => p.includes('string'))) {
throw new Error(
"String dynamic key parts cannot be decoded, because it's formatted as a keccak256 hash",
);
}

const dynamicParts: (DynamicKeyPart | false)[] = [];
switch (keyParts.length) {
case 2: // Mapping
Expand Down
24 changes: 9 additions & 15 deletions src/lib/encodeKeyName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@
* @date 2022
*/

import {
isAddress,
isHex,
keccak256,
leftPad,
numberToHex,
padLeft,
} from 'web3-utils';
import { isAddress, isHex } from 'web3-validator';
import { keccak256, leftPad, numberToHex, padLeft } from 'web3-utils';
import { stripHexPrefix } from 'web3-eth-accounts';

import { guessKeyTypeFromKeyName } from './utils';
import { DynamicKeyParts } from '../types/dynamicKeys';
Expand Down Expand Up @@ -112,24 +107,23 @@ export const encodeDynamicKeyPart = (
// TODO:
throw new Error('The encoding of <intM> has not been implemented yet.');
case 'bytes': {
const valueWithoutPrefix = value.replace('0x', '');
if (valueWithoutPrefix.length !== size * 2) {
if (!isHex(value)) {
throw new Error(
`Wrong value: ${value} for dynamic key with type: ${type}. Value is not ${size} bytes long.`,
`Wrong value: ${value} for dynamic key with type: ${type}. Value is not in hex.`,
);
}

if (!isHex(valueWithoutPrefix)) {
const valueWithoutPrefix = value.replace('0x', '');
if (valueWithoutPrefix.length > size * 2) {
throw new Error(
`Wrong value: ${value} for dynamic key with type: ${type}. Value is not in hex.`,
`Wrong value: ${value} for dynamic key with type: ${type}. Value longer than ${size} bytes.`,
);
}

if (valueWithoutPrefix.length > bytes * 2) {
return valueWithoutPrefix.slice(0, bytes * 2); // right cut
}

return leftPad(valueWithoutPrefix, bytes * 2).toLowerCase();
return stripHexPrefix(leftPad(value, bytes * 2).toLowerCase());
}
default:
throw new Error(`Dynamic key: ${type} is not supported`);
Expand Down

0 comments on commit 798f0b9

Please sign in to comment.