Skip to content

getpara/swift-sdk

Repository files navigation

Para Swift SDK

Swift iOS Swift Package Manager

Prerequisites

Find your TeamID and Bundle Identifier

Your team id can be found from Apple's developer portal in the top right corner of the Certificates, Identifiers & Profiles section.

Team ID

Your bundle identifier can be found here

Bundle Identifier

Set up a Para Developer Portal Account and Configure Native Passkeys

To get an API Key and configure your team and bundle ids, please go to the Developer Portal.

Once you've created an API key, please fill out the "Native Passkey Configuration" Section with your App Info described above. Please note that once entered, this information can take up to a day to be reflected by Apple. Ping us if you have any questions or if you would like to check in on the status of this

image

Installation

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.

Once you have your Swift package set up, adding ParaSwift as a dependency is as easy as adding it to the dependencies value of your Package.swift or the Package list in Xcode.

dependencies: [

.package(url: "https://github.com/getpara/swift-sdk.git", .upToNextMajor(from: "1.0.0"))

]

Normally you'll want to depend on the ParaSwift target:

.product(name: "ParaSwift", package: "ParaSwift")

Configuring You Project

ParaSwift utilizes native passkeys for authentication and wallet information. In order to use native passkeys in your app you will need several things

Associated Domains

Under Targets->AppName->Signing & Capabilities, click on the +Capability button.

Capability

From the prompt that appears, search for and select Associated Domains

Associated Domains

Note: In order to add the associated domains capability to your project, you cannot use a personal team for the purposes of signing. If you are, you need to set up a company team with Apple.

In the associated domains section that appears after adding it, you will need to add two domains

  1. webcredentials:app.beta.usecapsule.com
  2. webcredentials:app.usecapsule.com
Add Associated Domains AD Filled Out

This will allow you to use passkeys that have been created on any app that uses the Capsule system, so if your users already have a Capsule wallet they will be able to use it in your app.

DeepLink URL Scheme

Under Targets->AppName->Info, click on URL Types

Add a new URL Type and set the URL Schemes value to whatever you would like to use for deeplinking. By default, the ParaManager uses the apps Bundle Identifier, but this can be manually set when instantiating the class.

This will allow you to use OAuth and Connectors with Para

Using ParaSwift

Introduction

ParaSwift provides an interface to Capsule services from within iOS applications using SwiftUI (Support for UIKit coming soon).

Configuring

To configure the capsule instance, you will need to create an instance of the capsule object as well as the globally available authorizationController environment object. This will be needed in several functions later on. If you need an API Key, please reach out to the Capsule Team.

// Load Para configuration
let config = ParaConfig.fromEnvironment()

// Initialize Para manager
let paraManager = ParaManager(environment: config.environment, apiKey: config.apiKey)

Note: Make sure to configure your app's URL scheme in Info.plist under CFBundleURLTypes. The deepLink parameter should match this URL scheme. By default, the deepLink parameter will be your Bundle Identifier.

Creating a User

To create a user, you should first check in the provided email address exists, and if it does not then create it

Button("Sign Up") {

Task.init {

let userExists = try! await paraManager.checkIfUserExists(email: email)

if userExists {

return

}

try! await paraManager.createUser(email: email)

...

}

}

Upon success, the user should receive an email with a 6 digit verification pin. Call the verify function with the verification code acquired from this step. This will return a biometricsId which will be necessary to pass to the next function, generatePasskey.

Generate passkey takes in the authorizationController that was set up earlier. This is necessary to be able to allow the application to present the Passkey modals for creating and selecting a Passkey.

After generating the passkey, the last step is to create a wallet.

Button("Verify") {

Task.init {

let biometricsId = try! await paraManager.verify(verificationCode: code)

try! await paraManager.generatePasskey(email: email, biometricsId: biometricsId, authorizationController: authorizationController)

try! await paraManager.createWallet(skipDistributable: false)

}

}

After the wallet has been created, it will be set in the ParaManager object as a Published var.

Signing a Message

To sign a message, all you need to do is pass in the id of the wallet you would like to use which can be obtained from the paraManager.wallet property, and the text that you would like to sign. This will produce a messageSignature.

Button("Sign Message") {

Task.init {

let messageSignature = try! await paraManager.signMessage(walletId: wallet.id, message: "Some message to sign")

...

}

}

