Skip to main content

Write (Fee Delegation)

You can make a "transaction" that including payment request to feepayer when you want to execute the Smart Contract.

Import the ethers and @kaiachain/ethers-ext modules to add kaia features on ethers.js.

Define sender, fee payer address and sender private key

Set up the provider with the specified kaia Baobab testnet URL. A provider in ethers is a read-only abstraction to access the blockchain data.

Also, you can change the provider URL from baobab to allthatnode

Create a sender's wallet using the sender's private key and the provider

Create a fee payer's wallet using the sender's private key and the provider

Set the Abi generated from solidity code

Define contract address to interact with

Create a contract instance with ethers.Contract, fill in params contractAddr, abi, provider. You can read and write the contract through this instance

Get the value of number from contract by using method counter.number()

Create a transaction data to update the number value

Create a transaction object with data from previous step

Sign the transaction with sender's wallet

Send the transaction to blockchain using fee payer's wallet. Function sendTransactionAsFeePayer adds a signature with FeePayer’s private key to the sender’s signature and transmits it to the blockchain network.

Get the updated value number by using method counter.number()

writeWithFeeDelegation.js

const ethers = require("ethers");
const { Wallet, TxType } = require("@kaiachain/ethers-ext");
const senderAddr = "0x24e8efd18d65bcb6b3ba15a4698c0b0d69d13ff7";
const senderPriv = "0x4a72b3d09c3d5e28e8652e0111f9c4ce252e8299aad95bb219a38eb0a3f4da49";
const feePayerAddr = "0xcb0eb737dfda52756495a5e08a9b37aab3b271da";
const feePayerPriv = "0x9435261ed483b6efa3886d6ad9f64c12078a0e28d8d80715c773e16fc000cff4";
const provider = new ethers.providers.JsonRpcProvider("https://public-en-kairos.node.kaia.io");
const senderWallet = new Wallet(senderPriv, provider);
const feePayerWallet = new Wallet(feePayerPriv, provider);
/* compiled in remix.ethereum.org (compiler: 0.8.18, optimizer: false)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
uint256 public number;
event SetNumber(uint256 number);
constructor(uint256 initNumber) {
number = initNumber;
}
function setNumber(uint256 newNumber) public {
number = newNumber;
emit SetNumber(number);
}
function increment() public {
number++;
emit SetNumber(number);
}
}
*/
const abi = '[{"inputs":[{"internalType":"uint256","name":"initNumber","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"number","type":"uint256"}],"name":"SetNumber","type":"event"},{"inputs":[],"name":"increment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newNumber","type":"uint256"}],"name":"setNumber","outputs":[],"stateMutability":"nonpayable","type":"function"}]';
const contractAddr = "0x95Be48607498109030592C08aDC9577c7C2dD505";
async function main() {
const counter = new ethers.Contract(contractAddr, abi, senderWallet);
console.log("number before", (await counter.number()).toString());
const data = (await counter.populateTransaction.increment()).data;
const tx = {
type: TxType.FeeDelegatedSmartContractExecution,
from: senderAddr,
to: contractAddr,
value: 0,
data: data,
};
// Sign transaction by sender
const populatedTx = await senderWallet.populateTransaction(tx);
const senderTxHashRLP = await senderWallet.signTransaction(populatedTx);
console.log("senderTxHashRLP", senderTxHashRLP);
// Sign and send transaction by fee payer
const sentTx = await feePayerWallet.sendTransactionAsFeePayer(senderTxHashRLP);
const receipt = await sentTx.wait();
console.log("receipt", receipt);
console.log("number after", (await counter.number()).toString());
}
main();

output

❯ node writeWithFeeDelegation.js
number before 293
senderTxHashRLP 0x31f88447850ba43b7400830111939495be48607498109030592c08adc9577c7c2dd505809424e8efd18d65bcb6b3ba15a4698c0b0d69d13ff784d09de08af847f8458207f6a0d9d8ebf8d1c2665cf27903234536edc078bf2857a42941a140a8617b2ca1cb7aa05006695b49733abd7dbbb4e5192d81b1f1e84efb1cf919dee6f2d4687aa32fe2
receipt {
to: '0x95Be48607498109030592C08aDC9577c7C2dD505',
from: '0x24e8eFD18D65bCb6b3Ba15a4698c0b0d69d13fF7',
contractAddress: null,
transactionIndex: 0,
gasUsed: BigNumber { _hex: '0x947e', _isBigNumber: true },
logsBloom: '0x00000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000001200000002',
blockHash: '0x9ab3f98ef92495c3a6c4b7f353ae60459d2d96cf8d3270c3285c398fd3ee912a',
transactionHash: '0xa4ea502904b63b098e650d82c69999c1537ff2426b9f391f2f16b027f00656d4',
logs: [
{
transactionIndex: 0,
blockNumber: 148740703,
transactionHash: '0xa4ea502904b63b098e650d82c69999c1537ff2426b9f391f2f16b027f00656d4',
address: '0x95Be48607498109030592C08aDC9577c7C2dD505',
topics: [Array],
data: '0x0000000000000000000000000000000000000000000000000000000000000126',
logIndex: 0,
blockHash: '0x9ab3f98ef92495c3a6c4b7f353ae60459d2d96cf8d3270c3285c398fd3ee912a'
}
],
blockNumber: 148740703,
confirmations: 2,
cumulativeGasUsed: BigNumber { _hex: '0x947e', _isBigNumber: true },
effectiveGasPrice: BigNumber { _hex: '0x05d21dba00', _isBigNumber: true },
status: 1,
type: 0,
byzantium: true
}
number after 294