Skip to main content

Wallet Provider

1. Getting Started​

Latest Version​

How to get SDK Access(clientId & clientSecret)​

To integrate Unifi Apps SDK, you need to receive a clientId and clientSecret from the Unifi team.

Steps:

  1. Submit Unifi Apps Application
  2. Please review and submit the Unifi Apps SDK Terms & Conditions as instructed.
  3. Receive your clientId and clientSecret via the submitted email.
warning

Never expose clientSecret publicly.
If it has been compromised, request regeneration via Tech Support.

Project Setup & Domain Registration​

  • Your clientId becomes active only when a domain is registered.
    • For testing purposes, you may use http://localhost:3000.
    • For external test domains, please request whitelisting via Tech Support or email.
  • Payments via paymentProvider require a valid clientSecret.

Install SDK​

Install the SDK via npm, yarn, or pnpm

npm install @linenext/dapp-portal-sdk
# or
yarn add @linenext/dapp-portal-sdk
# or
pnpm add @linenext/dapp-portal-sdk

2. SDK Initialization​

Initialize the SDK​

You must initialize the SDK each time the Unifi Apps is loaded.

import DappPortalSDK from '@linenext/dapp-portal-sdk'
 
const sdk = await DappPortalSDK.init({
  clientId: '<CLIENT_ID>',
  chainId: '1001', // or '8217' for mainnet
});

Parameters

NameTypeDescription
clientId*required
stringthe clientId provided when applying for the SDK
chainId

stringThe default value is 1001(testnet). To use the mainnet after development, set the value to 8217(mainnet).

Response

Returns a DappPortalSDK object through which the following methods can be called.

warning
LINE MINI App and LINE Login LIFF version note
  • Call liff.init() before calling DappPortalSDK.init().
  • Do not trigger wallet connection(connectWallet) on LINE MINI App or LINE Login LIFF entry. Only connect when needed(e.g., item purchase, on-chain rewards).
  • This ensures accurate tracking of active users and attribution via LINE.
tip
Best Practice
  • Initialize the SDK only once and manage the DappPortalSDK instance as a singleton.
  • Avoid calling DappPortalSDK.init() multiple times—it may cause unexpected behavior or malfunctions.
We do not enforce singleton usage by default to allow multi-configuration setups(e.g., using both testnet and mainnet in a single app). In such cases, manage one singleton instance per configuration(e.g., one for testnet, one for mainnet).

The WalletProvider follows the EIP-1193 standard and supports the EventEmitter interface defined in it.

sdk.getWalletProvider()​

Initializes the walletProvider, allowing developers to use various wallet features.

const walletProvider = sdk.getWalletProvider();

Parameters

  • N/A

Responses

WalletProvider

walletProvider.getWalletType()​

Returns the type of the currently connected wallet.

const walletType = walletProvider.getWalletType();

Parameters

  • N/A

Responses

enum WalletType {
Web = "Web",
Liff = "Liff",
Extension = "Extension",
Mobile = "Mobile",
OKX = "OKX",
BITGET = "BITGET"
}

walletProvider.request()​

This function provides JSON-RPC API format on request. You can send request to retrieve the health status of the chain and sign transaction with wallet. If you send it before wallet connection, user will see a screen to select wallet type to connect.

You can find the available Kaia-related methods, their parameters, and corresponding responses in the table below. RPC methods that are not included in the table will be requested directly to the chain node and please refer to Kaia docs' RPC API Reference.

const getAccount = async() => {
   const accounts = await walletProvider.request({ method: 'kaia_accounts' }) as string[]; 
   return accounts[0]; 
} 
 
const requestAccount = async () => {
   const addresses = await walletProvider.request({ method: 'kaia_requestAccounts' }) as string[];
   return addresses[0];
}
 
const connectAndSign = async (msg:string) => {
   const [account, signature] = await walletProvider.request({ method: 'kaia_connectAndSign', params: [msg]}) as string[];
   return [account, signature];
}
 
