블록체인/이더리움

[SpeedRunEthereum] Challenge 1[Decentralized Staking App]

dev_dean 2022. 5. 15. 13:34

challenge 1은 스테이킹 앱을 만들어보는 것입니다.

 

Checkpoint 1: Environment

challenge 0처럼 템플릿 프로젝트를 받고 로컬 네트워크, 리액트, 디플로이를 해줍니다.

git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git challenge-1-decentralized-staking

cd challenge-1-decentralized-staking

git checkout challenge-1-decentralized-staking
yarn install

//terminal 1
yarn chain
//terminal 2
yarn start
//terminal 3
yarn deploy

Checkpoint 2: Staking

Staker.sol 에서 지갑별로 스테이크한 금액을 저장해둘 맵핑과 최대치를 선언해줍니다.

  mapping(address => uint256) public balances;
  uint256 public constant threshold = 1 ether;

 

stake함수를 작성합니다.

  function stake() public payable {
    require(balances[msg.sender].add(msg.value)<= threshold);
    
    balances[msg.sender] = balances[msg.sender].add(msg.value);
    emit Stake(msg.sender, msg.value);

  }

 

프론트에 접속해 stake 함수로 금액을 전송해 event와 금액이 정상적으로 전송되었는지 확인해봅니다.

컨트랙트 지갑의 잔고, 개인 주소에 저장되어 있는 금액, 이벤트 내역까지 확인할 수 있습니다.

Checkpoint 3: State Machine / Timing 

 

데드라인을 생성합니다. 시간은 컨트랙트 배포 시간 + 30초로 지정합니다.

uint256 public deadline = block.timestamp + 30 seconds;

 

deadline이 지난 후에 실행 가능한 execute 함수를 작성합니다.

execute함수는 컨트랙트 지갑의 잔고가 임계치(1 ether) 이상이라면 exampleExternalcontract.complete{value: address(this).balance}();를 호출하고 아니라면 openForWithdraw를 true로 하여 모든 사용자가 출금할 수 있게 합니다.

bool public openForWithdraw;

function execute() public deadlineExpire {
    if (address(this).balance >= threshold) {
      exampleExternalContract.complete{value: address(this).balance}();
    }else{
      openForWithdraw = true;
    }
  }
  
function withdraw() public payable {
    require(openForWithdraw);

    uint256 val = balances[msg.sender];
    require(val >= msg.value);
    balances[msg.sender] = val.sub(msg.value);
    msg.sender.call{value: msg.value}("");
  }

 

deadline까지 시간이 얼마나 남았는지를 반환하는 timeLeft 함수를 작성합니다.

function timeLeft() public view returns (uint256) {
    
    return (block.timestamp < deadline) ? deadline - block.timestamp : 0;
  
  }

 

Checkpoint 4: Receive Function / UX

컨트랙트에 직접 이더를 전송할 경우에도 대응 가능하게 receive 폴백 함수를 작성합니다.

 receive() external payable {
    stake();
  }

 

Checkpoint 5: 배포 / 프론트

challenge 0에서 한 것처럼 설정 변경 후 배포합니다.

1. hardhat.config.js 에서 localnetwork 변경

2. yarn generate로 menemonic 생성

3. yarn deploy

4. App.jsx 에서 targetNetwork 변경

5. yarn build

6. yarn surge

 

배포된 컨트랙트를 확인하려면

package.json의 verify에 이더스캔 api키를 적어준 후

터미널에서 다음과 같이 입력합니다.

 yarn verify --network your_network