Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zanyfly committed Jul 25, 2024
0 parents commit a9900c1
Showing 1 changed file with 267 additions and 0 deletions.
267 changes: 267 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
# SolanaSwift

Solana-blockchain client, written in pure swift.

[![Version](https://img.shields.io/cocoapods/v/SolanaSwift.svg?style=flat)](https://cocoapods.org/pods/SolanaSwift)
[![License](https://img.shields.io/cocoapods/l/SolanaSwift.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Platform](https://img.shields.io/cocoapods/p/SolanaSwift.svg?style=flat)](https://cocoapods.org/pods/SolanaSwift)
[![Documentation Status](https://readthedocs.org/projects/ansicolortags/badge/?version=latest)](https://p2p-org.github.io/solana-swift/documentation/solanaswift)

## Breaking changes
### v5.0
...
- Remove deprecated typealias Mint, use SPLTokenMintState or Token2022MintState instead.
- Remove deprecated typealias Wallet, use AccountBalance instead.
- Support token 2022 via method getAccountBalances (See GetAccountBalancesTests).
- Support token 2022 and Token2022Program.
...
[See more](https://github.com/p2p-org/solana-swift/blob/main/CHANGELOG.md)

### v2.0
- 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)
- For those who still use `SolanaSDK` class, follow [this link](https://github.com/p2p-org/solana-swift/blob/deprecated/1.3.8/README.md)

## Features
- [x] Supported swift concurrency (from 2.0.0)
- [x] Key pairs generation
- [x] Solana JSON RPC API
- [x] Create, sign transactions
- [x] Send, simulate transactions
- [x] Solana token list
- [x] Socket communication
- [x] OrcaSwapSwift
- [x] RenVMSwift
- [x] Token2022

## Requirements
- iOS 13 or later

## Dependencies
- TweetNacl
- secp256k1.swift
- Task_retrying

## Installation

### Cocoapods
SolanaSwift is available through [CocoaPods](https://cocoapods.org). To install
it, simply add the following line to your Podfile:

```ruby
pod 'SolanaSwift', '~> 5.0.0'
```

### Swift package manager
```swift
...
dependencies: [
...
.package(url: "https://github.com/p2p-org/solana-swift", from: "5.0.0")
],
...
```

## How to use

### Import
```swift
import SolanaSwift
```

### Logger
Create a logger that confirm to SolanaSwiftLogger
```swift
import SolanaSwift

class MyCustomLogger: SolanaSwiftLogger {
func log(event: String, data: String?, logLevel: SolanaSwiftLoggerLogLevel) {
// Custom log goes here
}
}

// AppDelegate or somewhere eles

let customLogger: SolanaSwiftLogger = MyCustomLogger()
SolanaSwift.Logger.setLoggers([customLogger])
```

### AccountStorage
Create 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.

Example:
```swift
import SolanaSwift
import KeychainSwift
struct KeychainAccountStorage: SolanaAccountStorage {
let tokenKey = <YOUR_KEY_TO_STORE_IN_KEYCHAIN>
func save(_ account: Account) throws {
let data = try JSONEncoder().encode(account)
keychain.set(data, forKey: tokenKey)
}

var account: Account? {
guard let data = keychain.getData(tokenKey) else {return nil}
return try JSONDecoder().decode(Account.self, from: data)
}
}

struct InMemoryAccountStorage: SolanaAccountStorage {
private var _account: Account?
func save(_ account: Account) throws {
_account = account
}

var account: Account? {
_account
}
}
```

### Create an account (keypair)
```swift
let account = try await KeyPair(network: .mainnetBeta)
// optional
accountStorage.save(account)
```

### Restore an account from a seed phrase (keypair)
```swift
let account = try await KeyPair(phrases: ["miracle", "hundred", ...], network: .mainnetBeta, derivablePath: ...)
// optional
accountStorage.save(account)
```

### Solana RPC Client
APIClient 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)

Example:
```swift
import SolanaSwift

let endpoint = APIEndPoint(
address: "https://api.mainnet-beta.solana.com",
network: .mainnetBeta
)

// To get block height
let apiClient = JSONRPCAPIClient(endpoint: endpoint)
let result = try await apiClient.getBlockHeight()

// To get balance of the current account
guard let account = try? accountStorage.account?.publicKey.base58EncodedString else { throw UnauthorizedError }
let balance = try await apiClient.getBalance(account: account, commitment: "recent")
```

Wait for confirmation method.

```swift
// Wait for confirmation
let signature = try await blockChainClient.sendTransaction(...)
try await apiClient.waitForConfirmation(signature: signature, ignoreStatus: true) // transaction will be mark as confirmed after timeout no matter what status is when ignoreStatus = true
let signature2 = try await blockchainClient.sendTransaction(/* another transaction that requires first transaction to be completed */)
```

Observe 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)
```swift
// Observe signature status with `observeSignatureStatus` method
var statuses = [TransactionStatus]()
for try await status in apiClient.observeSignatureStatus(signature: "jaiojsdfoijvaij", timeout: 60, delay: 3) {
print(status)
statuses.append(status)
}
// statuses.last == .sending // the signature is not confirmed
// statuses.last?.numberOfConfirmations == x // the signature is confirmed by x nodes (partially confirmed)
// statuses.last == .finalized // the signature is confirmed by all nodes
```

Batch support

```swift
// Batch request with different types
let req1: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getAccountInfo", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])
let req2: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getBalance", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])
let response = try await apiClient.batchRequest(with: [req1, req2])

// Batch request with same type
let balances: [Rpc<UInt64>?] = try await apiClient.batchRequest(method: "getBalance", params: [["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"], ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"], ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"]])
```

For the method that is not listed, use generic method `request(method:params:)` or `request(method:)` without params.

```swift
let result: String = try await apiClient.request(method: "getHealth")
XCTAssertEqual(result, "ok")
```

### Solana Blockchain Client
Prepare, send and simulate transactions. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/solanablockchainclient)

Example:
```swift
import SolanaSwift

let blockchainClient = BlockchainClient(apiClient: JSONRPCAPIClient(endpoint: endpoint))

/// Prepare any transaction, use any Solana program to create instructions, see section Solana program.
let preparedTransaction = try await blockchainClient.prepareTransaction(
instructions: [...],
signers: [...],
feePayer: ...
)

/// SPECIAL CASE: Prepare Sending Native SOL
let preparedTransaction = try await blockchainClient.prepareSendingNativeSOL(
account: account,
to: toPublicKey,
amount: 0
)

/// SPECIAL CASE: Sending SPL Tokens
let preparedTransactions = try await blockchainClient.prepareSendingSPLTokens(
account: account,
mintAddress: <SPL TOKEN MINT ADDRESS>, // USDC mint
decimals: 6,
from: <YOUR SPL TOKEN ADDRESS>, // Your usdc address
to: destination,
amount: <AMOUNT IN LAMPORTS>
)

/// Simulate or send

blockchainClient.simulateTransaction(
preparedTransaction: preparedTransaction
)

blockchainClient.sendTransaction(
preparedTransaction: preparedTransaction
)
```

### Solana Program
List of default programs and pre-defined method that live on Solana network:
1. SystemProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/systemprogram)
2. TokenProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/tokenprogram)
3. AssociatedTokenProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/associatedtokenprogram)
4. OwnerValidationProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/ownervalidationprogram)
5. TokenSwapProgram. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/tokenswapprogram)
6. Token2022Program. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/token2022program)

### Solana Tokens Repository
Tokens repository usefull when you need to get a list of tokens. See [Documentation](https://p2p-org.github.io/solana-swift/documentation/solanaswift/tokensrepository)

Example:
```swift
let tokenRepository = TokensRepository(endpoint: endpoint)
let list = try await tokenRepository.getTokensList()
```
TokenRepository be default uses cache not to make extra calls, it can disabled manually `.getTokensList(useCache: false)`

## Contribution
- Welcome to contribute, feel free to change and open a PR.

## Author
Chung Tran, [email protected]

## License

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

0 comments on commit a9900c1

Please sign in to comment.