import { Heading, Modal, ModalContent, ModalOverlay, Input, Button, Box, Text, Image, RadioGroup, Stack, Radio, useToast, } from "@chakra-ui/react"; import { Column, Center, Row } from "utils/chakraUtils"; import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import DashboardBox, { DASHBOARD_BOX_PROPS, } from "../../../shared/DashboardBox"; import { ModalDivider, MODAL_PROPS } from "../../../shared/Modal"; import { ETH_TOKEN_DATA, TokenData, useTokenData } from "hooks/useTokenData"; import SmallWhiteCircle from "static/small-white-circle.png"; import { useRari } from "context/RariContext"; import Fuse from "fuse-sdk"; import { ConfigRow } from "../FusePoolEditPage"; import { createComptroller, createRewardsDistributor, } from "utils/createComptroller"; import Web3 from "web3"; import TransactionStepper from "components/shared/TransactionStepper"; const steps = [ "Deploying Rewards Distributor", "Configuring Comptroller", ]; const AddRewardsDistributorModal = ({ comptrollerAddress, poolName, poolID, isOpen, onClose, }: { comptrollerAddress: string; poolName: string; poolID: string; isOpen: boolean; onClose: () => any; }) => { const { fuse, address: userAddress } = useRari(); const { t } = useTranslation(); const toast = useToast(); const [isDeploying, setIsDeploying] = useState(false); const [address, setAddress] = useState<string>( "" ); const [rewardToken, setRewardToken] = useState<string>(""); // If you have selected "Add RewardsDistributor, this value will be filled" const [nav, setNav] = useState<Nav>(Nav.CREATE); // Stepper const [activeStep, setActiveStep] = useState<0 | 1 | 2>(0); const tokenData = useTokenData(rewardToken); const isEmpty = address.trim() === ""; useEffect(() => { const isRewardsDistributorAddress = nav === Nav.ADD; if (isRewardsDistributorAddress) { setRewardToken(""); } try { const validAddress = Web3.utils.toChecksumAddress(address); if (validAddress && isRewardsDistributorAddress) { const rd = createRewardsDistributor(address, fuse); rd.methods .rewardToken() .call() .then((tokenAddr: string) => setRewardToken(tokenAddr)); } // If we're creating a rewardsDistributor then this is the rewardToken if (validAddress && !isRewardsDistributorAddress) { setRewardToken(address); } } catch (err) { return; } // If we're adding a rewardsDistributor then get the rewardToken }, [fuse, address, nav]); const handleDeploy = async () => { if (!tokenData) return; setIsDeploying(true); let rDAddress = address; try { if (nav === Nav.CREATE) { rDAddress = await deploy(); } } catch (err) { console.log({ err }); setIsDeploying(false); toast({ title: "Error deploying RewardsDistributor", description: "", status: "error", duration: 10000, isClosable: true, position: "top-right", }); return; } setActiveStep(1); try { await addRDToComptroller(comptrollerAddress, rDAddress, fuse); setIsDeploying(false); onClose(); } catch (err) { console.log({ err }); setIsDeploying(false); toast({ title: "Error adding RewardsDistributor to Comptroller", description: "", status: "error", duration: 10000, isClosable: true, position: "top-right", }); return; } }; // Deploy new RD const deploy = async (): Promise<string> => { if (!tokenData) throw new Error("No tokendata "); const deployedDistributor = await fuse.deployRewardsDistributor( tokenData.address, { from: userAddress, } ); toast({ title: "RewardsDistributor Deployed", description: "RewardsDistributor for " + tokenData.symbol + " deployed", status: "success", duration: 2000, isClosable: true, position: "top-right", }); const rDAddress = deployedDistributor.options.address; return rDAddress; }; const addRDToComptroller = async ( comptrollerAddress: string, rDAddress: string, fuse: Fuse ) => { const comptroller = await createComptroller(comptrollerAddress, fuse); if (!comptroller || !comptroller.methods._addRewardsDistributor) { throw new Error("Could not create Comptroller"); } // Add distributor to pool Comptroller await comptroller.methods ._addRewardsDistributor(rDAddress) .send({ from: userAddress }); toast({ title: "RewardsDistributor Added to Pool", description: "", status: "success", duration: 2000, isClosable: true, position: "top-right", }); }; const subtitle = useMemo(() => { if (nav === Nav.CREATE) { return tokenData ? tokenData.name ?? "Invalid ERC20 Token Address!" : "Loading..."; } else { return tokenData ? tokenData.name ?? "Invalid RewardsDistributor Address!" : "Loading..."; } }, [tokenData, nav]); return ( <Modal motionPreset="slideInBottom" isOpen={isOpen} onClose={onClose} isCentered size="lg" > <ModalOverlay /> <ModalContent {...MODAL_PROPS}> <Heading fontSize="27px" my={4} textAlign="center"> {nav === Nav.CREATE ? t("Deploy Rewards Distributor") : t("Add Rewards Distributor")} </Heading> <ModalDivider /> <Box h="100%" w="100%" bg=""> <Row mainAxisAlignment="flex-start" crossAxisAlignment="flex-start" bg="" p={4} > <RadioGroup onChange={(value: Nav) => setNav(value)} value={nav}> <Stack direction="row"> <Radio value={Nav.CREATE} disabled={isDeploying}> Create </Radio> <Radio value={Nav.ADD} disabled={isDeploying}> Add </Radio> </Stack> </RadioGroup> </Row> <Column mainAxisAlignment="flex-start" crossAxisAlignment="center" pb={4} > {!isEmpty ? ( <> {tokenData?.logoURL ? ( <Image mt={4} src={tokenData.logoURL} boxSize="50px" borderRadius="50%" backgroundImage={`url(${SmallWhiteCircle})`} backgroundSize="100% auto" /> ) : null} <Heading my={tokenData?.symbol ? 3 : 6} fontSize="22px" color={tokenData?.color ?? "#FFF"} > {subtitle} </Heading> </> ) : null} <Center px={4} mt={isEmpty ? 4 : 0} width="100%"> <Input width="100%" textAlign="center" placeholder={ nav === Nav.CREATE ? t( "Token Address: 0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) : t("RewardsDistributor Address:") } height="40px" variant="filled" size="sm" value={address} onChange={(event) => setAddress(event.target.value)} {...DASHBOARD_BOX_PROPS} _placeholder={{ color: "#e0e0e0" }} _focus={{ bg: "#121212" }} _hover={{ bg: "#282727" }} bg="#282727" /> </Center> {isDeploying && ( <Box my={3} w="100%" h="100%"> <TransactionStepper activeStep={activeStep} tokenData={tokenData} steps={steps} /> </Box> )} {tokenData?.symbol && ( <Box px={4} mt={4} width="100%"> <Button fontWeight="bold" fontSize="2xl" borderRadius="10px" width="100%" height="70px" color={tokenData.overlayTextColor! ?? "#000"} bg={tokenData.color! ?? "#FFF"} _hover={{ transform: "scale(1.02)" }} _active={{ transform: "scale(0.95)" }} // isLoading={isDeploying} disabled={isDeploying} onClick={handleDeploy} > {isDeploying ? steps[activeStep] : nav === Nav.CREATE ? t("Deploy RewardsDistributor") : t("Add RewardsDistributor")} </Button> </Box> )} </Column> </Box> </ModalContent> </Modal> ); }; export default AddRewardsDistributorModal; enum Nav { CREATE = "Create", ADD = "ADD", }