swig-smart-wallet

Create and manage Solana smart wallets using the Swig TypeScript SDK. This skill enables AI agents to generate Swig wallets, manage authorities (add/remove/update with granular permissions), execute transactions through the wallet, and handle gas sponsorship via the Swig Paymaster API, a custom gas server, or self-funded SOL. Works with both @swig-wallet/classic (web3.js 1.x) and @swig-wallet/kit (@solana/kit 2.x).

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "swig-smart-wallet" with this command: npx skills add anagrambuild/swig-ts/anagrambuild-swig-ts-swig-smart-wallet

Swig Smart Wallet Skill

You are an AI agent that can create and manage Solana smart wallets using the Swig protocol. Swig wallets are on-chain programmable wallets with granular authority and permission management. You write TypeScript scripts that use the Swig SDK to perform wallet operations.

Prerequisites

Before doing anything, you MUST gather the following from the user:

1. Solana RPC Endpoint

Ask the user: "What Solana RPC endpoint should I use for transactions?"

Acceptable answers:

  • A specific URL (e.g. https://api.mainnet-beta.solana.com, https://api.devnet.solana.com, or a custom RPC like Helius, Triton, etc.)
  • "devnet" — use https://api.devnet.solana.com
  • "mainnet" — use https://api.mainnet-beta.solana.com
  • "localnet" or "localhost" — use http://localhost:8899

If the user does not know, suggest they use devnet for testing: https://api.devnet.solana.com

Store the RPC URL in an environment variable SOLANA_RPC_URL or in a .env file.

2. Gas / Fee Sponsorship

Ask the user: "How would you like transaction fees to be handled?"

Present these three options:

Option A — Swig Paymaster (recommended for production) The Swig Paymaster API covers transaction fees. Ask the user to provide:

  • Their API Key from dashboard.onswig.com
  • Their Paymaster Public Key from dashboard.onswig.com
  • The network they want to use: mainnet or devnet

Store these as environment variables:

SWIG_PAYMASTER_API_KEY=<their-api-key>
SWIG_PAYMASTER_PUBKEY=<their-paymaster-pubkey>
SWIG_PAYMASTER_NETWORK=devnet

Option B — Custom Gas Sponsorship Server The user runs their own server that signs/sponsors transactions. Ask for:

  • The API URL of their gas sponsorship server

Store as:

GAS_SPONSOR_URL=<their-server-url>

Option C — Self-funded (agent pays its own fees) The agent generates its own Solana keypair and pays fees from its own balance. The user must send a small amount of SOL (0.01-0.1 SOL) to the agent's address.

When using this option:

  1. Generate a new Ed25519 keypair for the agent
  2. Save the keypair securely to a file (e.g. agent-keypair.json)
  3. Display the public key to the user
  4. Ask: "Please send a small amount of SOL (at least 0.01 SOL) to <agent-public-key> and let me know when done."
  5. Verify the balance before proceeding

SDK Choice

The Swig SDK comes in two flavors. Choose based on the project:

PackageSolana SDKWhen to Use
@swig-wallet/classic@solana/web3.js v1.xExisting projects using web3.js v1, broader ecosystem compatibility
@swig-wallet/kit@solana/kit v2.xNew projects, modern Solana development

If the user has no preference, default to @swig-wallet/classic for broader compatibility.

Installation

# For classic (web3.js 1.x)
npm install @swig-wallet/classic @solana/web3.js

# For kit (@solana/kit 2.x)
npm install @swig-wallet/kit @solana/kit

# For paymaster support (add one based on SDK choice)
npm install @swig-wallet/paymaster-classic
# or
npm install @swig-wallet/paymaster-kit

Core Operations

1. Create a Swig Wallet

A Swig wallet is created on-chain with:

  • A random 32-byte ID (used to derive the PDA address)
  • A root authority (the initial owner, typically an Ed25519 public key)
  • Root actions/permissions (typically Actions.set().all().get() for full control)

Classic Example

import {
  Connection,
  Keypair,
  Transaction,
  sendAndConfirmTransaction,
} from '@solana/web3.js';
import {
  Actions,
  createEd25519AuthorityInfo,
  fetchSwig,
  findSwigPda,
  getCreateSwigInstruction,
  getSwigWalletAddress,
} from '@swig-wallet/classic';

const connection = new Connection(process.env.SOLANA_RPC_URL!, 'confirmed');
const payer = Keypair.fromSecretKey(/* loaded from file or env */);

// 1. Generate random 32-byte Swig ID
const id = new Uint8Array(32);
crypto.getRandomValues(id);

// 2. Derive the Swig account PDA
const swigAccountAddress = findSwigPda(id);

// 3. Create root authority info from the payer's pubkey
const rootAuthorityInfo = createEd25519AuthorityInfo(payer.publicKey);

// 4. Set root permissions (full control)
const rootActions = Actions.set().all().get();

// 5. Build the create instruction
const createSwigIx = await getCreateSwigInstruction({
  payer: payer.publicKey,
  id,
  actions: rootActions,
  authorityInfo: rootAuthorityInfo,
});

// 6. Send transaction
const tx = new Transaction().add(createSwigIx);
const signature = await sendAndConfirmTransaction(connection, tx, [payer]);

// 7. Fetch and verify
const swig = await fetchSwig(connection, swigAccountAddress);
const walletAddress = await getSwigWalletAddress(swig);

console.log('Swig account:', swigAccountAddress.toBase58());
console.log('Swig wallet address:', walletAddress.toBase58());

Kit Example

import {
  createSolanaRpc,
  createSolanaRpcSubscriptions,
  generateKeyPairSigner,
  sendAndConfirmTransactionFactory,
  signTransaction,
  pipe,
  createTransactionMessage,
  setTransactionMessageFeePayer,
  setTransactionMessageLifetimeUsingBlockhash,
  appendTransactionMessageInstructions,
  compileTransaction,
  getSignatureFromTransaction,
} from '@solana/kit';
import {
  Actions,
  createEd25519AuthorityInfo,
  fetchSwig,
  findSwigPda,
  getCreateSwigInstruction,
  getSwigWalletAddress,
} from '@swig-wallet/kit';

const rpc = createSolanaRpc(process.env.SOLANA_RPC_URL!);
const rpcSubscriptions = createSolanaRpcSubscriptions(
  process.env.SOLANA_RPC_URL!.replace('https', 'wss'),
);
const payer = await generateKeyPairSigner();

const id = new Uint8Array(32);
crypto.getRandomValues(id);
const swigAccountAddress = await findSwigPda(id);

const rootAuthorityInfo = createEd25519AuthorityInfo(payer.address);
const rootActions = Actions.set().all().get();

const createSwigIx = await getCreateSwigInstruction({
  payer: payer.address,
  id,
  actions: rootActions,
  authorityInfo: rootAuthorityInfo,
});

const { value: blockhash } = await rpc.getLatestBlockhash().send();
const txMessage = pipe(
  createTransactionMessage({ version: 0 }),
  (m) => setTransactionMessageFeePayer(payer.address, m),
  (m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
  (m) => appendTransactionMessageInstructions([createSwigIx], m),
);
const compiledTx = compileTransaction(txMessage);
const signedTx = await signTransaction([payer.keyPair], compiledTx);

await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTx, {
  commitment: 'confirmed',
});

const swig = await fetchSwig(rpc, swigAccountAddress);
const walletAddress = await getSwigWalletAddress(swig);

2. Add an Authority

Authorities are additional keys that can interact with the Swig wallet, each with specific permissions.

import {
  fetchSwig,
  getAddAuthorityInstructions,
  createEd25519AuthorityInfo,
  Actions,
} from '@swig-wallet/classic';

const swig = await fetchSwig(connection, swigAccountAddress);
const rootRole = swig.findRolesByEd25519SignerPk(rootKeypair.publicKey)[0];

// Create a new authority with specific permissions
const newAuthorityInfo = createEd25519AuthorityInfo(newKeypair.publicKey);

// Example permissions: 0.5 SOL spend limit
const actions = Actions.set()
  .solLimit({ amount: 500_000_000n }) // 0.5 SOL in lamports
  .get();

const ixs = await getAddAuthorityInstructions(
  swig,
  rootRole.id,
  newAuthorityInfo,
  actions,
);

const tx = new Transaction().add(...ixs);
await sendAndConfirmTransaction(connection, tx, [rootKeypair]);

3. Remove an Authority

import {
  getRemoveAuthorityInstructions,
  fetchSwig,
} from '@swig-wallet/classic';

const swig = await fetchSwig(connection, swigAccountAddress);
const rootRole = swig.findRolesByEd25519SignerPk(rootKeypair.publicKey)[0];

// Find the role ID of the authority to remove
const roleToRemove = swig.findRolesByEd25519SignerPk(targetPubkey)[0];

const ixs = await getRemoveAuthorityInstructions(
  swig,
  rootRole.id,
  roleToRemove.id,
);

const tx = new Transaction().add(...ixs);
await sendAndConfirmTransaction(connection, tx, [rootKeypair]);

4. Update Authority Permissions

import {
  getUpdateAuthorityInstructions,
  updateAuthorityReplaceAllActions,
  updateAuthorityAddActions,
  updateAuthorityRemoveByType,
  Actions,
  Permission,
  fetchSwig,
} from '@swig-wallet/classic';

const swig = await fetchSwig(connection, swigAccountAddress);
const rootRole = swig.findRolesByEd25519SignerPk(rootKeypair.publicKey)[0];
const roleToUpdate = swig.findRolesByEd25519SignerPk(targetPubkey)[0];

// Option 1: Replace all actions
const updateInfo = updateAuthorityReplaceAllActions(
  Actions.set().solLimit({ amount: 1_000_000_000n }).programAll().get(),
);

// Option 2: Add new actions
// const updateInfo = updateAuthorityAddActions(
//   Actions.set().tokenLimit({ mint: tokenMintPubkey, amount: 1_000_000n }).get()
// );

// Option 3: Remove actions by type
// const updateInfo = updateAuthorityRemoveByType([Permission.SolLimit]);

const ixs = await getUpdateAuthorityInstructions(
  swig,
  rootRole.id,
  roleToUpdate.id,
  updateInfo,
);

const tx = new Transaction().add(...ixs);
await sendAndConfirmTransaction(connection, tx, [rootKeypair]);

5. Execute Transactions Through the Swig Wallet

The Swig wallet acts as the signer for inner instructions. Use getSignInstructions to wrap any instruction so it executes from the Swig wallet.

import { SystemProgram } from '@solana/web3.js';
import {
  getSignInstructions,
  getSwigWalletAddress,
  fetchSwig,
} from '@swig-wallet/classic';

const swig = await fetchSwig(connection, swigAccountAddress);
const walletAddress = await getSwigWalletAddress(swig);
const role = swig.findRolesByEd25519SignerPk(signerKeypair.publicKey)[0];

// Build the inner instruction (SOL transfer from the Swig wallet)
const transferIx = SystemProgram.transfer({
  fromPubkey: walletAddress,
  toPubkey: recipientPubkey,
  lamports: 100_000_000, // 0.1 SOL
});

// Wrap it with Swig signing
const signedIxs = await getSignInstructions(swig, role.id, [transferIx]);

const tx = new Transaction().add(...signedIxs);
await sendAndConfirmTransaction(connection, tx, [signerKeypair]);

6. Using the Paymaster (Gasless Transactions)

Classic Paymaster

import { Keypair } from '@solana/web3.js';
import { createPaymasterClient } from '@swig-wallet/paymaster-classic';

const paymaster = createPaymasterClient({
  apiKey: process.env.SWIG_PAYMASTER_API_KEY!,
  paymasterPubkey: process.env.SWIG_PAYMASTER_PUBKEY!,
  baseUrl: 'https://api.onswig.com',
  network: process.env.SWIG_PAYMASTER_NETWORK as 'mainnet' | 'devnet',
});

// Build your instructions normally, then:
const tx = await paymaster.createLegacyTransaction(
  [instruction1, instruction2],
  [userKeypair], // user signs
);

// Paymaster signs and sends
const signature = await paymaster.signAndSend(tx);

Kit Paymaster

import { partiallySignTransaction } from '@solana/kit';
import { createPaymasterClient } from '@swig-wallet/paymaster-kit';

const paymaster = createPaymasterClient({
  apiKey: process.env.SWIG_PAYMASTER_API_KEY!,
  paymasterPubkey: process.env.SWIG_PAYMASTER_PUBKEY!,
  baseUrl: 'https://api.onswig.com',
  network: process.env.SWIG_PAYMASTER_NETWORK as 'mainnet' | 'devnet',
});

const unsignedTx = await paymaster.createTransaction([instruction]);
const partiallySignedTx = await partiallySignTransaction(
  [userKeypair.keyPair],
  unsignedTx,
);
const fullySignedTx = await paymaster.fullySign(partiallySignedTx);

await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
  fullySignedTx,
  { commitment: 'confirmed' },
);

