Wallet Provider

Here we provide some implemented code examples on how the application can interact with it’s wallet provider. The wallet provider and wallet app are deeply connected since the wallet can only be activated by creating an account at the wallet provider and registering the wallet application by logging into that account.

The wallet provider interactions are part of the

WalletUnit

object, provided by the wallet SDK.

Register process

If the user of the wallet app does not have an account enrolled yet, the wallet app can provide a register functionality. To register a new user the following data can be provided to the wallet SDK, which will handle the registration at the provider and also automatically login the user when the registration is successful.

Register: SDK interface

let request = RegistrationRequest(email: _email,
                                  username: _username,
                                  password: _password)
WalletSdk.shared.walletUnit.register(registrationRequest: request) // async
// returns errors in returned WalletUnit object
wallet_sdk.RegistrationError

Register: App example

public func register(userName _username: String,
                        password _password: String,
                        email _email: String) async throws(WalletUnitRegistrationError) {
    let request = RegistrationRequest(email: _email,
                                        username: _username,
                                        password: _password)
    guard let result = try? await WalletSdk.shared.walletUnit.register(registrationRequest: request) else {
        throw WalletUnitRegistrationError.registrationFailed
    }
    
    let value = result.fold { _error in
        // Error occurred
        if let error = _error {
            return WalletUnitRegistrationError.from(error: error)
        }
        return WalletUnitRegistrationError.unknown
    } ifRight: { _ in
        // Success
        return nil
    }
    if let error = value as? WalletUnitRegistrationError {
        throw error
    }
    // success
}

// MARK: - WalletUnitRegistration Errors
public enum WalletUnitRegistrationError: Error {
    // registration errors
    case registrationFailed
    case emailExists
    case usernameInvalid
    case emailInvalid
    case passwordInvalid
    case unknown
    
    /// Handle registration errors
    public static func from(error _error: wallet_sdk.RegistrationError?) -> WalletUnitRegistrationError {
        guard let error = _error else {
            return .unknown
        }
        switch onEnum(of: error) {
        case .requestError:
            return .registrationFailed
        case .emailExists:
            return .emailExists
        case .usernameInvalid:
            return .usernameInvalid
        case .emailInvalid:
            return .emailInvalid
        case .passwordInvalid:
            return .passwordInvalid
        }
    }
}

In this example the WalletUnitRegistrationError enum is just a helper to wrap the Koltin sealed class in a Swift enum. Not needed as you could also just throw the wallets RegistrationError and use the onEnum(of:) function directly.

After the registration call the user has created an account at the wallet provider and is automatically logged in. The wallet SDK will save all needed information and the Wallet state will change to Operational.

Login process

If the user already has an account at the wallet provider and wants to login in the wallet application this could be done by providing following data to the wallet SDK, to handle the login process and update the Wallet state.

Login: SDK interface

let request = LoginRequest(email: _email,
                           password: _password)
WalletSdk.shared.walletUnit.login(loginRequest: request) // async
// returns errors in returned WalletUnit object
wallet_sdk.LoginError

Login: App example

public func login(email _email: String,
                    password _password: String) async throws(WalletUnitLoginError) {
    let request = LoginRequest(email: _email,
                                password: _password)
    guard let result = try? await WalletSdk.shared.walletUnit.login(loginRequest: request) else {
        throw WalletUnitLoginError.loginFailed
    }
    
    let value = result.fold { _error in
        if let error = _error {
            return WalletUnitLoginError.from(error: error)
        }
        return WalletUnitLoginError.unknown
    } ifRight: { _ in
        // KotlinUnit -> Void
        return nil
    }
    if let error = value as? WalletUnitLoginError {
        throw error
    }
    // success
}

public enum WalletUnitLoginError: Error {
    // login errors
    case loginFailed
    case downloadError
    case unAuthorized
    // general errors
    case unknown
    
    public static func from(error _error: wallet_sdk.LoginError?) -> WalletUnitLoginError {
        guard let error = _error else {
            return .unknown
        }
        switch onEnum(of: error) {
        case .downloadError:
            return .downloadError
        case .requestError:
            return .loginFailed
        case .unauthorizedError:
            return .unAuthorized
        }
    }
}

The same applies for the WalletUnitLoginError as for the above WalletUnitRegistrationError and are just helpers if you have to check the errors on different places in the app, so you do not have to think about the onEnum(of:) function.

After the login call the user should be logged in or be informed that an error happened. The wallet SDK will save all needed information and the Wallet state will change to Operational.