To get started with the Meso, you will need a Meso Partner ID which you can request here.

Meso does not yet offer an official library for iOS. However, an example implementation that can be found on Github. This example demonstrates rendering Meso’s transfer experience inside of a WebView.

If you have questions contact mailto:support@meso.network.

Requirements

To use Meso, you must have a partnerId which you can request here.

Usage

To initialize Meso, you will need to configure the transfer (see the reference for details).

Setup a transfer
// This is an example static configuration. Typically, this will by dynamically populated in your application at runtime.
let mesoTransferConfiguration = MesoTransferConfiguration(
    partnerId: "<YOUR_PARTNER_ID>",
    network: Network.solanaMainnet,
    // This is just an example Solana address. You will need to input your own wallet.
    walletAddress: walletAddress,
    sourceAmount: transferAmount,
    destinationAsset: Asset.sol,
    environment: Environment.sandbox
)
let meso = Meso(configuration: mesoTransferConfiguration)

meso.on { event in
    switch event {
    case .configurationError(let payload):
        print("[Configuration Error]: \(payload)")
    case .unsupportedAssetError(let payload):
        print("[Unsupported Asset Error]: \(payload)")
    case .unsupportedNetworkError(let payload):
        print("[Unsupported Network Error]: \(payload)")
    case .requestSignedMessage(let payload, let callback):
        // This demonstrates a generic method of signing messages with Solana wallets. In the real world, you would
        // typically use a library or your own signing implementation.
        // If the user cancels or rejects signing, or there is a failure, return nil – `callback(nil)`
        callback(signMessage(messageToSign: payload.messageToSign))
    case .close:
        showMeso = false
    case .transferApproved(let payload):
        print("Handling `transferApproved` \(payload.transfer.id), \(payload.transfer.status)")
    case .transferComplete(let payload):
        let networkTransactionId = payload.transfer.networkTransactionId ?? "unknown"
        print("Transfer complete! mesoId: \(payload.transfer.id), networkTransactionId: \(networkTransactionId)")
        showMeso = false
    default:
        print("Unknown or discarded event")
    }
}

You can then call meso.transfer() when you want to render Meso in a WebView. For example, in a SwiftUI View, you can do something like this:

Initiate a transfer
let meso = Meso(...) // Your Meso configuration

meso.on { event in
// Handle events from Meso
}

struct ContentView: View {
@State private var showMeso = false

    var body: some View {
        ZStack {
            VStack {
                Button("Buy Crypto") {
                    if !showMeso {
                        showMeso.toggle()
                    }
                }
            }

            if showMeso {
                // Calling `meso.transfer` will render the WebView
                meso.transfer()
            }
        }
    }

}

You can close the Meso WebView at any time by calling meso.destroy().

Reference

The full reference for the configuration options can be found in the meso-js docs. However, note that the iOS configuration varies slightly.

MesoTransferConfiguration

The MesoTransferConfiguration struct is located in Meso.swift.

PropertyTypeDescription
partnerIdStringUnique ID for your partner account. (See setup)
networkNetworkThe network to be used for the transfer.
walletAddressStringThe wallet address for the user. This address must be compatible with the selected network and destinationAsset.
sourceAmountFloatA JSON-string-serializable amount for the Transfer.
destinationAmountFloatA JSON-string-serializable amount received after the Transfer. If both sourceAmount and destinationAmount are specified, destinationAmount will take precedence.
destinationAssetAssetThe asset to be transferred.
environmentEnvironmentThe Meso environment to use. Typically you will use sandbox during development and production when you release your application.
authenticationStrategyAuthenticationStrategyDetermines the authentication mechanism for users to perform a transfer. In all scenarios, the user will still be required to perform two-factor authentication (2FA) and, in some cases provide email/password. If omitted, this will default to .walletVerification.

Network

A CAIP-2 network identifier.

  • ethereumMainnet: "eip155:1"
  • solanaMainnet: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
  • polygonMainnet: "eip155:137"

Asset

  • sol: Solana
  • eth: Ethereum
  • usdc: USDC

Environment

The Meso environment to be used for the Transfer. See Environments for more.

  • sandbox – This uses fake assets and stubbed onboarding data for you to test your integration. No funds are moved in this environment.
  • production – This uses real assets, funds, and KYC/user data to perform transfers.

