MaciejGad / solana-swift

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SolanaSwift

Solana-blockchain client, written in pure swift.

Version License Platform

Features

  • Key pairs generation
  • Networking with POST methods for comunicating with solana-based networking system
  • Create, sign transactions
  • Socket communication
  • Orca swap
  • Serum DEX Swap
  • RenVM (Support: Bitcoin)

Example

To run the example project, clone the repo, and run pod install from the Example directory first. Demo wallet: p2p-wallet

Requirements

  • iOS 11 or later
  • RxSwift

Dependencies

  • RxAlamofire
  • TweetNacl
  • CryptoSwift
  • Starscream

Installation

SolanaSwift is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'SolanaSwift', :git => 'https://github.com/p2p-org/solana-swift.git'

How to use

  • Every class or struct is defined within namespace SolanaSDK, for example: SolanaSDK.Account, SolanaSDK.Error.

  • Import

import SolanaSwift
  • Create an AccountStorage for saving account's keyPairs (public and private key), for example: KeychainAccountStorage for saving into Keychain in production, or InMemoryAccountStorage for temporarily saving into memory for testing. The AccountStorage must conform to protocol SolanaSDKAccountStorage, which has 2 requirements: function for saving save(_ account:) throws and computed property account: SolanaSDK.Account? for retrieving user's account.

Example:

import KeychainSwift
struct KeychainAccountStorage: SolanaSDKAccountStorage {
    let tokenKey = <YOUR_KEY_TO_STORE_IN_KEYCHAIN>
    func save(_ account: SolanaSDK.Account) throws {
        let data = try JSONEncoder().encode(account)
        keychain.set(data, forKey: tokenKey)
    }
    
    var account: SolanaSDK.Account? {
        guard let data = keychain.getData(tokenKey) else {return nil}
        return try? JSONDecoder().decode(SolanaSDK.Account.self, from: data)
    }
}

struct InMemoryAccountStorage: SolanaSDKAccountStorage {
    private var _account: SolanaSDK.Account?
    func save(_ account: SolanaSDK.Account) throws {
        _account = account
    }
    var account: SolanaSDK.Account? {
        _account
    }
}
  • Creating an instance of SolanaSDK:
let solanaSDK = SolanaSDK(endpoint: <YOUR_API_ENDPOINT>, accountStorage: KeychainAccountStorage.shared) // endpoint example: https://api.mainnet-beta.solana.com
  • Creating an account:
let mnemonic = Mnemonic()
let account = try SolanaSDK.Account(phrase: mnemonic.phrase, network: .mainnetBeta, derivablePath: .default)
try solanaSDK.accountStorage.save(account)

Example:

solanaSDK.getBalance(account: account, commitment: "recent")
    .subscribe(onNext: {balance in
        print(balance)
    })
    .disposed(by: disposeBag)
  • Send token:
solanaSDK.sendNativeSOL(
    to destination: String,
    amount: UInt64,
    isSimulation: Bool = false
)
    .subscribe(onNext: {result in
        print(result)
    })
    .disposed(by: disposeBag)
    
solanaSDK.sendSPLTokens(
    mintAddress: String,
    decimals: Decimals,
    from fromPublicKey: String,
    to destinationAddress: String,
    amount: UInt64,
    isSimulation: Bool = false
)
    .subscribe(onNext: {result in
        print(result)
    })
    .disposed(by: disposeBag)
  • Send custom method, which was not defined by using method request<T: Decodable>(method:, path:, bcMethod:, parameters:) -> Single<T>

Example:

(solanaSDK.request(method: .post, bcMethod: "aNewMethodThatReturnsAString", parameters: []) as Single<String>)
  • Subscribe and observe socket events:
// accountNotifications
solanaSDK.subscribeAccountNotification(account: <ACCOUNT_PUBLIC_KEY>, isNative: <BOOL>) // isNative = true if you want to observe native solana account
solanaSDK.observeAccountNotifications() // return an Observable<(pubkey: String, lamports: Lamports)>

// signatureNotifications
solanaSDK.observeSignatureNotification(signature: <SIGNATURE>) // return an Completable

How to use OrcaSwap

  • To test transitive swap with orca, the account must have some SOL, SLIM and KURO token
extension OrcaSwapTransitiveTests {
    var kuroPubkey: String {
        <KURO-pubkey-here>
    }
    
    var secretPhrase: String {
        <account-seed-phrases>
    }
    
    var slimPubkey: String {
        <SLIM-pubkey-here>
    }
}
  • Create instance of orca
let orcaSwap = OrcaSwap(
    apiClient: OrcaSwap.MockAPIClient(network: "mainnet"),
    solanaClient: solanaSDK,
    accountProvider: solanaSDK,
    notificationHandler: socket
)
  • Swap
// load any dependencies for swap to work
orcaSwap.load()

// find any destination that can be swapped to from a defined token mint
orcaSwap.findPosibleDestinationMints(fromMint: btcMint)

// get multiple tradable pools pairs (or routes) for a token pair (each pool pairs contains 1 or 2 pools for swapping)
orcaSwap.getTradablePoolsPairs(fromMint: btcMint, toMint: ethMint)

// get bestPool pair for swapping from tradable pools pairs that got from getTradablePoolsPair method, this method return a pool pair that can be used for swapping
orcaSwap.findBestPoolsPairForInputAmount(inputAmount, from: poolsPairs)
orcaSwap.findBestPoolsPairForEstimatedAmount(estimatedAmount, from: poolsPairs)

// swap
orcaSwap.swap(
    fromWalletPubkey: <BTC wallet>,
    toWalletPubkey: <ETH wallet>?,
    bestPoolsPair: <best pool pair>,
    amount: amount,
    slippage: 0.05,
    isSimulation: false
)
    .subscribe(onNext: {result in
        print(result)
    })
    .disposed(by: disposeBag)

How to use Serum swap (DEX) (NOT STABLE)

  • Create an instance of SerumSwap
let serumSwap = SerumSwap(client: solanaSDK, accountProvider: solanaSDK)
  • swap
serumSwap.swap(
    fromMint: <PublicKey>,
    toMint: <PublicKey>,
    amount: <Lamports>,
    minExpectedSwapAmount: <Lamports?>,
    referral: <PublicKey?>,
    quoteWallet: <PublicKey?>,
    fromWallet: <PublicKey>,
    toWallet: <PublicKey?>,
    feePayer: <PublicKey?>,
    configs: <SolanaSDK.RequestConfiguration? = nil>
)

Contribution

  • For supporting new methods, data types, edit SolanaSDK+Methods or SolanaSDK+Models
  • For testing, run Example project and creating test using RxBlocking
  • Welcome to contribute, feel free to change and open a PR.

Author

Chung Tran, chung.t@p2p.org

License

SolanaSwift is available under the MIT license. See the LICENSE file for more info.

About

License:MIT License


Languages

Language:Swift 99.8%Language:Ruby 0.2%