Para provides comprehensive support for Cosmos ecosystem integration in Swift applications, allowing you to leverage Para’s secure wallet infrastructure with multiple Cosmos-based blockchains.

Overview

The ParaCosmosSigner class enables seamless interaction with Cosmos chains through Para’s secure key management system. It provides:

  • Direct signing methods for both Direct (modern protobuf) and Amino (legacy) formats
  • Balance queries and wallet management across multiple chains
  • Message signing for arbitrary data authentication
  • Chain-specific configurations with proper prefixes and denominations
  • Secure key operations via Para’s MPC infrastructure
  • Bridge-based implementation that delegates to CosmJS signers for consistency
  • Clean, focused API that follows single responsibility principles

Supported Chains

Para Swift SDK supports the following Cosmos chains with reliable, CORS-enabled RPC endpoints:

ChainChain IDPrefixDefault DenomNetwork Type
Cosmos Hubcosmoshub-4cosmosuatomMainnet
Osmosisosmosis-1osmouosmoMainnet
Junojuno-1junoujunoMainnet
Stargazestargaze-1starsustarsMainnet
Cosmos TestnetprovidercosmosuatomTestnet
Osmosis Testnetosmo-test-5osmouosmoTestnet

Quick Start

1. Initialize ParaCosmosSigner

Create a ParaCosmosSigner instance with chain-specific configuration:

import ParaSwift

// Initialize for Cosmos Hub mainnet (recommended)
let cosmosSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "cosmoshub-4",
    rpcUrl: "https://cosmos-rpc.publicnode.com",
    prefix: "cosmos"
)

// Initialize for Osmosis mainnet
let osmosSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "osmosis-1",
    rpcUrl: "https://osmosis-rpc.publicnode.com",
    prefix: "osmo"
)

// Initialize for Juno mainnet
let junoSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "juno-1",
    rpcUrl: "https://rpc-juno.itastakers.com",
    prefix: "juno"
)

// Initialize for Cosmos testnet
let testnetSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "provider",
    rpcUrl: "https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz",
    prefix: "cosmos"
)

// Or initialize with a specific wallet
let cosmosSignerWithWallet = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "cosmoshub-4",
    rpcUrl: "https://cosmos-rpc.publicnode.com",
    prefix: "cosmos",
    walletId: "your-wallet-id"
)

2. Select a Wallet

Choose which Cosmos wallet to use for signing operations:

// Fetch available wallets
let wallets = try await paraManager.fetchWallets()
let cosmosWallet = wallets.first { $0.type == .cosmos }

// Select the wallet for signing
if let walletId = cosmosWallet?.id {
    try await cosmosSigner.selectWallet(walletId: walletId)
}

3. Get Wallet Address

Retrieve the bech32 address for the selected wallet with the chain-specific prefix:

// Get address for Cosmos Hub 
let cosmosAddress = try await cosmosSigner.getAddress()
print("Cosmos address: \(cosmosAddress)")
// Output: cosmos1abc123...

// Get address for Osmosis
let osmosAddress = try await osmosSigner.getAddress()
print("Osmosis address: \(osmosAddress)")
// Output: osmo1abc123...

// Get address for Juno
let junoAddress = try await junoSigner.getAddress()
print("Juno address: \(junoAddress)")
// Output: juno1abc123...

Wallet Operations

Check Balance

Query the wallet’s token balance with chain-specific denominations:

// Get ATOM balance on Cosmos Hub (default denomination)
let atomBalance = try await cosmosSigner.getBalance()
print("ATOM balance: \(atomBalance) uatom")

// Get OSMO balance on Osmosis (default denomination)
let osmoBalance = try await osmosSigner.getBalance()
print("OSMO balance: \(osmoBalance) uosmo")

// Get specific token balance with custom denomination
let usdcBalance = try await cosmosSigner.getBalance(denom: "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4")
print("USDC balance: \(usdcBalance)")

Sign Transactions

The ParaCosmosSigner provides direct signing methods that return signature data without broadcasting. This follows the single responsibility principle - the signer signs, but doesn’t handle transaction construction or broadcasting:

// Sign with Direct method (recommended - modern protobuf approach)
let directSignDocBase64 = "..." // Your transaction's SignDoc encoded as base64
let directResult = try await cosmosSigner.signDirect(signDocBase64: directSignDocBase64)

// The result contains the signature and signed document
if let signature = directResult["signature"] as? [String: Any],
   let signatureData = signature["signature"] as? String {
    print("Direct signature: \(signatureData)")
}

// Sign with Amino method (legacy - for compatibility)
let aminoSignDocBase64 = "..." // Your amino SignDoc encoded as base64
let aminoResult = try await cosmosSigner.signAmino(signDocBase64: aminoSignDocBase64)

// Handle the amino signature result
if let signature = aminoResult["signature"] as? [String: Any],
   let signatureData = signature["signature"] as? String {
    print("Amino signature: \(signatureData)")
}

Transaction Signing Details

Bridge-Based Implementation

The ParaCosmosSigner uses a bridge-based implementation that delegates to CosmJS signers in the web environment, ensuring consistent behavior with the broader Cosmos ecosystem. This provides:

  • Direct access to CosmJS signing methods (cosmJsSignDirect, cosmJsSignAmino)
  • Proper protobuf and amino handling through proven CosmJS libraries
  • Cross-platform consistency between Swift and web implementations

