Klip API를 사용해 Klip 지갑을 연결해보자!

gyub·2022년 5월 26일
0

GIMMEDUCK

목록 보기
1/1
post-thumbnail

뭣도 모르고 그저 호기심에 블록체인을 프로젝트의 주제로 삼아버린 저...
개발을 시작하고 매일 스불재(스스로 불러온 재앙ㅎ)를 외치며 열심히 맨 땅에 헤딩 중입니다...
그래도 오랜만에 개발하니까 재밌네요^^


저희 프로젝트의 주요 기능아주 간략하게 설명하자면,
유저가 NFT를 발행할 수 있는 권한(저희 프로젝트에서는 '알'이라고 합니다!)을 구매하면 유저가 직접 커스터마이징 해 NFT를 발행할 수 있고, 지불한 '알' 금액의 일부는 기부단체에 기부됩니다.


서비스를 이용하는 과정에서 '알'을 구매하기 위한 송금이 필요하기 때문에 암호화폐 지갑을 사용해야 하는데요!
이 지갑 정보는 민감한 정보이기 때문에 지갑 관련 데이터를 직접 다루는 것은 위험합니다.
그래서 데이터를 직접 받아오지 않고 암호화폐 지갑과 웹사이트를 연결하는 방식으로 지갑을 사용하는 과정을 처리하게 됩니다.


이 때 사용하는 지갑에는 대표적으로 메타마스크, 카이카스 등이 있습니다.
저희 팀은 klaytn 네트워크를 사용하기 때문에 klay를 저장할 수 있는 카이카스 지갑 사용을 고려했지만,
klip 지갑은 카카오톡과 연동이 되기 때문에 이 지갑을 사용하면 서비스의 접근성이 훨씬 좋아질 것으로 판단하여 klip 지갑과 연결하는 방식을 우선적으로 생각하기로 하였습니다!


klip 지갑을 이용한 작업은 다음과 같습니다.

  1. 유저의 지갑 주소 받아오기
  2. 유저의 지갑에서 우리 서비스 계좌로 klay 송금하기

위와 같은 작업을 klip api를 이용하여 실행시키고자 합니다.

Klip API란?


Klip API는 외부 서비스에서 API를 통해 Klip에 있는 KLAY 및 대체 가능한 토큰(FT)을 전송하거나 Klip에서 카드(NFT)를 발행, 조회, 전송 또는 삭제하는 기능을 제공합니다. Klip API는 Card Minting API와 App2App API로 구성됩니다.

Card Minting API를 이용하기 위해서는 서비스 가입이 필요하기 때문에 저희는 App2App API만 사용합니다.


이때, web3.js 사용, 스마트 컨트랙 작성과 같은 과정을 거치지 않아도 API 사용만으로 위와 같은 기능들을 구현할 수 있는 원리를 다음 그림과 같이 파악하였습니다.

klip 지갑에 저장되어 있는 데이터(ex. 지갑 주소)는 API를 통해 Klip 서비스 측에서 받아옵니다.
Klay 송금, 스마트 컨트랙 실행 등 블록체인과의 연결이 필요한 기능 역시, API를 통하면 Klip 서비스가 블록체인과 통신하여 과정을 처리해 줍니다.

Klip 지갑 주소 받아오기(인증)


App2App API의 사용 단계는 prepare, request, result로 총 3단계입니다.

prepare : 어떤 작업을 실행하고 싶은지 정의하는 단계
request : 위에서 정의한 작업을 실제로 실행하는 단계
result : request에서 실행한 작업에 대한 결과, 응답값을 받는 단계

사용자가 지갑 연동하기 버튼을 누르면 prepare 단계가 실행되어 klip에게 인증 작업을 실행하고 싶다는 것을 알리게 되고,
klip이 인증 작업을 실행할 수 있는 QR코드를 띄우면 사용자는 해당 QR코드를 인식시켜 카카오톡의 Klip 지갑이 실행되면 klip 서비스는 인증 작업을 처리(request)하게 됩니다.
처리가 끝나면 이에 대한 응답 값(result)을 얻을 수 있습니다.