EVM Signer

You may also use the evm signer to sign messages, sign transactions, and send transactions

Instantiating the signer

To start, you must instantiate the signer with your preferred JsonRPCProvider URL. For this example, we are using Infura Sepolia and the first wallet in the paraManager. The wallet is optional, and can be selected / changed after instantiation.

let paraEvmSigner = try! ParaEvmSigner(paraManager: paraManager, rpcUrl: "https://sepolia.infura.io/v3/<YOUR_API_KEY>", walletId: paraManager.wallets.first!.id)

Select a Wallet

try! await paraEvmSigner.selectWallet(walletId: paraManager.wallets.first!.id)

Signing a Message

let message = "Hello, World!"
let signature = try! await paraEvmSigner.signMessage(message)
print(signature)

Signing a Transaction

To sign a transaction, you must first JSONEncode the transaction object, and then b64Encode the resulting data to get the base64 encoded string. This is what needs to be passed to the paraEvmSigner signTransaction function.

let transaction = Transaction(<TX_PARAMS>)
let encodedTransaction = try! JSONEncoder().encode(transaction)
let b64EncodedTransaction = encodedTransaction.base64EncodedString()
let signature = try! await paraEvmSigner.signTransaction(b64EncodedTransaction)
print(signature)

Sending a Transaction

To send a transaction, you must first JSONEncode the transaction object, and then b64Encode the resulting data to get the base64 encoded string. This is what needs to be passed to the paraEvmSigner sendTransaction function.

let transaction = Transaction(<TX_PARAMS>)
let encodedTransaction = try! JSONEncoder().encode(transaction)
let b64EncodedTransaction = encodedTransaction.base64EncodedString()
let signedTx = try! await paraEvmSigner.sendTransaction(b64EncodedTransaction)
print(signedTx)

MetaMask Integration

ParaSwift provides seamless integration with MetaMask Mobile through the MetaMaskConnector class. This allows your iOS app to connect with MetaMask wallets, sign messages, and send transactions.

Setup MetaMask Connector

First, configure your app's Info.plist to allow querying MetaMask URL schemes:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>metamask</string>
</array>

This configuration is required to detect if MetaMask is installed on the device.

Then initialize the MetaMask connector with your app's configuration:

// Create MetaMask configuration
let bundleId = Bundle.main.bundleIdentifier ?? ""
let metaMaskConfig = MetaMaskConfig(
    appName: "Your App Name",
    appId: bundleId,
    apiVersion: "1.0"
)

// Initialize the connector
let metaMaskConnector = MetaMaskConnector(
    para: paraManager,
    appUrl: "https://\(bundleId)",  // Your app's URL
    config: metaMaskConfig
)

Handle Deep Links

Add deep link handling in your SwiftUI app's main entry point:

@main
struct YourApp: App {
    @StateObject private var metaMaskConnector: MetaMaskConnector
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    // Handle MetaMask deep links
                    metaMaskConnector.handleURL(url)
                }
        }
    }
}

Connect to MetaMask

Connect to MetaMask and get the user's accounts:

do {
    try await metaMaskConnector.connect()
    // Connection successful
    // Access connected accounts via metaMaskConnector.accounts
} catch {
    // Handle connection error
}

Sign Messages

Request message signing from the connected MetaMask wallet:

guard let account = metaMaskConnector.accounts.first else { return }

do {
    let signature = try await metaMaskConnector.signMessage(
        "Message to sign",
        account: account
    )
    // Use the signature
} catch {
    // Handle signing error
}

Send Transactions

Send transactions through the connected MetaMask wallet:

guard let account = metaMaskConnector.accounts.first else { return }

let transaction: [String: String] = [
    "from": account,
    "to": "0x...", // Recipient address
    "value": "0x...", // Value in wei (hex)
    "gasLimit": "0x..." // Gas limit (hex)
]

do {
    let txHash = try await metaMaskConnector.sendTransaction(
        transaction,
        account: account
    )
    // Transaction sent successfully
} catch {
    // Handle transaction error
}

Properties

The MetaMask connector provides several useful properties:

  • isConnected: Boolean indicating if MetaMask is connected
  • accounts: Array of connected MetaMask account addresses
  • chainId: Current chain ID (e.g., "0x1" for Ethereum mainnet)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages