Skip to content

Commit

Permalink
Merge pull request #181 from logion-network/feature/astar-tokens
Browse files Browse the repository at this point in the history
Add Astar PSP34 tokens
  • Loading branch information
gdethier authored Sep 6, 2023
2 parents 43d6955 + aab40dd commit f678641
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -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": "[email protected]",
Expand Down
71 changes: 69 additions & 2 deletions packages/client/src/Token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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'
);
}

Expand All @@ -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");
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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",
};
}
}
80 changes: 80 additions & 0 deletions packages/client/test/Token.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
];

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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", () => {
Expand Down

0 comments on commit f678641

Please sign in to comment.