diff --git a/.env b/.env index 698754ad..81e4bf8d 100644 --- a/.env +++ b/.env @@ -26,7 +26,7 @@ REACT_APP_AUTH0_CLIENT_ID= REACT_APP_GA_MEASUREMENT_ID= REACT_APP_BACKEND_URL_PRODUCTION="https://assist-prod.pasarprotocol.io" -REACT_APP_BACKEND_URL_TEST="https://assist-test.pasarprotocol.io" +REACT_APP_BACKEND_URL_TEST="https://token-assist.pasarprotocol.io" REACT_APP_IPFS_URL_PRODUCTION="https://ipfs.pasarprotocol.io" REACT_APP_IPFS_URL_TEST="https://ipfs-test.pasarprotocol.io" diff --git a/build_token.zip b/build_token.zip new file mode 100644 index 00000000..761cbb95 Binary files /dev/null and b/build_token.zip differ diff --git a/src/abi/tokenMiningABI.js b/src/abi/tokenMiningABI.js index 05ec7e12..d929f694 100644 --- a/src/abi/tokenMiningABI.js +++ b/src/abi/tokenMiningABI.js @@ -4,6 +4,25 @@ module.exports.TOKEN_MINING_ABI = [ "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "indexed": true, + "internalType": "bool", + "name": "state", + "type": "bool" + } + ], + "name": "MarketSet", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -41,7 +60,7 @@ module.exports.TOKEN_MINING_ABI = [ "inputs": [ { "indexed": true, - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "rewardType", "type": "uint8" }, @@ -66,7 +85,7 @@ module.exports.TOKEN_MINING_ABI = [ "inputs": [ { "indexed": true, - "internalType": "enum PasarMiningBase.PoolTypes", + "internalType": "enum IPasarMiningDataAndEvents.PoolTypes", "name": "pool", "type": "uint8" }, @@ -169,6 +188,19 @@ module.exports.TOKEN_MINING_ABI = [ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "VESTING_NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -177,7 +209,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "address" }, { - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "", "type": "uint8" } @@ -231,7 +263,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "uint256" } ], - "internalType": "struct PasarMiningBase.AccRewardInfo", + "internalType": "struct IPasarMiningDataAndEvents.AccRewardInfo", "name": "all", "type": "tuple" }, @@ -253,7 +285,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "uint256" } ], - "internalType": "struct PasarMiningBase.AccRewardInfo", + "internalType": "struct IPasarMiningDataAndEvents.AccRewardInfo", "name": "buyer", "type": "tuple" }, @@ -275,7 +307,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "uint256" } ], - "internalType": "struct PasarMiningBase.AccRewardInfo", + "internalType": "struct IPasarMiningDataAndEvents.AccRewardInfo", "name": "seller", "type": "tuple" }, @@ -297,7 +329,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "uint256" } ], - "internalType": "struct PasarMiningBase.AccRewardInfo", + "internalType": "struct IPasarMiningDataAndEvents.AccRewardInfo", "name": "creator", "type": "tuple" } @@ -308,7 +340,7 @@ module.exports.TOKEN_MINING_ABI = [ { "inputs": [ { - "internalType": "enum PasarMiningBase.PoolTypes", + "internalType": "enum IPasarMiningDataAndEvents.PoolTypes", "name": "", "type": "uint8" }, @@ -332,7 +364,7 @@ module.exports.TOKEN_MINING_ABI = [ { "inputs": [ { - "internalType": "enum PasarMiningBase.PoolTypes", + "internalType": "enum IPasarMiningDataAndEvents.PoolTypes", "name": "", "type": "uint8" }, @@ -559,7 +591,7 @@ module.exports.TOKEN_MINING_ABI = [ { "inputs": [ { - "internalType": "enum PasarMiningBase.PoolTypes", + "internalType": "enum IPasarMiningDataAndEvents.PoolTypes", "name": "", "type": "uint8" } @@ -586,7 +618,7 @@ module.exports.TOKEN_MINING_ABI = [ "name": "names", "outputs": [ { - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "", "type": "uint8" } @@ -648,12 +680,12 @@ module.exports.TOKEN_MINING_ABI = [ "type": "address" }, { - "internalType": "enum PasarMiningBase.PoolTypes", + "internalType": "enum IPasarMiningDataAndEvents.PoolTypes", "name": "", "type": "uint8" }, { - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "", "type": "uint8" } @@ -721,13 +753,54 @@ module.exports.TOKEN_MINING_ABI = [ "outputs": [ { "internalType": "uint256", - "name": "", + "name": "count", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "indexes", + "type": "uint256[]" + } + ], + "name": "rewardRecords", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", + "name": "rewardType", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "internalType": "struct IPasarMiningDataAndEvents.RewardInfo[]", + "name": "records", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -749,7 +822,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "uint256" }, { - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "rewardType", "type": "uint8" }, @@ -816,7 +889,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "address" }, { - "internalType": "enum PasarMiningBase.PoolTypes", + "internalType": "enum IPasarMiningDataAndEvents.PoolTypes", "name": "", "type": "uint8" }, @@ -826,7 +899,7 @@ module.exports.TOKEN_MINING_ABI = [ "type": "uint256" }, { - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "", "type": "uint8" } @@ -891,7 +964,7 @@ module.exports.TOKEN_MINING_ABI = [ { "inputs": [ { - "internalType": "enum PasarMiningBase.RewardTypes", + "internalType": "enum IPasarMiningDataAndEvents.RewardTypes", "name": "rewardType", "type": "uint8" } diff --git a/src/abi/tokenStakingABI.js b/src/abi/tokenStakingABI.js index 71a6ef82..181705d2 100644 --- a/src/abi/tokenStakingABI.js +++ b/src/abi/tokenStakingABI.js @@ -131,6 +131,19 @@ module.exports.TOKEN_STAKING_ABI = [ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "VESTING_NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "config", @@ -406,6 +419,25 @@ module.exports.TOKEN_STAKING_ABI = [ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "totalRewardAtTime", + "outputs": [ + { + "internalType": "uint256", + "name": "totalReward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/src/abi/tokenVestingABI.js b/src/abi/tokenVestingABI.js index 491b7e51..738fe26d 100644 --- a/src/abi/tokenVestingABI.js +++ b/src/abi/tokenVestingABI.js @@ -572,6 +572,54 @@ module.exports.TOKEN_VESTING_ABI = [ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "enum IPasarVesting.Allocations", + "name": "alloc", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "releaseAtTimeByAlloc", + "outputs": [ + { + "internalType": "uint256", + "name": "total", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "releaseAtTimeByName", + "outputs": [ + { + "internalType": "uint256", + "name": "total", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/src/components/signin-dlg/SignInDialog.js b/src/components/signin-dlg/SignInDialog.js index ebc25ce6..380f6ddd 100644 --- a/src/components/signin-dlg/SignInDialog.js +++ b/src/components/signin-dlg/SignInDialog.js @@ -511,6 +511,7 @@ export default function SignInDialog() { sessionStorage.removeItem('PASAR_TOKEN'); sessionStorage.removeItem('PASAR_DID'); sessionStorage.removeItem('KYCedProof'); + sessionStorage.removeItem('REWARD_USER'); try { setSigninEssentialSuccess(false); setActivatingConnector(null); diff --git a/src/config.js b/src/config.js index 153dde49..29de09bf 100644 --- a/src/config.js +++ b/src/config.js @@ -66,9 +66,9 @@ const addressForProduction = { const addressForTest = { MAIN_CONTRACT: { ESC: { - sticker: "0x32496388d7c0CDdbF4e12BDc84D39B9E42ee4CB0", - market: "0x19088c509C390F996802B90bdc4bFe6dc3F5AAA7", - register: "0x2b304ffC302b402785294629674A8C2b64cEF897" + sticker: "0x3748c352cF8B3e8c6CF6800F315072a2C1fD3F82", + market: "0x6a02E1942A6201C47BBd3246fF2b044a2536aB43", + register: "0x26CB562A77eB0610D3d1e6Fc5e856B5bcc93Fb8b" }, ETH: { sticker: "0xed1978c53731997f4DAfBA47C9b07957Ef6F3961", @@ -92,10 +92,10 @@ const addressForTest = { bunnyContract: "0x75740FC7058DA148752ef8a9AdFb73966DEb42a8", bnbBusdContract: "0x9f1d0Ed4E041C503BD487E5dc9FC935Ab57F9a57", elaOnEthContract: "0x8c947E0fA67e91370587076A4108Df17840e9982", - pasarERC20Contract: '0xa7B1a72266ad3a54Ac00071f05453feEeB5680dB', - pasarVestingContract: '0xD883303d400427C298d53e99a3faa7Cb1E9A8727', - pasarStakingContract: '0x048c96C7dF2d789A515c0c18c9345481c12e664E', - pasarMiningContract: '0x8158FF69C60Eb893e32869180D980853160b8d68', + pasarERC20Contract: '0x2E54635bee5F1451A7f138797d96f22e3Cba5453', + pasarVestingContract: '0xB2d03B5c9Dc4429EDde239183AaF39D74e29a536', + pasarStakingContract: '0xc7a57f6203f9F9b82cafb966c8940cA0527713A2', + pasarMiningContract: '0xB27CC87EaF372F78E3Ca4da38b013E154e7247e0', blockchain: 'Testnet (ESC)' } diff --git a/src/pages/rewards/Rewards.js b/src/pages/rewards/Rewards.js index 46caced8..e44ec188 100644 --- a/src/pages/rewards/Rewards.js +++ b/src/pages/rewards/Rewards.js @@ -3,23 +3,51 @@ import PropTypes from 'prop-types'; import * as math from 'mathjs'; import arrowIosDownwardFill from '@iconify/icons-eva/arrow-ios-downward-fill'; import { - Container, Box, Stack, Grid, Typography, Paper, Divider, Link, Tooltip, Button, Tabs, Tab, Accordion, AccordionSummary, AccordionDetails, - ToggleButtonGroup, ToggleButton, FormGroup, TextField, Slider + Container, + Box, + Stack, + Grid, + Typography, + Paper, + Divider, + Link, + Tooltip, + Button, + Tabs, + Tab, + Accordion, + AccordionSummary, + AccordionDetails, + ToggleButtonGroup, + ToggleButton, + FormGroup, + TextField, + Slider } from '@mui/material'; import { styled } from '@mui/material/styles'; import { Icon } from '@iconify/react'; -import Web3 from 'web3'; import { useSnackbar } from 'notistack'; // components import Page from '../../components/Page'; import TabPanel from '../../components/TabPanel'; import StyledButton from '../../components/signin-dlg/StyledButton'; -import StatisticPanel from '../../components/rewards/StatisticPanel' +import StatisticPanel from '../../components/rewards/StatisticPanel'; import { MHidden } from '../../components/@material-extend'; -import { addTokenToMM, callTokenContractMethod, fetchFrom, getERC20TokenPrice, isInAppBrowser, removeLeadingZero } from '../../utils/common' -import { essentialsConnector } from '../../components/signin-dlg/EssentialConnectivity'; -import { blankAddress, pasarERC20Contract as PASAR_TOKEN_ADDRESS } from '../../config'; +import { + addTokenToMM, + callTokenContractMethod, + fetchFrom, + getERC20TokenPrice, + getWalletAccounts, + removeLeadingZero +} from '../../utils/common'; +import useSignin from '../../hooks/useSignin'; +import { + blankAddress, + pasarERC20Contract as PASAR_TOKEN_ADDRESS, + pasarStakingContract as STAKING_CONTRACT_ADDRESS +} from '../../config'; // ---------------------------------------------------------------------- const RootStyle = styled(Page)(({ theme }) => ({ @@ -35,8 +63,8 @@ const RootStyle = styled(Page)(({ theme }) => ({ const SectionSx = { border: '1px solid', borderColor: 'action.disabledBackground', - boxShadow: (theme) => theme.customShadows.z1, -} + boxShadow: (theme) => theme.customShadows.z1 +}; const StackStyle = styled(Stack)(({ theme }) => ({ flexDirection: 'row', [theme.breakpoints.down('sm')]: { @@ -49,16 +77,16 @@ const AccordionStyle = styled(Accordion)(({ theme }) => ({ boxShadow: theme.customShadows.z1, [theme.breakpoints.up('xl')]: { paddingLeft: theme.spacing(2), - paddingRight: theme.spacing(2), + paddingRight: theme.spacing(2) // paddingTop: theme.spacing(1), // paddingBottom: theme.spacing(1) }, [theme.breakpoints.up('sm')]: { paddingLeft: theme.spacing(4), - paddingRight: theme.spacing(4), + paddingRight: theme.spacing(4) // paddingTop: theme.spacing(2), // paddingBottom: theme.spacing(2) - }, + } })); const EarnedValueStyle = styled(Typography)(({ theme }) => ({ backgroundImage: 'linear-gradient(90deg, #FF5082, #a951f4)', @@ -69,19 +97,19 @@ const EarnedValueStyle = styled(Typography)(({ theme }) => ({ MozBackgroundClip: 'text', MozTextFillColor: 'transparent', display: 'inline' -})) +})); const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({ '& .MuiToggleButtonGroup-grouped': { border: 0, '&.Mui-disabled': { - border: 0, + border: 0 }, '&:not(:first-of-type)': { - borderRadius: theme.shape.borderRadius / 2, + borderRadius: theme.shape.borderRadius / 2 }, '&:first-of-type': { - borderRadius: theme.shape.borderRadius / 2, - }, + borderRadius: theme.shape.borderRadius / 2 + } }, '& .MuiToggleButton-root': { margin: theme.spacing(1), @@ -104,25 +132,29 @@ const StyledTextField = styled(TextField)(({ theme }) => ({ '& fieldset': { borderTopRightRadius: 0, borderBottomRightRadius: 0 - }, + } })); const StyledSlider = styled(Slider)(({ theme }) => ({ // color: 'blue', marginTop: 8, - "& .MuiSlider-thumb": { - backgroundColor: '#5159ff', + '& .MuiSlider-thumb': { + backgroundColor: '#5159ff' }, - "& .MuiSlider-track": { + '& .MuiSlider-track': { background: `linear-gradient(90deg, #DB59A0 0%, #6A70FA 100%);`, height: 10, border: 0 }, - "& .MuiSlider-rail": { + '& .MuiSlider-rail': { color: 'grey', height: 10 } })); -const PinkLabel = ({ text }) => ({text}) +const PinkLabel = ({ text }) => ( + + {text} + +); const PaperStyle = (props) => ( ( > {props.children} -) +); const ClaimCard = ({ item, onClick }) => ( - {item.title} + + {item.title} + {item.action} item, earn{' '} - + PASAR {' '} @@ -148,102 +182,181 @@ const ClaimCard = ({ item, onClick }) => ( - PASAR{' '}earned + + PASAR + {' '} + earned {item.amount} - {`≈ USD ${item.price}`} - - Claim - + {`≈ USD ${item.price}`} + + Claim + -) +); ClaimCard.propTypes = { item: PropTypes.object, onClick: PropTypes.func -} +}; const ExternalLink = (props) => { - const { linkURL, title } = props - return - {title} - -} + const { linkURL, title } = props; + return ( + + {title} + + ); +}; -const AmountProgressType = ['25%', '50%', '75%', 'Max'] +const AmountProgressType = ['25%', '50%', '75%', 'Max']; export default function Rewards() { const { enqueueSnackbar } = useSnackbar(); + const { setOpenSigninEssentialDlg } = useSignin(); const [tabValue, setTabValue] = React.useState(0); - const [operAmount, setOperAmount] = React.useState(0); const [stakingType, setStakingType] = React.useState('Stake'); + const [operAmount, setOperAmount] = React.useState(0); const [amountProgress, setAmountProgress] = React.useState(0); + const [stakingTotalAmount, setStakingTotalAmount] = React.useState(0); + const [stakingSettleAmount, setStakingSettleAmount] = React.useState(0); + const cachedPool = JSON.parse(sessionStorage.getItem('REWARD_POOL')); + const cachedUser = JSON.parse(sessionStorage.getItem('REWARD_USER')); const [PASARToUSD, setPASARToUSD] = React.useState(0.01); - const [miningReward, setMiningReward] = React.useState({ - all: { total: 0, withdrawable: 0, withdrawn: 0 }, - buyer: { total: 0, withdrawable: 0, withdrawn: 0 }, - seller: { total: 0, withdrawable: 0, withdrawn: 0 }, - creator: { total: 0, withdrawable: 0, withdrawn: 0 } - }); - const [claimItems, setClaimItems] = React.useState([ - { title: "BUYERS", action: "Buy", name: 'buyer', amount: 0, price: 0 }, - { title: "SELLERS", action: "Sell", name: 'seller', amount: 0, price: 0 }, - { title: "CREATORS", action: "Create", name: 'creator', amount: 0, price: 0 } - ]); - const [listedItemCnt, setListedItemCnt] = React.useState({ native: 0, pasar: 0, eco: 0, other: 0 }); - const [miningPoolRatio, setMiningPoolRatio] = React.useState({ native: 0, pasar: 0, eco: 0, other: 0 }); + const [miningReward, setMiningReward] = React.useState( + cachedUser?.mining + ? cachedUser.mining + : { + all: { total: 0, withdrawable: 0, withdrawn: 0 }, + buyer: { total: 0, withdrawable: 0, withdrawn: 0 }, + seller: { total: 0, withdrawable: 0, withdrawn: 0 }, + creator: { total: 0, withdrawable: 0, withdrawn: 0 } + } + ); + const [claimItems, setClaimItems] = React.useState( + cachedUser?.claim + ? cachedUser.claim + : [ + { title: 'BUYERS', action: 'Buy', name: 'buyer', amount: 0, price: 0 }, + { title: 'SELLERS', action: 'Sell', name: 'seller', amount: 0, price: 0 }, + { title: 'CREATORS', action: 'Create', name: 'creator', amount: 0, price: 0 } + ] + ); + const [listedItemCnt, setListedItemCnt] = React.useState( + cachedPool?.item ? cachedPool.item : { native: 0, pasar: 0, eco: 0, other: 0 } + ); + const [miningPoolRatio, setMiningPoolRatio] = React.useState( + cachedPool?.pool ? cachedPool.pool : { native: 0, pasar: 0, eco: 0, other: 0 } + ); + const [userRewarded, setUserRewarded] = React.useState( + cachedPool?.user ? cachedPool.user : { elaCount: 0, pasarCount: 0, ecoCount: 0, otherCount: 0 } + ); + const [nextDistribution, setNextDistribution] = React.useState( + cachedPool?.next ? cachedPool.next : { native: 0, pasar: 0, eco: 0, other: 0 } + ); const [pasarBalance, setPasarBalance] = React.useState(0); - const [stakingAPR, setStakingAPR] = React.useState(48.48); - const [stakingState, setStakingState] = React.useState({ currentStaked: 0, rewardWithdrawable: 0, rewardWithdrawn: 0, rewardFeePaid: 0, feeEndTime: 0 }); - const walletConnectWeb3 = new Web3(isInAppBrowser() ? window.elastos.getWeb3Provider() : essentialsConnector.getWalletConnectProvider()); - - const handleSwitchTab = (event, newValue) => { - setTabValue(newValue); - }; + const [stakingAPR, setStakingAPR] = React.useState(cachedUser?.apr ? cachedUser.apr : 0.0); + const [stakingState, setStakingState] = React.useState( + cachedUser?.staking + ? cachedUser.staking + : { + currentStaked: 0, + rewardWithdrawable: 0, + rewardWithdrawn: 0, + rewardFeePaid: 0, + feeEndTime: 0 + } + ); + const [reloadPage, setReloadPage] = React.useState(false); - const handleStakingType = (event, type) => { + const handleStakingType = (_, type) => { if (type) setStakingType(type); + setAmountProgress(0); + setOperAmount(0); }; const handleProgressBtn = (event) => { - const progressType = event.target.value - setAmountProgress(progressType * 25) - setOperAmount(math.round(pasarBalance * progressType / 4, 4)) - } + const progressType = event.target.value; + setAmountProgress(progressType * 25); + const offsetAmount = math.round((stakingTotalAmount * progressType) / 4, 4); + setOperAmount(offsetAmount); + if (progressType === 4) { + if (stakingType === 'Stake') setStakingSettleAmount(pasarBalance); + else if (stakingType === 'Unstake') setStakingSettleAmount(0); + } else { + let totalStaked = BigInt(stakingState?.currentStaked ?? 0); + if (stakingType === 'Stake') totalStaked = BigInt(totalStaked) + BigInt(offsetAmount); + else if (stakingType === 'Unstake') totalStaked = BigInt(totalStaked) - BigInt(offsetAmount); + setStakingSettleAmount(totalStaked); + } + }; const handleChangeAmount = (event) => { - let amountValue = event.target.value - amountValue = removeLeadingZero(amountValue) - if (amountValue < 0) - return - if (amountValue * 1 > pasarBalance) - return; - setOperAmount(math.round(amountValue * 1, 4).toString()) + let amountValue = event.target.value; + amountValue = removeLeadingZero(amountValue); + if (amountValue < 0) return; + if (amountValue * 1 > stakingTotalAmount) return; + const offsetAmount = math.round(amountValue * 1, 4).toString(); + setOperAmount(offsetAmount); + let totalStaked = BigInt(stakingState?.currentStaked ?? 0); + if (stakingType === 'Stake') totalStaked = BigInt(totalStaked) + BigInt(offsetAmount); + else if (stakingType === 'Unstake') totalStaked = BigInt(totalStaked) - BigInt(offsetAmount); + setStakingSettleAmount(totalStaked); }; const handleChangeSlider = (event, newValue) => { setAmountProgress(newValue); - setOperAmount(math.round(pasarBalance * newValue / 100, 4)) + const offsetAmount = math.round((stakingTotalAmount * newValue) / 100, 4); + setOperAmount(offsetAmount); + if (newValue === 100) { + if (stakingType === 'Stake') setStakingSettleAmount(pasarBalance); + else if (stakingType === 'Unstake') setStakingSettleAmount(0); + } else { + let totalStaked = BigInt(stakingState?.currentStaked ?? 0); + if (stakingType === 'Stake') totalStaked = BigInt(totalStaked) + BigInt(offsetAmount); + else if (stakingType === 'Unstake') totalStaked = BigInt(totalStaked) - BigInt(offsetAmount); + setStakingSettleAmount(totalStaked); + } }; React.useEffect(() => { - const tempProgress = math.round(pasarBalance === 0 ? 0 : operAmount * 100 / pasarBalance, 1) - setAmountProgress(tempProgress) + const tempProgress = math.round( + stakingTotalAmount.toString() === '0' ? 0 : (operAmount * 100) / stakingTotalAmount, + 1 + ); + setAmountProgress(tempProgress); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [operAmount]); + }, [operAmount, stakingType]); + + React.useEffect(() => { + setStakingTotalAmount(stakingType === 'Stake' ? pasarBalance : stakingState?.currentStaked ?? 0); + }, [pasarBalance, stakingType, stakingState]); const fetchListedItemCount = async (quoteToken) => { - const response = await fetchFrom(`api/v2/sticker/getDetailedCollectibles?collectionType=&tokenType=${quoteToken}&status=All&itemType=All&adult=false&minPrice=&maxPrice=&order=0&marketPlace=1&keyword=&pageNum=1&pageSize=1`); - const json = await response.json(); - return json && json.data && json.data.total ? json.data.total : 0; + try { + const response = await fetchFrom( + `api/v2/sticker/getDetailedCollectibles?collectionType=&tokenType=${quoteToken}&status=All&itemType=All&adult=false&minPrice=&maxPrice=&order=0&marketPlace=1&keyword=&pageNum=1&pageSize=1` + ); + const json = await response.json(); + return json && json.data && json.data.total ? json.data.total : 0; + } catch (err) { + console.error(err); + return 0; + } + }; + + const fetchRewardedUserCount = async () => { + try { + const response = await fetchFrom(`api/v2/sticker/rewardusers`); + const json = await response.json(); + return json && json.data ? json.data : { ecoCount: 0, elaCount: 0, otherCount: 0, pasarCount: 0 }; + } catch (err) { + console.error(err); + return { ecoCount: 0, elaCount: 0, otherCount: 0, pasarCount: 0 }; + } }; React.useEffect(() => { @@ -251,50 +364,371 @@ export default function Rewards() { const resPasarPrice = await getERC20TokenPrice(PASAR_TOKEN_ADDRESS); if (!resPasarPrice || !resPasarPrice.token) setPASARToUSD(0); else setPASARToUSD(resPasarPrice.token.derivedELA * resPasarPrice.bundle.elaPrice); - const accounts = await walletConnectWeb3.eth.getAccounts(); - if (!accounts.length) return; - const balance = await callTokenContractMethod(walletConnectWeb3, { contractType: 'token', callType: 'call', methodName: 'balanceOf', account: accounts[0] }); - setPasarBalance(balance); - if (tabValue === 0) { // rewards page - const accountRewards = await callTokenContractMethod(walletConnectWeb3, { contractType: 'mining', callType: 'call', methodName: 'accountRewards', account: accounts[0] }); - const poolConfig = await callTokenContractMethod(walletConnectWeb3, {contractType: 'mining', callType: 'call', methodName: 'config'}); - const listedNativeCnt = await fetchListedItemCount(blankAddress); - const listedPasarCnt = await fetchListedItemCount(PASAR_TOKEN_ADDRESS); - const listedEcoCnt = await fetchListedItemCount(poolConfig.ecoToken); - const listedOtherCnt = (await fetchListedItemCount('')) - listedNativeCnt - listedPasarCnt - listedEcoCnt; - const currentRatios = await callTokenContractMethod(walletConnectWeb3, { contractType: 'mining', callType: 'call', methodName: 'getCurrentRatios' }); - setMiningReward(accountRewards); - setListedItemCnt({ native: listedNativeCnt, pasar: listedPasarCnt, eco: listedEcoCnt, other: listedOtherCnt }); - setMiningPoolRatio({ native: parseInt(currentRatios.native, 10) / 1e4, pasar: parseInt(currentRatios.pasar, 10) / 1e4, eco: parseInt(currentRatios.eco, 10) / 1e4, other: parseInt(currentRatios.other, 10) / 1e4 }); + const accounts = await getWalletAccounts(); + if (accounts.length) { + const balance = await callTokenContractMethod({ + contractType: 'token', + callType: 'call', + methodName: 'balanceOf', + account: accounts[0] + }); + setPasarBalance(balance); + } + // rewards page + const poolConfig = await callTokenContractMethod({ + contractType: 'mining', + callType: 'call', + methodName: 'config' + }); + const rewardedUsers = await fetchRewardedUserCount(); + const listedNativeCnt = await fetchListedItemCount(blankAddress); + const listedPasarCnt = await fetchListedItemCount(PASAR_TOKEN_ADDRESS); + const listedEcoCnt = await fetchListedItemCount(poolConfig.ecoToken); + const listedOtherCnt = (await fetchListedItemCount('')) - listedNativeCnt - listedPasarCnt - listedEcoCnt; + const currentRatios = await callTokenContractMethod({ + contractType: 'mining', + callType: 'call', + methodName: 'getCurrentRatios' + }); + const nextMiningReward = await callTokenContractMethod({ + contractType: 'mining', + callType: 'call', + methodName: 'pendingRewards' + }); + setListedItemCnt({ native: listedNativeCnt, pasar: listedPasarCnt, eco: listedEcoCnt, other: listedOtherCnt }); + setMiningPoolRatio({ + native: parseInt(currentRatios.native, 10) / 1e4, + pasar: parseInt(currentRatios.pasar, 10) / 1e4, + eco: parseInt(currentRatios.eco, 10) / 1e4, + other: parseInt(currentRatios.other, 10) / 1e4 + }); + setUserRewarded(rewardedUsers); + setNextDistribution({ + native: parseInt(nextMiningReward.native, 10) / 1e18, + pasar: parseInt(nextMiningReward.pasar, 10) / 1e18, + eco: parseInt(nextMiningReward.eco, 10) / 1e18, + other: parseInt(nextMiningReward.other, 10) / 1e18 + }); + sessionStorage.setItem( + 'REWARD_POOL', + JSON.stringify({ + item: { native: listedNativeCnt, pasar: listedPasarCnt, eco: listedEcoCnt, other: listedOtherCnt }, + pool: { + native: parseInt(currentRatios.native, 10) / 1e4, + pasar: parseInt(currentRatios.pasar, 10) / 1e4, + eco: parseInt(currentRatios.eco, 10) / 1e4, + other: parseInt(currentRatios.other, 10) / 1e4 + }, + user: rewardedUsers, + next: { + native: parseInt(nextMiningReward.native, 10) / 1e18, + pasar: parseInt(nextMiningReward.pasar, 10) / 1e18, + eco: parseInt(nextMiningReward.eco, 10) / 1e18, + other: parseInt(nextMiningReward.other, 10) / 1e18 + } + }) + ); + if (accounts.length) { + const accountRewards = await callTokenContractMethod({ + contractType: 'mining', + callType: 'call', + methodName: 'accountRewards', + account: accounts[0] + }); + setMiningReward({ + all: { + total: accountRewards.all.total / 1e18, + withdrawable: accountRewards.all.withdrawable / 1e18, + withdrawn: accountRewards.all.withdrawn / 1e18 + }, + buyer: { + total: accountRewards.buyer.total / 1e18, + withdrawable: accountRewards.buyer.withdrawable / 1e18, + withdrawn: accountRewards.buyer.withdrawn / 1e18 + }, + seller: { + total: accountRewards.seller.total / 1e18, + withdrawable: accountRewards.seller.withdrawable / 1e18, + withdrawn: accountRewards.seller.withdrawn / 1e18 + }, + creator: { + total: accountRewards.creator.total / 1e18, + withdrawable: accountRewards.creator.withdrawable / 1e18, + withdrawn: accountRewards.creator.withdrawn / 1e18 + } + }); setClaimItems([ - { title: "BUYERS", action: "Buy", name: "buyer", amount: accountRewards.buyer.withdrawable, price: accountRewards.buyer.withdrawable * PASARToUSD }, - { title: "SELLERS", action: "Sell", name: "seller", amount: accountRewards.seller.withdrawable, price: accountRewards.seller.withdrawable * PASARToUSD }, - { title: "CREATORS", action: "Create", name: "creator", amount: accountRewards.creator.withdrawable, price: accountRewards.creator.withdrawable * PASARToUSD } + { + title: 'BUYERS', + action: 'Buy', + name: 'buyer', + amount: (accountRewards.buyer.withdrawable / 1e18).toFixed(4), + price: ((accountRewards.buyer.withdrawable / 1e18) * PASARToUSD).toFixed(4) + }, + { + title: 'SELLERS', + action: 'Sell', + name: 'seller', + amount: (accountRewards.seller.withdrawable / 1e18).toFixed(4), + price: ((accountRewards.seller.withdrawable / 1e18) * PASARToUSD).toFixed(4) + }, + { + title: 'CREATORS', + action: 'Create', + name: 'creator', + amount: (accountRewards.creator.withdrawable / 1e18).toFixed(4), + price: ((accountRewards.creator.withdrawable / 1e18) * PASARToUSD).toFixed(4) + } ]); - } - else { // staking page - const stakingInfo = await await callTokenContractMethod(walletConnectWeb3, { contractType: 'staking', callType: 'call', methodName: 'getUserInfo', account: accounts[0] }); - setStakingState(stakingInfo); + // staking page + const stakingInfo = await callTokenContractMethod({ + contractType: 'staking', + callType: 'call', + methodName: 'getUserInfo', + account: accounts[0] + }); + setStakingState({ + currentStaked: stakingInfo.currentStaked, + rewardWithdrawable: stakingInfo.rewardWithdrawable, + rewardWithdrawn: stakingInfo.rewardWithdrawn, + rewardFeePaid: stakingInfo.rewardFeePaid, + feeEndTime: stakingInfo.feeEndTime + }); + // get APR + const days = 360; + const currentTime = parseInt( + await callTokenContractMethod({ + contractType: 'staking', + callType: 'call', + methodName: 'getCurrentTime' + }), + 10 + ); + const rewardTime = parseInt(currentTime + days * 3600 * 24, 10); + const rewardTotal = + parseInt( + await callTokenContractMethod({ + contractType: 'staking', + callType: 'call', + methodName: 'totalRewardAtTime', + timestamp: rewardTime + }), + 10 + ) - + parseInt( + await callTokenContractMethod({ + contractType: 'staking', + callType: 'call', + methodName: 'totalRewardAtTime', + timestamp: currentTime + }), + 10 + ); + const annualReward = (rewardTotal * 365) / days; + let rate = 0; + if (stakingInfo.currentStaked > 0) { + rate = (annualReward * 1000000) / stakingInfo.currentStaked; + } + const APR = parseInt(rate, 10) / 1000000; + setStakingAPR((APR * 100).toFixed(4)); + + sessionStorage.setItem( + 'REWARD_USER', + JSON.stringify({ + mining: { + all: { + total: accountRewards.all.total / 1e18, + withdrawable: accountRewards.all.withdrawable / 1e18, + withdrawn: accountRewards.all.withdrawn / 1e18 + }, + buyer: { + total: accountRewards.buyer.total / 1e18, + withdrawable: accountRewards.buyer.withdrawable / 1e18, + withdrawn: accountRewards.buyer.withdrawn / 1e18 + }, + seller: { + total: accountRewards.seller.total / 1e18, + withdrawable: accountRewards.seller.withdrawable / 1e18, + withdrawn: accountRewards.seller.withdrawn / 1e18 + }, + creator: { + total: accountRewards.creator.total / 1e18, + withdrawable: accountRewards.creator.withdrawable / 1e18, + withdrawn: accountRewards.creator.withdrawn / 1e18 + } + }, + staking: { + currentStaked: stakingInfo.currentStaked / 1e18, + rewardWithdrawable: stakingInfo.rewardWithdrawable / 1e18, + rewardWithdrawn: stakingInfo.rewardWithdrawn / 1e18, + rewardFeePaid: stakingInfo.rewardFeePaid / 1e18, + feeEndTime: stakingInfo.feeEndTime + }, + claim: [ + { + title: 'BUYERS', + action: 'Buy', + name: 'buyer', + amount: (accountRewards.buyer.withdrawable / 1e18).toFixed(4), + price: ((accountRewards.buyer.withdrawable / 1e18) * PASARToUSD).toFixed(4) + }, + { + title: 'SELLERS', + action: 'Sell', + name: 'seller', + amount: (accountRewards.seller.withdrawable / 1e18).toFixed(4), + price: ((accountRewards.seller.withdrawable / 1e18) * PASARToUSD).toFixed(4) + }, + { + title: 'CREATORS', + action: 'Create', + name: 'creator', + amount: (accountRewards.creator.withdrawable / 1e18).toFixed(4), + price: ((accountRewards.creator.withdrawable / 1e18) * PASARToUSD).toFixed(4) + } + ], + apr: (APR * 100).toFixed(4) + }) + ); + } else { + setMiningReward({ + all: { + total: 0, + withdrawable: 0, + withdrawn: 0 + }, + buyer: { + total: 0, + withdrawable: 0, + withdrawn: 0 + }, + seller: { + total: 0, + withdrawable: 0, + withdrawn: 0 + }, + creator: { + total: 0, + withdrawable: 0, + withdrawn: 0 + } + }); + setClaimItems([ + { + title: 'BUYERS', + action: 'Buy', + name: 'buyer', + amount: 0, + price: 0 + }, + { + title: 'SELLERS', + action: 'Sell', + name: 'seller', + amount: 0, + price: 0 + }, + { + title: 'CREATORS', + action: 'Create', + name: 'creator', + amount: 0, + price: 0 + } + ]); + setStakingState({ + currentStaked: 0, + rewardWithdrawable: 0, + rewardWithdrawn: 0, + rewardFeePaid: 0, + feeEndTime: 0 + }); + setStakingAPR(0); } }; fetchData(); + setTimeout(() => { + setReloadPage(!reloadPage); + }, 10 * 1000); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [tabValue]); + }, [tabValue, reloadPage, sessionStorage.getItem('PASAR_LINK_ADDRESS')]); + + const checkIfSignedOrNot = async () => { + const accounts = await getWalletAccounts(); + return accounts && !!accounts.length; + }; - const handleStake = async (amount) => { + const handleStake = async (type, amount) => { + const accounts = await getWalletAccounts(); + if (!(accounts && accounts.length)) { + setOpenSigninEssentialDlg(true); + return; + } + const stakingInfo = await callTokenContractMethod({ + contractType: 'staking', + callType: 'call', + methodName: 'getUserInfo', + account: accounts[0] + }); + if (type === 'Unstake' && stakingInfo.currentStaked.toString() === '0') { + enqueueSnackbar('You have not participated in the stake', { variant: 'info' }); + return; + } + let stakingAmount = stakingSettleAmount < 0 ? 0 : stakingSettleAmount; + if (type === 'Stake' && BigInt(pasarBalance) + BigInt(stakingInfo.currentStaked) < BigInt(stakingAmount)) stakingAmount = BigInt(pasarBalance) + BigInt(stakingInfo.currentStaked); + if (amount === 0) { + enqueueSnackbar('The amount you selected is 0, please select bigger than 0', { variant: 'info' }); + return; + } + if (type === 'Stake' && stakingAmount <= 0) { + enqueueSnackbar('Staking amount should be greater than 0', { variant: 'error' }); + return; + } try { - await callTokenContractMethod(walletConnectWeb3, { contractType: 'staking', callType: 'send', methodName: 'stake', amount }); - enqueueSnackbar('Stake success', { variant: 'success' }); + const allowance = await callTokenContractMethod({ + contractType: 'token', + callType: 'call', + methodName: 'allowance', + owner: accounts[0], + spender: STAKING_CONTRACT_ADDRESS + }); + if (allowance < stakingAmount) { + await callTokenContractMethod({ + contractType: 'token', + callType: 'send', + methodName: 'approve', + spender: STAKING_CONTRACT_ADDRESS, + amount: BigInt(stakingAmount).toString() + }); + } + await callTokenContractMethod({ + contractType: 'staking', + callType: 'send', + methodName: 'stake', + amount: BigInt(stakingAmount).toString() + }); + enqueueSnackbar(`${type} success`, { variant: 'success' }); + window.location.reload(); } catch (err) { console.error(err); - enqueueSnackbar('Stake error', { variant: 'error' }); + enqueueSnackbar(`${type} error`, { variant: 'error' }); } }; const handleWithdrawStakingReward = async () => { + const isSignedIn = await checkIfSignedOrNot(); + if (!isSignedIn) { + setOpenSigninEssentialDlg(true); + return; + } try { - await callTokenContractMethod(walletConnectWeb3, { contractType: 'staking', callType: 'send', methodName: 'withdraw' }); + await callTokenContractMethod({ + contractType: 'staking', + callType: 'send', + methodName: 'withdraw' + }); enqueueSnackbar('Withdraw success', { variant: 'success' }); + setReloadPage(!reloadPage); } catch (err) { console.error(err); enqueueSnackbar('Withdraw error', { variant: 'error' }); @@ -302,9 +736,20 @@ export default function Rewards() { }; const handleWithdrawMiningReward = async (name) => { + const isSignedIn = await checkIfSignedOrNot(); + if (!isSignedIn) { + setOpenSigninEssentialDlg(true); + return; + } try { - await callTokenContractMethod(walletConnectWeb3, { contractType: 'mining', callType: 'send', methodName: 'withdrawRewardByName', name }); + await callTokenContractMethod({ + contractType: 'mining', + callType: 'send', + methodName: 'withdrawRewardByName', + name + }); enqueueSnackbar('Withdraw success', { variant: 'success' }); + setReloadPage(!reloadPage); } catch (err) { console.error(err); enqueueSnackbar('Withdraw error', { variant: 'error' }); @@ -318,13 +763,20 @@ export default function Rewards() { Rewards - Earn rewards by just trading, staking and listing. Mining and staking rewards will constitute 40% (40,000,000) and 10% (10,000,000) respectively of the total PASAR token supply. + Earn rewards by just trading, staking and listing. Mining and staking rewards will constitute 40% (40,000,000) + and 10% (10,000,000) respectively of the total PASAR token supply. - Get PASAR + + + + Get PASAR + + + - {`1 PASAR ≈ USD ${PASARToUSD}`} + {`1 PASAR ≈ USD ${PASARToUSD.toFixed(4)}`} } sx={{ color: 'origin.main', height: 'max-content' }} - onClick={() => addTokenToMM(PASAR_TOKEN_ADDRESS, 'PASAR', 18, 'https://github.com/PasarProtocol/PasarDWebApp/blob/main/public/static/logo-icon.svg?raw=true')} + onClick={() => + addTokenToMM( + PASAR_TOKEN_ADDRESS, + 'PASAR', + 18, + 'https://github.com/PasarProtocol/PasarDWebApp/blob/main/public/static/logo-icon.svg?raw=true' + ) + } > Add to wallet @@ -344,7 +803,7 @@ export default function Rewards() { value={tabValue} variant="scrollable" scrollButtons="auto" - onChange={handleSwitchTab} + onChange={(_, value) => setTabValue(value)} TabIndicatorProps={{ style: { background: '#FF5082' } }} @@ -371,7 +830,7 @@ export default function Rewards() { + }} + /> - - Once a buy transaction is completed, the{' '}{' '}mining rewards will be distributed accordingly. - Mining rewards to earn{' '}{' '}will last 4 years. + + Once a buy transaction is completed, the mining rewards will be distributed + accordingly. Mining rewards to earn will last 4 years. + Users can claim rewards every day, or accumulate a one-time claim. Rewards never disappear nor expire. - PASAR{' '}earned + + + PASAR + {' '} + earned + - {miningReward.all.withdrawable} + {miningReward.all.withdrawable.toFixed(4)} - {`≈ USD ${miningReward.all.total * PASARToUSD}`} + {`≈ USD ${( + miningReward.all.total * PASARToUSD + ).toFixed(4)}`} - to collect from 4 mining rewards - - handleWithdrawMiningReward("all")}>Claim All - + + to collect from 4 mining rewards + + handleWithdrawMiningReward('all')} + > + Claim All + @@ -409,24 +883,71 @@ export default function Rewards() { ELA ESC - theme.palette.mode === 'dark' ? 'invert(1)' : 'none' }} /> + (theme.palette.mode === 'dark' ? 'invert(1)' : 'none') + }} + /> - + PASAR - theme.palette.mode === 'dark' ? 'invert(1)' : 'none' }} /> + (theme.palette.mode === 'dark' ? 'invert(1)' : 'none') + }} + /> - + Ecosystem - theme.palette.mode === 'dark' ? 'invert(1)' : 'none' }} /> + (theme.palette.mode === 'dark' ? 'invert(1)' : 'none') + }} + /> - + Others - + Mining Rewards @@ -447,11 +968,11 @@ export default function Rewards() { Standard Staking Stake{' '} - + PASAR - , - earn{' '} - + + , earn{' '} + PASAR @@ -459,7 +980,7 @@ export default function Rewards() { {stakingAPR}% - APR{' '} + APR @@ -475,15 +996,19 @@ export default function Rewards() { } }} > - } sx={{ '& .Mui-expanded': { marginBottom: '0 !important' } }}> + } + sx={{ '& .Mui-expanded': { marginBottom: '0 !important' } }} + > Your Stake - - {stakingState.currentStaked} - - {`≈ USD ${stakingState.currentStaked * PASARToUSD}`} + {(stakingState.currentStaked / 1e18).toFixed(4)} + {`≈ USD ${( + (stakingState.currentStaked * PASARToUSD) / + 1e18 + ).toFixed(4)}`} @@ -492,26 +1017,28 @@ export default function Rewards() { sx={{ display: 'inline-flex', border: (theme) => `1px solid ${theme.palette.divider}`, - borderRadius: .5, + borderRadius: 0.5, width: '100%' }} > - { - if (operAmount) handleStake(operAmount); - }}>Stake - handleStake(0)}>Unstake + Stake + Unstake - - PASAR in wallet: + + PASAR in wallet: - {pasarBalance} - - {`≈ USD ${pasarBalance * PASARToUSD}`} + {(pasarBalance / 1e18).toFixed(4)} + + + {`≈ USD ${( + (pasarBalance * PASARToUSD) / + 1e18 + ).toFixed(2)}`} @@ -521,17 +1048,18 @@ export default function Rewards() { type="number" variant="outlined" placeholder="Amount" - value={operAmount} + value={(operAmount / 1e18).toFixed(4)} onChange={handleChangeAmount} InputProps={{ endAdornment: ( + display: 'inline-flex' + }} + /> ), style: { fontSize: '16pt', @@ -541,31 +1069,57 @@ export default function Rewards() { }} sx={{ flexGrow: 1 }} /> - {stakingType} + handleStake(stakingType, operAmount)} + > + {stakingType} + - - {amountProgress}% + + + {amountProgress}% + - { - AmountProgressType.map((progType, _i) => { - const btnSx = { flexGrow: 1 } - if (amountProgress === (_i + 1) * 25) { - btnSx.background = (theme) => theme.palette.origin.main - btnSx.color = 'white' - } - return {progType} - }) - } + {AmountProgressType.map((progType, _i) => { + const btnSx = { flexGrow: 1 }; + if (amountProgress === (_i + 1) * 25) { + btnSx.background = (theme) => theme.palette.origin.main; + btnSx.color = 'white'; + } + return ( + + {progType} + + ); + })} - PASAR in wallet: + PASAR in wallet: - {pasarBalance} + {(pasarBalance / 1e18).toFixed(4)} - {`≈ USD ${pasarBalance * PASARToUSD}`} + {`≈ USD ${( + (pasarBalance * PASARToUSD) / + 1e18 + ).toFixed(2)}`} @@ -583,39 +1137,52 @@ export default function Rewards() { } }} > - } sx={{ '& .Mui-expanded': { marginBottom: '0 !important' } }}> + } + sx={{ '& .Mui-expanded': { marginBottom: '0 !important' } }} + > Rewards - - {stakingState.rewardWithdrawable} - - {`≈ USD ${stakingState.rewardWithdrawable * PASARToUSD}`} + {(stakingState.rewardWithdrawable / 1e18).toFixed(4)} + {`≈ USD ${( + (stakingState.rewardWithdrawable * PASARToUSD) / + 1e18 + ).toFixed(4)}`} - - Received so far: + + Received so far: - {stakingState.rewardWithdrawn} - - {`≈ USD ${stakingState.rewardWithdrawn * PASARToUSD}`} + {(stakingState.rewardWithdrawn / 1e18).toFixed(4)} + + + {`≈ USD ${( + (stakingState.rewardWithdrawn * PASARToUSD) / + 1e18 + ).toFixed(4)}`} - Claim + + Claim + - Received so far: + Received so far: - {stakingState.rewardWithdrawn} + {(stakingState.rewardWithdrawn / 1e18).toFixed(4)} - {`≈ USD ${stakingState.rewardWithdrawn * PASARToUSD}`} + {`≈ USD ${( + (stakingState.rewardWithdrawn * PASARToUSD) / + 1e18 + ).toFixed(4)}`} @@ -626,4 +1193,4 @@ export default function Rewards() { ); -} \ No newline at end of file +} diff --git a/src/utils/common.js b/src/utils/common.js index 2615af05..9f090ecf 100644 --- a/src/utils/common.js +++ b/src/utils/common.js @@ -2,7 +2,7 @@ import axios from 'axios'; import Web3 from 'web3'; import * as math from 'mathjs'; import { createHash } from 'crypto'; -import { create, urlSource } from 'ipfs-http-client'; +import { create } from 'ipfs-http-client'; import { format, subDays, subHours, formatDistance } from 'date-fns'; import Jazzicon from '@metamask/jazzicon'; import { DID, DIDBackend, DefaultDIDAdapter } from '@elastosfoundation/did-js-sdk'; @@ -553,7 +553,16 @@ export function callContractMethod(type, coinType, chainId, paramObj) { }); } -export const callTokenContractMethod = (walletConnectWeb3, param) => new Promise((resolve, reject) => { +export const callTokenContractMethod = (param) => new Promise((resolve, reject) => { + const linkType = sessionStorage.getItem('PASAR_LINK_ADDRESS'); + let walletConnectProvider; + if (linkType === '2') walletConnectProvider = isInAppBrowser() + ? window.elastos.getWeb3Provider() + : essentialsConnector.getWalletConnectProvider(); + else if (linkType === '1' && (Web3.givenProvider || window.ethereum)) walletConnectProvider = Web3.givenProvider || window.ethereum; + else walletConnectProvider = new Web3.providers.HttpProvider(rpcURL); + const walletConnectWeb3 = new Web3(walletConnectProvider); + let contractABI; let contractAddress; let contractMethod = null; @@ -587,9 +596,21 @@ export const callTokenContractMethod = (walletConnectWeb3, param) => new Promise case 'balanceOf': contractMethod = smartContract.methods.balanceOf(param.account); break; + case 'allowance': + contractMethod = smartContract.methods.allowance(param.owner, param.spender) + break; + case 'approve': + contractMethod = smartContract.methods.approve(param.spender, param.amount); + break; case 'getUserInfo': contractMethod = smartContract.methods.getUserInfo(param.account); break; + case 'getCurrentTime': + contractMethod = smartContract.methods.getCurrentTime(); + break; + case 'totalRewardAtTime': + contractMethod = smartContract.methods.totalRewardAtTime(param.timestamp); + break; case 'stake': contractMethod = smartContract.methods.stake(param.amount); break; @@ -605,6 +626,9 @@ export const callTokenContractMethod = (walletConnectWeb3, param) => new Promise case 'getCurrentRatios': contractMethod = smartContract.methods.getCurrentRatios(); break; + case 'pendingRewards': + contractMethod = smartContract.methods.pendingRewards(); + break; case 'withdrawRewardByName': contractMethod = smartContract.methods.withdrawRewardByName(param.name); break; @@ -626,36 +650,49 @@ export const callTokenContractMethod = (walletConnectWeb3, param) => new Promise reject(error); }; - walletConnectWeb3.eth.getAccounts() - .then((_accounts) => { - accounts = _accounts; - return walletConnectWeb3.eth.getGasPrice(); - }) - .then(async (_gasPrice) => getFilteredGasPrice(_gasPrice)) - .then((_estimatedGas) => { - const transactionParams = { - from: accounts[0], - gasPrice, - gas: _estimatedGas, - value: 0, - }; - if (param.callType === 'call') { - contractMethod.call().then(res => resolve(res)); - } else if (param.callType === 'send') { + if (param.callType === 'call') { + contractMethod.call().then(res => resolve(res)); + } else if (param.callType === 'send') { + walletConnectWeb3.eth.getAccounts() + .then((_accounts) => { + accounts = _accounts; + return walletConnectWeb3.eth.getGasPrice(); + }) + .then(async (_gasPrice) => getFilteredGasPrice(_gasPrice)) + .then((_estimatedGas) => { + const transactionParams = { + from: accounts[0], + gasPrice, + gas: _estimatedGas > 8000000 ? 8000000 : _estimatedGas, + value: 0, + }; contractMethod.send(transactionParams) .once('transactionHash', handleTxEvent) .once('receipt', handleReceiptEvent) .on('error', handleErrorEvent); - } - }) - .catch((error) => { - console.error(error); - }); -} -) + }) + .catch((error) => { + console.error(error); + }); + } +}) + +export const getWalletAccounts = async() => { + const linkType = sessionStorage.getItem('PASAR_LINK_ADDRESS'); + let walletConnectProvider; + if (linkType === '2') walletConnectProvider = isInAppBrowser() + ? window.elastos.getWeb3Provider() + : essentialsConnector.getWalletConnectProvider(); + else if (linkType === '1' && (Web3.givenProvider || window.ethereum)) walletConnectProvider = Web3.givenProvider || window.ethereum; + else walletConnectProvider = new Web3.providers.HttpProvider(rpcURL); + const walletConnectWeb3 = new Web3(walletConnectProvider); + + const accounts = await walletConnectWeb3.eth.getAccounts(); + return accounts; +}; export const addTokenToMM = async (address, symbol, decimals, image) => { - if (!address || !symbol || !decimals) return ; + if (!address || !symbol || !decimals) return; try { // wasAdded is a boolean. Like any RPC method, an error may be thrown. const { ethereum } = window; @@ -872,6 +909,11 @@ const coinTypes = [ name: 'DIA', address: DIA_CONTRACT_ADDRESS }, + { + icon: 'logo-icon.svg', + name: 'PASAR', + address: PASAR_TOKEN_ADDRESS + }, { icon: 'erc20/WELA.png', name: 'WELA',