diff --git a/src/index.test.ts b/src/index.test.ts index 7896adf2..ada63bfa 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -19,7 +19,10 @@ // Tests for the @erc725/erc725.js package import assert from 'assert'; +// eslint-disable-next-line import/no-extraneous-dependencies +import Web3 from 'web3'; import { hexToNumber, leftPad, numberToHex } from 'web3-utils'; + // eslint-disable-next-line import/no-extraneous-dependencies import { GraphProviderWrapper } from '@erc725/provider-wrappers'; @@ -48,7 +51,10 @@ import { import 'isomorphic-fetch'; import { Schema } from '../test/generatedSchema'; -import { SUPPORTED_HASH_FUNCTION_STRINGS } from './lib/constants'; +import { + INTERFACE_IDS, + SUPPORTED_HASH_FUNCTION_STRINGS, +} from './lib/constants'; const address = '0x0c03fba782b07bcf810deb3b7f0595024a444f4e'; @@ -92,161 +98,249 @@ describe('Running @erc725/erc725.js tests...', () => { } }); - describe('Getting all data in schema by provider', () => { - // Construct the full data and results - const fullResults = generateAllResults(mockSchema); - const allRawData = generateAllRawData(mockSchema); - const allGraphData = generateAllData(mockSchema); + describe('Getting all data in schema by provider [e2e]', () => { + const web3 = new Web3('https://rpc.l14.lukso.network'); - it('with web3.currentProvider', async () => { - const provider = new HttpProvider({ returnData: allRawData }); - const erc725 = new ERC725(mockSchema, address, provider); + const LEGACY_ERC725_CONTRACT_ADDRESS = + '0xb8E120e7e5EAe7bfA629Db5CEFfA69C834F74e99'; + const ERC725_CONTRACT_ADDRESS = + '0x320e678bEb3369702EA14555a74414B2C531c510'; + + const e2eSchema: any = [ + { + name: 'LSP3Profile', + key: '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', + keyType: 'Singleton', + valueContent: 'JSONURL', + valueType: 'bytes', + }, + { + name: 'SupportedStandards:ERC725Account', + key: '0xeafec4d89fa9619884b6b89135626455000000000000000000000000afdeb5d6', + keyType: 'Singleton', + valueContent: '0xafdeb5d6', + valueType: 'bytes', + }, + { + name: 'LSP1UniversalReceiverDelegate', + key: '0x0cfc51aec37c55a4d0b1a65c6255c4bf2fbdf6277f3cc0730c45b828b6db8b47', + keyType: 'Singleton', + valueContent: 'Address', + valueType: 'address', + }, + ]; + + const e2eResults = { + LSP3Profile: { + hashFunction: 'keccak256(utf8)', + hash: '0x70546a2accab18748420b63c63b5af4cf710848ae83afc0c51dd8ad17fb5e8b3', + url: 'ipfs://QmecrGejUQVXpW4zS948pNvcnQrJ1KiAoM6bdfrVcWZsn5', + }, + 'SupportedStandards:ERC725Account': '0xafdeb5d6', + LSP1UniversalReceiverDelegate: + '0x36e4Eb6Ee168EF54B1E8e850ACBE51045214B313', + }; + + it('with web3.currentProvider [legacy]', async () => { + const erc725 = new ERC725( + e2eSchema, + LEGACY_ERC725_CONTRACT_ADDRESS, + web3.currentProvider, + ); const result = await erc725.getData(); - assert.deepStrictEqual(result, fullResults); + assert.deepStrictEqual(result, e2eResults); }); - it('with ethereumProvider EIP 1193', async () => { - const provider = new EthereumProvider({ returnData: allRawData }); - const erc725 = new ERC725(mockSchema, address, provider); + it('with web3.currentProvider', async () => { + const erc725 = new ERC725( + e2eSchema, + ERC725_CONTRACT_ADDRESS, + web3.currentProvider, + ); const result = await erc725.getData(); - assert.deepStrictEqual(result, fullResults); + assert.deepStrictEqual(result, e2eResults); }); + }); + + [ + { name: 'legacy', interface: INTERFACE_IDS.ERC725Y_LEGACY }, + { name: 'latest', interface: INTERFACE_IDS.ERC725Y }, + ].forEach((contractVersion) => { + describe(`Getting all data in schema by provider [ERC725Y ${contractVersion.name}][mock]`, () => { + // Construct the full data and results + const fullResults = generateAllResults(mockSchema); + const allRawData = generateAllRawData( + mockSchema, + contractVersion.interface === INTERFACE_IDS.ERC725Y, + ); - xit('with apollo client', async () => { - const provider = new ApolloClient({ - returnData: allGraphData, - getAll: true, + it('with web3.currentProvider', async () => { + const provider = new HttpProvider({ returnData: allRawData }, [ + contractVersion.interface, + ]); + const erc725 = new ERC725(mockSchema, address, provider); + const result = await erc725.getData(); + assert.deepStrictEqual(result, fullResults); }); - const erc725 = new ERC725(mockSchema, address, { - provider, - type: 'ApolloClient', + + it('with ethereumProvider EIP 1193', async () => { + const provider = new EthereumProvider({ returnData: allRawData }, [ + contractVersion.interface, + ]); + const erc725 = new ERC725(mockSchema, address, provider); + const result = await erc725.getData(); + assert.deepStrictEqual(result, fullResults); }); - const result = await erc725.getData(); - assert.deepStrictEqual(result, fullResults); - }); - it('fetchData JSONURL', async () => { - // this test does a real request, TODO replace with mock? + xit('with apollo client', async () => { + const allGraphData = generateAllData(mockSchema); - const provider = new HttpProvider({ - returnData: [ - { - key: '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', - value: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000596f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a626400000000000000', - }, - ], + const provider = new ApolloClient({ + returnData: allGraphData, + getAll: true, + }); + const erc725 = new ERC725(mockSchema, address, { + provider, + type: 'ApolloClient', + }); + const result = await erc725.getData(); + assert.deepStrictEqual(result, fullResults); }); - const erc725 = new ERC725( - [ + + it('fetchData JSONURL', async () => { + // this test does a real request, TODO replace with mock? + const provider = new HttpProvider( { - name: 'TestJSONURL', - key: '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', - keyType: 'Singleton', - valueContent: 'JSONURL', - valueType: 'bytes', + returnData: allRawData.filter( + (rawData) => + rawData.key === + '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', + ), }, - ], - address, - provider, - ); - const result = await erc725.fetchData('TestJSONURL'); - assert.deepStrictEqual(result.TestJSONURL, { - LSP3Profile: { - backgroundImage: - 'ipfs://QmZF5pxDJcB8eVvCd74rsXBFXhWL3S1XR5tty2cy1a58Ew', - description: - "Beautiful clothing that doesn't cost the Earth. A sustainable designer based in London Patrick works with brand partners to refocus on systemic change centred around creative education. ", - profileImage: 'ipfs://QmYo8yg4zzmdu26NSvtsoKeU5oVR6h2ohmoa2Cx5i91mPf', - }, + [contractVersion.interface], + ); + const erc725 = new ERC725( + [ + { + name: 'TestJSONURL', + key: '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', + keyType: 'Singleton', + valueContent: 'JSONURL', + valueType: 'bytes', + }, + ], + address, + provider, + ); + const result = await erc725.fetchData('TestJSONURL'); + assert.deepStrictEqual(result.TestJSONURL, { + LSP3Profile: { + backgroundImage: + 'ipfs://QmZF5pxDJcB8eVvCd74rsXBFXhWL3S1XR5tty2cy1a58Ew', + description: + "Beautiful clothing that doesn't cost the Earth. A sustainable designer based in London Patrick works with brand partners to refocus on systemic change centred around creative education. ", + profileImage: + 'ipfs://QmYo8yg4zzmdu26NSvtsoKeU5oVR6h2ohmoa2Cx5i91mPf', + }, + }); }); - }); - it('fetchData JSONURL with custom config.ipfsGateway', async () => { - // this test does a real request, TODO replace with mock? + it('fetchData JSONURL with custom config.ipfsGateway', async () => { + // this test does a real request, TODO replace with mock? - const provider = new HttpProvider({ - returnData: [ + const provider = new HttpProvider( { - key: '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', - value: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000596f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a626400000000000000', + returnData: allRawData.filter( + (rawData) => + rawData.key === + '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', + ), }, - ], - }); - const erc725 = new ERC725( - [ + [contractVersion.interface], + ); + const erc725 = new ERC725( + [ + { + name: 'TestJSONURL', + key: '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', + keyType: 'Singleton', + valueContent: 'JSONURL', + valueType: 'bytes', + }, + ], + address, + provider, { - name: 'TestJSONURL', - key: '0xd154e1e44d32870ff5ade9e8726fd06d0ed6c996f5946dabfdfd46aa6dd2ea99', - keyType: 'Singleton', - valueContent: 'JSONURL', - valueType: 'bytes', + ipfsGateway: 'https://ipfs.lukso.network/ipfs/', }, - ], - address, - provider, - { - ipfsGateway: 'https://ipfs.lukso.network/ipfs/', - }, - ); - const result = await erc725.fetchData('TestJSONURL'); - assert.deepStrictEqual(result.TestJSONURL, { - LSP3Profile: { - backgroundImage: - 'ipfs://QmZF5pxDJcB8eVvCd74rsXBFXhWL3S1XR5tty2cy1a58Ew', - description: - "Beautiful clothing that doesn't cost the Earth. A sustainable designer based in London Patrick works with brand partners to refocus on systemic change centred around creative education. ", - profileImage: 'ipfs://QmYo8yg4zzmdu26NSvtsoKeU5oVR6h2ohmoa2Cx5i91mPf', - }, - }); - }); - - it('fetchData AssetURL', async () => { - // this test does a real request, TODO replace with mock? - - const provider = new HttpProvider({ - returnData: [ - { - key: '0xf18290c9b373d751e12c5ec807278267a807c35c3806255168bc48a85757ceee', - value: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000598019f9b1ea67779f76db55facacfe81114abcd56b36fe15d63223aba7e5fc8251f68139f697066733a2f2f516d596f387967347a7a6d647532364e537674736f4b6555356f56523668326f686d6f61324378356939316d506600000000000000', + ); + const result = await erc725.fetchData('TestJSONURL'); + assert.deepStrictEqual(result.TestJSONURL, { + LSP3Profile: { + backgroundImage: + 'ipfs://QmZF5pxDJcB8eVvCd74rsXBFXhWL3S1XR5tty2cy1a58Ew', + description: + "Beautiful clothing that doesn't cost the Earth. A sustainable designer based in London Patrick works with brand partners to refocus on systemic change centred around creative education. ", + profileImage: + 'ipfs://QmYo8yg4zzmdu26NSvtsoKeU5oVR6h2ohmoa2Cx5i91mPf', }, - ], + }); }); - const erc725 = new ERC725( - [ - { - name: 'TestAssetURL', - key: '0xf18290c9b373d751e12c5ec807278267a807c35c3806255168bc48a85757ceee', - keyType: 'Singleton', - valueContent: 'AssetURL', - valueType: 'bytes', - // Testing data - // @ts-ignore - expectedResult: { - hashFunction: 'keccak256(utf8)', // 0x8019f9b1 - hash: '0xea67779f76db55facacfe81114abcd56b36fe15d63223aba7e5fc8251f68139f', // hash of address '0x0c03fba782b07bcf810deb3b7f0595024a444f4e' - url: 'ipfs://QmYo8yg4zzmdu26NSvtsoKeU5oVR6h2ohmoa2Cx5i91mPf', // FAKE. just used from above + + if (contractVersion.interface === INTERFACE_IDS.ERC725Y_LEGACY) { + // We run this broken test only on legacy for now until it is fixed + it('fetchData AssetURL -> NOT VALID requests a JSON instead of a FILE', async () => { + // this test does a real request, TODO replace with mock? + + const provider = new HttpProvider( + { + returnData: [ + { + key: '0xf18290c9b373d751e12c5ec807278267a807c35c3806255168bc48a85757ceee', + value: + '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000598019f9b1ea67779f76db55facacfe81114abcd56b36fe15d63223aba7e5fc8251f68139f697066733a2f2f516d596f387967347a7a6d647532364e537674736f4b6555356f56523668326f686d6f61324378356939316d506600000000000000', + }, + ], }, - }, - ], - address, - provider, - ); - const result = await erc725.fetchData('TestAssetURL'); - assert.strictEqual( - Object.prototype.toString.call(result.TestAssetURL), - '[object Uint8Array]', - ); + [contractVersion.interface], + ); + const erc725 = new ERC725( + [ + { + name: 'TestAssetURL', + key: '0xf18290c9b373d751e12c5ec807278267a807c35c3806255168bc48a85757ceee', + keyType: 'Singleton', + valueContent: 'AssetURL', + valueType: 'bytes', + // Testing data + // @ts-ignore + expectedResult: { + hashFunction: 'keccak256(utf8)', // 0x8019f9b1 + hash: '0xea67779f76db55facacfe81114abcd56b36fe15d63223aba7e5fc8251f68139f', // hash of address '0x0c03fba782b07bcf810deb3b7f0595024a444f4e' + url: 'ipfs://QmYo8yg4zzmdu26NSvtsoKeU5oVR6h2ohmoa2Cx5i91mPf', // FAKE. just used from above + }, + }, + ], + address, + provider, + ); + const result = await erc725.fetchData('TestAssetURL'); + assert.strictEqual( + Object.prototype.toString.call(result.TestAssetURL), + '[object Uint8Array]', + ); + }); + } }); }); describe('Getting data by schema element by provider', () => { mockSchema.forEach((schemaElement) => { it(schemaElement.name + ' with web3.currentProvider', async () => { - const returnRawData = generateAllRawData([schemaElement]); - const provider = new HttpProvider({ returnData: returnRawData }); + const returnRawData = generateAllRawData([schemaElement], false); + const provider = new HttpProvider({ returnData: returnRawData }, [ + INTERFACE_IDS.ERC725Y_LEGACY, + ]); const erc725 = new ERC725(mockSchema, address, provider); const result = await erc725.getData(schemaElement.key); assert.deepStrictEqual(result, { @@ -255,8 +349,10 @@ describe('Running @erc725/erc725.js tests...', () => { }); it(schemaElement.name + ' with ethereumProvider EIP 1193', async () => { - const returnRawData = generateAllRawData([schemaElement]); - const provider = new HttpProvider({ returnData: returnRawData }); + const returnRawData = generateAllRawData([schemaElement], false); + const provider = new HttpProvider({ returnData: returnRawData }, [ + INTERFACE_IDS.ERC725Y_LEGACY, + ]); const erc725 = new ERC725(mockSchema, address, provider); const result = await erc725.getData(schemaElement.key); assert.deepStrictEqual(result, { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index b21fd53b..4d834c40 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -3,14 +3,27 @@ import { numberToHex, keccak256 } from 'web3-utils'; import { MethodData, Encoding, Method } from '../types/Method'; +// https://github.com/ERC725Alliance/ERC725/blob/develop/docs/ERC-725.md#specification +export const INTERFACE_IDS = { + ERC725Y_LEGACY: '0x2bd57b73', + ERC725Y: '0x5a988c0f', +}; + export const METHODS: Record = { - [Method.GET_DATA]: { + [Method.GET_DATA_LEGACY]: { sig: '0x54f6127f', gas: numberToHex(2000000), gasPrice: numberToHex(100000000), value: numberToHex(0), returnEncoding: Encoding.BYTES, }, + [Method.GET_DATA]: { + sig: '0x4e3e6e9c', + gas: numberToHex(2000000), + gasPrice: numberToHex(100000000), + value: numberToHex(0), + returnEncoding: Encoding.BYTES_ARRAY, + }, [Method.DATA_COUNT]: { sig: '0x5da40c47', gas: numberToHex(2000000), @@ -32,6 +45,13 @@ export const METHODS: Record = { value: numberToHex(0), returnEncoding: Encoding.ADDRESS, }, + [Method.SUPPORTS_INTERFACE]: { + sig: '0x01ffc9a7', + gas: numberToHex(2000000), + gasPrice: numberToHex(100000000), + value: numberToHex(0), + returnEncoding: Encoding.BOOL, + }, }; export enum SUPPORTED_HASH_FUNCTION_STRINGS { diff --git a/src/providers/ethereumProviderWrapper.ts b/src/providers/ethereumProviderWrapper.ts index 2bcf56f5..10941cd0 100644 --- a/src/providers/ethereumProviderWrapper.ts +++ b/src/providers/ethereumProviderWrapper.ts @@ -24,7 +24,7 @@ import * as abi from 'web3-eth-abi'; -import { METHODS } from '../lib/constants'; +import { INTERFACE_IDS, METHODS } from '../lib/constants'; import { Method } from '../types/Method'; import { ProviderTypes } from '../types/provider'; @@ -49,11 +49,58 @@ export class EthereumProviderWrapper { return this.decodeResult(Method.OWNER, result); } - async getData(address: string, keyHash: string) { - const result = await this.callContract([ - this.constructJSONRPC(address, Method.GET_DATA, keyHash), + /** + * https://eips.ethereum.org/EIPS/eip-165 + * + * @param address the smart contract address + * @param interfaceId ERC-165 identifier as described here: https://github.com/ERC725Alliance/ERC725/blob/develop/docs/ERC-725.md#specification + */ + async supportsInterface(address: string, interfaceId: string) { + const resp = await this.callContract([ + this.constructJSONRPC( + address, + Method.SUPPORTS_INTERFACE, + `${interfaceId}${'00000000000000000000000000000000000000000000000000000000'}`, + ), ]); - return this.decodeResult(Method.GET_DATA, result); + + return this.decodeResult(Method.SUPPORTS_INTERFACE, resp); + } + + async getData(address: string, keyHash: string) { + let isErc725Y = false; + let isErc725YLegacy = false; + + isErc725Y = await this.supportsInterface(address, INTERFACE_IDS.ERC725Y); + + if (!isErc725Y) { + isErc725YLegacy = await this.supportsInterface( + address, + INTERFACE_IDS.ERC725Y_LEGACY, + ); + } + + if (!isErc725Y && !isErc725YLegacy) { + throw new Error( + `Contract: ${address} does not support ERC725Y interface.`, + ); + } + + if (isErc725Y) { + return this.decodeResult( + Method.GET_DATA, + await this.callContract([ + this.constructJSONRPC(address, Method.GET_DATA, keyHash), + ]), + )[0]; + } + + return this.decodeResult( + Method.GET_DATA_LEGACY, + await this.callContract([ + this.constructJSONRPC(address, Method.GET_DATA_LEGACY, keyHash), + ]), + ); } async getAllData(address: string, keys: string[]) { @@ -63,9 +110,13 @@ export class EthereumProviderWrapper { }[] = []; for (let index = 0; index < keys.length; index++) { + // TODO: call getData with array instead of multiple calls with 1 element + const value = await this.getData(address, keys[index]); + results.push({ key: keys[index], - value: await this.getData(address, keys[index]), + // TODO: get the interface id here to prevent multiple calls in getData + value, }); } diff --git a/src/providers/web3ProviderWrapper.ts b/src/providers/web3ProviderWrapper.ts index f64d7ad5..161c4bf9 100644 --- a/src/providers/web3ProviderWrapper.ts +++ b/src/providers/web3ProviderWrapper.ts @@ -22,10 +22,17 @@ in accordance with implementation of smart contract interfaces of ERC725 */ +import AbiCoder from 'web3-eth-abi'; + import { JsonRpc } from '../types/JsonRpc'; import { Method } from '../types/Method'; import { constructJSONRPC, decodeResult } from '../lib/provider-wrapper-utils'; import { ProviderTypes } from '../types/provider'; +import { INTERFACE_IDS } from '../lib/constants'; + +// TS can't get the types from the import... +// @ts-ignore +const abiCoder: AbiCoder.AbiCoder = AbiCoder; export class Web3ProviderWrapper { type: ProviderTypes; @@ -46,19 +53,96 @@ export class Web3ProviderWrapper { return decodeResult(Method.OWNER, result); } + /** + * https://eips.ethereum.org/EIPS/eip-165 + * + * @param address the smart contract address + * @param interfaceId ERC-165 identifier as described here: https://github.com/ERC725Alliance/ERC725/blob/develop/docs/ERC-725.md#specification + */ + async supportsInterface(address: string, interfaceId: string) { + const resp = await this.callContract( + constructJSONRPC( + address, + Method.SUPPORTS_INTERFACE, + `${interfaceId}${'00000000000000000000000000000000000000000000000000000000'}`, + ), + ); + + return decodeResult(Method.SUPPORTS_INTERFACE, resp); + } + async getData(address: string, keyHash: string) { + let isErc725Y = false; + let isErc725YLegacy = false; + + isErc725Y = await this.supportsInterface(address, INTERFACE_IDS.ERC725Y); + + if (!isErc725Y) { + isErc725YLegacy = await this.supportsInterface( + address, + INTERFACE_IDS.ERC725Y_LEGACY, + ); + } + + if (!isErc725Y && !isErc725YLegacy) { + throw new Error( + `Contract: ${address} does not support ERC725Y interface.`, + ); + } + + if (isErc725Y) { + return decodeResult( + Method.GET_DATA, + await this.callContract( + constructJSONRPC( + address, + Method.GET_DATA, + abiCoder.encodeParameter('bytes32[]', [keyHash]), + ), + ), + )[0]; + } + return decodeResult( - Method.GET_DATA, + Method.GET_DATA_LEGACY, await this.callContract( - constructJSONRPC(address, Method.GET_DATA, keyHash), + constructJSONRPC(address, Method.GET_DATA_LEGACY, keyHash), ), ); } async getAllData(address: string, keys: string[]) { + let isErc725Y = false; + let isErc725YLegacy = false; + + isErc725Y = await this.supportsInterface(address, INTERFACE_IDS.ERC725Y); + + if (!isErc725Y) { + isErc725YLegacy = await this.supportsInterface( + address, + INTERFACE_IDS.ERC725Y_LEGACY, + ); + } + + if (!isErc725Y && !isErc725YLegacy) { + throw new Error( + `Contract: ${address} does not support ERC725Y interface.`, + ); + } + + const method = isErc725Y ? Method.GET_DATA : Method.GET_DATA_LEGACY; + const payload: JsonRpc[] = []; for (let index = 0; index < keys.length; index++) { - payload.push(constructJSONRPC(address, Method.GET_DATA, keys[index])); + payload.push( + constructJSONRPC( + address, + method, + isErc725Y + ? abiCoder.encodeParameter('bytes32[]', [keys[index]]) + : keys[index], + ), + ); } const results: any = await this.callContract(payload); @@ -69,12 +153,14 @@ export class Web3ProviderWrapper { value: Record | null; }[] = []; for (let index = 0; index < payload.length; index++) { + const decodedValue = decodeResult( + method, + results.find((element) => payload[index].id === element.id), + ); + returnValues.push({ key: keys[index], - value: decodeResult( - Method.GET_DATA, - results.find((element) => payload[index].id === element.id), - ), + value: isErc725Y ? decodedValue[0] : decodedValue, }); } diff --git a/src/types/Method.ts b/src/types/Method.ts index b5874c14..b84bc485 100644 --- a/src/types/Method.ts +++ b/src/types/Method.ts @@ -1,14 +1,18 @@ export enum Method { - GET_DATA = 'getData', + GET_DATA_LEGACY = 'getDataLegacy', // For legacy ERC725 with interface id: 0x2bd57b73 NOTE: I had to add Legacy at the end so the map keys stays unique + GET_DATA = 'getData', // For latest ERC725 with interface id: 0x5a988c0f DATA_COUNT = 'dataCount', ALL_DATA = 'allData', OWNER = 'owner', + SUPPORTS_INTERFACE = 'supportsInterface', } export enum Encoding { BYTES = 'bytes', + BOOL = 'bool', UINT256 = 'uint256', BYTES32_ARRAY = 'bytes32[]', + BYTES_ARRAY = 'bytes[]', ADDRESS = 'address', } diff --git a/test/mockProviders.ts b/test/mockProviders.ts index 4fb6d129..ba287077 100644 --- a/test/mockProviders.ts +++ b/test/mockProviders.ts @@ -1,44 +1,133 @@ // This file contains the mock providers used for tests +import { METHODS } from '../src/lib/constants'; +import { Method } from '../src/types/Method'; + +interface HttpProviderPayload { + jsonrpc: '2.0'; + method: string; + params: Array<{ + to: string; + gas: string; + gasPrice: string; + value: string; + data: string; + }>; + id: number; +} + export class HttpProvider { public returnData; + public supportsInterfaces: string[]; - constructor(props) { + constructor(props, supportsInterfaces: string[]) { // clone array this.returnData = Array.isArray(props.returnData) ? [...props.returnData] : props.returnData; + this.supportsInterfaces = supportsInterfaces; } - send(payload, cb) { + send(payload: HttpProviderPayload | HttpProviderPayload[], cb) { if (Array.isArray(payload)) { - const results: { jsonrpc: '2.0'; id: string; result: string }[] = []; + const results: { jsonrpc: '2.0'; id: number; result: string }[] = []; for (let index = 0; index < payload.length; index++) { - const foundResult = this.returnData.find((element) => { - // get call param (key) - const keyParam = '0x' + payload[index].params[0].data.substr(10); - return element.key === keyParam; - }); - - results.push({ - jsonrpc: '2.0', - id: payload[index].id, - result: foundResult ? foundResult.value : '0x', - }); + const methodSignature = payload[index].params[0].data.substr(0, 10); + + switch (methodSignature) { + case METHODS[Method.SUPPORTS_INTERFACE].sig: + throw new Error( + 'Mock of support interface not supported in array mode', + ); + case METHODS[Method.GET_DATA_LEGACY].sig: + { + const foundResult = this.returnData.find((element) => { + // get call param (key) + const keyParam = + '0x' + payload[index].params[0].data.substr(10); + return element.key === keyParam; + }); + + results.push({ + jsonrpc: '2.0', + id: payload[index].id, + result: foundResult ? foundResult.value : '0x', + }); + } + break; + case METHODS[Method.GET_DATA].sig: + { + const foundResult = this.returnData.find((element) => { + // get call param (key) + const keyParam = + '0x' + payload[index].params[0].data.substr(138); + return element.key === keyParam; + }); + + results.push({ + jsonrpc: '2.0', + id: payload[index].id, + result: foundResult ? foundResult.value : '0x', + }); + } + break; + default: + throw new Error( + `Method signature: ${methodSignature} mock is not supported in HttpProvider mock`, + ); + } } setTimeout(() => cb(null, results), 10); } else { - // get call param (key) - const keyParam = '0x' + payload.params[0].data.substr(10); + let result: string; + + const methodSignature = payload.params[0].data.substr(0, 10); + + switch (methodSignature) { + case METHODS[Method.SUPPORTS_INTERFACE].sig: + { + const requestedInterface = `0x${payload.params[0].data.substr( + 10, + 8, + )}`; + if (this.supportsInterfaces.includes(requestedInterface)) { + result = + '0x0000000000000000000000000000000000000000000000000000000000000001'; + } else { + result = + '0x0000000000000000000000000000000000000000000000000000000000000000'; + } + } + break; + case METHODS[Method.GET_DATA_LEGACY].sig: + { + const keyParam = '0x' + payload.params[0].data.substr(10); + result = Array.isArray(this.returnData) + ? this.returnData.find((e) => e.key === keyParam).value + : this.returnData; + } + break; + case METHODS[Method.GET_DATA].sig: + { + const keyParam = '0x' + payload.params[0].data.substr(138); + + result = Array.isArray(this.returnData) + ? this.returnData.find((e) => e.key === keyParam).value + : this.returnData; + } + break; + default: + throw new Error( + `Method signature: ${methodSignature} mock is not supported in HttpProvider mock`, + ); + } setTimeout( () => cb(null, { jsonrpc: '2.0', - result: Array.isArray(this.returnData) - ? this.returnData.find((e) => e.key === keyParam).value - : this.returnData, + result, }), 10, ); @@ -46,23 +135,68 @@ export class HttpProvider { } } +interface EthereumProviderPayload { + method: string; + params: Array<{ + to: string; + gas: string; + gasPrice: string; + value: string; + data: string; + }>; +} + export class EthereumProvider { public returnData; + public supportsInterfaces: string[]; - constructor(props) { + constructor(props, supportsInterfaces: string[]) { // Deconstruct to create local copy of array this.returnData = Array.isArray(props.returnData) ? [...props.returnData] : props.returnData; + this.supportsInterfaces = supportsInterfaces; } - request(payload) { - const keyParam = '0x' + payload.params[0].data.substr(10); // remove methodSig + request(payload: EthereumProviderPayload) { + let result: string; + + const methodSignature = payload.params[0].data.substr(0, 10); + + switch (methodSignature) { + case METHODS[Method.SUPPORTS_INTERFACE].sig: + { + const requestedInterface = `0x${payload.params[0].data.substr( + 10, + 8, + )}`; + if (this.supportsInterfaces.includes(requestedInterface)) { + result = + '0x0000000000000000000000000000000000000000000000000000000000000001'; + } else { + result = + '0x0000000000000000000000000000000000000000000000000000000000000000'; + } + } + break; + case METHODS[Method.GET_DATA_LEGACY].sig: + case METHODS[Method.GET_DATA].sig: + { + const keyParam = '0x' + payload.params[0].data.substr(10); + + result = Array.isArray(this.returnData) + ? this.returnData.find((e) => e.key === keyParam).value + : this.returnData; + } + break; + default: + throw new Error( + `Method signature: ${methodSignature} is not supported in EthereumProvider mock`, + ); + } + return new Promise((resolve) => { setTimeout(() => { - const result = Array.isArray(this.returnData) - ? this.returnData.find((e) => e.key === keyParam).value - : this.returnData; // TODO: Handle reject resolve(result); }, 50); diff --git a/test/mockSchema.ts b/test/mockSchema.ts index b8f2287f..41c4031a 100644 --- a/test/mockSchema.ts +++ b/test/mockSchema.ts @@ -1,11 +1,18 @@ // Mock schema for tests // make one schema that tests every single type -/* eslint-disable */ + +import AbiCoder from 'web3-eth-abi'; +import { utf8ToHex } from 'web3-utils'; import { ERC725JSONSchema } from '../src/types/ERC725JSONSchema'; +// TS can't get the types from the import... +// @ts-ignore +const abiCoder: AbiCoder.AbiCoder = AbiCoder; + export const mockSchema: (ERC725JSONSchema & { returnRawData?; + returnRawDataArray?; // Used for the array version of getData() returnGraphData?; expectedResult?; })[] = [ @@ -17,8 +24,8 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: '0xafdeb5d6', valueType: 'bytes', // Testing data - returnRawData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004afdeb5d600000000000000000000000000000000000000000000000000000000', + returnRawData: abiCoder.encodeParameter('bytes', '0xafdeb5d6'), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', ['0xafdeb5d6']), returnGraphData: '0xafdeb5d6', expectedResult: '0xafdeb5d6', }, @@ -31,8 +38,13 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'JSONURL', valueType: 'bytes', // Testing data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000596f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a626400000000000000', + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + ]), returnGraphData: '0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', expectedResult: { @@ -50,14 +62,19 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'AssetURL', valueType: 'bytes', // Testing data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000596f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a626400000000000000', + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x6f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x6f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + ]), returnGraphData: '0x6f357c6aa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', expectedResult: { hashFunction: 'keccak256(utf8)', hash: '0xa7d9a84b44013f71356d72e6c15fdc2533c573271c53d053ed8ddcdaa60f4c81', // hash of address '0x0c03fba782b07bcf810deb3b7f0595024a444f4e' - url: 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', // FAKE. just used from above + url: 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', // FAKE. just used from above TODO: fix this is not an asset URL but a JSON url !! }, }, @@ -69,8 +86,13 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Keccak256', valueType: 'bytes32', // Testing data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000204d75a97aff0964309140e9821514861e5ddcc827113b70a2b69db16dde0695dc', // this is bytes + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x4d75a97aff0964309140e9821514861e5ddcc827113b70a2b69db16dde0695dc', + ), // this is bytes + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x4d75a97aff0964309140e9821514861e5ddcc827113b70a2b69db16dde0695dc', + ]), returnGraphData: '0x4d75a97aff0964309140e9821514861e5ddcc827113b70a2b69db16dde0695dc', expectedResult: @@ -85,8 +107,13 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Address', valueType: 'bytes', // Testing data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000140c03fba782b07bcf810deb3b7f0595024a444f4e000000000000000000000000', + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x0c03fba782b07bcf810deb3b7f0595024a444f4e', + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x0c03fba782b07bcf810deb3b7f0595024a444f4e', + ]), returnGraphData: '0x0c03fba782b07bcf810deb3b7f0595024a444f4e', expectedResult: '0x0C03fBa782b07bCf810DEb3b7f0595024A444F4e', // a real address }, @@ -99,10 +126,16 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Markdown', valueType: 'bytes', // Testing data - returnRawData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000033232054657374696e67206d61726b646f776e2e200a2057656c636f6d6520746f206d61726b646f776e202a2a746573742a2a2e00000000000000000000000000', - returnGraphData: - '0x232054657374696e67206d61726b646f776e2e200a2057656c636f6d6520746f206d61726b646f776e202a2a746573742a2a2e', + returnRawData: abiCoder.encodeParameter( + 'bytes', + utf8ToHex('# Testing markdown. \n Welcome to markdown **test**.'), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('# Testing markdown. \n Welcome to markdown **test**.'), + ]), + returnGraphData: utf8ToHex( + '# Testing markdown. \n Welcome to markdown **test**.', + ), expectedResult: '# Testing markdown. \n Welcome to markdown **test**.', }, @@ -114,10 +147,12 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'String', valueType: 'string', // Testing data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000107061747269636b2d6d63646f77656c6c00000000000000000000000000000000', - returnGraphData: '0x7061747269636b2d6d63646f77656c6c', - expectedResult: 'patrick-mcdowell', + returnRawData: abiCoder.encodeParameter('bytes', utf8ToHex('john-snow')), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('john-snow'), + ]), + returnGraphData: utf8ToHex('john-snow'), + expectedResult: 'john-snow', }, // Case 8 @@ -128,10 +163,16 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'URL', valueType: 'bytes', // testing data - returnRawData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a62640000000000000000000000', - returnGraphData: - '0x697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + returnRawData: abiCoder.encodeParameter( + 'bytes', + utf8ToHex('ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd'), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd'), + ]), + returnGraphData: utf8ToHex( + 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', + ), expectedResult: 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', }, @@ -145,9 +186,26 @@ export const mockSchema: (ERC725JSONSchema & { // testing data // the full array of values returnRawData: [ - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002', // array length - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014c444009d38d3046bb0cf81fa2cd295ce46a67c78000000000000000000000000', - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000144febc3491230571f6e1829e46602e3b110215a2e000000000000000000000000', + abiCoder.encodeParameter('bytes', abiCoder.encodeParameter('uint256', 2)), // array length + abiCoder.encodeParameter( + 'bytes', + '0xc444009d38d3046bb0cf81fa2cd295ce46a67c78', + ), + abiCoder.encodeParameter( + 'bytes', + '0x4febc3491230571f6e1829e46602e3b110215a2e', + ), + ], + returnRawDataArray: [ + abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('uint256', 2), + ]), + abiCoder.encodeParameter('bytes[]', [ + '0xc444009d38d3046bb0cf81fa2cd295ce46a67c78', + ]), + abiCoder.encodeParameter('bytes[]', [ + '0x4febc3491230571f6e1829e46602e3b110215a2e', + ]), ], returnGraphData: [ '0x0000000000000000000000000000000000000000000000000000000000000002', // array length @@ -169,9 +227,21 @@ export const mockSchema: (ERC725JSONSchema & { // testing data // the full array of values returnRawData: [ - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002', // array length - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000144febc3491230571f6e1829e46602e3b110215a2e000000000000000000000000', + abiCoder.encodeParameter('bytes', abiCoder.encodeParameter('uint256', 2)), // array length + abiCoder.encodeParameter('bytes', '0x'), + abiCoder.encodeParameter( + 'bytes', + '0x4febc3491230571f6e1829e46602e3b110215a2e', + ), + ], + returnRawDataArray: [ + abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('uint256', 2), + ]), + abiCoder.encodeParameter('bytes[]', ['0x']), + abiCoder.encodeParameter('bytes[]', [ + '0x4febc3491230571f6e1829e46602e3b110215a2e', + ]), ], returnGraphData: [ '0x0000000000000000000000000000000000000000000000000000000000000002', // array length @@ -181,7 +251,7 @@ export const mockSchema: (ERC725JSONSchema & { expectedResult: [null, '0x4fEbC3491230571F6e1829E46602e3b110215A2E'], }, - // Case 10 + // // Case 10 { name: 'TestObjArray[]', key: '0x9985edaf12cbacf5ac7d6ed54f0445cc0ea56075aee9b9942e4ab3bf4239f950', @@ -191,9 +261,26 @@ export const mockSchema: (ERC725JSONSchema & { // testing data // the full array of values returnRawData: [ - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002', // array length - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000596f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a626400000000000000', - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000596f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a626400000000000000', + abiCoder.encodeParameter('bytes', abiCoder.encodeParameter('uint256', 2)), // array length + abiCoder.encodeParameter( + 'bytes', + '0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + ), + abiCoder.encodeParameter( + 'bytes', + '0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264', + ), + ], + returnRawDataArray: [ + abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('uint256', 2), + ]), + abiCoder.encodeParameter('bytes[]', [ + '0x6f357c6a733e78f2fc4a3304c141e8424d02c9069fe08950c6514b27289ead8ef4faa49d697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a6264', + ]), + abiCoder.encodeParameter('bytes[]', [ + '0x6f357c6a81bd0b7ed5ac354abbf24619ce16933f00a4bdfa8fcaf3791d25f69b497abf88697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a6264', + ]), ], returnGraphData: [ '0x0000000000000000000000000000000000000000000000000000000000000002', // array length @@ -216,7 +303,7 @@ export const mockSchema: (ERC725JSONSchema & { ], }, - // Testing other valueTypes + // // Testing other valueTypes // Case 11 { @@ -226,13 +313,15 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'String', valueType: 'string', // Test data - returnRawData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c47726561742d737472696e670000000000000000000000000000000000000000', - returnGraphData: '0x47726561742d737472696e67', + returnRawData: abiCoder.encodeParameter('bytes', utf8ToHex('Great-string')), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('Great-string'), + ]), + returnGraphData: utf8ToHex('Great-string'), expectedResult: 'Great-string', }, - // Case 12 + // // Case 12 { name: 'TestUintValueType', key: '0x61529294800f5739edc21a6cf8ba1bad3fd3e11d03d2ab5219ce9c0131b93f93', @@ -240,8 +329,13 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Number', valueType: 'uint256', // Test data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000063', + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x0000000000000000000000000000000000000000000000000000000000000063', + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x0000000000000000000000000000000000000000000000000000000000000063', + ]), returnGraphData: '0x0000000000000000000000000000000000000000000000000000000000000063', expectedResult: '99', // TODO: BUG: This should not need to be string to work? @@ -255,8 +349,13 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Number', valueType: 'bytes', // Test data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000063', + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x0000000000000000000000000000000000000000000000000000000000000063', + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x0000000000000000000000000000000000000000000000000000000000000063', + ]), returnGraphData: '0x0000000000000000000000000000000000000000000000000000000000000063', expectedResult: '99', @@ -270,10 +369,14 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'String', valueType: 'bytes', // Test data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000264f6b2074686973206973206120737472696e672073746f7265642061732062797465732e2e2e0000000000000000000000000000000000000000000000000000', - returnGraphData: - '0x4f6b2074686973206973206120737472696e672073746f7265642061732062797465732e2e2e', + returnRawData: abiCoder.encodeParameter( + 'bytes', + utf8ToHex('Ok this is a string stored as bytes...'), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('Ok this is a string stored as bytes...'), + ]), + returnGraphData: utf8ToHex('Ok this is a string stored as bytes...'), expectedResult: 'Ok this is a string stored as bytes...', }, @@ -286,10 +389,23 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'String', valueType: 'string[]', // Testing fields - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b6170706c65207361756365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e62757474657220636869636b656e000000000000000000000000000000000000', - returnGraphData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b6170706c65207361756365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e62757474657220636869636b656e000000000000000000000000000000000000', + returnRawData: abiCoder.encodeParameter( + 'bytes', + abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('apple sauce'), + utf8ToHex('butter chicken'), + ]), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('apple sauce'), + utf8ToHex('butter chicken'), + ]), + ]), + returnGraphData: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('apple sauce'), + utf8ToHex('butter chicken'), + ]), expectedResult: ['apple sauce', 'butter chicken'], }, @@ -301,14 +417,24 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'String', valueType: 'bytes[]', // Testing fields - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b6170706c65207361756365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e62757474657220636869636b656e000000000000000000000000000000000000', - returnGraphData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b6170706c65207361756365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e62757474657220636869636b656e000000000000000000000000000000000000', - expectedResult: [ - 'apple sauce', // 0x6170706c65207361756365 - 'butter chicken', // 0x62757474657220636869636b656e - ], + returnRawData: abiCoder.encodeParameter( + 'bytes', + abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('apple sauce'), + utf8ToHex('butter chicken'), + ]), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('apple sauce'), + utf8ToHex('butter chicken'), + ]), + ]), + returnGraphData: abiCoder.encodeParameter('bytes[]', [ + utf8ToHex('apple sauce'), + utf8ToHex('butter chicken'), + ]), + expectedResult: ['apple sauce', 'butter chicken'], }, // Case 17 @@ -319,17 +445,30 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Address', valueType: 'address[]', // Testing fields - returnRawData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ce3e75a43b0a29292219926eadc8c5585651219c000000000000000000000000ba61a0b24a228807f23b46064773d28fe51da81c', - returnGraphData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000ce3e75a43b0a29292219926eadc8c5585651219c000000000000000000000000ba61a0b24a228807f23b46064773d28fe51da81c', + returnRawData: abiCoder.encodeParameter( + 'bytes', + abiCoder.encodeParameter('address[]', [ + '0xCE3e75A43B0A29292219926EAdC8C5585651219C', + '0xba61a0b24a228807f23b46064773d28fe51da81c', + ]), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('address[]', [ + '0xCE3e75A43B0A29292219926EAdC8C5585651219C', + '0xba61a0b24a228807f23b46064773d28fe51da81c', + ]), + ]), + returnGraphData: abiCoder.encodeParameter('address[]', [ + '0xCE3e75A43B0A29292219926EAdC8C5585651219C', + '0xba61a0b24a228807f23b46064773d28fe51da81c', + ]), expectedResult: [ - '0xCE3e75A43B0A29292219926EAdC8C5585651219C', // (firefox metamask key) - '0xba61a0b24a228807f23B46064773D28Fe51dA81C', // {firefox metamask key} + '0xCE3e75A43B0A29292219926EAdC8C5585651219C', + '0xba61a0b24a228807f23B46064773D28Fe51dA81C', ], }, - // Case 18 + // // Case 18 { name: 'TestUintValueTypeArray', key: '0xdaa41a5e1acc41087359e61588e80bf0b7f1d96063b98bdff73b4ce3a645b40b', @@ -337,10 +476,14 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Number', valueType: 'uint256[]', // Testing fields - returnRawData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c8', - returnGraphData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c8', + returnRawData: abiCoder.encodeParameter( + 'bytes', + abiCoder.encodeParameter('uint256[]', [123, 456]), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('uint256[]', [123, 456]), + ]), + returnGraphData: abiCoder.encodeParameter('uint256[]', [123, 456]), expectedResult: [ '123', // (firefox metamask key) '456', // {firefox metamask key} @@ -355,17 +498,30 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'Keccak256', valueType: 'bytes32[]', // Testing fields - returnRawData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002e5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', - returnGraphData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002e5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', + returnRawData: abiCoder.encodeParameter( + 'bytes', + abiCoder.encodeParameter('bytes32[]', [ + '0xe5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f', + '0x828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', + ]), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('bytes32[]', [ + '0xe5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f', + '0x828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', + ]), + ]), + returnGraphData: abiCoder.encodeParameter('bytes32[]', [ + '0xe5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f', + '0x828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', + ]), expectedResult: [ - '0xe5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f', // test01 - '0x828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', // test02 + '0xe5d35cae7c9db9879eb8a205baa046ad99503414d6a55eb6725494a4254a6d3f', + '0x828e919feac2ec05939abd5d221692fbe6bac5667ba5af5d191df1f7ecb1ac21', ], }, - // Case 20 + // // Case 20 { name: 'TestURLStringValueTypeArray', key: '0x1a9818703b62d00000bd3e8c7499296d42966619cd735a92eac7488de8881bb8', @@ -373,13 +529,26 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: 'URL', valueType: 'string[]', // Testing fields - returnRawData: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a626400000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a62640000000000000000000000', - returnGraphData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d6245724b6833466a7378787878787878787878787878787878787878787878787878787639414a4a765a626400000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d6245724b6833466a73415236596a73546a485a4e6d364d6344703661527438324674637639414a4a765a62640000000000000000000000', + returnRawData: abiCoder.encodeParameter( + 'bytes', + abiCoder.encodeParameter('string[]', [ + 'ipfs://QmbErKh3Fjsxxxxxxxxxxxxxxxxxxxxxxxxxxv9AJJvZbd', + 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', + ]), + ), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + abiCoder.encodeParameter('string[]', [ + 'ipfs://QmbErKh3Fjsxxxxxxxxxxxxxxxxxxxxxxxxxxv9AJJvZbd', + 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', + ]), + ]), + returnGraphData: abiCoder.encodeParameter('string[]', [ + 'ipfs://QmbErKh3Fjsxxxxxxxxxxxxxxxxxxxxxxxxxxv9AJJvZbd', + 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', + ]), expectedResult: [ - 'ipfs://QmbErKh3Fjsxxxxxxxxxxxxxxxxxxxxxxxxxxv9AJJvZbd', // (firefox metamask key) - 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', // {firefox metamask key} + 'ipfs://QmbErKh3Fjsxxxxxxxxxxxxxxxxxxxxxxxxxxv9AJJvZbd', + 'ipfs://QmbErKh3FjsAR6YjsTjHZNm6McDp6aRt82Ftcv9AJJvZbd', ], }, @@ -392,8 +561,13 @@ export const mockSchema: (ERC725JSONSchema & { '0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', // keccak hash of 'test' valueType: 'bytes32', // Testing data - returnRawData: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000209c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', // this is bytes + returnRawData: abiCoder.encodeParameter( + 'bytes', + '0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', + ), // this is bytes + returnRawDataArray: abiCoder.encodeParameter('bytes[]', [ + '0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', + ]), returnGraphData: '0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658', expectedResult: @@ -407,8 +581,8 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: '0xafdeb5d6', valueType: 'bytes', // Testing data - returnRawData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004afdeb5d600000000000000000000000000000000000000000000000000000000', + returnRawData: abiCoder.encodeParameter('bytes', '0xafdeb5d6'), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', ['0xafdeb5d6']), returnGraphData: '0xafdeb5d6', expectedResult: '0xafdeb5d6', }, @@ -419,8 +593,8 @@ export const mockSchema: (ERC725JSONSchema & { valueContent: '0xafdeb5d6', valueType: 'bytes', // Testing data - returnRawData: - '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004afdeb5d600000000000000000000000000000000000000000000000000000000', + returnRawData: abiCoder.encodeParameter('bytes', '0xafdeb5d6'), + returnRawDataArray: abiCoder.encodeParameter('bytes[]', ['0xafdeb5d6']), returnGraphData: '0xafdeb5d6', expectedResult: '0xafdeb5d6', }, diff --git a/test/testHelpers.ts b/test/testHelpers.ts index 8858f657..3b309d0a 100644 --- a/test/testHelpers.ts +++ b/test/testHelpers.ts @@ -22,13 +22,17 @@ import { encodeArrayKey } from '../src/lib/utils'; /** * Takes the schema object and builds a full dataset as per expected from provider. */ -export function generateAllRawData(schema) { - const results: any[] = []; +export function generateAllRawData(schema, isArrayMode: boolean) { + const results: { key: string; value: string }[] = []; for (let index = 0; index < schema.length; index++) { const element = schema[index]; // if is array push data if (element.keyType === 'Array') { - element.returnRawData.forEach((e, i) => { + const correctReturnRawData = isArrayMode + ? element.returnRawDataArray + : element.returnRawData; + + correctReturnRawData.forEach((e, i) => { // we assume always first element in the array in returnData array is the length if (i === 0) { results.push({ @@ -46,7 +50,7 @@ export function generateAllRawData(schema) { } else { results.push({ key: element.key, - value: element.returnRawData, + value: isArrayMode ? element.returnRawDataArray : element.returnRawData, }); } }