AuthenticationStrategy

  • walletVerification - Verify wallet by signing a message. New users and returning users with new wallets will still need to perform 2FA and login with email/password.
  • headlessWalletVerification - Verify a wallet by signing a message in the background without prompting the user. This is useful for scenarios such as embedded wallets. New users and returning users with new wallets will still need to perform login and 2FA.
  • bypassWalletVerification - Bypass wallet signing altogether and rely only on email/password and 2FA. This is useful for cases where pre-deployment smart contract wallets are being used and wallet verification cannot be performed.

Events

The meso instance will dispatch events at various points in the lifecycle of a Transfer session.

You can handle these events like so:

meso.on { event in
    switch event {
    case .configurationError(let payload):
        print("[Configuration Error]: \(payload)")
    case .unsupportedAssetError(let payload):
        print("[Unsupported Asset Error]: \(payload)")
    case .unsupportedNetworkError(let payload):
        print("[Unsupported Network Error]: \(payload)")
    case .requestSignedMessage(let payload, let callback):
        // This demonstrates a generic method of signing messages with Solana wallets. In the real world, you would
        // typically use a library or your own signing implementation.
        // If the user cancels or rejects signing, or there is a failure, return nil – `callback(nil)`
        callback(signMessage(messageToSign: payload.messageToSign))
    case .close:
        showMeso = false
    case .transferApproved(let payload):
        print("Handling `transferApproved` \(payload.transfer.id), \(payload.transfer.status)")
    case .transferComplete(let payload):
        let networkTransactionId = payload.transfer.networkTransactionId ?? "unknown"
        print("Transfer complete! mesoId: \(payload.transfer.id), networkTransactionId: \(networkTransactionId)")
        showMeso = false
    default:
        print("Unknown or discarded event")
    }
}

Each event is a MesoEvent and will provide one of the following payloads:

Description
transferApproved(payload: TransferPayload)The Transfer has been approved and will have a status of TransferStatus.approved
transferComplete(payload: TransferPayload)The Transfer is complete, funds have moved, and will have a status of TransferStatus.complete
error(payload: ErrorPayload)An error occurred in the application. A client-friendly error will be surfaced.
configurationError(payload: ErrorPayload)The configuration is malformed and values may need to be updated. See ErrorPayload
unsupportedNetworkError(payload: ErrorPayload)The provided network is not currently supported by Meso. See ErrorPayload
unsupportedAssetError(payload: ErrorPayload)The provided asset is not currently supported by Meso. See ErrorPayload
requestSignedMessage(payload: RequestSignedMessagePayload, callback: (_ signedMessage: String?) -> Void)The Meso window has requested a message to be signed to prove ownership of a wallet. Upon signing, this callback can be used to return the signed message.

If no String is returned in the callback, it is assumed the user canceled or rejected the message signing or there was an error.
closeThe user has manually opted to close the Meso window.

TransferPayload

A wrapped result of a transfer status update to be sent to the partner application.

PropertiesDescription
transferTransfer

Transfer

Details of a Meso transfer.

PropertyTypeDescription
idStringThe Meso id for this transfer.
statusTransferStatusThe status of the transfer.
updatedAtStringAn ISO-8601 date string.
networkTransactionIdString?The on-chain identifier for the transfer.

Note: This will only be available for transfers that are complete.

TransferStatus

kind: enum
  • approved - The transfer has been approved and is pending completion. At this point, funds have not yet been moved.
  • complete - The transfer is complete and the user’s funds are available.
  • declined - The transfer has failed.
  • executing - The transfer is in flight.

ErrorPayload

TypeDescription
messageStringA client-friendly error message.

RequestSignedMessagePayload

The payload received when the webView prompts for a wallet signature.

TypeDescription
messageToSignStringAn opaque message to be signed via an action in the Meso window.

Testing

See details on environments and testing here.

Supported versions

While the example application targets iOS 15+, Meso should work with iOS 13-14.

Caveats

  • You will have to implement your own message signing mechanism. For this demo, we have roughed one in for Solana.
  • The demo code contains print statements, which you can remove according to your requirements. import from “process”