Merge pull request !23 from 骚/myf-dev
This commit is contained in:
gary 2022-05-24 02:46:59 +00:00 committed by Gitee
commit 76fc43d1fe
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
28 changed files with 908 additions and 124 deletions

View File

@ -1118,7 +1118,7 @@
"By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins": "使用页面右上方的邀请,可邀请新用户进入,并在用户购买币后获得", "By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins": "使用页面右上方的邀请,可邀请新用户进入,并在用户购买币后获得",
"The commission": "的提成!", "The commission": "的提成!",
"footer %number% text": "使用页面右上方的邀请,可邀请新用户进入,并在用户购买币后获得 %number% 的提成!", "footer %number% text": "使用页面右上方的邀请,可邀请新用户进入,并在用户购买币后获得 %number% 的提成!",
"market value": "市值", "market value": "市值(24h)",
"Loaded all": "已加载全部", "Loaded all": "已加载全部",
"Insufficient Balance": "余额不足", "Insufficient Balance": "余额不足",
"HCC Currency amount": "HCC币总量", "HCC Currency amount": "HCC币总量",
@ -1153,5 +1153,11 @@
"gross": "总量", "gross": "总量",
"remaining quantity": "剩余数量", "remaining quantity": "剩余数量",
"Immediately change": "立即兑换", "Immediately change": "立即兑换",
"IDO Exchange": "IDO 兑换" "IDO Exchange": "IDO 兑换",
"Get": "领取",
"IDO Get": "IDO 领取",
"Estimated time of collection": "预计领取时间",
"amount": "金额",
"Change the end": "兑换结束",
"After purchase, it is expected to be available for collection in %time% time. Do you confirm the purchase": "购买后,预计%time%时间后可进行领取,是否确认购买"
} }

View File

@ -54,7 +54,7 @@ const Referral = lazy(() => import('./views/Referral'))
const Board = lazy(() => import('./views/Board')) const Board = lazy(() => import('./views/Board'))
const Nft = lazy(() => import('./views/Nft')) const Nft = lazy(() => import('./views/Nft'))
const Announcement = lazy(() => import('./views/Announcement')) const Announcement = lazy(() => import('./views/Announcement'))
const Exchange = lazy(() => import('./views/Exchange')) const Ido = lazy(() => import('./views/Ido'))
// This config is required for number formatting // This config is required for number formatting
BigNumber.config({ BigNumber.config({
@ -100,8 +100,8 @@ const App: React.FC = () => {
<Route path="/pools"> <Route path="/pools">
<Pools /> <Pools />
</Route> </Route>
<Route path="/exchange"> <Route path="/ido">
<Exchange /> <Ido />
</Route> </Route>
<Route path="/referral"> <Route path="/referral">
<Referral /> <Referral />

View File

@ -28,7 +28,7 @@ const config: (t: ContextApi['t']) => MenuEntry[] = (t) => [
{ {
label: t('IDO Exchange'), label: t('IDO Exchange'),
icon: 'FarmIcon', icon: 'FarmIcon',
href: '/exchange', href: '/Ido',
}, },
{ {
label: t('Exchange'), label: t('Exchange'),

View File

@ -57,7 +57,6 @@ const Menu = (props) => {
sign() sign()
} }
}, [unActiveAccount, hasWalletLogin, library]) }, [unActiveAccount, hasWalletLogin, library])
useEffect(() => { useEffect(() => {
getDetails() getDetails()
}, []) }, [])
@ -72,7 +71,7 @@ const Menu = (props) => {
currentLang={currentLanguage.code} currentLang={currentLanguage.code}
langs={languageList} langs={languageList}
setLang={setLanguage} setLang={setLanguage}
cakePriceUsd={hccPriceUsdt.toNumber()} cakePriceUsd={hccPriceUsdt}
links={config(t)} links={config(t)}
socialLink={socialLink} socialLink={socialLink}
{...props} {...props}

View File

@ -0,0 +1,178 @@
[
{
"inputs": [{ "internalType": "contract IERC20", "name": "_HCC", "type": "address" }],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "uint256", "name": "round", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "total", "type": "uint256" },
{ "indexed": false, "internalType": "address", "name": "token", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "price", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "beginTime", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "endTime", "type": "uint256" }
],
"name": "AddRound",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "user", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "Harvest",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" },
{ "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" }
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [{ "indexed": false, "internalType": "uint256", "name": "newLockTime", "type": "uint256" }],
"name": "SetLockTimeEvent",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "uint256", "name": "round", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "total", "type": "uint256" },
{ "indexed": false, "internalType": "address", "name": "token", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "price", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "beginTime", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "endTime", "type": "uint256" }
],
"name": "SetRound",
"type": "event"
},
{
"inputs": [],
"name": "HCC",
"outputs": [{ "internalType": "contract IERC20", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "round", "type": "uint256" },
{ "internalType": "uint256", "name": "total", "type": "uint256" },
{ "internalType": "address", "name": "token", "type": "address" },
{ "internalType": "uint256", "name": "price", "type": "uint256" },
{ "internalType": "uint256", "name": "beginTime", "type": "uint256" },
{ "internalType": "uint256", "name": "endTime", "type": "uint256" }
],
"name": "addRound",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "uint256", "name": "round", "type": "uint256" }],
"name": "getRound",
"outputs": [
{ "internalType": "uint256", "name": "total", "type": "uint256" },
{ "internalType": "uint256", "name": "remaining", "type": "uint256" },
{ "internalType": "address", "name": "token", "type": "address" },
{ "internalType": "uint256", "name": "price", "type": "uint256" },
{ "internalType": "uint256", "name": "beginTime", "type": "uint256" },
{ "internalType": "uint256", "name": "endTime", "type": "uint256" }
],
"stateMutability": "view",
"type": "function"
},
{ "inputs": [], "name": "harvest", "outputs": [], "stateMutability": "nonpayable", "type": "function" },
{
"inputs": [],
"name": "lockTime",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "round", "type": "uint256" },
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "purchase",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"name": "purchaseInfo",
"outputs": [
{ "internalType": "uint256", "name": "total", "type": "uint256" },
{ "internalType": "uint256", "name": "purchasedAmount", "type": "uint256" },
{ "internalType": "address", "name": "token", "type": "address" },
{ "internalType": "uint256", "name": "price", "type": "uint256" },
{ "internalType": "uint256", "name": "beginTime", "type": "uint256" },
{ "internalType": "uint256", "name": "endTime", "type": "uint256" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "round", "type": "uint256" },
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "purchaseWithLock",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" },
{
"inputs": [{ "internalType": "uint256", "name": "_lockTime", "type": "uint256" }],
"name": "setLockTime",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ "inputs": [], "name": "setPause", "outputs": [], "stateMutability": "nonpayable", "type": "function" },
{
"inputs": [
{ "internalType": "uint256", "name": "round", "type": "uint256" },
{ "internalType": "uint256", "name": "total", "type": "uint256" },
{ "internalType": "address", "name": "token", "type": "address" },
{ "internalType": "uint256", "name": "price", "type": "uint256" },
{ "internalType": "uint256", "name": "beginTime", "type": "uint256" },
{ "internalType": "uint256", "name": "endTime", "type": "uint256" }
],
"name": "setRound",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "", "type": "address" }],
"name": "userInfo",
"outputs": [{ "internalType": "uint256", "name": "purchasedAmount", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
}
]

