OmnesMSA API Docs
Getting started

Quick Start Guide

Create your first Account Abstraction wallet in 5 minutes with MSA API.

This guide will walk you through creating your first Account Abstraction wallet using the MSA API. You'll learn the essential workflow and see practical examples in multiple programming languages.

Prerequisites

Before starting, ensure you have:

  1. API Key: Your MSA API key (obtain from Contact Us)
  2. Signing Credentials: One of the following:
    • Private Key (for testing): Your Ethereum private key
    • Fireblocks HSM: Client ID and Version ID
    • Fireblocks MPC: Client ID and Asset ID
    • Google Cloud KMS: GCP credentials and key information
  3. Network Access: RPC endpoint for your target blockchain
  4. API Base URL: https://api.msa.omnes.tech

Step 0: Get Your API Key

If you don't have an API key yet:

  1. Schedule a meeting with our team, or
  2. Send us an email to request access

Once you receive your API key, store it securely:

# .env file
API_KEY=your-api-key-here
PRIVATE_KEY=0x1234... # For testing only
RPC_URL=https://rpc-amoy.polygon.technology/

Step 1: Initialize the SDK

First, set up your environment and initialize the SDK with your API key and signer.

import { SmartWallet, PKSigner } from '@omnes/smartwallet-ts-sdk';

// Load environment variables
const apiKey = process.env.API_KEY!;
const rpcURL = process.env.RPC_URL!;
const privateKey = process.env.PRIVATE_KEY!; // For testing only

// Create a signer
const signer = await PKSigner.create(privateKey as `0x${string}`);

// Initialize SmartWallet with API key
const smartWallet = await SmartWallet.create(
  signer.signMessage,           // Message sign method
  signer.signMessage,           // UserOp hash sign method
  signer.getEVMAddress(),       // Signer address
  rpcURL,                       // RPC endpoint
  apiKey,                       // Your API key (required!)
  null,                         // Contracts (null = fetch from API)
  false                         // Use remote bundler
);

console.log('SmartWallet initialized successfully!');

Using API HTTP (fetch)

// Using API HTTP (fetch) for operations not covered by SmartWallet SDK
const response = await fetch('https://api.msa.omnes.tech/create', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.API_KEY! // API key for authentication
  },
  body: JSON.stringify({
    accounts: [{
      walletCustody: 1, // ECDSA_VALIDATOR
      salt: 'user@example.com'
    }],
    settings: {
      rpc: 'https://rpc-amoy.polygon.technology/',
      factory: '0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4',
      validator: '0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a',
      entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789',
      beaconAdminAddress: '0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618',
      signer: {
        clientId: process.env.FIREBLOCKS_CLIENT_ID!,
        versionId: process.env.FIREBLOCKS_VERSION_ID!
      }
    }
  })
});

const result = await response.json();
# Set your API key as an environment variable
export API_KEY="your-api-key-here"

# Test API connection
curl -X GET "https://api.msa.omnes.tech/getbundleraddress" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json"

Step 2: Predict Wallet Address

Predict the wallet address before deploying. This is useful for funding the wallet before creation.

import { SmartWallet, PKSigner, AccountOperations } from '@omnes/smartwallet-ts-sdk';

// Initialize (as shown in Step 1)
const signer = await PKSigner.create(privateKey as `0x${string}`);
const smartWallet = await SmartWallet.create(
  signer.signMessage,
  signer.signMessage,
  signer.getEVMAddress(),
  rpcURL,
  apiKey,
  null,
  false
);

// Predict wallet address
const accountOperations: AccountOperations[] = [{
  account: {
    walletCustody: 1, // ECDSA_VALIDATOR
    salt: "user@example.com",
    publicKeys: [] // Empty for ECDSA
  },
  operations: [], // No operations needed for prediction
  settings: {}
}];

// Get predicted address
const predictedAddress = smartWallet.predictWalletAddress("user@example.com");
console.log('Predicted wallet address:', predictedAddress);
curl -X POST "https://api.msa.omnes.tech/predict" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accounts": [{
      "walletCustody": 1,
      "salt": "user@example.com"
    }],
    "settings": {
      "rpc": "https://rpc-amoy.polygon.technology/",
      "factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
      "validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
      "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
      "beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618"
    }
  }'