prepare

https://a2a-api.klipwallet.com/v2/a2a/prepare 이 링크로 POST를 날립니다.
이때 보낼 데이터는 bapp의 이름과 인증 작업을 실행하고 싶다는 정보입니다.
prepare 단계에서 POST 해야하는 데이터 필드 정보는 klip api 공식 문서에서 찾아볼 수 있습니다. 이 필드 정보는 꼭 확인해서 양식에 맞춰야만 에러 없이 진행할 수 있습니다!

request

prepare 단계를 완료하면 위와 같은 객체를 얻습니다.
이 객체의 데이터 중 request_key에 담긴 request key를 추출합니다.
얻은 키를 https://klipwallet.com/?target=/a2a?request_key={request_key}request_key 자리에 넣어 QR 코드를 생성하고, 사용자는 이 QR코드를 인식시켜 klip 서비스가 인증 작업을 실행할 수 있도록 합니다.

result

https://a2a-api.klipwallet.com /v2/a2a/result?request_key= {request_key}
이 링크로부터 GET하여 인증 작업 실행에 대한 결과를 얻습니다.

이때 request에 대한 결과로 받은 객체는 다음과 같습니다.

이 객체의 데이터 중 result에 담긴 지갑 주소를 추출함으로써 지갑 주소를 받아오는 과정을 완성합니다.

코드 작성

//klip_test.js

import axios from "axios";
const A2P_API_PREPARE_URL = "https://a2a-api.klipwallet.com/v2/a2a/prepare";	//prepare url
const APP_NAME = "GIMMEDUCK";


//QR 생성 링크 만드는 함수
const getKlipAccessUrl = (request_key) => {
  return `https://klipwallet.com/?target=/a2a?request_key=${request_key}`;

};

//지갑 주소 수집
export const getAddress = (setQrvalue, callback) => {
    axios
      .post(A2P_API_PREPARE_URL, {    //prepare
        bapp: {
          name: APP_NAME,
        },
        type: "auth",	//prepare 단계에서 인증 작업 요구
      }) 
      .then((response) => {   //request
        const { request_key } = response.data;	//prepare 단계의 결과로request key 받음
        setQrvalue(getKlipAccessUrl(request_key));    //QR code 생성
        let timerId = setInterval(() => {
          axios
            .get(   //result
              `https://a2a-api.klipwallet.com/v2/a2a/result?request_key=${request_key}`
            )
            .then((res) => {
              if (res.data.result) {  
                console.log(`[Result] ${JSON.stringify(res.data.result.klaytn_address)}`);    //result에서 받은 결과 값 중 지갑 주소 확인
                console.log(res.data.result);
                console.log(res.data);
                callback(res.data.result.klaytn_address);
                clearInterval(timerId);
                setQrvalue("DEFAULT");
              }
            });
        }, 1000);
      });
  };
//App.js

import logo from './logo.svg';
import './App.css';
import React, { useState, useEffect } from "react";

import QRCode from "qrcode.react";
import * as KlipAPI from "./klip_test.js";
import {
Alert,
Container,
} from "react-bootstrap";

//QR코드와 지갑 주소를 초기화
const DEFAULT_QR_CODE = "DEFAULT";
const DEFAULT_ADDRESS = "0x00000000000000000000000000000";

function App() {

const [qrvalue_auth, setQrvalue_auth] = useState(DEFAULT_QR_CODE);
const [myAddress, setMyAddress] = useState(DEFAULT_ADDRESS);

//지갑 연동하는 함수 실행
const getUserData = () => {
  KlipAPI.getAddress(setQrvalue_auth, async (address) => {
    setMyAddress(address);	//사용자의 지갑 주소를 가져온다
  });
};

return (
  <div className="App">
    <header className="App-header">
      <button onClick={getUserData}> "지갑 연동하기"</button>
      {qrvalue_auth !== "DEFAULT" ? (		//klip_test.js에서 getAddress의 request_key가 제대로 설정되면 setQRvalue에 의해 DEFAULT 상태에서 벗어나게 된다
        <Container
          style={{
            backgroundColor: "white",
            width: 300,
            height: 300,
            padding: 20,
          }}
        >
          <QRCode value={qrvalue_auth} size={256} style={{ margin: "auto" }} />	//QR코드를 세팅한다

          <br />
          <br />
        </Container>
      ) : null}
      
    </header>
  </div>
);
}

