Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow to encode LSP2 Array length only #326

Merged
merged 4 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/classes/ERC725.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,30 @@ myErc725.encodeData([

</details>

<details>
<summary>Encode array length</summary>

If the key is of type Array and you pass an integer as a value (for instance, the array length), it will be encoded accordingly.

```javascript title="Encode the length of an array"
myErc725.encodeData([
{
keyName: 'LSP3IssuedAssets[]',
value: 5,
},
]);
/**
{
keys: [
'0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0',
],
values: ['0x00000000000000000000000000000005'],
}
*/
```

</details>

---

## encodeKeyName
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class ERC725 {
}

/**
* To prevent weird behovior from the lib, we must make sure all the schemas are correct before loading them.
* To prevent weird behavior from the lib, we must make sure all the schemas are correct before loading them.
*
* @param schemas
* @returns
Expand Down
37 changes: 11 additions & 26 deletions src/lib/encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,30 +332,6 @@ const returnTypesOfUintNCompactBytesArray = () => {
return types;
};

/**
* Encodes any set of strings to string[CompactBytesArray]
*
* @param values An array of non restricted strings
* @returns string[CompactBytesArray]
*/
const encodeStringCompactBytesArray = (values: string[]): string => {
const hexValues: string[] = values.map((element) => utf8ToHex(element));

return encodeCompactBytesArray(hexValues);
};

/**
* Decode a string[CompactBytesArray] to an array of strings
* @param compactBytesArray A string[CompactBytesArray]
* @returns An array of strings
*/
const decodeStringCompactBytesArray = (compactBytesArray: string): string[] => {
const hexValues: string[] = decodeCompactBytesArray(compactBytesArray);
const stringValues: string[] = hexValues.map((element) => hexToUtf8(element));

return stringValues;
};

const valueTypeEncodingMap = {
bool: {
encode: (value: boolean) => (value ? '0x01' : '0x00'),
Expand Down Expand Up @@ -494,8 +470,17 @@ const valueTypeEncodingMap = {
decode: (value: string) => decodeCompactBytesArray(value),
},
'string[CompactBytesArray]': {
encode: (value: string[]) => encodeStringCompactBytesArray(value),
decode: (value: string) => decodeStringCompactBytesArray(value),
encode: (values: string[]) => {
const hexValues: string[] = values.map((element) => utf8ToHex(element));
return encodeCompactBytesArray(hexValues);
},
decode: (value: string) => {
const hexValues: string[] = decodeCompactBytesArray(value);
const stringValues: string[] = hexValues.map((element) =>
hexToUtf8(element),
);
return stringValues;
},
},
...returnTypesOfBytesNCompactBytesArray(),
...returnTypesOfUintNCompactBytesArray(),
Expand Down
63 changes: 50 additions & 13 deletions src/lib/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { SUPPORTED_VERIFICATION_METHOD_STRINGS } from '../constants/constants';
import {
guessKeyTypeFromKeyName,
isDataAuthentic,
encodeArrayKey,
encodeKeyValue,
decodeKeyValue,
encodeKey,
Expand All @@ -44,6 +43,7 @@ import { decodeKey } from './decodeData';
describe('utils', () => {
describe('encodeKey/decodeKey', () => {
const testCases = [
// test encoding an array of address
{
schema: {
name: 'LSP3IssuedAssets[]',
Expand Down Expand Up @@ -226,12 +226,28 @@ describe('utils', () => {
encodeKey(testCase.schema as ERC725JSONSchema, testCase.decodedValue),
testCase.encodedValue,
);

assert.deepStrictEqual(
decodeKey(testCase.schema as ERC725JSONSchema, testCase.encodedValue),
testCase.decodedValue,
);
});
});

it('should encode the array length only if passing a number', async () => {
const schema: ERC725JSONSchema = {
name: 'LSP3IssuedAssets[]',
key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0',
keyType: 'Array',
valueContent: 'Address',
valueType: 'address',
};

const decodedValue = 3;
const encodedValue = '0x00000000000000000000000000000003';

assert.equal(encodeKey(schema, decodedValue), encodedValue);
});
});

describe('encodeKeyValue/decodeKeyValue', () => {
Expand Down Expand Up @@ -391,19 +407,19 @@ describe('utils', () => {
});

describe('encodeArrayKey', () => {
it('encodes array key correctly', () => {
const key =
'0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0';

const expectedValues = [
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000000',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000001',
'0x3a47ab5bd3a594c3a8995f8fa58d087600000000000000000000000000000002',
];
it('should encode the array length only if passing a number', async () => {
const schema: ERC725JSONSchema = {
name: 'LSP3IssuedAssets[]',
key: '0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0',
keyType: 'Array',
valueContent: 'Address',
valueType: 'address',
};

expectedValues.forEach((expectedValue, index) => {
assert.strictEqual(encodeArrayKey(key, index), expectedValue);
});
const decodedValue = 3;
const encodedValue = '0x00000000000000000000000000000003';

assert.equal(encodeKey(schema, decodedValue), encodedValue);
});
});

Expand Down Expand Up @@ -567,6 +583,27 @@ describe('utils', () => {
});
});

it('encodes array length only if giving a number', () => {
const length = 5;

const encodedArrayLengthKey = encodeData(
[
{
keyName: 'LSP3IssuedAssets[]',
value: length,
},
],
schemas,
);

assert.deepStrictEqual(encodedArrayLengthKey, {
keys: [
'0x3a47ab5bd3a594c3a8995f8fa58d0876c96819ca4516bd76100c92462f2f9dc0',
],
values: ['0x00000000000000000000000000000005'],
});
});

it('encodes multiple keys', () => {
const encodedMultipleKeys = encodeData(
[
Expand Down
5 changes: 5 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ export function encodeKey(

switch (lowerCaseKeyType) {
case 'array': {
// if we are encoding only the Array length
if (typeof value === 'number') {
return encodeValueType('uint128', value);
}

if (!Array.isArray(value)) {
console.error("Can't encode a non array for key of type array");
return null;
Expand Down
7 changes: 6 additions & 1 deletion src/types/encodeData/JSONURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ export interface URLDataWithJson extends URLData {

export type JSONURLDataToEncode = URLDataWithHash | URLDataWithJson;

export type EncodeDataType = string | string[] | JSONURLDataToEncode | boolean;
export type EncodeDataType =
| string
| string[]
| JSONURLDataToEncode
| boolean
| number;

export interface EncodeDataReturn {
keys: string[];
Expand Down
Loading