Web3.js과 비슷한 Caver를 사용하여 KAS기반 클레이튼 서버 개발을 진행해봤다.
https://github.com/PILSUCHOI/Cas-Server -- 코드 저장소
https://ko.docs.klaytn.foundation/dapp/sdk/caver-js/getting-started#smart-contract --- 클레이튼 공식 문서
원했던 기능 구현 :
ㄱ. 버전 체크
ㄴ. 계정 생성
ㄷ. 잔고 확인
ㄹ. 토큰 전송
ㅁ. 스마트 컨트랙트 배포
현재 완성된 기능 : ㄱ, ㄴ, ㄷ
ㄹ & ㅁ, 즉 토큰 전송과 스마트 컨트랙트 배포는 에러로 인해 디버깅 중이다..
바탕화면에 cas 폴더 생성
VS CODE로 접속 후 해당 폴더 (cas) 오픈. 이후 터미널 열기
npm init // json 파일 생성 위한 모듈 설치
npm install caver-js // cas 구축 위한 모듈 설치
npm install express // 미들웨어 사용 위한 express 설치
.env 파일 생성 // 본인의 카이카스 address 및 비밀키(개인키) 보관용
.gitignore 파일 생성 // .env 파일이 git에 올라가는 것을 막기 위해 파일 생성
셋팅이 완료되면 좌측 디렉토리에 파일이 5개 생성되어 있을 것이다. 이제 index.js에 각각의 기능들을 간단하게 구현하면 된다. 그 전에 우리가 사용할 모듈들을 상단에 import 하는 작업을 먼저 진행하자
const express = require('express'); // 미들웨어 적용 위한 express 모듈 갖고오기
const app = express(); // 미들웨어 적용
const port = 8080;
const Caver = require('caver-js'); // cas 구현 위한 모듈 caver-js 설치 후 import
const { application } = require('express');
const caver = new Caver('https://api.baobab.klaytn.net:8651/')
require('dotenv').config(); // 환경 변수 .env파일 사용을 위한 dotenv import
app.use(express.json());
app.use(express.urlencoded({ extended: false })); // undefined 오류 방지 위한 urlencoded
app.listen(port, () => { console.log('서버 시작') }); // 터미널에 찍히는 멘트. 서버 렌더링 위한 코드
app.get("/", async (req, res) => { res.send("서버 start") }); // 서버 페이지에 찍히는 멘트. 서버 정상 실행시 응답 돌려준다
기본 모듈들을 가져왔다면 첫 번째 기능인 버젼 체크를 구현해보자.
서버를 실행하기 위해서는 터미널에 다음을 입력하자.
node index.js
물론 package.json에 scripts 파트에 start를 집어넣어서 npm start로 진행해도 된다.
"scripts" : {
----- 중략 ----
"start" : "node index.js"
----- 중략 ----
}
lsof -i : (포트번호) // 포트번호에 점유된 pid 검색 ex) --- lsof -i :8080
kill -9 (pid) // 검색된 pid를 해당 명령어로 강제 종료시킬 수 있다
// 1. 버젼 확인
app.get('/version', async (req, res)=> {
const version = await caver.rpc.klay.getClientVersion();
res.send(version);
})
postman에서 get 메소드로 다음의 주소를 입력하면 body를 통해 현재 버젼을 응답한다
http://localhost:8080/version
// 2. 계정(주소, 비밀키) 생성
app.get('/createaccount', async(req, res)=> {
const account = await caver.klay.accounts.create();
const create = await caver.klay.accounts.wallet.add(account);
const newAccount = {
Address : create.address,
Privatekey : create.privateKey
}
res.json(newAccount)
}) // create() 메서드로 계정 만들고 계정을 지갑에 넣어 사용가능한 지갑으로 만든다
마찬가지로 포스트맨을 활용하여 createaccount 루트로 get 메소드로 요청하면 주소와 키를 생성할 수 있다.
// 3. 잔고 확인
app.get('/getbalance', async(req,res) => {
const balance = await caver.klay.getBalance(req.body.address)
const show = caver.utils.convertFromPeb(balance, 'KLAY')
res.json(`현재 잔고 : ${show}`);
}) // 바디로 받은 주소값을 getBalance에 넣어주면 현재 잔고값을 가져온다.
// 잔고값을 convertFromPeb 메서드로 지갑에 디스플레이한다
카이카스에서 잔고를 확인하고 싶은 계정 주소를 복사한 후 postman에서 Body의 key와 value를 채워서 get 메소드로 요청한다.
key : address, value : (해당 주소)
// 4. 토큰 전송
app.get('/transfer', async(req, res) => {
let to = req.body.toAddress // 받을 사람 주소
let amount = req.body.amount
let balance = await caver.klay.getBalance(process.env.FROM_ADDRESS)
balance = caver.utils.fromPeb(balance, 'KLAY')
let check = await caver.klay.accountCreated(to); // 계정 존재 유무 체크
console.log(check);
if(check && balance > amount) { // 계정 존재하고 토큰 부족 여부를 체크한 후 요청 갯수보다 예치된 금액이 더 크면 전송
const keyring = caver.wallet.keyring.createFromPrivateKey(process.env.PRIVATE_KEY);
const valueTransfer = caver.transaction.valueTransfer.create({
from : keyring.address,
to : to,
value : caver.utils.toPeb(`${amount}`, 'KLAY'),
gas : 30000,
});
const signed = await valueTransfer.sign(keyring)
const receipt = await caver.rpc.klay.sendRawTransaction(signed)
console.log(receipt)
res.send(receipt)
}
else { // 계정 없거나 잔액 부족시
res.status(400).send('유효하지 않은 계정이거나 잔액 부족입니다')
}
})
즉, 정상 응답 처리가 아닌 에러 처리로만 응답 중이다.
터미널에서 true가 찍히는걸 보아하니 console.log(check) 까지는 정상적으로 넘어가는 것 같은데 다음단부터가 문제다.
keyring이고 valueTransfer고 signed고 다 콘솔을 넣어서 어느 부분부터 막히나 확인하려 했지만 아예 반응이 없다..
이게 뭐지..?
그냥 개인적인 추측인데 클레이튼 서버가 최근 자주 다운되고 메인넷이 불안정하기에 메서드를 교체하거나 수정한거 같은데 아직 docs가 업데이트가 되지 않은거 같다. cas 개발 관련 커뮤니티가 활성화된것도 아니라서 디버깅에 상당히 애를 먹고 있는 중이다. 우선은 그래서 막히는 부분은 스킵하고 여유가 있을 때 다시 시도해보기로 했다
// 5. smart contract 배포
app.post('/deploy', async(req, res) => {
const account = caver.klay.accounts.wallet.add(process.env.PRIVATE_KEY)
const ABI = req.body.abi
const Bytecode = req.body.bytecode ;
await caver.klay.sendTransaction({
type : 'SMART_CONTRACT_DEPLOY',
from : account.address,
data : caver.klay.abi.encodeContractDeploy(ABI, Bytecode, 1, 2),
gas : '300000',
value : 0,
}).on('transactionHash', function(hash){
console.log('transaction Hash!', hash)
}).on('receipt', function(receipt){
console.log(receipt)
res.json('contract deploy success!')
}).on('error', console.error);
})
원했던 기능들을 다 구현하지 못해서 살짝 찝찝한 기분이다. 메소드의 문제인가, syntax의 문제인가 감이 아직 오지 않는거 같다. 추후에 시간이 생긴다면 다시 건들여보고 수정해야겠다