Swig supports using Ethereum-style secp256k1 keys for authorization, enabling you to use your Ethereum wallet to control assets on Solana. This guide explains how to integrate Ethereum wallets with Swig and showcases different implementation approaches.

Current Implementation

Currently, Swig uses the compressed public key format for authentication (not the Ethereum address). A future update will introduce an EvmAddress authority type that uses the hashed form of the public key (the standard Ethereum address).

Integration Examples

The recommended approach for Ethereum wallet integration uses the Viem library. Here’s a complete example showing different signing methods:
import { Wallet } from '@ethereumjs/wallet';
import {
  Keypair,
  LAMPORTS_PER_SOL,
  PublicKey,
  SystemProgram,
  Transaction,
  TransactionInstruction,
} from '@solana/web3.js';
import {
  Actions,
  createSecp256k1AuthorityInfo,
  findSwigPda,
  getCreateSwigInstruction,
  getEvmPersonalSignPrefix,
  getSignInstructions,
  Swig,
  SWIG_PROGRAM_ADDRESS,
  type SigningFn,
} from '@swig-wallet/classic';
import { hexToBytes, keccak256 } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// Create an Ethereum wallet account
const userWallet = Wallet.generate();
const privateKeyAccount = privateKeyToAccount(userWallet.getPrivateKeyString());

const transactionPayer = Keypair.generate();
const dappTreasury = Keypair.generate().publicKey;
const id = Uint8Array.from(Array(32).fill(0));
const swigAddress = findSwigPda(id);
const rootActions = Actions.set().all().get();

// Create Swig with secp256k1 authority
const createSwigInstruction = await getCreateSwigInstruction({
  authorityInfo: createSecp256k1AuthorityInfo(privateKeyAccount.publicKey),
  id,
  payer: transactionPayer.publicKey,
  actions: rootActions,
});

// Fetch Swig and find role
let swig = fetchSwig(svm, swigAddress);
let rootRole = swig.findRolesBySecp256k1SignerAddress(
  privateKeyAccount.address,
)[0];

// Different signing methods available:

// 1. Direct keccak256 hash signing (raw message bytes)
const viemSign: SigningFn = async (message: Uint8Array) => {
  const sig = await privateKeyAccount.sign({ hash: keccak256(message) });
  return { signature: hexToBytes(sig) };
};

// 2. Manual Ethereum personal sign prefix
const viemSignWithPrefix: SigningFn = async (message: Uint8Array) => {
  const prefix = getEvmPersonalSignPrefix(message.length);
  const prefixedMessage = new Uint8Array(prefix.length + message.length);

  prefixedMessage.set(prefix);
  prefixedMessage.set(message, prefix.length);

  const sig = await privateKeyAccount.sign({ 
    hash: keccak256(prefixedMessage) 
  });

  return { signature: hexToBytes(sig), prefix };
};

// 3. Viem signMessage method (automatically adds Ethereum personal sign prefix)
const viemSignMessage: SigningFn = async (message: Uint8Array) => {
  const sig = await privateKeyAccount.signMessage({ 
    message: { raw: message } 
  });
  
  return {
    signature: hexToBytes(sig),
    prefix: getEvmPersonalSignPrefix(message.length),
  };
};

// Create and sign a transfer transaction
const transfer = SystemProgram.transfer({
  fromPubkey: swigAddress,
  toPubkey: dappTreasury,
  lamports: 0.1 * LAMPORTS_PER_SOL,
});

const signTransfer = await getSignInstructions(
  swig,
  rootRole.id,
  [transfer],
  false,
  {
    currentSlot: svm.getClock().slot,
    signingFn: viemSign, // or viemSignWithPrefix, or viemSignMessage
    payer: transactionPayer.publicKey,
  },
);

Session-Based Authorization

For enhanced security and better UX, you can use session-based authorization with secp256k1 keys:
import {
  createSecp256k1SessionAuthorityInfo,
  getCreateSessionInstruction,
  getCreateSwigInstruction,
} from '@swig-wallet/classic';

// Create a session-based Swig
const createSwigInstruction = await getCreateSwigInstruction({
  authorityInfo: createSecp256k1SessionAuthorityInfo(
    privateKeyAccount.publicKey,
    100n, // session duration in slots
  ),
  id,
  payer: transactionPayer.publicKey,
  actions: rootActions,
});

// Create a new session
const newSessionInstruction = await getCreateSessionInstruction(
  swig,
  rootRole.id,
  dappSessionKeypair.publicKey,
  50n, // session duration
  {
    currentSlot: svm.getClock().slot,
    signingFn: viemSign,
    payer: transactionPayer.publicKey,
  }
);

Best Practices

  1. Wallet Integration
    • Use the Viem examples as your primary reference for Ethereum wallet integration
    • Choose the appropriate signing method based on your wallet implementation:
      • Direct keccak256: Signs raw message bytes directly
      • Manual prefix: Adds \x19Ethereum Signed Message:\n{length} prefix manually
      • Viem signMessage: Automatically adds Ethereum personal sign prefix
    • Test all three signing methods for maximum wallet compatibility
  2. API Differences
    • Classic: Uses getCreateSwigInstruction(), getSignInstructions(), and fetchSwig() from SVM context
    • Kit: Uses similar functions but with Solana Kit’s RPC and address types
    • Both support the same signing methods and authority types
  3. Security Considerations
    • Use session-based authorities for dApp integrations to limit exposure
    • Keep session durations appropriate for your use case
    • Remember that while using Ethereum keys, you still need a Solana account for transaction fees
  4. Implementation Tips
    • Use the provided helper functions like createSecp256k1AuthorityInfo
    • Implement proper error handling for signing operations
    • Use findRolesBySecp256k1SignerAddress() to locate roles by Ethereum address

Future Developments

The upcoming EvmAddress authority type will allow using the standard Ethereum address format (the hashed form of the public key) instead of the current compressed public key format. This will make integration even more straightforward and familiar to Ethereum developers.

Additional Resources

For complete working examples, check out these files in the swig-ts repository: Classic Examples: Kit Examples: You can also explore the full examples directory in the swig-ts repository for more implementation patterns and use cases.