Expected Response:

{
  "predictions": [{
    "wallet": "0x28097eF2268B553783D9c32A33ECb1bB78B209F3",
    "salt": "user@example.com",
    "walletCustody": 1
  }]
}

Expected Response:

{
  "predictions": [{
    "wallet": "0x28097eF2268B553783D9c32A33ECb1bB78B209F3",
    "salt": "user@example.com",
    "walletCustody": 1
  }]
}

Step 3: Fund the Wallet (Optional)

For wallet creation to succeed, the predicted address needs sufficient native tokens to pay for gas. You can:

  1. Send tokens to the predicted address from another wallet
  2. Use a paymaster to sponsor the transaction
  3. Fund via faucet (testnet only)
# Example: Send 0.1 MATIC to the predicted address
# (Replace with actual wallet address from Step 1)
cast send 0x28097eF2268B553783D9c32A33ECb1bB78B209F3 \
  --value 0.1ether \
  --rpc-url https://rpc-amoy.polygon.technology/

Step 4: Create the Wallet

Deploy the wallet. This requires signing credentials (private key for testing, or HSM/MPC for production).

import { SmartWallet, PKSigner, AccountOperations, Operation } from '@omnes/smartwallet-ts-sdk';

// Initialize SmartWallet (from Step 1)
const signer = await PKSigner.create(privateKey as `0x${string}`);
const smartWallet = await SmartWallet.create(
  signer.signMessage,
  signer.signMessage,
  signer.getEVMAddress(),
  rpcURL,
  apiKey,
  null,
  false // Use remote bundler (requires API key)
);

// Create wallet operation
const accountOperations: AccountOperations[] = [{
  account: {
    walletCustody: 1, // ECDSA_VALIDATOR
    salt: "user@example.com",
    publicKeys: []
  },
  operations: [], // Empty operations array = just create wallet
  settings: {}
}];

// Create wallet using remote bundler
const result = await smartWallet.buildAndRequestSendUserOperations(
  accountOperations,
  [], // useABI
  []  // additional signers
);

console.log('Wallet created!');
console.log('Transaction hash:', result.txHash);
console.log('Status:', result.status === 1 ? 'Success' : 'Failed');
curl -X POST "https://api.msa.omnes.tech/create" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accounts": [{
      "walletCustody": 1,
      "salt": "user@example.com"
    }],
    "settings": {
      "rpc": "https://rpc-amoy.polygon.technology/",
      "factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
      "validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
      "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
      "beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618",
      "beaconAdminCreationCode": "0x60a060405260405161059d...",
      "signer": {
        "clientId": "your-fireblocks-client-id",
        "versionId": "1"
      }
    }
  }'

Note: For REST API, you can also use private key signing by providing the private key in the signer configuration, but this is not recommended for production.

Expected Response:

{
  "status": 1,
  "txHash": "0x066a0269a55aa42498da9993f01b9bfc82517330669c240807ed1b94b2acd938",
  "gasUsed": 549731,
  "effectiveGasPrice": "1136849215",
  "returnData": [{
    "0": {
      "salt": "user@example.com",
      "wallet": "0x28097eF2268B553783D9c32A33ECb1bB78B209F3"
    }
  }]
}

Step 5: Verify Wallet Creation

Check if the wallet was successfully created:

import { SmartWallet, PKSigner } from '@omnes/smartwallet-ts-sdk';

// Initialize SmartWallet (from Step 1)
const signer = await PKSigner.create(privateKey as `0x${string}`);
const smartWallet = await SmartWallet.create(
  signer.signMessage,
  signer.signMessage,
  signer.getEVMAddress(),
  rpcURL,
  apiKey,
  null,
  false
);

// Verify wallet exists
const accounts = await smartWallet.checkAccounts(
  ["user@example.com"], // Salts
  []                    // Wallet addresses (empty for salt-based check)
);