export default App;

코드 실행 결과

1. 지갑 연동하기 버튼 클릭

2. QR 인식(휴대폰 화면)

3. 지갑 주소 출력

이로써 지갑 주소를 받아 사용자를 구별할 수 있는 기반이 마련되었습니다!

이렇게 얻은 지갑 주소를 통해 아래와 같은 작업들을 진행하게 됩니다.

  1. 지갑 연동을 하면 유저가 현재 몇 개의 '알'을 가지고 있는지 보여주기
  2. 송금 할 때 klay를 보내는 주체가 해당 유저가 맞는지 확인하기
  3. NFT 발행 할 때 NFT 소유자로 지정하기 등

Klip 지갑에서 송금하기


유저의 지갑 주소를 받아왔다면, 유저가 '알' 구매를 할 때 이 주소로부터 저희 서비스 계좌로 송금을 해야겠죠?
송금 역시 QR 코드를 찍어 klip 서비스를 실행시키고, 유저가 작업을 승인하면 송금이 완료됩니다.
이 과정도 지갑 주소 받아올 때와 같이 prepare, request, result 3단계로 이루어집니다.

prepare

prepare 단계니까 https://a2a-api.klipwallet.com/v2/a2a/prepare 이 링크로 POST를 날립니다.
이때 보낼 데이터는 bapp의 이름과 klay를 송금 작업을 실행하고 싶다는 정보, 누가 누구에게 얼마를 보낸다는 정보입니다.

request

지갑 주소 받아오기 과정과 동일하게 prepare 단계를 완료하면 위와 같은 형태의 객체를 얻게 되고, 이 객체의 데이터에서 request key를 추출합니다.
얻은 키를 https://klipwallet.com/?target=/a2a?request_key={request_key}request_key 자리에 넣어 QR 코드를 생성하고, 사용자는 이 QR코드를 인식시켜 klip 서비스가 인증 작업을 실행할 수 있도록 합니다.

result

https://a2a-api.klipwallet.com /v2/a2a/result?request_key= {request_key}
이 링크로부터 GET하여 인증 작업 실행에 대한 결과를 얻습니다.

송금 request에 대한 결과로 받은 객체의 형태는 다음과 같습니다.

transaction hash값이 있기 때문에 이후에 이 값을 이용해 송금 내역을 확인할 수도 있습니다.

코드 작성

//klip_test.js 위의 지갑 주소 받아오기에 코드 추가

import axios from "axios";
const A2P_API_PREPARE_URL = "https://a2a-api.klipwallet.com/v2/a2a/prepare"; //prepare url
const APP_NAME = "GIMMEDUCK";
const to = '0x38596eD0dceaC58632bCf8BD92B5af3854d6A768';	//GIMMEDUCK 서비스의 지갑 주소
const amount = '0.1';	//보낼 Klay 양

//QR 생성 링크 만드는 함수
const getKlipAccessUrl = (request_key) => {
  return `https://klipwallet.com/?target=/a2a?request_key=${request_key}`;

};

