LogoLogo
SupportGithubSign InGet Access
  • Introduction
  • GETTING STARTED
    • SDK Quick Start
    • API Quick Start
  • Guides
    • Web
      • Create a wallet
      • Send tokens
      • Sign a transaction
      • Simulate a transaction
      • Back up a wallet
      • Recover a wallet
      • Cross-device sessions
      • Manage wallet lifecycle states
      • Web authentication methods
      • Perform swaps
      • Add custom signature hooks
      • MPC progress callbacks
      • Portal API methods
      • Configure a custom subdomain
      • Eject a wallet
      • Using the EIP-1193 Provider
      • Legacy documentation
        • Back up a wallet
          • Backup Options
        • Recover a wallet
    • iOS
      • Create a wallet
      • Send tokens
      • Sign a transaction
      • Simulate a transaction
      • Back up a wallet
      • Recover a wallet
      • Cross-device sessions
      • Manage wallet lifecycle states
      • Connect with WalletConnect
      • Build a WebView
      • Perform swaps
      • Add custom signature hooks
      • MPC progress callbacks
      • Portal API methods
      • Manage ERC20 tokens
      • Eject a wallet
      • Legacy documentation
        • Back up a wallet
          • Backup Options
          • Passkey + Enclave Storage
        • Recover a wallet
      • Troubleshooting Tips
      • Feature Flags
    • Android
      • Create a wallet
      • Send tokens
      • Sign a transaction
      • Simulate a transaction
      • Back up a wallet
      • Recover a wallet
      • Cross-device sessions
      • Manage wallet lifecycle states
      • Connect with WalletConnect
      • Build a WebView
      • Perform swaps
      • Add custom signature hooks
      • MPC progress callbacks
      • Portal API methods
      • Eject a wallet
      • Legacy documentation
        • Back up a wallet
          • Backup Options
        • Recover a wallet
    • React Native
      • Create a wallet
      • Send tokens
      • Sign a transaction
      • Simulate a transaction
      • Back up a wallet
      • Recover a wallet
      • Cross-device sessions
      • Manage wallet lifecycle states
      • Connect with WalletConnect
      • Build a WebView
      • Perform swaps
      • Add custom signature hooks
      • MPC progress callbacks
      • Portal API methods
      • Eject a wallet
      • Legacy documentation
        • Back up a wallet
          • Backup Options
        • Recover a wallet
    • Enclave MPC API
      • Create a client
      • Create a wallet
      • Send tokens
      • Sign Ethereum transactions
      • Sign Solana transactions
      • Sign Tron transactions
      • Sign Stellar Transaction
      • Concurrent Transactions
      • Back up a wallet
      • Eject a wallet
  • Reference
    • iOS
      • createWallet
      • backupWallet
      • recoverWallet
      • ejectPrivateKeys
      • registerBackupMethod
      • setGDriveConfiguration
      • setPasskeyConfiguration
      • setPasskeyAuthenticationAnchor
      • setPassword
      • availableRecoveryMethods
      • doesWalletExist
      • isWalletBackedUp
      • isWalletOnDevice
      • isWalletRecoverable
      • getBalances
      • getAssets
      • getNftAssets
      • getTransactions
      • sendSol
      • evaluateTransaction
      • buildEip155Transaction
      • buildSolanaTransaction
      • getWalletCapabilities
    • Android
      • Reference Documentation
    • React Native
      • @portal-hq/core
      • Storage adapters
        • Cloud storage
          • @portal-hq/gdrive-storage
          • @portal-hq/icloud-storage
        • Mobile storage
          • @portal-hq/keychain
          • @portal-hq/mobile-key-values
    • Enclave MPC API
      • V1 endpoints
    • Client API
      • V3 endpoints
      • V1 endpoints
    • Custodian API
      • V3 endpoints
      • V1 endpoints
    • Swaps API
      • V3 endpoints
      • V1 endpoints
  • Resources
    • Flutter
      • iOS
      • Android
    • Error codes
      • Overview
      • MPC errors
      • Network errors
      • General errors
      • Encryption errors
      • Portal Connect errors
    • Portal's MPC architecture
    • Authentication and API Keys
    • Self-Managed Backups
    • Alert Webhooks
    • Wallet lifecycle
    • Backup options
      • Password/PIN
      • GDrive
      • iCloud
      • Passkey + Enclave
    • WalletConnect metadata
    • Advanced security scanning
    • Account abstraction
    • Security firewall
    • Eject
    • Security
    • Blockchain support
    • Chain ID formatting
    • Testnet faucets
    • Going to Production
    • Rate Limits
    • Multi-backup migration guide
    • Multi-wallet migration guides
      • Migrating from Android SDK v3.x.x to v4.x.x
      • Migrating from iOS SDK v3.0.x to v3.2.x
  • Support
    • Changelog
      • Android
      • iOS
      • React Native
      • Web
      • Past Releases
        • 2024 Releases
        • 2023 Releases
    • Celo Hackathon Hub
    • Glossary
