SPB Git

spb/os-vault Public

Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.

Swift 96% Shell 3.4% Makefile 0.6%
3.7 KB · 101 lines swift
Raw Blame History
1import Foundation2import Task_retrying34/// BlockchainClient that prepares and serialises transaction to send to blockchain5public protocol SolanaBlockchainClient: AnyObject {6    /// APIClient for handling network requests7    var apiClient: SolanaAPIClient { get set }89    /// Prepare a transaction base on its instructions10    /// - Parameters:11    ///   - instructions: instructions of the transaction12    ///   - signers: the signers13    ///   - feePayer: the feePayer, usually is the first signer14    ///   - recentBlockhash: recentBlockhash, can be fetched lately when the value is nil15    ///   - feeCalculator: the fee calculator, leave it nil to use DefaultFeeCalculator16    /// - Returns: information of a prepared transaction17    func prepareTransaction(18        instructions: [TransactionInstruction],19        signers: [KeyPair],20        feePayer: PublicKey,21        feeCalculator: FeeCalculator?22    ) async throws -> PreparedTransaction2324    /// Send transaction25    /// - Parameter preparedTransaction: a prepared transaction26    /// - Returns: Transaction id27    func sendTransaction(28        preparedTransaction: PreparedTransaction29    ) async throws -> String3031    /// Simulate transaction32    /// - Parameter preparedTransaction: a prepared transaction33    func simulateTransaction(34        preparedTransaction: PreparedTransaction35    ) async throws -> SimulationResult36}3738public extension SolanaBlockchainClient {39    /// Send preparedTransaction40    /// - Parameter preparedTransaction: preparedTransaction to be sent41    /// - Returns: Transaction signature42    func sendTransaction(43        preparedTransaction: PreparedTransaction44    ) async throws -> String {45        try await Task.retrying(46            where: { $0.isEqualTo(.blockhashNotFound) },47            maxRetryCount: 3,48            retryDelay: 1,49            timeoutInSeconds: 6050        ) {51            let recentBlockhash = try await self.apiClient.getRecentBlockhash()52            let serializedTransaction = try self.signAndSerialize(53                preparedTransaction: preparedTransaction,54                recentBlockhash: recentBlockhash55            )56            return try await self.apiClient.sendTransaction(57                transaction: serializedTransaction,58                configs: RequestConfiguration(encoding: "base64")!59            )60        }61        .value62    }6364    /// Simulate transaction (for testing purpose)65    /// - Parameter preparedTransaction: preparedTransaction to be simulated66    /// - Returns: The result of Simulation67    func simulateTransaction(68        preparedTransaction: PreparedTransaction69    ) async throws -> SimulationResult {70        let recentBlockhash = try await apiClient.getRecentBlockhash()71        let serializedTransaction = try signAndSerialize(72            preparedTransaction: preparedTransaction,73            recentBlockhash: recentBlockhash74        )75        return try await apiClient.simulateTransaction(76            transaction: serializedTransaction, configs: RequestConfiguration(77                commitment: "confirmed",78                encoding: "base64",79                replaceRecentBlockhash: true80            )!81        )82    }8384    // MARK: - Helpers8586    /// Sign and serialize transaction (for testing purpose)87    /// - Parameters:88    ///   - preparedTransaction: preparedTransaction89    ///   - recentBlockhash: recentBlockhash90    /// - Returns: serializedTransaction91    internal func signAndSerialize(92        preparedTransaction: PreparedTransaction,93        recentBlockhash: String94    ) throws -> String {95        var preparedTransaction = preparedTransaction96        preparedTransaction.transaction.recentBlockhash = recentBlockhash97        try preparedTransaction.sign()98        return try preparedTransaction.serialize()99    }100}101