1. Problem1 ```typescript= import { useEffect, useState } from "react"; function getResult(count: number) { return new Promise<number>((resolve) => { const timeout = Math.floor(Math.random() * 1000); const timer = setTimeout(() => { resolve(count); clearTimeout(timer); }, timeout); }); } function useResult() { const [count, setCount] = useState<number>(0); const [result, setResult] = useState<number | "loading">(0); useEffect(() => { setResult("loading"); getResult(count).then(setResult); }, [count]); return [count, setCount, result] as const; } export default useResult; ``` 2. Problem2 ```typescript= const STATE = { AL: "AL", // Alabama AK: "AK", // Alaska AZ: "AZ", // Arizona AR: "AR", // Arkansas }; const STATE_DATA = { POST_CODE: { [STATE.AL]: "01", [STATE.AK]: "02", [STATE.AZ]: "03", [STATE.AR]: "04", }, AREA: { [STATE.AL]: 100, [STATE.AK]: 200, [STATE.AZ]: 300, [STATE.AR]: 400, }, CITIES: { [STATE.AL]: ["city 1", "city 2"], [STATE.AK]: ["city 3", "city 4"], [STATE.AZ]: ["city 5", "city 6"], [STATE.AR]: ["city 7", "city 8"], }, }; function getStateData<T>(data: { [x: string]: T; }, state: string): T { return data[state]; } // Here are some use case. // the editor may be able to infer code as type of string const code = getStateData<string>(STATE_DATA.POST_CODE, STATE.AL); // the editor may be able to infer area as type of number const area = getStateData<number>(STATE_DATA.AREA, STATE.AL); // the editor may be able to infer cities as type of an array of numbers const cities = getStateData<string[]>(STATE_DATA.CITIES, STATE.AZ); ``` 3. Problem3 ```typescript= enum KeyType { Number = 1, DOT = 2, Operator = 3, Clear = 4, Equal = 5, } enum StateType { Start = 1, FirstArg = 2, FirstArgFloat = 3, Operator = 4, SecondArg = 5, SecondArgFloat = 6, SecondArgDot = 7, Equal = 8, } function getNextStateType(key: KeyType, previousStateType: StateType): StateType { switch (previousStateType) { case StateType.Start: if (key === KeyType.Number) { return StateType.FirstArg; } if (key === KeyType.DOT) { return StateType.FirstArgFloat; } break; case StateType.FirstArg: if (key === KeyType.Number) { return StateType.FirstArg; } if (key === KeyType.Operator) { return StateType.Operator; } if (key === KeyType.DOT) { return StateType.FirstArgFloat; } if (key === KeyType.Clear) { return StateType.Start; } break; case StateType.FirstArgFloat: if (key === KeyType.Number) { return StateType.FirstArgFloat; } if (key === KeyType.Operator) { return StateType.Operator; } if (key === KeyType.Clear) { return StateType.Start; } break; case StateType.Operator: if (key === KeyType.Number) { return StateType.SecondArg; } if (key === KeyType.DOT) { return StateType.SecondArgDot; } break; case StateType.SecondArg: if (key === KeyType.DOT) { return StateType.SecondArgFloat; } if (key === KeyType.Number) { return StateType.SecondArg; } if (key === KeyType.Equal) { return StateType.Equal; } if (key === KeyType.Operator) { return StateType.Operator; } if (key === KeyType.Clear) { return StateType.Operator; } break; case StateType.SecondArgFloat: if (key === KeyType.Number) { return StateType.SecondArgFloat; } if (key === KeyType.Equal) { return StateType.Equal; } if (key === KeyType.Operator) { return StateType.Operator; } if (key === KeyType.Clear) { return StateType.Operator; } break; case StateType.SecondArgDot: if (key === KeyType.Number) { return StateType.SecondArgFloat; } if (key === KeyType.Clear) { return StateType.Operator; } break; case StateType.Equal: if (key === KeyType.Equal) { return StateType.Equal; } if (key === KeyType.Number) { return StateType.FirstArg; } if (key === KeyType.Operator) { return StateType.Operator; } if (key === KeyType.DOT) { return StateType.FirstArgFloat; } break; } } ``` 4. Problem4 index.tsx ```typescript= import * as React from "react"; import { createRoot } from 'react-dom/client'; import { App } from "./App"; const container: any = document.getElementById('root'); const root = createRoot(container); root.render( <React.StrictMode> <App /> </React.StrictMode> ); reportWebVitals() ``` App.tsx ```typescript= import { ChakraProvider } from "@chakra-ui/react"; import { DAppProvider } from "@usedapp/core" import theme from "./theme"; import Header from "./components/Header"; import TransferringEthers from "./pages/transferringEthers"; export const App = () => { return ( <DAppProvider config={{}}> <ChakraProvider theme={theme}> <Header /> <TransferringEthers /> </ChakraProvider> </DAppProvider> ); } ``` 主题 index.tsx ```typescript= import { extendTheme } from "@chakra-ui/react"; export default extendTheme({ fonts: { initialColorMode: "light", useSystemColorMode: false }, }); ``` Identicon index.tsx ```typescript= import { useEffect, useRef } from "react"; import { useEthers } from "@usedapp/core"; import Jazzicon from "@metamask/jazzicon"; import styled from "@emotion/styled"; const StyledIdenticon = styled.div` height: 1rem; width: 1rem; border-radius: 1.125rem; background-color: black; `; export default function Identicon() { const ref = useRef<HTMLDivElement>(); const { account } = useEthers(); useEffect(() => { if (account && ref.current) { ref.current.innerHTML = ""; ref.current.appendChild(Jazzicon(16, parseInt(account.slice(2, 10), 16))); } }, [account]); return <StyledIdenticon ref={ref as any} />; } ``` Header index.tsx ```typescript= import { Spacer, Box, Flex, useDisclosure, HStack } from "@chakra-ui/react"; import ConnectButton from "../ConnectButton"; import ModalAccount from "../ModalAccount"; import { ColorModeSwitcher } from "../../ColorModeSwitcher"; function Header() { const { isOpen, onOpen, onClose } = useDisclosure(); return ( <Flex width="90%" margin="auto" p="4" minWidth="500px"> <Spacer /> <HStack> <Box> <ConnectButton handleOpenModal={onOpen} /> {isOpen && <ModalAccount isOpen={isOpen} onClose={onClose} />} </Box> <Box> <ColorModeSwitcher justifySelf="flex-end" /> </Box> </HStack> </Flex> ); } export default Header; ``` ModalAccount index.tsx ```typescript= import { Box, Button, Flex, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalCloseButton, Text, } from "@chakra-ui/react"; import { useEthers } from "@usedapp/core"; import Identicon from "../Identicon"; type Props = { isOpen: any; onClose: any; }; export default function ModalAccount({ isOpen, onClose }: Props) { const { account, deactivate } = useEthers(); function handleDeactivateAccount() { deactivate(); onClose(); } return ( <Modal isOpen={isOpen} onClose={onClose} isCentered size="md"> <ModalOverlay /> <ModalContent background="gray.900" border="1px" borderStyle="solid" borderColor="gray.700" borderRadius="3xl" > <ModalHeader color="white" px={4} fontSize="lg" fontWeight="medium"> 账户 </ModalHeader> <ModalCloseButton color="white" fontSize="sm" _hover={{ color: "whiteAlpha.700", }} /> <ModalBody pt={0} px={4}> <Box borderRadius="3xl" border="1px" borderStyle="solid" borderColor="gray.600" px={5} pt={4} pb={2} mb={3} > <Flex justifyContent="space-between" alignItems="center" mb={3}> <Text color="gray.400" fontSize="sm"> MetaMask </Text> <Button variant="outline" size="sm" borderColor="blue.800" borderRadius="3xl" color="blue.500" fontSize="13px" fontWeight="normal" px={2} height="26px" _hover={{ background: "none", borderColor: "blue.300", textDecoration: "underline", }} onClick={handleDeactivateAccount} > 更改 </Button> </Flex> <Flex alignItems="center" mt={2} mb={4} lineHeight={1}> <Identicon /> <Text color="white" fontSize="xl" fontWeight="semibold" ml="2" lineHeight="1.1" > {`${account?.slice(0, 6)}...${account?.slice( account?.length - 4, account?.length )}`} </Text> </Flex> </Box> </ModalBody> </ModalContent> </Modal> ); } ``` 连接钱包 index.tsx ```typescript= import { Button, Box, Text } from "@chakra-ui/react"; import { useEthers, useEtherBalance } from "@usedapp/core"; import { formatEther } from "@ethersproject/units"; import Identicon from "../Identicon"; type Props = { handleOpenModal: any; }; export default function ConnectButton({ handleOpenModal }: Props) { const { activateBrowserWallet, account } = useEthers(); const etherBalance = useEtherBalance(account); function handleConnectWallet() { activateBrowserWallet(); } return account ? ( <Box display="flex" alignItems="center" background="gray.700" borderRadius="xl" py="0" > <Box px="3"> <Text color="white" fontSize="md"> {etherBalance && parseFloat(formatEther(etherBalance)).toFixed(3)} ETH </Text> </Box> <Button onClick={handleOpenModal} bg="gray.800" border="1px solid transparent" _hover={{ border: "1px", borderStyle: "solid", borderColor: "blue.400", backgroundColor: "gray.700", }} borderRadius="xl" m="1px" px={3} height="38px" > <Text color="white" fontSize="md" fontWeight="medium" mr="2"> {account && `${account.slice(0, 6)}...${account.slice( account.length - 4, account.length )}`} </Text> <Identicon /> </Button> </Box> ) : ( <Button onClick={handleConnectWallet} bg="blue.800" color="blue.300" fontSize="lg" fontWeight="medium" borderRadius="xl" border="1px solid transparent" _hover={{ borderColor: "blue.700", color: "blue.400", }} _active={{ backgroundColor: "blue.800", borderColor: "blue.700", }} > 连接钱包 </Button> ); } ``` 转移比特币 index.tsx ```typescript= import { Box, Button, Center, Flex, FormControl, Input, InputGroup, NumberInput, NumberInputField, useMediaQuery, useToast } from "@chakra-ui/react"; import { useEtherBalance, useEthers, useSendTransaction } from "@usedapp/core"; import { utils } from "ethers"; import { useEffect, useState } from "react"; import { formatEther } from "@ethersproject/units"; const STATUS_CONFIG: any = { "Success": 'success', "Exception": 'error', }; const TransferringEthers: React.FC = () => { const [amount, setAmount] = useState<number>(0); const [receipent, setReceipent] = useState<string>(''); const [disabledButton, setDisabledButton] = useState<boolean>(true); const [isLoading, setIsLoading] = useState<boolean>(false); const [isTablet] = useMediaQuery("(min-width: 750px)"); const [isMobile] = useMediaQuery("(min-width: 320px)"); const { sendTransaction, state } = useSendTransaction(); const { account } = useEthers(); const etherBalance = useEtherBalance(account); const toast = useToast(); const [buttonText,setButtonText] = useState<string>('转移'); const handleAmountInputChange = (e: any) => { setAmount(e?.target?.value); } const handlesetReceipentInputChange = (e: any) => { setReceipent(e?.target?.value); } const handleTransfer = () => { setIsLoading(true); sendTransaction({ to: receipent, value: utils.parseEther(amount.toString()) }); } useEffect(() => { if (amount > 0 && receipent) { setDisabledButton(false); } }, [amount, receipent]) const toastMessage = (values: any) => { toast({ title: `${values?.errorMessage}`, status: STATUS_CONFIG[values?.status], isClosable: true, position: "top", }) } useEffect(() => { if (state?.status === "Exception" || state?.status === "Success" || state?.status === "Fail") { setIsLoading(false); toastMessage(state); } }, [state, toastMessage]) useEffect(() => { if (etherBalance && amount) { const count = formatEther(etherBalance); if(Number(amount) > Number(count)) { setButtonText('余额不足'); setDisabledButton(true); } else { setButtonText('转移'); setDisabledButton(false); } } }, [amount, etherBalance]); return ( <> <Flex margin="auto" paddingTop={isMobile ? "10vh" : isTablet ? "12vh" : "15vh"} width="100%" minWidth="500px" > <FormControl isRequired> <Box w="450px" borderRadius="35px" m="auto" backgroundColor="withAlpha(gray.900, 0.9)" boxShadow="2xl" p="25px" > <Box id="Receipent Field" p="5" height="80px" backgroundColor="gray.100" borderRadius="25" > <Flex> <InputGroup> <Input id="receipent" p="0" border="0" placeholder="账户" w="100%" focusBorderColor="none" onChange={handlesetReceipentInputChange} disabled={isLoading} /> </InputGroup> </Flex> </Box> <Flex height="2"></Flex> <Box id="Amount Field" p="5" height="80px" backgroundColor="gray.100" borderRadius="25" > <Flex> <InputGroup> <NumberInput w="100%" focusBorderColor="none"> <NumberInputField id="amount" p="0" placeholder="0.0" border="0" onChange={handleAmountInputChange} disabled={isLoading} /> </NumberInput> </InputGroup> </Flex> </Box> <Flex height="2"></Flex> <Center> <Button id="Transfer Button" border="0" w="100%" h="60px" borderRadius="25" onClick={handleTransfer} isDisabled={disabledButton} isLoading={isLoading} loadingText='正在转移中...' colorScheme='pink' > {buttonText} </Button> </Center> </Box> </FormControl> </Flex> </> ); } export default TransferringEthers; ```