View File

@ -8,11 +8,11 @@ export default {
56: '0x6ab8463a4185b80905e05a9ff80a2d6b714b9e95', 56: '0x6ab8463a4185b80905e05a9ff80a2d6b714b9e95',
}, },
boardChef: { boardChef: {
97: '0x126935cae1988efbf8e310abe6be1f9046eaf0ac', 97: '0x4ECC687D67138694729433e77cD95eEE9a858E40',
56: '0xD34871F12ace1BB8034E18009104b9dA60B84250', // NEED CHANGE 节点董事会合约 56: '0xD34871F12ace1BB8034E18009104b9dA60B84250', // NEED CHANGE 节点董事会合约
}, },
boardRewardChef: { boardRewardChef: {
97: '0x2937a050705009270c9b5bc096d57d519ab7c39b', 97: '0xbCb980b6A4CD67d81B63B0bFA734B4116B218700',
56: '0xD34871F12ace1BB8034E18009104b9dA60B84250', // NEED CHANGE 节点董事会分红合约 56: '0xD34871F12ace1BB8034E18009104b9dA60B84250', // NEED CHANGE 节点董事会分红合约
}, },
holderChef: { holderChef: {
@ -20,16 +20,20 @@ export default {
56: '0xD34871F12ace1BB8034E18009104b9dA60B84250', // NEED CHANGE 持币人 56: '0xD34871F12ace1BB8034E18009104b9dA60B84250', // NEED CHANGE 持币人
}, },
holderRewardChef: { holderRewardChef: {
97: '0x46271393dd6f2c8798a44f857888aa6a85af3527', 97: '0x61FB526924c6BAC9A08E146Da103B19c0DFA1899',
56: '0x46271393dd6f2c8798a44f857888aa6a85af3527', // NEED CHANGE 持币人分红 56: '0x46271393dd6f2c8798a44f857888aa6a85af3527', // NEED CHANGE 持币人分红
}, },
referralChef: { referralChef: {
97: '0x8a5dc1e8262d6a3de664624fdc13a533ba64e60d', 97: '0xe94282DA5166AD3FEB82F7aE299b2D5DFDF392Ae',
56: '0x88F46EF2Ee08494D84942DCA3bd24cDEf7C88Ae2', // NEED CHANGE 邀请或则军团长 56: '0xf42D1e1883C2FAA058dfa0D301556EB2d964859a', // NEED CHANGE 邀请或则军团长
}, },
referralRewardChef: { referralRewardChef: {
97: '0x86a510e82aceb27ed9e9880fb981d4b42ff16cb4', 97: '0xf42D1e1883C2FAA058dfa0D301556EB2d964859a',
56: '0x88F46EF2Ee08494D84942DCA3bd24cDEf7C88Ae2', // NEED CHANGE 邀请或则军团长收益 56: '0xf42D1e1883C2FAA058dfa0D301556EB2d964859a', // NEED CHANGE 邀请或则军团长收益
},
idoPurchase: {
97: '0xCCFD5B33774a1568A322FCa262D3378Ff8CcdeCB',
56: '0xCCFD5B33774a1568A322FCa262D3378Ff8CcdeCB', // NEED CHANGE IDO兑换
}, },
lotteryV2: { lotteryV2: {
97: '0x5790c3534F30437641541a0FA04C992799602998', 97: '0x5790c3534F30437641541a0FA04C992799602998',

View File

@ -73,7 +73,7 @@ const tokens = {
symbol: 'HCC', symbol: 'HCC',
address: { address: {
56: '0x20de22029ab63cf9A7Cf5fEB2b737Ca1eE4c82A6', 56: '0x20de22029ab63cf9A7Cf5fEB2b737Ca1eE4c82A6',
97: '0x77f2efa78c1c2798ad3c753330aa4e1babcaeff8', 97: '0xE7619D544bD06f4d7362c8aA06a4ca0Ea73ce8c2',
}, },
decimals: 18, decimals: 18,
projectLink: 'https://tranchess.com/', projectLink: 'https://tranchess.com/',

View File

@ -1247,7 +1247,7 @@
"By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins": "By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins", "By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins": "By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins",
"The commission": "The commission", "The commission": "The commission",
"footer %number% text": "By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins %number% The commission", "footer %number% text": "By using the invitation at the top right of the page, new users can be invited to enter and obtained after users purchase coins %number% The commission",
"market value": "market value", "market value": "market value(24h)",
"Loaded all": "Loaded all", "Loaded all": "Loaded all",
"HCC Currency amount": "HCC Currency amount", "HCC Currency amount": "HCC Currency amount",
"Lock up time": "Lock up time", "Lock up time": "Lock up time",
@ -1280,5 +1280,11 @@
"gross": "gross", "gross": "gross",
"remaining quantity": "remaining quantity", "remaining quantity": "remaining quantity",
"Immediately change": "Immediately change", "Immediately change": "Immediately change",
"IDO Exchange": "IDO Exchange" "IDO Exchange": "IDO Exchange",
"Get": "Get",
"IDO Get": "IDO Get",
"Estimated time of collection": "Estimated time of collection",
"amount": "amount",
"Change the end": "Change the end",
"After purchase, it is expected to be available for collection in %time% time. Do you confirm the purchase": "After purchase, it is expected to be available for collection in %time% time. Do you confirm the purchase"
} }

View File

@ -27,6 +27,7 @@ import {
getReferralchefContract, getReferralchefContract,
getBoardchefContract, getBoardchefContract,
getReferralRewardchefContract, getReferralRewardchefContract,
getIdoPurchaseContract,
} from 'utils/contractHelpers' } from 'utils/contractHelpers'
// Imports below migrated from Exchange useContract.ts // Imports below migrated from Exchange useContract.ts
@ -109,6 +110,10 @@ export const useReferralchef = () => {
const { library } = useActiveWeb3React() const { library } = useActiveWeb3React()
return useMemo(() => getReferralchefContract(library.getSigner()), [library]) return useMemo(() => getReferralchefContract(library.getSigner()), [library])
} }
export const useIdoPurchase = () => {
const { library } = useActiveWeb3React()
return useMemo(() => getIdoPurchaseContract(library.getSigner()), [library])
}
export const useReferralRewardchef = () => { export const useReferralRewardchef = () => {
const { library } = useActiveWeb3React() const { library } = useActiveWeb3React()
return useMemo(() => getReferralRewardchefContract(library.getSigner()), [library]) return useMemo(() => getReferralRewardchefContract(library.getSigner()), [library])

View File

@ -0,0 +1,10 @@
import request from 'utils/request'
export const getPurchaseActivity = () => {
return request.request({
url: '/high_city/app/api/purchase/activity/current',
method: 'get',
})
}
export default getPurchaseActivity

View File

@ -373,9 +373,12 @@ export const usePriceCakeBusd = (): BigNumber => {
const cakeBnbFarm = useFarmFromPid(251) const cakeBnbFarm = useFarmFromPid(251)
return new BigNumber(cakeBnbFarm.token.busdPrice) return new BigNumber(cakeBnbFarm.token.busdPrice)
} }
export const usePriceHccUsdt = (): BigNumber => { export const usePriceHccUsdt = (): number => {
const hccUsdtFarm = useFarmFromPid(1000) // NEED CHANGE const hccUsdtFarm = useFarmFromPid(1000) // NEED CHANGE
return new BigNumber(hccUsdtFarm.token.busdPrice) return new BigNumber(hccUsdtFarm.token.busdPrice).toString() || !hccUsdtFarm.token.busdPrice
? 0
: new BigNumber(hccUsdtFarm.token.busdPrice).toNumber()
// return new BigNumber(hccUsdtFarm.token.busdPrice)
} }
// Block // Block

21
src/state/ido/index.ts Normal file
View File

@ -0,0 +1,21 @@
import { createSlice } from '@reduxjs/toolkit'
import BigNumber from 'bignumber.js'
import erc20ABI from 'config/abi/erc20.json'
import multicall from 'utils/multicall'
import tokens from 'config/constants/tokens'
import { getAddress, getIdoPurchaseAddress } from 'utils/addressHelpers'
export const fetchIdoUserAllowances = async (account: string) => {
const tokenAddresses = getAddress(tokens.usdt.address)
const idoPurchaseAddress = getIdoPurchaseAddress()
const calls = [{ address: tokenAddresses, name: 'allowance', params: [account, idoPurchaseAddress] }]
const rawLpAllowances = await multicall(erc20ABI, calls)
const parsedLpAllowances = rawLpAllowances.map((balance) => {
return new BigNumber(balance).toNumber()
})
return {
usdt: parsedLpAllowances[0],
}
}
export default fetchIdoUserAllowances

View File

@ -74,3 +74,6 @@ export const getBunnySpecialCakeVaultAddress = () => {
export const getBunnySpecialPredictionAddress = () => { export const getBunnySpecialPredictionAddress = () => {
return getAddress(addresses.bunnySpecialPrediction) return getAddress(addresses.bunnySpecialPrediction)
} }
export const getIdoPurchaseAddress = () => {
return getAddress(addresses.idoPurchase)
}

View File

@ -27,6 +27,7 @@ import {
getBoardAddress, getBoardAddress,
getReferralAddress, getReferralAddress,
getReferralRewardAddress, getReferralRewardAddress,
getIdoPurchaseAddress,
} from 'utils/addressHelpers' } from 'utils/addressHelpers'
// ABI // ABI
@ -59,6 +60,7 @@ import chainlinkOracleAbi from 'config/abi/chainlinkOracle.json'
import MultiCallAbi from 'config/abi/Multicall.json' import MultiCallAbi from 'config/abi/Multicall.json'
import bunnySpecialCakeVaultAbi from 'config/abi/bunnySpecialCakeVault.json' import bunnySpecialCakeVaultAbi from 'config/abi/bunnySpecialCakeVault.json'
import bunnySpecialPredictionAbi from 'config/abi/bunnySpecialPrediction.json' import bunnySpecialPredictionAbi from 'config/abi/bunnySpecialPrediction.json'
import idoPurchase from 'config/abi/idoPurchase.json'
import { ChainLinkOracleContract, PredictionsContract } from './types' import { ChainLinkOracleContract, PredictionsContract } from './types'
const getContract = (abi: any, address: string, signer?: ethers.Signer | ethers.providers.Provider) => { const getContract = (abi: any, address: string, signer?: ethers.Signer | ethers.providers.Provider) => {
@ -127,6 +129,9 @@ export const getReferralchefContract = (signer?: ethers.Signer | ethers.provider
export const getReferralRewardchefContract = (signer?: ethers.Signer | ethers.providers.Provider) => { export const getReferralRewardchefContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
return getContract(referralRewardChef, getReferralRewardAddress(), signer) return getContract(referralRewardChef, getReferralRewardAddress(), signer)
} }
export const getIdoPurchaseContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
return getContract(idoPurchase, getIdoPurchaseAddress(), signer)
}
export const getClaimRefundContract = (signer?: ethers.Signer | ethers.providers.Provider) => { export const getClaimRefundContract = (signer?: ethers.Signer | ethers.providers.Provider) => {
return getContract(claimRefundAbi, getClaimRefundAddress(), signer) return getContract(claimRefundAbi, getClaimRefundAddress(), signer)
} }

View File

@ -65,6 +65,6 @@ export const formatFixedNumber = (number: ethers.FixedNumber, displayDecimals =
return formatBigNumber(ethers.BigNumber.from(leftSide), displayDecimals, decimals) return formatBigNumber(ethers.BigNumber.from(leftSide), displayDecimals, decimals)
} }
export const formatDivNumber = (number: number, decimals = 4) => { export const formatDivNumber = (number: BigNumber | number, decimals = 4) => {
return new BigNumber(number).div(BIG_TEN.pow(decimals)).toNumber() return new BigNumber(number).div(BIG_TEN.pow(decimals)).toNumber()
} }

View File

@ -119,7 +119,7 @@ const BoardCard: React.FC<NodeCardProps> = ({ board, account, boardsData }) => {
const date2 = dayjs(date) const date2 = dayjs(date)
const time = date2.diff(date1) const time = date2.diff(date1)
if (time > 0) { if (time > 0) {
const hour = Math.floor((time / (1000 * 60 * 60)) % 24) const hour = Math.floor(time / (1000 * 60 * 60))
const minute = Math.floor((time / (1000 * 60)) % 60) const minute = Math.floor((time / (1000 * 60)) % 60)
const second = Math.round((time / 1000) % 60) const second = Math.round((time / 1000) % 60)
setCountDown(`${hour}:${minute}:${second}`) setCountDown(`${hour}:${minute}:${second}`)

View File

@ -1,4 +1,4 @@
import React, { useState, useCallback, useMemo } from 'react' import React, { useState, useCallback, useMemo, useEffect } from 'react'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import styled from 'styled-components' import styled from 'styled-components'
import { provider as ProviderType } from 'web3-core' import { provider as ProviderType } from 'web3-core'
@ -76,7 +76,7 @@ const CardActions: React.FC<NodeCardActionsProps> = ({ board, account }) => {
{displayBalance} {displayBalance}
</Text> </Text>
<Text fontSize="12px" color="#9BE5EB"> <Text fontSize="12px" color="#9BE5EB">
{(Number(hccPriceUsdt.toNumber().toFixed(3)) * Number(displayBalance)).toFixed(3)} USDT {hccPriceUsdt ? (hccPriceUsdt * Number(displayBalance)).toFixed(3) : 0} USDT
</Text> </Text>
</PriceCoin> </PriceCoin>
</Flex> </Flex>

View File

@ -1,74 +0,0 @@
import React, { useMemo, useState, useEffect } from 'react'
import styled, { keyframes } from 'styled-components'
import { useTranslation } from 'contexts/Localization'
import { Flex, Text, Button } from '@pancakeswap/uikit'
import { useAccount } from 'state/userInfo/hooks'
import UnlockButton from 'components/UnlockButton'
import ExchangeInput from './ExchangeInput'
const FCard = styled.div`
width: 650px;
background: ${(props) => props.theme.card.background};
border-radius: 32px;
box-shadow: 0px 2px 30px 0px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
position: relative;
text-align: center;
padding: 50px 70px;
`
const HeaderText = styled(Text)`
font-size: 48px;
color: #280d5f;
`
const TimeText = styled(Text)`
color: #7a6eaa;
font-size: 22px;
`
const RateText = styled(Text)`
font-size: 30px;
color: #280d5f;
`
const RateNumber = styled(Text)`
font-size: 30px;
color: #1fc7d4;
`
const FooterButton = styled.div`
margin-top: 50px;
width: 100%;
`
const UnlockButtonDiv = styled(UnlockButton)`
width: 100%;
`
const ExchangeCard: React.FC = () => {
const { t } = useTranslation()
const account = useAccount()
return (
<FCard>
<HeaderText>{t('IDO exchange in the first phase')}</HeaderText>
<TimeText>{t('Opening time of next exchange period:')}2022.5.16 00:00</TimeText>
<ExchangeInput name="USDT" />
<Flex alignItems="center" justifyContent="center" marginTop={20}>
<RateText>{t('Exchange rate')}</RateText>
<RateNumber>1USDT=100HCC</RateNumber>
</Flex>
<Flex alignItems="center" justifyContent="center">
<Text color="textSubtle">{t('gross')}100000HCC</Text>
<Text color="textSubtle" marginLeft={20}>
{t('remaining quantity')}100000HCC
</Text>
</Flex>
<ExchangeInput name="HCC" />
<FooterButton>
{account ? <Button width="100%">{t('Immediately change')}</Button> : <UnlockButtonDiv />}
</FooterButton>
</FCard>
)
}
export default ExchangeCard

View File

@ -1,22 +0,0 @@
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import ExchangeCard from './components/ExchangeCard'
const PageContent = styled.div`
min-height: calc(100vh - 64px);
background-image: url('/images/recommend/bg.svg');
background-size: cover;
background-repeat: no-repeat;
display: flex;
align-items: center;
justify-content: center;
`
const Exchange: React.FC = () => {
return (
<PageContent>
<ExchangeCard />
</PageContent>
)
}
export default Exchange

View File

@ -201,7 +201,7 @@ const FristCom: React.FC = () => {
<ScoreDiv> <ScoreDiv>
<FlexItemCom name={t('Number of holders')} valueNum={detail?.userCount} /> <FlexItemCom name={t('Number of holders')} valueNum={detail?.userCount} />
<FlexItemCom name={t('Your volume')} valueNum={detail?.volume} /> <FlexItemCom name={t('Your volume')} valueNum={detail?.volume} />
<FlexItemCom name={t('market value')} valueNum={detail?.market * Number(hccPriceUsdt) || 0} /> <FlexItemCom name={t('market value')} valueNum={detail?.market * hccPriceUsdt || 0} />
{/* {burned.map((item) => { {/* {burned.map((item) => {
return <FlexItemCom key={item.id} name={item.name} value={item.value} /> return <FlexItemCom key={item.id} name={item.name} value={item.value} />
})} */} })} */}

View File

@ -0,0 +1,37 @@
import BigNumber from 'bignumber.js'
import React, { useCallback, useMemo, useState } from 'react'
import { Button, Modal, Text } from '@pancakeswap/uikit'
import { ModalActions, ModalInput } from 'components/Modal'
import { useTranslation } from 'contexts/Localization'
import useToast from 'hooks/useToast'
import { getFullDisplayBalance } from 'utils/formatBalance'
interface AffirmModalProps {
title?: string
content?: string
onDismiss?: () => void
handSubmit?: () => void
}
const BuyModal: React.FC<AffirmModalProps> = ({ title, content, onDismiss, handSubmit }) => {
const { t } = useTranslation()
const submit = async () => {
await handSubmit()
onDismiss()
}
return (
<Modal title={t(`${title}`)} onDismiss={onDismiss}>
<Text>{!content ? t('Whether to cancel') : content}</Text>
<ModalActions>
<Button variant="secondary" onClick={onDismiss} width="100%">
{t('Cancel')}
</Button>
<Button width="100%" onClick={submit}>
{t('Confirm')}
</Button>
</ModalActions>
</Modal>
)
}
export default BuyModal

View File

@ -0,0 +1,79 @@
import React, { useMemo, useState, useEffect, useCallback } from 'react'
import dayjs from 'dayjs'
import styled, { keyframes } from 'styled-components'
import { useTranslation } from 'contexts/Localization'
import { Flex, Text, Button, Input } from '@pancakeswap/uikit'
import { useHarvest } from '../hooks'
interface GetCardProps {
price?: number | string
time?: number | string
}
const FCard = styled.div`
width: 434px;
background: ${(props) => props.theme.card.background};
border-radius: 32px;
box-shadow: 0px 2px 30px 0px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
position: relative;
text-align: left;
padding: 27px 20px;
margin-top: 50px;
`
const ExchangeCard: React.FC<GetCardProps> = ({ price = 0, time = 0 }) => {
const { t } = useTranslation()
// const account = useAccount()
// const lockTime = useLockTime()
// const [time, setTime] = useState(0)
// const userInfo = useUserInfo()
// const [price, setPrice] = useState(0)
// const init = async () => {
// const data = await lockTime()
// console.log(data)
// setTime(data)
// const info = await userInfo(account)
// console.log(info)
// setPrice(info)
// }
// useEffect(() => {
// if (account) {
// init()
// }
// }, [account])
const harvest = useHarvest()
const getPrice = async () => {
const res = await harvest()
console.log(res)
}
return (
<FCard>
{/* 锁仓时间大于当前时间 不可领取 */}
{/* 锁仓时间小于当前时间 可领取 */}
{/* 当前时间大于锁仓时间 不显示 */}
<Flex justifyContent="space-between" alignItems="center">
<div>
<Text>{t('IDO Get')}</Text>
{new Date().getTime() <= time && (
<Text>
{t('Estimated time of collection')}{dayjs(time).format('YYYY-MM-DD HH:mm:ss')}
</Text>
)}
<Flex alignItems="center">
<Text>{t('amount')}</Text>
<Text>{price}HCC</Text>
</Flex>
</div>
<Button disabled={time > new Date().getTime() || !price} onClick={getPrice}>
{t('Get')}
</Button>
</Flex>
</FCard>
)
}
export default ExchangeCard

View File

@ -0,0 +1,40 @@
import React from 'react'
import dayjs from 'dayjs'
import styled from 'styled-components'
import { useTranslation } from 'contexts/Localization'
import { Text } from '@pancakeswap/uikit'
const TimeText = styled(Text)`
color: #7a6eaa;
font-size: 22px;
`
interface RoundDetailProps {
beginTime?: number
endTime?: number
price?: number
remaining?: number
token?: string
total?: number
}
interface HeaderStatusProps {
status?: string
roundDetail?: RoundDetailProps
}
const HeaderStatus: React.FC<HeaderStatusProps> = ({ status, roundDetail }) => {
const { t } = useTranslation()
return (
<TimeText>
{status === 'none' && t('Change the end')}
{status === 'proceed' &&
`${dayjs(roundDetail?.beginTime).format('YYYY-MM-DD HH:mm:ss')} ~ ${dayjs(roundDetail?.endTime).format(
'YYYY-MM-DD HH:mm:ss',
)}`}
{status === 'end' &&
`${t('Opening time of next exchange period:')}${dayjs(roundDetail?.beginTime).format('YYYY-MM-DD HH:mm:ss')}`}
</TimeText>
)
}
export default HeaderStatus

View File

@ -19,18 +19,26 @@ const CoinText = styled(Text)`
margin-bottom: 20px; margin-bottom: 20px;
` `
interface InputProps { interface ExchangeInputProps {
name: string name: string
value?: number | string value?: number | string
disabled?: boolean
onChange: (e: React.FormEvent<HTMLInputElement>) => void
} }
const ExchangeInput: React.FC<InputProps> = ({ name, value }) => { const ExchangeInput: React.FC<ExchangeInputProps> = ({ name, value, onChange, disabled = true }) => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<PriceContent> <PriceContent>
<CoinText>{name}</CoinText> <CoinText>{name}</CoinText>
<Input value={value} placeholder={t('Please enter the amount')} /> <Input
value={value}
placeholder={t('Please enter the amount')}
onChange={onChange}
type="number"
disabled={disabled}
/>
</PriceContent> </PriceContent>
) )
} }

View File

@ -0,0 +1,191 @@
import React, { useState, useEffect } from 'react'
import dayjs from 'dayjs'
import styled from 'styled-components'
import BigNumber from 'bignumber.js'
import { useTranslation } from 'contexts/Localization'
import { Text, Button, useModal } from '@pancakeswap/uikit'
import { getAddress } from 'utils/addressHelpers'
import { getPurchaseActivity } from 'services/idoPurchase'
import { fetchIdoUserAllowances } from 'state/ido'
import { useERC20 } from 'hooks/useContract'
import useToast from 'hooks/useToast'
import { getDecimalAmountNumber, formatDivNumber } from 'utils/formatBalance'
import tokens from 'config/constants/tokens'
import { useAccount } from 'state/userInfo/hooks'
import UnlockButton from 'components/UnlockButton'
import ExchangeInput from './IdoInput'
import HeaderStatus from './HeaderStatus'
import RateText from './RateText'
import BuyModal from './BuyModal'
import { useApproveIdo, useBuyTransaction, useCheckTokenBalance } from '../hooks'
const FCard = styled.div`
width: 650px;
background: ${(props) => props.theme.card.background};
border-radius: 32px;
box-shadow: 0px 2px 30px 0px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
position: relative;
text-align: center;
padding: 50px 70px;
${({ theme }) => theme.mediaQueries.xs} {
width: 350px;
padding: 20px 30px;
}
${({ theme }) => theme.mediaQueries.lg} {
width: 650px;
padding: 50px 70px;
}
`
const HeaderText = styled(Text)`
font-size: 48px;
color: #280d5f;
`
const FooterButton = styled.div`
margin-top: 50px;
width: 100%;
`
const UnlockButtonDiv = styled(UnlockButton)`
width: 100%;
`
interface DetailProps {
id?: string
name?: string
beginTime?: string
endTime?: string
}
interface RoundDetailProps {
beginTime?: number
endTime?: number
price?: number
remaining?: number
token?: string
total?: number
}
interface Props {
status?: string
roundDetail?: RoundDetailProps
time?: number
}
const ExchangeCard: React.FC<Props> = ({ status, roundDetail, time }) => {
const { t } = useTranslation()
const { toastSuccess, toastError } = useToast()
const account = useAccount()
const [allowanceList, setAllowanceList] = useState({ usdt: 0 })
const [loading, setLoading] = useState(false)
const getAllowances = async () => {
const allowances = await fetchIdoUserAllowances(account)
setAllowanceList({
usdt: allowances.usdt,
})
}
const [idoInfo, setIdoInfo] = useState<DetailProps>({})
const getPurchaseInfo = async () => {
const data = await getPurchaseActivity()
setIdoInfo(data)
}
useEffect(() => {
if (account) {
getAllowances()
getPurchaseInfo()
}
}, [account])
const usdtContract = useERC20(getAddress(tokens.usdt.address))
const { onApprove: onUsdtApprove } = useApproveIdo(usdtContract)
const handleApprove = async (approve) => {
try {
setLoading(true)
await approve()
setLoading(false)
getAllowances()
} catch (e) {
console.error(e)
}
}
const [usdtPrice, setUsdtPrice] = useState('')
const [hccPrice, setHccPrice] = useState('')
const handleUsdtChange = (e: React.FormEvent<HTMLInputElement>) => {
const price = new BigNumber(e.currentTarget.value).multipliedBy(roundDetail?.price)
setUsdtPrice(e.currentTarget.value)
e.currentTarget.value ? setHccPrice(price.toString()) : setHccPrice('')
}
const handleHccChange = (e: React.FormEvent<HTMLInputElement>) => {
const price = new BigNumber(e.currentTarget.value).div(roundDetail?.price).toNumber()
setHccPrice(e.currentTarget.value)
e.currentTarget.value ? setUsdtPrice(price.toString()) : setUsdtPrice('')
}
const buyTransaction = useBuyTransaction()
const [onCheckBalance] = useCheckTokenBalance()
// 立即兑换
const immediatelyChange = async () => {
try {
const enoughBalance = onCheckBalance(usdtPrice)
if (enoughBalance) {
const res = await buyTransaction(hccPrice)
}
} catch (e: any) {
toastError(e?.error?.message || e.message)
}
}
const [onPresentAffirm] = useModal(
<BuyModal
title="Trade in"
content={t(
'After purchase, it is expected to be available for collection in %time% time. Do you confirm the purchase',
{ time: dayjs(time).format('YYYY-MM-DD HH:mm:ss') },
)}
handSubmit={immediatelyChange}
/>,
)
return (
<FCard>
<HeaderText>{idoInfo?.name}</HeaderText>
<HeaderStatus status={status} roundDetail={roundDetail} />
<ExchangeInput name="USDT" value={usdtPrice} onChange={handleUsdtChange} disabled={status !== 'proceed'} />
<RateText status={status} roundDetail={roundDetail} />
<ExchangeInput name="HCC" value={hccPrice} onChange={handleHccChange} disabled={status !== 'proceed'} />
<FooterButton>
{account ? (
allowanceList.usdt ? (
time ? (
<Button width="100%" onClick={onPresentAffirm} disabled={status !== 'proceed' || !hccPrice}>
{t('Immediately change')}
</Button>
) : (
<Button width="100%" onClick={immediatelyChange} disabled={status !== 'proceed' || !hccPrice}>
{t('Immediately change')}
</Button>
)
) : (
<Button
mt="8px"
width="100%"
disabled={loading}
onClick={() => {
handleApprove(onUsdtApprove)
}}
>
{t('Approve %coin% Contract', { coin: 'USDT' })}
</Button>
)
) : (
<UnlockButtonDiv />
)}
</FooterButton>
</FCard>
)
}
export default ExchangeCard

View File

@ -0,0 +1,75 @@
import React from 'react'
import styled from 'styled-components'
import { useTranslation } from 'contexts/Localization'
import { Flex, Text } from '@pancakeswap/uikit'
const RateText = styled(Text)`
font-size: 30px;
color: #280d5f;
${({ theme }) => theme.mediaQueries.xs} {
font-size: 25px;
}
${({ theme }) => theme.mediaQueries.lg} {
font-size: 30px;
}
`
const RateNumber = styled(Text)`
font-size: 30px;
color: #1fc7d4;
${({ theme }) => theme.mediaQueries.xs} {
font-size: 25px;
}
${({ theme }) => theme.mediaQueries.lg} {
font-size: 30px;
}
`
const FlexRowCenter = styled(Flex)`
justify-content: center;
align-items: center;
`
const FlexCenter = styled(Flex)`
justify-content: center;
align-items: center;
${({ theme }) => theme.mediaQueries.xs} {
flex-direction: column;
}
${({ theme }) => theme.mediaQueries.lg} {
flex-direction: row;
}
`
interface RoundDetailProps {
beginTime?: number
endTime?: number
price?: number
remaining?: number
token?: string
total?: number
}
interface Props {
status?: string
roundDetail?: RoundDetailProps
}
const RateCom: React.FC<Props> = ({ status, roundDetail }) => {
const { t } = useTranslation()
return (
<>
<FlexRowCenter marginTop={20}>
<RateText>{t('Exchange rate')}</RateText>
<RateNumber>{status === 'none' ? '-------' : `1USDT=${roundDetail?.price}HCC`}</RateNumber>
</FlexRowCenter>
<FlexCenter>
<Text color="textSubtle">
{t('gross')}{status === 'none' ? ' -------- ' : `${roundDetail?.total}HCC`}
</Text>
<Text color="textSubtle" marginLeft={20}>
{t('remaining quantity')}{status === 'none' ? ' -------- ' : `${roundDetail?.remaining}HCC`}
</Text>
</FlexCenter>
</>
)
}
export default RateCom

View File

@ -0,0 +1,138 @@
import { useCallback } from 'react'
import { useIdoPurchase, useReferralchef } from 'hooks/useContract'
import useTokenBalance from 'hooks/useTokenBalance'
import idoPurchaseABI from 'config/abi/idoPurchase.json'
import { getAddress, getIdoPurchaseAddress } from 'utils/addressHelpers'
import { getPurchaseActivity } from 'services/idoPurchase'
import BigNumber from 'bignumber.js'
import multicall from 'utils/multicall'
import tokensList from 'config/constants/tokens'
import useToast from 'hooks/useToast'
import { useTranslation } from 'contexts/Localization'
import { ethers, Contract } from 'ethers'
import { getBalanceNumber, getDecimalAmount, formatDivNumber, getDecimalAmountNumber } from 'utils/formatBalance'
// 判断余额
export const useCheckTokenBalance = () => {
const { balance: usdtTokenBalance } = useTokenBalance(getAddress(tokensList.usdt.address))
const { toastWarning } = useToast()
const { t } = useTranslation()
const onCheck = useCallback(
(usdtAmount) => {
if (getBalanceNumber(usdtTokenBalance) <= usdtAmount) {
toastWarning(t('Insufficient Balance'))
return false
}
return true
},
[usdtTokenBalance],
)
return [onCheck]
}
// 授权usdt
export const useApproveIdo = (tokenContract: Contract) => {
const handleApprove = useCallback(async () => {
try {
const tx = await tokenContract.approve(getIdoPurchaseAddress(), ethers.constants.MaxUint256)
const receipt = await tx.wait()
return receipt.status
} catch (e) {
return false
}
}, [tokenContract])
return { onApprove: handleApprove }
}
// 兑换
export const useBuyTransaction = () => {
const idoPurchase = useIdoPurchase()
const transaction = async (amount) => {
const data = await getPurchaseActivity()
const { id } = data
const params = [id, getDecimalAmount(amount).toString()]
const res = await idoPurchase.purchaseWithLock(...params)
return res
}
return transaction
}
// 获取信息
export const useGetRound = () => {
const transaction = async () => {
const data = await getPurchaseActivity()
if (!data) {
return null
}
const { id } = data
const idoPurchaseAddress = getIdoPurchaseAddress()
const calls = [
{
address: idoPurchaseAddress,
name: 'getRound',
params: [id],
},
]
const res = await multicall(idoPurchaseABI, calls)
const detail = res.map((item) => {
return {
beginTime: new BigNumber(item?.beginTime._hex).toNumber() * 1000,
endTime: new BigNumber(item?.endTime._hex).toNumber() * 1000,
price: 1 / formatDivNumber(item?.price._hex, 18),
remaining: formatDivNumber(item?.remaining._hex, 18),
// remaining: new BigNumber(item?.remaining._hex).toString(),
token: item?.token,
// total: new BigNumber(item?.total._hex).toString(),
total: formatDivNumber(item?.total._hex, 18),
}
})
return detail[0]
}
return transaction
}
// 获取锁仓时间
export const useLockTime = () => {
const transaction = async () => {
const idoPurchaseAddress = getIdoPurchaseAddress()
const calls = [
{
address: idoPurchaseAddress,
name: 'lockTime',
},
]
const [res] = await multicall(idoPurchaseABI, calls)
return new BigNumber(res[0]._hex).toNumber() * 1000
}
return transaction
}
// 获取领取数量
export const useUserInfo = () => {
const transaction = async (account) => {
const idoPurchaseAddress = getIdoPurchaseAddress()
const calls = [
{
address: idoPurchaseAddress,
name: 'userInfo',
params: [account],
},
]
const [res] = await multicall(idoPurchaseABI, calls)
return formatDivNumber(res.purchasedAmount._hex, 18)
}
return transaction
}
// 领取收益
export const useHarvest = () => {
const idoPurchase = useIdoPurchase()
const transaction = async () => {
const res = await idoPurchase.harvest()
return res
}
return transaction
}
export default useApproveIdo

72
src/views/Ido/index.tsx Normal file
View File

@ -0,0 +1,72 @@
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import { useAccount } from 'state/userInfo/hooks'
import useRefresh from 'hooks/useRefresh'
import { useLockTime, useUserInfo, useGetRound } from './hooks'
import IdoPurchaseCard from './components/IdoPurchaseCard'
import GetCard from './components/GetCard'
interface RoundDetailProps {
beginTime?: number
endTime?: number
price?: number
remaining?: number
token?: string
total?: number
}
const PageContent = styled.div`
min-height: calc(100vh - 64px);
background-image: url('/images/recommend/bg.svg');
background-size: cover;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`
const Exchange: React.FC = () => {
const account = useAccount()
const lockTime = useLockTime()
const [time, setTime] = useState(0)
const userInfo = useUserInfo()
const [price, setPrice] = useState(0)
const [status, setStatus] = useState('none') // none proceed end
const [roundDetail, setRoundDetail] = useState<RoundDetailProps>({})
const getRound = useGetRound()
const init = async () => {
const detail = await getRound()
if (!detail) {
setStatus('none')
} else if (detail.beginTime < new Date().getTime() && detail.endTime > new Date().getTime()) {
setStatus('proceed')
} else {
setStatus('end')
}
setRoundDetail(detail)
const data = await lockTime()
setTime(data)
const info = await userInfo(account)
setPrice(info)
}
const { fastRefresh } = useRefresh()
useEffect(() => {
if (account) {
init()
}
}, [account, fastRefresh])
return (
<PageContent>
<IdoPurchaseCard status={status} time={time} roundDetail={roundDetail} />
{price > 0 && <GetCard price={price} time={time} />}
</PageContent>
)
}
export default Exchange