
Minting Financial Pass xรฃ hแปi ฤแบงu tiรชn trรชn thแบฟ giแปi: แปจng dแปฅng Dopamine X CyberConnect
Khi thแบฟ giแปi tร i chรญnh vร web3 ngร y cร ng trแป nรชn kแบฟt nแปi, ฤiแปu quan trแปng hฦกn bao giแป hแบฟt lร ฤแบฃm bแบฃo rแบฑng cรกc giao dแปch tร i chรญnh ฤฦฐแปฃc an toร n vร bแบฃo mแบญt. Mแปt trong nhแปฏng mแปi quan tรขm cแบฅp bรกch nhแบฅt trong lฤฉnh vแปฑc tร i chรญnh truyแปn thแปng vร hiแปn tแบกi lร trong khรดng gian tiแปn ฤiแปn tแปญ lร rแปญa tiแปn, liรชn quan ฤแบฟn viแปc ngแปฅy tแบกo sแป tiแปn thu ฤฦฐแปฃc tแปซ hoแบกt ฤแปng bแบฅt hแปฃp phรกp thร nh tiแปn hแปฃp phรกp. ฤแป chแปng lแบกi mแปi ฤe dแปa nร y, cรกc tแป chแปฉc tร i chรญnh trรชn toร n thแบฟ giแปi phแบฃi tuรขn thแปง cรกc quy ฤแปnh vแป Chแปng rแปญa t...

5 Lessons "For a Lifetime" Thanks to the Collapse of UST and Luna
The loss of UST's peg and the severe collapse of LUNA resulted in significant damage, both financially and psychologically. This article provides insights into some of the lessons that can be learned from this incident.UST Loses Peg, LUNA Crashes, and 5 Lessons for a LifetimePerhaps many people have suffered due to the recent loss of UST's peg and the collapse of LUNA. Money has been lost and the market continues to move on. So, what can we learn from this event? Here are five lesso...

Alchemy Road to web3 week5 เธเธนเนเธกเธทเธญเธ เธฒเธฉเธฒเนเธเธข
เนเธกเธทเนเธญเนเธกเนเธเธฒเธเธกเธฒเธเธตเนเนเธเธฃเนเธเธ Alchemy เนเธเนเนเธเนเธฒเธชเธนเน web3 เธเนเธงเธขเธกเธนเธฅเธเนเธฒ 10.2 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธฅเธฐเนเธเนเธฃเธฑเธเธเธฒเธฃเธฃเธฐเธเธกเธเธธเธ 545 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน. Alchemy เธเธทเธญเนเธเธฃเนเธเธเธญเธฐเนเธฃ๏ผ Alchemy เธเธทเธญเนเธเธฅเธเธเธญเธฃเนเธกเธชเธณเธซเธฃเธฑเธเธเธฑเธเธเธฑเธเธเธฒ dApp เธเธ web3. เนเธเนเธเธฃเธฒเธเธเธฒเธเธเธตเนเธญเธขเธนเนเนเธเธทเนเธญเธเธซเธฅเธฑเธเธเธฅเธฒเธ NFT เธขเธญเธเธเธดเธขเธกเธญเธขเนเธฒเธ OpenSea, Nifty เนเธฅเธฐเธเธญเธฅเนเธฅเนเธเธเธฑเนเธเธฃเธฐเธเธฑเธเนเธฅเธเธเธตเนเธชเธณเธเธฑเธเธกเธฒเธเธกเธฒเธข. 12/2019, Alchemy เนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series A เธกเธนเธฅเธเนเธฒ 15 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเธเธฒเธ Pantera Capital, Stanford University, Coinbase, Samsung,โฆ 4/2021, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series B เธกเธนเธฅเธเนเธฒ 80 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน...

Minting Financial Pass xรฃ hแปi ฤแบงu tiรชn trรชn thแบฟ giแปi: แปจng dแปฅng Dopamine X CyberConnect
Khi thแบฟ giแปi tร i chรญnh vร web3 ngร y cร ng trแป nรชn kแบฟt nแปi, ฤiแปu quan trแปng hฦกn bao giแป hแบฟt lร ฤแบฃm bแบฃo rแบฑng cรกc giao dแปch tร i chรญnh ฤฦฐแปฃc an toร n vร bแบฃo mแบญt. Mแปt trong nhแปฏng mแปi quan tรขm cแบฅp bรกch nhแบฅt trong lฤฉnh vแปฑc tร i chรญnh truyแปn thแปng vร hiแปn tแบกi lร trong khรดng gian tiแปn ฤiแปn tแปญ lร rแปญa tiแปn, liรชn quan ฤแบฟn viแปc ngแปฅy tแบกo sแป tiแปn thu ฤฦฐแปฃc tแปซ hoแบกt ฤแปng bแบฅt hแปฃp phรกp thร nh tiแปn hแปฃp phรกp. ฤแป chแปng lแบกi mแปi ฤe dแปa nร y, cรกc tแป chแปฉc tร i chรญnh trรชn toร n thแบฟ giแปi phแบฃi tuรขn thแปง cรกc quy ฤแปnh vแป Chแปng rแปญa t...

5 Lessons "For a Lifetime" Thanks to the Collapse of UST and Luna
The loss of UST's peg and the severe collapse of LUNA resulted in significant damage, both financially and psychologically. This article provides insights into some of the lessons that can be learned from this incident.UST Loses Peg, LUNA Crashes, and 5 Lessons for a LifetimePerhaps many people have suffered due to the recent loss of UST's peg and the collapse of LUNA. Money has been lost and the market continues to move on. So, what can we learn from this event? Here are five lesso...