const account = accounts[0];
if (account?.exists) {
  console.log('โœ… Wallet exists!');
  console.log('Wallet address:', account.wallet);
} else {
  console.log('โŒ Wallet does not exist yet');
}
curl -X POST "https://api.msa.omnes.tech/check" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accounts": [{
      "walletCustody": 1,
      "salt": "user@example.com"
    }],
    "settings": {
      "rpc": "https://rpc-amoy.polygon.technology/",
      "factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
      "validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
      "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
      "beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618"
    }
  }'

Expected Response:

{
  "results": [{
    "exists": true,
    "wallet": "0x28097eF2268B553783D9c32A33ECb1bB78B209F3",
    "salt": "user@example.com",
    "walletCustody": 1
  }]
}

Step 6: Execute Your First Transaction

Execute a simple transaction from the wallet. We'll approve an ERC-20 token:

import { SmartWallet, PKSigner, AccountOperations, Operation } from '@omnes/smartwallet-ts-sdk';

// Initialize SmartWallet (from Step 1)
const signer = await PKSigner.create(privateKey as `0x${string}`);
const smartWallet = await SmartWallet.create(
  signer.signMessage,
  signer.signMessage,
  signer.getEVMAddress(),
  rpcURL,
  apiKey,
  null,
  false
);

// Define the operation
const operation: Operation = {
  to: "0x097d4Aed5924e2172451973153Fc0e03407eD1F9", // Token contract address
  value: BigInt(0), // No ETH sent
  funcSignature: "approve(address,uint256)",
  params: [
    "0xA65aae78EdEF916d4102BA7b5672068C0D35fbff", // Spender address
    BigInt("1000000000000000000") // Amount (1 token, 18 decimals)
  ]
};

// Create account operations
const accountOperations: AccountOperations[] = [{
  account: {
    walletCustody: 1,
    salt: "user@example.com",
    publicKeys: []
  },
  operations: [operation],
  settings: {}
}];

// Execute transaction
const result = await smartWallet.buildAndRequestSendUserOperations(
  accountOperations,
  [], // useABI
  []  // additional signers
);

console.log('Transaction executed!');
console.log('Transaction hash:', result.txHash);
console.log('Status:', result.status === 1 ? 'Success' : 'Failed');
curl -X POST "https://api.msa.omnes.tech/execute" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [{
      "walletCustody": 1,
      "salt": "user@example.com",
      "to": "0x097d4Aed5924e2172451973153Fc0e03407eD1F9",
      "funcSignature": "approve(address,uint256)",
      "funcParams": [
        "0xA65aae78EdEF916d4102BA7b5672068C0D35fbff",
        "1000000000000000000"
      ]
    }],
    "settings": {
      "rpc": "https://rpc-amoy.polygon.technology/",
      "factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
      "validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
      "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
      "beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618",
      "signer": {
        "clientId": "your-fireblocks-client-id",
        "versionId": "1"
      }
    }
  }'

Complete Workflow Example

Here's a complete end-to-end example using the SmartWallet SDK:

import { SmartWallet, PKSigner, AccountOperations, Operation } from '@omnes/smartwallet-ts-sdk';
import dotenv from 'dotenv';

dotenv.config();

