본문으로 건너뛰기

Gas Fee Delegation

Kaia Wave 빌더를 위한 Kaia Fee Delegation 프로그램

소개

Kaia 네트워크의 fee delegation은 다른 계정이 트랜잭션 gas fee를 대신 지불할 수 있게 해주는 기능입니다. 이를 통해 사용자는 트랜잭션의 gas fee로 자신의 $KAIA를 소비하지 않고도 트랜잭션을 수행할 수 있습니다.

신청서 작성 >

개념

Kaia fee delegation은 세 가지 주요 구성 요소로 이루어집니다:

  1. Sender: 트랜잭션을 제출하는 계정 (from)
  2. Unifi Apps: 사용자가 서명한 트랜잭션을 fee payer 서버로 전달하는 relayer
  3. Fee payer server: fee payer로서 서명하고 서명된 트랜잭션을 네트워크로 전송한 뒤 호출자에게 receipt를 반환

Kaia fee delegation의 동작 과정은 다음과 같습니다:

  1. sender가 트랜잭션을 생성합니다.
  2. sender가 트랜잭션에 fee payer의 주소를 지정합니다.
  3. sender가 트랜잭션에 서명합니다.
  4. sender가 서명된 트랜잭션을 Unifi Apps의 backend로 전송합니다.
  5. backend가 fee payer 서버에 트랜잭션 서명을 요청합니다.
  6. fee payer 서버가 fee payer로서 트랜잭션에 서명하고, 네트워크로 전송하여 트랜잭션 receipt를 받아 반환합니다.

코드 샘플

사전 준비

  1. SDK
    1. kaia-sdk 중 하나인 ethers-ext를 설치해야 합니다.
    2. ethers-ext getting-started
  2. Wallet
    1. fee-delegation은 다음에서만 지원됩니다
      1. kaia-wallet mobile/extension, Unifi-wallet liff/web
    2. Unifi Apps front-end는 wallet을 통해 사용자가 서명한 트랜잭션을 받아야 합니다

웹 애플리케이션 코드 스니펫

Frontend (React) - 사용자가 서명한 트랜잭션 받기

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: "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: accounts[0],
    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 - feePayer 서버에 'sign' 요청

  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 또는 sender가 등록되어 있어야 합니다
    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");
    };