Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create basic Redeem page #354

Merged
merged 1 commit into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/course/contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,83 @@ export const isRegistered = async (learner, provider) => {
return res
}

export const hasStakeInCourse = async (provider) => {
const { chainId } = await provider.getNetwork()

const deSchoolContract = new Contract(
addresses(chainId).deSchool,
abis.deSchool,
provider
)
let res = false
try {
res = !!(await deSchoolContract.isDeployed(KERNEL_COURSE_ID))
} catch (err) {
// throws an error if either the learner is not registered or if the courseId does not exist
/** */
}
return res
}

export const getBlockRegistered = async (learner, provider) => {
const { chainId } = await provider.getNetwork()

const deSchoolContract = new Contract(
addresses(chainId).deSchool,
abis.deSchool,
provider
)

let res
try {
res = await deSchoolContract.getBlockRegistered(learner, KERNEL_COURSE_ID)
} catch (err) {
// throws an error if either the learner is not registered or if the courseId does not exist
/** */
}
return res
}

export const getCourseLength = async (provider) => {
const { chainId } = await provider.getNetwork()

const deSchoolContract = new Contract(
addresses(chainId).deSchool,
abis.deSchool,
provider
)

let res
try {
res = await deSchoolContract.courses(KERNEL_COURSE_ID)[1]
} catch (err) {
// throws an error if either the learner is not registered or if the courseId does not exist
/** */
}
return res
}

export const redeemDeposit = async (signer) => {
const chainId = await signer.getChainId()

const deSchoolContract = new Contract(
addresses(chainId).deSchool,
abis.deSchool,
signer
)

let res

try {
res = !!(await deSchoolContract.redeem(KERNEL_COURSE_ID))
} catch (err) {
// throws an error if either the learner is not registered or if the courseId does not exist
/** */
}

return res
}

