Usage

Once the SDK is installed and the AirService is successfully initialized, it can be used to authenticate users. Further, the native provider given by the service instance can be used to let users interact with the blockchain.

The AirService instance offers following:

Method
Description

init(…)

The init method should generally be called right after creating the AirService instance.

login(…)

This will login the user with their Global ID.

getUserInfo()

Retrieves general user information.

goToPartner(...)

Share the user's session from your dApp to another AIR Kit-enabled dApp.

getProvider()

Returns Eip1193Provider compatible with web3, ethers, Viem, etc. This call will also load the wallet in the background.

getAccessToken()

Returns the current access token or a new one in case of expiry.

preloadWallet()

Loads the wallet in the background. Needs the user to be logged in.

setupOrUpdateMfa()

Triggers the MFA enrollment screen where the user can set up or update the Passkey.

isSmartAccountDeployed()

Check if the AA has been deployed. During this call the wallet will be loaded if not yet happened.

deploySmartAccount()

Deploy the AA if not yet deployed. It will also automatically be deployed when minting an Air Id. During this call the wallet will be loaded if not yet happened.

logout()

Logs out the user and clears up the session

clearInit()

Clears the initialization of the AirService

on(…) / off(…)

To keep in sync with the service's state, you can subscribe to it and receive events such as initialized, logged_in, wallet_initialized*, air_id_minting_started*, air_id_minting_failed* and logged_out.

Import and Initialize

The AirService creates an iframe that loads the login flow and sets up communication streams between the iframe and the DApp's JavaScript context.

import { AirService, BUILD_ENV } from "@mocanetwork/airkit";

const service = new AirService({
  partnerId: YOUR_PARTNER_ID, // Replace with your actual Partner ID
});
await service.init({
  buildEnv: BUILD_ENV.SANDBOX,
  enableLogging: true,
});

// Without any parameters, this will trigger the default Air login dialog which provides different login methods for the user to choose from.
await embed.login();

Once the SDK is installed and AirService is successfully initialized, it can be used to authenticate users.

Login

login(options?: { authToken?: string; })
: Promise<AirLoginResult>

Without any parameters, this will trigger the default Air login dialog, which provides different login methods for the user to choose from. We recommend to always require passing in a signed JWT via the authToken parameter with at minimum your partnerId inside the payload. This would also trigger the default login but enhances security. If you're having your users already authenticated on your side, you can add the email and partnerUserId to the payload as well.

An example JWT could look like the following:

{
  "partnerId": "YOUR PARTNER ID",
  "partnerUserId": "YOUR USER ID", // optional
  "email": "YOUR USER EMAIL", // optional
  "exp": 1728973684,
  "iat": 1728970084
}

To validate the JWTs on our end, we need to know your JWKS endpoint with the following JSON:

{
  "keys": [
    {
      "kty": "EC",
      "use": "sig",
      "alg": "ES256",
      "kid": "{your_kid}",
      "crv": "P-256",
      "x": "{your_x}",
      "y": "{your_y}"
    }
  ]
}

If you don't want to provide a JWKS endpoint, you can also provide us the public key directly.

After successful login, an AirLoginResult object will be returned, which also contains a property token generated by us containing the following information:

{
  sub: string,
  abstractAccountAddress: string,
  partnerId: string,
  partnerUserId?: string,
  sourcePartnerId?: string
}

This token can be used in the future to query some of our partner endpoints.

You can validate our token by using the following JWKS endpoint: https://static.air3.com/.well-known/jwks.json

The native provider given by the embed instance can now be used to let users interact with the blockchain.

Signing Example

Using ethers


const ethProvider = new BrowserProvider(service.provider, 'any');
const signer = await ethProvider.getSigner();
const signedMessage = await signer.signMessage('Your message');

Using Web3


const web3 = new Web3(service.provider);
const signedMessage = await web3.eth.personal.sign(
    'Your message',
    eoaAccount,
    'password',
);

Sending Transaction Example

Using ethers

const transactionParams: TransactionRequest = {...};
const ethProvider = new BrowserProvider(service.provider, 'any');
const signer = await ethProvider.getSigner();
const response = signer.sendTransaction(transactionParams);

Using web3

const transactionParams: Transaction = {...};
const web3 = new Web3(service.provider);
const response = await web3.eth.sendTransaction(transactionParams);

User Session Across AIR Kit dApps

