Skip to content

Commit

Permalink
Merge pull request #1243 from Itheum/stg
Browse files Browse the repository at this point in the history
1.12.0 STG -> MAIN
  • Loading branch information
damienen authored Mar 5, 2024
2 parents e42c911 + f75fd81 commit 2bd4a4f
Show file tree
Hide file tree
Showing 38 changed files with 1,277 additions and 1,046 deletions.
550 changes: 290 additions & 260 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "data-dex",
"version": "1.11.4",
"version": "1.12.0",
"description": "The Itheum Data DEX enables you to trade your data using web3 tech",
"dependencies": {
"@chakra-ui/icons": "2.1.1",
"@chakra-ui/react": "2.8.2",
"@emotion/react": "11.11.3",
"@emotion/styled": "11.11.0",
"@hookform/resolvers": "3.3.4",
"@itheum/sdk-mx-data-nft": "2.6.2",
"@itheum/sdk-mx-data-nft": "2.7.0-beta.6",
"@itheum/sdk-mx-enterprise": "0.2.0",
"@multiversx/sdk-core": "12.18.0",
"@multiversx/sdk-dapp": "2.28.0",
Expand Down
4 changes: 2 additions & 2 deletions src/components/CustomPagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const CustomPagination: FC<PropsType> = ({ pageCount, pageIndex, gotoPage
};

return (
<Flex justifyContent="center" alignItems="center" gap={3}>
<Flex justifyContent="center" alignItems="center" gap={3} py={2}>
<Flex>
<Tooltip label="First Page">
<IconButton
Expand Down Expand Up @@ -62,7 +62,7 @@ export const CustomPagination: FC<PropsType> = ({ pageCount, pageIndex, gotoPage
</Tooltip>
</Flex>

<Flex alignItems="center" mx={2} fontSize="sm" w={{ base: "5rem", lg: "auto" }}>
<Flex alignItems="center" justify={"center"} mx={2} fontSize="sm" w={{ base: "5rem", lg: "auto" }}>
<Box flexShrink="0">
Page{" "}
<Box fontWeight="bold" as="span">
Expand Down
2 changes: 1 addition & 1 deletion src/components/Faucet/Faucet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const Faucet = ({ tileBoxW, tileBoxH }: any) => {
<Spacer />

<Button colorScheme="teal" size="lg" variant="outline" borderRadius="xl" onClick={handleOnChainFaucet} isDisabled={isMxFaucetDisabled}>
<Text color={colorMode === "dark" ? "white" : "black"}>Send me 20 {CHAIN_TOKEN_SYMBOL(chainID)}</Text>
<Text color={colorMode === "dark" ? "white" : "black"}>Send me 120 {CHAIN_TOKEN_SYMBOL(chainID)}</Text>
</Button>
</Stack>
</Stack>
Expand Down
167 changes: 119 additions & 48 deletions src/components/ListDataNFTModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,52 @@ import {
Divider,
useToast,
useColorMode,
Alert,
AlertIcon,
} from "@chakra-ui/react";
import { DataNft } from "@itheum/sdk-mx-data-nft/out";
import { Offer } from "@itheum/sdk-mx-data-nft/out";
import { useGetAccountInfo, useGetLoginInfo, useGetNetworkConfig, useGetPendingTransactions, useTrackTransactionStatus } from "@multiversx/sdk-dapp/hooks";
import axios from "axios";

import BigNumber from "bignumber.js";
import DataNFTLiveUptime from "components/UtilComps/DataNFTLiveUptime";
import { contractsForChain } from "libs/config";
import { getApi } from "libs/MultiversX/api";
import { sleep, printPrice, convertToLocalString, getTokenWantedRepresentation, backendApi, getApiDataMarshal } from "libs/utils";
import { DataNftMarketContract } from "libs/MultiversX/dataNftMarket";
import { sleep, printPrice, convertToLocalString, getTokenWantedRepresentation, backendApi, getApiDataMarshal, convertWeiToEsdt } from "libs/utils";
import { useMarketStore } from "store";
import { getOffersByIdAndNoncesFromBackendApi } from "../libs/MultiversX";
import { labels } from "../libs/language";

export type ListModalProps = {
isOpen: boolean;
onClose: () => void;
sellerFee: number;
nftData: any;
offer: any;
marketContract: any;
offer: Partial<Offer>;
marketContract: DataNftMarketContract;
amount: number;
setAmount: (amount: number) => void;
};

export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData, offer, marketContract, amount, setAmount }: ListModalProps) {
const { chainID } = useGetNetworkConfig();
const { address } = useGetAccountInfo();
const { hasPendingTransactions } = useGetPendingTransactions();
const marketRequirements = useMarketStore((state) => state.marketRequirements);
const toast = useToast();
const fullPrice = amount * offer.wanted_token_amount;
const fullPrice = amount * Number(offer.wantedTokenAmount);
const priceWithSellerFee = fullPrice - (fullPrice * sellerFee) / 10000;
const priceWithSellerFeeAndRoyalties = priceWithSellerFee - priceWithSellerFee * nftData.royalties;
const feePrice =
address !== nftData.creator
? printPrice(priceWithSellerFeeAndRoyalties, getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce))
: printPrice(priceWithSellerFee, getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce));
const fee = offer.wanted_token_amount;
? printPrice(priceWithSellerFeeAndRoyalties, getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0))
: printPrice(priceWithSellerFee, getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0));
const fee = offer.wantedTokenAmount;
const [readTermsChecked, setReadTermsChecked] = useState(false);
const [liveUptimeFAIL, setLiveUptimeFAIL] = useState<boolean>(true);
const [isLiveUptimeSuccessful, setIsLiveUptimeSuccessful] = useState<boolean>(false);
const [priceFromApi, setPriceFromApi] = useState<number>(-1);
const { tokenLogin, loginMethod } = useGetLoginInfo();

const backendUrl = backendApi(chainID);
Expand Down Expand Up @@ -92,15 +99,15 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,

async function addOfferBackend(
txHash = listTxHash,
offered_token_identifier = nftData.collection,
offered_token_nonce = nftData.nonce,
offered_token_amount = 1,
offeredTokenIdentifier = nftData.collection,
offeredTokenNonce = nftData.nonce,
offeredTokenAmount = 1,
title = nftData.title,
description = nftData.description,
wanted_token_identifier = offer.wanted_token_identifier,
wanted_token_nonce = offer.wanted_token_nonce,
wanted_token_amount = Number(
(Number(offer.wanted_token_amount) + (Number(offer.wanted_token_amount) * (marketRequirements.buyerTaxPercentage ?? 200)) / 10000) * Number(10 ** 18)
wantedTokenIdentifier = offer.wantedTokenIdentifier,
wantedTokenNonce = offer.wantedTokenNonce,
wantedTokenAmount = Number(
(Number(offer.wantedTokenAmount) + (Number(offer.wantedTokenAmount) * (marketRequirements.buyerTaxPercentage ?? 200)) / 10000) * Number(10 ** 18)
).toString(),
quantity = amount * 1,
owner = address
Expand Down Expand Up @@ -135,17 +142,17 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
};

const requestBody = {
index: index,
offered_token_identifier: offered_token_identifier,
offered_token_nonce: offered_token_nonce,
offered_token_amount: offered_token_amount,
title: title,
description: description,
wanted_token_identifier: wanted_token_identifier,
wanted_token_nonce: wanted_token_nonce,
wanted_token_amount: wanted_token_amount,
quantity: quantity,
owner: owner,
index,
offeredTokenIdentifier,
offeredTokenNonce,
offeredTokenAmount,
title,
description,
wantedTokenIdentifier,
wantedTokenNonce,
wantedTokenAmount,
quantity,
owner,
};

const response = await fetch(`${backendUrl}/addOffer`, {
Expand Down Expand Up @@ -196,21 +203,21 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
}
}

const { sessionId } = await marketContract.addToMarket(nftData.collection, nftData.nonce, amount, offer.wanted_token_amount, address);
const { sessionId } = await marketContract.addToMarket(nftData.collection, nftData.nonce, amount, offer.wantedTokenAmount ?? 0, address);
if (isWebWallet) {
const price = Number(offer.wanted_token_amount) + (Number(offer.wanted_token_amount) * (marketRequirements.buyerTaxPercentage ?? 200)) / 10000;
const price = Number(offer.wantedTokenAmount) + (Number(offer.wantedTokenAmount) * (marketRequirements.buyerTaxPercentage ?? 200)) / 10000;
sessionStorage.setItem(
"web-wallet-tx",
JSON.stringify({
type: "add-offer-tx",
offered_token_identifier: nftData.collection,
offered_token_nonce: nftData.nonce,
offered_token_amount: 1,
offeredTokenIdentifier: nftData.collection,
offeredTokenNonce: nftData.nonce,
offeredTokenAmount: 1,
title: nftData.title,
description: nftData.description,
wanted_token_identifier: offer.wanted_token_identifier,
wanted_token_nonce: offer.wanted_token_nonce,
wanted_token_amount: Number(price * Number(10 ** 18)).toString(),
wantedTokenIdentifier: offer.wantedTokenIdentifier,
wantedTokenNonce: offer.wantedTokenNonce,
wantedTokenAmount: Number(price * Number(10 ** 18)).toString(),
quantity: amount * 1,
owner: address,
})
Expand All @@ -224,6 +231,49 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
onClose();
};

async function getTokenHistory(tokenIdArg: string) {
try {
const inputString = tokenIdArg;

// Extracting identifier
const identifier = inputString?.split("-").slice(0, 2).join("-");

// Extracting nonce
const nonceHex = inputString?.split("-")[2];
const nonceDec = parseInt(nonceHex, 16);

const _offers = await getOffersByIdAndNoncesFromBackendApi(chainID, identifier, [nonceDec]);
const price = Math.min(..._offers.map((offerArg: any) => offerArg.wantedTokenAmount));
if (price !== Infinity) {
setPriceFromApi(price);
} else {
setPriceFromApi(-1);
}
} catch (err) {
if ((err as any).response.status === 404) {
toast({
title: labels.ERR_MARKET_OFFER_NOT_FOUND,
description: (err as Error).message,
status: "error",
duration: 9000,
isClosable: true,
});
} else {
toast({
title: labels.ERR_API_ISSUE_DATA_NFT_OFFERS,
description: (err as Error).message,
status: "error",
duration: 9000,
isClosable: true,
});
}
}
}

useEffect(() => {
getTokenHistory(nftData.id);
}, [hasPendingTransactions]);

return (
<>
<Modal isOpen={isOpen} onClose={onClose} closeOnEsc={false} closeOnOverlayClick={false}>
Expand Down Expand Up @@ -251,6 +301,27 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
</Box>
</HStack>

{convertWeiToEsdt(priceFromApi).toNumber() -
(Number(offer.wantedTokenAmount) + new BigNumber(offer.wantedTokenAmount ?? 0).multipliedBy(sellerFee).div(10000).toNumber()) >
0 && (
<Alert status="warning" rounded="lg" mt={3} fontSize="md">
<AlertIcon />
You want to list for{" "}
{offer && Number(offer.wantedTokenAmount) + new BigNumber(offer.wantedTokenAmount ?? 0).multipliedBy(sellerFee).div(10000).toNumber()} ITHEUM
which is lower by&nbsp;
{(
((convertWeiToEsdt(priceFromApi).toNumber() -
(Number(offer.wantedTokenAmount) +
BigNumber(offer.wantedTokenAmount ?? 0)
.multipliedBy(sellerFee)
.div(10000)
.toNumber())) *
100) /
convertWeiToEsdt(priceFromApi).toNumber()
).toFixed(2)}
% than the current lowest price ({convertWeiToEsdt(priceFromApi).toNumber()} ITHEUM).
</Alert>
)}
<Box>
<Flex fontSize="md" mt="2">
<Box w="140px">How many</Box>
Expand All @@ -263,8 +334,8 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
<>
{": "}
{printPrice(
new BigNumber(offer.wanted_token_amount).toNumber(),
getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce)
new BigNumber(offer.wantedTokenAmount ?? 0).toNumber(),
getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0)
)}
</>
) : (
Expand All @@ -277,10 +348,10 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
<Box w="140px">Seller Tax (per NFT)</Box>
<Box>
:{" "}
{`${sellerFee / 100}% (${new BigNumber(offer.wanted_token_amount)
{`${sellerFee / 100}% (${new BigNumber(offer.wantedTokenAmount ?? 0)
.multipliedBy(sellerFee)
.div(10000)
.toNumber()} ${getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce)})`}
.toNumber()} ${getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0)})`}
</Box>
</Flex>

Expand All @@ -290,8 +361,8 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
<Box>
:{" "}
{`${convertToLocalString(nftData.royalties * 100)}% (${convertToLocalString(
new BigNumber(offer.wanted_token_amount).multipliedBy((1 - sellerFee / 10000) * nftData.royalties)
)} ${getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce)})`}
new BigNumber(offer.wantedTokenAmount ?? 0).multipliedBy((1 - sellerFee / 10000) * nftData.royalties)
)} ${getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0)})`}
</Box>
</Flex>
)}
Expand All @@ -302,7 +373,7 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
{": "}
{
<>
{feePrice} {fee && itheumPrice ? `(~${convertToLocalString(fee * itheumPrice * amount, 2)} USD)` : ""}
{feePrice} {fee && itheumPrice ? `(~${convertToLocalString(Number(fee) * itheumPrice * amount, 2)} USD)` : ""}
</>
}
</Box>
Expand All @@ -312,20 +383,20 @@ export default function ListDataNFTModal({ isOpen, onClose, sellerFee, nftData,
<Box>
{
<>
{new BigNumber(offer.wanted_token_amount).comparedTo(0) <= 0 ? (
{new BigNumber(offer.wantedTokenAmount ?? 0).comparedTo(0) <= 0 ? (
""
) : (
<>
{" " + convertToLocalString(new BigNumber(offer.wanted_token_amount).multipliedBy(amount)) + " "}
{getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce)}
{" " + convertToLocalString(new BigNumber(offer.wantedTokenAmount ?? 0).multipliedBy(amount)) + " "}
{getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0)}
{" - "}
{convertToLocalString(new BigNumber(offer.wanted_token_amount).multipliedBy(amount).multipliedBy(sellerFee).div(10000))}
{" " + getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce)}
{convertToLocalString(new BigNumber(offer.wantedTokenAmount ?? 0).multipliedBy(amount).multipliedBy(sellerFee).div(10000))}
{" " + getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0)}
{address != nftData.creator && (
<>
{" - "}
{convertToLocalString(new BigNumber(offer.wanted_token_amount).multipliedBy((1 - sellerFee / 10000) * nftData.royalties))}
{" " + getTokenWantedRepresentation(offer.wanted_token_identifier, offer.wanted_token_nonce)}
{convertToLocalString(new BigNumber(offer.wantedTokenAmount ?? 0).multipliedBy((1 - sellerFee / 10000) * nftData.royalties))}
{" " + getTokenWantedRepresentation(offer.wantedTokenIdentifier ?? "", offer.wantedTokenNonce ?? 0)}
</>
)}
</>
Expand Down
48 changes: 48 additions & 0 deletions src/components/Liveliness/LivelinessScore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useEffect, useState } from "react";
import { Box, Flex, Progress, Text } from "@chakra-ui/react";
import { settingLivelinessScore } from "../../libs/utils";

type LivelinessScoreProp = {
tokenIdentifier?: string;
unboundTimestamp?: number;
lockPeriod?: number;
};

export const LivelinessScore: React.FC<LivelinessScoreProp> = (props) => {
const { tokenIdentifier, unboundTimestamp, lockPeriod } = props;
const [livelinessScore, setLivelinessScore] = useState<number>(-1);

useEffect(() => {
(async () => {
const livelinessScore = await settingLivelinessScore(tokenIdentifier, unboundTimestamp, lockPeriod);
setLivelinessScore(livelinessScore ?? -1);
})();
}, [tokenIdentifier, unboundTimestamp]);
return (
<>
{livelinessScore === -1 ? (
<Text fontSize="lg" fontWeight="light" display="flex" justifyContent="flex-start" pt={3} pb={4} textColor="indianred">
No liveliness score available.
</Text>
) : livelinessScore !== 0 ? (
<Flex flexDirection="column">
<Text fontSize="lg" fontWeight="light" display="flex" justifyContent="flex-start" pb="14px">
Liveliness Score: {livelinessScore}
</Text>
<Box border="1px solid" borderColor="teal.200" borderRadius="sm">
<Progress hasStripe value={livelinessScore} rounded="xs" colorScheme="teal" />
</Box>
</Flex>
) : (
<Flex flexDirection="column">
<Text fontSize="lg" fontWeight="light" display="flex" justifyContent="flex-start" pt={2} pb={1} textColor="indianred">
Liveliness score expired.
</Text>
<Box border="1px solid" borderColor="indianred" borderRadius="sm">
<Progress hasStripe value={livelinessScore} rounded="xs" colorScheme="red" />
</Box>
</Flex>
)}
</>
);
};
Loading

0 comments on commit 2bd4a4f

Please sign in to comment.