Skip to content

SwiftyLimi/solana-swift

 
 

Repository files navigation

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

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 99.8%
  • Ruby 0.2%