async function completeWalletWorkflow() {
  // Load configuration
  const apiKey = process.env.API_KEY!;
  const rpcURL = process.env.RPC_URL!;
  const privateKey = process.env.PRIVATE_KEY!;
  const userSalt = `user-${Date.now()}@example.com`;

  try {
    // Step 1: Initialize SmartWallet
    console.log('๐Ÿ”ง Initializing SmartWallet...');
    const signer = await PKSigner.create(privateKey as `0x${string}`);
    const smartWallet = await SmartWallet.create(
      signer.signMessage,
      signer.signMessage,
      signer.getEVMAddress(),
      rpcURL,
      apiKey,
      null, // Contracts will be fetched from API using API key
      false // Use remote bundler
    );
    console.log('โœ… SmartWallet initialized');

    // Step 2: Predict wallet address
    console.log('๐Ÿ”ฎ Predicting wallet address...');
    const predictedAddress = smartWallet.predictWalletAddress(userSalt);
    console.log(`โœ… Predicted address: ${predictedAddress}`);

    // Step 3: Check if wallet exists
    console.log('๐Ÿ” Checking wallet existence...');
    const accountOperations: AccountOperations[] = [{
      account: {
        walletCustody: 1,
        salt: userSalt,
        publicKeys: []
      },
      operations: [],
      settings: {}
    }];
    
    // Check wallet existence using checkAccounts
    const accounts = await smartWallet.checkAccounts([userSalt], []);
    const walletExists = accounts[0]?.exists || false;
    
    if (walletExists) {
      console.log('โ„น๏ธ Wallet already exists');
    } else {
      console.log('โ„น๏ธ Wallet does not exist, will create');
    }

    // Step 4: Create wallet (if needed)
    if (!walletExists) {
      console.log('๐Ÿ—๏ธ Creating wallet...');
      const createResult = await smartWallet.buildAndRequestSendUserOperations(
        accountOperations,
        [],
        []
      );
      console.log(`โœ… Wallet created! Tx: ${createResult.txHash}`);
      // Wait for confirmation
      await new Promise(resolve => setTimeout(resolve, 5000));
    }

    // Step 5: Execute a transaction
    console.log('โšก Executing transaction...');
    const operation: Operation = {
      to: "0x097d4Aed5924e2172451973153Fc0e03407eD1F9", // Token address
      value: BigInt(0),
      funcSignature: "approve(address,uint256)",
      params: [
        "0xA65aae78EdEF916d4102BA7b5672068C0D35fbff", // Spender
        BigInt("1000000000000000000") // Amount
      ]
    };

    const executeOperations: AccountOperations[] = [{
      account,
      operations: [operation],
      settings: {}
    }];

    const executeResult = await smartWallet.buildAndRequestSendUserOperations(
      executeOperations,
      [],
      []
    );
    console.log(`โœ… Transaction executed! Tx: ${executeResult.txHash}`);

    return {
      walletAddress: predictedAddress,
      txHash: executeResult.txHash
    };

  } catch (error) {
    console.error('โŒ Error:', error);
    throw error;
  }
}

// Run the workflow
completeWalletWorkflow()
  .then(result => {
    console.log('๐ŸŽ‰ Workflow completed successfully!');
    console.log('Result:', result);
  })
  .catch(error => {
    console.error('๐Ÿ’ฅ Workflow failed:', error);
    process.exit(1);
  });

Environment Variables (.env):

API_KEY=your-api-key-here
PRIVATE_KEY=0x1234...
RPC_URL=https://rpc-amoy.polygon.technology/

Common Issues & Solutions

1. Insufficient Gas

Error: Transaction fails with "insufficient funds"

Solution: Ensure the predicted wallet address has enough native tokens:

// Check balance before creating
const balance = await provider.getBalance(walletAddress);
console.log('Wallet balance:', ethers.utils.formatEther(balance));

2. Invalid API Key

Error: "Invalid API key" or "Unauthorized"

Solution:

  • Verify your API key is correct: echo $API_KEY
  • Ensure the API key is included in the X-API-Key header for REST API requests
  • Verify your API key is passed to SmartWallet.create() when using the SDK
  • Request a new API key if needed: Contact Us

3. Invalid Client ID or Signing Credentials

Error: "Invalid client ID" or authentication failure

Solution: Verify your Fireblocks credentials:

# Check environment variables
echo $FIREBLOCKS_CLIENT_ID
echo $FIREBLOCKS_VERSION_ID

4. Network Connection Issues

Error: "Network connection failed"

Solution: Verify RPC endpoint and network status:

# Test RPC endpoint
curl -X POST https://rpc-amoy.polygon.technology/ \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

Next Steps

Now that you've created your first wallet, explore more advanced features:

  1. Wallet Management - Learn about different custody types
  2. Transaction Execution - Explore batch operations and gas optimization
  3. SDK Integration - Build production applications
  4. API Reference - Try all endpoints interactively

๐ŸŽฏ Congratulations! You've successfully created and used your first Account Abstraction wallet. The wallet address is deterministic based on your salt, so you can always recreate the same address.