Alchemy Road to web3 week5 เธเธนเนเธกเธทเธญเธ เธฒเธฉเธฒเนเธเธข
เนเธกเธทเนเธญเนเธกเนเธเธฒเธเธกเธฒเธเธตเนเนเธเธฃเนเธเธ Alchemy เนเธเนเนเธเนเธฒเธชเธนเน web3 เธเนเธงเธขเธกเธนเธฅเธเนเธฒ 10.2 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธฅเธฐเนเธเนเธฃเธฑเธเธเธฒเธฃเธฃเธฐเธเธกเธเธธเธ 545 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน. Alchemy เธเธทเธญเนเธเธฃเนเธเธเธญเธฐเนเธฃ๏ผ Alchemy เธเธทเธญเนเธเธฅเธเธเธญเธฃเนเธกเธชเธณเธซเธฃเธฑเธเธเธฑเธเธเธฑเธเธเธฒ dApp เธเธ web3. เนเธเนเธเธฃเธฒเธเธเธฒเธเธเธตเนเธญเธขเธนเนเนเธเธทเนเธญเธเธซเธฅเธฑเธเธเธฅเธฒเธ NFT เธขเธญเธเธเธดเธขเธกเธญเธขเนเธฒเธ OpenSea, Nifty เนเธฅเธฐเธเธญเธฅเนเธฅเนเธเธเธฑเนเธเธฃเธฐเธเธฑเธเนเธฅเธเธเธตเนเธชเธณเธเธฑเธเธกเธฒเธเธกเธฒเธข. 12/2019, Alchemy เนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series A เธกเธนเธฅเธเนเธฒ 15 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเธเธฒเธ Pantera Capital, Stanford University, Coinbase, Samsung,โฆ 4/2021, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series B เธกเธนเธฅเธเนเธฒ 80 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน...

Subscribe to JQ

Subscribe to JQ
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers


เนเธกเธทเนเธญเนเธกเนเธเธฒเธเธกเธฒเธเธตเนเนเธเธฃเนเธเธ Alchemy เนเธเนเนเธเนเธฒเธชเธนเน web3 เธเนเธงเธขเธกเธนเธฅเธเนเธฒ 10.2 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธฅเธฐเนเธเนเธฃเธฑเธเธเธฒเธฃเธฃเธฐเธเธกเธเธธเธ 545 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน.
Alchemy เธเธทเธญเนเธเธฃเนเธเธเธญเธฐเนเธฃ๏ผ
Alchemy เธเธทเธญเนเธเธฅเธเธเธญเธฃเนเธกเธชเธณเธซเธฃเธฑเธเธเธฑเธเธเธฑเธเธเธฒ dApp เธเธ web3. เนเธเนเธเธฃเธฒเธเธเธฒเธเธเธตเนเธญเธขเธนเนเนเธเธทเนเธญเธเธซเธฅเธฑเธเธเธฅเธฒเธ NFT เธขเธญเธเธเธดเธขเธกเธญเธขเนเธฒเธ OpenSea, Nifty เนเธฅเธฐเธเธญเธฅเนเธฅเนเธเธเธฑเนเธเธฃเธฐเธเธฑเธเนเธฅเธเธเธตเนเธชเธณเธเธฑเธเธกเธฒเธเธกเธฒเธข.
12/2019, Alchemy เนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series A เธกเธนเธฅเธเนเธฒ 15 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเธเธฒเธ Pantera Capital, Stanford University, Coinbase, Samsung,โฆ
4/2021, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series B เธกเธนเธฅเธเนเธฒ 80 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธเธขเธกเธตเธกเธนเธฅเธเนเธฒ 505 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เธเธณเนเธเธข Coatue and Addition เนเธเธขเธกเธตเธชเนเธงเธเธฃเนเธงเธกเธเธฒเธ DFJ Growth, K5 Global, Chainsmokers, เธเธฑเธเนเธชเธเธ Jared Leto เนเธฅเธฐเธเธฃเธญเธเธเธฃเธฑเธง Glazer.
10/2021, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series C เธกเธนเธฅเธเนเธฒ 250 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธเธขเธกเธตเธกเธนเธฅเธเนเธฒ 3.5 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เธเธณเนเธเธข a16z.
2/2022, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ 200 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเนเธเธขเธกเธตเธกเธนเธฅเธเนเธฒ 10.2 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเธเธถเนเธเธเธณเนเธเธข Lightspeed เนเธฅเธฐ Silver Lake.
Alchemy เนเธเนเธเธเธตเธกเธเธตเนเธกเธตเธเธทเนเธเธเธฒเธเธเธตเนเนเธเนเธเนเธเธฃเนเธ, เนเธเธดเธเธเธธเธเธเธตเนเนเธเธตเธขเธเธเธญ, เธเธณเธเธฒเธเธเธฃเธดเธ, เนเธฅเธฐเธขเธฑเธเนเธกเนเนเธเนเธญเธญเธ token.
เนเธฅเธฐ Alchemy เธงเธฒเธเนเธเธเธเธตเนเธเธฐเนเธเนเนเธเธดเธเธเธธเธเนเธซเธกเนเธเธตเนเนเธเธทเนเธญเธเธฃเธฐเธเธธเนเธเธเธฒเธฃเนเธเนเธเธฒเธ Web3, เธเธฒเธเธชเนเธงเธเธฃเธงเธกเธเธถเธเธเธฒเธฃเนเธเธดเธเธเธฑเธง Web3 University, เธเธถเนเธเธเธฑเธเธเธธเธเธฑเธเนเธเนเธเธเธฒเธ Road to Web3 เนเธเนเธเนเธงเธฅเธฒ 10 เธชเธฑเธเธเธฒเธซเนเธเนเธงเธขเธซเธเธถเนเธ NFT เธเนเธญเธชเธฑเธเธเธฒเธซเน. เธเธกเนเธซเนเธเธงเนเธฒเธเธณเธเธงเธ nfts เธเธตเนเธกเธดเนเธเธญเธญเธเธกเธฒเธเธฑเนเธเธเนเธญเธขเธกเธฒเธ เธเธฒเธเธงเนเธฒเนเธเธทเนเธญเธเธเธฒเธเธเธงเธฒเธกเธขเธฒเธเธเธญเธเธเธฒเธ เธเธเธเธณเธเธงเธเธกเธฒเธเธเธถเธเธขเธญเธกเนเธเนเธเธตเนเธเธฐเนเธเนเธฒเธฃเนเธงเธก, เธซเธฒเธเนเธเธฃเนเธเธเธเธตเนเธกเธต Airdrop เธชเนเธงเธเธเธฑเธงเธเธกเธกเธญเธเธงเนเธฒเธเนเธฒเธเธฐเนเธเนเนเธขเธญเธฐเธญเธขเนเธฒเธเนเธเนเธเธญเธ.
เธเธฒเธงเธเนเนเธซเธฅเธ git เนเธงเธญเธฃเนเธเธฑเนเธ windows เธเธฒเธเนเธงเนเธเนเธเธเนเธเธฒเธเธเธฒเธฃเธเธญเธ git: http://git-scm.com/downloads

