Why is the address used for fee delegation not the same as one derived from the private key?

You’ve received an account (a pair of address and private key) that can be used for fee delegation. However, the given address is different from the address derived from the given private key? No worry! This is not an incorrect account nor a deceiving address.

To figure out why this account is valid in Klaytn, you’d first need to understand AccountKey.

AccountKey

Klaytn’s account model allows user to update his/her account’s private key as it decouples account’s address and private key. Here, AccountKey is the account’s public key value that is stored in the Klaytn network.

In some blockchains (e.g., Bitcoin and Ethereum), account’s address is derived form a public key, which is again determined by a private key. These relations are fixed, thus if your private key is exposed, you have to create a new account. However, in Klaytn, you don’t always have to abandon your address and create new one. Instead you can change the private key of your Klaytn account while keeping the account’s address.

For more details about Klaytn accounts, please refer to KlaytnDocs.

Confirming AccountKey

Now let’s look into AccountKey of the account received for fee delegation.

Instead of using caver, we can simply send a request using RPC API on terminal and check the output:

curl -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"klay_getAccountKey","params":["0x5a51664639409096E1A4C36439d53c4b0c9F996A", "latest"],"id":1}' https://api.baobab.klaytn.net:8651

In the command above, you can set the address parameter for klay_getAccountKey to the fee-delegation account’s address (e.g., 0x5a51664639409096E1A4C36439d53c4b0c9F996A) and the endpoint address to the one for your test node (e.g., https://api.baobab.klaytn.net:8651).

A result from executing the command above would look like the below:

{
   jsonrpc: ‘2.0’,
   id: 1,
   result: {
      keyType: 5,
      key: [
         { keyType: 2, key: { x: ‘0x56e00…’, y: ‘0x705c3…’ } },
         { keyType: 2, key: { x: ‘0xea42f…’, y: ‘0x3b7a8…’ } },
         { keyType: 2, key: { x: ‘0x88ee9…’, y: ‘0x134c3…’ } },
      ],
   },
}

keyType: 5 in the result above indicates that the account’s AccountKey is AccountKeyRoleBased, whose Account Key Type ID is 5. For details about Account Key Type ID, please visit KlaytnDocs.

AcountKeyRoleBased

The account for fee delegation is generated by setting the account’s AccountKey as AccountKeyRoleBased in order to separate the account’s roles using different private keys. The private key you’ve received is the one corresponding to RoleFeePayer of AccountKeyRoleBased. With the received private key, you can pay only for the transaction fee and cannot use for other purposes.

In summary, since AccountKey of the fee-delegation account is set to AccountKeyRoleBased, the account’s address is not the same as the address derived from the private key that you received. That is, the private key has no relationship with the account’s address.

Using Fee-delegation Account

To utilize the fee-delegation account, the transaction has to set fee payer’s address to the address you received, and then you need to sign the transaction with the private key that came together with the address of fee-delegation account (i.e., RoleFeePayer key).

The code below is an example using caver-js, where a fee payer signs a transaction with the private key for the fee delegation role:

async function feePayer() {
    // Private key and address of fee-delegation account
    const feePayerKey = '0x{private key}'
    const address = '0x{address in hex}'

    // Add the account to caver-js' in-memory wallet
    // If in-memory wallet is not used, the private key can be passed as the third parameter to feePayerSignTransaction.
    const feePayerAccount = caver.klay.accounts.createWithAccountKey(address, { feePayerKey })
    caver.klay.accounts.wallet.add(feePayerAccount)

    // Sign using either transaction object or rawTransaction string signed by sender (senderRawTransaction)
    const feeDelegatedValueTransferTx = {
        type: 'FEE_DELEGATED_VALUE_TRANSFER',
        ...
    }

    const feePayerSigned = await caver.klay.accounts.feePayerSignTransaction(feeDelegatedValueTransferTx, feePayerAccount.address)
}

For more details about managing Klaytn accounts in caver-js, please refer to KlaytnDocs.

If you’d like to sign a transaction with fee-delegation account using caver-java, Getting Started in caver-java would be a useful guide.

Lastly, to sign a transaction with RPC API on EN, the EN should enable personal API. If personal API is allowed on the EN, you can follow the steps below:

  1. Add a fee-delegation account by importing raw key using personal API.
  2. Unlock the account.
  3. Call klay_sendTransationAsFeePayer function to request signing of fee payer account.

Conclusion

The reason that the address received for fee delegation is different from the address derived from the received private key is that the fee-delegation account had been updated with AccountKeyRoleBased and thus its address and private keys are decoupled.

Have you caught concepts and mechanisms behind the fee-delegation account with the explanation above? If not yet or have more questions, please feel free to ask questions or leave some comments. Your questions and comments are always welcome! :slight_smile:

4개의 좋아요