7. Custom Gas Sponsorship Server

If the user has their own gas server, send the serialized transaction to it for signing:

async function sponsorTransaction(
  serializedTx: Uint8Array,
  sponsorUrl: string,
): Promise<Uint8Array> {
  const response = await fetch(`${sponsorUrl}/sponsor`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      transaction: Buffer.from(serializedTx).toString('base64'),
    }),
  });
  const { signedTransaction } = await response.json();
  return Buffer.from(signedTransaction, 'base64');
}

Available Permission Types

Use the Actions builder to set permissions for authorities:

MethodDescription
.all()Full root permissions (everything)
.manageAuthority()Can add/remove/update other authorities
.allButManageAuthority()Everything except managing authorities
.closeSwigAuthority()Can close the Swig account
.solLimit({ amount })One-time SOL spend limit (in lamports as bigint)
.solRecurringLimit({ recurringAmount, window })Recurring SOL limit (window in slots)
.solDestinationLimit({ amount, destination })SOL limit to specific recipient
.solRecurringDestinationLimit({ recurringAmount, window, destination })Recurring SOL to specific recipient
.tokenLimit({ mint, amount })One-time token spend limit
.tokenRecurringLimit({ mint, recurringAmount, window })Recurring token limit
.tokenDestinationLimit({ mint, amount, destination })Token limit to specific recipient
.tokenRecurringDestinationLimit({ mint, recurringAmount, window, destination })Recurring token to specific recipient
.programLimit({ programId })Can interact with a specific program
.programAll()Can interact with any program
.programCurated()Can interact with curated programs
.subAccount()Can create/manage sub-accounts
.stakeAll()Full staking permissions
.stakeLimit({ amount })Staking with amount limit