เนเธเธขเธเธฑเนเธงเนเธ, เธเธธเธเธชเธฒเธกเธฒเธฃเธเนเธเนเธเธฒเธฃเธเธฑเนเธเธเนเธฒเนเธฃเธดเนเธกเธเนเธเนเธเน: เธเธ next เนเธเธเธเนเธฃเธทเนเธญเธขเน เนเธฅเธฐเธชเธธเธเธเนเธฒเธขเธเธ install.
1.เธเนเธญเธ git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git challenge-1-decentralized-staking เนเธ console เธเธ Enter เนเธฅเธฐเธฃเธญเธชเธฑเธเธเธฃเธนเนเนเธเธทเนเธญเนเธซเนเธเธฒเธฃเธเธฒเธงเธเนเนเธซเธฅเธเนเธชเธฃเนเธเธชเธดเนเธ.

2. เธเนเธญเธ cd challenge-1-decentralized-staking เนเธ console เนเธฅเนเธงเธเธ Enter.

3. เธเนเธญเธ git checkout challenge-1-decentralized-staking เนเธ console เนเธฅเนเธงเธเธ Enter.

4. เธเนเธญเธ yarn install เนเธ console เนเธฅเนเธงเธเธ Enter เนเธเธทเนเธญเธเธดเธเธเธฑเนเธ yarn เนเธฅเธฐเธฃเธญเธชเธฑเธเธเธฃเธนเนเธเธเธเธงเนเธฒเธเธฐเธเธดเธเธเธฑเนเธเนเธชเธฃเนเธ.

5. เธซเธฅเธฑเธเธเธฒเธเธเธดเธเธเธฑเนเธเธเธธเธเธญเธขเนเธฒเธเนเธฅเนเธง เธเธธเธเธเธงเธฃเนเธซเนเธเนเธเธฅเนเธเธญเธฃเน challenge-1-decentralized-staking.

เธซเธกเธฒเธขเนเธซเธเธธ: เนเธเธเธเธเนเธงเธขเธชเธญเธเธเธตเน เนเธฃเธฒเธเธฐเนเธเนเธเนเธเธตเธขเธ code เนเธเธเธตเนเธชเธญเธเนเธเธฅเน Staker.sol เนเธฅเธฐ App.jsx เนเธเนเธเธซเธฅเธฑเธ


เนเธเธฃเธเธเธฃเธฒเธเธงเนเธฒเธเนเธญเนเธเธเธฐเนเธเน console เนเธขเธเธเธฑเธเธชเธฒเธกเธเธฑเธง, เนเธฅเธฐเธเธกเนเธเนเนเธเธดเธ console เธชเธฒเธกเธเธฑเธงเนเธงเน.
1. เธเธดเธกเธเน yarn chain เนเธ console เนเธเธทเนเธญเนเธฃเธดเนเธก back end hardhat เธเธญเธเธเธธเธ.

2. เนเธเธดเธ console เธญเธทเนเธ, เธเนเธญเธ cd เธฅเธเนเธเนเธเธฅเนเธเธญเธฃเนเธเธฑเนเธ เนเธฅเธฐเธเนเธญเธ yarn deploy เธเนเธญเนเธ console.

3. เนเธเธดเธ console เธญเธทเนเธ, เธเนเธญเธ cd เธฅเธเนเธเนเธเธฅเนเธเธญเธฃเนเธเธฑเนเธ เนเธฅเธฐเธเธดเธกเธเน yarn start เนเธ console เนเธเธทเนเธญเนเธฃเธดเนเธกเธชเนเธงเธเธซเธเนเธฒ React เธเธญเธเธเธธเธ.

เนเธฅเนเธงเนเธฃเธฒเธเธฐเนเธซเนเธเธซเธเนเธฒเธเธตเน.

เนเธเธกเธธเธกเธกเธญเธเนเธฃเธดเนเธกเธเนเธเธเธญเธเนเธฃเธฒ, เนเธฃเธฒเธกเธตเธชเธญเธเนเธเนเธ - Staker UI & Debug Contracts.

