Ethereum 계약과 React의 협력

추가 2020/3/4



web3 업데이트를 지원하고 TypeScript + React + Redux + Web3 + truffle + React-router 보일러 플레이트를 만들었습니다. 여기에 있습니다.

추가 2019/12/29



이 기사보다 React Truffe Box 더 낫습니다.

이 기사에 대하여



solidity로 계약은 쓸 수 있지만, 결국 어떻게 프런트 엔드와 연결하면 좋을까?
라고 하는 의문을 조금이라도 해결할 수 있으면 좋겠다고 생각해, 자신의 체험을 써 봅니다.

개발 환경



현재의 Ethereum상에서 동작하고 있는 Daaps로 폭넓게 사용되고 있는 프레임워크인 truffle에서의 개발을 상정합니다.
프런트 엔드는 truffle의 공식 사이트에서도 추진되고 있는 React를 이용합니다.
  • 이더리움
  • Truffle
  • Ganache 1.1.0
  • remix
  • 인프라. 이오
  • React
  • Next.js

  • 절차



    다양한 설치


  • npm init
  • npm install --save next react react-dom
  • npm install truffle-contract --save

  • package.json에 다음을 추가



    package.json
     {
       // ...
       "scripts": {
         "dev": "next client", 
         "test": "echo \"Error: no test specified\" && exit 1"
       },
       // ...
     }
    

    다음과 같이 클라이언트 폴더, 페이지 폴더 등을 만듭니다.





    metamask 확인



    client/web3/provider.js
    
     import Web3 from "web3"
    
     const provider = () => {
       // If the user has MetaMask:
       if (typeof web3 !== 'undefined') {
         return web3.currentProvider
       } else {
         console.error("You need to install MetaMask for this app to work!")
       }
     }
    
     export const eth = new Web3(provider()).eth
    

    client/pages/index.js 만들기



    client/pages/index.js
     import {eth,getInstance} from "../web3/provider"
    
     export default class IndexPage extends React.Component{
         render() {
             return (
              <h1>Hello</h1>
             )
         }
     }
    
    npm run dev 그러면 브라우저가 열리고 localhost : 3030에 Hello가 표시됩니다.

    truffle migrate 다음에 contract의 json 파일을 복사해야하므로 다음을 package.json에 추가



    package.json
     {
       // ...
       "scripts": {
         "dev": "npm run artifacts && next client",
         "artifacts": "cp -r ./build/contracts/ ./client/web3/artifacts",
         "test": "echo \"Error: no test specified\" && exit 1"
       },
    
       // ...
     }
    
    npm run artifacts 실행.
    이제 js 파일에서 계약 인스턴스를 호출 할 수 있습니다.

    인스턴스를 호출하는 방법



    index.js
    import { eth, getInstance } from "../web3/provider"
    export default class IndexPage extends React.Component {
        async componentDidMount() {
            const storage = await getInstance(Vote) 
            console.log(storage) 
        }
    }
    

    getInstance는 web3/provider.js에 정의되어 있습니다.



    이하, getInstance의 정의

    web3/provider.js
     export const getInstance = artifact => {
         const contractObj = contract(artifact)
         contractObj.setProvider(provider())
         return contractObj.deployed()
     }
    

    함수를 실행하려면


  • 기본적으로 contractInstance.function()에서 함수를 호출 할 수 있습니다.

  • client/pages/index.js
      import { eth, getInstance } from '../web3/provider'
      import Vote from "../web3/artifacts/Vote.json"
      import {SetVoterAddr} from "../web3/voters"
    
      export default class IndexPage extends React.Component {
        async componentDidMount() {
          const storage = await getInstance(Vote)
          const ownerAddr = await storage.ownerAddr.call()         
          console.log("Owner Address : ",ownerAddr)
        }
      }
    

    이제 계약으로 구현 된 함수를 프론트 엔드에서 호출 할 수있었습니다.

    양식과의 협력



    양식


  • handleSubmit에 await function(this.state.value) 추가

  • voter.js
     export class SetVoterAddr extends React.Component{
       constructor(props){
         super(props);
         this.state = {value:''};
         this.handleChange = this.handleChange.bind(this);
         this.handleSubmit = this.handleSubmit.bind(this);
       }
    
       async handleChange(event){
         this.setState({value:event.target.value});
       }
    
       async handleSubmit(event){
         console.log("An address was submitted:" + this.state.value);
         event.preventDefault();
         await setVoterAddr(this.state.value)   // <-- add this line
         await test(this.state.value)
       }
    
       render(){
         return(
           <form onSubmit={this.handleSubmit}>
             <label>
               Voter Address:
               <input type="text" value={this.state.value} onChange={this.handleChange}/>
             </label>
             <input type="submit" value="Submit"/>
           </form>
         )
       }
     }
    

    참고 : 함수를 호출 할 때 계정을 지정하지 않으면 invalid address가됩니다.



    기본 함수 호출 방법
     // eth.getAccounts()でaddressをゲットしておかないといけない
     export const test = async(value)  => {
       const storage = await getInstance(Vote)
       const addresses = await eth.getAccounts()
       const tx = await storage.test(
         value,
       {
         from:addresses[0],
       })
    
       return tx
     }
    

    요약



    프론트 엔드와 계약을 연결하는 방법은 다른 것입니다.
    여기까지 올린 샘플 코드는 여기에 있습니다.

    좋은 웹페이지 즐겨찾기