Fee Delegation 이벤트 사용 문의

Fee Delegation 이벤트 사용 가이드에 따라 Baobab 에서 테스트 중입니다.

caver-js 1.5.0 으로 Contract 전송 코드를 작성하였습니다.

기존 방식으로 전송이 성공하는 것을 확인한 다음, 가이드 지침에 따라 수령한 feePayer address 를 keystore 파일에서 기존 주소를 변경하고 테스트 전송을 하면 다음 오류가 발생합니다.

(node:3121) UnhandledPromiseRejectionWarning: Error: Returned error: invalid fee payer

    at Object.ErrorResponse (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/caver-js/packages/caver-core-helpers/src/errors.js:74:16)

    at /Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/caver-js/packages/caver-core-requestmanager/src/index.js:155:44

    at XMLHttpRequest.request.onreadystatechange (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/caver-js/packages/caver-core-requestmanager/caver-providers-http/src/index.js:112:13)

    at XMLHttpRequestEventTarget.dispatchEvent (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request-event-target.ts:44:13)

    at XMLHttpRequest._setReadyState (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request.ts:219:8)

    at XMLHttpRequest._onHttpResponseEnd (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request.ts:345:8)

    at IncomingMessage.<anonymous> (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request.ts:311:39)

    at IncomingMessage.emit (events.js:203:15)

    at IncomingMessage.EventEmitter.emit (domain.js:448:20)

    at endReadableNT (_stream_readable.js:1129:12)

(node:3121) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)

(node:3121) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

그리고 Cypress 에서도 돌려봤는데… 여기서는 다음 오류가 발생합니다.

send error Error: Returned error: not a program account (e.g., an account having code and storage)
at Object.ErrorResponse (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/caver-js/packages/caver-core-helpers/src/errors.js:74:16)
at /Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/caver-js/packages/caver-core-requestmanager/src/index.js:155:44
at XMLHttpRequest.request.onreadystatechange (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/caver-js/packages/caver-core-requestmanager/caver-providers-http/src/index.js:112:13)
at XMLHttpRequestEventTarget.dispatchEvent (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request-event-target.ts:44:13)
at XMLHttpRequest._setReadyState (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request.ts:219:8)
at XMLHttpRequest._onHttpResponseEnd (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request.ts:345:8)
at IncomingMessage.<anonymous> (/Users/leesangwon/Documents/projects/blockpet/examples/klaytn-1.5.x/node_modules/xhr2-cookies/xml-http-request.ts:311:39)
at IncomingMessage.emit (events.js:203:15)
at IncomingMessage.EventEmitter.emit (domain.js:448:20)
at endReadableNT (_stream_readable.js:1129:12)

무슨 이유일까요?

관련 부분 소스 코드 첨부합니다.

const sendTransaction = async (from, input, options) => {
  const { privateKey } = from;
  let { feePayer } = options || {};

  if (!feePayer) {
    const keystore = fs.readFileSync(FEE_DELEGATED_KEYSTORE, 'utf8');
    feePayer = caver.wallet.keyring.decrypt(keystore, FEE_DELEGATED_KEYSTORE_PASSWORD);
  }
  try {
    caver.wallet.add(feePayer);
  } catch (ex) {
    const errorMessage = ex.toString();
    if (!errorMessage.includes(`Error: Duplicate Account ${feePayer.address}`)) {
      console.log('Adding feePayer into the wallet failed', ex);
      return;
    }
  }

  const sender = caver.wallet.keyring.createFromPrivateKey(privateKey);
  try {
    caver.wallet.add(sender);
  } catch (ex) {
    const errorMessage = ex.toString();
    if (!errorMessage.includes(`Error: Duplicate Account ${sender.address}`)) {
      console.log('Adding sender into the wallet failed', ex);
      caver.wallet.remove(feePayer.address);
      return;
    }
  }

  const tx = new caver.transaction.feeDelegatedSmartContractExecution({
    from: sender.address,
    to: SMART_CONTRACT_ADDRESS,
    input,
    gas: GAS_LIMIT,
    feePayer: feePayer.address,
  });

  await caver.wallet.sign(sender.address, tx);
  await caver.wallet.signAsFeePayer(feePayer.address, tx);
  let receipt;
  try {
    receipt = await caver.rpc.klay.sendRawTransaction(tx.getRLPEncoding());
  } catch (ex) {
    console.log('send error', ex);
  }

  caver.wallet.remove(sender.address);
  caver.wallet.remove(feePayer.address);

  return receipt;
};

안녕하세요, 질문 주셔서 감사합니다 :slight_smile:

일단 cypress로 실행했을 때에 나는 에러의 경우, cypress 네트워크에서 SMART_CONTRACT_ADDRESS에 해당하는 주소가 스마트 컨트랙트가 아니기 때문에 나는 에러인 것 같습니다 !

그리고 올려주신 코드로 제가 따로 실행했을 때에 정상적으로 동작하는 것을 확인 했습니다.
아마 keystore에 저장된 정보와 사용하려고 하는 fee payer 정보가 제대로 일치하지 않는 것 같아 보이는데,
혹시 feePayer keystore를 로드하고 나서 아래와 같이 콘솔을 찍어서 정보를 좀 비교해볼 수 있을까요?
아래 콘솔에서 찍히는 값을 공유해 주시면 좀 더 수월하게 원인을 파악할 수 있을 것 같습니다 :slight_smile:

if (!feePayer) {
    const keystore = fs.readFileSync('keystore.json', 'utf8')
    feePayer = caver.wallet.keyring.decrypt(keystore, FEE_DELEGATED_KEYSTORE_PASSWORD)
    console.log(feePayer)
    console.log(`feePayer address: ${feePayer.address}`)
    console.log(`feePayer.key.getPublicKey(): ${feePayer.key.getPublicKey()}`)
    console.log(`feePayer key from Network:`)
    console.log(await caver.rpc.klay.getAccountKey(feePayer.address))
}

실행해보니 publicKey까지는 정상적으로 리턴이 되구요. 마지막 값이 null 리턴입니다.

feePayer address: 0xacbxxxxxxxx...
feePayer.key.getPublicKey(): 0xd4470xxxxxxxxx...
feePayer key from Network:
null

네, 감사합니다.
혹시 출력되는 fee payer address가 사용하고자 하는 address가 맞으실까요?
참고로 마지막에 Klaytn에 getAccountKey 요청의 결과가 null이 나왔다는 것은 network에 해당 주소의 account 가 존재하지 않는다는 의미입니다.