1. เนเธญเธฒ public address เธเธฒเธเธกเธธเธกเธเธงเธฒเธเธเธกเธฒเนเธชเนเธเธฃเธเธเนเธญเธเธเนเธฒเธเธฅเนเธฒเธ, เธเธฒเธเธเธฑเนเธเธเธฅเธดเธเธชเนเธ token test เนเธเธเธตเน public wallet (เธญเธขเนเธฒเธเธ connect wallet).

2. เธเธธเธเธเธฐเนเธซเนเธเธขเธญเธเธเธเนเธซเธฅเธทเธญเธเธตเนเธกเธธเธกเธเธงเธฒเธเธเธกเธตเธเธฒเธฃเนเธเธฅเธตเนเธขเธเนเธเธฅเธ.

3. เธซเธฅเธฑเธเธเธฒเธเนเธเธดเธกเนเธเธดเธเนเธ public wallet เธเธญเธเธเธธเธเนเธฅเนเธงเธเธฅเธดเธ เธเธ send.

1. เนเธเธดเธ vscode เธเธฅเธดเธ เนเธเธดเธเนเธเธฅเนเธเธญเธฃเน, เธเนเธเธซเธฒเนเธเธฅเนเธเธญเธฃเนเธเธตเนเธเธธเธเธชเธฃเนเธฒเธ เนเธฅเนเธงเธเธฅเธดเธเนเธเธทเนเธญเนเธฅเธทเธญเธเนเธเธฅเนเธเธญเธฃเน.


2.เนเธเธดเธ packagesโhardhatโโcontractsโโStaker.sol.

3. เธเธฑเธเธฅเธญเธเนเธฅเธฐเธงเธฒเธเนเธเนเธเธเนเธญเนเธเธเธตเนเธฅเธเนเธเนเธเธฅเนเนเธเธขเธเธฃเธ (เธฅเธดเธเธเนเธญเธขเนเธฒเธเนเธเนเธเธเธฒเธเธเธฒเธฃเธเธฐเธญเธเธดเธเธฒเธขเนเธเนเธฅเธฐ step เธเนเธฒเธชเธเนเธเธเนเธชเธฒเธกเธฒเธฃเธเนเธเนเธฒเนเธเธเธน module function เธเธตเนเธเธฃเธเธเธฑเธเนเธเนเธเนเธเนเธฅเธฐเธชเนเธงเธเนเธเธเธเธฒเธฃ paste เธฃเธงเธเนเธเธตเธขเธงเนเธเธเธเธตเนเนเธเนเนเธฅเธขเธเธฃเธฑเธ, เนเธเนเธเนเธฒเธเธฐเนเธเนเนเธเนเธเธเธญเธ official เธเนเธญเธเนเธเธฅเธตเนเธขเธ rewardRatePerBlock เนเธเธเธฃเธฃเธเธฑเธเธเธตเน 78 เนเธเนเธ rewardRatePerSecond เธเนเธงเธข).
1. เธเนเธเธซเธฒ packagesโโreact-appโโsrcโโApp.jsx.

2. เธเธฑเธเธฅเธญเธเนเธฅเธฐเธงเธฒเธเนเธเนเธเธเนเธญเนเธเธเธตเนเธฅเธเนเธเนเธเธฅเนเนเธเธขเธเธฃเธ (เธฅเธดเธเธเนเธญเธขเนเธฒเธเนเธเนเธเธเธฒเธเธเธฒเธฃเธเธฐเธญเธเธดเธเธฒเธขเนเธเนเธฅเธฐ step เธเนเธฒเธชเธเนเธเธเนเธชเธฒเธกเธฒเธฃเธเนเธเนเธฒเนเธเธเธน module function เธเธตเนเธเธฃเธเธเธฑเธเนเธเนเธเนเธเนเธฅเธฐเธชเนเธงเธเนเธเธเธเธฒเธฃ paste เธฃเธงเธเนเธเธตเธขเธงเนเธเธเธเธตเนเนเธเนเนเธฅเธขเธเธฃเธฑเธ).
3. เนเธเธดเธ console เธญเธตเธเธเธฃเธฑเนเธ, เธเนเธญเธ yarn deploy --reset เนเธฅเนเธงเธเธธเธเธเธฐเนเธซเนเธเธงเนเธฒเธซเธเนเธฒเนเธงเนเธเนเธเธเธเนเธฒเธเธเธฒเธเธเนเธญเธเธซเธเนเธฒเธเธตเนเนเธฅเนเธเธเนเธญเธข.

4. เธเธเธชเธญเธเธเธฑเธเธเนเธเธฑเนเธ stake เธเธฅเธดเธ stake เธเนเธฒเนเธเนเธเธงเนเธฒเธซเธกเธเนเธงเธฅเธฒเธเธฒเธฃเธเธญเธเนเธฅเนเธงเธเธทเธญเธเธเธเธด.