Signing Methods

Para supports both Cosmos signing methods with clear terminology:

  • Direct Signing - Modern, efficient binary format using protobuf encoding (SIGN_MODE_DIRECT)
  • Amino Signing - Legacy JSON format for backward compatibility

Note: Direct signing is the protobuf-based signing method in CosmJS.

Creating SignDoc for Signing

To use the signing methods, you need to create properly formatted SignDoc objects:

// For Direct signing: create base64-encoded protobuf SignDoc
// This would typically be constructed using transaction building libraries
let directSignDocBase64 = createDirectSignDoc(
    chainId: "cosmoshub-4",
    accountNumber: 12345,
    sequence: 0,
    bodyBytes: txBodyBytes,
    authInfoBytes: authInfoBytes
)

// For Amino signing: create base64-encoded JSON SignDoc  
let aminoSignDoc = [
    "chain_id": "cosmoshub-4",
    "account_number": "12345", 
    "sequence": "0",
    "fee": ["amount": [["denom": "uatom", "amount": "5000"]], "gas": "200000"],
    "msgs": [/* your transaction messages */],
    "memo": "Demo transaction"
]
let aminoSignDocBase64 = try JSONSerialization.data(withJSONObject: aminoSignDoc)
    .base64EncodedString()

Message Signing

Sign arbitrary messages for authentication or verification:

let message = "Welcome to Para Cosmos!"
let signature = try await cosmosSigner.signMessage(message)
print("Message signature: \(signature.hexString())")

Error Handling

Handle Cosmos-specific errors appropriately:

do {
    let result = try await cosmosSigner.signDirect(signDocBase64: directSignDocBase64)
    // Handle successful signing
} catch ParaCosmosSignerError.missingWalletId {
    print("Please select a wallet first")
} catch ParaCosmosSignerError.invalidWalletAddress {
    print("Invalid Cosmos wallet address")
} catch ParaCosmosSignerError.protoSigningFailed(let underlyingError) {
    print("Direct signing failed: \(underlyingError?.localizedDescription ?? "Unknown error")")
} catch ParaCosmosSignerError.aminoSigningFailed(let underlyingError) {
    print("Amino signing failed: \(underlyingError?.localizedDescription ?? "Unknown error")")
} catch ParaCosmosSignerError.bridgeError(let message) {
    print("Bridge communication error: \(message)")
} catch {
    print("Unexpected error: \(error)")
}

Chain Configuration Examples

Here are complete examples for each supported chain with reliable RPC endpoints:

let cosmosSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "cosmoshub-4",
    rpcUrl: "https://cosmos-rpc.publicnode.com",
    prefix: "cosmos"
)

Osmosis Mainnet

let osmosSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "osmosis-1",
    rpcUrl: "https://osmosis-rpc.publicnode.com",
    prefix: "osmo"
)

Juno Mainnet

let junoSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "juno-1",
    rpcUrl: "https://rpc-juno.itastakers.com",
    prefix: "juno"
)

Stargaze Mainnet

let stargazeSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "stargaze-1",
    rpcUrl: "https://rpc.stargaze-apis.com",
    prefix: "stars"
)

Cosmos Testnet

let testnetSigner = try ParaCosmosSigner(
    paraManager: paraManager,
    chainId: "provider",
    rpcUrl: "https://rpc.provider-state-sync-01.rs-testnet.polypore.xyz",
    prefix: "cosmos"
)

Important Notes

Chain-Specific Configuration

Each chain requires specific configuration parameters:

  • Chain ID: The unique identifier for the network (e.g., “cosmoshub-4”, “osmosis-1”)
  • Prefix: The bech32 address prefix (e.g., “cosmos”, “osmo”, “juno”, “stars”)
  • RPC URL: The Tendermint RPC endpoint for the specific chain

RPC Endpoints

Para uses reliable, CORS-enabled RPC endpoints optimized for mobile applications:

  • PublicNode endpoints (recommended): https://cosmos-rpc.publicnode.com
  • ITAStakers endpoints: https://rpc-juno.itastakers.com
  • Official chain endpoints: https://rpc.stargaze-apis.com

These endpoints are specifically chosen for:

  • SSL/TLS compatibility with mobile environments
  • CORS support for browser and mobile app usage
  • High availability and reliability
  • No rate limiting for development usage

API Design Philosophy

The ParaCosmosSigner follows single responsibility principle:

  • Focused on signing only - doesn’t handle transaction construction or broadcasting
  • Clean separation of concerns - signing vs. transaction building vs. broadcasting
  • Direct access to CosmJS methods - signDirect() and signAmino()
  • Minimal surface area - easier to understand and maintain

This approach provides:

  • Flexibility for advanced transaction construction
  • Compatibility with existing Cosmos tooling
  • Clarity about what each method does
  • Maintainability through focused responsibilities

Performance Considerations

  • Direct signing is generally faster and more efficient than Amino
  • Bridge architecture provides direct access to proven CosmJS implementations
  • CORS-enabled endpoints eliminate connection issues in mobile environments
  • Mainnet defaults provide more reliable service than testnets

Next Steps