export const getDaiNonce = async (learner, provider) => {
const { chainId } = await provider.getNetwork()

Expand Down
34 changes: 5 additions & 29 deletions src/modules/flashcard/card.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
/** @jsx jsx */
import { Children, Fragment, useState, useEffect } from 'react'
import { jsx, Flex, Text, Box } from 'theme-ui'
import { jsx, Flex } from 'theme-ui'
import { useConnect, useAccount, useProvider } from 'wagmi'
import { Button } from '@modules/ui'
import { motion } from 'framer-motion'
import { Connector } from '@src/course/connect'
import { isRegistered } from '@src/course/contracts'
import Web3Modal from '../web3/modal'

const Web3Control = ({
children,
onClickButton,
buttonText,
descriptionText,
isDisabled,
}) => {
return (
<div>
<Box sx={{ padding: '0.5rem' }}>
<Text sx={styles.connectText}>{descriptionText}</Text>
</Box>
<Button
sx={{ marginX: 'auto' }}
disabled={isDisabled}
onClick={onClickButton}>
{buttonText}
</Button>
{children}
</div>
)
}
import { Modal as Web3Modal, Button as Web3Button } from '@src/modules/web3'

const Card = ({
children,
Expand Down Expand Up @@ -149,15 +125,15 @@ const Card = ({
</Flex>
)}
{isConnected && !isUserRegistered && (
<Web3Control
<Web3Button
descriptionText="Register to reveal"
buttonText="Register"
isDisabled={!connector.ready}
onClickButton={() => setIsModalVisible(true)}
/>
)}
{!isConnected && (
<Web3Control
<Web3Button
descriptionText="Connect wallet to reveal"
buttonText="Metamask"
isDisabled={!connector.ready}
Expand All @@ -167,7 +143,7 @@ const Card = ({
{error?.message && (
<div sx={styles.connectError}>Failed to connect</div>
)}
</Web3Control>
</Web3Button>
)}
</motion.div>
{isConnected && isUserRegistered && (
Expand Down
28 changes: 28 additions & 0 deletions src/modules/redemptionPage/ConnectButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/** @jsx jsx */

import { Flex, jsx } from 'theme-ui'
import { useConnect } from 'wagmi'
import { useState } from 'react'

import { Button as Web3Button } from '@src/modules/web3'
import { Connector } from '@src/course/connect'

const ConnectButton = () => {
const { connect, connectors } = useConnect()
const [connector] = useState(connectors[Connector.INJECTED])

return (
<Flex>
<Web3Button
descriptionText="Connect your wallet to continue"
buttonText="Metamask"
isDisabled={!connector.ready}
onClickButton={() => {
connect(connector)
}}
/>
</Flex>
)
}

export default ConnectButton
37 changes: 37 additions & 0 deletions src/modules/redemptionPage/RedemptionConnector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/** @jsx jsx */

import { jsx } from 'theme-ui'
import { useAccount, useProvider } from 'wagmi'
import { useEffect, useState } from 'react'

import { hasStakeInCourse } from '@src/course/contracts'
import RegisterButton from './RegisterButton'
import RedemptionDetails from './RedemptionDetails'

const RedemptionConnector = () => {
const { data: accountData } = useAccount()
const provider = useProvider()
const [hasStakeStakeToRedeem, setHasStakeToRedeem] = useState(false)

useEffect(() => {
const retrieveAndSetStakeState = async () => {
const _hasStake = await hasStakeInCourse(provider)
setHasStakeToRedeem(_hasStake)
}

if (accountData?.address && provider) {
retrieveAndSetStakeState()
}
}, [accountData?.address, provider])

return (
<div>
{hasStakeStakeToRedeem && (
<RedemptionDetails address={accountData?.address} />
)}
{!hasStakeStakeToRedeem && <RegisterButton />}
</div>
)
}

export default RedemptionConnector
110 changes: 110 additions & 0 deletions src/modules/redemptionPage/RedemptionDetails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/** @jsx jsx */

import { Flex, jsx } from 'theme-ui'
import { useConnect, useProvider, useBlockNumber, useSigner } from 'wagmi'
import { useEffect, useState } from 'react'

import { Button as Web3Button } from '@src/modules/web3'
import { Connector } from '@src/course/connect'
import {
getBlockRegistered,
getCourseLength,
redeemDeposit,
} from '@src/course/contracts'

const isRedemptionTime = (currentBlockNumber, redemptionBlockNumber) => {
return currentBlockNumber >= redemptionBlockNumber
}

const getTimeUntilRedemptionText = (
currentBlockNumber,
redemptionBlockNumber
) => {
if (isRedemptionTime(currentBlockNumber, redemptionBlockNumber)) {
return 'You can redeem your deposit now'
} else {
const averageBlockTimeInDays = 14 / 60 / 60 / 24
const daysUntilRedemption =
(redemptionBlockNumber - currentBlockNumber) * averageBlockTimeInDays

if (daysUntilRedemption <= 1) {
return `You can redeem your deposit today at block number ${redemptionBlockNumber}`
} else {
const roundedDays = Math.round(daysUntilRedemption)
const dayText = roundedDays == 1 ? 'day' : 'days'
return `You can redeem your deposit in ${roundedDays} ${dayText} at block number ${redemptionBlockNumber}`
}
}
}

const RedemptionDetails = ({ address }) => {
const provider = useProvider()
const { data: signer } = useSigner()
const { data: currentBlockNumber } = useBlockNumber({ watch: true })
const { connectors } = useConnect()

const [connector] = useState(connectors[Connector.INJECTED])
const [blockRegistered, setBlockRegistered] = useState(0)
const [courseLength, setCourseLength] = useState(0)
const [canRedeemDeposit, setCanRedeemDeposit] = useState(false)

const redemptionBlockNumber = blockRegistered + courseLength
const timeUntilRedemptionText = getTimeUntilRedemptionText(
currentBlockNumber,
redemptionBlockNumber
)

useEffect(() => {
const retrieveBlockRegistered = async () => {
const blockNumber = await getBlockRegistered(address, provider)
setBlockRegistered(blockNumber || 0)
}

const retrieveCourseLength = async () => {
const lengthOfCourse = await getCourseLength(provider)
setCourseLength(lengthOfCourse || 0)
}

if (address && provider) {
retrieveBlockRegistered()
retrieveCourseLength()
}
}, [address, provider])

useEffect(() => {
if (currentBlockNumber && blockRegistered) {
setCanRedeemDeposit(
isRedemptionTime(currentBlockNumber, redemptionBlockNumber)
)
}
}, [blockRegistered, currentBlockNumber])

const handleOnPressRedeem = async () => {
await redeemDeposit(signer)
}

return (
<Flex sx={styles.container}>
<p sx={styles.blockNumberText}>Current block: {currentBlockNumber}</p>
<Web3Button
descriptionText={timeUntilRedemptionText}
buttonText="Redeem"
isDisabled={!connector.ready || !canRedeemDeposit}
onClickButton={handleOnPressRedeem}
/>
</Flex>
)
}

const styles = {
container: {
flexDirection: 'column',
},
blockNumberText: {
textAlign: 'center',
fontWeight: 'bold',
marginX: 'auto',
},
}

export default RedemptionDetails
28 changes: 28 additions & 0 deletions src/modules/redemptionPage/RegisterButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/** @jsx jsx */

import { Flex, jsx } from 'theme-ui'
import { useConnect } from 'wagmi'
import { useState } from 'react'

import { Button as Web3Button, Modal as Web3Modal } from '@src/modules/web3'
import { Connector } from '@src/course/connect'

const RegisterButton = () => {
const { connectors } = useConnect()
const [connector] = useState(connectors[Connector.INJECTED])
const [isModalVisible, setIsModalVisible] = useState(false)

return (
<Flex>
{isModalVisible && <Web3Modal setIsVisible={setIsModalVisible} />}
<Web3Button
descriptionText="You don't have any deposits in the course"
buttonText="Register"
isDisabled={!connector.ready}
onClickButton={() => setIsModalVisible(true)}
/>
</Flex>
)
}

export default RegisterButton
4 changes: 4 additions & 0 deletions src/modules/redemptionPage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import ConnectButton from './ConnectButton'
import RedemptionConnector from './RedemptionConnector'

export { ConnectButton, RedemptionConnector }
37 changes: 37 additions & 0 deletions src/modules/web3/button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/** @jsx jsx */

import { jsx, Text, Box } from 'theme-ui'
import { Button } from '@modules/ui'

const Web3Button = ({
children,
onClickButton,
buttonText,
descriptionText,
isDisabled,
}) => {
return (
<div>
<Box sx={{ padding: '0.5rem' }}>
<Text sx={styles.connectText}>{descriptionText}</Text>
</Box>
<Button
sx={{ marginX: 'auto' }}
disabled={isDisabled}
onClick={onClickButton}>
{buttonText}
</Button>
{children}
</div>
)
}

const styles = {
connectText: {
textAlign: 'center',
fontWeight: 'bold',
marginX: 'auto',
},
}

export default Web3Button
Loading