เธเธฑเนเธเธเธญเธเธญเธฑเธเนเธเธฅเนเธเธญเธฃเนเนเธเธฃเนเธเธเธฅเธ github เธกเธตเธกเธฒเธเธกเธฒเธขเนเธกเนเธงเนเธฒเธเธฐเนเธเนเธเนเธเธดเธ git bash เนเธฅเนเธงเธญเธฑเธเธฅเธเธเนเธงเธข code, เธญเธฑเธเธเธฃเธเธเธฒเธ vscode เธฅเธญเธเนเธเธซเธฒเนเธ Google, youtube เธเธน. เธซเธฃเธทเธญเธชเธฒเธกเธฒเธฃเธเธญเธฑเธเนเธเธ github desktop เนเธซเธกเธทเธญเธเธชเธฑเธเธเธฒเธฃเนเธเนเธญเธเธซเธเนเธฒเธเธตเนเนเธเนเธเธฃเธฑเธ.
https://docs.google.com/forms/d/e/1FAIpQLSdNNLXMYZmIhjcWoT-UedS3AoGpRiPDRaNARUPGXLbX1TVvSg/viewform
เนเธฃเธฒเธชเธฒเธกเธฒเธฃเธเนเธเนเธ nft เธเธตเนเนเธฃเธฒเธขเธฑเธเนเธกเนเนเธเนเนเธเธฅเธกเนเธเนเธเธฐเธเธฃเธฑเธเนเธเธขเนเธเนเธฒเนเธเธเธตเน mintkudos เธเธฒเธเธเธฑเนเธเธเนเธญเธเธฃเธฐเนเธเนเธฒเธกเธธเธกเธเธงเธฒเธกเธทเธญเธฅเธญเธเธเธเนเธเนเธเธเธนเธเนเธฒเธกเธตเธเธฅเธธเนเธก claim เนเธเธฅเธงเนเธฒเนเธฃเธฒเธกเธต nft เธเธตเนเนเธฃเธฒเธชเธฒเธกเธฒเธฃเธเนเธเธฅเธกเนเธเนเนเธเนเนเธฃเธฒเธขเธฑเธเนเธกเนเนเธเนเนเธเธฅเธก.

เนเธเนเธฒเธเธตเนเธเนเธเธเธเธฑเธเนเธเนเธฅเนเธงเธเธฐเธเธฃเธฑเธเธเธฑเธ Alchemy Road to web3 week6 เนเธเธฃเธกเธตเธเธณเธเธฒเธก เธซเธฃเธทเธญเธชเธเธชเธฑเธขเธขเธฑเธเนเธเธชเธฒเธกเธฒเธฃเธเธเธฒเธกเนเธเน. เธชเนเธงเธเนเธเธฃเธเธตเนเธญเธขเธฒเธเธเธฐเธชเธเธฑเธเธชเธเธธเธเธเนเธฒเธเธฒเนเธเนเธซเนเธเธนเนเนเธเธตเธขเธเธชเธฒเธกเธฒเธฃเธเธเธเธเธธเนเธก Collect Entry เนเธเนเธเธตเนเธเนเธฒเธเธฅเนเธฒเธเธเธตเนเธเธฒเธเธเธฑเนเธเนเธฃเธฒเธเธฐเนเธเน nft เธเธเธเธงเธฒเธกเธเธญเธ mirror.xyz chain optimism เนเธฅเธฐเธชเธฒเธกเธฒเธฃเธเนเธเนเธ nft เธเธตเนเนเธฃเธฒ collect เธกเธฒเนเธเนเธเธตเน QxProfile.
collect://
เนเธกเธทเนเธญเนเธกเนเธเธฒเธเธกเธฒเธเธตเนเนเธเธฃเนเธเธ Alchemy เนเธเนเนเธเนเธฒเธชเธนเน web3 เธเนเธงเธขเธกเธนเธฅเธเนเธฒ 10.2 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธฅเธฐเนเธเนเธฃเธฑเธเธเธฒเธฃเธฃเธฐเธเธกเธเธธเธ 545 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน.
Alchemy เธเธทเธญเนเธเธฃเนเธเธเธญเธฐเนเธฃ๏ผ
Alchemy เธเธทเธญเนเธเธฅเธเธเธญเธฃเนเธกเธชเธณเธซเธฃเธฑเธเธเธฑเธเธเธฑเธเธเธฒ dApp เธเธ web3. เนเธเนเธเธฃเธฒเธเธเธฒเธเธเธตเนเธญเธขเธนเนเนเธเธทเนเธญเธเธซเธฅเธฑเธเธเธฅเธฒเธ NFT เธขเธญเธเธเธดเธขเธกเธญเธขเนเธฒเธ OpenSea, Nifty เนเธฅเธฐเธเธญเธฅเนเธฅเนเธเธเธฑเนเธเธฃเธฐเธเธฑเธเนเธฅเธเธเธตเนเธชเธณเธเธฑเธเธกเธฒเธเธกเธฒเธข.
12/2019, Alchemy เนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series A เธกเธนเธฅเธเนเธฒ 15 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเธเธฒเธ Pantera Capital, Stanford University, Coinbase, Samsung,โฆ
4/2021, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series B เธกเธนเธฅเธเนเธฒ 80 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธเธขเธกเธตเธกเธนเธฅเธเนเธฒ 505 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เธเธณเนเธเธข Coatue and Addition เนเธเธขเธกเธตเธชเนเธงเธเธฃเนเธงเธกเธเธฒเธ DFJ Growth, K5 Global, Chainsmokers, เธเธฑเธเนเธชเธเธ Jared Leto เนเธฅเธฐเธเธฃเธญเธเธเธฃเธฑเธง Glazer.
10/2021, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ Series C เธกเธนเธฅเธเนเธฒ 250 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เนเธเธขเธกเธตเธกเธนเธฅเธเนเธฒ 3.5 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเน เธเธณเนเธเธข a16z.
2/2022, Alchemy เนเธเนเนเธชเธฃเนเธเธชเธดเนเธเธเธฒเธฃเธเธฑเธเธซเธฒเนเธเธดเธเธเธธเธ 200 เธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเนเธเธขเธกเธตเธกเธนเธฅเธเนเธฒ 10.2 เธเธฑเธเธฅเนเธฒเธเธเธญเธฅเธฅเธฒเธฃเนเธเธถเนเธเธเธณเนเธเธข Lightspeed เนเธฅเธฐ Silver Lake.
Alchemy เนเธเนเธเธเธตเธกเธเธตเนเธกเธตเธเธทเนเธเธเธฒเธเธเธตเนเนเธเนเธเนเธเธฃเนเธ, เนเธเธดเธเธเธธเธเธเธตเนเนเธเธตเธขเธเธเธญ, เธเธณเธเธฒเธเธเธฃเธดเธ, เนเธฅเธฐเธขเธฑเธเนเธกเนเนเธเนเธญเธญเธ token.
เนเธฅเธฐ Alchemy เธงเธฒเธเนเธเธเธเธตเนเธเธฐเนเธเนเนเธเธดเธเธเธธเธเนเธซเธกเนเธเธตเนเนเธเธทเนเธญเธเธฃเธฐเธเธธเนเธเธเธฒเธฃเนเธเนเธเธฒเธ Web3, เธเธฒเธเธชเนเธงเธเธฃเธงเธกเธเธถเธเธเธฒเธฃเนเธเธดเธเธเธฑเธง Web3 University, เธเธถเนเธเธเธฑเธเธเธธเธเธฑเธเนเธเนเธเธเธฒเธ Road to Web3 เนเธเนเธเนเธงเธฅเธฒ 10 เธชเธฑเธเธเธฒเธซเนเธเนเธงเธขเธซเธเธถเนเธ NFT เธเนเธญเธชเธฑเธเธเธฒเธซเน. เธเธกเนเธซเนเธเธงเนเธฒเธเธณเธเธงเธ nfts เธเธตเนเธกเธดเนเธเธญเธญเธเธกเธฒเธเธฑเนเธเธเนเธญเธขเธกเธฒเธ เธเธฒเธเธงเนเธฒเนเธเธทเนเธญเธเธเธฒเธเธเธงเธฒเธกเธขเธฒเธเธเธญเธเธเธฒเธ เธเธเธเธณเธเธงเธเธกเธฒเธเธเธถเธเธขเธญเธกเนเธเนเธเธตเนเธเธฐเนเธเนเธฒเธฃเนเธงเธก, เธซเธฒเธเนเธเธฃเนเธเธเธเธตเนเธกเธต Airdrop เธชเนเธงเธเธเธฑเธงเธเธกเธกเธญเธเธงเนเธฒเธเนเธฒเธเธฐเนเธเนเนเธขเธญเธฐเธญเธขเนเธฒเธเนเธเนเธเธญเธ.
เธเธฒเธงเธเนเนเธซเธฅเธ git เนเธงเธญเธฃเนเธเธฑเนเธ windows เธเธฒเธเนเธงเนเธเนเธเธเนเธเธฒเธเธเธฒเธฃเธเธญเธ git: http://git-scm.com/downloads

