Gas Abstraction Wallet Controller ⛽️

All cross chain gas abstraction interactions should be done with this controller. Basically if crossChain is true for Gas type for any transaction, use GaWalletController instead of WalletController.

Functions

Create an instance
const wallet = new GaWalletController({
    baseUrl: 'http://localhost:8000',
    walletType: {
        embedded: true, // for external wallet it should be false
        suppportAa: boolean,
    }, 
    environment, // ENV // default is mainnet
    sessionSignatures,
    currentAccount,
    customAuthMethod,
    accessToken,
    sentryDns,
    aa,
    selectedWallet,
    walletController, // pass walletController if wallet.init() done before (i.e. Lit handshakes) is done before in background // then no need to do gaWallet.init()
} as GaWalletArgs);

export type GaWalletArgs = TriaArgs & {
  walletController?: WalletController;
};

export type ENV = 'testnet' | 'mainnet-staging' | 'mainnet';

export type AaDetails = {
  pimlicoApiKey?: string;
  isSponsored?: boolean;
  sponsorshipPolicyId?: string;
  accountType?: AaAccountType;
  sponsorshipPolicyIds?: ChainNameToPolicyId; // {"FUSE": "sp_id_fuse", "POLYGON": "sp_id_poly"}
};

export type AaAccountType = 'Simple' | 'Kernel' | 'Safe' | 'Biconomy';
Init
// This inits the signer elements in the wallet instance
// Should be done for all write interactions
await wallet.init()
Send Tokens ⛽️
send(args: {
    payload: Send;
    chainName?: ChainName;
    gas?: Gas;
    privateKey?: string;
  }): Promise<TxnResponse>;
export interface Send {
  fromTriaName: string;
  recipientTriaName: string;
  amount: number;
  tokenAddress?: string | number | Object;
}
// Example
const chainName = "ETHEREUM";
const payload = {
  fromTriaName: "dawn@tria",
  recipientTriaName: "kate@tria";
  amount: 0.1, // ETH
  tokenAddress: null;
};
const txn = keyring.send(chainName, payload)
  • internally we fetch the privateKey from the client storage, i.e., from decrypted vault

  • A check on the FE needs to made for the input & total balance. ( Input <= Total Balance)

    • you will get totalBalance values from getAllAssets

      • which will be used to show the assets in choose asset block

  • tokenAddress -> will be whatever you receive from getAllAssets in number, string, or Object

    • number -> assetId in Polkadot -> Statemint

    • Object -> in case of sui

Approve ⛽️
approve(args: {
    payload: Approve;
    chainName?: ChainName;
    privateKey?: string;
    gas?: Gas;
  }): Promise<TxnResponse>;
export interface Approve {
  tokenAddress: string;
  amount: number;
  spender: string;
}
Send NFT ⛽️
sendNFT(args: {
    recipientTriaName: string;
    nftDetails: NFTDetails;
    chainName?: ChainName;
    privateKey?: string;
    gas?: Gas;
  }): Promise<TxnResponse>;
export interface NFTDetails {
  type: string; // ERC721 or ERC1155 - in "interface" field from getNFTs
  tokenAddress: string; // nftInfo.contract_address
  tokenId: string; // nftInfo.token_id
  amount: number; // input in case of ERC1155, 1 in case of ERC721
}
Call Contract ⛽️
callContract(args: {
    contractDetails: ContractDetails;
    chainName?: ChainName;
    privateKey?: string;
    gas?: Gas;
  }): Promise<TxnResponse>;
export interface ContractDetails {
  contractAddress: string;
  abi: Object[];
  functionName: string;
  args: [];
  value?: number; // specify native token amount to be transfered, eg. 1 (if 1 MATIC), 0 if no native token payment or erc20.
} 
Broadcast Transaction ⛽️
async broadcastTransaction({
    txnObject,
    userOperation,
    chainName,
    privateKey,
    gas,
  }: {
    txnObject?: Object;
    userOperation?: Object;
    chainName?: ChainName;
    privateKey?: string;
    gas?: Gas;
  }): Promise<TxnResponse>;
  • pass gas param for cutting the gas token on some other chain - Fee will be deducted, and then main userOp gets broadcasted.

Types

Gas
export type Gas = {
  token?: { name: GasTokenType; address?: string; amount?: number };
  crossChain?: boolean; // true if gas payment is done on chain other than source chain
  chainName?: ChainName; // chain to pay gas on
  selectedWallet?: "EOA" | "AA"; // wallet to pay free from // EOA can only be in case of native tokens // or if the user have enough native tokens on the EOA wallet to pay gas for the send txn of suppose USDC token (as gas to tria)
};

export type GasTokenType = "USDC" | "USDT" | "TST" | string;
TxnResponse
export interface TxnResponse {
  success: boolean;
  data?: {
    txnId: string | null; // might be null for AA txns
    userOpHash?: string; // only for AA wallet txns
    viewInExplorer: string | null; // might be null for AA txns
    wait: Function;
  };
  message?: string;
  error?: any;
}

How it works?

  • This will create 2 seperate transactions on 2 different chains

    • one for cutting the gas fee (useful for cross-chain mostly)

      • if gas token selected on the same chain (gas cut txn can be batched in the same userOp and broadcasted once)

    • wait for the gas fee txn success cross chain (we can skip this step too, will save us 7-8s depending on txn success time on different chains)

    • other one for the main user transaction

Last updated