Overview
Message signing allows users to prove ownership of their wallet by signing arbitrary messages. This is commonly used for authentication and verification.Prerequisites
- Dynamic SDK initialized (see Installation Guide)
- User authenticated (see Authentication Guide)
- EVM wallet available (see Wallet Creation)
Sign a Message
Copy
Ask AI
import DynamicSDKSwift
let sdk = DynamicSDK.instance()
func signMessage(wallet: BaseWallet, message: String) async {
do {
let signature = try await sdk.wallets.signMessage(
wallet: wallet,
message: message
)
print("Message signed successfully!")
print("Signature: \(signature)")
} catch {
print("Failed to sign message: \(error)")
}
}
// Usage
let wallet = sdk.wallets.userWallets.first!
await signMessage(wallet: wallet, message: "Hello, Dynamic!")
Sign Message with SwiftUI
Copy
Ask AI
import SwiftUI
import DynamicSDKSwift
struct SignMessageView: View {
let wallet: BaseWallet
@State private var message = ""
@State private var signature: String?
@State private var isLoading = false
@State private var errorMessage: String?
private let sdk = DynamicSDK.instance()
var body: some View {
VStack(spacing: 16) {
TextField("Enter message to sign", text: $message)
.textFieldStyle(.roundedBorder)
Button("Sign Message") {
signMessage()
}
.disabled(message.isEmpty || isLoading)
if isLoading {
ProgressView()
}
if let signature = signature {
VStack(alignment: .leading, spacing: 8) {
Text("Signature:")
.font(.caption)
.foregroundColor(.secondary)
Text(signature)
.font(.system(.caption, design: .monospaced))
.lineLimit(4)
.truncationMode(.middle)
Button("Copy") {
UIPasteboard.general.string = signature
}
.font(.caption)
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(8)
}
if let error = errorMessage {
Text(error)
.foregroundColor(.red)
.font(.caption)
}
}
.padding()
}
private func signMessage() {
isLoading = true
errorMessage = nil
signature = nil
Task { @MainActor in
do {
signature = try await sdk.wallets.signMessage(
wallet: wallet,
message: message
)
} catch {
errorMessage = "Failed to sign: \(error.localizedDescription)"
}
isLoading = false
}
}
}
Common Use Cases
Authentication
Copy
Ask AI
/// Sign a message to prove wallet ownership
func authenticateWithSignature(wallet: BaseWallet) async throws -> String {
let nonce = UUID().uuidString
let message = "Sign this message to authenticate: \(nonce)"
let signature = try await sdk.wallets.signMessage(
wallet: wallet,
message: message
)
// Send signature to your backend for verification
return signature
}
Signing User Actions
Copy
Ask AI
/// Sign a message to confirm user action
func signUserAction(
wallet: BaseWallet,
action: String,
timestamp: Date
) async throws -> String {
let message = """
Action: \(action)
Wallet: \(wallet.address)
Timestamp: \(timestamp.timeIntervalSince1970)
"""
return try await sdk.wallets.signMessage(
wallet: wallet,
message: message
)
}
Off-Chain Signatures
Copy
Ask AI
/// Create off-chain signature for gasless transactions
func signOffChainPermit(
wallet: BaseWallet,
spender: String,
amount: String,
deadline: Int
) async throws -> String {
let message = """
Permit:
Spender: \(spender)
Amount: \(amount)
Deadline: \(deadline)
"""
return try await sdk.wallets.signMessage(
wallet: wallet,
message: message
)
}
Verify Signatures
While signature verification typically happens on the backend or smart contract, here’s how to structure the verification data:Copy
Ask AI
struct SignatureData {
let message: String
let signature: String
let signerAddress: String
func toJSON() -> [String: String] {
return [
"message": message,
"signature": signature,
"signer": signerAddress
]
}
}
// Usage
let signatureData = SignatureData(
message: "Hello, Dynamic!",
signature: signature,
signerAddress: wallet.address
)
// Send to backend for verification
let jsonData = signatureData.toJSON()
Best Practices
1. Always Handle Errors
Copy
Ask AI
do {
let signature = try await sdk.wallets.signMessage(wallet: wallet, message: message)
// Use signature
} catch {
// Show user-friendly error message
print("Could not sign message. Please try again.")
}
2. Include Context in Messages
Copy
Ask AI
// Bad: Unclear message
let message = "12345"
// Good: Clear message with context
let message = """
Welcome to MyApp!
Click "Sign" to prove you own this wallet.
Wallet: \(wallet.address)
Nonce: 12345
"""
3. Show Loading States
Copy
Ask AI
@Published var isLoading = false
func signMessage(wallet: BaseWallet, message: String) {
isLoading = true
Task {
defer { isLoading = false }
let signature = try await sdk.wallets.signMessage(wallet: wallet, message: message)
// Process signature
}
}
4. Clear Sensitive Data
Copy
Ask AI
var signature: String? = try await sdk.wallets.signMessage(wallet: wallet, message: message)
// ... use signature ...
signature = nil // Clear from memory
Error Handling
Copy
Ask AI
do {
let signature = try await sdk.wallets.signMessage(
wallet: wallet,
message: message
)
} catch {
let errorDesc = error.localizedDescription.lowercased()
if errorDesc.contains("rejected") || errorDesc.contains("denied") {
print("User rejected the signature request")
} else if errorDesc.contains("unsupported") {
print("Wallet does not support message signing")
} else {
print("Signing failed: \(error.localizedDescription)")
}
}
Next Steps
- Typed Data Signing - Sign structured data (EIP-712)
- Send ETH Transactions - Send transactions
- Smart Contract Interactions - Interact with contracts