Powered by GitBook
On this page
  • Signing an ethereum transaction
  • Estimating Gas
  • Signing Solana Transactions
  • Raw sign
  • Enabling the Enclave Signer

Was this helpful?

  1. Guides
  2. iOS

Sign a transaction

Want to implement your own style, but with all the functionality Portal offers? Use these functions to implement your own custom web3 UI for your users.

PreviousSend tokensNextSimulate a transaction

Last updated 1 month ago

Was this helpful?

This example shows how the Portal Provider interacts with the blockchain.

Signing an ethereum transaction

The Provider has a address of our MPC wallet. The Provider then proxies the request for balance to the configured RPC url and returns the result.

Ensure you have set the gateway URL correctly with or when you initialize the portal class.

Below is an example of how to use Portal to send a USDC transaction on the Ethereum Sepolia testnet:

// Ethereum Sepolia
let chainId = "eip155:11155111" // CAIP-2 format.

// Define the transaction parameters
let transactionParam = BuildTransactionParam(
    to: "0xDestinationAddress", // Replace with the recipient's address
    token: "USDC", // Token to send (USDC in this case)
    amount: "1" // Amount of USDC to send
)

// Build the transaction using Portal
let txDetails = try await portal.buildEip155Transaction(
  chainId: chainId,
  params: transactionParam
)
    
// Sign and send the transaction
let response = try await portal.request(
    chainId,
    withMethod: .eth_sendTransaction,
    andParams: [txDetails.transaction]
)

// Obtain the transaction hash.
guard let txHash = response.result as? String else {
    // Handle a bad response here
    return
}

print("✅ Transaction hash: \(txHash)")

This example demonstrates how to use Portal's SDK to send a transaction on the Ethereum Sepolia testnet. The transaction involves sending 1 USDC to a specified recipient address. Here's a breakdown of the process:

  1. Chain ID: The transaction is configured for the Ethereum Sepolia testnet using the CAIP-2 format (eip155:11155111).

  2. Transaction Parameters: The BuildTransactionParam struct is used to define the transaction details:

    • to: The recipient's address.

    • token: The token to send (in this case, USDC).

    • amount: The amount of the token to send (e.g., 1 USDC).

  3. Building the Transaction: The portal.buildEip155Transaction method constructs the transaction object using the specified parameters.

  4. Signing and Sending: The portal.request method is used to sign and send the transaction. The method takes the chain ID, the eth_sendTransaction method, and the transaction details as parameters.

  5. Transaction Hash: Once the transaction is successfully sent, the transaction hash is returned and printed to the console.

Estimating Gas

By default, Portal will estimate and populate the gas property in a transaction object if the property is undefined.

To estimate the gas value manually, you'll want to use the eth_estimateGas RPC call and pass in your transaction as the parameter.

// Ethereum Sepolia
let chainId = "eip155:11155111" // CAIP-2 format.

// Obtain the eip155 address of the user's wallet.
guard let eip155Address = await portal.getAddress(chainId) else {
  throw PortalExampleAppError.addressNotFound()
}

// Create the transaction object.
let transaction = [
  "from": eip155Address, // Replace with the sender's address
  "to": "0xRecipientAddress", // Replace with the recipient's address
  "value": "0x10", // Native token amount to send (WEI for eip155:11155111).
]

// Make the eth_estimateGas request with the transaction object.
let requestResponse = try await portal.request(
  chainId,
  withMethod: .eth_estimateGas,
  andParams: [transaction]
)

// Retrieve the estimated gas value.
guard let estimatedGas = requestResponse.result as? String else {
  throw PortalExampleAppError.invalidResponseTypeForRequest()
}

// ✅ Nice! You just retrieved the gas estimate.

Here's a breakdown of the process:

  1. Chain ID: The transaction is configured for the Ethereum Sepolia testnet using the CAIP-2 format (eip155:11155111).

  2. Sender Address: The portal.getAddress method retrieves the user's wallet address for the specified chain.

  3. Transaction Object: A transaction object is created with the following fields:

    • from: The sender's address.

    • to: The recipient's address.

    • value: The amount of native token (ETH) to send, specified in WEI.

  4. Gas Estimation: The portal.request method is used to call the eth_estimateGas method, which estimates the gas required for the transaction.

  5. Result Handling: The estimated gas value is retrieved from the response and printed to the console.

