Skip to content

Commit

Permalink
fix: encode uintN with correct padding and bytes length
Browse files Browse the repository at this point in the history
  • Loading branch information
CJ42 committed Apr 25, 2024
1 parent 06d872b commit f8dc5ae
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 17 deletions.
54 changes: 54 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,60 @@ describe('Running @erc725/erc725.js tests...', () => {
});
});

describe('Testing `encodeData`', () => {
describe('for `uintN` as `Number`', () => {
[
{ valueType: 'uint8', valueToEncode: 10, expectedEncodedValue: '0x0a' },
{
valueType: 'uint16',
valueToEncode: 10,
expectedEncodedValue: '0x000a',
},
{
valueType: 'uint24',
valueToEncode: 10,
expectedEncodedValue: '0x00000a',
},
{
valueType: 'uint32',
valueToEncode: 10,
expectedEncodedValue: '0x0000000a',
},
{
valueType: 'uint128',
valueToEncode: 10,
expectedEncodedValue: '0x0000000000000000000000000000000a',
},
{
valueType: 'uint256',
valueToEncode: 10,
expectedEncodedValue:
'0x000000000000000000000000000000000000000000000000000000000000000a',
},
].forEach((testCase) => {
it('should encode a valueType `uintN` as valueContent `Number` correctly with the right padding', () => {
const schema = {
name: 'ExampleUintN',
key: '0x512cddbe2654abd240fafbed308d91e82ff977301943f08ea825ba3e435bfa57',
keyType: 'Singleton',
valueType: testCase.valueType,
valueContent: 'Number',
};
const erc725js = new ERC725([schema]);
const result = erc725js.encodeData([
{ keyName: schema.name, value: testCase.valueToEncode },
]);

assert.equal(result.values[0], testCase.expectedEncodedValue);
});
});
});
});

describe('Testing `decodeData`', () => {
// ...
});

describe('Testing utility encoding & decoding functions', () => {
const allGraphData = generateAllData(mockSchema) as any;
/* **************************************** */
Expand Down
6 changes: 6 additions & 0 deletions src/lib/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,12 @@ describe('utils', () => {
encodedValue: '0xdeadbeaf0000000000000010',
decodedValue: ['0xdeadbeaf', 16],
},
{
valueContent: '(Bytes4,Number)',
valueType: '(bytes4,uint128)',
encodedValue: '0xdeadbeaf00000000000000000000000000000020',
decodedValue: ['0xdeadbeaf', 32],
},
]; // we may need to add more test cases! Address, etc.

testCases.forEach((testCase) => {
Expand Down
34 changes: 17 additions & 17 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ import { EncodeDataInput } from '../types/decodeData';
import { GetDataDynamicKey } from '../types/GetData';
import { isValidTuple } from './decodeData';

function isValueContentLiteralHex(valueContent: string): boolean {
return valueContent.slice(0, 2) === '0x';
}

/**
*
* @param {string} valueContent as per ERC725Schema definition
Expand All @@ -84,17 +88,23 @@ export function encodeKeyValue(
name?: string,
): string | false {
const isSupportedValueContent =
!!valueContentMap(valueContent) || valueContent.slice(0, 2) === '0x';
!!valueContentMap(valueContent) || isValueContentLiteralHex(valueContent);

if (!isSupportedValueContent) {
throw new Error(
`The valueContent '${valueContent}'
for ${name} is not supported.`,
`The valueContent '${valueContent}' for ${name} is not supported.`,
);
}

const isValueTypeArray = valueType.slice(valueType.length - 2) === '[]';

if (
(valueType.startsWith('uint') || valueType.startsWith('bytes')) &&
typeof decodedValue !== 'object'
) {
return encodeValueType(valueType, decodedValue);
}

if (!isValueTypeArray && !Array.isArray(decodedValue)) {
// Straight forward encode
return encodeValueContent(valueContent, decodedValue);
Expand Down Expand Up @@ -187,15 +197,16 @@ export function guessKeyTypeFromKeyName(
}

export const encodeTupleKeyValue = (
valueContent: string, // i.e. (bytes4,Number,bytes16)
valueType: string, // i.e. (bytes4,bytes8,bytes16)
valueContent: string, // i.e. (Bytes4,Number,Bytes16,Address)
valueType: string, // i.e. (bytes4,uint128,bytes16,address)
decodedValues: Array<string | number | URLDataToEncode | string[]>,
) => {
// We assume data has already been validated at this stage

const valueTypeParts = valueType
.substring(1, valueType.length - 1)
.split(',');

const valueContentParts = valueContent
.substring(1, valueContent.length - 1)
.split(',');
Expand All @@ -218,18 +229,7 @@ export const encodeTupleKeyValue = (
return ''; // may cause issues?
}
const numberOfBytes = Number.parseInt(valueTypeParts[i].substring(5), 10); // bytes50 -> 50
// If the encoded value is too large for the expected valueType, we shrink it from the left
// i.e. number are encoded on 32bytes
// TODO: might be missing cases !
if (encodedKeyValue.length > 2 + numberOfBytes * 2) {
return encodedKeyValue.slice(
encodedKeyValue.length - numberOfBytes * 2,
);
}
return padLeft(encodedKeyValue, numberOfBytes * 2).replace('0x', '');
return stripHexPrefix(encodedKeyValue);
})
.join('')}`;

Expand Down

0 comments on commit f8dc5ae

Please sign in to comment.