Combine permissions by chaining:

const actions = Actions.set()
  .solLimit({ amount: 1_000_000_000n }) // 1 SOL limit
  .tokenLimit({ mint: usdcMint, amount: 100_000_000n }) // 100 USDC
  .programLimit({ programId: jupiterProgramId }) // Jupiter access
  .get();

Authority Types

TypeFunctionUse Case
Ed25519createEd25519AuthorityInfo(publicKey)Standard Solana keypair
Ed25519 SessioncreateEd25519SessionAuthorityInfo(publicKey, maxDuration)Time-limited Ed25519
Secp256k1createSecp256k1AuthorityInfo(publicKey)Ethereum-style keys
Secp256r1createSecp256r1AuthorityInfo(publicKey)Passkeys / WebAuthn

Agent Identity Key Setup (Self-Funded)

When the agent needs its own keypair:

import { Keypair } from '@solana/web3.js';
import fs from 'fs';

// Generate and save
const agentKeypair = Keypair.generate();
fs.writeFileSync(
  'agent-keypair.json',
  JSON.stringify(Array.from(agentKeypair.secretKey)),
);
console.log('Agent public key:', agentKeypair.publicKey.toBase58());

// Load later
const loaded = Keypair.fromSecretKey(
  new Uint8Array(JSON.parse(fs.readFileSync('agent-keypair.json', 'utf-8'))),
);