const getBalance = async(params: [account:string,blockNumberOrHash:'latest' | 'earliest'])=>{
   return await walletProvider.request({ method: 'kaia_getBalance', params: params });
}
 
const transaction = {
  from: '0xYourWalletAddress', //The currently connected wallet account can be retrieved using the kaia_accounts method.
  to: '0xRecipientAddress', //Please replace it with a valid wallet address.
  value: '0x10',
  gas: '0x5208', //general gas usage for Kaia transaction
};
 
const sendTransaction = async(transaction) => {
    const transactionHash = await walletProvider.request({ method: 'kaia_sendTransaction', params: [transaction]});
    return transactionHash;
};

Parameters

  • RequestArguments *required · object
    • method *required · string
    • params unknown[]

Responses

Promise<unknown>
methodparamsResponses
kaia_accounts

Returns the list of addresses currently connected to the wallet. If no wallet is connected, an empty array is returned.
null
['Account1']
kaia_requestAccounts

Initiates wallet connection. During the process, a window is displayed for the user to select a wallet provider. Returns a list of addresses associated with the selected wallet.
null
['Account1']
personal_sign (EIP-191)

Initiate sign procedure. We recommend to use personal_sign to get compatibility with various wallets including OKX Wallet.
[message: string, account: string]
"0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b"
signature
kaia_connectAndSign (EIP-191)recommended

Initiates wallet connection and signing. Prompts the user to select a wallet provider, then signs the provided message. Returns [account, signature] as an array

[message: string]
["account","0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b"]
account and signature as Array
kaia_getBalance

Returns the KAIA balance.
[account: string, blockNumberOrHash: string]

blockNumberOrHash can be set as latest or earliest
  • latest: the most recent block
  • earliest: the genesis block (block 0)
"0x00000000000000000"
the balance value in kei, the smallest unit of the Kaia blockchain.
1 KAIA = 10^18 kei
kaia_sendTransaction

Constructs a transaction with given parameters
[{
  from: string,
  to: string,
  value: string,
  gas: string
 }]

from field should be the account that obtained from 'kaia_accounts','kaia_requestAccounts' or 'kaia_connectAndSign'
"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d059210"
transactionHash
tip

Smart contract-based transfers of USDT/JPYC (e.g. Swap)
When you transfer USDT or JPYC via a smart contract call (Swap, etc.), include depositTokenAddress and depositAmount in the kaia_sendTransaction params so the transfer also draws from the balance deposited in Unifi. This is only required when getWalletType() returns Web or Liff — for OKX, BITGET, Extension, or Mobile, use the params as-is without these two fields.

const params = {
  typeInt: 48,
  from: 'walletAddress',
  to: 'contractAddress',
  value: '0x0', // Kaia amount
  input: '0xabcd...', // contract call data
  depositTokenAddress: '0xd077a400968890eacc75cdc901f0356c943e4fdb', // USDT contract address (JPYC: 0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29)
  depositAmount: '1000000', // amount to transfer, in the token's decimals (USDT: 10^6, JPYC: 10^18)
  gas: '0x30D40', // ~200,000 - gas estimation can fail with 'execution revert' since USDT/JPYC in Unifi Wallet is fully deposited into the interest vault
};
await walletProvider.request({ method: 'kaia_sendTransaction', params: [params] });

Error

{code: -32001, message: 'User canceled'}
CodeDescription
-32001
{
  "code": -32001,
  "message": "User canceled" 
}

//When the user dismissed the wallet connection popup.
{code: -32001, message: 'User closed popup', data: null}

//When the user clicks the dismiss button on the signature popup
{
  "code": -32001,
  "message": "User denied message signature"
}

