The Para Swift SDK provides robust support for Ethereum Virtual Machine (EVM) compatible blockchains through the ParaEvmSigner class. This guide demonstrates how to perform common operations such as signing messages, signing transactions, and sending transactions on EVM chains.

Getting Started

To work with EVM chains, you’ll need:

  1. An initialized ParaManager instance
  2. A wallet with EVM capabilities
  3. An RPC URL for your target EVM network

Initializing the EVM Signer

First, create an instance of ParaEvmSigner by providing your Para manager, an RPC URL, and optionally a wallet ID:

import ParaSwift

// Create the EVM signer
let paraEvmSigner = try ParaEvmSigner(
    paraManager: paraManager, 
    rpcUrl: "https://sepolia.infura.io/v3/YOUR_API_KEY",
    walletId: wallet.id // Optional, can be selected later
)

Replace YOUR_API_KEY with your actual API key from providers like Infura, Alchemy, or your own RPC node.

Selecting a Wallet

If you didn’t specify a wallet ID when creating the signer, or if you want to switch to a different wallet, use the selectWallet method:

// Select a wallet for signing
try await paraEvmSigner.selectWallet(walletId: wallet.id)

Signing Messages

Para makes it easy to sign arbitrary messages with your EVM wallet:

// Create a message and convert to base64
let message = "Hello, Ethereum!"
let messageBytes = message.data(using: .utf8)!
let base64Message = messageBytes.base64EncodedString()

// Sign the message
let signature = try await paraManager.signMessage(
    walletId: wallet.id, 
    message: base64Message
)

Working with Transactions

Creating an EVM Transaction

Para uses the EVMTransaction model to represent transactions:

import BigInt

// Create transaction parameters
let transaction = EVMTransaction(
    to: "0x301d75d850c878b160ad9e1e3f6300202de9e97f",
    value: BigUInt("1000000000000000")!, // 0.001 ETH in wei
    gasLimit: BigUInt("21000")!,
    gasPrice: nil, // For Type 2 transactions (EIP-1559)
    maxPriorityFeePerGas: BigUInt("1000000000")!, // 1 Gwei
    maxFeePerGas: BigUInt("3000000000")!, // 3 Gwei
    nonce: BigUInt("0")!, // Transaction count for the address
    chainId: BigUInt("11155111")!, // Sepolia testnet
    smartContractAbi: nil, // Optional: ABI for contract interactions
    smartContractFunctionName: nil, // Optional: Function to call
    smartContractFunctionArgs: [], // Optional: Function arguments
    smartContractByteCode: nil, // Optional: For contract deployment
    type: 2 // Transaction type (2 for EIP-1559)
)

Signing a Transaction

To sign a transaction without broadcasting it to the network:

// Sign the transaction
let signedTransaction = try await paraEvmSigner.signTransaction(
    transactionB64: transaction.b64Encoded()
)

Sending a Transaction

To sign and broadcast a transaction in a single step:

// Sign and send the transaction
let transactionHash = try await paraEvmSigner.sendTransaction(
    transactionB64: transaction.b64Encoded()
)

Interacting with Smart Contracts

Para’s EVMTransaction model supports smart contract interactions:

Calling a Contract Function (Read-Only)

// Example of creating a transaction for calling a read function
let contractTransaction = EVMTransaction(
    to: "0x123abc...", // Contract address
    value: BigUInt(0), // No value sent
    gasLimit: BigUInt("100000")!,
    gasPrice: nil,
    maxPriorityFeePerGas: BigUInt("1000000000")!,
    maxFeePerGas: BigUInt("3000000000")!,
    nonce: BigUInt("5")!,
    chainId: BigUInt("11155111")!,
    smartContractAbi: """
    [
        {
            "inputs": [],
            "name": "retrieve",
            "outputs": [{"internalType":"uint256","name":"","type":"uint256"}],
            "stateMutability":"view",
            "type":"function"
        }
    ]
    """,
    smartContractFunctionName: "retrieve",
    smartContractFunctionArgs: [],
    smartContractByteCode: nil,
    type: 2
)

Sending a Transaction to a Contract (Write)

// Example of creating a transaction for a state-changing function
let contractWriteTransaction = EVMTransaction(
    to: "0x123abc...", // Contract address
    value: BigUInt(0), // No value sent
    gasLimit: BigUInt("150000")!,
    gasPrice: nil,
    maxPriorityFeePerGas: BigUInt("1000000000")!,
    maxFeePerGas: BigUInt("3000000000")!,
    nonce: BigUInt("6")!,
    chainId: BigUInt("11155111")!,
    smartContractAbi: """
    [
        {
            "inputs": [{"internalType":"uint256","name":"num","type":"uint256"}],
            "name": "store",
            "outputs": [],
            "stateMutability":"nonpayable",
            "type":"function"
        }
    ]
    """,
    smartContractFunctionName: "store",
    smartContractFunctionArgs: ["42"], // Arguments as strings
    smartContractByteCode: nil,
    type: 2
)

// Send the transaction
try await paraEvmSigner.sendTransaction(
    transactionB64: contractWriteTransaction.b64Encoded()
)

Deploying a Smart Contract

// Example of creating a transaction for contract deployment
let deployTransaction = EVMTransaction(
    to: nil, // nil for contract deployment
    value: BigUInt(0),
    gasLimit: BigUInt("4000000")!,
    gasPrice: nil,
    maxPriorityFeePerGas: BigUInt("1500000000")!,
    maxFeePerGas: BigUInt("3500000000")!,
    nonce: BigUInt("7")!,
    chainId: BigUInt("11155111")!,
    smartContractAbi: nil,
    smartContractFunctionName: nil,
    smartContractFunctionArgs: [],
    smartContractByteCode: "0x608060405234801561001057600080fd5b50...", // Contract bytecode
    type: 2
)

// Send the transaction to deploy the contract
try await paraEvmSigner.sendTransaction(
    transactionB64: deployTransaction.b64Encoded()
)

Working with Different Networks

Para supports any EVM-compatible network. Simply update the RPC URL and chain ID to target different networks:

// Ethereum Mainnet
let mainnetSigner = try ParaEvmSigner(
    paraManager: paraManager,
    rpcUrl: "https://mainnet.infura.io/v3/YOUR_API_KEY",
    walletId: wallet.id
)

// Create transaction with appropriate chain ID
let mainnetTransaction = EVMTransaction(
    // ... other parameters
    chainId: BigUInt("1")!, // Ethereum Mainnet
    // ... other parameters
)

Example Integration