diff --git a/.env.example b/.env.example index 0ec60be5..ef2af920 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ WS_CORETIME_CHAIN="WSS endpoint of the coretime chain" WS_RELAY_CHAIN="WSS endpoint of the coretime relay chain" -WS_CONTRACTS_CHAIN="WSS endpoint of the contracts chain" \ No newline at end of file +WS_CONTRACTS_CHAIN="WSS endpoint of the contracts chain" +CONTRACT_XC_REGIONS="AddressOfXcRegionsContract" \ No newline at end of file diff --git a/next.config.js b/next.config.js index e232ff0a..dea8ae68 100644 --- a/next.config.js +++ b/next.config.js @@ -8,6 +8,7 @@ const nextConfig = { WS_CORETIME_CHAIN: process.env.WS_CORETIME_CHAIN, WS_RELAY_CHAIN: process.env.WS_RELAY_CHAIN, WS_CONTRACTS_CHAIN: process.env.WS_CONTRACTS_CHAIN, + CONTRACT_XC_REGIONS: process.env.CONTRACT_XC_REGIONS, }, }; diff --git a/src/contexts/apis/consts.ts b/src/contexts/apis/consts.ts index a0f0eded..aac47a64 100644 --- a/src/contexts/apis/consts.ts +++ b/src/contexts/apis/consts.ts @@ -1,3 +1,4 @@ export const WS_RELAY_CHAIN = process.env.WS_RELAY_CHAIN ?? ''; export const WS_CORETIME_CHAIN = process.env.WS_CORETIME_CHAIN ?? ''; export const WS_CONTRACTS_CHAIN = process.env.WS_CONTRACTS_CHAIN ?? ''; +export const CONTRACT_XC_REGIONS = process.env.CONTRACT_XC_REGIONS ?? ''; diff --git a/src/contexts/regions/index.tsx b/src/contexts/regions/index.tsx index 007b4bf7..f0fce7e6 100644 --- a/src/contexts/regions/index.tsx +++ b/src/contexts/regions/index.tsx @@ -1,10 +1,11 @@ -import { useInkathon } from '@scio-labs/use-inkathon'; +import { contractQuery, decodeOutput, useContract, useInkathon } from '@scio-labs/use-inkathon'; import React, { createContext, useContext, useEffect, useState } from 'react'; import { countOne, getBlockTimestamp, parseHNString, + parseHNStringToString, stringifyOnChainId as stringifyOnChainRegionId, } from '@/utils/functions'; @@ -19,7 +20,9 @@ import { } from '@/models'; import { useCoretimeApi, useRelayApi } from '../apis'; +import { CONTRACT_XC_REGIONS } from '../apis/consts'; import { ApiState } from '../apis/types'; +import XcRegionsMetadata from "../../contracts/xc_regions.json"; interface RegionsData { regions: Array; @@ -57,7 +60,9 @@ const RegionDataProvider = ({ children }: Props) => { const { state: { api: relayApi, apiState: relayApiState }, } = useRelayApi(); - const { activeAccount } = useInkathon(); + const { api: contractsApi, isConnected: contractsReady, activeAccount } = useInkathon(); + + const { contract } = useContract(XcRegionsMetadata, CONTRACT_XC_REGIONS); const [regions, setRegions] = useState>([]); const [timeslicePeriod, setTimeslicePeriod] = useState(0); @@ -67,7 +72,9 @@ const RegionDataProvider = ({ children }: Props) => { coretimeApi && coretimeApiState === ApiState.READY && relayApi && - relayApiState === ApiState.READY; + relayApiState === ApiState.READY && + contractsApi && + contractsReady; const fetchTasks = async () => { if (!coretimeApi || coretimeApiState !== ApiState.READY) return {}; @@ -105,14 +112,19 @@ const RegionDataProvider = ({ children }: Props) => { const tasks = await fetchTasks(); + const rawXcRegionIds = await getOwnedRawXcRegionIds(); + const xcRegions = await getOwnedXcRegions(rawXcRegionIds); + + const brokerRegions = await getBrokerRegions(); + const _regions: Array = []; - const res = await coretimeApi.query.broker.regions.entries(); - for await (const [key, value] of res) { - const [regionId] = key.toHuman() as [HumanRegionId]; - const regionData = value.toHuman() as HumanRegionRecord; + + for await (const region of [...brokerRegions, ...xcRegions]) { + const regionId = region[0]; + const regionData = region[1]; const { begin, core, mask } = regionId; - const { end, owner, paid } = regionData; + const { end, owner, paid, origin } = regionData; const beginBlockHeight = timeslicePeriod * parseHNString(begin); const beginTimestamp = await getBlockTimestamp(relayApi, beginBlockHeight); // begin block timestamp @@ -149,7 +161,7 @@ const RegionDataProvider = ({ children }: Props) => { end: endTimestamp, owner, paid: nPaid, - origin: RegionOrigin.CORETIME_CHAIN, + origin: origin ? origin : RegionOrigin.CORETIME_CHAIN, rawId, consumed, name: name ?? `Region #${_regions.length + 1}`, @@ -189,6 +201,108 @@ const RegionDataProvider = ({ children }: Props) => { ); }; + const getBrokerRegions = async (): Promise> => { + if (!coretimeApi) { + return []; + } + const brokerEntries = await coretimeApi.query.broker.regions.entries(); + + const brokerRegions: Array<[HumanRegionId, HumanRegionRecord]> = brokerEntries + .map(([key, value]) => { + const keyTuple = key.toHuman(); + + // This is defensive. + if (keyTuple && Array.isArray(keyTuple) && keyTuple[0] !== undefined) { + return [keyTuple[0] as HumanRegionId, value.toHuman() as HumanRegionRecord]; + } + return null; + }) + .filter(entry => entry !== null) as Array<[HumanRegionId, HumanRegionRecord]>; + + return brokerRegions; + } + + const getOwnedRawXcRegionIds = async (): Promise> => { + if (!contractsApi || !contract || !activeAccount) { + return []; + } + + const rawRegionIds = []; + let isError = false; + let index = 0; + + while (!isError) { + const result = await contractQuery( + contractsApi, + "", + contract, + "PSP34Enumerable::owners_token_by_index", + {}, + [activeAccount.address, index], + ); + + const { output, isError: queryError, decodedOutput } = decodeOutput( + result, + contract, + "PSP34Enumerable::owners_token_by_index", + ); + + if (queryError || decodedOutput === "TokenNotExists") { + isError = true; + } else { + rawRegionIds.push(parseHNStringToString(output.Ok.U128)); + index++; + } + } + + return rawRegionIds; + }; + + const getOwnedXcRegions = async (rawRegionIds: Array): Promise> => { + if (!contractsApi || !contract || !activeAccount) { + return []; + } + + const regions: Array<[HumanRegionId, HumanRegionRecord]> = []; + + for await (const regionId of rawRegionIds) { + const result = await contractQuery( + contractsApi, + "", + contract, + "RegionMetadata::get_metadata", + {}, + [regionId], + ); + + const { output, isError: queryError } = decodeOutput( + result, + contract, + "RegionMetadata::get_metadata", + ); + + if (!queryError) { + const versionedRegion = output.Ok; + + // TODO: Once cross-chain region transfers are enabled from the broker pallet ensure + // metadata is correct. + + regions.push([{ + begin: versionedRegion.region.begin, + core: versionedRegion.region.core, + mask: versionedRegion.region.mask, + }, { + end: versionedRegion.region.end, + owner: activeAccount.address, + origin: RegionOrigin.CONTRACTS_CHAIN, + paid: undefined + }]); + } + } + + return regions; + } + return ( " + ], + "description": "Cross-chain Regions contracts." + }, + "spec": { + "constructors": [ + { + "args": [], + "default": false, + "docs": [], + "label": "new", + "payable": false, + "returnType": { + "displayName": [ + "ink_primitives", + "ConstructorResult" + ], + "type": 9 + }, + "selector": "0x9bae9d5e" + } + ], + "docs": [], + "environment": { + "accountId": { + "displayName": [ + "AccountId" + ], + "type": 0 + }, + "balance": { + "displayName": [ + "Balance" + ], + "type": 5 + }, + "blockNumber": { + "displayName": [ + "BlockNumber" + ], + "type": 4 + }, + "chainExtension": { + "displayName": [ + "ChainExtension" + ], + "type": 36 + }, + "hash": { + "displayName": [ + "Hash" + ], + "type": 35 + }, + "maxEventTopics": 4, + "timestamp": { + "displayName": [ + "Timestamp" + ], + "type": 7 + } + }, + "events": [ + { + "args": [ + { + "docs": [ + " The identifier of the region that got initialized." + ], + "indexed": true, + "label": "region_id", + "type": { + "displayName": [ + "RawRegionId" + ], + "type": 5 + } + }, + { + "docs": [ + " The associated metadata." + ], + "indexed": false, + "label": "metadata", + "type": { + "displayName": [ + "Region" + ], + "type": 19 + } + }, + { + "docs": [ + " The version of the metadata. This is incremented by the contract each time the same", + " region is initialized." + ], + "indexed": false, + "label": "version", + "type": { + "displayName": [ + "Version" + ], + "type": 4 + } + } + ], + "docs": [], + "label": "RegionInitialized" + }, + { + "args": [ + { + "docs": [ + " The identifier of the region that got removed." + ], + "indexed": true, + "label": "region_id", + "type": { + "displayName": [ + "RawRegionId" + ], + "type": 5 + } + } + ], + "docs": [], + "label": "RegionRemoved" + } + ], + "lang_error": { + "displayName": [ + "ink", + "LangError" + ], + "type": 10 + }, + "messages": [ + { + "args": [ + { + "label": "id", + "type": { + "displayName": [ + "regionmetadata_external", + "RemoveInput1" + ], + "type": 5 + } + } + ], + "default": false, + "docs": [ + " A function to return the region to its owner.", + "", + " This process involves burning the wrapped region and eliminating its associated", + " metadata.", + "", + "Only the owner of the wrapped region can call this function.", + "", + " ## Arguments:", + " - `raw_region_id` - The `u128` encoded region identifier.", + "", + " ## Events:", + " On success this ink message emits the `RegionRemoved` event." + ], + "label": "RegionMetadata::remove", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 11 + }, + "selector": "0xc1e3b44f" + }, + { + "args": [ + { + "label": "id", + "type": { + "displayName": [ + "regionmetadata_external", + "GetMetadataInput1" + ], + "type": 5 + } + } + ], + "default": false, + "docs": [ + " A function to retrieve all metadata associated with a specific region.", + "", + " The function returns a `VersionedRegion`, encompassing the version of the retrieved", + " metadata that is intended for client-side verification.", + "", + " ## Arguments:", + " - `raw_region_id` - The `u128` encoded region identifier." + ], + "label": "RegionMetadata::get_metadata", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 16 + }, + "selector": "0x22c5cfd4" + }, + { + "args": [ + { + "label": "id", + "type": { + "displayName": [ + "regionmetadata_external", + "InitInput1" + ], + "type": 5 + } + }, + { + "label": "metadata", + "type": { + "displayName": [ + "regionmetadata_external", + "InitInput2" + ], + "type": 19 + } + } + ], + "default": false, + "docs": [ + " A function for minting a wrapped xcRegion and initializing the metadata of it. It can", + " only be called if the specified region exists on this chain and the caller is the actual", + " owner of the region.", + "", + " ## Arguments:", + " - `raw_region_id` - The `u128` encoded region identifier.", + " - `region` - The corresponding region metadata.", + "", + " This function conducts a sanity check to verify that the metadata derived from the", + " `raw_region_id` aligns with the respective components of the metadata supplied through", + " the region argument.", + "", + " If this is not the first time that this region is inititalized, the metadata version", + " will get incremented.", + "", + " The underlying region will be transferred to this contract, and in response, a wrapped", + " token will be minted for the caller.", + "", + " NOTE: Prior to invoking this ink message, the caller must grant approval to the contract", + " for the region, enabling its transfer.", + "", + " ## Events:", + " On success this ink message emits the `RegionInitialized` event." + ], + "label": "RegionMetadata::init", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 11 + }, + "selector": "0xd8354645" + }, + { + "args": [ + { + "label": "owner", + "type": { + "displayName": [ + "psp34_external", + "BalanceOfInput1" + ], + "type": 0 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34::balance_of", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 22 + }, + "selector": "0xcde7e55f" + }, + { + "args": [], + "default": false, + "docs": [], + "label": "PSP34::collection_id", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 23 + }, + "selector": "0xffa27a5f" + }, + { + "args": [ + { + "label": "owner", + "type": { + "displayName": [ + "psp34_external", + "AllowanceInput1" + ], + "type": 0 + } + }, + { + "label": "operator", + "type": { + "displayName": [ + "psp34_external", + "AllowanceInput2" + ], + "type": 0 + } + }, + { + "label": "id", + "type": { + "displayName": [ + "psp34_external", + "AllowanceInput3" + ], + "type": 25 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34::allowance", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 26 + }, + "selector": "0x4790f55a" + }, + { + "args": [ + { + "label": "id", + "type": { + "displayName": [ + "psp34_external", + "OwnerOfInput1" + ], + "type": 24 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34::owner_of", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 28 + }, + "selector": "0x1168624d" + }, + { + "args": [ + { + "label": "operator", + "type": { + "displayName": [ + "psp34_external", + "ApproveInput1" + ], + "type": 0 + } + }, + { + "label": "id", + "type": { + "displayName": [ + "psp34_external", + "ApproveInput2" + ], + "type": 25 + } + }, + { + "label": "approved", + "type": { + "displayName": [ + "psp34_external", + "ApproveInput3" + ], + "type": 27 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34::approve", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 30 + }, + "selector": "0x1932a8b0" + }, + { + "args": [ + { + "label": "to", + "type": { + "displayName": [ + "psp34_external", + "TransferInput1" + ], + "type": 0 + } + }, + { + "label": "id", + "type": { + "displayName": [ + "psp34_external", + "TransferInput2" + ], + "type": 24 + } + }, + { + "label": "data", + "type": { + "displayName": [ + "psp34_external", + "TransferInput3" + ], + "type": 8 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34::transfer", + "mutates": true, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 30 + }, + "selector": "0x3128d61b" + }, + { + "args": [], + "default": false, + "docs": [], + "label": "PSP34::total_supply", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 32 + }, + "selector": "0x628413fe" + }, + { + "args": [ + { + "label": "index", + "type": { + "displayName": [ + "psp34enumerable_external", + "TokenByIndexInput1" + ], + "type": 5 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34Enumerable::token_by_index", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 33 + }, + "selector": "0xcd0340d0" + }, + { + "args": [ + { + "label": "owner", + "type": { + "displayName": [ + "psp34enumerable_external", + "OwnersTokenByIndexInput1" + ], + "type": 0 + } + }, + { + "label": "index", + "type": { + "displayName": [ + "psp34enumerable_external", + "OwnersTokenByIndexInput2" + ], + "type": 5 + } + } + ], + "default": false, + "docs": [], + "label": "PSP34Enumerable::owners_token_by_index", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "ink", + "MessageResult" + ], + "type": 33 + }, + "selector": "0x3bcfb511" + } + ] + }, + "storage": { + "root": { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0x252d8eda", + "ty": 0 + } + }, + "root_key": "0x252d8eda" + } + }, + "name": "token_owner" + }, + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0xcb1393da", + "ty": 3 + } + }, + "root_key": "0xcb1393da" + } + }, + "name": "operator_approvals" + }, + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0xf957bbd8", + "ty": 4 + } + }, + "root_key": "0xf957bbd8" + } + }, + "name": "owned_tokens_count" + }, + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0xe3d7d04e", + "ty": 5 + } + }, + "root_key": "0xe3d7d04e" + } + }, + "name": "total_supply" + } + ], + "name": "Data" + } + }, + "name": "psp34" + }, + { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0x2d2b79f3", + "ty": 0 + } + }, + "root_key": "0x2d2b79f3" + } + }, + "name": "token_owner" + }, + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0x5b0030d8", + "ty": 3 + } + }, + "root_key": "0x5b0030d8" + } + }, + "name": "operator_approvals" + }, + { + "layout": { + "root": { + "layout": { + "enum": { + "dispatchKey": "0x1bd7db1e", + "name": "Id", + "variants": { + "0": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x1bd7db1e", + "ty": 2 + } + }, + "name": "0" + } + ], + "name": "U8" + }, + "1": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x1bd7db1e", + "ty": 6 + } + }, + "name": "0" + } + ], + "name": "U16" + }, + "2": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x1bd7db1e", + "ty": 4 + } + }, + "name": "0" + } + ], + "name": "U32" + }, + "3": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x1bd7db1e", + "ty": 7 + } + }, + "name": "0" + } + ], + "name": "U64" + }, + "4": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x1bd7db1e", + "ty": 5 + } + }, + "name": "0" + } + ], + "name": "U128" + }, + "5": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x1bd7db1e", + "ty": 8 + } + }, + "name": "0" + } + ], + "name": "Bytes" + } + } + } + }, + "root_key": "0x1bd7db1e" + } + }, + "name": "balances" + } + ], + "name": "Data" + } + }, + "name": "enumerable" + }, + { + "layout": { + "root": { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "leaf": { + "key": "0x90333d95", + "ty": 4 + } + }, + "name": "begin" + }, + { + "layout": { + "leaf": { + "key": "0x90333d95", + "ty": 4 + } + }, + "name": "end" + }, + { + "layout": { + "leaf": { + "key": "0x90333d95", + "ty": 6 + } + }, + "name": "core" + }, + { + "layout": { + "struct": { + "fields": [ + { + "layout": { + "array": { + "layout": { + "leaf": { + "key": "0x90333d95", + "ty": 2 + } + }, + "len": 10, + "offset": "0x90333d95" + } + }, + "name": "0" + } + ], + "name": "CoreMask" + } + }, + "name": "mask" + } + ], + "name": "Region" + } + }, + "root_key": "0x90333d95" + } + }, + "name": "regions" + }, + { + "layout": { + "root": { + "layout": { + "leaf": { + "key": "0xb00e1336", + "ty": 4 + } + }, + "root_key": "0xb00e1336" + } + }, + "name": "metadata_versions" + } + ], + "name": "XcRegions" + } + }, + "root_key": "0x00000000" + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 1, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "AccountId" + ] + } + }, + { + "id": 1, + "type": { + "def": { + "array": { + "len": 32, + "type": 2 + } + } + } + }, + { + "id": 2, + "type": { + "def": { + "primitive": "u8" + } + } + }, + { + "id": 3, + "type": { + "def": { + "tuple": [] + } + } + }, + { + "id": 4, + "type": { + "def": { + "primitive": "u32" + } + } + }, + { + "id": 5, + "type": { + "def": { + "primitive": "u128" + } + } + }, + { + "id": 6, + "type": { + "def": { + "primitive": "u16" + } + } + }, + { + "id": 7, + "type": { + "def": { + "primitive": "u64" + } + } + }, + { + "id": 8, + "type": { + "def": { + "sequence": { + "type": 2 + } + } + } + }, + { + "id": 9, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 3 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 3 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 10, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 1, + "name": "CouldNotReadInput" + } + ] + } + }, + "path": [ + "ink_primitives", + "LangError" + ] + } + }, + { + "id": 11, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 12 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 12 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 12, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 3 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 13 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 3 + }, + { + "name": "E", + "type": 13 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 13, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 0, + "name": "InvalidRegionId" + }, + { + "index": 1, + "name": "CannotInitialize" + }, + { + "index": 2, + "name": "CannotRemove" + }, + { + "index": 3, + "name": "RegionNotFound" + }, + { + "index": 4, + "name": "MetadataNotFound" + }, + { + "index": 5, + "name": "InvalidMetadata" + }, + { + "index": 6, + "name": "VersionNotFound" + }, + { + "index": 7, + "name": "RuntimeError" + }, + { + "index": 8, + "name": "NotSupported" + }, + { + "fields": [ + { + "type": 14, + "typeName": "PSP34Error" + } + ], + "index": 9, + "name": "Psp34" + } + ] + } + }, + "path": [ + "xc_regions", + "types", + "XcRegionsError" + ] + } + }, + { + "id": 14, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 15, + "typeName": "String" + } + ], + "index": 0, + "name": "Custom" + }, + { + "index": 1, + "name": "SelfApprove" + }, + { + "index": 2, + "name": "NotApproved" + }, + { + "index": 3, + "name": "TokenExists" + }, + { + "index": 4, + "name": "TokenNotExists" + }, + { + "fields": [ + { + "type": 15, + "typeName": "String" + } + ], + "index": 5, + "name": "SafeTransferCheckFailed" + } + ] + } + }, + "path": [ + "openbrush_contracts", + "traits", + "errors", + "psp34", + "PSP34Error" + ] + } + }, + { + "id": 15, + "type": { + "def": { + "primitive": "str" + } + } + }, + { + "id": 16, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 17 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 17 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 17, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 18 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 13 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 18 + }, + { + "name": "E", + "type": 13 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 18, + "type": { + "def": { + "composite": { + "fields": [ + { + "name": "version", + "type": 4, + "typeName": "Version" + }, + { + "name": "region", + "type": 19, + "typeName": "Region" + } + ] + } + }, + "path": [ + "xc_regions", + "types", + "VersionedRegion" + ] + } + }, + { + "id": 19, + "type": { + "def": { + "composite": { + "fields": [ + { + "name": "begin", + "type": 4, + "typeName": "Timeslice" + }, + { + "name": "end", + "type": 4, + "typeName": "Timeslice" + }, + { + "name": "core", + "type": 6, + "typeName": "CoreIndex" + }, + { + "name": "mask", + "type": 20, + "typeName": "CoreMask" + } + ] + } + }, + "path": [ + "primitives", + "coretime", + "Region" + ] + } + }, + { + "id": 20, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 21, + "typeName": "[u8; 10]" + } + ] + } + }, + "path": [ + "primitives", + "coretime", + "CoreMask" + ] + } + }, + { + "id": 21, + "type": { + "def": { + "array": { + "len": 10, + "type": 2 + } + } + } + }, + { + "id": 22, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 4 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 4 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 23, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 24 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 24 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 24, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 2, + "typeName": "u8" + } + ], + "index": 0, + "name": "U8" + }, + { + "fields": [ + { + "type": 6, + "typeName": "u16" + } + ], + "index": 1, + "name": "U16" + }, + { + "fields": [ + { + "type": 4, + "typeName": "u32" + } + ], + "index": 2, + "name": "U32" + }, + { + "fields": [ + { + "type": 7, + "typeName": "u64" + } + ], + "index": 3, + "name": "U64" + }, + { + "fields": [ + { + "type": 5, + "typeName": "u128" + } + ], + "index": 4, + "name": "U128" + }, + { + "fields": [ + { + "type": 8, + "typeName": "Vec" + } + ], + "index": 5, + "name": "Bytes" + } + ] + } + }, + "path": [ + "openbrush_contracts", + "traits", + "types", + "Id" + ] + } + }, + { + "id": 25, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 0, + "name": "None" + }, + { + "fields": [ + { + "type": 24 + } + ], + "index": 1, + "name": "Some" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 24 + } + ], + "path": [ + "Option" + ] + } + }, + { + "id": 26, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 27 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 27 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 27, + "type": { + "def": { + "primitive": "bool" + } + } + }, + { + "id": 28, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 29 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 29 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 29, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 0, + "name": "None" + }, + { + "fields": [ + { + "type": 0 + } + ], + "index": 1, + "name": "Some" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 0 + } + ], + "path": [ + "Option" + ] + } + }, + { + "id": 30, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 31 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 31 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 31, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 3 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 14 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 3 + }, + { + "name": "E", + "type": 14 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 32, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 5 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 5 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 33, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 34 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 10 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 34 + }, + { + "name": "E", + "type": 10 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 34, + "type": { + "def": { + "variant": { + "variants": [ + { + "fields": [ + { + "type": 24 + } + ], + "index": 0, + "name": "Ok" + }, + { + "fields": [ + { + "type": 14 + } + ], + "index": 1, + "name": "Err" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 24 + }, + { + "name": "E", + "type": 14 + } + ], + "path": [ + "Result" + ] + } + }, + { + "id": 35, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 1, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_primitives", + "types", + "Hash" + ] + } + }, + { + "id": 36, + "type": { + "def": { + "composite": {} + }, + "path": [ + "extension", + "Extension" + ] + } + } + ], + "version": "4" +} \ No newline at end of file diff --git a/src/models/types.ts b/src/models/types.ts index 0e71e7ef..87727667 100644 --- a/src/models/types.ts +++ b/src/models/types.ts @@ -35,6 +35,7 @@ export type HumanRegionRecord = { end: string; owner: Address; paid?: string; + origin?: RegionOrigin; }; export enum RegionOrigin { diff --git a/src/utils/functions.ts b/src/utils/functions.ts index d6bb3453..41056704 100644 --- a/src/utils/functions.ts +++ b/src/utils/functions.ts @@ -9,7 +9,11 @@ import { // parse human readable number string export const parseHNString = (str: string): number => { - return parseInt(str.replace(',', '')); + return parseInt(parseHNStringToString(str)); +}; + +export const parseHNStringToString = (str: string): string => { + return str.replace(/,/g, ''); }; export const getBlockTimestamp = async (