본문 바로가기
블록체인/블록체인 서비스 개발

[이더리움개발101] JavaScript/React로 Contract 이용하기

by 마고커 2022. 4. 26.


Solidity로 Contract를 개발해서 테스트하는 방법은 아래 두가지로 알아보았다.

 

 

[이더리움개발101] Truffle Console 사용

Truffle의 초기화 및 배포 방법은 아래를 참조한다. npm install truffle -g > npm install ganache-cli -g 2. 설치 후 version 확인 > truffle version Truffle v5.5.7 (core: 5.5.7) G.." data-og-host="magoker..

magoker.tistory.com

 

 

[이더리움개발101] Truffle Test 사용해서 검증하기

계약서를 수정시마다 매번 배포하고, Truffle Console에서 테스트하는 일은 좀 번거로울 수도 있다. 테스트 과정을 코드화 할 수 있다면, 좀 더 직관적으로 확인할 수 있을 것이다. truffle을 initialize(t

magoker.tistory.com

 

실제 개발이 들어간다면, 이보다는 대부분 웹환경에서 개발하게 될 것이다. 그 간단한 과정은 아래와 같다.

 

1. Contract 가져오기 

 

web3 객체를 생성하고, Contract을 가져오면 된다.

 

let lotteryAddress = "0xBfaD9A9982B2169E124F754b2F8036bCEA542137";
let lotteryABI = [...]

if (window.ethereum) {
  this.web3 = new Web3(window.ethereum);

  try {
    await window.ethereum.enable();
    // this.web3.eth.sendTransaction({/* ... */});
  } catch (error) {
    console.log(`user denied account access error : ${error}`);
  }
} 
else {
  console.log("non-ethereum browser detected");
}

let accounts = await this.web3.eth.getAccounts();
this.account = accounts[0];

// lottery는 내가 만든 contract. 각자가 알맞게 수정
this.lotteryContract = new this.web3.eth.Contract(lotteryABI, lotteryAddress);

 

Contract을 가져오기 위해서는 ABI와 Address가 필요한데, ABI는 컴파일하고 Migration 하면 생기는 build/contract 디렉토리 안에 xxxx.json 파일에서 가져온다. (길어서 vscode에서 줄여서 가져왔다)

 

 

contract의 address는 'truffle migrate --reset'으로 배포할 때 나온다.

 

 

2. 함수 호출하기

 

web3에서 제공되는 것이나 contract에서 만든 함수를 호출할 때는 send나 call 함수를 이용한다. send는 gas fee를 지정해서 보낼 수 있고, call이나 transfer는 정해져 있다. 작성 예제는 아래와 같다.

 

bet = async() => {
    let challenges = '0x' + this.state.challenges[0].toLowerCase() + this.state.challenges[1].toLowerCase(); 
    
    // nonce는 transaction의 순서를 나타낸다
    let nonce = await this.web3.eth.getTransactionCount(this.account);

	// contract의 betAndDistribute는 문자열 type의 변수만 파라미터로 받는다
    // 하지만 payable 형태(금전거래)의 함수여서 value와 gas fee를 transaction의 인자로 받는다. 
    this.lotteryContract.methods.betAndDistribute(challenges).send({from:this.account, value:5000000000000000, gas:300000, nonce:nonce})
    .on('transactionHash', (hash) => {
      console.log(hash);
    })
  }
  
let owner = await this.lotteryContract.methods.owner().call();
console.log(owner);

 

3. 이벤트 로그 활용하기

 

contract 내 함수에서는 주어진 절차를 수행하닥 아래와 같이 이벤트를 발생시킬 수 있다.

 

// 발생하는 이벤트의 이름과 형식
event BET(uint256 index, address indexed bettor, uint256 amount, bytes1 challenges, uint256 answerBlockNumber );

function bet(bytes1 challenges) public payable returns (bool result) {
    // check the proper ether is sent
    require(msg.value == BET_AMOUNT, "Not Enough ETH");

    // push bet to the queue
    require(pushBet(challenges), "Fail to add a new Bet Info");

    // emit 명령으로 event 로그를 남길 수 있다
    emit BET(_tail-1, msg.sender, msg.value, challenges, block.number+BET_BLOCK_INTERVAL);

    return true;
}

 

contract에서 발생한 이벤트를 javascript에서는 아래와 같이 getPastEvents로 수집하여 처리할 수 있다.

 

getBetEvents = async () => {
    const records = [];
    
    // getPastEvents 명령으로 모든 event block을 가져옴
    let events = await this.lotteryContract.getPastEvents('BET', {fromBlock:0, toBlock:'latest'});

	// 원하는 형태대로 수집된 event log를 활용
    for (let i=0;i<events.length; i+=1) {
      const record = {}
      record.index = parseInt(events[i].returnValues.index, 10).toString();
      record.bettor = events[i].returnValues.bettor;
      record.betBlockNumber = events[i].blockNumber;
      record.targetBlockNumber = events[i].returnValues.answerBlockNumber.toString();
      record.challenges = events[i].returnValues.challenges;
      record.win = 'Not Revealed';
      record.answer = '0x00';
      records.unshift(record);
    }
    // console.log(records);
    this.setState({betRecords: records});
  }

 



댓글