Skip to content

Signatures

Ethereum

Privy supports requesting both EIP191 personal_sign and EIP712 eth_signTypedData_v4 signatures from a user's embedded wallet.

Signing messages (EIP191)

To request an EIP191 signature from a user's embedded wallet, send a personal_sign JSON-RPC request to the wallet's EIP1193 provider.

As a parameter to request, pass an object with the fields:

  • method: 'personal_sign'
  • params: [<insert-message>, <insert-wallet-address>]
swift
func personalSign() async throws {
    guard case .connected(let wallets) = privy.embeddedWallet.embeddedWalletState else {
        print("Wallet not connected")
        return
    }

    guard let wallet = wallets.first, wallet.chainType == .ethereum else {
        print("No Ethereum wallets available")
        return
    }

    // Get the provider for wallet
    let provider = try privy.embeddedWallet.getEthereumProvider(for: wallet.address)

    let signature = try await provider.request(
        RpcRequest(
            method: "personal_sign",
            params: ["This is the message that is being signed", wallet.address]
        )
    )

    print(signature)
}

Signing typed data (EIP712)

To request an EIP712 signature from a user's embedded wallet, send an eth_signTypedData_v4 JSON-RPC request to the wallet's EIP1193 provider.

As a parameter to request, pass an object with the fields:

  • method: 'eth_signTypedData_v4'
  • params: [<insert-wallet-address>, <insert-stringified-typed-data>]
swift
// Define a struct to represent your typed data
struct Param: Codable {
    let types: ParamTypes
    let primaryType: String
    let domain: Domain
    let message: Message
}

struct ParamTypes: Codable {
    let eIP712Domain: [DomainType]
    let person: [DomainType]
    let mail: [DomainType]

    enum CodingKeys: String, CodingKey {
        case eIP712Domain = "EIP712Domain"
        case person = "Person"
        case mail = "Mail"
    }
}

struct DomainType: Codable {
    let name: String
    let type: String
}

struct Domain: Codable {
    let name: String
    let version: String
    let chainId: Int
    let verifyingContract: String
}

struct Message: Codable {
    struct W: Codable {
        let name: String
        let wallet: String
    }

    let from: W
    let to: W
    let contents: String
}

func typedData() async throws {
    guard case .connected(let wallets) = privy.embeddedWallet.embeddedWalletState else {
        print("Wallet not connected")
        return
    }

    guard let wallet = wallets.first, wallet.chainType == .ethereum else {
        print("No Ethereum wallets available")
        return
    }

    // Get RPC provider for wallet
    let provider = try privy.embeddedWallet.getEthereumProvider(for: wallet.address)

    let typedData = Param(
        types: ParamTypes(
            eIP712Domain: [
                DomainType(name: "name", type: "string"),
                DomainType(name: "version", type: "string"),
                DomainType(name: "chainId", type: "uint256"),
                DomainType(name: "verifyingContract", type: "address"),
            ],
            person: [
                DomainType(name: "name", type: "string"),
                DomainType(name: "wallet", type: "address")
            ],
            mail: [
                DomainType(name: "from", type: "Person"),
                DomainType(name: "to", type: "Person"),
                DomainType(name: "contents", type: "string"),
            ]
        ), primaryType: "Mail",
        domain: Domain(
            name: "Ether Mail",
            version: "1",
            chainId: 1,
            verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
        ),
        message: Message(
            from: Message.W(name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"),
            to: Message.W(name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"),
            contents: "Hello, Bob!"
        )
    )

    let encodedTypedData = try JSONEncoder().encode(typedData)

    guard let typedDataStr = String(data: encodedTypedData, encoding: .utf8) else {
        print("Data parse error")
        return
    }

    let signature = try await provider.request(
        RpcRequest(
            method: "eth_signTypedData_v4",
            params: [wallet.address, typedDataStr]
        )
    )

    print(signature)
}

Solana

Privy supports requesting signatures on messages and transactions from a user's Solana embedded wallet using the signMessage RPC. To request a signature, get the Solana embedded wallet provider and call the signMessage method on it with a base-64 encoded message to sign. If the signature is computed successfully, signMessage will return it as a base64-encoded string.

ParameterTypeDescription
messageStringThe message to sign, as a base64-encoded string.
swift
func signSolanaMessage() async throws {
    guard case .connected(let wallets) = privy.embeddedWallet.embeddedWalletState else {
        print("Wallet not connected")
        return
    }

    // Replace this with your desired wallet, ensure it's a Solana wallet
    guard let wallet = wallets.first, wallet.chainType == .solana else {
        print("No Solana wallets available")
        return
    }

    // Get the provider for wallet. Wallet chainType MUST be .solana
    let provider = try privy.embeddedWallet.getSolanaProvider(for: wallet.address)

    // Sign a Base64 encoded message
    let signature = try await provider.signMessage(message: "SGVsbG8hIEkgYW0gdGhlIGJhc2U2NCBlbmNvZGVkIG1lc3NhZ2UgdG8gYmUgc2lnbmVkLg==")

    print(signature)
}