Skip to content

Commit

Permalink
feat: SendService as separated package, update SolanaSwift, move Repo…
Browse files Browse the repository at this point in the history
…sitory from Ethe...
  • Loading branch information
bigearsenal committed Jan 26, 2024
1 parent f54fb59 commit d038e32
Show file tree
Hide file tree
Showing 48 changed files with 1,105 additions and 38 deletions.
27 changes: 26 additions & 1 deletion Packages/KeyAppKit/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ let package = Package(
targets: ["History"]
),

// Repository
.library(
name: "Repository",
targets: ["Repository"]
),

// Sell
.library(
name: "Sell",
Expand Down Expand Up @@ -100,6 +106,11 @@ let package = Package(
targets: ["TokenService"]
),

.library(
name: "SendService",
targets: ["SendService"]
),

// KeyAppBusiness
.library(
name: "KeyAppBusiness",
Expand All @@ -117,7 +128,7 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/p2p-org/solana-swift", branch: "feature/token-2022"),
.package(url: "https://github.com/p2p-org/solana-swift", branch: "main"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.6.0")),
.package(url: "https://github.com/Boilertalk/Web3.swift.git", from: "0.6.0"),
// .package(url: "https://github.com/trustwallet/wallet-core", branch: "master"),
Expand Down Expand Up @@ -236,6 +247,7 @@ let package = Package(
"Wormhole",
"KeyAppNetworking",
"TokenService",
"SendService",
]
),

Expand All @@ -254,6 +266,12 @@ let package = Package(
]
),

// Repository
.target(
name: "Repository",
dependencies: []
),

// Sell
.target(
name: "Sell",
Expand Down Expand Up @@ -300,6 +318,13 @@ let package = Package(
]
),

.target(
name: "SendService",
dependencies: [
"KeyAppNetworking",
]
),

.target(
name: "KeyAppBusiness",
dependencies: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension SolanaAPIClient {
///
/// - Returns: The associated address.
func getAssociatedSPLTokenAddress(for address: PublicKey, mint: PublicKey) async throws -> PublicKey {
let account: BufferInfo<SPLTokenAccountState>? = try? await getAccountInfo(account: address.base58EncodedString)
let account: BufferInfo<TokenAccountState>? = try? await getAccountInfo(account: address.base58EncodedString)

// The account doesn't exists
if account == nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ public class DestinationAnalysatorImpl: DestinationAnalysator {
let address = try await solanaAPIClient.getAssociatedSPLTokenAddress(for: owner, mint: mint)

// Check destination address is exist.
let info: BufferInfo<SPLTokenAccountState>? = try? await solanaAPIClient
let info: BufferInfo<TokenAccountState>? = try? await solanaAPIClient
.getAccountInfo(account: address.base58EncodedString)
let needsCreateDestinationTokenAccount = !PublicKey.isSPLTokenOrToken2022ProgramId(info?.owner)
let needsCreateDestinationTokenAccount = !PublicKey.isSPLTokenProgram(info?.owner)

return .splAccount(needsCreation: needsCreateDestinationTokenAccount)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class TransitTokenAccountManagerImpl: TransitTokenAccountManager {
public func checkIfNeedsCreateTransitTokenAccount(transitToken: TokenAccount?) async throws -> Bool? {
guard let transitToken = transitToken else { return nil }

guard let account: BufferInfo<SPLTokenAccountState> = try await solanaAPIClient
guard let account: BufferInfo<TokenAccountState> = try await solanaAPIClient
.getAccountInfo(account: transitToken.address.base58EncodedString)
else {
return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extension SwapTransactionBuilderImpl {
from: feePayerAddress,
toNewPubkey: destinationNewAccount.publicKey,
lamports: minimumTokenAccountBalance,
space: SPLTokenAccountState.BUFFER_LENGTH,
space: TokenAccountState.BUFFER_LENGTH,
programId: TokenProgram.id
),
TokenProgram.initializeAccountInstruction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ extension SwapTransactionBuilderImpl {
from: feePayerAddress,
toNewPubkey: sourceWSOLNewAccount!.publicKey,
lamports: minimumTokenAccountBalance + inputAmount,
space: SPLTokenAccountState.BUFFER_LENGTH,
space: TokenAccountState.BUFFER_LENGTH,
programId: TokenProgram.id
),
TokenProgram.initializeAccountInstruction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {

// Parse
var reader = BinaryReader(bytes: data.bytes)
let tokenAccountData = try SPLTokenAccountState(from: &reader)
let tokenAccountData = try TokenAccountState(from: &reader)

// Get token
let token = try await tokensService.get(address: tokenAccountData.mint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ extension OrcaSwap {
} else {
try Task.checkCancellation()
let pool = pool
async let tokenAMinRentResult: BufferInfo<SPLTokenAccountState>? = solanaClient
async let tokenAMinRentResult: BufferInfo<TokenAccountState>? = solanaClient
.getAccountInfo(account: pool.tokenAccountA)
async let tokenBMinRentResult: BufferInfo<SPLTokenAccountState>? = solanaClient
async let tokenBMinRentResult: BufferInfo<TokenAccountState>? = solanaClient
.getAccountInfo(account: pool.tokenAccountB)
(tokenAMinRent, tokenBMinRent) = try await(
tokenAMinRentResult?.lamports ?? 2_039_280,
Expand Down
39 changes: 39 additions & 0 deletions Packages/KeyAppKit/Sources/Repository/Models/LoadingState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

/// Loading state for a specific time-consuming operation
public enum LoadingState {
/// Nothing loaded
case initialized
/// Data is loading
case loading
/// Data is loaded
case loaded
/// Error
case error
}

public enum ListLoadingState {
public enum Status {
case loading
case loaded
case error(Error)
}

public enum LoadMoreStatus {
case loading
case reachedEndOfList
case error(Error)
}

case empty(Status)
case nonEmpty(loadMoreStatus: LoadMoreStatus)

public var isEmpty: Bool {
switch self {
case .empty:
return true
default:
return false
}
}
}
17 changes: 17 additions & 0 deletions Packages/KeyAppKit/Sources/Repository/Provider/ListProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

/// Repository that is only responsible for fetching list of items
public protocol ListProvider {
/// ListItemType to be fetched
associatedtype ItemType: Hashable & Identifiable
/// Indicate if should fetching item
func shouldFetch() -> Bool
/// Fetch list of item from outside
func fetch() async throws -> [ItemType]
}

public extension ListProvider {
func shouldFetch() -> Bool {
true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

public protocol PaginatedListProvider: ListProvider {
associatedtype PS: PaginationStrategy
/// Pagination strategy
var paginationStrategy: PS { get }
}

public extension PaginatedListProvider {
@MainActor func shouldFetch() -> Bool {
!paginationStrategy.isLastPageLoaded
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Foundation

/// PaginationStrategy using limit and offset
@MainActor
public class LimitOffsetPaginationStrategy: PaginationStrategy {
// MARK: - Properties

private let limit: Int
private(set) var offset: Int = 0
public private(set) var isLastPageLoaded: Bool = false

// MARK: - Initializer

public nonisolated init(limit: Int) {
self.limit = limit
}

public func checkIfLastPageLoaded<ItemType>(lastSnapshot: [ItemType]?) {
guard let lastSnapshot else {
isLastPageLoaded = true
return
}
isLastPageLoaded = lastSnapshot.count < limit
}

public func resetPagination() {
offset = 0
isLastPageLoaded = false
}

public func moveToNextPage() {
offset += limit
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

/// Strategy of to define how pagination works in ListRepository
@MainActor
public protocol PaginationStrategy {
/// Boolean value to indicate that last page was loaded or not
var isLastPageLoaded: Bool { get }
/// Check if last page loaded
func checkIfLastPageLoaded<ItemType>(lastSnapshot: [ItemType]?)
/// Reset pagination
func resetPagination()
/// Move to next page
func moveToNextPage()
}
51 changes: 51 additions & 0 deletions Packages/KeyAppKit/Sources/Repository/Provider/Provider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Foundation

/// Repository that is only responsible for fetching item
public protocol Provider<ItemType> {
/// ItemType to be fetched
associatedtype ItemType
/// Indicate if should fetching item
func shouldFetch() -> Bool
/// Fetch item from outside
func fetch() async throws -> ItemType?
}

public extension Provider {
func shouldFetch() -> Bool {
true
}
}

// class ListRepository<ItemType: Hashable & Identifiable>: AnyListRepository {
// // MARK: - Properties
//
// /// Strategy that indicates how pagination works, nil if pagination is disabled
// let paginationStrategy: PaginationStrategy?
//
// // MARK: - Initializer
// init(paginationStrategy: PaginationStrategy? = nil) {
// self.paginationStrategy = paginationStrategy
// }
//
// func shouldFetch() -> Bool {
// var shouldRequest: Bool = true
//
// // check if isLastPageLoaded
// if let paginationStrategy {
// shouldRequest = shouldRequest && !paginationStrategy.isLastPageLoaded
// }
//
// return shouldRequest
// }
//
// func fetch() async throws -> [ItemType] {
// fatalError("Must override")
// }
// }

// extension AsyncSequence: Repository {
// func fetch() async throws {
// let iterator = makeAsyncIterator()
// return iterator.next()
// }
// }
Loading

0 comments on commit d038e32

Please sign in to comment.