In this tutorial, we’ll learn how to add multiple authorities to a Swig account with different permission sets. We’ll create a root authority that can manage other authorities, then add two specialized authorities: one for SOL spending and another for token management.

Prerequisites

Before starting this tutorial:

  1. Make sure you’re in the examples/transfer/tutorial directory
  2. Ensure your local validator is running with:
    bun start-validator

Quick Review

In Tutorial 1, we learned how to create a basic Swig account. Now we’ll expand on that by managing multiple authorities with different permissions.

mkdir tutorial && touch tutorial-2.ts

Open that file up in your favorite editor, or AI overlord super virtual reality googles. Lets make a function called createSwigAccount

Example(note this is only the changed code)

async function addNewAuthority(
  connection: Connection,
  rootUser: Keypair,
  newAuthority: Keypair,
  swigAddress: PublicKey,
  actions: any,
  description: string
) {
  try {
    // Fetch the Swig account
    const swig = await fetchSwig(connection, swigAddress);

    // Find the root role that can manage authorities
    const rootRole = swig.findRolesByEd25519SignerPk(rootUser.publicKey)[0];
    if (!rootRole) {
      throw new Error('Root role not found for authority');
    }

    // Create the instruction to add the new authority
    const addAuthorityIx = await addAuthorityInstruction(
      rootRole,
      rootUser.publicKey,
      createEd25519AuthorityInfo(newAuthority.publicKey),
      actions,
    );

    // Send and confirm the transaction
    const transaction = new Transaction().add(addAuthorityIx);
    await sendAndConfirmTransaction(connection, transaction, [rootUser]);
    console.log(chalk.green(`✓ New ${description} authority added:`), chalk.cyan(newAuthority.publicKey.toBase58()));
  } catch (error) {
    console.error(chalk.red(`✗ Error adding ${description} authority:`), chalk.red(error));
    throw error;
  }
}

(async () => {
  console.log(chalk.blue("🚀 Starting tutorial - Adding Multiple Authorities"));

  // Connect to local Solana network
  const connection = new Connection('http://localhost:8899', 'confirmed');

  // Create and fund the root user
  const rootUser = Keypair.generate();
  console.log(chalk.green("👤 Root user public key:"), chalk.cyan(rootUser.publicKey.toBase58()));

  let airdrop = await connection.requestAirdrop(rootUser.publicKey, 100 * LAMPORTS_PER_SOL);
  let blockhash = await connection.getLatestBlockhash();
  await connection.confirmTransaction({
    signature: airdrop,
    blockhash: blockhash.blockhash,
    lastValidBlockHeight: blockhash.lastValidBlockHeight,
  });

  // Create the Swig account
  console.log(chalk.yellow("\n📝 Creating Swig account..."));
  const swigAddress = await createSwigAccount(connection, rootUser);

  // Create the spending authority
  const spendingAuthority = Keypair.generate();
  console.log(chalk.green("\n👥 Spending authority public key:"), chalk.cyan(spendingAuthority.publicKey.toBase58()));

  // Create the token authority
  const tokenAuthority = Keypair.generate();
  console.log(chalk.green("👥 Token authority public key:"), chalk.cyan(tokenAuthority.publicKey.toBase58()));

  // Add some delay to ensure the Swig account is created
  await new Promise(resolve => setTimeout(resolve, 2000));

  // Add spending authority with SOL limit
  console.log(chalk.yellow("\n🔑 Adding spending authority..."));
  const spendingActions = Actions.set()
    .solLimit({ amount: BigInt(0.1 * LAMPORTS_PER_SOL) })
    .get();
  await addNewAuthority(connection, rootUser, spendingAuthority, swigAddress, spendingActions, "spending");

  // Add token authority with token management permissions
  console.log(chalk.yellow("\n🔑 Adding token authority..."));
  const tokenMint = Keypair.generate().publicKey; // Example token mint
  const tokenActions = Actions.set()
    .tokenLimit({ mint: tokenMint, amount: BigInt(1000000) })
    .get();
  await addNewAuthority(connection, rootUser, tokenAuthority, swigAddress, tokenActions, "token");

  // Verify the authorities were added
  const swig = await fetchSwig(connection, swigAddress);
  console.log(chalk.blue("\n📊 Authority Permissions:"));

  const spendingRole = swig.findRolesByEd25519SignerPk(spendingAuthority.publicKey)[0];
  console.log(chalk.yellow("Spending Authority:"));
  console.log("- Can spend SOL:", chalk.green(spendingRole.canSpendSol(BigInt(0.1 * LAMPORTS_PER_SOL))));
  console.log("- Can spend tokens:", chalk.red(spendingRole.canSpendToken(tokenMint, BigInt(1000000))));

  const tokenRole = swig.findRolesByEd25519SignerPk(tokenAuthority.publicKey)[0];
  console.log(chalk.yellow("\nToken Authority:"));
  console.log("- Can spend SOL:", chalk.red(tokenRole.canSpendSol(BigInt(0.1 * LAMPORTS_PER_SOL))));
  console.log("- Can spend tokens:", chalk.green(tokenRole.canSpendToken(tokenMint, BigInt(1000000))));

  await new Promise(resolve => setTimeout(resolve, 2000));
  console.log(chalk.green("\n✨ Tutorial completed successfully!"));
  console.log(chalk.yellow("🔍 Check out your transaction on Solana Explorer:"));
  console.log(chalk.cyan(`https://explorer.solana.com/address/${swigAddress}?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899`));
})();

