This guide will walk you through creating and configuring your first Smart Account using TypeScript.

Prerequisites

  1. API Key: Get your API key
  2. Network: Choose between mainnet or devnet for testing
  3. Dependencies: Install required packages:
    npm install axios @solana/web3.js
    # or
    yarn add axios @solana/web3.js
    

Step 1: Create a Smart Account

First, let’s set up our client and create a basic 2-of-3 Smart Account:

import axios from "axios";
import { Keypair } from "@solana/web3.js";

// Initialize API client
const api = axios.create({
  baseURL: "https://developers.squads.so/api/v1",
  headers: {
    Authorization: `Bearer YOUR_API_KEY`,
    "x-squads-network": "devnet",
    "Content-Type": "application/json",
  },
});

// Generate or import your signers
const signer1 = Keypair.generate();
const signer2 = Keypair.generate();
const signer3 = Keypair.generate();

// Create a Smart Account
async function createSmartAccount() {
  const response = await api.post("/smart-accounts", {
    smart_account_signers: [
      {
        address: signer1.publicKey.toString(),
        permissions: ["CAN_INITIATE", "CAN_VOTE", "CAN_EXECUTE"],
      },
      {
        address: signer2.publicKey.toString(),
        permissions: ["CAN_VOTE"],
      },
      {
        address: signer3.publicKey.toString(),
        permissions: ["CAN_VOTE"],
      },
    ],
    threshold: 2,
  });

  return response.data;
}

Using Idempotency

To prevent duplicate accounts during retries:

async function createSmartAccountIdempotent() {
  const response = await api.post(
    "/smart-accounts",
    {
      // ... same configuration as above
    },
    {
      headers: {
        "x-idempotency-key": "unique-random-string",
      },
    }
  );

  if (response.data.status === "pending") {
    // Account creation in progress
    return;
  }

  return response.data.smart_account_address;
}

Step 2: Add Policies

Adding a Time Lock

Add a 24-hour time lock for additional security:

async function addTimeLock(smartAccountAddress: string) {
  const response = await api.patch(`/smart-accounts/${smartAccountAddress}`, {
    time_lock: 86400, // 24 hours in seconds
    transaction_signers: [
      signer1.publicKey.toString(),
      signer2.publicKey.toString(),
    ],
  });

  // Sign and submit the transaction
  const { transaction } = response.data;
  // ... sign with signer1 and signer2
}

Setting Up Admin Control

Optionally, designate an admin address for settings management:

async function setAdmin(smartAccountAddress: string, adminAddress: string) {
  const response = await api.patch(`/smart-accounts/${smartAccountAddress}`, {
    admin_address: adminAddress,
    transaction_signers: [
      signer1.publicKey.toString(),
      signer2.publicKey.toString(),
    ],
  });

  // Sign and submit the transaction
  const { transaction } = response.data;
  // ... sign with signer1 and signer2
}

Configuring Spending Limits

Set up a daily USDC spending limit to allow controlled token spending:

async function createSpendingLimit(smartAccountAddress: string) {
  const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

  const response = await api.post(
    `/smart-accounts/${smartAccountAddress}/spending-limits`,
    {
      amount: "1000000000", // 1000 USDC (6 decimals)
      token_address: USDC_MINT,
      period: "DAILY",
      spending_limit_signers: [signer1.publicKey.toString()],
      destinations: ["ALLOWED_DEST1", "ALLOWED_DEST2"],
      transaction_signers: [
        signer1.publicKey.toString(),
        signer2.publicKey.toString(),
      ],
    }
  );

  // Sign and submit the transaction
  const { transaction } = response.data;
  // ... sign with signer1 and signer2
}

Step 3: Verify Configuration

Check your Smart Account settings:

async function getSmartAccount(smartAccountAddress: string) {
  const response = await api.get(`/smart-accounts/${smartAccountAddress}`);

  // Example response data
  // {
  //   smart_account_address: string;
  //   signers: Array<{
  //     address: string;
  //     permissions: Array<"CAN_INITIATE" | "CAN_VOTE" | "CAN_EXECUTE">;
  //   }>;
  //   threshold: number;
  //   time_lock?: number;
  //   admin_address?: string;
  // }

  return response.data;
}

// Check spending limits
async function getSpendingLimits(smartAccountAddress: string) {
  const response = await api.get(
    `/smart-accounts/${smartAccountAddress}/spending-limits`
  );
  return response.data;
}

Next Steps

  1. Explore Advanced Features

  2. Security Best Practices

  3. Integration Tips

    • Use idempotency for reliability
    • Handle time lock delays
    • Monitor spending limits with GET endpoints
    • Implement proper error handling

For detailed API documentation, check out: