Caver-js-ext-kas을 이용해서 앱에서 event 구독하는 방법이 궁금합니다

안녕하세요. 컨트랙트에서 이벤트가 발생하는 것을 실시간으로 받아서 별도의 처리를 해주는 노드js프로그램을 만들려고 합니다. 이를 위해서 일단 caver-js-ext-kas를 이용해서 앱에서 이벤트를 받아보고 싶어서 아래와 같은 형식을 작성해봤는데 “TypeError: event.watch is not a function” 에러가 발생합니다. 관련 문서나 포멧을 알려주시면 감사하겠습니다.

const contract = new caver.contract(abi, address);
const event = contract.events.SetCustomer({}, {fromBlock:61517244, toBlock: ‘latest’});
event.watch(function(error, result) {
if (!error) {
console.log("Block Number: ", result.blockNumber);
console.log(result.args.firstname);
console.log(result.args.lastname);
}
})

안녕하세요. 질문 올려주셔서 감사합니다.
먼저 이벤트를 받아서 처리할 때에는 websocket provider를 사용해서 KAS Node API를 사용해야 합니다.
아래의 예제를 참고해 주시면 감사하겠습니다.
caver-js-ext-kas의 경우 caver-js의 extension이기 때문에 caver-js Contract의 기능을 모두 사용할 수 있습니다.
다른 다양한 기능들에 대한 자세한 내용은 문서를 참고해 주시기 바랍니다.

const caver = new CaverExtKAS()
caver.initNodeAPI(chainId, accessKeyId, secretAccessKey, false) // Use websocket

const keyringContainer = new caver.keyringContainer()
const keyring = keyringContainer.add(keyringContainer.keyring.createFromPrivateKey(senderPrivateKey))

const contractAddress ='0x...'
const byteCode ='0x...'
const abi = [ {...}, {...}, ... ]

const c = caver.contract.create(abi, contractAddress)
c.setWallet(keyringContainer)
const contract = await c.deploy(
    {
        from: keyring.address,
        gas: 100000000,
        value: 0,
    },
    byteCode
)

contract.events.callevent(
    {
        fromBlock: 61517244,
        toBlock: 'latest',
    },
    (error, data) => {
        console.log(`callevent: ${data}`)
    }
)

const options = {
    from: keyring.address,
    gas: 30000,
}
await contract.methods.say().send(options) // To invoke event, send the transaction to execute function

example 소스 주신걸 실행시켜보니 caver.initNodeAPI(chainId, accessKeyId, secretAccessKey, false) 여기에서 Error: Invalid auth: To use the websocket provider, you must use an accessKey and seretAccessKey that do not contain special characters. Please obtain a new AccessKey through the KAS Console. 이런 오류가 발생합니다.

그리고 적어주신 예제 소스에서는 새로 배포를 하는 코드로 보이는데 create() 함수안에 컨트랙스 주소를 넣는 부분이 이해가 어렵습니다.

엇, 제가 테스트 코드를 만들고 질문에 적어주신 예제에 맞게 바꾸다 보니 ㅠ 잘못 전달드렸네요
일단 발생한 에러는 KAS auth에 특수문자가 들어간 경우인데요, websocket을 사용하시려면 accessKeyId와 secretAccessKey에 특수문자가 들어가지 않아야 합니다.
KAS console에서 재발급 받아 주시기 바랍니다.

const caver = new CaverExtKAS()
caver.initNodeAPI(chainId, accessKeyId, secretAccessKey, false) // Use websocket

const keyringContainer = new caver.keyringContainer()
const keyring = keyringContainer.add(keyringContainer.keyring.createFromPrivateKey(senderPrivateKey))

const contractAddress ='0x...'
const abi = [ {...}, {...}, ... ]

const contract = caver.contract.create(abi, contractAddress)
contract.setWallet(keyringContainer)
contract.events.callevent(
    {
        fromBlock: 61517244,
        toBlock: 'latest',
    },
    (error, data) => {
        console.log(`callevent: ${data}`)
    }
)

const options = {
    from: keyring.address,
    gas: 30000,
}
await contract.methods.say().send(options) // To invoke event, send the transaction to execute function