Code Breakdown

Let’s examine the key parts of tutorial-2.ts:

1. Creating a Root Authority

const rootActions = Actions.set().manageAuthority().get();
const tx = await createSwig(
  connection,
  id,
  rootAuthority,
  rootActions,
  user.publicKey,
  [user]
);

This creates a Swig account where the root authority has permission to manage other authorities. We specifically use .manageAuthority() to limit this authority to only managing other authorities.

2. Adding a SOL Spending Authority

Dont forget that the full list of actions an authority can have is here.

const spendingActions = Actions.set()
  .solLimit({ amount: BigInt(0.1 * LAMPORTS_PER_SOL) })
  .get();

await addNewAuthority(
  connection,
  rootUser,
  spendingAuthority,
  swigAddress,
  spendingActions,
  "spending"
);

This creates an authority that:

  • Can only spend SOL (no token permissions)
  • Has a spending limit of 0.1 SOL
  • Cannot manage other authorities

3. Adding a Token Authority

const tokenMint = Keypair.generate().publicKey; // Example token mint
const tokenActions = Actions.set()
  .tokenLimit({ mint: tokenMint, amount: BigInt(1000000) })
  .get();

await addNewAuthority(
  connection,
  rootUser,
  tokenAuthority,
  swigAddress,
  tokenActions,
  "token"
);

This creates an authority that:

  • Can only manage tokens for a specific mint
  • Has a token spending limit of 1,000,000 units
  • Cannot spend SOL or manage other authorities

Understanding the Output

When you run the tutorial, you’ll see:

  1. The root user’s public key
  2. The Swig account address
  3. Two new authority public keys
  4. A permission summary showing what each authority can and cannot do

The tutorial provides links to view your transactions on Solana Explorer (using your local validator).

Key Concepts

  • Root Authority: An authority with management permissions that can add or remove other authorities
  • Specialized Authorities: Authorities with specific, limited permissions (e.g., SOL spending or token management)
  • Permission Limits:
    • SOL limits are set in lamports (1 SOL = 1,000,000,000 lamports)
    • Token limits are set based on the token’s decimals
  • Action Sets: Define what an authority can do using methods like:
    • .manageAuthority()
    • .solLimit()
    • .tokenLimit()

Running the Tutorial

Execute the tutorial with:

bun tutorial-2.ts

You nailed it , first try!! You now have a multi authority Swig, free energy and perpetual motion next.