> ## Documentation Index
> Fetch the complete documentation index at: https://build.onswig.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Wallet

This tutorial creates your first Swig wallet from the TypeScript SDK.

Before you start, finish [Environment Setup](./env), switch into the
appropriate tutorial directory, and start the local validator with
`bun start-validator`.

```bash theme={null}
mkdir tutorial && touch tutorial-1.ts 
```

Create the file and implement a `createSwigAccount` helper.

## Example

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    import {
      Connection,
      Keypair,
      LAMPORTS_PER_SOL,
      Transaction,
      sendAndConfirmTransaction,
    } from "@solana/web3.js";

    import {
      Actions,
      createEd25519AuthorityInfo,
      findSwigPda,
      getCreateSwigInstruction,
    } from "@swig-wallet/classic";

    import chalk from "chalk";

    async function createSwigAccount(connection: Connection, user: Keypair) {
      try {
        const id = new Uint8Array(32);
        crypto.getRandomValues(id);
        const swigAddress = findSwigPda(id);
        const rootAuthorityInfo = createEd25519AuthorityInfo(user.publicKey);
        const rootActions = Actions.set().manageAuthority().get();

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

        const transaction = new Transaction().add(createSwigIx);
        const signature = await sendAndConfirmTransaction(connection, transaction, [
          user,
        ]);

        console.log(
          chalk.green("✓ Swig account created at:"),
          chalk.cyan(swigAddress.toBase58()),
        );
        console.log(chalk.blue("Transaction signature:"), chalk.cyan(signature));
        return swigAddress;
      } catch (error) {
        console.error(
          chalk.red("✗ Error creating Swig account:"),
          chalk.red(error),
        );
        throw error;
      }
    }

    (async () => {
      console.log(chalk.blue("🚀 Starting tutorial"));
      const connection = new Connection("http://localhost:8899", "confirmed");
      const userKeypair = Keypair.generate();
      const f = await connection.requestAirdrop(
        userKeypair.publicKey,
        100 * LAMPORTS_PER_SOL,
      );
      const blockhash = await connection.getLatestBlockhash();
      await connection.confirmTransaction({
        signature: f,
        blockhash: blockhash.blockhash,
        lastValidBlockHeight: blockhash.lastValidBlockHeight,
      });
      console.log(
        chalk.green("👤 User public key:"),
        chalk.cyan(userKeypair.publicKey.toBase58()),
      );
      const swigAddress = await createSwigAccount(connection, userKeypair);
      setTimeout(() => {
        console.log(chalk.green("\n✨ Everything looks good!"));
        console.log(
          chalk.yellow("🔍 Check out your transaction on Solana Explorer:"),
        );
        console.log(
          chalk.cyan(
            `https://explorer.solana.com/address/${swigAddress.toBase58()}?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899`,
          ),
        );
      }, 2000);
    })();
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    import {
      createSolanaRpc,
      createSolanaRpcSubscriptions,
      generateKeyPairSigner,
      sendAndConfirmTransactionFactory,
      signTransactionMessageWithSigners,
      getSignatureFromTransaction,
      lamports,
      pipe,
      createTransactionMessage,
      setTransactionMessageFeePayerSigner,
      setTransactionMessageLifetimeUsingBlockhash,
      appendTransactionMessageInstructions,
      addSignersToTransactionMessage,
      type IInstruction,
      type KeyPairSigner,
      type Blockhash,
    } from '@solana/kit';

    import {
      Actions,
      createEd25519AuthorityInfo,
      findSwigPda,
      getCreateSwigInstruction,
    } from '@swig-wallet/kit';

    import chalk from 'chalk';
    import { sleepSync } from 'bun';

    // ---------------------------------------
    // Util
    // ---------------------------------------
    function randomBytes(length: number): Uint8Array {
      const array = new Uint8Array(length);
      crypto.getRandomValues(array);
      return array;
    }

    function getTransactionMessage<Inst extends IInstruction[]>(
      instructions: Inst,
      latestBlockhash: Readonly<{
        blockhash: Blockhash;
        lastValidBlockHeight: bigint;
      }>,
      feePayer: KeyPairSigner,
      signers: KeyPairSigner[] = [],
    ) {
      return pipe(
        createTransactionMessage({ version: 0 }),
        (tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
        (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
        (tx) => appendTransactionMessageInstructions(instructions, tx),
        (tx) => addSignersToTransactionMessage(signers, tx),
      );
    }

    async function sendTransaction<T extends IInstruction[]>(
      connection: {
        rpc: ReturnType<typeof createSolanaRpc>;
        rpcSubscriptions: ReturnType<typeof createSolanaRpcSubscriptions>;
      },
      instructions: T,
      payer: KeyPairSigner,
      signers: KeyPairSigner[] = [],
    ) {
      const { value: latestBlockhash } = await connection.rpc
        .getLatestBlockhash()
        .send();
      const transactionMessage = getTransactionMessage(
        instructions,
        latestBlockhash,
        payer,
        signers,
      );
      const signedTransaction =
        await signTransactionMessageWithSigners(transactionMessage);

      await sendAndConfirmTransactionFactory(connection as any)(signedTransaction, {
        commitment: 'confirmed',
      });

      const signature = getSignatureFromTransaction(signedTransaction);

      return signature.toString();
    }

    // ---------------------------------------
    // Create Swig Account
    // ---------------------------------------
    async function createSwigAccount(
      connection: {
        rpc: ReturnType<typeof createSolanaRpc>;
        rpcSubscriptions: ReturnType<typeof createSolanaRpcSubscriptions>;
      },
      user: KeyPairSigner,
    ) {
      try {
        const id = randomBytes(32);
        const swigAddress = await findSwigPda(id);
        const authorityInfo = createEd25519AuthorityInfo(user.address);
        const actions = Actions.set().manageAuthority().get();

        const ix = await getCreateSwigInstruction({
          payer: user.address,
          id,
          authorityInfo,
          actions,
        });

        const sig = await sendTransaction(connection, [ix], user);

        console.log(
          chalk.green('✓ Swig account created at:'),
          chalk.cyan(swigAddress.toString()),
        );
        console.log(chalk.blue('Transaction signature:'), chalk.cyan(sig));
        return swigAddress;
      } catch (error) {
        console.error(chalk.red('✗ Error creating Swig account:'), chalk.red(error));
        throw error;
      }
    }

    // ---------------------------------------
    // Main
    // ---------------------------------------
    (async () => {
      console.log(chalk.blue('🚀 Starting tutorial'));

      const connection = {
        rpc: createSolanaRpc('http://localhost:8899'),
        rpcSubscriptions: createSolanaRpcSubscriptions('ws://localhost:8900'),
      };

      const user = await generateKeyPairSigner();

      // Airdrop
      await connection.rpc
        .requestAirdrop(user.address, lamports(BigInt(100 * 1_000_000_000)))
        .send();

      await sleepSync(2000);

      console.log(
        chalk.green('👤 User public key:'),
        chalk.cyan(user.address.toString()),
      );

      const swigAddress = await createSwigAccount(connection, user);

      setTimeout(() => {
        console.log(chalk.green('\n✨ Everything looks good!'));
        console.log(
          chalk.yellow('🔍 Check out your transaction on Solana Explorer:'),
        );
        console.log(
          chalk.cyan(
            `https://explorer.solana.com/address/${swigAddress.toString()}?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899`,
          ),
        );
      }, 2000);
    })();
    ```
  </Tab>
</Tabs>

Lets save this and get ready to run it, but before we do lets break it down step by step.

## 1. Import Required SDKs

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    import {
      Connection,
      Keypair,
      LAMPORTS_PER_SOL,
      Transaction,
      sendAndConfirmTransaction,
    } from '@solana/web3.js';

    import {
      Actions,
      createEd25519AuthorityInfo,
      findSwigPda,
      getCreateSwigInstruction,
    } from '@swig-wallet/classic';
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    import {
      createSolanaRpc,
      createSolanaRpcSubscriptions,
      generateKeyPairSigner,
      sendAndConfirmTransactionFactory,
      signTransactionMessageWithSigners,
      getSignatureFromTransaction,
      lamports,
      pipe,
      createTransactionMessage,
      setTransactionMessageFeePayerSigner,
      setTransactionMessageLifetimeUsingBlockhash,
      appendTransactionMessageInstructions,
      addSignersToTransactionMessage,
      type IInstruction,
      type KeyPairSigner,
      type Blockhash,
    } from '@solana/kit';

    import {
      Actions,
      createEd25519AuthorityInfo,
      findSwigPda,
      getCreateSwigInstruction,
    } from '@swig-wallet/kit';
    ```
  </Tab>
</Tabs>

Imports Solana primitives and essential utilities from the Swig SDK.

## 2. Generate a Unique Swig ID

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    const id = new Uint8Array(32);
    crypto.getRandomValues(id);
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    function randomBytes(length: number): Uint8Array {
      const array = new Uint8Array(length);
      crypto.getRandomValues(array);
      return array;
    }

    const id = randomBytes(32);
    ```
  </Tab>
</Tabs>

Generates a secure 32-byte ID that uniquely identifies this Swig wallet instance. This ID is used to derive the PDA (Program Derived Address).

> 💡 This can really be anything, as long as it's globally unique. You can even use other public keys, strings, or a boring old number if needed.

## 3. Derive the Swig PDA

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    const [swigAddress] = findSwigPda(id);
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    const swigAddress = await findSwigPda(id);
    ```
  </Tab>
</Tabs>

Computes the wallet's on-chain PDA using the generated ID. This is the unique address of the Swig account on Solana.

> 🧠 This is a standard Solana pattern—Swig just makes it easier.

## 4. Create the Root Role

Swig is role-based: it combines Authorities (who) and Actions (what) to determine permissions. This section builds the root role.

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    const rootAuthority = createEd25519AuthorityInfo(user.publicKey);
    const rootActions = Actions.set().manageAuthority().get();
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    const authorityInfo = createEd25519AuthorityInfo(user.address);
    const actions = Actions.set().manageAuthority().get();
    ```
  </Tab>
</Tabs>

This sets up the root role. Since this is the root, it must have at least `manageAuthority()` or `all()`.

> ✅ `manageAuthority()` is restrictive but safe.
>
> 🚨 `all()` gives full control—use carefully in production.

You can find all available action types in the [Swig SDK docs](https://anagrambuild.github.io/swig-ts/enums/_swig-wallet_coder.Permission.html). New types may be added over time.

Swig supports multiple Authority types—this example uses Ed25519 authorities, but others are available for different credentials or verification methods. These handle the Authentication half of Swig's model. You can find all the types of authorities on the [SDK Docs](https://anagrambuild.github.io/swig-ts/enums/_swig-wallet_coder.AuthorityType.html).

## 5. Create the Swig Account On-Chain

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    const createSwigIx = await getCreateSwigInstruction({
      payer: user.publicKey,
      id,
      actions: rootActions,
      authorityInfo: rootAuthority,
    });

    const transaction = new Transaction().add(createSwigIx);
    const signature = await sendAndConfirmTransaction(connection, transaction, [user]);
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    const ix = await getCreateSwigInstruction({
      payer: user.address,
      id,
      authorityInfo,
      actions,
    });

    const sig = await sendTransaction(connection, [ix], user);
    ```
  </Tab>
</Tabs>

Creates the Swig account by building and sending a transaction to the Solana blockchain. The transaction must be signed by the user. In this case the payer of the transaction and the rent is the user, but you can also have a different fee payer for the transaction.

## 6. Simulate a Funded User

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    const userKeypair = Keypair.generate();
    const f = await connection.requestAirdrop(userKeypair.publicKey, 100 * LAMPORTS_PER_SOL);
    const blockhash = await connection.getLatestBlockhash();
    await connection.confirmTransaction({
      signature: f,
      blockhash: blockhash.blockhash,
      lastValidBlockHeight: blockhash.lastValidBlockHeight,
    });
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    const user = await generateKeyPairSigner();

    await connection.rpc
      .requestAirdrop(user.address, lamports(BigInt(100 * 1_000_000_000)))
      .send();

    await sleepSync(2000);
    ```
  </Tab>
</Tabs>

Creates a fresh Keypair and airdrops some SOL from the local validator so it can pay for the transaction.

## 7. Connect to the Validator

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    const connection = new Connection('http://localhost:8899', 'confirmed');
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    const connection = {
      rpc: createSolanaRpc('http://localhost:8899'),
      rpcSubscriptions: createSolanaRpcSubscriptions('ws://localhost:8900'),
    };
    ```
  </Tab>
</Tabs>

Creates a connection to the local Solana cluster. Ensure you've run:

<Tabs>
  <Tab title="Classic">
    ```bash theme={null}
    bun start-validator
    ```
  </Tab>

  <Tab title="Kit">
    ```bash theme={null}
    bun start-validator
    ```
  </Tab>
</Tabs>

This spins up a local testnet with the Swig programs deployed.

## 8. Log Success

<Tabs>
  <Tab title="Classic">
    ```typescript theme={null}
    console.log(chalk.green("✓ Swig account created at:"), chalk.cyan(swigAddress.toBase58()));
    ```
  </Tab>

  <Tab title="Kit">
    ```typescript theme={null}
    console.log(chalk.green("✓ Swig account created at:"), chalk.cyan(swigAddress.toString()));
    ```
  </Tab>
</Tabs>

Prints the address of the new Swig account in a colorized format.

## Ready to run it?

```bash theme={null}
bun run ./tutorial/tutorial-1.ts
```

Congratulations on your first Swig!