컨트랙트가 배포되어 있을 경우, caver.contract.create를 통해 Contract 인스턴스를 생성할 때 컨트랙트 주소를 같이 넣어주고 바로 사용하시면 됩니다.

정정해주신 방법대로 테스트하여 컨트랙트 함수 호출까지 진행했지만 evm: execution reverted 에러가 발생합니다. 이유는 contract owner만 실행할 수 있는 함수이기 때문입니다. 그런데 저희 컨트랙트의 owner는 kas로 생성된 계정이기 때문에 private키를 알 수 없는 상황입니다. 그래서 아래 코드부분을 private을 이용하는 방법이 아닌 형태로 수정할 방법이 없을까요?

const keyring = keyringContainer.add(keyringContainer.keyring.createFromPrivateKey(“0x35dc4bdce77201590600138a410bf0e9eb550b6fc2f33be8d2403172f724989e”))
const contract = caver.contract.create(abi, address)
contract.setWallet(keyringContainer)

카스에 있는 계정을 사용하는 경우 contract.setWallet 과정 없이 진행하시면 됩니다. 아래 예제 참고해 주세요.
caver-js-ext-kas의 경우 KAS Wallet API 위에서 동작합니다.
제가 예제로 드린 것은 따로 private key를 관리하는데 KAS API를 사용하는 경우입니다.

const caver = new CaverExtKAS()
caver.initNodeAPI(chainId, accessKeyId, secretAccessKey, false) // Use websocket

const contractAddress ='0x...'
const abi = [ {...}, {...}, ... ]

const contract = caver.contract.create(abi, contractAddress)
contract.events.callevent(
    {
        fromBlock: 61517244,
        toBlock: 'latest',
    },
    (error, data) => {
        console.log(`callevent: ${data}`)
    }
)

const options = {
    from: contractOwnerAddress,
    gas: 30000,
}
await contract.methods.say().send(options) // To invoke event, send the transaction to execute function

도와주신 덕분에 프로그램이 잘 작동하고 있습니다. 그런데 프로그램이 돌다가 1분정도 후에 자동 종료되고 있습니다. 혹시 따로 설정해줘야하는 옵션이 있는 건가요? 아래 소스 공유드립니다.

import CaverExtKAS from “caver-js-ext-kas”;

import { abi, contractAddress, contractOwner, bytecode, accessKeyId, secretAccessKey, chainId } from “./config.js”;

const caver = new CaverExtKAS()

caver.initNodeAPI(chainId, accessKeyId, secretAccessKey, false) // Use websocket

caver.initWalletAPI(chainId, accessKeyId, secretAccessKey)

const contract = caver.contract.create(abi, contractAddress)

contract.events.SetCustomer(

{

    fromBlock: 61517244,

    toBlock: 'latest',

},

(error, data) => {

    console.log("SetCustomer:", data)

}

)

contract.events.SetCreator(

{

    fromBlock: 61517244,

    toBlock: 'latest',

},

(error, data) => {

    console.log("SetCreator:", data)

}

)

const options = {

from: contractOwner,

gas:'0x4bfd200'

}

async function test() {

await contract.methods.setCustomer("0x3756a6e4B496Ac0666388e168d3b8A340B8B8c8D").send(options) // To invoke event, send the transaction to execute function

}

test();

웹소켓 연결 후 통신이 없으면 설정값에 따라 연결이 끊어지도록 되어 있습니다.

현재 KAS 의 경우 웹소켓 커넥션은 요청을 받는 것을 기준으로 관리되며, 연결 지속 시간은 1분으로 설정이 되어 있습니다.
contract.events.eventName처럼 subscribe로 주기적으로 결과를 받아오는 작업으로는 연결을 유지할 수 없습니다.
연결을 유지하려면 caver.rpc.klay.getBlockNumber와 같은 요청을 주기적으로 보내서 연결을 유지할 수 있습니다.

1개의 좋아요

아하 그렇군요… Jasmine님 모든 부분 친절히 설명해주셔서 감사합니다!! 해결되었습니다 ㅎㅎ

1개의 좋아요