[Caver js] 리액트에서 스마트 컨트랙트 연동

연정·2022년 8월 11일
1

Work & Internship

목록 보기
7/7
post-thumbnail

들어가기 전에,
클레이튼 기반의 환경에서 지갑 연동을 구현하기 위하여 스터디 및 작업한 내용을 정리하였습니다.
이더리움 혹은 그 외의 환경이 궁금하신 분들께는 도움이 되지 않을 수 있습니다.


블록체인과 스마트 컨트랙트를 막 배워가는 입장에서 가장 어려웠던 점은
기본적인 FE-BE 구조와 어떤 차이점이 있고 어떤 방식으로 코드를 구성해야할지 모른다는 것이었다.
이에 대해 얕지만 쉽게 설명할 수 있는 방법이 있어 정리해본다.

REST API
FE <-- API를 통해 소통 --> BE

블록체인
FE <-- ABI를 통해 소통 --> Smart Contract --> BlockChain


FE는 ABI를 통해 스마트 컨트랙트와 통신하며, 블록체인에 영향을 미치게 된다.
일반적으로 스마트 컨트랙트는 Solidity라는 언어를 통해 구현하는데,
그 결과로 구현된 스마트 컨트랙트 파일(json) 내에 ABI가 포함되어 있다.

마치 계약의 양 측 당사자가 동일한 계약서의 사본을 각각 가지고 있는 것과 같이,
FE에서도 동일한 ABI json 파일을 프로젝트 내에 저장해두고 스마트 컨트랙트를 호출할 때 함께 전달하여 통신을 시도하게 된다.

여기까지 이해가 되었다면 다음 단계!
Klaytn 네트워크에서 스마트 컨트랙트를 실행하기 위해서 caver-js 를 활용하였다.

[ caver-js ]
개발자가 HTTP 또는 웹소켓 연결을 사용하여 Klaytn 노드와 상호작용할 수 있도록 하는 자바스크립트 API 라이브러리

[ Smart Contract 실행을 위한 단계! ]

  1. 일반 함수처럼 원하는 곳에서 호출
  2. new Caver 정의
  3. ABI를 활용하여 JSON 인터페이스 오브젝트에 정의된 모든 메소드 및 이벤트로 새 컨트랙트 인스턴스 생성
  4. 원하는 메소드에 대한 트랜잭션 객체를 생성 및 실행

1) new Caver 정의

const caver = new Caver(new Caver.providers.HttpProvider(URL, option))
const caver = new Caver('https://')
const caver = new Caver(window.klaytn)

new Caver를 정의하는 방법은 위와 같이 여러가지인데,
위의 두 가지는 HTTP provider를 통해 provider를 정의하는 방법이며
마지막 방법은 브라우저 상에서 카이카스 지갑의 provider를 이용할 때 사용하는 방법이라 한다.
나는 해당 코드를 hook으로 만들어두고 필요할 때마다 간편하게 사용하는 편.

// Custom Hook
const useCaver = () => {
	const caver = new Caver();
    return caver;
}

export { useCaver }


// 임포트 시
import { useCaver } from '/경로'

const caver = useCaver();

2) 새 컨트랙트 인스턴스 생성

new caver.klay.Contract(jsonInterface [, address] [, options])

*jsonInterface : 원하는 메소드를 보유한 전체 ABI
*address : contract address

caver-js의 해당 객체를 통해 ABI에 정의된 모든 메소드와 이벤트를 가진 컨트랙트 인스턴스(복제본)를 생성할 수 있다. 즉 이 작업을 통해 드디어 우리는 스마트 컨트랙트 내에 구현되어 있는 메소드(함수)를 사용할 수 있다는 이야기!!

+) ABI를 잘 살펴보면 name이라는 키값으로 우리가 불러올 메소드명이 정리된 걸 볼 수 있다!

3) 원하는 메소드에 대한 트랜잭션 객체를 생성 및 실행

컨트랙트 인스턴스가 준비 되었다면, 이제는 그 중 원하는 메소드를 실행할 차례!

myContract.methods.methodName([param1 [, param2 [, ...]]])
myContract.methods['methodName']([param1 [, param2 [, ...]]])

*myContract : 2단계에서 생성한 컨트랙트 인스턴스를 변수에 저장한 값
*methodName : 실행을 원하는 메소드의 이름
*param : 메소드별 상이

위와 같이 메소드에 대한 트랜잭션 객체를 생성했다면,
뒤에 몇가지를 덧붙이는 것으로 원하는 방식으로 실행이 가능하다

myContract.methods.methodName().call(options [, callback])
myContract.methods.methodName().send(options [, callback])

call()은 트랜잭션을 보내지 않고 메소드를 Klaytn 가상머신에서 실행한다.
데이터를 읽어오기만 하면될 때 주로 사용한다.

send()는 Klaytn으로 트랜잭션을 전송하고 메소드를 실행한다. (스마트 컨트랙트 상태 변경 가능)
또한 이 호출은 옵션에 기본적으로 from / gas를 포함하는데,
from은 트랜잭션을 보낼 송신자 주소(트랜잭션 실행에 따른 수수료가 빠져나갈 주소)이며
gas는 해당 트랜잭션을 위한 최대 가스값(limit)을 지정한다. gas는 최댓값으로 그 안의 범위 내에서 수수료가 나가니 두려워하지 말 것.

이 외에도 다수의 방법이 있으니 공식문서 참고!


이 모든 방법을 이리저리 연구해서 실제로는 아래와 같이 활용 중이다.

// app.js
function App () {
	const { onAdd } = useAddData(필요한 params 전달)
    
    const addData = () => {
    	const res = onAdd();
        
        if(!res){
        	alert('Failed!')
        } else {
        	alert('Success!')
        }
    }
    
    return (
    	<div>
        	<button onClick={addData}>버튼</button>
        </div>
    )
}

// useAddData.js
export const useAddData = () => {
	let contract = getSmartContractPool(컨트랙트 주소, ABI)
    
    const handleAdd = useCallback(async () => {
    	try {
        	const tx = await addData(contract, 송신자 주소, 필요한 params)
            return tx;
        } catch (err) {
        	console.error('contract err', err)
            return false;
        }
    }, [의존하는 것 전부 기입]);
    
    return { onAdd: handleAdd }
}

// getSmartContractPool.js
import { useCaver } from '/경로'

const caver = useCaver();

export const getSmartContractPool = (컨트랙트 주소, ABI) => {
	const contract = new cav.klay.Contract(ABI, 컨트랙트 주소); //2단계
    return contract;
}

// addData.js
export const addData = async(contract, 송신자 주소, params) => {
	return contract.methods.addData(params).send({
    	from: 송신자 주소,
        gas: 3000000,
    }) //3단계
}

사실 전체 프로젝트를 지갑 연동과 함께 사용 중이라, 위에 작성한 전체 이전에 지갑 연결이 우선되어야 한다. 또한 가장 기본인 kaikas 연결을 기준으로 작성한 코드라 다른 지갑과 연결이 되면 코드가 달라질 수 있다. 이건 다음 포스트에서 다루기로!

참고자료
https://ko.docs.klaytn.foundation/dapp/sdk/caver-js

profile
성장형 프론트엔드 개발자

1개의 댓글

comment-user-thumbnail
2022년 9월 30일

한가지 질문이 있습니당. custom hook을 만들어주신다고하셨는데.. 저거는 그냥 서비스 함수라던지 유틸함수가 아닐까용??

답글 달기