Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Message signing on Solana allows users to prove wallet ownership by signing arbitrary messages.

Prerequisites

Sign Message

import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func signMessage(wallet: BaseWallet, message: String) async throws -> String {
    let signer = sdk.solana.createSigner(wallet: wallet)
    return try await signer.signMessage(message: message)
}

// Usage
let wallet = sdk.wallets.userWallets.first { $0.chain.uppercased() == "SOL" }!
let signature = try await signMessage(wallet: wallet, message: "Hello, Solana!")
print("Signature: \(signature)")

SwiftUI Example

import SwiftUI
import DynamicSDKSwift

struct SolanaSignView: View {
    let wallet: BaseWallet

    @State private var message = ""
    @State private var signature: String?
    @State private var isLoading = false
    @State private var error: String?

    private let sdk = DynamicSDK.instance()

    var body: some View {
        VStack(spacing: 16) {
            Text("Wallet: \(formatAddress(wallet.address))")
                .font(.caption)

            TextField("Message to sign", text: $message)
                .textFieldStyle(.roundedBorder)

            Button("Sign Message") { signMessage() }
                .buttonStyle(.borderedProminent)
                .disabled(message.isEmpty || isLoading)

            if let signature = signature {
                VStack(alignment: .leading) {
                    Text("Signature:").font(.headline)
                    Text(signature)
                        .font(.system(.caption, design: .monospaced))
                        .textSelection(.enabled)
                    Button("Copy") {
                        UIPasteboard.general.string = signature
                    }
                }
                .padding()
                .background(Color.green.opacity(0.1))
                .cornerRadius(8)
            }

            if let error = error {
                Text(error).foregroundColor(.red).font(.caption)
            }
        }
        .padding()
        .navigationTitle("Sign Message")
    }

    private func formatAddress(_ address: String) -> String {
        "\(address.prefix(6))...\(address.suffix(4))"
    }

    private func signMessage() {
        isLoading = true
        error = nil

        Task { @MainActor in
            do {
                let signer = sdk.solana.createSigner(wallet: wallet)
                signature = try await signer.signMessage(message: message)
            } catch {
                self.error = error.localizedDescription
            }
            isLoading = false
        }
    }
}

Authentication Use Case

/// Sign a message to prove wallet ownership
func authenticateWithSignature(wallet: BaseWallet) async throws -> String {
    let nonce = UUID().uuidString
    let message = "Sign to authenticate: \(nonce)"

    let signer = sdk.solana.createSigner(wallet: wallet)
    let signature = try await signer.signMessage(message: message)

    // Send signature to your backend for verification
    return signature
}

Sign Action Confirmation

/// Sign a message to confirm user action
func signActionConfirmation(
    wallet: BaseWallet,
    action: String,
    timestamp: Date
) async throws -> String {
    let message = """
    Action: \(action)
    Wallet: \(wallet.address)
    Timestamp: \(timestamp.timeIntervalSince1970)
    """

    let signer = sdk.solana.createSigner(wallet: wallet)
    return try await signer.signMessage(message: message)
}

Verify Signature Data

Structure for sending to backend:
struct SolanaSignatureData {
    let message: String
    let signature: String
    let publicKey: String

    func toJSON() -> [String: String] {
        return [
            "message": message,
            "signature": signature,
            "publicKey": publicKey
        ]
    }
}

// Usage
let signatureData = SolanaSignatureData(
    message: "Hello, Solana!",
    signature: signature,
    publicKey: wallet.address
)

let jsonData = signatureData.toJSON()
// Send to backend for verification

Best Practices

1. Include Context

// Bad: Unclear message
let message = "12345"

// Good: Clear message with context
let message = """
Welcome to MyApp!

Sign to prove ownership of this wallet.

Wallet: \(wallet.address)
Nonce: 12345
Timestamp: \(Date().timeIntervalSince1970)
"""

2. Handle Errors

do {
    let signer = sdk.solana.createSigner(wallet: wallet)
    let signature = try await signer.signMessage(message: message)
} catch {
    let errorDesc = error.localizedDescription.lowercased()

    if errorDesc.contains("rejected") || errorDesc.contains("denied") {
        print("User rejected the signature request")
    } else {
        print("Signing failed: \(error)")
    }
}

3. Clear Sensitive Data

var signature: String? = try await signer.signMessage(message: message)
// ... use signature ...
signature = nil  // Clear from memory

Error Handling

do {
    let signer = sdk.solana.createSigner(wallet: wallet)
    let signature = try await signer.signMessage(message: message)
    print("Message signed: \(signature)")
} catch {
    print("Failed to sign message: \(error)")
}

Next Steps