Important Constants

  • Swig Program ID: swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB
  • 1 SOL = 1_000_000_000 lamports (use BigInt or n suffix)
  • Swig Paymaster Dashboard: dashboard.onswig.com

Workflow Summary

  1. Gather config: RPC URL, gas strategy, SDK choice
  2. Install packages: @swig-wallet/classic or @swig-wallet/kit (+ paymaster if needed)
  3. Set up identity: Load or generate a keypair
  4. Create Swig wallet: Generate ID, derive PDA, send create instruction
  5. Fund the wallet: Transfer SOL to the Swig wallet address
  6. Add authorities: Grant granular permissions to other keys
  7. Transact: Wrap inner instructions with getSignInstructions to execute from the wallet
  8. Manage: Update or remove authorities as needed

Error Handling

Always wrap transactions in try/catch and handle common errors:

  • Insufficient balance (need SOL for rent + fees)
  • Authority not found (refetch swig before operations)
  • Permission denied (authority lacks required actions)
  • Spend limit exceeded (authority has already used its allowance)

Always call swig.refetch() before building new instructions to ensure you have the latest on-chain state.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

breeze-x402-payment-api

No summary provided by upstream source.

Repository SourceNeeds Review
Web3

Binance Coach

AI-powered crypto trading behavior coach for Binance users. Analyzes live portfolio health, detects emotional trading patterns (FOMO, panic selling, overtrad...

Registry SourceRecently Updated
Web3

zHive

Register as a trading agent on zHive, post predictions on recurring megathread rounds for top 100 crypto tokens, and compete for accuracy rewards. Rounds res...

Registry SourceRecently Updated
5320kerlos
Web3

Edge.Trade

Use when user asks about crypto tokens, trading, portfolios, or price alerts.

Registry SourceRecently Updated