# 第 3 次讀書會主題實作練習 - 建立一個 Bank 銀行
Dapp_陳其駿_Jim
<h3>
Staking Token
</h3>
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract testERC20 is ERC20 {
constructor() ERC20("testERC20", "tERC") {
// _mint(msg.sender, 10 ** (9 + 18));
_mint(msg.sender, 1_000_000_000 * 1e18);
}
}
```
<h3>
Bank
</h3>
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract BasicBank {
IERC20 public stakingToken;
uint256 public totalStakedToken;
mapping(address => uint256) public balanceOf;
uint256 public withdrawDeadline = 10 seconds;
uint256 public rewardRate = 1;
mapping(address => uint256) public rewardOf;
struct Deposit {
uint256 amount;
uint256 startTime;
uint256 endTime;
}
mapping(address => Deposit[]) public depositOf;
constructor(IERC20 _stakingToken) {
stakingToken = _stakingToken;
}
function updateTotalStakenToken() internal {
totalStakedToken = stakingToken.balanceOf(address(this));
}
function deposit(uint256 _amount) external {
stakingToken.transferFrom(msg.sender, address(this), _amount);
totalStakedToken += _amount;
balanceOf[msg.sender] += _amount;
depositOf[msg.sender].push(
Deposit({
amount: _amount,
startTime: block.timestamp,
endTime: block.timestamp + withdrawDeadline
})
);
}
function withdraw(uint256 _depositId) external {
require(balanceOf[msg.sender] > 0, "You have no balance to withdraw");
Deposit[] storage deposits = depositOf[msg.sender];
require(block.timestamp >= deposits[_depositId].endTime, "Withdrawal Period is not reached yet");
require(_depositId <= deposits.length, "Deposit ID not exist!!");
uint256 currentReward = deposits[_depositId].amount + getInterest(_depositId);
updateTotalStakenToken();
require(totalStakedToken >= currentReward, "Tokens in the pool is insufficient for the withdrawal");
rewardOf[msg.sender] += currentReward;
stakingToken.transfer(msg.sender, currentReward);
totalStakedToken -= currentReward;
balanceOf[msg.sender] -= deposits[_depositId].amount;
deposits[_depositId] = deposits[deposits.length - 1];
deposits.pop();
}
function getInterest(uint256 _depositId) public view returns (uint256) {
uint256 start = depositOf[msg.sender][_depositId].startTime;
uint256 _amount = depositOf[msg.sender][_depositId].amount;
return (block.timestamp - start) * rewardRate * _amount;
}
function getAllInterest() public view returns (uint256){
uint256 N = depositOf[msg.sender].length;
uint256 allRewards;
for (uint256 i = 0; i < N; i++) {
allRewards += getInterest(i);
}
return allRewards;
}
}
```
<h3>屬性與方法</h3>
>mapping
>>balanceOf:查詢地址的餘額
>>rewardOf:查詢地址領取的總額
>>depositOf:查詢地址的存款狀況
>function
>>deposit:存款方法
>>getInterest:取得存款的利息
>>getAllInterest:取得所有存款的利息
>>withdraw:提領方法