Skip to content

Commit

Permalink
fix: Add support for VerifiableURL (squash to recover discrepancies b…
Browse files Browse the repository at this point in the history
…etween develop and main)
  • Loading branch information
richtera committed Dec 12, 2023
1 parent 90f735c commit 4df2377
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 39 deletions.
31 changes: 29 additions & 2 deletions examples/src/decodeData.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ import { getInstance } from './instantiation.js';
const myERC725 = getInstance();

const decodedDataOneKey = myERC725.decodeData([
{
keyName: 'LSP3Profile',
value:
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
},
]);
/**
[
{
name: 'LSP3Profile',
key: '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5',
value: {
verification: {
method: 'keccak256(utf8)',
data: '0x820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361',
},
url: 'ipfs://QmYr1VJLwerg6pEoscdhVGugo39pa6rycEZLjtRPDfW84UAx'
}
}
]
*/

const decodedDataOneKeyOld = myERC725.decodeData([
{
keyName: 'LSP3Profile',
value:
Expand All @@ -31,7 +54,7 @@ const decodedDataManyKeys = myERC725.decodeData([
{
keyName: 'LSP3Profile',
value:
'0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
},
{
keyName: 'LSP3IssuedAssets[]',
Expand Down Expand Up @@ -76,10 +99,14 @@ const decodedDataManyKeys = myERC725.decodeData([
]
*/
console.log('/*--------------------------------------------/*');
console.log('/* decodeData - one key /*');
console.log('/* decodeData - one key (VerifiableURL) /*');
console.log('/*--------------------------------------------/*');
console.log(decodedDataOneKey);
console.log('/*--------------------------------------------/*');
console.log('/* decodeData - one key (JSONURL) /*');
console.log('/*--------------------------------------------/*');
console.log(decodedDataOneKeyOld);
console.log('/*--------------------------------------------/*');
console.log('/* decodeData - many keys /*');
console.log('/*--------------------------------------------/*');
console.log(decodedDataManyKeys);
4 changes: 2 additions & 2 deletions examples/src/encodeData.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const encodedDataOneKeyV2 = myERC725.encodeData({
'0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5'
],
values: [
'0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178'
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178'
]
}
*/
Expand Down Expand Up @@ -76,7 +76,7 @@ const encodedDataManyKeys = myERC725.encodeData([
'0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47'
],
values: [
'0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
'0x0000000000000000000000000000000000000000000000000000000000000002',
'0xd94353d9b005b3c0a9da169b768a31c57844e490',
'0xdaea594e385fc724449e3118b2db7e86dfba1826',
Expand Down
35 changes: 33 additions & 2 deletions src/lib/decodeData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,31 @@ describe('decodeData', () => {
{
name: 'MyKeyName:<bytes32>:<bool>',
key: '0x',
keyType: 'Singleton',
keyType: 'MappingWithGrouping',
valueType: 'bytes',
valueContent: 'JSONURL',
},
{
name: 'MyKeyName2:<bytes32>:<bool>',
key: '0x',
keyType: 'MappingWithGrouping',
valueType: 'bytes',
valueContent: 'VerifiableURL',
},
{
name: 'MyDynamicKey:<address>',
key: '0x',
keyType: 'Singleton',
keyType: 'Mapping',
valueType: 'bytes',
valueContent: 'JSONURL',
},
{
name: 'MyDynamicKey2:<address>',
key: '0x',
keyType: 'Mapping',
valueType: 'bytes',
valueContent: 'VerifiableURL',
},
];

it('decodes each key', () => {
Expand Down Expand Up @@ -160,6 +174,21 @@ describe('decodeData', () => {
value:
'0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
},
{
keyName: 'MyKeyName2:<bytes32>:<bool>',
dynamicKeyParts: [
'0xaaaabbbbccccddddeeeeffff111122223333444455556666777788889999aaaa',
'true',
],
value:
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
},
{
keyName: 'MyDynamicKey2:<address>',
dynamicKeyParts: '0xcafecafecafecafecafecafecafecafecafecafe',
value:
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
},
{
keyName: 'KeyTwo',
value: '0x2222',
Expand All @@ -171,6 +200,8 @@ describe('decodeData', () => {
expect(decodedData.map(({ name }) => name)).to.eql([
'MyKeyName:aaaabbbbccccddddeeeeffff111122223333444455556666777788889999aaaa:true',
'MyDynamicKey:cafecafecafecafecafecafecafecafecafecafe',
'MyKeyName2:aaaabbbbccccddddeeeeffff111122223333444455556666777788889999aaaa:true',
'MyDynamicKey2:cafecafecafecafecafecafecafecafecafecafe',
'KeyTwo',
]);
});
Expand Down
15 changes: 12 additions & 3 deletions src/lib/encoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@

import { expect, assert } from 'chai';

import { keccak256, utf8ToHex, stripHexPrefix, toBN, toHex } from 'web3-utils';
import {
keccak256,
utf8ToHex,
stripHexPrefix,
toBN,
toHex,
padLeft,
} from 'web3-utils';
import {
valueContentEncodingMap,
encodeValueType,
Expand Down Expand Up @@ -899,7 +906,7 @@ describe('encoder', () => {
url: 'http://test.com/asset.glb',
},
encodedValue:
'0x6f357c6a027547537d35728a741470df1ccf65de10b454ca0def7c5c20b257b7b8d16168687474703a2f2f746573742e636f6d2f61737365742e676c62',
'0x00006f357c6a0020027547537d35728a741470df1ccf65de10b454ca0def7c5c20b257b7b8d16168687474703a2f2f746573742e636f6d2f61737365742e676c62',
},
{
valueContent: 'BitArray',
Expand Down Expand Up @@ -959,7 +966,9 @@ describe('encoder', () => {
).substring(2);
assert.deepStrictEqual(
encodedValue,
verificationMethod + jsonVerificationData + hexUrl,
`0x0000${stripHexPrefix(verificationMethod)}${stripHexPrefix(
padLeft(jsonVerificationData.length / 2, 4),
)}${jsonVerificationData}${hexUrl}`,
);

const expectedDecodedValue: URLDataWithHash = {
Expand Down
58 changes: 47 additions & 11 deletions src/lib/encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,58 @@ const encodeDataSourceWithHash = (
const verificationMethod = getVerificationMethod(
verification?.method || UNKNOWN_VERIFICATION_METHOD,
);
return (
(verificationMethod
? keccak256(verificationMethod.name).slice(0, 10)
: padLeft(0, 8)) +
stripHexPrefix(verification ? verification.data : padLeft(0, 64)) +
stripHexPrefix(utf8ToHex(dataSource))
);
return [
padLeft(0, 4),
stripHexPrefix(
verificationMethod
? padLeft(keccak256(verificationMethod.name).slice(0, 10), 8)
: padLeft(0, 8),
),
stripHexPrefix(
verification?.data
? padLeft(verification.data.slice(2).length / 2, 4)
: padLeft(0, 4),
),
stripHexPrefix(
verification?.data ? stripHexPrefix(verification?.data) : '',
),
stripHexPrefix(utf8ToHex(dataSource)),
].join('');
};

const decodeDataSourceWithHash = (value: string): URLDataWithHash => {
if (value.slice(0, 6) === '0x0000') {
/*
0 1 2 3 4 5 6 7 8
12345678901234567890123456789012345678901234567890123456789012345678901234567890
0x0000 code
6f357c6a hash fn [6]
0020 data len [14]
820464ddfac1be...[18 + data len]
[18 + data len]...696670733a2f2...[...rest]
*/
const verificationMethodSig = `0x${value.slice(6, 14)}`;
const verificationMethod = getVerificationMethod(verificationMethodSig);
if (verificationMethod !== undefined) {
const encodedLength = `0x${value.slice(14, 18)}`; // Rest of data string after function hash
const dataLength = hexToNumber(encodedLength, false) as number;
const dataHash = `0x${value.slice(18, 18 + dataLength * 2)}`; // Get jsonHash 32 bytes
const dataSource = hexToUtf8('0x' + value.slice(18 + dataLength * 2)); // Get remainder as URI
return {
verification: {
method: verificationMethod.name,
data: dataHash,
},
url: dataSource,
};
}
}

const verificationMethodSig = value.slice(0, 10);
const verificationMethod = getVerificationMethod(verificationMethodSig);

const encodedData = value.replace('0x', '').slice(8); // Rest of data string after function hash
const encodedData = value.slice(10); // Rest of data string after function hash
const dataHash = '0x' + encodedData.slice(0, 64); // Get jsonHash 32 bytes
const dataSource = hexToUtf8('0x' + encodedData.slice(64)); // Get remainder as URI

return {
verification: {
method: verificationMethod?.name || UNKNOWN_VERIFICATION_METHOD,
Expand Down Expand Up @@ -648,7 +683,8 @@ export const valueContentEncodingMap = (
};
}
// https://github.com/lukso-network/LIPs/blob/master/LSPs/LSP-2-ERC725YJSONSchema.md#jsonurl
case 'JSONURL': {
case 'JSONURL':
case 'VerifiableURL': {
return {
type: 'custom',
encode: (dataToEncode: JSONURLDataToEncode) => {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/getDataFromExternalSources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export const getDataFromExternalSources = (
}

if (
!['jsonurl', 'asseturl'].includes(
!['jsonurl', 'asseturl', 'verifiableurl'].includes(
schemaElement.valueContent.toLowerCase(),
)
) {
return dataEntry;
}

// At this stage, value should be of type jsonurl or asseturl
// At this stage, value should be of type jsonurl, verifiableurl or asseturl
if (typeof dataEntry.value === 'string') {
console.error(
`Value of key: ${dataEntry.name} (${dataEntry.value}) is string but valueContent is: ${schemaElement.valueContent}. Expected type should be object with url key.`,
Expand Down
10 changes: 5 additions & 5 deletions src/lib/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ describe('utils', () => {
{
key: '0x9985edaf12cbacf5ac7d6ed54f0445cc00000000000000000000000000000000',
value:
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
},
{
key: '0x9985edaf12cbacf5ac7d6ed54f0445cc00000000000000000000000000000001',
value:
'0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
'0x00006f357c6a002081bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
},
],
},
Expand Down Expand Up @@ -317,7 +317,7 @@ describe('utils', () => {
url: 'http://day.night/asset.glb',
},
encodedValue:
'0x6f357c6a81dadadadadadadadadadadadadadadf00a4bdfa8fcaf3791d25f69b497abf88687474703a2f2f6461792e6e696768742f61737365742e676c62',
'0x00006f357c6a002081dadadadadadadadadadadadadadadf00a4bdfa8fcaf3791d25f69b497abf88687474703a2f2f6461792e6e696768742f61737365742e676c62',
},
{
valueContent: 'JSONURL',
Expand All @@ -330,7 +330,7 @@ describe('utils', () => {
url: 'ipfs://QmbErKh3Fjsxxxxxxxxxxxxxxxxxxxxxxxxxxv9AJJvZbd',
},
encodedValue:
'0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
'0x00006f357c6a002081bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
},

{
Expand Down Expand Up @@ -643,7 +643,7 @@ describe('utils', () => {
'0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47',
],
values: [
'0x6f357c6a820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
'0x00006f357c6a0020820464ddfac1bec070cc14a8daf04129871d458f2ca94368aae8391311af6361697066733a2f2f516d597231564a4c776572673670456f73636468564775676f3339706136727963455a4c6a7452504466573834554178',
'0x00000000000000000000000000000002',
'0xd94353d9b005b3c0a9da169b768a31c57844e490',
'0xdaea594e385fc724449e3118b2db7e86dfba1826',
Expand Down
24 changes: 12 additions & 12 deletions test/mockSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ export const mockSchema: (ERC725JSONSchema & {
// Testing data
returnRawData: abiCoder.encodeParameter(
'bytes',
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
),
returnRawDataArray: abiCoder.encodeParameter('bytes[]', [
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
]),
returnGraphData:
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
expectedResult: {
verification: {
method: 'keccak256(utf8)',
Expand All @@ -65,13 +65,13 @@ export const mockSchema: (ERC725JSONSchema & {
// Testing data
returnRawData: abiCoder.encodeParameter(
'bytes',
'0x6f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020a7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
),
returnRawDataArray: abiCoder.encodeParameter('bytes[]', [
'0x6f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020a7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
]),
returnGraphData:
'0x6f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020a7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
expectedResult: {
verification: {
method: 'keccak256(utf8)',
Expand Down Expand Up @@ -263,26 +263,26 @@ export const mockSchema: (ERC725JSONSchema & {
abiCoder.encodeParameter('bytes', leftPad(2, 32)), // array length
abiCoder.encodeParameter(
'bytes',
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
),
abiCoder.encodeParameter(
'bytes',
'0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
'0x00006f357c6a002081bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
),
],
returnRawDataArray: [
abiCoder.encodeParameter('bytes[]', [leftPad(2, 32)]),
abiCoder.encodeParameter('bytes[]', [
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
]),
abiCoder.encodeParameter('bytes[]', [
'0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
'0x00006f357c6a002081bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
]),
],
returnGraphData: [
leftPad(2, 32), // array length
'0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
'0x00006f357c6a0020733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264',
'0x00006f357c6a002081bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264',
],
expectedResult: [
// This JSON from JSONURL above...
Expand Down

0 comments on commit 4df2377

Please sign in to comment.