Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/pwn 722 #1626

Merged
merged 13 commits into from
Jan 16, 2024
2 changes: 1 addition & 1 deletion Packages/KeyAppKit/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/p2p-org/solana-swift", branch: "main"),
.package(url: "https://github.com/p2p-org/solana-swift", branch: "feature/token-2022"),
.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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ extension SolanaAPIClient {

// The account doesn't exists
if account == nil {
return try PublicKey.associatedTokenAddress(walletAddress: address, tokenMintAddress: mint)
return try PublicKey.associatedTokenAddress(
walletAddress: address,
tokenMintAddress: mint,
tokenProgramId: TokenProgram.id
)
}

// The account is already token account
Expand All @@ -28,7 +32,11 @@ extension SolanaAPIClient {
guard account?.owner != SystemProgram.id.base58EncodedString else {
throw FeeRelayerError.wrongAddress
}
return try PublicKey.associatedTokenAddress(walletAddress: address, tokenMintAddress: mint)
return try PublicKey.associatedTokenAddress(
walletAddress: address,
tokenMintAddress: mint,
tokenProgramId: TokenProgram.id
)
}

func isAccountExists(_ address: PublicKey) async throws -> Bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@ import SolanaSwift

/// A basic class that represents SPL TokenMetadata.
public struct TokenAccount: Equatable, Codable {
public init(address: PublicKey, mint: PublicKey) {
public init(
address: PublicKey,
mint: PublicKey,
minimumTokenAccountBalance: UInt64
) {
self.address = address
self.mint = mint
self.minimumTokenAccountBalance = minimumTokenAccountBalance
}

/// A address of spl token.
public let address: PublicKey

/// A mint address for spl token.
public let mint: PublicKey

/// Mint rent for token
public let minimumTokenAccountBalance: UInt64
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,19 @@ import Foundation
import SolanaSwift

public struct RelayContext: Hashable, Codable {
public let minimumTokenAccountBalance: UInt64
public let minimumRelayAccountBalance: UInt64
public let feePayerAddress: PublicKey
public let lamportsPerSignature: UInt64
public let relayAccountStatus: RelayAccountStatus
public var usageStatus: UsageStatus

public init(
minimumTokenAccountBalance: UInt64,
minimumRelayAccountBalance: UInt64,
feePayerAddress: PublicKey,
lamportsPerSignature: UInt64,
relayAccountStatus: RelayAccountStatus,
usageStatus: UsageStatus
) {
self.minimumTokenAccountBalance = minimumTokenAccountBalance
self.minimumRelayAccountBalance = minimumRelayAccountBalance
self.feePayerAddress = feePayerAddress
self.lamportsPerSignature = lamportsPerSignature
Expand All @@ -26,7 +23,6 @@ public struct RelayContext: Hashable, Codable {
}

public func hash(into hasher: inout Hasher) {
hasher.combine(minimumTokenAccountBalance)
hasher.combine(minimumRelayAccountBalance)
hasher.combine(feePayerAddress)
hasher.combine(lamportsPerSignature)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,12 @@ public class RelayContextManagerImpl: RelayContextManager {

// retrieve RelayContext
let (
minimumTokenAccountBalance,
minimumRelayAccountBalance,
lamportsPerSignature,
feePayerAddress,
relayAccountStatus,
usageStatus
) = try await(
solanaAPIClient.getMinimumBalanceForRentExemption(span: 165),
solanaAPIClient.getMinimumBalanceForRentExemption(span: 0),
solanaAPIClient.getFees(commitment: nil).feeCalculator?.lamportsPerSignature ?? 0,
feeRelayerAPIClient.getFeePayerPubkey(),
Expand All @@ -77,7 +75,6 @@ public class RelayContextManagerImpl: RelayContextManager {
)

return try RelayContext(
minimumTokenAccountBalance: minimumTokenAccountBalance,
minimumRelayAccountBalance: minimumRelayAccountBalance,
feePayerAddress: PublicKey(string: feePayerAddress),
lamportsPerSignature: lamportsPerSignature,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class DestinationAnalysatorImpl: DestinationAnalysator {
// Check destination address is exist.
let info: BufferInfo<SPLTokenAccountState>? = try? await solanaAPIClient
.getAccountInfo(account: address.base58EncodedString)
let needsCreateDestinationTokenAccount = info?.owner != TokenProgram.id.base58EncodedString
let needsCreateDestinationTokenAccount = !PublicKey.isSPLTokenOrToken2022ProgramId(info?.owner)

return .splAccount(needsCreation: needsCreateDestinationTokenAccount)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public class TransitTokenAccountManagerImpl: TransitTokenAccountManager {

return TokenAccount(
address: transitTokenAccountAddress,
mint: transitTokenMintPubkey
mint: transitTokenMintPubkey,
minimumTokenAccountBalance: getTransitTokenMintRentExemption(pools: pools) ?? 2_039_280
)
}

Expand All @@ -39,6 +40,11 @@ public class TransitTokenAccountManagerImpl: TransitTokenAccountManager {
return try PublicKey(string: orcaSwap.getMint(tokenName: interTokenName))
}

func getTransitTokenMintRentExemption(pools: PoolsPair) -> UInt64? {
guard pools.count == 2 else { return nil }
return pools[0].tokenBMinimumBalanceForRentExemption
}

public func checkIfNeedsCreateTransitTokenAccount(transitToken: TokenAccount?) async throws -> Bool? {
guard let transitToken = transitToken else { return nil }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@ extension SwapTransactionBuilderImpl {
// For other token, get associated token address
let associatedAddress = try PublicKey.associatedTokenAddress(
walletAddress: owner.publicKey,
tokenMintAddress: destinationMint
tokenMintAddress: destinationMint,
tokenProgramId: TokenProgram.id
)

if needsCreation {
let instruction = try AssociatedTokenProgram.createAssociatedTokenAccountInstruction(
mint: destinationMint,
owner: owner.publicKey,
payer: feePayerAddress
payer: feePayerAddress,
tokenProgramId: TokenProgram.id
)

// SPECIAL CASE WHEN WE SWAP FROM SOL TO NON-CREATED SPL TOKEN, THEN WE NEEDS ADDITIONAL TRANSACTION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public class SwapTransactionBuilderImpl: SwapTransactionBuilder {
// assert userSource
let associatedToken = try PublicKey.associatedTokenAddress(
walletAddress: feePayerAddress,
tokenMintAddress: sourceTokenAccount.mint
tokenMintAddress: sourceTokenAccount.mint,
tokenProgramId: TokenProgram.id
)
guard output.userSource != associatedToken else { throw FeeRelayerError.wrongAddress }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class TopUpTransactionBuilderImpl: TopUpTransactionBuilder {
let feePayerAddress = context.feePayerAddress
let associatedTokenAddress = try PublicKey.associatedTokenAddress(
walletAddress: feePayerAddress,
tokenMintAddress: sourceTokenMintAddress
tokenMintAddress: sourceTokenMintAddress,
tokenProgramId: TokenProgram.id
) ?! FeeRelayerError.unknown
let network = solanaApiClient.endpoint.network

Expand Down Expand Up @@ -102,7 +103,7 @@ class TopUpTransactionBuilderImpl: TopUpTransactionBuilder {

switch swap.swapData {
case let swap as DirectSwapData:
expectedFee.accountBalances += context.minimumTokenAccountBalance
expectedFee.accountBalances += sourceToken.minimumTokenAccountBalance
// approve
if let userTransferAuthority = userTransferAuthority {
instructions.append(
Expand Down Expand Up @@ -154,7 +155,7 @@ class TopUpTransactionBuilderImpl: TopUpTransactionBuilder {
}

// Destination WSOL account funding
expectedFee.accountBalances += context.minimumTokenAccountBalance
expectedFee.accountBalances += sourceToken.minimumTokenAccountBalance

// top up
try instructions.append(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,30 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {
]
)

let splToken2022AccountChange = solanaWebSocketMethod.programSubscribe(
program: Token2022Program.id.base58EncodedString,
commitment: "confirmed",
encoding: "base64",
filters: [
[
"dataSize": 165,
],
[
"memcmp": [
"offset": 32,
"bytes": owner,
] as [String: Any],
],
]
)

let nativeAccountChangeRequest = try JSONSerialization.data(withJSONObject: nativeAccountChange)
let splAccountChangeRequest = try JSONSerialization.data(withJSONObject: splAccountChange)
let splToken2022AccountChangeRequest = try JSONSerialization.data(withJSONObject: splToken2022AccountChange)

ws.send(nativeAccountChangeRequest.bytes)
ws.send(splAccountChangeRequest.bytes)
ws.send(splToken2022AccountChangeRequest.bytes)

return nil
} catch {
Expand All @@ -267,6 +286,7 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {
apiClient.getBalance(account: owner, commitment: "confirmed"),
apiClient.getAccountBalances(
for: owner,
withToken2022: true,
tokensRepository: tokensService,
commitment: "confirmed"
)
Expand All @@ -277,7 +297,9 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {
let solanaAccount = try SolanaAccount(
address: owner,
lamports: balance,
token: await tokensService.nativeToken
token: await tokensService.nativeToken,
minRentExemption: nil,
tokenProgramId: nil
)

let accounts = [solanaAccount] + resolved
Expand All @@ -289,7 +311,9 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {
return SolanaAccount(
address: pubKey,
lamports: accountBalance.lamports ?? 0,
token: accountBalance.token
token: accountBalance.token,
minRentExemption: accountBalance.minimumBalanceForRentExemption,
tokenProgramId: accountBalance.tokenProgramId
)
}
.compactMap { $0 }
Expand Down Expand Up @@ -328,10 +352,13 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {

// TODO: Add case when token info is invalid
if let token {
let minRentExempt = value.account.lamports
let splAccount = SolanaAccount(
address: pubKey,
lamports: tokenAccountData.lamports,
token: token
token: token,
minRentExemption: minRentExempt,
tokenProgramId: value.account.owner
)
accountsSubject.send(splAccount)
}
Expand All @@ -347,7 +374,9 @@ final class RealtimeSolanaAccountServiceImpl: RealtimeSolanaAccountService {
let nativeSolanaAccount = try SolanaAccount(
address: owner,
lamports: notification.result.value.lamports,
token: await tokensService.nativeToken
token: await tokensService.nativeToken,
minRentExemption: nil,
tokenProgramId: nil
)
accountsSubject.send(nativeSolanaAccount)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class SolanaAccountAsyncValue: AsyncValue<[SolanaAccount]> {
solanaAPIClient.getBalance(account: accountAddress, commitment: "confirmed"),
solanaAPIClient.getAccountBalances(
for: accountAddress,
withToken2022: true,
tokensRepository: tokensService,
commitment: "confirmed"
)
Expand All @@ -271,7 +272,9 @@ class SolanaAccountAsyncValue: AsyncValue<[SolanaAccount]> {
let solanaAccount = try SolanaAccount(
address: accountAddress,
lamports: balance,
token: await tokensService.nativeToken
token: await tokensService.nativeToken,
minRentExemption: nil,
tokenProgramId: nil
)

newAccounts = [solanaAccount] + resolved
Expand All @@ -283,7 +286,9 @@ class SolanaAccountAsyncValue: AsyncValue<[SolanaAccount]> {
return SolanaAccount(
address: pubkey,
lamports: accountBalance.lamports ?? 0,
token: accountBalance.token
token: accountBalance.token,
minRentExemption: accountBalance.minimumBalanceForRentExemption,
tokenProgramId: accountBalance.tokenProgramId
)
}
.compactMap { $0 }
Expand Down
Loading
Loading