-
-
Save KashifCh-eth/b208d554d594dab9060ae8c52b40c408 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.App { | |
background-color: #2B2D3C; | |
text-align: center; | |
min-height: 100vh; | |
padding-top: 25px; | |
padding-bottom: 25px | |
} | |
/*////////////////////////////////////////////////////////////////////////////*/ | |
/* Nav Bar */ | |
.connectButton { | |
float: right; | |
margin-right: 24px; | |
background-color: #1168f1; | |
border-radius: 4px; | |
padding: 5px 15px; | |
color: #f1f1f3; | |
font-size: 24px; | |
cursor: pointer; | |
} | |
.connectButton:hover { | |
background-color: #f90; | |
} | |
/*////////////////////////////////////////////////////////////////////////////*/ | |
/* Market */ | |
.marketContainer { | |
background-color: #fff; | |
width: 620px; | |
margin: 0 auto; | |
border-radius: 24px; | |
padding: 8px; | |
} | |
.subContainer { | |
margin-bottom: 20px; | |
} | |
.marketOption { | |
display: flex; | |
margin-left: 22px; | |
} | |
.optionData { | |
margin-left: 10px; | |
color: #fff; | |
font-weight: 700; | |
} | |
.optionPercent { | |
display: block; | |
font-size: 24px; | |
font-weight: 1000; | |
color: #f90; | |
} | |
.logoImg { | |
background-color: #fff; | |
border-radius: 100px; | |
margin-bottom: 14px; | |
margin-right: 14px; | |
width: 28px; | |
height: 28px; | |
} | |
.marketHeader { | |
color: #1168f1; | |
font-size: 32px; | |
font-weight: 800; | |
} | |
.stakedTokensHeader { | |
color: #fff; | |
} | |
.hoverButton:hover { | |
background: #f90; | |
cursor: pointer; | |
} | |
.hoverButton:active { | |
/* box-shadow: 0 0 0 white; */ | |
box-shadow: inset; | |
} | |
/*////////////////////////////////////////////////////////////////////////////*/ | |
/* Assets */ | |
.assetContainer { | |
background-color: #1168f1; | |
padding: 8px 0 10px 28px; | |
width: 620px; | |
min-height: 225px; | |
margin: 0 auto; | |
top: -25px; | |
border-radius: 24px; | |
margin-top: 50px; /* space between sections */ | |
color: #fff; | |
font-weight: 500; | |
position: relative; | |
} | |
.columnHeaders { | |
font-weight: 800; | |
color: #f90; | |
} | |
/*////////////////////////////////////////////////////////////////////////////*/ | |
/* Assets */ | |
.stakedLogoImg { | |
background-color: #fff; | |
border-radius: 100px; | |
margin-bottom: 14px; | |
margin-right: 14px; | |
width: 18px; | |
height: 18px; | |
} | |
/*////////////////////////////////////////////////////////////////////////////*/ | |
/* Glyphs */ | |
.glyphContainer { | |
background-color: #fff; | |
display: inline-block; | |
width: 60px; | |
height: 60px; | |
border-radius: 12px; | |
} | |
.glyph { | |
font-size: 34px; | |
} | |
/******************************************************************************/ | |
/* Stake Modal */ | |
.modal-class { | |
background-color: rgba(0,0,0,0.5); | |
position: fixed; | |
left: 0; | |
top: -400px; | |
right: 0px; | |
bottom: 0; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
color: rgb(86, 90, 105); | |
} | |
.modal-content { | |
background-color: #fff; | |
width: 300px !important; | |
padding: 10px 25px; | |
background-color: rgb(237, 238, 242) !important; | |
border: 1px solid rgb(206, 208, 217) !important; | |
border-radius: 12px !important; | |
} | |
.fieldContainer { | |
padding-left: 0px !important; | |
} | |
.inputField { | |
padding-left: 10px; | |
border-radius: 36px; | |
border: 1px solid #65cdee; | |
height: 2rem; | |
margin: 10px 0; | |
width: 100%; | |
} | |
.inputFieldUnitsContainer { | |
padding-left: 0px !important; | |
padding-top: 14px; | |
} | |
.pinkButton { | |
width: 100%; | |
height: 45px; | |
line-height: 45px; | |
font-size: 24px; | |
color: #fff; | |
border-radius: 20px; | |
background-color: #dd2f81; | |
cursor: pointer | |
} | |
.orangeMiniButton { | |
width: 100%; | |
height: 25px; | |
line-height: 25px; | |
font-size: 12px; | |
color: #000; | |
border-radius: 20px; | |
background-color: #fff; | |
cursor: pointer | |
} | |
.orangeMiniButton:hover { | |
color: #fff; | |
background-color: #f90;; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState } from 'react'; | |
import { ethers } from 'ethers'; | |
import artifact from './artifacts/contracts/Staking.sol/Staking.json' | |
import linkArtifact from './artifacts/contracts/Chainlink.sol/Chainlink.json' | |
import usdtArtifact from './artifacts/contracts/Tether.sol/Tether.json' | |
import usdcArtifact from './artifacts/contracts/UsdCoin.sol/UsdCoin.json' | |
import wbtcArtifact from './artifacts/contracts/WrappedBitcoin.sol/WrappedBitcoin.json' | |
import wethArtifact from './artifacts/contracts/WrappedEther.sol/WrappedEther.json' | |
import './App.css'; | |
import StakeModal from './components/StakeModal' | |
const CONTRACT_ADDRESS = '0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1' | |
const LINK_ADDRESS = '0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44' | |
const USDT_ADDRESS = '0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f' | |
const USDC_ADDRESS = '0x4A679253410272dd5232B3Ff7cF5dbB88f295319' | |
const WBTC_ADDRESS = '0x7a2088a1bFc9d81c55368AE168C2C02570cB814F' | |
const WETH_ADDRESS = '0x09635F643e140090A9A8Dcd712eD6285858ceBef' | |
function App() { | |
const [provider, setProvider] = useState(undefined); | |
const [signer, setSigner] = useState(undefined); | |
const [contract, setContract] = useState(undefined); | |
const toEther = wei => Number(ethers.utils.formatEther(String(wei))).toFixed(2); | |
const [tokenSymbols, setTokenSymbols] = useState([]) | |
const [tokens, setTokens] = useState({}) | |
const [stakedTokens, setStakedTokens] = useState({}) | |
const [assetIds, setAssetIds] = useState([]); | |
const [assets, setAssets] = useState([]); | |
const [showStakeModal, setShowStakeModal] = useState(false) | |
const [stakeTokenSymbol, setStakeTokenSymbol] = useState(undefined) | |
const [stakeTokenQuantity, setStakeTokenQuantity] = useState(undefined) | |
const [tokenContracts, setTokenContracts] = useState({}) | |
useEffect(() => { | |
const onLoad = async () => { | |
const provider = await new ethers.providers.Web3Provider(window.ethereum) | |
setProvider(provider) | |
const contract = await new ethers.Contract(CONTRACT_ADDRESS, artifact.abi, provider) | |
setContract(contract) | |
const linkContract = await new ethers.Contract(LINK_ADDRESS, linkArtifact.abi, provider) | |
const usdtContract = await new ethers.Contract(USDT_ADDRESS, usdtArtifact.abi, provider) | |
const usdcContract = await new ethers.Contract(USDC_ADDRESS, usdcArtifact.abi, provider) | |
const wbtcContract = await new ethers.Contract(WBTC_ADDRESS, wbtcArtifact.abi, provider) | |
const wethContract = await new ethers.Contract(WETH_ADDRESS, wethArtifact.abi, provider) | |
setTokenContracts(prev => ({...prev, ['LINK']:linkContract})) | |
setTokenContracts(prev => ({...prev, ['USDT']:usdtContract})) | |
setTokenContracts(prev => ({...prev, ['USDC']:usdcContract})) | |
setTokenContracts(prev => ({...prev, ['WBTC']:wbtcContract})) | |
setTokenContracts(prev => ({...prev, ['WETH']:wethContract})) | |
const tokenSymbols = await contract.getTokenSymbols() | |
setTokenSymbols(tokenSymbols) | |
tokenSymbols.map(async symbol => { | |
const token = await contract.getToken(symbol) | |
setTokens(prev => ({...prev, [symbol]:token})) | |
const stakedAmount = await contract.stakedTokens(symbol) | |
setStakedTokens(prev => ({...prev, [symbol]:toEther(stakedAmount)})) | |
}) | |
} | |
onLoad(); | |
}, []) | |
const isConnected = () => signer !== undefined | |
const getSigner = async () => { | |
const signer = provider.getSigner(); | |
setSigner(signer) | |
return signer | |
} | |
const connectAndLoad = async () => { | |
const signer = await getSigner(provider) | |
setSigner(signer) | |
const assetIdsHex = await contract.connect(signer).getPositionIdsForAddress() | |
const assetIds = assetIdsHex.map(id => Number(id)) | |
setAssetIds(assetIds) | |
const queriedAssets = await Promise.all( | |
assetIds.map(id => contract.connect(signer).getPositionById(Number(id)) ) | |
) | |
queriedAssets.map(async asset => { | |
const tokensStaked = toEther(asset.tokenQuantity) | |
const ethAccruedInterestWei = await calcAccruedInterest(asset.apy, asset.ethValue, asset.createdDate) | |
const ethAccruedInterest = toEther(ethAccruedInterestWei) | |
const usdAccruedInterest = ((ethAccruedInterest * tokens['WETH'].usdPrice) / 100).toFixed(2) | |
const parsedAsset = { | |
positionId: Number(asset.positionId), | |
tokenName: asset.name, | |
tokenSymbol: asset.symbol, | |
createdDate: asset.createdDate, | |
apy: asset.apy / 100, | |
tokensStaked: tokensStaked, | |
usdValue: toEther(asset.usdValue) / 100, | |
usdAccruedInterest: usdAccruedInterest, | |
ethAccruedInterest: ethAccruedInterest, | |
open: asset.open, | |
} | |
setAssets(prev => [...prev, parsedAsset]) | |
}) | |
} | |
const calcAccruedInterest = async (apy, value, createdDate) => { | |
const numberOfDays = await contract.calculateNumberDays(createdDate) | |
const accruedInterest = await contract.calculateInterest(apy, value, numberOfDays) | |
return Number(accruedInterest) | |
} | |
const openStakingModal = (tokenSymbol) => { | |
setShowStakeModal(true) | |
setStakeTokenSymbol(tokenSymbol) | |
} | |
const stakeTokens = async () => { | |
const stakeTokenQuantityWei = ethers.utils.parseEther(stakeTokenQuantity); | |
await tokenContracts[stakeTokenSymbol].connect(signer).approve(contract.address, stakeTokenQuantityWei); | |
contract.connect(signer).stakeTokens(stakeTokenSymbol, stakeTokenQuantityWei); | |
} | |
const withdraw = (positionId) => { | |
contract.connect(signer).closePosition(positionId) | |
} | |
const tokenRow = (tokenSymbol) => { | |
const token = tokens[tokenSymbol] | |
const amountStaked = Number(stakedTokens[tokenSymbol]) | |
return ( | |
<div className="row"> | |
<div className="col-md-2"> | |
{displayLogo(token?.symbol)} | |
</div> | |
<div className="col-md-2"> | |
{token?.symbol} | |
</div> | |
<div className="col-md-2"> | |
{(Number(token?.usdPrice) / 100).toFixed(0)} | |
</div> | |
<div className="col-md-2"> | |
{amountStaked} | |
</div> | |
<div className="col-md-2"> | |
{(Number(token?.apy) / 100).toFixed(0)}% | |
</div> | |
<div className="col-md-2"> | |
{isConnected() && ( | |
<div | |
className="orangeMiniButton" | |
onClick={() => openStakingModal(tokenSymbol, '12%')}> | |
Stake | |
</div> | |
)} | |
</div> | |
</div> | |
) | |
} | |
const displayLogo = symbol => { | |
if (symbol === 'LINK') { | |
return (<><img className="logoImg" src="link.webp"/></>) | |
} else if (symbol === 'USDT') { | |
return (<><img className="logoImg" src="usdt.webp"/></>) | |
} else if (symbol === 'USDC') { | |
return (<><img className="logoImg" src="usdc.webp"/></>) | |
} else if (symbol === 'WBTC') { | |
return (<><img className="logoImg" src="wbtc.webp"/></>) | |
} else if (symbol === 'WETH') { | |
return (<><img className="logoImg" src="weth.webp"/></>) | |
} | |
} | |
return ( | |
<div className="App"> | |
<div className="marketContainer"> | |
<div className="subContainer"> | |
<span> | |
<img className="logoImg" src="eth-logo.webp"/> | |
</span> | |
<span className="marketHeader">Ethereum Market</span> | |
</div> | |
<div> | |
<div className="row columnHeaders"> | |
<div className="col-md-2">Asset</div> | |
<div className="col-md-2">Symbol</div> | |
<div className="col-md-2">Price (USD)</div> | |
<div className="col-md-2">Total Supplied</div> | |
<div className="col-md-2">APY</div> | |
<div className="col-md-2"></div> | |
</div> | |
</div> | |
<div> | |
{tokenSymbols.length > 0 && Object.keys(tokens).length > 0 && tokenSymbols.map((a,idx) => ( | |
<div> | |
{tokenRow(a)} | |
</div> | |
))} | |
</div> | |
</div> | |
<div className="assetContainer"> | |
{isConnected() ? ( | |
<> | |
<div className="subContainer"> | |
<span className="marketHeader stakedTokensHeader">Staked Assets</span> | |
</div> | |
<div> | |
<div> | |
<div className="row columnHeaders"> | |
<div className="col-md-1">Asset</div> | |
<div className="col-md-2">Tokens Staked</div> | |
<div className="col-md-2">Market Value (USD)</div> | |
<div className="col-md-2">Accrued Interest (USD)</div> | |
<div className="col-md-2">Accrued Interest (ETH)</div> | |
<div className="col-md-2"></div> | |
</div> | |
</div> | |
<br /> | |
{assets.length > 0 && assets.map((a,idx) => ( | |
<div className="row"> | |
<div className="col-md-1"> | |
{displayLogo(a.tokenSymbol)} | |
</div> | |
<div className="col-md-2"> | |
{a.tokensStaked} | |
</div> | |
<div className="col-md-2"> | |
{a.usdValue} | |
</div> | |
<div className="col-md-2"> | |
{a.usdAccruedInterest} | |
</div> | |
<div className="col-md-2"> | |
{a.ethAccruedInterest} | |
</div> | |
<div className="col-md-2"> | |
{a.open ? ( | |
<div onClick={() => withdraw(a.positionId)} className="orangeMiniButton">Withdraw</div> | |
) : ( | |
<span>closed</span> | |
)} | |
</div> | |
</div> | |
))} | |
</div> | |
</> | |
) : ( | |
<div | |
onClick={() => connectAndLoad()} | |
className="connectButton"> | |
Connect Wallet | |
</div> | |
)} | |
</div> | |
{showStakeModal && ( | |
<StakeModal | |
onClose={() => setShowStakeModal(false)} | |
stakeTokenSymbol={stakeTokenSymbol} | |
setStakeTokenQuantity={setStakeTokenQuantity} | |
stakeTokens={stakeTokens} | |
/> | |
)} | |
</div> | |
); | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "client", | |
"version": "0.1.0", | |
"private": true, | |
"dependencies": { | |
"@testing-library/jest-dom": "^5.16.5", | |
"@testing-library/react": "^13.3.0", | |
"@testing-library/user-event": "^13.5.0", | |
"bootstrap": "^5.2.0", | |
"ethers": "^5.6.9", | |
"react": "^18.2.0", | |
"react-dom": "^18.2.0", | |
"react-scripts": "5.0.1", | |
"styled-components": "^5.3.5" | |
}, | |
"scripts": { | |
"start": "react-scripts start", | |
"build": "react-scripts build", | |
"test": "react-scripts test", | |
"eject": "react-scripts eject" | |
}, | |
"eslintConfig": { | |
"extends": [ | |
"react-app", | |
"react-app/jest" | |
] | |
}, | |
"browserslist": { | |
"production": [ | |
">0.2%", | |
"not dead", | |
"not op_mini all" | |
], | |
"development": [ | |
"last 1 chrome version", | |
"last 1 firefox version", | |
"last 1 safari version" | |
] | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require("@nomiclabs/hardhat-waffle"); | |
/** | |
* @type import('hardhat/config').HardhatUserConfig | |
*/ | |
module.exports = { | |
solidity: { | |
version: "0.8.0", | |
}, | |
paths: { | |
artifacts: "./client/src/artifacts", | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import ReactDOM from 'react-dom/client'; | |
import './index.css'; | |
import App from './App'; | |
import 'bootstrap/dist/css/bootstrap.css'; | |
const root = ReactDOM.createRoot(document.getElementById('root')); | |
root.render( | |
<React.StrictMode> | |
<App /> | |
</React.StrictMode> | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "stake-erc20-tokens", | |
"version": "1.0.0", | |
"description": "", | |
"main": "index.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"keywords": [], | |
"author": "", | |
"license": "ISC", | |
"dependencies": { | |
"@nomiclabs/hardhat-ethers": "^2.1.0", | |
"@nomiclabs/hardhat-waffle": "^2.0.3", | |
"@openzeppelin/contracts": "^4.7.3", | |
"chai": "^4.3.6", | |
"ethereum-waffle": "^3.4.4", | |
"ethers": "^5.6.9", | |
"hardhat": "^2.10.1" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function main() { | |
[owner] = await ethers.getSigners(); | |
const Staking = await ethers.getContractFactory('Staking', owner); | |
const staking = await Staking.deploy( | |
187848, | |
{ | |
value: ethers.utils.parseEther('100') | |
} | |
); | |
const Chainlink = await ethers.getContractFactory('Chainlink', owner); chainlink = await Chainlink.deploy(); | |
const Tether = await ethers.getContractFactory('Tether', owner); tether = await Tether.deploy(); | |
const UsdCoin = await ethers.getContractFactory('UsdCoin', owner); usdCoin = await UsdCoin.deploy(); | |
const WrappedBitcoin = await ethers.getContractFactory('WrappedBitcoin', owner); wrappedBitcoin = await WrappedBitcoin.deploy(); | |
const WrappedEther = await ethers.getContractFactory('WrappedEther', owner); wrappedEther = await WrappedEther.deploy(); | |
await staking.connect(owner).addToken('Chainlink', 'LINK', chainlink.address, 867, 1500); | |
await staking.connect(owner).addToken('Tether', 'USDT', tether.address, 100, 200); | |
await staking.connect(owner).addToken('UsdCoin', 'USDC', usdCoin.address, 100, 200, ); | |
await staking.connect(owner).addToken('WrappedBitcoin','WBTC', wrappedBitcoin.address, 2382096, 500); | |
await staking.connect(owner).addToken('WrappedEther', 'WETH', wrappedEther.address, 187848, 1000); | |
console.log("Staking:", staking.address); | |
console.log("Chainlink:", chainlink.address); | |
console.log("Tether:", tether.address); | |
console.log("UsdCoin:", usdCoin.address); | |
console.log("WrappedBitcoin:", wrappedBitcoin.address); | |
console.log("WrappedEther:", wrappedEther.address); | |
await chainlink.connect(owner).approve(staking.address, ethers.utils.parseEther('100')); | |
await staking.connect(owner).stakeTokens('LINK',ethers.utils.parseEther('100')) | |
await wrappedBitcoin.connect(owner).approve(staking.address, ethers.utils.parseEther('2')); | |
await staking.connect(owner).stakeTokens('WBTC',ethers.utils.parseEther('2')) | |
await wrappedBitcoin.connect(owner).approve(staking.address, ethers.utils.parseEther('10')); | |
await staking.connect(owner).stakeTokens('WBTC',ethers.utils.parseEther('10')) | |
await wrappedEther.connect(owner).approve(staking.address, ethers.utils.parseEther('10')); | |
await staking.connect(owner).stakeTokens('WETH',ethers.utils.parseEther('10')) | |
const provider = waffle.provider; | |
const block = await provider.getBlock() | |
const newCreatedDate = block.timestamp - (86400 * 365) | |
await staking.connect(owner).modifyCreatedDate(1, newCreatedDate) | |
await staking.connect(owner).modifyCreatedDate(2, newCreatedDate) | |
await staking.connect(owner).modifyCreatedDate(3, newCreatedDate) | |
} | |
// npx hardhat run --network localhost scripts/deploy.js | |
main() | |
.then(() => process.exit(0)) | |
.catch((error) => { | |
console.error(error); | |
process.exit(1); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
const StakeModal = props => { | |
const { | |
onClose, | |
stakeTokenSymbol, | |
setStakeTokenQuantity, | |
stakeTokens, | |
} = props | |
return ( | |
<> | |
<div className="modal-class" onClick={onClose}> | |
<div className="modal-content" onClick={e => e.stopPropagation()}> | |
<div className="modal-body"> | |
<h2 className="titleHeader">Stake</h2> | |
<div className="row"> | |
<div className="col-md-9 fieldContainer"> | |
<input | |
className="inputField" | |
placeholder="0.0" | |
onChange={e => props.setStakeTokenQuantity(e.target.value)} | |
/> | |
</div> | |
<div className="col-md-3 inputFieldUnitsContainer"> | |
<span>{stakeTokenSymbol}</span> | |
</div> | |
</div> | |
<div className="row"> | |
<div | |
onClick={() => {stakeTokens(); onClose()}} | |
className="pinkButton hoverButton"> | |
Stake | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</> | |
) | |
} | |
export default StakeModal; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { expect } = require("chai"); | |
describe('Staking', () => { | |
beforeEach(async () => { | |
[owner, signer2] = await ethers.getSigners(); | |
Staking = await ethers.getContractFactory('Staking', owner); | |
staking = await Staking.deploy( | |
187848, | |
{ | |
value: ethers.utils.parseEther('100') | |
} | |
); | |
Chainlink = await ethers.getContractFactory('Chainlink', signer2); | |
chainlink = await Chainlink.deploy(); | |
staking.connect(owner).addToken( | |
'Chainlink', | |
'LINK', | |
chainlink.address, | |
867, | |
1500 | |
) | |
await chainlink.connect(signer2).approve( | |
staking.address, | |
ethers.utils.parseEther('100') | |
); | |
staking.connect(signer2).stakeTokens( | |
'LINK', | |
ethers.utils.parseEther('100') | |
) | |
}); | |
describe('addToken', () => { | |
it('adds a token symbol', async () => { | |
const tokenSymbols = await staking.getTokenSymbols() | |
expect(tokenSymbols).to.eql(['LINK']) | |
}) | |
it('adds token information', async () => { | |
const token = await staking.getToken('LINK') | |
expect(token.tokenId).to.equal(1) | |
expect(token.name).to.equal('Chainlink') | |
expect(token.symbol).to.equal('LINK') | |
expect(token.tokenAddress).to.equal(chainlink.address) | |
expect(token.usdPrice).to.equal(867) | |
expect(token.ethPrice).to.equal(0) | |
expect(token.apy).to.equal(1500) | |
}) | |
it('increments currentTokenId', async () => { | |
expect( await staking.currentTokenId() ).to.equal(2) | |
}) | |
}) | |
describe('stakeToken', () => { | |
it('transfers tokens', async () => { | |
const signerBalance = await chainlink.balanceOf(signer2.address) | |
expect(signerBalance).to.equal( ethers.utils.parseEther('4900') ) | |
const contractBalance = await chainlink.balanceOf(staking.address) | |
expect(contractBalance).to.equal( ethers.utils.parseEther('100') ) | |
}) | |
it('creates a position', async () => { | |
const positionIds = await staking.connect(signer2).getPositionIdsForAddress() | |
expect(positionIds.length).to.equal(1) | |
const position = await staking.connect(signer2).getPositionById(positionIds[0]) | |
expect(position.positionId).to.equal(1) | |
expect(position.walletAddress).to.equal(signer2.address) | |
expect(position.name).to.equal('Chainlink') | |
expect(position.symbol).to.equal('LINK') | |
expect(position.apy).to.equal(1500) | |
expect(position.tokenQuantity).to.equal( ethers.utils.parseEther('100') ) | |
expect(position.open).to.equal(true) | |
}) | |
it('increments positionId', async () => { | |
expect(await staking.currentPositionId()).to.equal(2) | |
}) | |
it('increases total amount of staked token', async () => { | |
expect(await staking.stakedToken('LINK')).to.equal( ethers.utils.parseEther('100') ) | |
}) | |
}) | |
describe('calculateInterest', () => { | |
it('returns interest accrued to a position', async () => { | |
const apy = 1500 | |
const value = ethers.utils.parseEther('100') | |
const days = 365 | |
const interestRate = await staking.calculateInterest(apy, value, days) | |
expect( String(interestRate) ).to.equal( String(ethers.utils.parseEther('15')) ) | |
}) | |
}) | |
describe('calculateNumberDays', () => { | |
it('returns the number of days since createdDate', async () => { | |
const provider = waffle.provider; | |
const block = await provider.getBlock() | |
const oneYearAgo = block.timestamp - (86400 * 101) | |
const days = await staking.connect(owner).calculateNumberDays(oneYearAgo) | |
expect(days).to.be.equal(101) | |
}) | |
}) | |
describe('closePosition', () => { | |
beforeEach(async () => { | |
provider = waffle.provider; | |
contractEthbalanceBefore = await provider.getBalance(staking.address) | |
signerEthBalanceBefore = await provider.getBalance(signer2.address) | |
const block = await provider.getBlock() | |
const newCreatedDate = block.timestamp - (86400 * 365) | |
await staking.connect(owner).modifyCreatedDate(1, newCreatedDate) | |
await staking.connect(signer2).closePosition(1) | |
}) | |
it('returns tokens to wallet', async () => { | |
const signerBalance = await chainlink.balanceOf(signer2.address) | |
expect(signerBalance).to.equal( ethers.utils.parseEther('5000') ) | |
const contractBalance = await chainlink.balanceOf(staking.address) | |
expect(contractBalance).to.equal( ethers.utils.parseEther('0') ) | |
}) | |
it('sends ether interest to wallet', async () => { | |
const contractEthBalanceAfter = await provider.getBalance(staking.address) | |
const signerEthBalanceAfter = await provider.getBalance(signer2.address) | |
expect(contractEthBalanceAfter).to.be.below(contractEthbalanceBefore) | |
expect(signerEthBalanceAfter).to.be.above(signerEthBalanceBefore) | |
}) | |
it('closes position', async () => { | |
const position = await staking.connect(signer2).getPositionById(1) | |
expect(position.open).to.equal(false) | |
}) | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
position