Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- github 에러
- 투표
- 업그레이더블 컨트랙트
- 옵저버패턴
- 멀티시그
- 팀 프로젝트
- 팩토리패턴
- 인센티브 기반 커뮤니티
- 스테이트머신패턴
- 일시정지
- github
- git commit
- 토큰노믹스
- 회로차단
- 코드리뷰
- 부트캠프
- 블록체인
- 재진입
- 코드스테이츠
- solidity
- 트러블슈팅
- 프록시패턴
- 싱글톤패턴
- 디자인 패턴
- 솔리디티
- RBAC
- 웹툰
- 배팅
- git add
Archives
- Today
- Total
보다 더 생생한 기록
[Solidity][코드리뷰] 스테이킹 시스템 코드 분석 본문
부트캠프 4번째 프로젝트에 들어간 컨트랙트 코드분석
1. Deposit
function deposit(uint256 amount_) public {
require(amount_ > 0, "you must have non-zero token amount");
Staker storage staker = _stakers[msg.sender];
StakeToken(address(stakeToken)).transferFrom(msg.sender, address(this), amount_);
// 스테이킹을 위해 msg.sender(유저)로 부터 address(this)(컨트랙트)로 토큰을 전달
_update();
// 전체 스테이킹 밸런스의 변경이 있을때마다 update 실행
if (!_stakerList.contains(msg.sender)) {
// stakerList에 아직 msg.sender가 없다면, 리스트에 추가시켜줌
_stakerList.add(msg.sender);
staker.tookRewardTime = block.timestamp; // unixTime
// 추후 보상을 받을때 얼마나 스테이킹했는지 확인하기위해, 첫 예치 시점에 타임스탬프 찍어줌
}
staker.amount += amount_;
totalStaked += amount_;
emit Deposit(msg.sender, amount_, staker.tookRewardTime);
}
2. Update
1. 철수만 스테이킹 - 시간당 받을 수 있는 보상토큰을 철수만 받는다.
스테이킹 풀 | 철수 10000개 (100%) |
시간당 보상토큰 (10개) | 10개 |
2. 철수와 같은양을 영희도 스테이킹 - 시간당 받을 수 있는 보상토큰을 철수와 영희가 반반 나눠 갖는다.
스테이킹 풀 | 철수 10000개 (50%) | 영희 10000개 (50%) |
시간당 보상토큰 (10개) | 5개 | 5개 |
3. 영희가 2만개를 더 스테이킹 - 시간당 받을 수 있는 보상토큰을 철수가 25퍼센트, 영희가 75퍼센트로 나눠갖는다.
스테이킹 풀 | 철수 10000개 (25%) | 영희 30000개 (75%) |
시간당 보상토큰 (10개) | 2.5개 | 7.5개 |
4. 철수가 스테이킹한 수량을 전체 출금 - 시간당 받을 수 있는 보상토큰을 영희만 받는다.
스테이킹 풀 | 영희 30000개 (100%) |
시간당 보상토큰 (10개) | 10개 |
위의 순서에서 봤듯이, 예금과 출금같이 스테이킹 풀 비율에 영향을 주는 이벤트가 일어나면, 스테이커에게 돌아가는 보상토큰의 양이 달라진다.
즉, 이전까지 쌓인 보상토큰은 킵해두고, 새롭게 정해진 시간당 보상토큰양으로 쌓이기 시작.
이걸 위해 deposit과 withdraw에 update 함수가 실행되도록 한다.
function _update() public {
// 한명이라도 스테이킹 풀에 입금하거나 출금한다면, 전체적인 비율이 달라지게 된다.
// 즉 스테이킹풀에 영향을 주는 일이 일어날때마다 스테이커들의 보상토큰양을 수정해줘야한다.
for(uint i = 0; i < _stakerList.length(); i++) {
Staker storage staker = _stakers[_stakerList.at(i)];
uint rewardAmount = (staker.amount / totalStaked) * rewardPerSec;
// 전체 스테이킹 풀에서 본인의 비율이 어느정도인가 * 시간당 보상토큰
uint stakingPeriod = block.timestamp - staker.tookRewardTime;
// 업데이트를 한적 있다면 그때부터 스테이킹을 얼마나 시간이 흘렀는가
// 한적 없다면, 최초 예치부터 얼마나 시간이 흘렀는가
uint reward = rewardAmount * stakingPeriod;
// 새로운 보상토큰 비율로 받기전에, 이전까지 쌓여온 보상토큰들을 킵해줌
staker.tookRewardTime = block.timestamp;
// 새로운 보상토큰 비율로 받기위해, 현재 시간으로 타임스탬프를 찍어줌
staker.rewards += reward;
}
3. Claim
function claim() public {
require(_stakerList.contains(msg.sender), "staker does not exist");
Staker storage staker = _stakers[msg.sender];
require(staker.amount > 0, "should stake more than 0");
_update();
// 여태까지 쌓여온 보상토큰을 수령하는거기때문에, timestamp를 업데이트시켜줘야함.
uint claimAmount = staker.rewards;
staker.rewards = 0;
// 보상토큰 축적량 초기화
rewardToken.mint(msg.sender, claimAmount);
// 해당 스테이커에게 보상토큰 발행
emit Claim(msg.sender, claimAmount);
}
4. Withdraw
function withdraw() public {
require(_stakerList.contains(msg.sender), "you are not staker");
Staker storage staker = _stakers[msg.sender];
uint256 withdrawal = staker.amount;
require(withdrawal > 0, "cannot withdraw zero value");
_update();
// 출금이므로 업데이트 필요
claim();
// 스테이킹한 토큰도 출금하고, 그 동안 쌓여온 보상토큰도 수령하고
staker.amount -= withdrawal;
totalStaked -= withdrawal;
_stakerList.remove(msg.sender);
// 리스트에서 제거
stakeToken.transfer(msg.sender, withdrawal);
// 스테이킹한 토큰 출금
emit Withdraw(msg.sender, withdrawal);
}
'블록체인' 카테고리의 다른 글
[블록체인] did 관련 문서, 레포, 레퍼런스 (0) | 2023.08.15 |
---|---|
[Solidity] 다수의 반환값 처리하기 (0) | 2023.05.26 |
[Solidity][코드리뷰] Lazy Minting in OpenSea (오픈씨내에서의 레이지민팅) (0) | 2023.01.13 |
[Solidity] 크립토좀비 Ch1,2 정리 (0) | 2022.12.26 |
[Solidity] UniSwap v2 - 이론 정리 (0) | 2022.12.25 |