[React] 카카오톡 Klip 지갑 연동 후 컨트랙트 값 변경하기 (클레이튼 메인넷)
NFT 블록체인 마켓 앱 만들기 3기 / Klip / Klip API

🦁 [PROJECT LION] NFT 블록체인 마켓 앱 만들기 with 그라운드X 3기 - 챕터 4-6 회고
Klip
Klip은 모바일용 블록체인 지갑 서비스이다
👉 카카오톡에 연동되어 메신저만큼 쉬운 사용자 경험을 제공한다

Klip API
Klip API는 외부 서비스에서 API를 통해
Klip에 있는 토큰을 전송하거나
NFT 발행 & 조회 & 전송 & 삭제하는 기능을 제공한다
https://docs.klipwallet.com/
(👆 Klip Docs)
Klip API를 이용하여 Klip 지갑 연동 (메인넷)
-1. Klaytn IDE 에서 간단한 스마트 컨트랙트 코드를 작성하고 배포(Deploy)
👉 카운터 숫자를 증가시키는 예제
⭐ Klip 은 테스트넷(Baobab) 에서 실행을 못하기때문에
메인넷에서 사용할 실제 KLAY 가 필요하다 ❗

배포하고 나온 ABI / 컨트랙트 주소 를 복사한다
-2. ABI / 컨트랙트 주소 를 입력하고 axios 를 이용해 API 호출을 한다

이때 ❗ ABI 는 다 가져오지않고 내가 호출하고싶은 (변경하고싶은 값) 컨트랙트만 가져와서 붙여넣는다 (setCount)
https://docs.klipwallet.com/rest-api/rest-api-a2a
(👆 API 코드는 Klip Docs에 나와있음)
-3. 앞에 작성된 코드에 이어서 request_key 값을 이용해서 API를 가져오고 콜백함수 setQrCodeValue 에 담아준다

-4. App.js 로 돌아와서 Klip 지갑 연동을 위해 QR코드 생성해준다

👆 콜백함수로 받았던 자리에 setState 값을 대입해서 QR코드 value 값을 바꿔준다
-5. npm run start 로 실행시킨뒤 확인해보면 기본값인 QR코드가 나온다

👆 버튼을 누르면 Klip 지갑 연결 QR코드와
> 컨트랙트 값을 변경하는 QR코드가 생성 된다
-6. 카운트 값 변경 버튼을 눌러 생성한 QR코드를 ‘스마트폰’ 으로 스캔해보면 Klip 로그인창이 나온다

👆 배포할때 나온 컨트랙트 주소가 Klip 에도 똑같이 나오는걸 확인 할 수 있다
-7. Klip 지갑을 연결하면 콘솔창에 "status" : "pending" 이라는 트랜잭션 발생값이 찍힌다

👆 발생한 트랜잭션을 ‘klaytnscope’ 에서 확인해보면
pending 중이던 상태가 👉 Success 로 바껴 있는걸확인
-8. Klaytn IDE 로 다시 돌아가서 카운트 값 변경 (컨트랙트 값 변경) 이 잘 되었는지 count 를 클릭(call) 해본다

리액트 코드에서 설정한 ‘2000’ 값으로 값이 변경되어 있는걸 볼 수 있다 ❗
카운터 숫자를 증가시키는 스마트컨트랙트 예제 코드
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.24 <=0.5.6;
contract Count {
uint256 public count = 0;
function getBlockNumber() public view returns (uint256) {
return block.number;
}
function setCount(uint256 _count) public {
count = _count;
}
}
Klip 지갑 연동 후 컨트랙트 값 변경하기 (메인넷)
UseKlip.js
import axios from "axios";
export const COUNT_CONTRACT = "0xA914d3Eb961E209906dc76AF341141Bba712b7f9";
// 배포하고 나온 컨트랙트 주소
const A2P_API_PREPARE_URL = "https://a2a-api.klipwallet.com/v2/a2a/prepare";
const APP_NAME = "KLAY_MARKET";
// 공통적으로 들어가는 URL, 파라미터 👉 변수로 지정해준다
export const setCount = (count, setQrCodeValue) => {
// 카운터
axios
.post(A2P_API_PREPARE_URL, {
bapp: {
name: APP_NAME,
},
type: "execute_contract",
transaction: {
to: COUNT_CONTRACT,
abi: '{ "constant": false, "inputs": [{ "name": "_count", "type": "uint256" }], "name": "setCount", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }',
value: "0",
params: `[\"${count}\"]`, // count값을 뭘로 변경할건지 (파라미터값)
},
})
// { // 클립 API 에 👉 execute_contract 👉 transaction 파라미터
// "transaction": {
// "from": "0x8756...4321", // optional
// "to": "0xA987...4321", // contract address
// "value": "1000000000000000000", // 단위는 peb. 1 KLAY
// "abi": "...",
// "params": "..."
// }
// }
.then((res) => {
const requestKey = res.data.request_key;
// API 로부터 request_key 값
const qrcode = `https://klipwallet.com/?target=/a2a?request_key=${requestKey}`;
setQrCodeValue(qrcode);
// 콜백함수에 담음
let timeId = setInterval(() => {
// 주기적으로 실행한다 (1초마다)
axios
.get(
`https://a2a-api.klipwallet.com/v2/a2a/result?request_key=${requestKey}`
) // result API에 request_key 값
.then((res2) => {
if (res2.data.result) {
// result 값이 있다면
console.log(`[Result] ${JSON.stringify(res2.data.result)}`);
clearInterval(timeId); // 주기적으로 실행하던걸 중지
}
});
}, 1000); // 1초마다
});
};
export const getAddress = (setQrCodeValue) => {
axios
.post(A2P_API_PREPARE_URL, {
bapp: {
name: APP_NAME,
},
type: "auth",
})
.then((res) => {
const requestKey = res.data.request_key;
const qrcode = `https://klipwallet.com/?target=/a2a?request_key=${requestKey}`;
setQrCodeValue(qrcode);
let timeId = setInterval(() => {
axios
.get(
`https://a2a-api.klipwallet.com/v2/a2a/result?request_key=${requestKey}`
)
.then((res2) => {
if (res2.data.result) {
console.log(`[Result] ${JSON.stringify(res2.data.result)}`);
clearInterval(timeId);
}
});
}, 1000);
});
};
App.js
import "./App.css";
import { useState } from "react";
import QRCode from "qrcode.react";
import * as KlipAPI from "./api/UseKlip";
const DEFAULT_QR_CODE = "DEFAULT"; // QR코드는 기본 DEFAULT 값
function App() {
const [qrvalue, setQrvalue] = useState(DEFAULT_QR_CODE);
const onGetAddress = () => {
// 주소가져오기
KlipAPI.getAddress(setQrvalue);
// UseKlip.js 에서 getAddress 함수를 가져옴
// getAddress에서 받는 인자를 setState에 대입한다
};
const onCount = () => {
// 카운터 변경하기
KlipAPI.setCount(2000, setQrvalue);
// UseKlip.js 에서 setCount 함수를 가져옴
// setCount에서 받는 인자 / 콜백함수는 setState에 대입한다
};
return (
<div className="App">
<button
onClick={() => {
onGetAddress();
}}
>
주소가져오기
</button>
<button
onClick={() => {
onCount();
}}
>
카운트 값 변경
</button>
<QRCode value={qrvalue} />
</div>
);
}
export default App;