Skip to main content

Gas Fee Delegation

Kaia Fee Delegation Program for Kaia Wave Builders

Introduction

The fee delegation of Kaia network is a feature that allows another account to pay for the transaction gas fee. This allows users to perform transactions without spending their own $KAIA for the gas fee of a transaction.

Apply Form >

Concept

Kaia fee delegation consists of three main components:

  1. Sender: The account submitting the transaction (from)
  2. Unifi Apps: The relayer that relays the user signed transaction to the fee payer server
  3. Fee payer server: Sign as fee payer and send the signed transaction to the network and return the receipt to the caller

The operations of Kaia fee delegation are as follows:

  1. The sender creates the transaction.
  2. The sender specifies the fee payer's address in the transaction.
  3. The sender signs the transaction.
  4. The sender sends the signed transaction to backend of Unifi Apps.
  5. The backend requests a transaction sign to the fee payer server.
  6. The fee payer server signs the transaction as a fee payer, sends it to the network, gets a receipt of the transaction and returns the transaction receipt.

Code Samples

Pre-requisite

  1. SDK
    1. ethers-ext is one of kaia-sdk should be installed.
    2. ethers-ext getting-started
  2. Wallet
    1. fee-delegation is only supported by
      1. kaia-wallet mobile/extension, Unifi-wallet liff/web
    2. Unifi Apps front-end should get a user signed transaction via the wallets

Code snippet in web application

Frontend (React) - getting a user signed transaction

fee-delegated value transfer example

import { Web3Provider } from "@kaiachain/ethers-ext";
import { TxType, parseKaia } from "@kaiachain/js-ext-core";
import DappPortalSDK from "@linenext/dapp-portal-sdk";
import { useEffect, useState } from "react";
 
// testnet
const feePayer = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
// mainnet
const feePayer = "0x22a4ebd6c88882f7c5907ec5a2ee269fecb5ed7a";
 
const clientId = "30e…b89";
const chainId = "1001";
 
export default function home() {
 const [provider, setProvider] = useState<any>(null);
 const [accounts, setAccounts] = useState<string[]>([]);
 
 const initProvider = async () => {
   const sdk = await DappPortalSDK.init({
     clientId,
     chainId,
   });
   const provider = new Web3Provider(sdk.getWalletProvider());
   const accounts = await provider.send("kaia_requestAccounts", []);
   setProvider(provider);
   setAccounts(accounts);
 };
 
 const sign = async () => {
   const tx = {
     typeInt: TxType.FeeDelegatedValueTransfer,
     from: accounts[0],
     to: accounts[0],
     value: parseKaia("0.1").toHexString(),
     feePayer,
   };
   const signedTx = await provider.send("kaia_signTransaction", [tx]);
 
   // send the signed tx to backend
   console.log(signedTx);
 };
 
 useEffect(() => {
   initProvider();
 }, []);
 
 return (
   <div>
     <button onClick={sign}>Get user signed tx</button>
   </div>
 );
}

fee-delegated smart contract execution example

import { Web3Provider } from "@kaiachain/ethers-ext";
import { TxType, parseKaia } from "@kaiachain/js-ext-core";
import DappPortalSDK from "@linenext/dapp-portal-sdk";
import { useEffect, useState } from "react";
 
const feePayer = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
const clientId = "30e…b89";
const chainId = "1001";
const contractAddr = "0x95Be48607498109030592C08aDC9577c7C2dD505";
const abi = '[...]' //copy from https://docs.kaia.io/ko/references/sdk/ethers-ext/v6/smart-contract/write/
 
export default function home() {
const [provider, setProvider] = useState<any>(null);
const [accounts, setAccounts] = useState<string[]>([]);
 
const initProvider = async () => {
  const sdk = await DappPortalSDK.init({
    clientId,
    chainId,
  });
  const provider = new Web3Provider(sdk.getWalletProvider());
  const accounts = await provider.send("kaia_requestAccounts", []);
  setProvider(provider);
  setAccounts(accounts);
};
 
const sign = async () => {
  const contract = new ethers.Contract(contractAddr, abi, provider);
  const contractCallData = await contract.increment.populateTransaction();
  const tx = {
    typeInt: TxType.FeeDelegatedSmartContractExecution, // fee delegated smart contract execution
    from: accountAddress,
    to: contractCallData.to,
    input: contractCallData.data,
    value: "0x0",
    feePayer: feePayer,
  };
  const signedTx = await provider.send("kaia_signTransaction", [tx]);
  // send the signed tx to backend
  console.log(signedTx);
};
 
useEffect(() => {
  initProvider();
}, []);
 
return (
  <div>
    <button onClick={sign}>Get user signed tx</button>
  </div>
);
}

backend - request 'sign' to feePayer server

  1. input : userSignedTx - RLP encoded transaction

  2. return : transaction receipt

  3. feePayer server URL

    const { Wallet } = require("@kaiachain/ethers-ext/v6");
    const ethers = require("ethers");

    //testnet
    const feePayerServer = "https://fee-delegation-kairos.kaia.io";
    const provider = new ethers.JsonRpcProvider("https://public-en-kairos.node.kaia.io");

    async function main() {
    /* signed tx from user on frontend side */
    const signedTxRLPEncoded = {
    raw: RLP encoded signed TX hex string
    }
    const response = await fetch(`${feePayerServer}/api/signAsFeePayer`, {
    method: "POST",
    headers: {
    "Content-Type": "application/json",
    },
    body: JSON.stringify({ userSignedTx:signedTxRLPEncoded }),
    });
    const data = await response.json();
    console.log(data);
    }

    main();
    1. https://fee-delegation.kaia.io (mainnet)
      1. Contract or sender should be registered
    2. https://fee-delegation-kairos.kaia.io (testnet)
  4. balance check

    const checkBalance = async () => {
    // It's an address of contracts or senders you registered for fee delegation
    const address = "0x63d4f17d2a8a729fd050f7679d961b1dfbb1e3af";
    const result = await fetch(`${feePayerServer}/api/balance?address=${address}`);
    const isEnough = (await result.json()).data;
    console.log(isEnough ? "enough balance" : "not enough balance");
    };