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%
1# SolanaSwift23Solana-blockchain client, written in pure swift.45[](https://cocoapods.org/pods/SolanaSwift)6[](https://www.apache.org/licenses/LICENSE-2.0.html)7[](https://cocoapods.org/pods/SolanaSwift)8[](https://p2p-org.github.io/solana-swift/documentation/solanaswift)910## Breaking changes11### v5.012...13- Remove deprecated typealias Mint, use SPLTokenMintState or Token2022MintState instead.14- Remove deprecated typealias Wallet, use AccountBalance instead.15- Support token 2022 via method getAccountBalances (See GetAccountBalancesTests).16- Support token 2022 and Token2022Program.17...18[See more](https://github.com/p2p-org/solana-swift/blob/main/CHANGELOG.md)1920## Features21- [x] Supported swift concurrency (from 2.0.0)22- [x] Key pairs generation23- [x] Solana JSON RPC API24- [x] Create, sign transactions25- [x] Send, simulate transactions26- [x] Solana token list27- [x] Socket communication28- [x] OrcaSwapSwift29- [x] RenVMSwift3031## Example3233To run the example project, clone the repo, and run `pod install` from the Example directory first.34Demo wallet: [p2p-wallet](https://github.com/p2p-org/p2p-wallet-ios)3536## Requirements37- iOS 13 or later3839## Dependencies40- TweetNacl41- secp256k1.swift4243## Installation4445### Cocoapods46SolanaSwift is available through [CocoaPods](https://cocoapods.org). To install47it, simply add the following line to your Podfile:4849```ruby50pod 'SolanaSwift', '~> 5.0.0'51```5253### Swift package manager54```swift55...56dependencies: [57 ...58 .package(url: "https://github.com/p2p-org/solana-swift", from: "5.0.0")59],60...61```6263## How to use64### Version 2.0 update anouncement65* From v2.0.0 we officially omited Rx library and a lot of dependencies, thus we also adopt swift concurrency to `solana-swift`. [What have been changed?](https://github.com/p2p-org/solana-swift/issues/42)66* For those who still use `SolanaSDK` class, follow [this link](https://github.com/p2p-org/solana-swift/blob/deprecated/1.3.8/README.md)6768### Import69```swift70import SolanaSwift71```7273### Logger74Create a logger that confirm to SolanaSwiftLogger75```swift76import SolanaSwift7778class MyCustomLogger: SolanaSwiftLogger {79 func log(event: String, data: String?, logLevel: SolanaSwiftLoggerLogLevel) {80 // Custom log goes here81 }82}8384// AppDelegate or somewhere eles8586let customLogger: SolanaSwiftLogger = MyCustomLogger()87SolanaSwift.Logger.setLoggers([customLogger])88```8990### AccountStorage91Create an `SolanaAccountStorage` 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 "`CustomAccountStorage`" must conform to protocol `SolanaAccountStorage`, which has 2 requirements: function for saving `save(_ account:) throws` and computed property `account: Account? { get thrrows }` for retrieving user's account.9293Example:94```swift95import SolanaSwift96import KeychainSwift97struct KeychainAccountStorage: SolanaAccountStorage {98 let tokenKey = <YOUR_KEY_TO_STORE_IN_KEYCHAIN>99 func save(_ account: Account) throws {100 let data = try JSONEncoder().encode(account)101 keychain.set(data, forKey: tokenKey)102 }103 104 var account: Account? {105 guard let data = keychain.getData(tokenKey) else {return nil}106 return try JSONDecoder().decode(Account.self, from: data)107 }108}109110struct InMemoryAccountStorage: SolanaAccountStorage {111 private var _account: Account?112 func save(_ account: Account) throws {113 _account = account114 }115 116 var account: Account? {117 _account118 }119}120```121122### Create an account (keypair)123```swift124let account = try await Account(network: .mainnetBeta)125// optional126accountStorage.save(account)127```128129### Restore an account from a seed phrase (keypair)130```swift131let account = try await Account(phrases: ["miracle", "hundred", ...], network: .mainnetBeta, derivablePath: ...)132// optional133accountStorage.save(account)134```135136### Solana RPC Client137APIClient for [Solana JSON RPC API](https://docs.solana.com/developing/clients/jsonrpc-api). See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/solanaapiclient)138139Example: 140```swift141import SolanaSwift142143let endpoint = APIEndPoint(144 address: "https://api.mainnet-beta.solana.com",145 network: .mainnetBeta146)147148// To get block height149let apiClient = JSONRPCAPIClient(endpoint: endpoint)150let result = try await apiClient.getBlockHeight()151152// To get balance of the current account153guard let account = try? accountStorage.account?.publicKey.base58EncodedString else { throw UnauthorizedError }154let balance = try await apiClient.getBalance(account: account, commitment: "recent")155```156157Wait for confirmation method.158159```swift160// Wait for confirmation161let signature = try await blockChainClient.sendTransaction(...)162try await apiClient.waitForConfirmation(signature: signature, ignoreStatus: true) // transaction will be mark as confirmed after timeout no matter what status is when ignoreStatus = true163let signature2 = try await blockchainClient.sendTransaction(/* another transaction that requires first transaction to be completed */)164```165166Observe signature status. In stead of using socket to observe signature status, which is not really reliable (socket often returns signature status == `finalized` when it is not fully finalized), we observe its status by periodically sending `getSignatureStatuses` (with `observeSignatureStatus` method)167```swift168// Observe signature status with `observeSignatureStatus` method169var statuses = [TransactionStatus]()170for try await status in apiClient.observeSignatureStatus(signature: "jaiojsdfoijvaij", timeout: 60, delay: 3) {171 print(status)172 statuses.append(status)173}174// statuses.last == .sending // the signature is not confirmed175// statuses.last?.numberOfConfirmations == x // the signature is confirmed by x nodes (partially confirmed)176// statuses.last == .finalized // the signature is confirmed by all nodes177```178179Batch support180181```swift182// Batch request with different types183let req1: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getAccountInfo", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])184let req2: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getBalance", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])185let response = try await apiClient.batchRequest(with: [req1, req2])186187// Batch request with same type188let balances: [Rpc<UInt64>?] = try await apiClient.batchRequest(method: "getBalance", params: [["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"], ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"], ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"]])189```190191For the method that is not listed, use generic method `request(method:params:)` or `request(method:)` without params.192193```swift194let result: String = try await apiClient.request(method: "getHealth")195XCTAssertEqual(result, "ok")196```197198### Solana Blockchain Client199Prepare, send and simulate transactions. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/solanablockchainclient)200201Example: 202```swift203import SolanaSwift204205let blockchainClient = BlockchainClient(apiClient: JSONRPCAPIClient(endpoint: endpoint))206207/// Prepare any transaction, use any Solana program to create instructions, see section Solana program. 208let preparedTransaction = try await blockchainClient.prepareTransaction(209 instructions: [...],210 signers: [...],211 feePayer: ...212)213214/// SPECIAL CASE: Prepare Sending Native SOL215let preparedTransaction = try await blockchainClient.prepareSendingNativeSOL(216 account: account,217 to: toPublicKey,218 amount: 0219)220221/// SPECIAL CASE: Sending SPL Tokens222let preparedTransactions = try await blockchainClient.prepareSendingSPLTokens(223 account: account,224 mintAddress: <SPL TOKEN MINT ADDRESS>, // USDC mint225 decimals: 6,226 from: <YOUR SPL TOKEN ADDRESS>, // Your usdc address227 to: destination,228 amount: <AMOUNT IN LAMPORTS>229)230231/// Simulate or send232233blockchainClient.simulateTransaction(234 preparedTransaction: preparedTransaction235)236237blockchainClient.sendTransaction(238 preparedTransaction: preparedTransaction239)240```241242### Solana Program243List of default programs and pre-defined method that live on Solana network:2441. SystemProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/systemprogram)2452. TokenProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/tokenprogram)2463. AssociatedTokenProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/associatedtokenprogram)2474. OwnerValidationProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/ownervalidationprogram)2485. TokenSwapProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/tokenswapprogram)249250### Solana Tokens Repository251Tokens repository usefull when you need to get a list of tokens. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/tokensrepository)252253Example:254```swift255let tokenRepository = TokensRepository(endpoint: endpoint)256let list = try await tokenRepository.getTokensList()257```258TokenRepository be default uses cache not to make extra calls, it can disabled manually `.getTokensList(useCache: false)`259260## How to use OrcaSwap261OrcaSwap has been moved to new library [OrcaSwapSwift](https://github.com/p2p-org/OrcaSwapSwift) 262263## How to use RenVM264RenVM has been moved to new library [RenVMSwift](https://github.com/p2p-org/RenVMSwift)265266## How to use Serum swap (DEX) (NOT STABLE)267SerumSwap has been moved to new library [SerumSwapSwift](https://github.com/p2p-org/SerumSwapSwift)268269## Contribution270- Welcome to contribute, feel free to change and open a PR.271272## Author273Chung Tran, chung.t@p2p.org274275## License276277SolanaSwift is available under the MIT license. See the LICENSE file for more info.278