Caver-js invalid fee payer 질문

안녕하세요.
SDK 버전: SDK : Caver-js 1.3.1

json rpc로 아래와 같이 사이닝을 진행 했습니다.

curl -v -H " content-type : application/json" -d '{"jsonrpc":"2.0","id":"1","method":"klay_signTransaction","params":[{ "typeInt":9,
            "from": "0x보내는 어카운트는 레거시 어카운트 입니다",
            "to": "0x받는 어카운트는 레거시 어카운트 입니다",
            "value": "0xddcfbbb7a606000",
            "feePayer":"0x대납 계정은 직접 생성 했고 role bases account 입니다. ( 키타입 :5)"}]}'


response 는 아주 잘 왔습니다. 

이제 이 rawTransaction 을 가지고 Fee signing 서버에 보내서 사인하고 노드에 보내서 트랜잭션을 전파하려고 합니다.

fee payer 서버의 사이닝 및 전파 코드 입니다.
여기서 feePayerKeystoreFile 은 위에 curl 에서 feepayer로 지정한 Account json 파일입니다.
실제로 wallet 에 add되는 것을 확인했고 사이닝을 하고 전파를 하면

아래와 같은 응답이 옵니다.

invalid fee payer
let feePayerKeystoreFile = fs.readFileSync(config.walletDirectory+'/'+config.feePayerKeystoreFile)
let feePayerAccount = caver.klay.accounts.decrypt(feePayerKeystoreFile.toString(), config.feePayerKeystorePass)
console.log("fee acc addr ", feePayerAccount.address)
caver.klay.accounts.wallet.add(feePayerAccount.privateKey, feePayerAccount.address);
caver.klay.accounts.feePayerSignTransaction(rawTransactionHash, 
feePayerAccount.address).then((signedTransaction) => {

console.log(new Date().toLocaleString('en-US',{timeZone: 'Asia/Seoul'}), "Signed TX : " +req.url,JSON.stringify(signedTransaction),"\n");
caver.klay.sendSignedTransaction(signedTransaction).then(function(transactionReceipt){

console.log(new Date().toLocaleString('en-US',{timeZone: 'Asia/Seoul'}), "Daemon RESPONSE: " + req.url,JSON.stringify(transactionReceipt),"\n");

return res.status(200).json(transactionReceipt)	

			})
}

여쭈어 보고 싶은것은

  1. caver-js 사용시 fee delegation 타입의 트랜잭션들은 사이닝 할때 코드에 role based fee delegation 키가 있어야 하는가? account json 파일로 decrypt 하고 in memory wallet 에 add 하여 fee delegation 타입의 트랜잭션을 사이닝 할 수 없는가?

  2. 만약 account json 파일에서 fee delegation key를 임포트 하지 못한다면 caver-js v1.5.0 버전을 사용해서

keyring.getKeyByRole(caver.wallet.keyring.role.roleFeePayerKey)

API를 사용하면 role feepayer Key 를 노출시키지 않고도 사이닝 할 수 있는가?

이 두가지 질문입니다.

늘 친절히 답변해주셔서 감사합니다.

네 안녕하세요, 먼저 질문 올려 주셔서 감사합니다 :slight_smile:

  1. caver-js를 사용할 때에 role based fee delegation 키가 없는 경우, 즉 role에 상관없이 동일한 키를 사용하는 경우 트랜잭션의 발송자(sender)로써 서명할 때에, 그리고 Account update 트랜잭션(TxTypeAccountUpdate, TxTypeFeeDelegatedAccountUpdate, TxTypeFeeDelegatedAccountUpdateWithRatio)에 서명할 때에, 그리고 수수료 대납자(fee payer)로써 서명할 때에 모두 동일한 키를 사용하게 됩니다.

따라서 위에 올려주신 코드에서, key store 파일이 역할 별로 다르게 키를 정의하지 않았다면 decrypt된 1개 혹은 여러 개의 키를 사용하여 fee delegation 트랜잭션에 서명이 가능합니다.

  1. account json파일에서 임포트 한 계정으로 fee payer 로써 서명이 가능합니다 :slight_smile:

아래에 참고하실 수 있는 예제 코드를 첨부하겠습니다.
최대한 올려주신 코드와 비슷하게 작성했는데, 혹시 이해 안되시는 부분이 있으면 말씀해 주세요 !
참고로 아래의 rawTransactionklay_signTransaction RPC 콜 호출 결과의 raw 필드에 해당되는 값입니다.

const caver = new Caver('https://api.baobab.klaytn.net:8651/')

// Create sender and add to wallet
const sender = caver.klay.accounts.wallet.add('0x{private key}')

// Create fee delegation transaction for getting RLP-encoded string(rawTransaction)
const vt = {
    type: 'FEE_DELEGATED_VALUE_TRANSFER',
    from: sender.address,
    to: '0x{address in hex}',
    value: 1,
    gas: 50000,
}

// Sender signs to the transaction
const { rawTransaction } = await caver.klay.accounts.signTransaction(vt)
console.log(rawTransaction)

// Decrypt fee payer keystore and add to wallet
const feePayerKeystore = fs.readFileSync('./feePayer.json')
const password = 'test1234!'
const feePayer = caver.klay.accounts.decrypt(feePayerKeystore.toString(), password)
caver.klay.accounts.wallet.add(feePayer)

// Fee payer signs to the transaction as a fee payer.
const signed = await caver.klay.accounts.feePayerSignTransaction(rawTransaction, feePayer.address)
console.log(new Date().toLocaleString('en-US', { timeZone: 'Asia/Seoul' }), `Signed TX : ${JSON.stringify(signed)}\n`)

// Send signed transaction to Klaytn Node
const transactionReceipt = await caver.klay.sendSignedTransaction(signed)
console.log(new Date().toLocaleString('en-US', { timeZone: 'Asia/Seoul' }), `Daemon RESPONSE: ${JSON.stringify(transactionReceipt)}\n`)
1 Like

말씀해주셔서 감사합니다.

제가 생성하는 account가 v3버전인거 같아요
왜냐면 운영하는 en 노드 버전이 v1. 3.0에서 생성하는 account거든요.

말씀해주신 코드로 작동을 시켜봐도
여전히 invalid fee payer 응답이 옵니다.

그리고 코드상의 json 파일은 role based account 로 업데이트 된 account json 키스토어 파일입니다.

테스트 환경을 말씀드리자면
Baobab에서 en v1. 3.0 노드로 테스트 하고 있습니다

keystore 파일에서 version 이랑 address 필드 값 한 번 확인해 주실 수 있나요?

{"address":"9a84578ff351348cc3b7db13c9640d74a225e4eb","crypto":{"cipher":"aes-128-ctr","ciphertext":"c3df1bffd059a0bdd7991b22bd3609247b4f6d37995cdc969f54ac700c728bfd","cipherparams":{"iv":"0432d75f4cf3f16c5f0e969a909d375b"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"0024333345c1c9d7bdc8586a33a866efa6b0320180ea14a1942fcdddd3    704be8"},"mac":"8df46c09a6f343de7d145f1ae339dd46690da75f362079223689de3bc3be08ee"},"id":"a6851fb5-b4a5-4934-ad51-d77350396002","version":3}

입니다. 어짜피 테스트 account 라 전부다 ㅎㅎ 올리겠습니당

처음 curl 로 signing 을 진행할때 feePayer 도 당연히 올려드린 동일 Account 로 진행했습니다.

재미있는 점은 Caver-js v 1.5.0 로 caver.wallet.getKeyring(0x addr) 를 하면
Single Key ring으로 나옵니다.

확인 부탁드려도 될까요?

그럼 논의를 이쪽에서 이어나가는 것이 맞는 것 같은데요, keystore v3라면 role based key를 지원하지 않는 키스토어 버전입니다. 그걸 import하면 single key로 나오는 것이 맞는 것 같습니다. Keystore.json은 어떻게 생성하셨나요?

엇 그렇군요.
sdk v 1.3.0 버전에서
키를 3개 를 만들어서

 updateKey: caver.klay.accounts.create().privateKey ,
        transactionKey: caver.klay.accounts.create().privateKey,
        feePayerKey: caver.klay.accounts.create().privateKey,

이런식으로요

그래서

caver.klay.accounts.createAccountForUpdate

로 업데이트를 했습니다.

결과값은 키 타입이 5로 업데이트가 잘 되었어요.

아마 rpc로 “0x9a84578ff351348cc3b7db13c9640d74a225e4eb”
어카운트를 Baobab 에서 확인하시면 해당 어카운트의 타입이 5로 나옵니당.

네 이후에 다시 keystore.json에 업데이트 된 키를 저장하셔야 하는건데, 그건 어떻게 하신건가요?

업데이트 된 키는 keystore 디렉토리에 그냥 있어요.
그러니까 전체 과정을 설명드리자면

  1. ken attach
  2. CLI 에서 personal.newAccount (“pass”) 로 생성
  3. caver-js를 사용해서 Account 업데이트
  4. Account 업데이트 확인
  5. 2번에서 만든 Account.json 파일은 keystore dir에 잘 있습니다.

뭔가 더 업데이트 된 키를 저장하는 프로세스가 또 필요한가요??ㅜㅜ

혹시나 해서 말씀드리자만
ken version 1.3.0
caver-js version 1.3.1
network : baobab
입니다.

네 2번에서 만들어진 keystore.json은 single key로 처음에 만들어집니다. 3번에서 account update를 하고나서 다시 keystore.json을 업데이트 시켜줘야 role based key가 keystore.json에 저장이 됩니다. 자동으로 업데이트 되진 않구요. Keystore.json을 업데이트 하시려면 encrypt함수를 사용하면 됩니다.

아래 링크를 참고 부탁드립니다.

1 Like

앗 넵! 감사합니다.
테스트 해보고 말씀드릴게요!

퇴근시간에 죄송하지만 하나만 더 여쭤봐도 될까요? ㅠㅠㅠ
말씀하신 API 는 keystore v3 에도 적용이 되는거죵??
아님 이전에 언급하신대로 keystore v4 에만 적용이 되고 v3에서는 안되는건가요??

Keystore v4가 role based key가 적용된 버전이니까 v4만 되겠죠? V3, v4가 크게 다르지 않습니다. Caver-js는 둘 다 지원하구요. V3로만 해야 하는 이유가 있으신지요?

아 그런건 아닙니당

말씀해주신 API 를 쓰기위해서 SDK 를 1.4.1 로 업그레이드를 하고
ㅎㅎ 방금 말씀해주신 부분 encrypt를 해보니 제가 만든 Account update 를 적용해보니
Encrypt 해본 결과물을 찍어보니까 Version 4 로 나오는군요.

이대로 이 결과물을 json 파일에 넣으면 된단 말씀이시죠?

네 맞습니다. 그렇게 저장하시고 불러서 사용하시면 되겠습니다.