2019 年 12 月,Alchemy 完成1500 万美元 A 轮融资,资方为 Pantera Capital,斯坦福大学,Coinbase,三星等。
2021 年 4 月,Alchemy 以 5.05 亿美元估值完成8000 万美元 B 轮融资,Coatue 和 Addition 领投,DFJ Growth、K5 Global、Chainsmokers(烟鬼组合)、演员 Jared Leto 和 Glazer 家族参投。
2021 年 10 月,Alchemy 以 35 亿美元估值完成2.5 亿美元 C 轮融资,由 a16z 领投的。
2022 年 2 月,Alchemy 以 102 亿美元估值完成2 亿美元融资,Lightspeed 与 Silver Lake 领投。
Alchemy 是一个背景强大、经费充足、踏实做事、没有发币的团队,这样的项目不刷,难道去刷土狗吗?
并且,Alchemy 计划将新资金用于推广 Web3 采用,这方面的一些举措包括推出 Web3 University,就是现在的 Road to Web3 活动,活动为期 10 周,每周一个 NFT。看了下 nft 数量极少,估计由于任务难度大,很多小伙伴直接放弃,这样的项目若是空投,绝对是大毛。
从 git 官网下载 windows 版本的 git:http://git-scm.com/downloads
一般使用默认设置即可:一路 next,最后 install,git 安装完毕!
1.在控制台输入 git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git challenge-1-decentralized-staking ,按回车,等一会下载完毕。
2.控制台输入 cd challenge-1-decentralized-staking,再按回车。
3.控制台输入 git checkout challenge-1-decentralized-staking ,按回车。
4.控制台输入 yarn install ,按回车,多等一会。
5.都装好后,在 challenge-1-decentralized-staking 这个文件夹中应该能看到这样的目录。
注意:在本教程中,我们将主要致力于 Staker.sol
和 App.jsx
.这两个文件的代码编写。
注意,接下来用到三个单独的控制台,我开了三个控制台。
1.在控制台输入 yarn chain,启动您的安全帽后端。
2.再开一个控制台,cd 进入那个文件夹,在控制台输入 yarn deploy。
3.再开一个控制台,cd 进入那个文件夹,在控制台输入 yarn start ,启动你的 React 前端。
然后我们就可以看到网页跳出了这个页面!!!
在我们的默认视图中,我们有两个选项卡—— Staker UI
& Debug Contracts
.
1.往本地钱包发送测试币,先不要点那个连接!复制右上角的地址(这就是本地地址),然后粘贴到右下角,点击小飞机。
2.可以看到下面有提示,并且左上角余额发生变化。
3.或者这里也可以,点击 send。充值本地钱包后,您将能够与您的合约进行交互!
1.打开 vscode,点击 open folder,找到你创建的那个文件夹,点击选择文件夹。
2.找到 packages——hardhat——contracts——Staker.sol
3.将下面的代码直接复制粘贴进去。(官方链接对每一步都做了解释,很有意思,感兴趣的可以看一下每段代码对应的模块功能, 而不是单纯的粘贴最终代码哈哈,但是用官方代码的话,第 78 行的rewardRatePerBlock要改成rewardRatePerSecond,下面这个是改好的)
// SPDX-License-Identifier: MITpragma solidity 0.8.4;import "hardhat/console.sol";import "./ExampleExternalContract.sol";contract Staker { ExampleExternalContract public exampleExternalContract; mapping(address => uint256) public balances; mapping(address => uint256) public depositTimestamps; uint256 public constant rewardRatePerSecond = 0.1 ether; uint256 public withdrawalDeadline = block.timestamp + 120 seconds; uint256 public claimDeadline = block.timestamp + 240 seconds; uint256 public currentBlock = 0; // Events event Stake(address indexed sender, uint256 amount); event Received(address, uint); event Execute(address indexed sender, uint256 amount); // Modifiers /* Checks if the withdrawal period has been reached or not */ modifier withdrawalDeadlineReached( bool requireReached ) { uint256 timeRemaining = withdrawalTimeLeft(); if( requireReached ) { require(timeRemaining == 0, "Withdrawal period is not reached yet"); } else { require(timeRemaining > 0, "Withdrawal period has been reached"); } _; } /* Checks if the claim period has ended or not */ modifier claimDeadlineReached( bool requireReached ) { uint256 timeRemaining = claimPeriodLeft(); if( requireReached ) { require(timeRemaining == 0, "Claim deadline is not reached yet"); } else { require(timeRemaining > 0, "Claim deadline has been reached"); } _; } /* Requires that the contract only be completed once! */ modifier notCompleted() { bool completed = exampleExternalContract.completed(); require(!completed, "Stake already completed!"); _; } constructor(address exampleExternalContractAddress){ exampleExternalContract = ExampleExternalContract(exampleExternalContractAddress); } // Stake function for a user to stake ETH in our contract function stake() public payable withdrawalDeadlineReached(false) claimDeadlineReached(false){ balances[msg.sender] = balances[msg.sender] + msg.value; depositTimestamps[msg.sender] = block.timestamp; emit Stake(msg.sender, msg.value); } /* Withdraw function for a user to remove their staked ETH inclusive of both principal and any accrued interest */ function withdraw() public withdrawalDeadlineReached(true) claimDeadlineReached(false) notCompleted{ require(balances[msg.sender] > 0, "You have no balance to withdraw!"); uint256 individualBalance = balances[msg.sender]; uint256 indBalanceRewards = individualBalance + ((block.timestamp-depositTimestamps[msg.sender])*rewardRatePerSecond); balances[msg.sender] = 0; // Transfer all ETH via call! (not transfer) cc: https://solidity-by-example.org/sending-ether (bool sent, bytes memory data) = msg.sender.call{value: indBalanceRewards}(""); require(sent, "RIP; withdrawal failed :( "); } /* Allows any user to repatriate "unproductive" funds that are left in the staking contract past the defined withdrawal period */ function execute() public claimDeadlineReached(true) notCompleted { uint256 contractBalance = address(this).balance; exampleExternalContract.complete{value: address(this).balance}(); } /* READ-ONLY function to calculate the time remaining before the minimum staking period has passed */ function withdrawalTimeLeft() public view returns (uint256 withdrawalTimeLeft) { if( block.timestamp >= withdrawalDeadline) { return (0); } else { return (withdrawalDeadline - block.timestamp); } } /* READ-ONLY function to calculate the time remaining before the minimum staking period has passed */ function claimPeriodLeft() public view returns (uint256 claimPeriodLeft) { if( block.timestamp >= claimDeadline) { return (0); } else { return (claimDeadline - block.timestamp); } } /* Time to "kill-time" on our local testnet */ function killTime() public { currentBlock = block.timestamp; } /* \Function for our smart contract to receive ETH cc: https://docs.soliditylang.org/en/latest/contracts.html#receive-ether-function */ receive() external payable { emit Received(msg.sender, msg.value); }}
1.找到 packages——react-app——src——App.jsx 。官方链接对每一步都做了解释,很有意思,感兴趣的可以看一下每段代码对应的模块功能, 而不是单纯的粘贴最终代码哈哈)
2.将如下代码复制粘贴进去。
import WalletConnectProvider from "@walletconnect/web3-provider";//import Torus from "@toruslabs/torus-embed"import WalletLink from "walletlink";import { Alert, Button, Col, Menu, Row, List, Divider } from "antd";import "antd/dist/antd.css";import React, { useCallback, useEffect, useState } from "react";import { BrowserRouter, Link, Route, Switch } from "react-router-dom";import Web3Modal from "web3modal";import "./App.css";import { Account, Address, Balance, Contract, Faucet, GasGauge, Header, Ramp, ThemeSwitch } from "./components";import { INFURA_ID, NETWORK, NETWORKS } from "./constants";import { Transactor } from "./helpers";import { useBalance, useContractLoader, useContractReader, useGasPrice, useOnBlock, useUserProviderAndSigner,} from "eth-hooks";import { useEventListener } from "eth-hooks/events/useEventListener";import { useExchangeEthPrice } from "eth-hooks/dapps/dex";// import Hints from "./Hints";import { ExampleUI, Hints, Subgraph } from "./views";import { useContractConfig } from "./hooks";import Portis from "@portis/web3";import Fortmatic from "fortmatic";import Authereum from "authereum";import humanizeDuration from "humanize-duration";const { ethers } = require("ethers");/* Welcome to 🏗 scaffold-eth ! Code: https://github.com/austintgriffith/scaffold-eth Support: https://t.me/joinchat/KByvmRe5wkR-8F_zz6AjpA or DM @austingriffith on Twitter or Telegram You should get your own Infura.io ID and put it in `constants.js` (this is your connection to the main Ethereum network for ENS etc.) 🌏 EXTERNAL CONTRACTS: You can also bring in contract artifacts in `constants.js` (and then use the `useExternalContractLoader()` hook!)*//// 📡 What chain are your contracts deployed to?const targetNetwork = NETWORKS.localhost; // <------- select your target frontend network (localhost, rinkeby, xdai, mainnet)// 😬 Sorry for all the console loggingconst DEBUG = true;const NETWORKCHECK = true;// 🛰 providersif (DEBUG) console.log("📡 Connecting to Mainnet Ethereum");// const mainnetProvider = getDefaultProvider("mainnet", { infura: INFURA_ID, etherscan: ETHERSCAN_KEY, quorum: 1 });// const mainnetProvider = new InfuraProvider("mainnet",INFURA_ID);//// attempt to connect to our own scaffold eth rpc and if that fails fall back to infura...// Using StaticJsonRpcProvider as the chainId won't change see https://github.com/ethers-io/ethers.js/issues/901const scaffoldEthProvider = navigator.onLine ? new ethers.providers.StaticJsonRpcProvider("https://rpc.scaffoldeth.io:48544") : null;const poktMainnetProvider = navigator.onLine ? new ethers.providers.StaticJsonRpcProvider( "https://eth-mainnet.gateway.pokt.network/v1/lb/611156b4a585a20035148406", ) : null;const mainnetInfura = navigator.onLine ? new ethers.providers.StaticJsonRpcProvider("https://mainnet.infura.io/v3/" + INFURA_ID) : null;// ( ⚠️ Getting "failed to meet quorum" errors? Check your INFURA_ID// 🏠 Your local provider is usually pointed at your local blockchainconst localProviderUrl = targetNetwork.rpcUrl;// as you deploy to other networks you can set REACT_APP_PROVIDER=https://dai.poa.network in packages/react-app/.envconst localProviderUrlFromEnv = process.env.REACT_APP_PROVIDER ? process.env.REACT_APP_PROVIDER : localProviderUrl;if (DEBUG) console.log("🏠 Connecting to provider:", localProviderUrlFromEnv);const localProvider = new ethers.providers.StaticJsonRpcProvider(localProviderUrlFromEnv);// 🔭 block explorer URLconst blockExplorer = targetNetwork.blockExplorer;// Coinbase walletLink initconst walletLink = new WalletLink({ appName: "coinbase",});// WalletLink providerconst walletLinkProvider = walletLink.makeWeb3Provider(`https://mainnet.infura.io/v3/${INFURA_ID}`, 1);// Portis ID: 6255fb2b-58c8-433b-a2c9-62098c05ddc9/* Web3 modal helps us "connect" external wallets:*/const web3Modal = new Web3Modal({ network: "mainnet", // Optional. If using WalletConnect on xDai, change network to "xdai" and add RPC info below for xDai chain. cacheProvider: true, // optional theme: "light", // optional. Change to "dark" for a dark theme. providerOptions: { walletconnect: { package: WalletConnectProvider, // required options: { bridge: "https://polygon.bridge.walletconnect.org", infuraId: INFURA_ID, rpc: { 1: `https://mainnet.infura.io/v3/${INFURA_ID}`, // mainnet // For more WalletConnect providers: https://docs.walletconnect.org/quick-start/dapps/web3-provider#required 42: `https://kovan.infura.io/v3/${INFURA_ID}`, 100: "https://dai.poa.network", // xDai }, }, }, portis: { display: { logo: "https://user-images.githubusercontent.com/9419140/128913641-d025bc0c-e059-42de-a57b-422f196867ce.png", name: "Portis", description: "Connect to Portis App", }, package: Portis, options: { id: "6255fb2b-58c8-433b-a2c9-62098c05ddc9", }, }, fortmatic: { package: Fortmatic, // required options: { key: "pk_live_5A7C91B2FC585A17", // required }, }, // torus: { // package: Torus, // options: { // networkParams: { // host: "https://localhost:8545", // optional // chainId: 1337, // optional // networkId: 1337 // optional // }, // config: { // buildEnv: "development" // optional // }, // }, // }, "custom-walletlink": { display: { logo: "https://play-lh.googleusercontent.com/PjoJoG27miSglVBXoXrxBSLveV6e3EeBPpNY55aiUUBM9Q1RCETKCOqdOkX2ZydqVf0", name: "Coinbase", description: "Connect to Coinbase Wallet (not Coinbase App)", }, package: walletLinkProvider, connector: async (provider, _options) => { await provider.enable(); return provider; }, }, authereum: { package: Authereum, // required }, },});function App(props) { const mainnetProvider = poktMainnetProvider && poktMainnetProvider._isProvider ? poktMainnetProvider : scaffoldEthProvider && scaffoldEthProvider._network ? scaffoldEthProvider : mainnetInfura; const [injectedProvider, setInjectedProvider] = useState(); const [address, setAddress] = useState(); const logoutOfWeb3Modal = async () => { await web3Modal.clearCachedProvider(); if (injectedProvider && injectedProvider.provider && typeof injectedProvider.provider.disconnect == "function") { await injectedProvider.provider.disconnect(); } setTimeout(() => { window.location.reload(); }, 1); }; /* 💵 This hook will get the price of ETH from 🦄 Uniswap: */ const price = useExchangeEthPrice(targetNetwork, mainnetProvider); /* 🔥 This hook will get the price of Gas from ⛽️ EtherGasStation */ const gasPrice = useGasPrice(targetNetwork, "fast"); // Use your injected provider from 🦊 Metamask or if you don't have it then instantly generate a 🔥 burner wallet. const userProviderAndSigner = useUserProviderAndSigner(injectedProvider, localProvider); const userSigner = userProviderAndSigner.signer; useEffect(() => { async function getAddress() { if (userSigner) { const newAddress = await userSigner.getAddress(); setAddress(newAddress); } } getAddress(); }, [userSigner]); // You can warn the user if you would like them to be on a specific network const localChainId = localProvider && localProvider._network && localProvider._network.chainId; const selectedChainId = userSigner && userSigner.provider && userSigner.provider._network && userSigner.provider._network.chainId; // For more hooks, check out 🔗eth-hooks at: https://www.npmjs.com/package/eth-hooks // The transactor wraps transactions and provides notificiations const tx = Transactor(userSigner, gasPrice); // Faucet Tx can be used to send funds from the faucet const faucetTx = Transactor(localProvider, gasPrice); // 🏗 scaffold-eth is full of handy hooks like this one to get your balance: const yourLocalBalance = useBalance(localProvider, address); // Just plug in different 🛰 providers to get your balance on different chains: const yourMainnetBalance = useBalance(mainnetProvider, address); const contractConfig = useContractConfig(); // Load in your local 📝 contract and read a value from it: const readContracts = useContractLoader(localProvider, contractConfig); // If you want to make 🔐 write transactions to your contracts, use the userSigner: const writeContracts = useContractLoader(userSigner, contractConfig, localChainId); // EXTERNAL CONTRACT EXAMPLE: // // If you want to bring in the mainnet DAI contract it would look like: const mainnetContracts = useContractLoader(mainnetProvider, contractConfig); // If you want to call a function on a new block useOnBlock(mainnetProvider, () => { console.log(`⛓ A new mainnet block is here: ${mainnetProvider._lastBlockNumber}`); }); // Then read your DAI balance like: const myMainnetDAIBalance = useContractReader(mainnetContracts, "DAI", "balanceOf", [ "0x34aA3F359A9D614239015126635CE7732c18fDF3", ]); //keep track of contract balance to know how much has been staked total: const stakerContractBalance = useBalance( localProvider, readContracts && readContracts.Staker ? readContracts.Staker.address : null, ); if (DEBUG) console.log("💵 stakerContractBalance", stakerContractBalance); const rewardRatePerSecond = useContractReader(readContracts, "Staker", "rewardRatePerSecond"); console.log("💵 Reward Rate:", rewardRatePerSecond); // ** keep track of a variable from the contract in the local React state: const balanceStaked = useContractReader(readContracts, "Staker", "balances", [address]); console.log("💸 balanceStaked:", balanceStaked); // ** 📟 Listen for broadcast events const stakeEvents = useEventListener(readContracts, "Staker", "Stake", localProvider, 1); console.log("📟 stake events:", stakeEvents); const receiveEvents = useEventListener(readContracts, "Staker", "Received", localProvider, 1); console.log("📟 receive events:", receiveEvents); // ** keep track of a variable from the contract in the local React state: const claimPeriodLeft = useContractReader(readContracts, "Staker", "claimPeriodLeft"); console.log("⏳ Claim Period Left:", claimPeriodLeft); const withdrawalTimeLeft = useContractReader(readContracts, "Staker", "withdrawalTimeLeft"); console.log("⏳ Withdrawal Time Left:", withdrawalTimeLeft); // ** Listen for when the contract has been 'completed' const complete = useContractReader(readContracts, "ExampleExternalContract", "completed"); console.log("✅ complete:", complete); const exampleExternalContractBalance = useBalance( localProvider, readContracts && readContracts.ExampleExternalContract ? readContracts.ExampleExternalContract.address : null, ); if (DEBUG) console.log("💵 exampleExternalContractBalance", exampleExternalContractBalance); let completeDisplay = ""; if (complete) { completeDisplay = ( <div style={{padding: 64, backgroundColor: "#eeffef", fontWeight: "bold", color: "rgba(0, 0, 0, 0.85)" }} > -- 💀 Staking App Fund Repatriation Executed 🪦 -- <Balance balance={exampleExternalContractBalance} fontSize={32} /> ETH locked! </div> ); } /* const addressFromENS = useResolveName(mainnetProvider, "austingriffith.eth"); console.log("🏷 Resolved austingriffith.eth as:", addressFromENS) */ // // 🧫 DEBUG 👨🏻🔬 // useEffect(() => { if ( DEBUG && mainnetProvider && address && selectedChainId && yourLocalBalance && yourMainnetBalance && readContracts && writeContracts && mainnetContracts ) { console.log("_____________________________________ 🏗 scaffold-eth _____________________________________"); console.log("🌎 mainnetProvider", mainnetProvider); console.log("🏠 localChainId", localChainId); console.log("👩💼 selected address:", address); console.log("🕵🏻♂️ selectedChainId:", selectedChainId); console.log("💵 yourLocalBalance", yourLocalBalance ? ethers.utils.formatEther(yourLocalBalance) : "..."); console.log("💵 yourMainnetBalance", yourMainnetBalance ? ethers.utils.formatEther(yourMainnetBalance) : "..."); console.log("📝 readContracts", readContracts); console.log("🌍 DAI contract on mainnet:", mainnetContracts); console.log("💵 yourMainnetDAIBalance", myMainnetDAIBalance); console.log("🔐 writeContracts", writeContracts); } }, [ mainnetProvider, address, selectedChainId, yourLocalBalance, yourMainnetBalance, readContracts, writeContracts, mainnetContracts, ]); let networkDisplay = ""; if (NETWORKCHECK && localChainId && selectedChainId && localChainId !== selectedChainId) { const networkSelected = NETWORK(selectedChainId); const networkLocal = NETWORK(localChainId); if (selectedChainId === 1337 && localChainId === 31337) { networkDisplay = ( <div style={{ zIndex: 2, position: "absolute", right: 0, top: 60, padding: 16 }}> <Alert message="⚠️ Wrong Network ID" description={ <div> You have <b>chain id 1337</b> for localhost and you need to change it to <b>31337</b> to work with HardHat. <div>(MetaMask -> Settings -> Networks -> Chain ID -> 31337)</div> </div> } type="error" closable={false} /> </div> ); } else { networkDisplay = ( <div style={{ zIndex: 2, position: "absolute", right: 0, top: 60, padding: 16 }}> <Alert message="⚠️ Wrong Network" description={ <div> You have <b>{networkSelected && networkSelected.name}</b> selected and you need to be on{" "} <Button onClick={async () => { const ethereum = window.ethereum; const data = [ { chainId: "0x" + targetNetwork.chainId.toString(16), chainName: targetNetwork.name, nativeCurrency: targetNetwork.nativeCurrency, rpcUrls: [targetNetwork.rpcUrl], blockExplorerUrls: [targetNetwork.blockExplorer], }, ]; console.log("data", data); let switchTx; // https://docs.metamask.io/guide/rpc-api.html#other-rpc-methods try { switchTx = await ethereum.request({ method: "wallet_switchEthereumChain", params: [{ chainId: data[0].chainId }], }); } catch (switchError) { // not checking specific error code, because maybe we're not using MetaMask try { switchTx = await ethereum.request({ method: "wallet_addEthereumChain", params: data, }); } catch (addError) { // handle "add" error } } if (switchTx) { console.log(switchTx); } }} > <b>{networkLocal && networkLocal.name}</b> </Button> </div> } type="error" closable={false} /> </div> ); } } else { networkDisplay = ( <div style={{ zIndex: -1, position: "absolute", right: 154, top: 28, padding: 16, color: targetNetwork.color }}> {targetNetwork.name} </div> ); } const loadWeb3Modal = useCallback(async () => { const provider = await web3Modal.connect(); setInjectedProvider(new ethers.providers.Web3Provider(provider)); provider.on("chainChanged", chainId => { console.log(`chain changed to ${chainId}! updating providers`); setInjectedProvider(new ethers.providers.Web3Provider(provider)); }); provider.on("accountsChanged", () => { console.log(`account changed!`); setInjectedProvider(new ethers.providers.Web3Provider(provider)); }); // Subscribe to session disconnection provider.on("disconnect", (code, reason) => { console.log(code, reason); logoutOfWeb3Modal(); }); }, [setInjectedProvider]); useEffect(() => { if (web3Modal.cachedProvider) { loadWeb3Modal(); } }, [loadWeb3Modal]); const [route, setRoute] = useState(); useEffect(() => { setRoute(window.location.pathname); }, [setRoute]); let faucetHint = ""; const faucetAvailable = localProvider && localProvider.connection && targetNetwork.name.indexOf("local") !== -1; const [faucetClicked, setFaucetClicked] = useState(false); if ( !faucetClicked && localProvider && localProvider._network && localProvider._network.chainId === 31337 && yourLocalBalance && ethers.utils.formatEther(yourLocalBalance) <= 0 ) { faucetHint = ( <div style={{ padding: 16 }}> <Button type="primary" onClick={() => { faucetTx({ to: address, value: ethers.utils.parseEther("0.01"), }); setFaucetClicked(true); }} > 💰 Grab funds from the faucet ⛽️ </Button> </div> ); } return ( <div className="App"> {/* ✏️ Edit the header and change the title to your project name */} <Header /> {networkDisplay} <BrowserRouter> <Menu style={{ textAlign: "center" }} selectedKeys={[route]} mode="horizontal"> <Menu.Item key="/"> <Link onClick={() => { setRoute("/"); }} to="/" > Staker UI </Link> </Menu.Item> <Menu.Item key="/contracts"> <Link onClick={() => { setRoute("/contracts"); }} to="/contracts" > Debug Contracts </Link> </Menu.Item> </Menu> <Switch> <Route exact path="/"> {completeDisplay} <div style={{ padding: 8, marginTop: 16 }}> <div>Staker Contract:</div> <Address value={readContracts && readContracts.Staker && readContracts.Staker.address} /> </div> <Divider /> <div style={{ padding: 8, marginTop: 16 }}> <div>Reward Rate Per Second:</div> <Balance balance={rewardRatePerSecond} fontSize={64} /> ETH </div> <Divider /> <div style={{ padding: 8, marginTop: 16, fontWeight: "bold" }}> <div>Claim Period Left:</div> {claimPeriodLeft && humanizeDuration(claimPeriodLeft.toNumber() * 1000)} </div> <div style={{ padding: 8, marginTop: 16, fontWeight: "bold"}}> <div>Withdrawal Period Left:</div> {withdrawalTimeLeft && humanizeDuration(withdrawalTimeLeft.toNumber() * 1000)} </div> <Divider /> <div style={{ padding: 8, fontWeight: "bold"}}> <div>Total Available ETH in Contract:</div> <Balance balance={stakerContractBalance} fontSize={64} /> </div> <Divider /> <div style={{ padding: 8,fontWeight: "bold" }}> <div>ETH Locked 🔒 in Staker Contract:</div> <Balance balance={balanceStaked} fontSize={64} /> </div> <div style={{ padding: 8 }}> <Button type={"default"} onClick={() => { tx(writeContracts.Staker.execute()); }} > 📡 Execute! </Button> </div> <div style={{ padding: 8 }}> <Button type={"default"} onClick={() => { tx(writeContracts.Staker.withdraw()); }} > 🏧 Withdraw </Button> </div> <div style={{ padding: 8 }}> <Button type={balanceStaked ? "success" : "primary"} onClick={() => { tx(writeContracts.Staker.stake({ value: ethers.utils.parseEther("0.5") })); }} > 🥩 Stake 0.5 ether! </Button> </div> {/* 🎛 this scaffolding is full of commonly used components this <Contract/> component will automatically parse your ABI and give you a form to interact with it locally */} {/* uncomment for a second contract: <Contract name="SecondContract" signer={userProvider.getSigner()} provider={localProvider} address={address} blockExplorer={blockExplorer} contractConfig={contractConfig} /> */} </Route> <Route path="/contracts"> <Contract name="Staker" signer={userSigner} provider={localProvider} address={address} blockExplorer={blockExplorer} contractConfig={contractConfig} /> <Contract name="ExampleExternalContract" signer={userSigner} provider={localProvider} address={address} blockExplorer={blockExplorer} contractConfig={contractConfig} /> </Route> </Switch> </BrowserRouter> <ThemeSwitch /> {/* 👨💼 Your account is in the top right with a wallet at connect options */} <div style={{ position: "fixed", textAlign: "right", right: 0, top: 0, padding: 10 }}> <Account address={address} localProvider={localProvider} userSigner={userSigner} mainnetProvider={mainnetProvider} price={price} web3Modal={web3Modal} loadWeb3Modal={loadWeb3Modal} logoutOfWeb3Modal={logoutOfWeb3Modal} blockExplorer={blockExplorer} /> {faucetHint} </div> <div style={{ marginTop: 32, opacity: 0.5 }}> {/* Add your address here */} Created by <Address value={"Your...address"} ensProvider={mainnetProvider} fontSize={16} /> </div> <div style={{ marginTop: 32, opacity: 0.5 }}> <a target="_blank" style={{ padding: 32, color: "#000" }} href="https://github.com/scaffold-eth/scaffold-eth"> 🍴 Fork me! </a> </div> {/* 🗺 Extra UI like gas price, eth price, faucet, and support: */} <div style={{ position: "fixed", textAlign: "left", left: 0, bottom: 20, padding: 10 }}> <Row align="middle" gutter={[4, 4]}> <Col span={8}> <Ramp price={price} address={address} networks={NETWORKS} /> </Col> <Col span={8} style={{ textAlign: "center", opacity: 0.8 }}> <GasGauge gasPrice={gasPrice} /> </Col> <Col span={8} style={{ textAlign: "center", opacity: 1 }}> <Button onClick={() => { window.open("https://t.me/joinchat/KByvmRe5wkR-8F_zz6AjpA"); }} size="large" shape="round" > <span style={{ marginRight: 8 }} role="img" aria-label="support"> 💬 </span> Support </Button> </Col> </Row> <Row align="middle" gutter={[4, 4]}> <Col span={24}> { /* if the local provider has a signer, let's show the faucet: */ faucetAvailable ? ( <Faucet localProvider={localProvider} price={price} ensProvider={mainnetProvider} /> ) : ( "" ) } </Col> </Row> </div> </div> );}export default App;
3.再打开控制台,输入 yarn deploy –reset,可以看到前端界面和刚才有细微差别。
4.测试 stake 功能,点击 stake,测试一下,据说正常部署都会提示取款时间已过。。。
1.登录 github,点击 New。
2.这三个地方填一下,然后直接拉到最下面,点击 Create repository。
3.点击 code,复制仓库地址备用。
4..接下来就到本地操作了,首先确保你已经成功安装 Git 这个软件,在电脑上找到你要上传到 Github 上面的那个项目文件夹,进入项目文件夹,单击鼠标右键,选择 Git Bash Here,如下图所示。
5.接下来输入如下代码(关键步骤),把 github 上面的仓库克隆到本地
6.这个步骤以后你的本地项目文件夹下面就会多出个文件夹,该文件夹名即为你 github 上面的项目名,如图我多出了个 road-to-web3-06 文件夹,我们把本地项目文件夹下的所有文件(除了新多出的那个文件夹不用),其余都复制到那个新多出的文件夹下。(扔那里不管,去打把王者再回来差不多就复制完成了,电脑慢的去打把 dota 回来估计差不多了,毕竟时间要用在刀刃上)
7.接着继续输入命令 cd road-to-web3-06,进入 road-to-web3-06 文件夹(road-to-web3-06 是我建的仓库,这里应该改成你自己的仓库名字)
8.接下来依次输入以下代码即可完成其他剩余操作:
git add . (注:别忘记后面的 . ,此操作是把 Test 文件夹下面的文件都添加进来)
git commit -m ”提交信息” (注:“提交信息”里面换成你需要,也可以不管,这里可能会出现如下第一张图提示,按照提示输入 git config –global user.email “you@example.com”git config –global user.name “Your Name” 就可以了 )
git push -u origin main (注:此操作目的是把本地仓库 push 到 github 上面,此步骤需要你输入帐号和密码)
9.第一次使用 Git,会弹框要求登录,把这个码复制下来。
10.点第九步码下面那个链接,进去登录自己的 git 账号,然后把把复制粘贴在这里,授权就可以了。
11.复制这个链接即可。
提交链接
前几周的内容在推特@greta0086 看哦
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。