Skip to content

Commit 48f98d4

Browse files
authored
Merge pull request #85 from p2p-org/feature/token-2022
Token 2022 Support
2 parents d39aeb8 + 5c3b9b9 commit 48f98d4

File tree

43 files changed

+2293
-461
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2293
-461
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## 5.0.0
2+
3+
- Fix TokenMetadata encoding, tags.
4+
- Remove deprecated PublicKey.tokenProgramId, use TokenProgram.id instead.
5+
- Remove deprecated PublicKey.programId, use SystemProgram.id instead.
6+
- Remove deprecated PublicKey.ownerValidationProgramId, use OwnerValidationProgram.id instead.
7+
- Remove deprecated PublicKey.splAssociatedTokenAccountProgramId, use AssociatedTokenProgram.id instead.
8+
- Remove deprecated typealias AccountInfo, use TokenAccountState or Token2022AccountState instead.
9+
- Remove deprecated typealias Mint, use TokenMintState or Token2022MintState instead.
10+
- Remove deprecated typealias Wallet, use AccountBalance instead.
11+
- Support token 2022 via method getAccountBalances (See GetAccountBalancesTests).
12+
- Support token 2022 and Token2022Program.
13+
114
## 4.0.0
215

316
- Rename Wallet to AccountBalance.

Package.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ let package = Package(
3636
),
3737
.testTarget(
3838
name: "SolanaSwiftUnitTests",
39-
dependencies: ["SolanaSwift"]
39+
dependencies: ["SolanaSwift"],
40+
resources: [
41+
.process("Resources/get_all_tokens_info.json"),
42+
]
4043
),
4144
.testTarget(
4245
name: "SolanaSwiftIntegrationTests",

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ Solana-blockchain client, written in pure swift.
77
[![Platform](https://img.shields.io/cocoapods/p/SolanaSwift.svg?style=flat)](https://cocoapods.org/pods/SolanaSwift)
88
[![Documentation Status](https://readthedocs.org/projects/ansicolortags/badge/?version=latest)](https://p2p-org.github.io/solana-swift/documentation/solanaswift)
99

10+
## Breaking changes
11+
### v5.0
12+
...
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)
19+
1020
## Features
1121
- [x] Supported swift concurrency (from 2.0.0)
1222
- [x] Key pairs generation

Sources/SolanaSwift/APIClient/APIClient+Extension.swift

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ import Foundation
55
public extension SolanaAPIClient {
66
// MARK: - Convenience methods
77

8+
func getTokenAccountsByOwner(
9+
pubkey: String,
10+
params: OwnerInfoParams?,
11+
configs: RequestConfiguration?
12+
) async throws -> [TokenAccount<TokenAccountState>] {
13+
try await getTokenAccountsByOwner(
14+
pubkey: pubkey,
15+
params: params,
16+
configs: configs,
17+
decodingTo: TokenAccountState.self
18+
)
19+
}
20+
821
func getMinimumBalanceForRentExemption(span: UInt64) async throws -> UInt64 {
922
try await getMinimumBalanceForRentExemption(dataLength: span, commitment: "recent")
1023
}
@@ -27,19 +40,21 @@ public extension SolanaAPIClient {
2740
try await request(method: method, params: [])
2841
}
2942

30-
func getMultipleMintDatas(
43+
func getMultipleMintDatas<M: MintLayoutState>(
3144
mintAddresses: [String],
32-
commitment: Commitment
33-
) async throws -> [String: SPLTokenMintState?] {
34-
let accounts: [BufferInfo<SPLTokenMintState>?] = try await getMultipleAccounts(
45+
commitment: Commitment,
46+
mintType _: M.Type
47+
) async throws -> [String: M] {
48+
let accounts: [BufferInfo<M>?] = try await getMultipleAccounts(
3549
pubkeys: mintAddresses,
3650
commitment: commitment
3751
)
3852

39-
var mintDict = [String: SPLTokenMintState?]()
53+
var mintDict = [String: M]()
4054

4155
for (index, address) in mintAddresses.enumerated() {
42-
mintDict[address] = accounts[index]?.data
56+
let account = accounts[index] as BufferInfo<M>?
57+
mintDict[address] = account?.data
4358
}
4459

4560
return mintDict
@@ -73,16 +88,18 @@ public extension SolanaAPIClient {
7388

7489
func checkIfAssociatedTokenAccountExists(
7590
owner: PublicKey,
76-
mint: String
91+
mint: String,
92+
tokenProgramId: PublicKey
7793
) async throws -> Bool {
7894
let mintAddress = try mint.toPublicKey()
7995

8096
let associatedTokenAccount = try PublicKey.associatedTokenAddress(
8197
walletAddress: owner,
82-
tokenMintAddress: mintAddress
98+
tokenMintAddress: mintAddress,
99+
tokenProgramId: tokenProgramId
83100
)
84101

85-
let bufferInfo: BufferInfo<SPLTokenAccountState>? = try await getAccountInfo(account: associatedTokenAccount
102+
let bufferInfo: BufferInfo<TokenAccountState>? = try await getAccountInfo(account: associatedTokenAccount
86103
.base58EncodedString)
87104
return bufferInfo?.data.mint == mintAddress
88105
}
@@ -99,10 +116,11 @@ public extension SolanaAPIClient {
99116

100117
func findSPLTokenDestinationAddress(
101118
mintAddress: String,
102-
destinationAddress: String
119+
destinationAddress: String,
120+
tokenProgramId: PublicKey
103121
) async throws -> SPLTokenDestinationAddress {
104122
var address: String
105-
var accountInfo: BufferInfo<SPLTokenAccountState>?
123+
var accountInfo: BufferInfo<TokenAccountState>?
106124
do {
107125
accountInfo = try await getAccountInfoThrowable(account: destinationAddress)
108126
let toTokenMint = accountInfo?.data.mint.base58EncodedString
@@ -116,7 +134,8 @@ public extension SolanaAPIClient {
116134
// create associated token address
117135
address = try PublicKey.associatedTokenAddress(
118136
walletAddress: owner,
119-
tokenMintAddress: tokenMint
137+
tokenMintAddress: tokenMint,
138+
tokenProgramId: tokenProgramId
120139
).base58EncodedString
121140
} else {
122141
throw PublicKeyError.invalidAddress(destinationAddress)
@@ -127,7 +146,8 @@ public extension SolanaAPIClient {
127146
// create associated token address
128147
address = try PublicKey.associatedTokenAddress(
129148
walletAddress: owner,
130-
tokenMintAddress: tokenMint
149+
tokenMintAddress: tokenMint,
150+
tokenProgramId: tokenProgramId
131151
).base58EncodedString
132152
} catch {
133153
throw error
@@ -139,7 +159,7 @@ public extension SolanaAPIClient {
139159
var isUnregisteredAsocciatedToken = false
140160
if destinationAddress != toPublicKey.base58EncodedString {
141161
// check if associated address is already registered
142-
let info: BufferInfo<SPLTokenAccountState>?
162+
let info: BufferInfo<TokenAccountState>?
143163
do {
144164
info = try await getAccountInfoThrowable(account: toPublicKey.base58EncodedString)
145165
} catch {
@@ -148,7 +168,9 @@ public extension SolanaAPIClient {
148168
isUnregisteredAsocciatedToken = true
149169

150170
// if associated token account has been registered
151-
if info?.owner == TokenProgram.id.base58EncodedString, info?.data != nil {
171+
if PublicKey.isSPLTokenProgram(info?.owner),
172+
info?.data != nil
173+
{
152174
isUnregisteredAsocciatedToken = false
153175
}
154176
}

Sources/SolanaSwift/APIClient/Networking/JSONRPCAPIClient.swift

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,13 @@ public class JSONRPCAPIClient: SolanaAPIClient {
143143
return result.value
144144
}
145145

146-
public func getTokenAccountsByDelegate(
146+
public func getTokenAccountsByDelegate<T: TokenAccountLayoutState>(
147147
pubkey: String,
148148
mint: String? = nil,
149149
programId: String? = nil,
150150
configs: RequestConfiguration? = nil
151-
) async throws -> [TokenAccount<SPLTokenAccountState>] {
152-
let result: Rpc<[TokenAccount<SPLTokenAccountState>]> = try await get(
151+
) async throws -> [TokenAccount<T>] {
152+
let result: Rpc<[TokenAccount<T>]> = try await get(
153153
method: "getTokenAccountsByDelegate",
154154
params: [
155155
pubkey,
@@ -161,12 +161,13 @@ public class JSONRPCAPIClient: SolanaAPIClient {
161161
return result.value
162162
}
163163

164-
public func getTokenAccountsByOwner(
164+
public func getTokenAccountsByOwner<T: TokenAccountLayoutState>(
165165
pubkey: String,
166-
params: OwnerInfoParams? = nil,
167-
configs: RequestConfiguration? = nil
168-
) async throws -> [TokenAccount<SPLTokenAccountState>] {
169-
let result: Rpc<[TokenAccount<SPLTokenAccountState>]> = try await get(
166+
params: OwnerInfoParams?,
167+
configs: RequestConfiguration?,
168+
decodingTo _: T.Type
169+
) async throws -> [TokenAccount<T>] {
170+
let result: Rpc<[TokenAccount<T>]> = try await get(
170171
method: "getTokenAccountsByOwner",
171172
params: [pubkey, params, configs]
172173
)

Sources/SolanaSwift/APIClient/SolanaAPIClient.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,12 @@ public protocol SolanaAPIClient {
166166
/// - Returns The result will be an array of TokenAccount<AccountInfo>
167167
/// - SeeAlso https://docs.solana.com/developing/clients/jsonrpc-api#gettokenaccountsbydelegate
168168
///
169-
func getTokenAccountsByDelegate(
169+
func getTokenAccountsByDelegate<T: TokenAccountLayoutState>(
170170
pubkey: String,
171171
mint: String?,
172172
programId: String?,
173173
configs: RequestConfiguration?
174-
) async throws -> [TokenAccount<SPLTokenAccountState>]
174+
) async throws -> [TokenAccount<T>]
175175

176176
/// Returns all SPL Token accounts by token owner
177177
/// - Parameters:
@@ -183,8 +183,12 @@ public protocol SolanaAPIClient {
183183
/// - Returns The result will be an array of TokenAccount<AccountInfo>
184184
/// - SeeAlso https://docs.solana.com/developing/clients/jsonrpc-api#gettokenaccountsbyowner
185185
///
186-
func getTokenAccountsByOwner(pubkey: String, params: OwnerInfoParams?, configs: RequestConfiguration?) async throws
187-
-> [TokenAccount<SPLTokenAccountState>]
186+
func getTokenAccountsByOwner<T: TokenAccountLayoutState>(
187+
pubkey: String,
188+
params: OwnerInfoParams?,
189+
configs: RequestConfiguration?,
190+
decodingTo: T.Type
191+
) async throws -> [TokenAccount<T>]
188192

189193
/// Returns the 20 largest accounts of a particular SPL Token type
190194
/// - Parameters:

Sources/SolanaSwift/BlockchainClient/BlockchainClient+Extensions.swift

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,9 @@ public extension SolanaBlockchainClient {
1313
from owner: PublicKey,
1414
amount: Lamports,
1515
payer: PublicKey,
16-
minRentExemption mre: Lamports?
16+
minRentExemption: Lamports
1717
) async throws -> AccountInstructions {
18-
let newAccount: KeyPair
19-
let minRentExemption: Lamports
20-
async let requestNewAccount = KeyPair(network: apiClient.endpoint.network)
21-
22-
if let mre = mre {
23-
minRentExemption = mre
24-
newAccount = try await requestNewAccount
25-
} else {
26-
(minRentExemption, newAccount) = try await (
27-
apiClient.getMinimumBalanceForRentExemption(
28-
dataLength: UInt64(SPLTokenAccountState.BUFFER_LENGTH),
29-
commitment: "recent"
30-
),
31-
requestNewAccount
32-
)
33-
}
18+
let newAccount = try await KeyPair(network: apiClient.endpoint.network)
3419

3520
return .init(
3621
account: newAccount.publicKey,
@@ -39,7 +24,7 @@ public extension SolanaBlockchainClient {
3924
from: owner,
4025
toNewPubkey: newAccount.publicKey,
4126
lamports: amount + minRentExemption,
42-
space: SPLTokenAccountState.BUFFER_LENGTH,
27+
space: TokenAccountState.BUFFER_LENGTH,
4328
programId: TokenProgram.id
4429
),
4530
TokenProgram.initializeAccountInstruction(
@@ -72,19 +57,21 @@ public extension SolanaBlockchainClient {
7257
func prepareForCreatingAssociatedTokenAccount(
7358
owner: PublicKey,
7459
mint: PublicKey,
60+
tokenProgramId: PublicKey,
7561
feePayer: PublicKey,
7662
closeAfterward: Bool
7763
) async throws -> AccountInstructions {
7864
let associatedAddress = try PublicKey.associatedTokenAddress(
7965
walletAddress: owner,
80-
tokenMintAddress: mint
66+
tokenMintAddress: mint,
67+
tokenProgramId: tokenProgramId
8168
)
8269

8370
let isAssociatedTokenAddressRegistered: Bool
8471
do {
85-
let info: BufferInfo<SPLTokenAccountState>? = try await apiClient
72+
let info: BufferInfo<TokenAccountState>? = try await apiClient
8673
.getAccountInfo(account: associatedAddress.base58EncodedString)
87-
if info?.owner == TokenProgram.id.base58EncodedString,
74+
if PublicKey.isSPLTokenProgram(info?.owner),
8875
info?.data.owner == owner
8976
{
9077
isAssociatedTokenAddressRegistered = true
@@ -127,7 +114,8 @@ public extension SolanaBlockchainClient {
127114
.createAssociatedTokenAccountInstruction(
128115
mint: mint,
129116
owner: owner,
130-
payer: feePayer
117+
payer: feePayer,
118+
tokenProgramId: tokenProgramId
131119
),
132120
],
133121
cleanupInstructions: cleanupInstructions,

0 commit comments

Comments
 (0)