//지갑 주소 수집
export const getAddress = (setQrvalue, callback) => {
    axios
      .post(A2P_API_PREPARE_URL, {    //prepare
        bapp: {
          name: APP_NAME,
        },
        type: "auth",
      }) 
      .then((response) => {   //request
        const { request_key } = response.data;
        setQrvalue(getKlipAccessUrl(request_key));    //QR code 생성
        let timerId = setInterval(() => {
          axios
            .get(   //result
              `https://a2a-api.klipwallet.com/v2/a2a/result?request_key=${request_key}`
            )
            .then((res) => {
              if (res.data.result) {  
                console.log(`[Result] ${JSON.stringify(res.data.result.klaytn_address)}`);    //result에서 받은 결과 값 중 지갑 주소 확인
                console.log(res.data.result);
                console.log(res.data);
                callback(res.data.result.klaytn_address);
                clearInterval(timerId);
                setQrvalue("DEFAULT");
              }
            });
        }, 1000);
      });
  };

  //klay 전송
  export const send_klay = (setQrvalue, setMyAddress) => {
    axios
      .post(A2P_API_PREPARE_URL, {	//prepare
        bapp: {
          name: APP_NAME,
        },
        transaction: {
          from : setMyAddress, // optional, 위에서 받은 지갑 주소에서 송금한다는 것을 확인하기 위함.
          to : to,	//GIMMEDUCK 계좌로
          amount : amount,	//0.1 klay 송금
        },
        type : "send_klay",	//prepare 단게에서 klay 송금 요청
      })
      .then((response) => {	//request
        const { request_key } = response.data;
        setQrvalue(getKlipAccessUrl( request_key));		//QR코드 생성
        let timerId = setInterval(() => {
          axios
            .get(	//result
              `https://a2a-api.klipwallet.com/v2/a2a/result?request_key=${request_key}`
            )
            .then((res) => {
              if (res.data.result) {
                console.log(res.data);
                console.log(res.data.result);
                clearInterval(timerId);
                setQrvalue("DEFAULT");
              };
            });
        }, 1000);
      })
      .catch((err)=>{
        console.log(err);
      });
};
//App.js 위의 지갑 주소 받아오기에 코드 추가

import logo from './logo.svg';
import './App.css';
import React, { useState, useEffect } from "react";

import QRCode from "qrcode.react";
import * as KlipAPI from "./klip_test.js";
import {
  Alert,
  Container,
} from "react-bootstrap";

//QR코드와 지갑 주소를 초기화
const DEFAULT_QR_CODE = "DEFAULT";
const DEFAULT_ADDRESS = "0x00000000000000000000000000000";

function App() {

  const [qrvalue_auth, setQrvalue_auth] = useState(DEFAULT_QR_CODE);
  const [qrvalue_send, setQrvalue_send] = useState(DEFAULT_QR_CODE);

  const [myAddress, setMyAddress] = useState(DEFAULT_ADDRESS);

//지갑 연동하는 함수 실행
  const getUserData = () => {
    KlipAPI.getAddress(setQrvalue_auth, async (address) => {
      setMyAddress(address);
    });
  };

  //klay 송금하는 함수 실행
 const sendKLAYtoGMD = () => {
    KlipAPI.send_klay(setQrvalue_send, setMyAddress);	//인자 값으로 위에서 받은 지갑 주소를 전달한다
  };

  return (
    <div className="App">
      <header className="App-header">
        <button onClick={getUserData}> "지갑 연동하기"</button>
        {qrvalue_auth !== "DEFAULT" ? (
          <Container
            style={{
              backgroundColor: "white",
              width: 300,
              height: 300,
              padding: 20,
            }}
          >
            <QRCode value={qrvalue_auth} size={256} style={{ margin: "auto" }} />

            <br />
            <br />
          </Container>
        ) : null}

        <button onClick={sendKLAYtoGMD}> "klay 전송"</button>
        {qrvalue_send !== "DEFAULT" ? (
          <Container
            style={{
              backgroundColor: "white",
              width: 300,
              height: 300,
              padding: 20,
            }}
          >
            <QRCode value={qrvalue_send} size={256} style={{ margin: "auto" }} />

            <br />
            <br />
          </Container>
        ) : null}
      </header>
    </div>
  );
}

export default App;

코드 실행 결과

1. klay 전송 버튼 클릭

2. QR 인식(휴대폰 화면)

3. 송금 완료

객체에서 얻은 transaction hash 값을 이용하면, klaytnscope에서 해시 값으로 검색하기 기능을 활용해 transaction 내역을 확인할 수 있습니다.

이로써 klip API를 이용해 송금까지 완료하였습니다~!

profile
Want to be a developer

0개의 댓글