เนเธเธขเธเธฑเนเธงเนเธ, เธเธธเธเธชเธฒเธกเธฒเธฃเธเนเธเนเธเธฒเธฃเธเธฑเนเธเธเนเธฒเนเธฃเธดเนเธกเธเนเธเนเธเน: เธเธ next เนเธเธเธเนเธฃเธทเนเธญเธขเน เนเธฅเธฐเธชเธธเธเธเนเธฒเธขเธเธ install.
1.เธเนเธญเธ git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git challenge-1-decentralized-staking เนเธ console เธเธ Enter เนเธฅเธฐเธฃเธญเธชเธฑเธเธเธฃเธนเนเนเธเธทเนเธญเนเธซเนเธเธฒเธฃเธเธฒเธงเธเนเนเธซเธฅเธเนเธชเธฃเนเธเธชเธดเนเธ.

2. เธเนเธญเธ cd challenge-1-decentralized-staking เนเธ console เนเธฅเนเธงเธเธ Enter.

3. เธเนเธญเธ git checkout challenge-1-decentralized-staking เนเธ console เนเธฅเนเธงเธเธ Enter.

4. เธเนเธญเธ yarn install เนเธ console เนเธฅเนเธงเธเธ Enter เนเธเธทเนเธญเธเธดเธเธเธฑเนเธ yarn เนเธฅเธฐเธฃเธญเธชเธฑเธเธเธฃเธนเนเธเธเธเธงเนเธฒเธเธฐเธเธดเธเธเธฑเนเธเนเธชเธฃเนเธ.

5. เธซเธฅเธฑเธเธเธฒเธเธเธดเธเธเธฑเนเธเธเธธเธเธญเธขเนเธฒเธเนเธฅเนเธง เธเธธเธเธเธงเธฃเนเธซเนเธเนเธเธฅเนเธเธญเธฃเน challenge-1-decentralized-staking.

เธซเธกเธฒเธขเนเธซเธเธธ: เนเธเธเธเธเนเธงเธขเธชเธญเธเธเธตเน เนเธฃเธฒเธเธฐเนเธเนเธเนเธเธตเธขเธ code เนเธเธเธตเนเธชเธญเธเนเธเธฅเน Staker.sol เนเธฅเธฐ App.jsx เนเธเนเธเธซเธฅเธฑเธ