To maintain a user's logged-in state across dApps in our ecosystem, we offer a convenient way to share the user's session from your dApp to another AIR Kit-enabled dApp.

From your dApp, call goToPartner(partnerUrl: string) and pass in the target URL of the other dApp to receive an updated URL, which can be used to carry over the user. Once the user lands on the target dApp, the user session will automatically be rehydrated during SDK initialization.

Example:

const { urlWithToken } = await airService.goToPartner('https://www.partner-dapp.xyz/stake');
document.window.href = urlWithToken;

Handling MFA Requirements

In order to make use of any wallet functionality, the user needs to have set up MFA, which currently requires Passkey. After the user has set up the Passkey, any wallet action that requires signing or confirming a transaction will require users to verify their Passkey. This ensures funds are protected and only accessible by the user.

By default, the MFA enrollment screen will automatically pop up whenever the user has not set up MFA yet and a wallet action is triggered. This also includes getting the accounts and balance checks.

The MFA screen can also be programmatically triggered by calling setupOrUpdateMfa() Before doing any wallet-related actions, if more control over the time of the MFA enrollment is needed.

The example below illustrates a potential way of handling the MFA setup:

const loggedInUser = await airService.login();

// The wallet initialization can take a few seconds, so we can preload the wallet
// in the background before we need it
airService.preloadWallet();

// Some time later...
// If the user has not set up MFA yet and we want to trigger it now, we can do
if(!loggedInUser.isMFASetup) {
    await airService.setupOrUpdateMfa();
}

// At this point, we're ready to use the wallet

Interact with blockchain

To interact with the blockchain, users need to log in and mint an Air ID, which you can explore further in above section.

The provider returned from the service is a compatible Eip1193Provider and can be used with web3, ethers, Viem, etc.

To interact with blockchain data, libraries such as Ethers.js, Viem, and Web3.js can be used. Here are some small snippets for signing, querying, and mutating simple functions on the blockchain.

Sample smart contract

Consider a sample ERC20 smart contract with a minimal setup, including balanceOf, symbol, and mint functions

Make sure to replace {CONTRACT_ADDRESS} and {CHAIN_ID} with your corresponding values.

const MOCK_TOKEN_CONTRACT = {
  address: "{CONTRACT_ADDRESS}",
  abi: [
    "function balanceOf(address account) view returns (uint256)",
    "function symbol() view returns (string)",
    "function mint(address to, uint256 amount)",
  ],
  chainId: {CHAIN_ID},
};

The SDK manages two types of accounts:

  1. Smart Account (AA)

The Realm SDK’s smart contract account complies with the ERC-4337 standard, supporting gas sponsorship via paymasters and other AA-related features. User assets are securely stored within this AA.

  1. Signer Account (EOA)

The signer account is used for signing transactions and messages and controls the Smart Account (AA).

  • For users logging in with a wallet (e.g., MetaMask), this account directly controls the AA.

  • For users utilizing social login, a multi-party computation (MPC) wallet is constructed to manage the AA.

Wallet client

const airProvider = await service.getProvider();
const walletClient = createWalletClient({
  transport: custom(airProvider),
  chain: baseSepolia,
});

Sign a Message

const airProvider = await service.getProvider();
const ethProvider = new BrowserProvider(airProvider, "any");
const signer = await ethProvider.getSigner();
const signedMessage = await signer.signMessage(message);

Query the Blockchain

const airProvider = await service.getProvider();
const ethProvider = new BrowserProvider(airProvider, "any");
const signer = await ethProvider.getSigner();
const contract = new ethers.Contract(
  MOCK_TOKEN_CONTRACT.address,
  MOCK_TOKEN_CONTRACT.abi,
  signer
);

const result = await contract.balanceOf(await signer.getAddress());

Mutation (Send a Transaction)

const airProvider = await service.getProvider();
const ethProvider = new BrowserProvider(airProvider, "any");

const accounts = await ethProvider.listAccounts(); 
const signer = accounts[0]; // The first account will be the AA account address, and the second will be the EOA/MPC signer
const contractAddress = MOCK_TOKEN_CONTRACT.address;
const abi = MOCK_TOKEN_CONTRACT.abi;
const contract = new ethers.Contract(contractAddress, abi, signer);

const tx = await contract.mint(await signer.getAddress(), ethers.parseUnits(amount, 18)); // Assuming 18 decimals
await tx.wait(); // Wait for the transaction to be mined\