Todo :
0. 추가하려는 내용
1. access control module 사용
2. 기타 수정사항
사용자의 증가, 시장 상황 변화 등으로 인해 rewardPerBlock을 변경해야 하는 상황에 필요한 setRewardPerBlock 기능을 만드려고 한다.
contract TinyBank {
event Staked(address, uint256);
event Withdraw(uint256 amount, address to);
IMyToken public stakingToken;
mapping(address => uint256) public lastClaimedBlock;
// 추가 및 변경
uint256 defaultRewardPerBlock = 1*10 ** 18; //추가
uint256 rewardPerBlock; //변경
mapping(address => uint256) public staked;
uint256 public totalStaked;
constructor(IMyToken _stakingToken) {
stakingToken = _stakingToken;
rewardPerBlock = defaultRewardPerBlock; //추가
}
//추가
function setRewardPerBlock(uint256 _amount) external {
rewardPerBlock = _amount;
}
이렇게 코드를 추가하면 리워드를 변경할 수는 있으나,
이것 역시 이전 mint() 와 동일하게 외부에서 악의적으로 사용할 수 있다는 문제가 생긴다.
describe("reward", async () => {
...
it("Should revert when changing rewardPerBlock by hacker", async () => {
const hacker = signers[3];
const rewardToChange = hre.ethers.parseUnits("10000", DECIMALS);
await expect(
tinyBankC.connect(hacker).setRewardPerBlock(rewardToChange),
).to.be.revertedWith("You are not authorized to manage this contract");
});
..
}
따라서 이것 역시 권한이 없으면 사용하지 못하게 하는 테스트를 만들고, 성공하도록 코드를 만들어보자
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "./ManagedAccess.sol"; //추가
...
contract TinyBank is ManagedAccess { //상속
event Staked(address, uint256);
event Withdraw(uint256 amount, address to);
IMyToken public stakingToken;
mapping(address => uint256) public lastClaimedBlock;
uint256 defaultRewardPerBlock = 1*10 ** 18;
uint256 rewardPerBlock;
mapping(address => uint256) public staked;
uint256 public totalStaked;
constructor(IMyToken _stakingToken) ManagedAccess(msg.sender, msg.sender) { //생성자
stakingToken = _stakingToken;
rewardPerBlock = defaultRewardPerBlock;
}
function setRewardPerBlock(uint256 _amount) external onlyManager { //ManagedAccess 사용
rewardPerBlock = _amount;
}
지난번에 했던 것처럼 똑같이 해주면 된다.
( 8-2. mint 함수 접근권한 제한하기 (access control) )
만들어둔 access control module를 사용한다.
ManagedAccess를 상속받고 생성자 써주고,
권한을 제한하려는 setRewardPerBlock에 onlyManager를 작성해준다.
이 ManagedAccess가 다양한 함수에 사용되니까 revertedWith 문구를 좀 더 일반적인 걸로 바꿔주는 것이 좋다고 한다.
modifier onlyManager {
require(
msg.sender == manager,
"You are not authorized to manage this contract" //변경
);
_;
}
token --> contract로 변경해줬다.
describe("Mint", () => {
....
it("should return or revert when minting infinitly", async () => {
const hacker = signers[2];
const mintingAgainAmount = hre.ethers.parseUnits("10000", DECIMALS);
await expect(
myTokenC.connect(hacker).mint(mintingAgainAmount, hacker.address),
).to.be.revertedWith("You are not authorized to manage this contract");
//문구 변경
});
});
이전에 사용했던 MyToken에서 Mint 테스트 부분도 변경해준다.
❯ git add .
❯ git commit
-m 없이 git commit 만 입력하니까 편집창이 뜨는데,
거기에
feat(TinyBank): add function to change rewardPerBlock
- Apply AccessManager to TinyBank for onlyManager restriction.
- Rename onlyManager modifier message to be more generic.
- Add test for malicious attempt to change rewardPerBlock.
이렇게 메세지 입력해주고
들어간 편집창이 nano 라는 거길래.. (vim만 써봄)
Ctrl+O(저장) > (File Name to Write) Enter > Ctrl+X
이 방식으로 저장하고 나왔다.