From aab40dd327a70531ba151204614493e89deff9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Dethier?= Date: Wed, 6 Sep 2023 16:03:15 +0200 Subject: [PATCH] feat: add Astar tokens. logion-network/logion-internal#980 --- packages/client/package.json | 2 +- packages/client/src/Token.ts | 71 +++++++++++++++++++++++++- packages/client/test/Token.spec.ts | 80 ++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 3 deletions(-) diff --git a/packages/client/package.json b/packages/client/package.json index b1de4a25..3b32815d 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@logion/client", - "version": "0.30.0", + "version": "0.30.1-1", "description": "logion SDK for client applications", "main": "dist/index.js", "packageManager": "yarn@3.2.0", diff --git a/packages/client/src/Token.ts b/packages/client/src/Token.ts index 973f2b23..4278451d 100644 --- a/packages/client/src/Token.ts +++ b/packages/client/src/Token.ts @@ -25,6 +25,9 @@ export type TokenType = | 'multiversx_devnet_esdt' | 'multiversx_testnet_esdt' | 'multiversx_esdt' + | 'astar_psp34' + | 'astar_shiden_psp34' + | 'astar_shibuya_psp34' ; export type NetworkType = 'ETHEREUM' | 'POLKADOT' | 'MULTIVERSX'; @@ -48,6 +51,9 @@ export function isTokenType(type: string): type is TokenType { || type === 'multiversx_devnet_esdt' || type === 'multiversx_testnet_esdt' || type === 'multiversx_esdt' + || type === 'astar_psp34' + || type === 'astar_shiden_psp34' + || type === 'astar_shibuya_psp34' ); } @@ -58,11 +64,12 @@ export function isTokenCompatibleWith(type: TokenType, networkType: NetworkType) if (networkType === 'ETHEREUM') { return type.startsWith("ethereum") || type.startsWith("goerli") - || type.startsWith("polygon") + || type.startsWith("polygon"); } else if (networkType === 'MULTIVERSX') { - return type.startsWith("multiversx") + return type.startsWith("multiversx"); } else { return type === "singular_kusama" + || type.startsWith("astar"); } } @@ -125,6 +132,8 @@ export function validateToken(api: LogionNodeApiClass, itemToken: ItemTokenWithR error: "token ID must be a valid MultiversX ESDT ID", } } + } else if (itemToken.type.includes("psp34")) { + return validatePsp34TokenId(itemToken.id); } else { return { valid: false, @@ -183,3 +192,61 @@ export function isSingularKusamaId(tokenId: string): boolean { export function isMultiversxESDTId(tokenId: string): boolean { return /^[0-9A-Z]+-[0-9a-f]{6}(-[0-9a-f]+)?$/.test(tokenId); } + +export function validatePsp34TokenId(tokenId: string): TokenValidationResult { + try { + const idObject = JSON.parse(tokenId); + if(typeof idObject !== "object") { + return { + valid: false, + error: "token ID is not a JSON dictionnary", + }; + } + + const contract = idObject['contract']; + if(!contract) { + return { + valid: false, + error: "token ID is missing the 'contract' field", + }; + } + if(typeof contract !== "string") { + return { + valid: false, + error: "token ID's 'contract' field is not a string", + }; + } + + const id = idObject['id']; + if(!id) { + return { + valid: false, + error: "token ID is missing the 'id' field", + }; + } + if(typeof id !== "object") { + return { + valid: false, + error: "token ID's 'id' field is not an object", + }; + } + if(!idObject.id.U8 + && !idObject.id.U16 + && !idObject.id.U32 + && !idObject.id.U64 + && !idObject.id.U128 + && !idObject.id.Bytes) { + return { + valid: false, + error: "token ID's 'id' object is missing a value for U8, U16, U32, U64, U128 or Bytes", + }; + } + + return { valid: true }; + } catch(e) { + return { + valid: false, + error: "token ID is not valid JSON", + }; + } +} diff --git a/packages/client/test/Token.spec.ts b/packages/client/test/Token.spec.ts index 8434f95a..638a63ae 100644 --- a/packages/client/test/Token.spec.ts +++ b/packages/client/test/Token.spec.ts @@ -36,10 +36,17 @@ const esdtTypes: TokenType[] = [ "multiversx_esdt", ] +const psp34Types: TokenType[] = [ + "astar_psp34", + "astar_shiden_psp34", + "astar_shibuya_psp34", +] + const allTypes: TokenType[] = [ ...ercNonFungibleTypes, ...ercFungibleTypes, ...esdtTypes, + ...psp34Types, ...otherTypes, ]; @@ -90,6 +97,10 @@ describe("Token", () => { testIsTokenCompatibleWith('singular_kusama', 'POLKADOT') ); + it(`checks that PSP34 token types are POLKADOT-compatible`, () => + psp34Types.forEach(type => testIsTokenCompatibleWith(type, 'POLKADOT')) + ); + it("validates valid owner token with Ethereum address", () => { testValid({ type: "owner", @@ -157,6 +168,75 @@ describe("Token", () => { ) }); + it("validates valid PSP34 token", () => { + psp34Types.forEach(type => { + testValid({ + type, + issuance: 1n, + id: '{"contract":"XyNVZ92vFrYf4rCj8EoAXMRWRG7okRy7gxhn167HaYQZqTc","id":{ "U32": 42 }}', + }); + }); + }); + + it("invalidates PSP34 token with invalid JSON", () => { + psp34Types.forEach(type => { + testInvalid({ + type, + issuance: 1n, + id: '{42}', + }, "token ID is not valid JSON"); + }); + }); + + it("invalidates PSP34 token with no JSON dictionnary", () => { + psp34Types.forEach(type => { + testInvalid({ + type, + issuance: 1n, + id: '42', + }, "token ID is not a JSON dictionnary"); + }); + }); + + it("invalidates PSP34 token with missing contract", () => { + psp34Types.forEach(type => { + testInvalid({ + type, + issuance: 1n, + id: '{"id": { "U32": 42 }}', + }, "token ID is missing the 'contract' field"); + }); + }); + + it("invalidates PSP34 token with missing id", () => { + psp34Types.forEach(type => { + testInvalid({ + type, + issuance: 1n, + id: '{"contract":"XyNVZ92vFrYf4rCj8EoAXMRWRG7okRy7gxhn167HaYQZqTc"}', + }, "token ID is missing the 'id' field"); + }); + }); + + it("invalidates PSP34 token with non-object ID", () => { + psp34Types.forEach(type => { + testInvalid({ + type, + issuance: 1n, + id: '{"contract":"XyNVZ92vFrYf4rCj8EoAXMRWRG7okRy7gxhn167HaYQZqTc","id": 42}', + }, "token ID's 'id' field is not an object"); + }); + }); + + it("invalidates PSP34 token with ID without value", () => { + psp34Types.forEach(type => { + testInvalid({ + type, + issuance: 1n, + id: '{"contract":"XyNVZ92vFrYf4rCj8EoAXMRWRG7okRy7gxhn167HaYQZqTc","id": {}}', + }, "token ID's 'id' object is missing a value for U8, U16, U32, U64, U128 or Bytes"); + }); + }); }); describe("isTokenType", () => {