Signing Solana Transactions

To construct your own advanced transaction for solana simply follow that example:

// Solana Devnet
let chainId = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" // CAIP-2 format.
​
// Define the transaction parameters
let transactionParam = BuildTransactionParam(
    to: "DestinationAddress", // Replace with the recipient's address
    token: "USDC", // Token to send (USDC in this case)
    amount: "1" // Amount of USDC to send
)
​
// Build the transaction using Portal
let txDetails = await portal.buildSolanaTransaction(
  chainId: chainId,
  params: transactionParam
)
​
// Sign and send the transaction
let response = try await portal.request(
    chainId,
    withMethod: .sol_signAndSendTransaction,
    andParams: [txDetails.transaction]
)
​
// Obtain the transaction hash.
guard let txHash = response.result as? String else {
    // Handle a bad response here
    return
}
​
print("✅ Transaction hash: \(txHash)")

This example demonstrates how to use Portal's SDK to send a transaction on the Solana Devnet. The transaction involves sending 1 USDC to a specified recipient address. Here's a breakdown of the process:

  1. Chain ID: The transaction is configured for the Solana Devnet using the CAIP-2 format (solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1).

  2. Transaction Parameters: The BuildTransactionParam struct is used to define the transaction details:

    • to: The recipient's address.

    • token: The token to send (in this case, USDC).

    • amount: The amount of the token to send (e.g., 1 USDC).

  3. Building the Transaction: The portal.buildSolanaTransaction method constructs the transaction object using the specified parameters.

  4. Signing and Sending: The portal.request method is used to sign and send the transaction. The method takes the chain ID, the sol_signAndSendTransaction method, and the transaction details as parameters.

  5. Transaction Hash: Once the transaction is successfully sent, the transaction hash is returned and printed to the console.

Raw sign

You can now utilize our SDK to generate raw signatures that are generated using the underlying key share without adding any chain specific formatting to the signature. This effectively unlocks your ability to use the Portal SDK with any chain that uses SECP256K1 or ED25519.

  do {
      let response = try await portal.rawSign(
          message: "74657374", // Must be in hex format, e.g. "test" is "74657374" in hex.
          chainId: "eip155:11155111" // choose the chainId eip155 = secp256k1, solana = ed25519
      )
      
      if let signature = response.result as? String  {
          print("✅ Successfully signed message: \(signature)")
      }
      
  } catch {
      print("❌ Error signing message: \(error)")
  }

Enabling the Enclave Signer

Executing MPC operations requires computation on the client device. Depending on the CPU of the client device this can take variable amounts of time, leading to inconsistent signing times across users.

To solve this, you can leverage the Enclave MPC API from your SDK to execute MPC operations server-side which leads to consistent (and often faster) signing speeds.

This feature leverages the Enclave MPC API by sending the user's key share to a Trusted Execution Environment (TEE) which runs the MPC code in a secure AWS Nitro Enclave with the same non-custodial guarantees as client-side MPC.

By enabling the useEnclaveMpcApi feature flag the client key share will be transmitted from the user device, but it is never stored.

TEEs in Nitro Enclaves work by encrypting memory and verifying execution. Encrypted memory means that all of the data being processed on the enclave can’t be accessed by anything other than the running application. Portal employees can’t even read the data on there! Verified execution means that a user can cryptographically verify that their request was handled in a secure enclave. When a user sends an API request to the enclave, Portal returns a set of signed “measurements” that can be verified by the enclave’s public key to ensure that the request was processed on an AWS Nitro Enclave.

Here’s how to enable it:

import PortalSwift

// Initialize Portal with the Enclave MPC API enabled
let portal = try Portal(
  "CLIENT_API_KEY_OR_CLIENT_SESSION_TOKEN", 
   featureFlags: FeatureFlags(
     useEnclaveMPCApi: true
   )
)

By setting useEnclaveMPCApi to true, the Portal instance will use the Enclave MPC API for signing transactions, ensuring faster computation and consistent performance across client devices.


And now you are signing transactions with Portal! 🙌 🚀 Next, we'll explore how to simulate a transaction so that you can create smoother experiences for your users.

Related Documentation

However, there's many other PortalRequestMethods available for you to use, which .

To learn more check out our blog post introducing.

Infura
Alchemy
you can find in the SDK
the Enclave MPC API
buildEip155Transaction function reference
buildSolanaTransaction function reference
sendSol function reference