//When the user clicks the dismiss button on the transaction popup
{
  "code": -32001,
  "message": "User denied transaction send."
}
-32004Invalid from address (Please retry methods after executing walletProvider.disconnectWallet())
-32005User logged out due to incorrect password input (Please retry methods after executing walletProvider.disconnectWallet())
-32006Wallet is not connected yet (If an error occurs while the wallet is connected, Please retry methods after executing walletProvider.disconnectWallet(). If an error occurs while the wallet is not connected, please connect wallet first)

walletProvider.disconnectWallet()​

Disconnects the wallet. When this function is called, a confirmation window will appear to confirm the disconnection.

 const disconnectWallet = async ()=>{
    await walletProvider.disconnectWallet();
    window.location.reload();
}

Parameters

  • N/A

Responses

  • N/A

walletProvider.getErc20TokenBalanceWithDepositedBalance()​

warning

Why use this instead of getErc20TokenBalance()?
Unifi automatically deposits USDT and JPYC held in the Unifi Wallet into an internal pool. Because of this, getErc20TokenBalance() does not include the deposited amount for these tokens—for a user connected via Unifi Wallet, it can return a balance of 0 even when the user actually holds funds, which will incorrectly fail your app's balance check and block payment.

If your dapp checks USDT or JPYC balance before a transaction, use getErc20TokenBalanceWithDepositedBalance() instead. This is safe to call unconditionally—for wallets other than Unifi Wallet (which have no deposit pool), it simply returns the on-chain balance with a deposited amount of 0.

This method returns the total amount, which is the sum of the on-chain balance and the balance deposited in Unifi, for supported tokens (USDT, JPYC).

const getErc20TokenBalanceWithDepositedBalance = async(contractAddress:string,account:string)=> {
    return await walletProvider.getErc20TokenBalanceWithDepositedBalance(contractAddress,account);
}
 
const USDTContractAddress = '0xd077a400968890eacc75cdc901f0356c943e4fdb';
const account = 'my_account_address';
getErc20TokenBalanceWithDepositedBalance(USDTContractAddress, account).then(balance => {
    const formattedUSDTBalance = Number(microUSDTHexToUSDTDecimal(balance as string)).toFixed(2);
    //microUSDTHexToUSDTDecimal is format function to transform hexadecimal string to decimal string
    //https://github.com/techreadiness/unifi-apps-starter/blob/main/src/utils/format.ts
    console.log(formattedUSDTBalance);
    //0.00
})
TokenContract Address (Kaia)
USDT0xd077a400968890eacc75cdc901f0356c943e4fdb
JPYC0xE7C3D8C9a439feDe00D2600032D5dB0Be71C3c29

Parameters

  • contractAddress *required · string
  • account *required · string

Responses

64-byte hexadecimal string. The returned value includes the token’s decimal scaling according to its decimals specification.

For example, USDT uses a decimal scale of 10⁶, while JPYC uses a decimal scale of 10¹⁸.

string

walletProvider.getErc20TokenBalance()​

It returns the on-chain balance of an ERC20-based token.

const getErc20TokenBalance = async(contractAddress:string,account:string)=> {
    return await walletProvider.getErc20TokenBalance(contractAddress,account);
}
 
const USDTContractAddress = '0xd077a400968890eacc75cdc901f0356c943e4fdb';
const account = 'my_account_address';
getErc20TokenBalance(USDTContractAddress, account).then(balance => {
    const formattedUSDTBalance = Number(microUSDTHexToUSDTDecimal(balance as string)).toFixed(2);
    //microUSDTHexToUSDTDecimal is format function to transform hexadecimal string to decimal string
    //https://github.com/techreadiness/unifi-apps-starter/blob/main/src/utils/format.ts
    console.log(formattedUSDTBalance);
    //0.00
})

Parameters

  • contractAddress *required · string
  • account *required · string

Responses

64-byte hexadecimal string. The returned value includes the token’s decimal scaling according to its decimals specification.

For example, USDT uses a decimal scale of 10⁶, while JPYC uses a decimal scale of 10¹⁸.

string

Compatible Libraries​