เนเธเธฃเธเธเธฃเธฒเธเธงเนเธฒเธเนเธญเนเธเธเธฐเนเธเน console เนเธขเธเธเธฑเธเธชเธฒเธกเธเธฑเธง, เนเธฅเธฐเธเธกเนเธเนเนเธเธดเธ console เธชเธฒเธกเธเธฑเธงเนเธงเน.
1. เธเธดเธกเธเน yarn chain เนเธ console เนเธเธทเนเธญเนเธฃเธดเนเธก back end hardhat เธเธญเธเธเธธเธ.

2. เนเธเธดเธ console เธญเธทเนเธ, เธเนเธญเธ cd เธฅเธเนเธเนเธเธฅเนเธเธญเธฃเนเธเธฑเนเธ เนเธฅเธฐเธเนเธญเธ yarn deploy เธเนเธญเนเธ console.

3. เนเธเธดเธ console เธญเธทเนเธ, เธเนเธญเธ cd เธฅเธเนเธเนเธเธฅเนเธเธญเธฃเนเธเธฑเนเธ เนเธฅเธฐเธเธดเธกเธเน yarn start เนเธ console เนเธเธทเนเธญเนเธฃเธดเนเธกเธชเนเธงเธเธซเธเนเธฒ React เธเธญเธเธเธธเธ.

เนเธฅเนเธงเนเธฃเธฒเธเธฐเนเธซเนเธเธซเธเนเธฒเธเธตเน.

เนเธเธกเธธเธกเธกเธญเธเนเธฃเธดเนเธกเธเนเธเธเธญเธเนเธฃเธฒ, เนเธฃเธฒเธกเธตเธชเธญเธเนเธเนเธ - Staker UI & Debug Contracts.

1. เนเธญเธฒ public address เธเธฒเธเธกเธธเธกเธเธงเธฒเธเธเธกเธฒเนเธชเนเธเธฃเธเธเนเธญเธเธเนเธฒเธเธฅเนเธฒเธ, เธเธฒเธเธเธฑเนเธเธเธฅเธดเธเธชเนเธ token test เนเธเธเธตเน public wallet (เธญเธขเนเธฒเธเธ connect wallet).

2. เธเธธเธเธเธฐเนเธซเนเธเธขเธญเธเธเธเนเธซเธฅเธทเธญเธเธตเนเธกเธธเธกเธเธงเธฒเธเธเธกเธตเธเธฒเธฃเนเธเธฅเธตเนเธขเธเนเธเธฅเธ.

3. เธซเธฅเธฑเธเธเธฒเธเนเธเธดเธกเนเธเธดเธเนเธ public wallet เธเธญเธเธเธธเธเนเธฅเนเธงเธเธฅเธดเธ เธเธ send.

1. เนเธเธดเธ vscode เธเธฅเธดเธ เนเธเธดเธเนเธเธฅเนเธเธญเธฃเน, เธเนเธเธซเธฒเนเธเธฅเนเธเธญเธฃเนเธเธตเนเธเธธเธเธชเธฃเนเธฒเธ เนเธฅเนเธงเธเธฅเธดเธเนเธเธทเนเธญเนเธฅเธทเธญเธเนเธเธฅเนเธเธญเธฃเน.


2.เนเธเธดเธ packagesโhardhatโโcontractsโโStaker.sol.

3. เธเธฑเธเธฅเธญเธเนเธฅเธฐเธงเธฒเธเนเธเนเธเธเนเธญเนเธเธเธตเนเธฅเธเนเธเนเธเธฅเนเนเธเธขเธเธฃเธ (เธฅเธดเธเธเนเธญเธขเนเธฒเธเนเธเนเธเธเธฒเธเธเธฒเธฃเธเธฐเธญเธเธดเธเธฒเธขเนเธเนเธฅเธฐ step เธเนเธฒเธชเธเนเธเธเนเธชเธฒเธกเธฒเธฃเธเนเธเนเธฒเนเธเธเธน module function เธเธตเนเธเธฃเธเธเธฑเธเนเธเนเธเนเธเนเธฅเธฐเธชเนเธงเธเนเธเธเธเธฒเธฃ paste เธฃเธงเธเนเธเธตเธขเธงเนเธเธเธเธตเนเนเธเนเนเธฅเธขเธเธฃเธฑเธ, เนเธเนเธเนเธฒเธเธฐเนเธเนเนเธเนเธเธเธญเธ official เธเนเธญเธเนเธเธฅเธตเนเธขเธ rewardRatePerBlock เนเธเธเธฃเธฃเธเธฑเธเธเธตเน 78 เนเธเนเธ rewardRatePerSecond เธเนเธงเธข).
1. เธเนเธเธซเธฒ packagesโโreact-appโโsrcโโApp.jsx.

2. เธเธฑเธเธฅเธญเธเนเธฅเธฐเธงเธฒเธเนเธเนเธเธเนเธญเนเธเธเธตเนเธฅเธเนเธเนเธเธฅเนเนเธเธขเธเธฃเธ (เธฅเธดเธเธเนเธญเธขเนเธฒเธเนเธเนเธเธเธฒเธเธเธฒเธฃเธเธฐเธญเธเธดเธเธฒเธขเนเธเนเธฅเธฐ step เธเนเธฒเธชเธเนเธเธเนเธชเธฒเธกเธฒเธฃเธเนเธเนเธฒเนเธเธเธน module function เธเธตเนเธเธฃเธเธเธฑเธเนเธเนเธเนเธเนเธฅเธฐเธชเนเธงเธเนเธเธเธเธฒเธฃ paste เธฃเธงเธเนเธเธตเธขเธงเนเธเธเธเธตเนเนเธเนเนเธฅเธขเธเธฃเธฑเธ).
3. เนเธเธดเธ console เธญเธตเธเธเธฃเธฑเนเธ, เธเนเธญเธ yarn deploy --reset เนเธฅเนเธงเธเธธเธเธเธฐเนเธซเนเธเธงเนเธฒเธซเธเนเธฒเนเธงเนเธเนเธเธเธเนเธฒเธเธเธฒเธเธเนเธญเธเธซเธเนเธฒเธเธตเนเนเธฅเนเธเธเนเธญเธข.

4. เธเธเธชเธญเธเธเธฑเธเธเนเธเธฑเนเธ stake เธเธฅเธดเธ stake เธเนเธฒเนเธเนเธเธงเนเธฒเธซเธกเธเนเธงเธฅเธฒเธเธฒเธฃเธเธญเธเนเธฅเนเธงเธเธทเธญเธเธเธเธด.

เธเธฑเนเธเธเธญเธเธญเธฑเธเนเธเธฅเนเธเธญเธฃเนเนเธเธฃเนเธเธเธฅเธ github เธกเธตเธกเธฒเธเธกเธฒเธขเนเธกเนเธงเนเธฒเธเธฐเนเธเนเธเนเธเธดเธ git bash เนเธฅเนเธงเธญเธฑเธเธฅเธเธเนเธงเธข code, เธญเธฑเธเธเธฃเธเธเธฒเธ vscode เธฅเธญเธเนเธเธซเธฒเนเธ Google, youtube เธเธน. เธซเธฃเธทเธญเธชเธฒเธกเธฒเธฃเธเธญเธฑเธเนเธเธ github desktop เนเธซเธกเธทเธญเธเธชเธฑเธเธเธฒเธฃเนเธเนเธญเธเธซเธเนเธฒเธเธตเนเนเธเนเธเธฃเธฑเธ.
https://docs.google.com/forms/d/e/1FAIpQLSdNNLXMYZmIhjcWoT-UedS3AoGpRiPDRaNARUPGXLbX1TVvSg/viewform
เนเธฃเธฒเธชเธฒเธกเธฒเธฃเธเนเธเนเธ nft เธเธตเนเนเธฃเธฒเธขเธฑเธเนเธกเนเนเธเนเนเธเธฅเธกเนเธเนเธเธฐเธเธฃเธฑเธเนเธเธขเนเธเนเธฒเนเธเธเธตเน mintkudos เธเธฒเธเธเธฑเนเธเธเนเธญเธเธฃเธฐเนเธเนเธฒเธกเธธเธกเธเธงเธฒเธกเธทเธญเธฅเธญเธเธเธเนเธเนเธเธเธนเธเนเธฒเธกเธตเธเธฅเธธเนเธก claim เนเธเธฅเธงเนเธฒเนเธฃเธฒเธกเธต nft เธเธตเนเนเธฃเธฒเธชเธฒเธกเธฒเธฃเธเนเธเธฅเธกเนเธเนเนเธเนเนเธฃเธฒเธขเธฑเธเนเธกเนเนเธเนเนเธเธฅเธก.

เนเธเนเธฒเธเธตเนเธเนเธเธเธเธฑเธเนเธเนเธฅเนเธงเธเธฐเธเธฃเธฑเธเธเธฑเธ Alchemy Road to web3 week6 เนเธเธฃเธกเธตเธเธณเธเธฒเธก เธซเธฃเธทเธญเธชเธเธชเธฑเธขเธขเธฑเธเนเธเธชเธฒเธกเธฒเธฃเธเธเธฒเธกเนเธเน. เธชเนเธงเธเนเธเธฃเธเธตเนเธญเธขเธฒเธเธเธฐเธชเธเธฑเธเธชเธเธธเธเธเนเธฒเธเธฒเนเธเนเธซเนเธเธนเนเนเธเธตเธขเธเธชเธฒเธกเธฒเธฃเธเธเธเธเธธเนเธก Collect Entry เนเธเนเธเธตเนเธเนเธฒเธเธฅเนเธฒเธเธเธตเนเธเธฒเธเธเธฑเนเธเนเธฃเธฒเธเธฐเนเธเน nft เธเธเธเธงเธฒเธกเธเธญเธ mirror.xyz chain optimism เนเธฅเธฐเธชเธฒเธกเธฒเธฃเธเนเธเนเธ nft เธเธตเนเนเธฃเธฒ collect เธกเธฒเนเธเนเธเธตเน QxProfile.
collect://
// SPDX-License-Identifier: MIT
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);
}
}
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 logging
const DEBUG = true;
const NETWORKCHECK = true;
// ๐ฐ providers
if (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/901
const 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 blockchain
const localProviderUrl = targetNetwork.rpcUrl;
// as you deploy to other networks you can set REACT_APP_PROVIDER=https://dai.poa.network in packages/react-app/.env
const 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 URL
const blockExplorer = targetNetwork.blockExplorer;
// Coinbase walletLink init
const walletLink = new WalletLink({
appName: "coinbase",
});
// WalletLink provider
const 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;
// SPDX-License-Identifier: MIT
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);
}
}
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 logging
const DEBUG = true;
const NETWORKCHECK = true;
// ๐ฐ providers
if (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/901
const 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 blockchain
const localProviderUrl = targetNetwork.rpcUrl;
// as you deploy to other networks you can set REACT_APP_PROVIDER=https://dai.poa.network in packages/react-app/.env
const 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 URL
const blockExplorer = targetNetwork.blockExplorer;
// Coinbase walletLink init
const walletLink = new WalletLink({
appName: "coinbase",
});
// WalletLink provider
const 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;
No activity yet