diff --git a/Packages/KeyAppKit/Sources/FeeRelayerSwift/Helpers/SolanaAPIClient+FeeRelayer.swift b/Packages/KeyAppKit/Sources/FeeRelayerSwift/Helpers/SolanaAPIClient+FeeRelayer.swift index ea21374058..25ee570bb8 100644 --- a/Packages/KeyAppKit/Sources/FeeRelayerSwift/Helpers/SolanaAPIClient+FeeRelayer.swift +++ b/Packages/KeyAppKit/Sources/FeeRelayerSwift/Helpers/SolanaAPIClient+FeeRelayer.swift @@ -11,7 +11,7 @@ extension SolanaAPIClient { /// Retrieves associated SPL Token address for ``address``. /// /// - Returns: The associated address. - internal func getAssociatedSPLTokenAddress(for address: PublicKey, mint: PublicKey) async throws -> PublicKey { + func getAssociatedSPLTokenAddress(for address: PublicKey, mint: PublicKey) async throws -> PublicKey { let account: BufferInfo? = try? await getAccountInfo(account: address.base58EncodedString) // The account doesn't exists @@ -31,7 +31,7 @@ extension SolanaAPIClient { return try PublicKey.associatedTokenAddress(walletAddress: address, tokenMintAddress: mint) } - internal func isAccountExists(_ address: PublicKey) async throws -> Bool { + func isAccountExists(_ address: PublicKey) async throws -> Bool { let account: BufferInfo? = try await getAccountInfo(account: address.base58EncodedString) return account != nil } diff --git a/Packages/KeyAppKit/Sources/FeeRelayerSwift/Relay/Context/RelayContextManagerImpl.swift b/Packages/KeyAppKit/Sources/FeeRelayerSwift/Relay/Context/RelayContextManagerImpl.swift index 1bb64d9173..455f30445a 100644 --- a/Packages/KeyAppKit/Sources/FeeRelayerSwift/Relay/Context/RelayContextManagerImpl.swift +++ b/Packages/KeyAppKit/Sources/FeeRelayerSwift/Relay/Context/RelayContextManagerImpl.swift @@ -102,7 +102,7 @@ public class RelayContextManagerImpl: RelayContextManager { } } -internal extension FeeLimitForAuthorityResponse { +extension FeeLimitForAuthorityResponse { func asUsageStatus() -> UsageStatus { UsageStatus( maxUsage: limits.maxFeeCount, diff --git a/Packages/KeyAppKit/Sources/History/KeyAppHistoryProvider.swift b/Packages/KeyAppKit/Sources/History/KeyAppHistoryProvider.swift index 84bb225197..97d6436da6 100644 --- a/Packages/KeyAppKit/Sources/History/KeyAppHistoryProvider.swift +++ b/Packages/KeyAppKit/Sources/History/KeyAppHistoryProvider.swift @@ -64,7 +64,7 @@ public class KeyAppHistoryProviderImpl: KeyAppHistoryProvider { } } -internal struct TransactionsRequestParams: Codable { +struct TransactionsRequestParams: Codable { var pubKey: String var limit: UInt64 var offset: UInt64 diff --git a/Packages/KeyAppKit/Sources/JSBridge/JSBContext.swift b/Packages/KeyAppKit/Sources/JSBridge/JSBContext.swift index ce2d8304f5..a5320f5d98 100644 --- a/Packages/KeyAppKit/Sources/JSBridge/JSBContext.swift +++ b/Packages/KeyAppKit/Sources/JSBridge/JSBContext.swift @@ -6,18 +6,18 @@ public class JSBContext: NSObject { /// An id that indicates current unused local variable. /// /// The local variable will be used for temporary or permanent js data storage. - internal var variableId: Int = 0 + var variableId: Int = 0 /// A dispatch table for callback from async js functions. - internal var promiseDispatchTable: PromiseDispatchTable = .init() + var promiseDispatchTable: PromiseDispatchTable = .init() - internal let wkWebView: WKWebView + let wkWebView: WKWebView /// A local variable prefix. private static let kJsbValueName = "__localBridgeVariable" /// A WKWebview channel for returning values from JS `Promise`. - internal static let kPromiseCallback = "promiseCallback" + static let kPromiseCallback = "promiseCallback" public init(wkWebView: WKWebView? = nil) { self.wkWebView = wkWebView ?? WKWebView() diff --git a/Packages/KeyAppKit/Sources/JSBridge/JSBValue.swift b/Packages/KeyAppKit/Sources/JSBridge/JSBValue.swift index bea72748b8..ba28f5a090 100644 --- a/Packages/KeyAppKit/Sources/JSBridge/JSBValue.swift +++ b/Packages/KeyAppKit/Sources/JSBridge/JSBValue.swift @@ -15,7 +15,7 @@ public class JSBValue: JSBridge, CustomStringConvertible { currentContext = context } - internal init(name: String) { + init(name: String) { // Set variable name self.name = name } @@ -114,13 +114,13 @@ public class JSBValue: JSBridge, CustomStringConvertible { } /// Parse swift args to js args. - internal func parseArgs(_ args: [CustomStringConvertible]) throws -> String { + func parseArgs(_ args: [CustomStringConvertible]) throws -> String { try args .map(parse) .joined(separator: ", ") } - internal func parse(_ arg: CustomStringConvertible) throws -> String { + func parse(_ arg: CustomStringConvertible) throws -> String { if let arg = arg as? String { return "\"\(arg.safe)\"" } @@ -187,7 +187,7 @@ public class JSBValue: JSBridge, CustomStringConvertible { } } -internal extension String { +extension String { /// Make string be safed in js var safe: String { replacingOccurrences(of: "\"", with: "\\\"") diff --git a/Packages/KeyAppKit/Sources/Jupiter/JupiterRestClientAPI.swift b/Packages/KeyAppKit/Sources/Jupiter/JupiterRestClientAPI.swift index f16074685f..3f9dbf9675 100644 --- a/Packages/KeyAppKit/Sources/Jupiter/JupiterRestClientAPI.swift +++ b/Packages/KeyAppKit/Sources/Jupiter/JupiterRestClientAPI.swift @@ -11,7 +11,7 @@ public class JupiterRestClientAPI: JupiterAPI { } public func getTokens() async throws -> [TokenMetadata] { - let (data, _) = try await URLSession.shared.data(from: URL(string: "\(tokensHost ?? host)/tokens")!) + let (data, _) = try await URLSession.shared.data(from: URL(string: "\(tokensHost ?? "\(host)/tokens")")!) return try JSONDecoder().decode([TokenMetadata].self, from: data) } diff --git a/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumAccountsService.swift b/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumAccountsService.swift index 338c9543a1..90d1700fa6 100644 --- a/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumAccountsService.swift +++ b/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumAccountsService.swift @@ -98,7 +98,7 @@ public final class EthereumAccountsService: NSObject, AccountsService { try await accounts.fetch()?.value } - internal func fetchPrice( + func fetchPrice( state: AsyncValueState<[EthereumAccount]>, fiat: String ) -> Future, Never> { @@ -153,7 +153,7 @@ public final class EthereumAccountsService: NSObject, AccountsService { } } -internal class EthereumAccountAsyncValue: AsyncValue<[EthereumAccount]> { +class EthereumAccountAsyncValue: AsyncValue<[EthereumAccount]> { enum Error: Swift.Error { case invalidEthereumAddress } @@ -208,7 +208,7 @@ internal class EthereumAccountAsyncValue: AsyncValue<[EthereumAccount]> { } /// Method resolve ethereum erc-20 token accounts. - internal static func resolveTokenAccounts( + static func resolveTokenAccounts( address: String, balances: [EthereumTokenBalances.Balance], repository: EthereumTokensRepository diff --git a/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumTokenService.swift b/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumTokenService.swift index 91e20251cf..4cdde5c570 100644 --- a/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumTokenService.swift +++ b/Packages/KeyAppKit/Sources/KeyAppBusiness/Ethereum/EthereumTokenService.swift @@ -131,7 +131,7 @@ public final class EthereumTokensRepository { try await resolve(addresses: [address]).values.first } - internal func parseToken(tokenData: KeyAppTokenProviderData.Token) throws -> EthereumToken { + func parseToken(tokenData: KeyAppTokenProviderData.Token) throws -> EthereumToken { // Logo let logo: URL? if let logoUrl = tokenData.logoUrl { diff --git a/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceRule.swift b/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceRule.swift index e687628a5d..ed04e631a6 100644 --- a/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceRule.swift +++ b/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceRule.swift @@ -2,17 +2,17 @@ import BigDecimal import Foundation import KeyAppKitCore -internal enum PriceRuleHandler { +enum PriceRuleHandler { case `continue`(TokenPrice?) case `break`(TokenPrice?) } -internal protocol PriceRule { +protocol PriceRule { func adjustValue(token: SomeToken, price: TokenPrice, fiat: String) -> PriceRuleHandler } // Make price rate equals 1:1 when `ruleOfProcessingTokenPrice` equals `byCountOfTokensValue`. -internal class OneToOnePriceRule: PriceRule { +class OneToOnePriceRule: PriceRule { func adjustValue(token: SomeToken, price: TokenPrice, fiat _: String) -> PriceRuleHandler { if token.keyAppExtension.ruleOfProcessingTokenPriceWS == .byCountOfTokensValue { return .continue(TokenPrice(currencyCode: price.currencyCode, value: 1.0, token: token)) @@ -23,7 +23,7 @@ internal class OneToOnePriceRule: PriceRule { } // Depegging price by measure percentage difference. -internal class DepeggingPriceRule: PriceRule { +class DepeggingPriceRule: PriceRule { func adjustValue(token: SomeToken, price: TokenPrice, fiat _: String) -> PriceRuleHandler { if let allowPercentageDifferenceValue = token.keyAppExtension.percentDifferenceToShowByPriceOnWS { let percentageDifferenceValue = 100 - (1 / price.value) * 100 diff --git a/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceService.swift b/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceService.swift index f8a8eadd1d..6c4457a31b 100644 --- a/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceService.swift +++ b/Packages/KeyAppKit/Sources/KeyAppBusiness/Price/PriceService.swift @@ -177,7 +177,7 @@ public class PriceServiceImpl: PriceService { } /// Method for fetching price from server - internal func fetchTokenPrice(tokens: [AnyToken], fiat: String) async throws -> [SomeToken: TokenPrice] { + func fetchTokenPrice(tokens: [AnyToken], fiat: String) async throws -> [SomeToken: TokenPrice] { var result: [SomeToken: TokenPrice] = [:] // Request token price @@ -261,7 +261,7 @@ public class PriceServiceImpl: PriceService { } } -internal extension AnyToken { +extension AnyToken { /// Map token to requested primary key in backend. var addressPriceMapping: String { switch network { diff --git a/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaAccountsService.swift b/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaAccountsService.swift index 0162b07dbd..4e525ecd89 100644 --- a/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaAccountsService.swift +++ b/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaAccountsService.swift @@ -151,7 +151,7 @@ public final class SolanaAccountsService: NSObject, AccountsService { try await fetchedAccountsByRpc.fetch()?.value } - internal func fetchPrice( + func fetchPrice( for state: AsyncValueState<[Account]>, fiat: String ) -> Future, Never> { @@ -193,7 +193,7 @@ public final class SolanaAccountsService: NSObject, AccountsService { } /// Update single accounts. - internal func onUpdateAccount(account: SolanaAccount) { + func onUpdateAccount(account: SolanaAccount) { var state = accountsStream.value let matchIdx = state.value @@ -238,7 +238,7 @@ public extension SolanaAccountsService { } } -internal class SolanaAccountAsyncValue: AsyncValue<[SolanaAccount]> { +class SolanaAccountAsyncValue: AsyncValue<[SolanaAccount]> { enum Error: Swift.Error { case authorityError } diff --git a/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaTokenService.swift b/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaTokenService.swift index 8b353f0363..c4126d640b 100644 --- a/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaTokenService.swift +++ b/Packages/KeyAppKit/Sources/KeyAppBusiness/Solana/SolanaTokenService.swift @@ -7,13 +7,13 @@ public typealias SolanaTokensService = TokenRepository public actor KeyAppSolanaTokenRepository: TokenRepository { static let version: Int = 1 - internal struct Database: Codable, Hashable { + struct Database: Codable, Hashable { var timestamps: Date? var data: [String: SolanaToken] var version: Int? } - internal enum Status: Int { + enum Status: Int { case initialising = 0 case updating case ready @@ -200,7 +200,7 @@ private extension TokenMetadata { // fix the mint return SolanaToken( - _tags: [], + tags: tags.map(\.name), chainId: chainId, mintAddress: "So11111111111111111111111111111111111111112", symbol: symbol, diff --git a/Packages/KeyAppKit/Sources/KeyAppKitCore/Blockchain/Ethereum/EthereumKeyPair.swift b/Packages/KeyAppKit/Sources/KeyAppKitCore/Blockchain/Ethereum/EthereumKeyPair.swift index 89a1fb5874..57fd217ded 100644 --- a/Packages/KeyAppKit/Sources/KeyAppKitCore/Blockchain/Ethereum/EthereumKeyPair.swift +++ b/Packages/KeyAppKit/Sources/KeyAppKitCore/Blockchain/Ethereum/EthereumKeyPair.swift @@ -10,7 +10,7 @@ public struct EthereumKeyPair: Equatable, Hashable { } /// Protected area data. - internal let privateKey: EthereumPrivateKey + let privateKey: EthereumPrivateKey /// Ethereum public key public var publicKey: String { diff --git a/Packages/KeyAppKit/Sources/Onboarding/API/TKeyFacade/TKeyJSFacade.swift b/Packages/KeyAppKit/Sources/Onboarding/API/TKeyFacade/TKeyJSFacade.swift index 3e890f0319..eded4b3c74 100644 --- a/Packages/KeyAppKit/Sources/Onboarding/API/TKeyFacade/TKeyJSFacade.swift +++ b/Packages/KeyAppKit/Sources/Onboarding/API/TKeyFacade/TKeyJSFacade.swift @@ -371,7 +371,7 @@ public actor TKeyJSFacade: TKeyFacade { return RefreshDeviceShareResult(share: deviceShare) } - internal func parseFacadeJSError(error: Any) -> TKeyFacadeError? { + func parseFacadeJSError(error: Any) -> TKeyFacadeError? { guard let errorStr = error as? String, let error = errorStr.data(using: .utf8) diff --git a/Packages/KeyAppKit/Sources/Onboarding/Common/Crypto.swift b/Packages/KeyAppKit/Sources/Onboarding/Common/Crypto.swift index f47d34c46d..378e355001 100644 --- a/Packages/KeyAppKit/Sources/Onboarding/Common/Crypto.swift +++ b/Packages/KeyAppKit/Sources/Onboarding/Common/Crypto.swift @@ -7,8 +7,8 @@ enum CryptoError: Error { case invalidMac } -internal enum Crypto { - internal struct EncryptedMetadata: Codable { +enum Crypto { + struct EncryptedMetadata: Codable { let nonce: String let metadataCiphered: String @@ -18,7 +18,7 @@ internal enum Crypto { } } - internal static func extractSymmetricKey(seedPhrase: String) throws -> Data { + static func extractSymmetricKey(seedPhrase: String) throws -> Data { try extractOnboardingSeedPhrase(phrase: seedPhrase, path: "m/44'/101'/0'/0'") } diff --git a/Packages/KeyAppKit/Sources/Onboarding/Common/Mnemonic.swift b/Packages/KeyAppKit/Sources/Onboarding/Common/Mnemonic.swift index e188520bba..e15cfa602e 100644 --- a/Packages/KeyAppKit/Sources/Onboarding/Common/Mnemonic.swift +++ b/Packages/KeyAppKit/Sources/Onboarding/Common/Mnemonic.swift @@ -2,7 +2,7 @@ import Foundation import SolanaSwift import TweetNacl -internal func extractOnboardingSeedPhrase(phrase: String, path: String) throws -> Data { +func extractOnboardingSeedPhrase(phrase: String, path: String) throws -> Data { let mnemonic = try Mnemonic(phrase: phrase.components(separatedBy: " ")) let secretKey = try Ed25519HDKey.derivePath(path, seed: mnemonic.seed.toHexString()).get().key let keyPair = try NaclSign.KeyPair.keyPair(fromSeed: secretKey) diff --git a/Packages/KeyAppKit/Sources/Onboarding/Service/CreateWalletFlow/CreateWalletState/SocialSignInState.swift b/Packages/KeyAppKit/Sources/Onboarding/Service/CreateWalletFlow/CreateWalletState/SocialSignInState.swift index ad3556b610..9fa0f6ae76 100644 --- a/Packages/KeyAppKit/Sources/Onboarding/Service/CreateWalletFlow/CreateWalletState/SocialSignInState.swift +++ b/Packages/KeyAppKit/Sources/Onboarding/Service/CreateWalletFlow/CreateWalletState/SocialSignInState.swift @@ -63,7 +63,7 @@ public enum SocialSignInState: Codable, State, Equatable { } } - internal func socialSelectionEventHandler( + func socialSelectionEventHandler( currentState _: Self, event: Event, provider: Provider ) async throws -> Self { @@ -78,7 +78,7 @@ public enum SocialSignInState: Codable, State, Equatable { } } - internal func socialSignInProgressEventHandler(event: Event, provider: Provider) async throws -> Self { + func socialSignInProgressEventHandler(event: Event, provider: Provider) async throws -> Self { switch event { case let .signInTorus(value, email, socialProvider): let tokenID = TokenID(value: value, provider: socialProvider.rawValue) @@ -118,7 +118,7 @@ public enum SocialSignInState: Codable, State, Equatable { } } - internal func socialTryAgainEventHandler( + func socialTryAgainEventHandler( currentState _: Self, event: Event, provider: Provider ) async throws -> Self { @@ -161,7 +161,7 @@ public enum SocialSignInState: Codable, State, Equatable { } } - internal func socialSignInAccountWasUsedHandler( + func socialSignInAccountWasUsedHandler( currentState: Self, event: Event, provider: Provider ) async throws -> Self { diff --git a/Packages/KeyAppKit/Sources/Onboarding/Service/RestoreWalletFlow/RestoreICloud/ICloudAccount.swift b/Packages/KeyAppKit/Sources/Onboarding/Service/RestoreWalletFlow/RestoreICloud/ICloudAccount.swift index 1517a9554a..a7ae5a4511 100644 --- a/Packages/KeyAppKit/Sources/Onboarding/Service/RestoreWalletFlow/RestoreICloud/ICloudAccount.swift +++ b/Packages/KeyAppKit/Sources/Onboarding/Service/RestoreWalletFlow/RestoreICloud/ICloudAccount.swift @@ -3,7 +3,7 @@ import SolanaSwift public struct ICloudAccount: Codable, Hashable { public let name: String? - internal let phrase: String + let phrase: String public let derivablePath: DerivablePath public let publicKey: String diff --git a/Packages/KeyAppKit/Sources/Send/Input/SendInputBusinessLogic.swift b/Packages/KeyAppKit/Sources/Send/Input/SendInputBusinessLogic.swift index 0e8a407a86..56041888ca 100644 --- a/Packages/KeyAppKit/Sources/Send/Input/SendInputBusinessLogic.swift +++ b/Packages/KeyAppKit/Sources/Send/Input/SendInputBusinessLogic.swift @@ -2,7 +2,7 @@ import FeeRelayerSwift import Foundation import SolanaSwift -struct SendInputBusinessLogic { +enum SendInputBusinessLogic { static func sendInputBusinessLogic( state: SendInputState, action: SendInputAction, diff --git a/Packages/KeyAppKit/Sources/Send/RecipientSearch/RecipientSearchServiceImpl/RecipientSearchServiceImpl+searchBySolanaAddress.swift b/Packages/KeyAppKit/Sources/Send/RecipientSearch/RecipientSearchServiceImpl/RecipientSearchServiceImpl+searchBySolanaAddress.swift index 31748ab7c3..5e76405dae 100644 --- a/Packages/KeyAppKit/Sources/Send/RecipientSearch/RecipientSearchServiceImpl/RecipientSearchServiceImpl+searchBySolanaAddress.swift +++ b/Packages/KeyAppKit/Sources/Send/RecipientSearch/RecipientSearchServiceImpl/RecipientSearchServiceImpl+searchBySolanaAddress.swift @@ -54,7 +54,13 @@ extension RecipientSearchServiceImpl { // detect token let token = config .tokens[accountInfo.mint.base58EncodedString] ?? - .unsupported(mint: accountInfo.mint.base58EncodedString, decimals: 1, symbol: "", supply: nil) + .unsupported( + tags: nil, + mint: accountInfo.mint.base58EncodedString, + decimals: 1, + symbol: "", + supply: nil + ) // detect category let category = try Recipient.Category.solanaTokenAddress( diff --git a/Packages/KeyAppKit/Sources/Send/UsernameUtils.swift b/Packages/KeyAppKit/Sources/Send/UsernameUtils.swift index c4a94d51ab..68ecd8c87e 100644 --- a/Packages/KeyAppKit/Sources/Send/UsernameUtils.swift +++ b/Packages/KeyAppKit/Sources/Send/UsernameUtils.swift @@ -1,6 +1,6 @@ import Foundation -struct UsernameUtils { +enum UsernameUtils { static func splitIntoNameAndDomain(rawName: String) -> (name: String, domain: String) { var name = "" var domain = "" diff --git a/Packages/KeyAppKit/Sources/Wormhole/Model/TokenAmount.swift b/Packages/KeyAppKit/Sources/Wormhole/Model/TokenAmount.swift index 0a73e65daf..70d28a8038 100644 --- a/Packages/KeyAppKit/Sources/Wormhole/Model/TokenAmount.swift +++ b/Packages/KeyAppKit/Sources/Wormhole/Model/TokenAmount.swift @@ -97,7 +97,7 @@ extension TokenAmount: CryptoAmountConvertible { if let mint { token = SolanaToken( - _tags: nil, + tags: nil, chainId: 0, mintAddress: mint, symbol: symbol, diff --git a/Packages/KeyAppKit/Sources/Wormhole/SupportedToken.swift b/Packages/KeyAppKit/Sources/Wormhole/SupportedToken.swift index 10a4801435..7950979630 100644 --- a/Packages/KeyAppKit/Sources/Wormhole/SupportedToken.swift +++ b/Packages/KeyAppKit/Sources/Wormhole/SupportedToken.swift @@ -3,7 +3,7 @@ import KeyAppKitCore public enum SupportedToken { public static let usdt: SolanaToken = .init( - _tags: nil, + tags: nil, chainId: 101, mintAddress: "Dn4noZ5jgGfkntzcQSUZ8czkreiZ1ForXYoV2H8Dm7S1", symbol: "USDTet", diff --git a/Packages/KeyAppKit/Tests/FeeRelayerSwiftUnitTests/APIClient/ErrorTests/Helpers/ClientError.swift b/Packages/KeyAppKit/Tests/FeeRelayerSwiftUnitTests/APIClient/ErrorTests/Helpers/ClientError.swift index 497d008efc..3f8066f0e4 100644 --- a/Packages/KeyAppKit/Tests/FeeRelayerSwiftUnitTests/APIClient/ErrorTests/Helpers/ClientError.swift +++ b/Packages/KeyAppKit/Tests/FeeRelayerSwiftUnitTests/APIClient/ErrorTests/Helpers/ClientError.swift @@ -1,6 +1,6 @@ import Foundation -struct ClientError { +enum ClientError { static var insufficientFunds: String { #"{"code":6,"data":{"ClientError":["RpcError: RpcResponseError {\n code: -32002,\n message: \"Transaction simulation failed: Error processing Instruction 3: custom program error: 0x1\",\n data: SendTransactionPreflightFailure(\n RpcSimulateTransactionResult {\n err: Some(\n InstructionError(\n 3,\n Custom(\n 1,\n ),\n ),\n ),\n logs: Some(\n [\n \"Program 11111111111111111111111111111111 invoke [1]\",\n \"Program 11111111111111111111111111111111 success\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [1]\",\n \"Program log: Instruction: InitializeAccount\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3392 of 200000 compute units\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success\",\n \"Program 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9 invoke [1]\",\n \"Program log: Process instruction. Program id: 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9, 7 accounts, data: [3]\",\n \"Program log: Instruction: CreateTransitTokenAccount\",\n \"Program log: Invoke create transit token account\",\n \"Program 11111111111111111111111111111111 invoke [2]\",\n \"Program 11111111111111111111111111111111 success\",\n \"Program 11111111111111111111111111111111 invoke [2]\",\n \"Program 11111111111111111111111111111111 success\",\n \"Program 11111111111111111111111111111111 invoke [2]\",\n \"Program 11111111111111111111111111111111 success\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]\",\n \"Program log: Instruction: InitializeAccount\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3272 of 171619 compute units\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success\",\n \"Program 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9 consumed 32387 of 200000 compute units\",\n \"Program 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9 success\",\n \"Program 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9 invoke [1]\",\n \"Program log: Process instruction. Program id: 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9, 20 accounts, data: [4, 160, 134, 1, 0, 0, 0, 0, 0, 83, 148, 12, 0, 0, 0, 0, 0, 70, 86, 10, 0, 0, 0, 0, 0]\",\n \"Program log: Instruction: SplSwapTransitive { amount_in: 100000, transit_minimum_amount: 824403, minimum_amount_out: 677446 }\",\n \"Program log: Invoke SPL swap to transit\",\n \"Program 9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP invoke [2]\",\n \"Program log: Instruction: Swap\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]\",\n \"Program log: Instruction: Transfer\",\n \"Program log: Error: insufficient funds\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2135 of 150701 compute units\",\n \"Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA failed: custom program error: 0x1\",\n \"Program 9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP consumed 20050 of 168616 compute units\",\n \"Program 9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP failed: custom program error: 0x1\",\n \"Program 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9 consumed 51434 of 200000 compute units\",\n \"Program 12YKFL4mnZz6CBEGePrf293mEzueQM3h8VLPUJsKpGs9 failed: custom program error: 0x1\",\n ],\n ),\n accounts: None,\n },\n ),\n}"]},"message":"Solana RPC client error: RPC response error -32002: Transaction simulation failed: Error processing Instruction 3: custom program error: 0x1 [37 log messages]"}"# } diff --git a/p2p_wallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/p2p_wallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d09005c6e7..0464bb5191 100644 --- a/p2p_wallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/p2p_wallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -162,15 +162,6 @@ "version" : "1.3.1" } }, - { - "identity" : "intercom-ios-sp", - "kind" : "remoteSourceControl", - "location" : "https://github.com/intercom/intercom-ios-sp", - "state" : { - "revision" : "1031655ceb49a8c8975b0cb138fe3bed897d159e", - "version" : "15.0.3" - } - }, { "identity" : "jazziconswift", "kind" : "remoteSourceControl", @@ -194,8 +185,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/onevcat/Kingfisher.git", "state" : { - "revision" : "c75584ac759cbb16b204d0a7de3ebf53ea6b304d", - "version" : "7.9.0" + "revision" : "add0a87ec4e31e2ca2a0b2085f0559201e4f5918", + "version" : "7.10.1" } }, { @@ -239,8 +230,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/marmelroy/PhoneNumberKit.git", "state" : { - "revision" : "b6c141f4a97dde7cd3ea335a5d6d679faa7675f6", - "version" : "3.6.7" + "revision" : "d2886b0735a47e47fb227504666756efb2e2ac26", + "version" : "3.7.6" } }, { @@ -321,7 +312,7 @@ "location" : "https://github.com/p2p-org/solana-swift", "state" : { "branch" : "main", - "revision" : "5d186612724dd806eb5293e565ef8dab43d24d39" + "revision" : "0751755b18d162f534b3e96eb09de37c51e444a0" } }, { @@ -401,8 +392,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "dc46eeb3928a75390651fac6c1ef7f93ad59a73b", - "version" : "1.11.1" + "revision" : "59b663f68e69f27a87b45de48cb63264b8194605", + "version" : "1.15.1" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", + "version" : "509.0.2" } }, { diff --git a/p2p_wallet/AppDelegate/AppDelegate.swift b/p2p_wallet/AppDelegate/AppDelegate.swift index 2889a0401b..b02cc5888d 100644 --- a/p2p_wallet/AppDelegate/AppDelegate.swift +++ b/p2p_wallet/AppDelegate/AppDelegate.swift @@ -27,7 +27,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Defaults.fiat = .usd UserDefaults.standard.set(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable") - IntercomStartingConfigurator().configure() setupNavigationAppearance() diff --git a/p2p_wallet/AppDelegate/AppDelegateProxyService/AppDelegateProxyService.swift b/p2p_wallet/AppDelegate/AppDelegateProxyService/AppDelegateProxyService.swift index d52fd05747..7d7126ff9d 100644 --- a/p2p_wallet/AppDelegate/AppDelegateProxyService/AppDelegateProxyService.swift +++ b/p2p_wallet/AppDelegate/AppDelegateProxyService/AppDelegateProxyService.swift @@ -9,7 +9,6 @@ final class AppDelegateProxyService: NSObject, UIApplicationDelegate { AppflyerAppDelegateService(), DeeplinkAppDelegateService(), HistoryAppdelegateService(), - IntercomAppDelegateService(), LokaliseAppDelegateService(), ] serviceAppDelegates = services.compactMap { $0 } diff --git a/p2p_wallet/AppDelegate/AppDelegateProxyService/DeeplinkAppDelegateService.swift b/p2p_wallet/AppDelegate/AppDelegateProxyService/DeeplinkAppDelegateService.swift index e31e50183d..f6fa47d197 100644 --- a/p2p_wallet/AppDelegate/AppDelegateProxyService/DeeplinkAppDelegateService.swift +++ b/p2p_wallet/AppDelegate/AppDelegateProxyService/DeeplinkAppDelegateService.swift @@ -61,23 +61,17 @@ final class DeeplinkAppDelegateService: NSObject, AppDelegateService { return } - // Intercom survey - // https://key.app/intercom?intercom_survey_id=133423424 - if urlComponents.host == "key.app", - urlComponents.path == "/intercom", - let queryItem = urlComponents.queryItems?.first(where: { $0.name == "intercom_survey_id" }), - let value = queryItem.value - { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - GlobalAppState.shared.surveyID = value - } - } - // Send via link // https://t.key.app/ - else if urlComponents.host == "t.key.app" { + if urlComponents.host == "t.key.app" { GlobalAppState.shared.sendViaLinkUrl = urlComponents.url } + + // Swap via link + // https://s.key.app/swap?inputMint=&outputMint= + if urlComponents.host == "s.key.app" { + GlobalAppState.shared.swapUrl = urlComponents.url + } } private func handleCustomURIScheme(urlComponents components: URLComponents) { @@ -123,6 +117,10 @@ final class DeeplinkAppDelegateService: NSObject, AppDelegateService { let seed = String(path.dropFirst()) GlobalAppState.shared.sendViaLinkUrl = urlFromSeed(seed) } + // keyapp://swap?inputMint=&outputMint= + else if scheme == "keyapp", host == "swap" { + GlobalAppState.shared.swapUrl = components.url + } } } diff --git a/p2p_wallet/AppDelegate/AppDelegateProxyService/IntercomAppDelegateService.swift b/p2p_wallet/AppDelegate/AppDelegateProxyService/IntercomAppDelegateService.swift deleted file mode 100644 index 4b1c25a282..0000000000 --- a/p2p_wallet/AppDelegate/AppDelegateProxyService/IntercomAppDelegateService.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation -import Intercom - -final class IntercomAppDelegateService: NSObject, AppDelegateService { - // MARK: - Methods - - func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { - Intercom.setDeviceToken(deviceToken) { error in - #if DEBUG - if let error { - print("Intercom.setDeviceToken error: ", error) - } - #endif - } - } - - func applicationWillResignActive(_: UIApplication) { - // Hide any presented intercom vc - Intercom.hide() - } -} diff --git a/p2p_wallet/Common/Extensions/Double+Extensions.swift b/p2p_wallet/Common/Extensions/Double+Extensions.swift index 0d4058ac9f..26c12f10b6 100644 --- a/p2p_wallet/Common/Extensions/Double+Extensions.swift +++ b/p2p_wallet/Common/Extensions/Double+Extensions.swift @@ -145,3 +145,18 @@ extension Double { "\(toString(maximumFractionDigits: maximumFractionDigits, roundingMode: roundingMode)) \(currency.code)" } } + +extension Double { + // Check if lamport value is smaller than UInt64 max + func isLamportsBiggerThanUInt64(decimals: Int) -> Bool { + let value = (self * Double.pow(10, Double(decimals))).rounded() + let maxValue = Decimal(UInt64.max) + + if Decimal(value) > maxValue { + debugPrint("\(value) overflows Int64 max \(maxValue)") + return true + } + + return false + } +} diff --git a/p2p_wallet/Common/Extensions/SolanaSDK+Extensions.swift b/p2p_wallet/Common/Extensions/SolanaSDK+Extensions.swift index d92c09fea7..1a2481dc1d 100644 --- a/p2p_wallet/Common/Extensions/SolanaSDK+Extensions.swift +++ b/p2p_wallet/Common/Extensions/SolanaSDK+Extensions.swift @@ -13,16 +13,19 @@ extension APIEndPoint { ) } var endpoints = remoteEndpoints.isEmpty ? defaultEndpoints : remoteEndpoints - if remoteEndpoints.isEmpty { - endpoints.insert( - .init(address: "https://p2p.rpcpool.com", network: .mainnetBeta, - additionalQuery: .secretConfig("RPCPOOL_API_KEY")), - at: 0 - ) - #if !DEBUG - endpoints.removeAll { $0.network == .testnet || $0.network == .devnet } - #endif - } +// if remoteEndpoints.isEmpty { + endpoints.insert( + .init( + address: "https://solana.keyapp.org", + network: .mainnetBeta, + additionalQuery: .secretConfig("KEYAPP_ORG_API_KEY") + ), + at: 0 + ) + #if !DEBUG + endpoints.removeAll { $0.network == .testnet || $0.network == .devnet } + #endif +// } return endpoints } } diff --git a/p2p_wallet/Common/Models/WormholeSupportedTokens.swift b/p2p_wallet/Common/Models/WormholeSupportedTokens.swift index be64809d1a..a39057b447 100644 --- a/p2p_wallet/Common/Models/WormholeSupportedTokens.swift +++ b/p2p_wallet/Common/Models/WormholeSupportedTokens.swift @@ -2,7 +2,7 @@ import Foundation import SolanaSwift import Wormhole -class WormholeSupportedTokens { +enum WormholeSupportedTokens { static var bridges: [SupportedToken.WormholeBridge] { SupportedToken.bridges.filter { bridge in bridge.solAddress == TokenMetadata.nativeSolana.mintAddress ? available(.solanaEthAddressEnabled) : true diff --git a/p2p_wallet/Common/Services/BackgroundWebViewManager.swift b/p2p_wallet/Common/Services/BackgroundWebViewManager.swift index ec693ce8ae..cdcb4c192b 100644 --- a/p2p_wallet/Common/Services/BackgroundWebViewManager.swift +++ b/p2p_wallet/Common/Services/BackgroundWebViewManager.swift @@ -2,7 +2,7 @@ import Foundation import WebKit /// The class is responsible for creating background web view. -class BackgroundWebViewManager { +enum BackgroundWebViewManager { static func requestWebView() -> WKWebView { HTTPCookieStorage.shared.removeCookies(since: Date.distantPast) WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in diff --git a/p2p_wallet/Common/Services/Buy/Buy.swift b/p2p_wallet/Common/Services/Buy/Buy.swift index 4d50acd190..45f6a588db 100644 --- a/p2p_wallet/Common/Services/Buy/Buy.swift +++ b/p2p_wallet/Common/Services/Buy/Buy.swift @@ -3,7 +3,7 @@ import Foundation import SolanaSwift import SwiftyUserDefaults -struct Buy { +enum Buy { typealias Currency = BuyCurrencyType enum FiatCurrency: String, BuyCurrencyType, Equatable { diff --git a/p2p_wallet/Common/Services/Buy/BuyProccessing/Utils.swift b/p2p_wallet/Common/Services/Buy/BuyProccessing/Utils.swift index dbbc5aa821..c8dd5bc73b 100644 --- a/p2p_wallet/Common/Services/Buy/BuyProccessing/Utils.swift +++ b/p2p_wallet/Common/Services/Buy/BuyProccessing/Utils.swift @@ -1,6 +1,6 @@ import Foundation -struct BuyProviderUtils { +enum BuyProviderUtils { typealias Params = [String: String?] } diff --git a/p2p_wallet/Common/Services/GlobalAppState.swift b/p2p_wallet/Common/Services/GlobalAppState.swift index 0f8f7fcd43..977bb45e56 100644 --- a/p2p_wallet/Common/Services/GlobalAppState.swift +++ b/p2p_wallet/Common/Services/GlobalAppState.swift @@ -41,6 +41,7 @@ class GlobalAppState: ObservableObject { // TODO: Refactor! @Published var surveyID: String? @Published var sendViaLinkUrl: URL? + @Published var swapUrl: URL? private init() { if let forcedValue = Defaults.forcedNameServiceEndpoint { diff --git a/p2p_wallet/Common/Services/Intercom/HelpCenterLauncher.swift b/p2p_wallet/Common/Services/Intercom/HelpCenterLauncher.swift deleted file mode 100644 index 76fb6449ac..0000000000 --- a/p2p_wallet/Common/Services/Intercom/HelpCenterLauncher.swift +++ /dev/null @@ -1,3 +0,0 @@ -protocol HelpCenterLauncher: AnyObject { - func launch() -} diff --git a/p2p_wallet/Common/Services/Intercom/IntercomMessengerLauncher.swift b/p2p_wallet/Common/Services/Intercom/IntercomMessengerLauncher.swift deleted file mode 100644 index fd1260ca64..0000000000 --- a/p2p_wallet/Common/Services/Intercom/IntercomMessengerLauncher.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Intercom -import Resolver - -final class IntercomMessengerLauncher: HelpCenterLauncher { - private let attributesService = IntercomUserAttributesService() - - func launch() { - attributesService.setParameters() - - Intercom.presentMessenger() - } -} diff --git a/p2p_wallet/Common/Services/Intercom/IntercomStartingConfigurator.swift b/p2p_wallet/Common/Services/Intercom/IntercomStartingConfigurator.swift deleted file mode 100644 index 9dfbd8597b..0000000000 --- a/p2p_wallet/Common/Services/Intercom/IntercomStartingConfigurator.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Intercom - -final class IntercomStartingConfigurator { - func configure() { - Intercom.setApiKey("ios_sdk-ea34dac95867378c8a568a970312d07a668822fc", forAppId: "imvolhpe") - Intercom.loginUnidentifiedUser() - } -} diff --git a/p2p_wallet/Common/Services/Intercom/IntercomUserAttributesService.swift b/p2p_wallet/Common/Services/Intercom/IntercomUserAttributesService.swift deleted file mode 100644 index e32a4772f1..0000000000 --- a/p2p_wallet/Common/Services/Intercom/IntercomUserAttributesService.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Intercom -import Resolver -import SolanaSwift - -final class IntercomUserAttributesService { - @Injected private var nameStorage: NameStorageType - @Injected private var accountStorage: SolanaAccountStorage - - func setParameters() { - let userAddress = accountStorage.account?.publicKey.base58EncodedString - let name = nameStorage.getName() - - let userAttributes = ICMUserAttributes() - userAttributes.name = name - if let userAddress = userAddress { - userAttributes.customAttributes = ["public_address": userAddress] - } - - Intercom.updateUser(with: userAttributes) - } -} diff --git a/p2p_wallet/Common/Services/SwiftNotificationCenter/SwiftNotificationCenter.swift b/p2p_wallet/Common/Services/SwiftNotificationCenter/SwiftNotificationCenter.swift index af66b773c5..9fd9a6a4d8 100644 --- a/p2p_wallet/Common/Services/SwiftNotificationCenter/SwiftNotificationCenter.swift +++ b/p2p_wallet/Common/Services/SwiftNotificationCenter/SwiftNotificationCenter.swift @@ -1,6 +1,6 @@ import Foundation -class Broadcaster { +enum Broadcaster { fileprivate static var observersDic = [String: Any]() fileprivate static let notificationQueue = DispatchQueue( diff --git a/p2p_wallet/Common/Services/WarmupService/MigrationWarmupProcess.swift b/p2p_wallet/Common/Services/WarmupService/MigrationWarmupProcess.swift new file mode 100644 index 0000000000..fb8946a2ea --- /dev/null +++ b/p2p_wallet/Common/Services/WarmupService/MigrationWarmupProcess.swift @@ -0,0 +1,20 @@ +import Foundation +import Resolver + +class MigrationWarmupProcess: WarmupProcess { + func start() async { + // Migrate to endpoint solana.keyapp.org + let migration1Key = "APIEndpoint.migrationKey1" + if !UserDefaults.standard.bool(forKey: migration1Key) { + Resolver.resolve(ChangeNetworkResponder.self) + .changeAPIEndpoint( + to: .init( + address: "https://solana.keyapp.org", + network: .mainnetBeta, + additionalQuery: .secretConfig("KEYAPP_ORG_API_KEY") + ) + ) + UserDefaults.standard.set(true, forKey: migration1Key) + } + } +} diff --git a/p2p_wallet/Info.plist b/p2p_wallet/Info.plist index 322de822a5..17d104cedb 100644 --- a/p2p_wallet/Info.plist +++ b/p2p_wallet/Info.plist @@ -177,6 +177,8 @@ $(TRANSAK_PRODUCTION_API_KEY) TRANSAK_STAGING_API_KEY $(TRANSAK_STAGING_API_KEY) + KEYAPP_ORG_API_KEY + $(KEYAPP_ORG_API_KEY) UIApplicationSupportsIndirectInputEvents UIBackgroundModes diff --git a/p2p_wallet/Injection/Resolver+registerAllServices.swift b/p2p_wallet/Injection/Resolver+registerAllServices.swift index c1166ccfd5..bfa6f86eba 100644 --- a/p2p_wallet/Injection/Resolver+registerAllServices.swift +++ b/p2p_wallet/Injection/Resolver+registerAllServices.swift @@ -42,6 +42,7 @@ extension Resolver: ResolverRegistering { WarmupManager(processes: [ RemoteConfigWarmupProcess(), TokenServiceWarmupProcess(), + MigrationWarmupProcess(), ]) }.scope(.application) @@ -226,10 +227,6 @@ extension Resolver: ResolverRegistering { /// Graph scope: Recreate and reuse dependencies @MainActor private static func registerForGraphScope() { - // Intercom - register { IntercomMessengerLauncher() } - .implements(HelpCenterLauncher.self) - // ImageSaver register { ImageSaver() } .implements(ImageSaverType.self) @@ -545,8 +542,9 @@ extension Resolver: ResolverRegistering { register { JupiterRestClientAPI( host: GlobalAppState.shared.newSwapEndpoint, - tokensHost: GlobalAppState.shared - .newSwapEndpoint == "https://quote-api.jup.ag" ? "https://cache.jup.ag" : nil, + tokensHost: "https://token.jup.ag/all", +// GlobalAppState.shared +// .newSwapEndpoint == "https://quote-api.jup.ag" ? "https://cache.jup.ag/tokens" : nil, version: .v4 ) } diff --git a/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Contents.json b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Contents.json new file mode 100644 index 0000000000..05e9b4fb78 --- /dev/null +++ b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Subtract.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Subtract@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Subtract@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract.png b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract.png new file mode 100644 index 0000000000..f8507c55f4 Binary files /dev/null and b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract.png differ diff --git a/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract@2x.png b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract@2x.png new file mode 100644 index 0000000000..b34c456497 Binary files /dev/null and b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract@2x.png differ diff --git a/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract@3x.png b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract@3x.png new file mode 100644 index 0000000000..4037789201 Binary files /dev/null and b/p2p_wallet/Resources/Assets.xcassets/info-gray-20.imageset/Subtract@3x.png differ diff --git a/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Contents.json b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Contents.json new file mode 100644 index 0000000000..a483619782 --- /dev/null +++ b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 1523446.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1523446@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1523446@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446.png b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446.png new file mode 100644 index 0000000000..550aa1c651 Binary files /dev/null and b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446.png differ diff --git a/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446@2x.png b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446@2x.png new file mode 100644 index 0000000000..386942d28d Binary files /dev/null and b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446@2x.png differ diff --git a/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446@3x.png b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446@3x.png new file mode 100644 index 0000000000..b480218bd9 Binary files /dev/null and b/p2p_wallet/Resources/Assets.xcassets/non-strict-token.imageset/Group 1523446@3x.png differ diff --git a/p2p_wallet/Resources/Base.lproj/Localizable.strings b/p2p_wallet/Resources/Base.lproj/Localizable.strings index ee52b5554a..ac14ce8519 100644 --- a/p2p_wallet/Resources/Base.lproj/Localizable.strings +++ b/p2p_wallet/Resources/Base.lproj/Localizable.strings @@ -586,3 +586,6 @@ "Username copied to clipboard" = "Username copied to clipboard"; "Address copied to clipboard" = "Address copied to clipboard"; "1%% fees" = "1%% fees"; +"Confirm selection" = "Confirm selection"; +"The token %@ is out of the strict list" = "The token %@ is out of the strict list"; +"Make sure the mint address %@ is correct before confirming" = "Make sure the mint address %@ is correct before confirming"; diff --git a/p2p_wallet/Resources/en.lproj/Localizable.strings b/p2p_wallet/Resources/en.lproj/Localizable.strings index 7d494eb94d..696734e37e 100644 --- a/p2p_wallet/Resources/en.lproj/Localizable.strings +++ b/p2p_wallet/Resources/en.lproj/Localizable.strings @@ -570,3 +570,6 @@ "✌️ Great! Your new PIN is set." = "✌️ Great! Your new PIN is set."; "😓 name is not available" = "😓 name is not available"; "😢 PIN doesn't match. Please try again" = "😢 PIN doesn't match. Please try again"; +"Confirm selection" = "Confirm selection"; +"The token %@ is out of the strict list" = "The token %@ is out of the strict list"; +"Make sure the mint address %@ is correct before confirming" = "Make sure the mint address %@ is correct before confirming"; diff --git a/p2p_wallet/Scenes/DebugMenu/ViewModel/DebugMenuViewModel.swift b/p2p_wallet/Scenes/DebugMenu/ViewModel/DebugMenuViewModel.swift index 396524ac32..e7916acdf7 100644 --- a/p2p_wallet/Scenes/DebugMenu/ViewModel/DebugMenuViewModel.swift +++ b/p2p_wallet/Scenes/DebugMenu/ViewModel/DebugMenuViewModel.swift @@ -25,10 +25,28 @@ final class DebugMenuViewModel: BaseViewModel, ObservableObject { } let solanaEndpoints: [APIEndPoint] = [ - .init(address: "https://api.mainnet-beta.solana.com", network: .mainnetBeta), - .init(address: "https://solana-api.projectserum.com", network: .mainnetBeta), - .init(address: "https://p2p.rpcpool.com", network: .mainnetBeta), - .init(address: "https://api.devnet.solana.com", network: .devnet), + .init( + address: "https://api.mainnet-beta.solana.com", + network: .mainnetBeta + ), + .init( + address: "https://solana-api.projectserum.com", + network: .mainnetBeta + ), + .init( + address: "https://p2p.rpcpool.com", + network: .mainnetBeta, + additionalQuery: .secretConfig("RPCPOOL_API_KEY") + ), + .init( + address: "https://solana.keyapp.org", + network: .mainnetBeta, + additionalQuery: .secretConfig("KEYAPP_ORG_API_KEY") + ), + .init( + address: "https://api.devnet.solana.com", + network: .devnet + ), ] self.solanaEndpoints = solanaEndpoints selectedEndpoint = solanaEndpoints.first(where: { $0 == Defaults.apiEndPoint }) diff --git a/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Accounts/Aggregator/CryptoSolanaAccountsAggregator.swift b/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Accounts/Aggregator/CryptoSolanaAccountsAggregator.swift index 4a7b0406ee..eb11b8b6e1 100644 --- a/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Accounts/Aggregator/CryptoSolanaAccountsAggregator.swift +++ b/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Accounts/Aggregator/CryptoSolanaAccountsAggregator.swift @@ -19,24 +19,24 @@ struct CryptoSolanaAccountsAggregator: DataAggregator { return accounts .filter { !$0.isNFTToken } - .filter { !($0.token.keyAppExtensions.isPositionOnWS ?? false) } +// .filter { !($0.token.keyAppExtensions.isPositionOnWS ?? false) } .sorted(by: Self.defaultSorter) .map { account in var tags: AccountTags = [] if favourites.contains(account.address) { tags.insert(.favourite) - } else if ignores.contains(account.address), account.token.keyAppExtensions.canBeHidden == true { + } else if ignores.contains(account.address) /* , account.token.keyAppExtensions.canBeHidden == true */ { tags.insert(.ignore) } else if hideZeroBalance, account.lamports == 0 { tags.insert(.ignore) } - let extraAction: AccountExtraAction? = account.token.keyAppExtensions.canBeHidden ? .showHide : nil +// let extraAction: AccountExtraAction? = account.token.keyAppExtensions.canBeHidden ? .showHide : nil return RenderableSolanaAccount( account: account, - extraAction: extraAction, + extraAction: nil, // extraAction, tags: tags ) } diff --git a/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Actions Panel/CryptoActionsPanelViewModel.swift b/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Actions Panel/CryptoActionsPanelViewModel.swift index c144b9bc08..3fb82fa387 100644 --- a/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Actions Panel/CryptoActionsPanelViewModel.swift +++ b/p2p_wallet/Scenes/Main/Crypto/Components/Crypto Actions Panel/CryptoActionsPanelViewModel.swift @@ -31,7 +31,7 @@ final class CryptoActionsPanelViewModel: BaseViewModel, ObservableObject { super.init() - actions = [.receive, .swap] + actions = [.buy, .receive, .send, .swap] bind() } @@ -42,9 +42,9 @@ final class CryptoActionsPanelViewModel: BaseViewModel, ObservableObject { solanaAccountsService.statePublisher .map { (state: AsyncValueState<[SolanaAccountsService.Account]>) -> String in let equityValue: CurrencyAmount = state.value - .filter { !($0.token.keyAppExtensions.isPositionOnWS ?? false) } +// .filter { !($0.token.keyAppExtensions.isPositionOnWS ?? false) } .reduce(CurrencyAmount(usd: 0)) { - return $0 + $1.amountInFiat + $0 + $1.amountInFiat } let formatter = CurrencyFormatter( @@ -63,11 +63,17 @@ final class CryptoActionsPanelViewModel: BaseViewModel, ObservableObject { func actionClicked(_ action: WalletActionType) { switch action { + case .buy: + analyticsManager.log(event: .buyScreenOpened(lastScreen: "mainScreen")) + navigation.send(.buy) case .receive: guard let pubkey = try? PublicKey(string: solanaAccountsService.state.value.nativeWallet?.address) else { return } analyticsManager.log(event: .cryptoReceiveClick) navigation.send(.receive(publicKey: pubkey)) + case .send: + analyticsManager.log(event: .mainScreenSendClick) + navigation.send(.send) case .swap: analyticsManager.log(event: .cryptoSwapClick) navigation.send(.swap) diff --git a/p2p_wallet/Scenes/Main/Crypto/Container/CryptoCoordinator.swift b/p2p_wallet/Scenes/Main/Crypto/Container/CryptoCoordinator.swift index 496863539f..0ff1d39a3f 100644 --- a/p2p_wallet/Scenes/Main/Crypto/Container/CryptoCoordinator.swift +++ b/p2p_wallet/Scenes/Main/Crypto/Container/CryptoCoordinator.swift @@ -22,7 +22,7 @@ enum CryptoNavigation: Equatable { case claim(EthereumAccount, WormholeClaimUserAction?) case actions([WalletActionType]) // Empty - case topUpCoin(Token) + case topUpCoin(TokenMetadata) // Error case error(show: Bool) } @@ -82,6 +82,10 @@ final class CryptoCoordinator: Coordinator { private func navigate(to scene: CryptoNavigation) -> AnyPublisher { switch scene { + case .buy: + return coordinate(to: BuyCoordinator(navigationController: navigationController, context: .fromHome)) + .map { _ in () } + .eraseToAnyPublisher() case .receive: if available(.ethAddressEnabled) { let coordinator = SupportedTokensCoordinator( @@ -96,6 +100,32 @@ final class CryptoCoordinator: Coordinator { ) return coordinate(to: coordinator).eraseToAnyPublisher() } + case .send: + return coordinate( + to: SendCoordinator( + rootViewController: navigationController, + preChosenWallet: nil, + hideTabBar: true, + allowSwitchingMainAmountType: true + ) + ) + .receive(on: RunLoop.main) + .handleEvents(receiveOutput: { [weak self] result in + switch result { + case let .sent(model): + self?.navigationController.popToRootViewController(animated: true) + self?.showSendTransactionStatus(model: model) + case let .wormhole(trx): + self?.navigationController.popToRootViewController(animated: true) + self?.showUserAction(userAction: trx) + case .sentViaLink: + self?.navigationController.popToRootViewController(animated: true) + case .cancelled: + break + } + }) + .map { _ in () } + .eraseToAnyPublisher() case .swap: return coordinate( to: JupiterSwapCoordinator( @@ -154,4 +184,22 @@ final class CryptoCoordinator: Coordinator { .eraseToAnyPublisher() } } + + private func showUserAction(userAction: any UserAction) { + coordinate(to: TransactionDetailCoordinator( + viewModel: .init(userAction: userAction), + presentingViewController: navigationController.parent ?? navigationController + )) + .sink(receiveValue: { _ in }) + .store(in: &subscriptions) + } + + private func showSendTransactionStatus(model: SendTransaction) { + coordinate(to: SendTransactionStatusCoordinator( + parentController: navigationController.parent ?? navigationController, + transaction: model + )) + .sink(receiveValue: {}) + .store(in: &subscriptions) + } } diff --git a/p2p_wallet/Scenes/Main/NewSettings/Settings/View/SettingsView.swift b/p2p_wallet/Scenes/Main/NewSettings/Settings/View/SettingsView.swift index acd699e130..bdefac3782 100644 --- a/p2p_wallet/Scenes/Main/NewSettings/Settings/View/SettingsView.swift +++ b/p2p_wallet/Scenes/Main/NewSettings/Settings/View/SettingsView.swift @@ -49,10 +49,6 @@ struct SettingsView: View { } ) } - Button( - action: { viewModel.showView(.support) }, - label: { cellView(image: .settingsSupport, title: L10n.support.uppercaseFirst) } - ) Button( action: { viewModel.sendSignOutAnalytics() diff --git a/p2p_wallet/Scenes/Main/NewSettings/Settings/ViewModel/SettingsViewModel.swift b/p2p_wallet/Scenes/Main/NewSettings/Settings/ViewModel/SettingsViewModel.swift index 554b48cd89..791008c68e 100644 --- a/p2p_wallet/Scenes/Main/NewSettings/Settings/ViewModel/SettingsViewModel.swift +++ b/p2p_wallet/Scenes/Main/NewSettings/Settings/ViewModel/SettingsViewModel.swift @@ -66,8 +66,6 @@ final class SettingsViewModel: BaseViewModel, ObservableObject { return KeyAppAnalyticsEvent.settingsPinClick case .network: return KeyAppAnalyticsEvent.settingsNetworkClick - case .support: - return KeyAppAnalyticsEvent.settingsSupportClick case .recoveryKit: return KeyAppAnalyticsEvent.settingsRecoveryClick default: @@ -195,7 +193,6 @@ final class SettingsViewModel: BaseViewModel, ObservableObject { extension SettingsViewModel { enum OpenAction { case username - case support case reserveUsername(userAddress: String) case recoveryKit case yourPin diff --git a/p2p_wallet/Scenes/Main/NewSettings/SettingsCoordinator.swift b/p2p_wallet/Scenes/Main/NewSettings/SettingsCoordinator.swift index 34e51f2004..04652fe013 100644 --- a/p2p_wallet/Scenes/Main/NewSettings/SettingsCoordinator.swift +++ b/p2p_wallet/Scenes/Main/NewSettings/SettingsCoordinator.swift @@ -3,8 +3,6 @@ import Resolver import UIKit final class SettingsCoordinator: Coordinator { - @Injected private var helpLauncher: HelpCenterLauncher - private let navigationController: UINavigationController init(navigationController: UINavigationController) { @@ -24,8 +22,6 @@ final class SettingsCoordinator: Coordinator { case .username: let vc = NewUsernameViewController() navigationController.pushViewController(vc, animated: true) - case .support: - helpLauncher.launch() case .reserveUsername: coordinate(to: CreateUsernameCoordinator(navigationOption: .settings(parent: navigationController))) .sink { [unowned self] in diff --git a/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeChangeCoordinator.swift b/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeChangeCoordinator.swift index 833aa3795b..ef3317f9e1 100644 --- a/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeChangeCoordinator.swift +++ b/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeChangeCoordinator.swift @@ -7,7 +7,6 @@ class PincodeChangeCoordinator: Coordinator { private let transition = PanelTransition() @Injected private var pincodeStorage: PincodeStorageType - @Injected private var helpLauncher: HelpCenterLauncher let result = PassthroughSubject() init(navVC: UINavigationController) { @@ -52,11 +51,6 @@ class PincodeChangeCoordinator: Coordinator { viewController.modalPresentationStyle = .custom self.navVC.present(viewController, animated: true) } - view.help - .sink(receiveValue: { [unowned self] in - helpLauncher.launch() - }) - .store(in: &subscriptions) let vc = UIHostingController(rootView: view) vc.title = L10n.changePIN diff --git a/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeVerifyView.swift b/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeVerifyView.swift index b6be5591f2..c4e1fb9491 100644 --- a/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeVerifyView.swift +++ b/p2p_wallet/Scenes/Main/NewSettings/Subscenes/PincodeChange/PincodeVerifyView.swift @@ -8,8 +8,6 @@ struct PincodeVerifyView: View { @Injected private var pincodeStorage: PincodeStorageType var onSuccess: (() -> Void)? var forgetPinCode: (() -> Void)? - private let helpSubject = PassthroughSubject() - var help: AnyPublisher { helpSubject.eraseToAnyPublisher() } var body: some View { VStack { @@ -59,15 +57,6 @@ struct PincodeVerifyView: View { .padding(.top, 24) } } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button { - helpSubject.send() - } label: { - Image(.helpOutline) - } - } - } .padding(.top, safeAreaInsets.top + 50) .padding(.bottom, 54) .background(Color(.rain)) diff --git a/p2p_wallet/Scenes/Main/ReceiveFundsViaLink/ViewModel/ReceiveFundsViaLinkViewModel.swift b/p2p_wallet/Scenes/Main/ReceiveFundsViaLink/ViewModel/ReceiveFundsViaLinkViewModel.swift index 1f90a05aa7..8268697c64 100644 --- a/p2p_wallet/Scenes/Main/ReceiveFundsViaLink/ViewModel/ReceiveFundsViaLinkViewModel.swift +++ b/p2p_wallet/Scenes/Main/ReceiveFundsViaLink/ViewModel/ReceiveFundsViaLinkViewModel.swift @@ -172,6 +172,7 @@ final class ReceiveFundsViaLinkViewModel: BaseViewModel, ObservableObject { address: claimableToken.mintAddress ) ?? .unsupported( + tags: nil, mint: claimableToken.mintAddress, decimals: claimableToken.decimals, symbol: "", diff --git a/p2p_wallet/Scenes/Main/Send/Input/SendInputViewModel.swift b/p2p_wallet/Scenes/Main/Send/Input/SendInputViewModel.swift index 1c02086130..56c26a6548 100644 --- a/p2p_wallet/Scenes/Main/Send/Input/SendInputViewModel.swift +++ b/p2p_wallet/Scenes/Main/Send/Input/SendInputViewModel.swift @@ -304,6 +304,10 @@ private extension SendInputViewModel { if self.status != .initializing { self.logTokenChosen(symbol: value.token.symbol) } + if currentState.amountInToken.isLamportsBiggerThanUInt64(decimals: Int(value.token.decimals)) { + _ = await self.stateMachine.accept(action: .changeAmountInToken(0)) + self.inputAmountViewModel.amountText = "0" + } _ = await self.stateMachine.accept(action: .changeUserToken(value.token)) await MainActor.run { [weak self] in self?.inputAmountViewModel.token = value diff --git a/p2p_wallet/Scenes/Main/Send/Input/Subviews/AmountView/SendInputAmountField.swift b/p2p_wallet/Scenes/Main/Send/Input/Subviews/AmountView/SendInputAmountField.swift index 6c1c687e8d..6b31f0eef4 100644 --- a/p2p_wallet/Scenes/Main/Send/Input/Subviews/AmountView/SendInputAmountField.swift +++ b/p2p_wallet/Scenes/Main/Send/Input/Subviews/AmountView/SendInputAmountField.swift @@ -103,6 +103,10 @@ struct SendInputAmountField: UIViewRepresentable { let number = Double(updatedText.replacingOccurrences(of: " ", with: "")) + if number?.isLamportsBiggerThanUInt64(decimals: countAfterDecimalPoint) == true { + return false + } + if (string.isEmpty || string.starts(with: "0")) && updatedText.starts(with: "0\(decimalSeparator)") && number == 0 diff --git a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/ChooseSwapTokenCoordinator.swift b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/ChooseSwapTokenCoordinator.swift index dd1ab9d502..204570af0c 100644 --- a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/ChooseSwapTokenCoordinator.swift +++ b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/ChooseSwapTokenCoordinator.swift @@ -9,6 +9,7 @@ final class ChooseSwapTokenCoordinator: Coordinator { private let fromToken: Bool private let tokens: [SwapToken] private let title: String + private var nonStrictTokenAlertVC: CustomPresentableViewController? init( chosenWallet: SwapToken, @@ -47,12 +48,42 @@ final class ChooseSwapTokenCoordinator: Coordinator { } viewModel.chooseTokenSubject - .sink { [weak self] value in self?.close(token: value as? SwapToken) } + .sink { [weak self] value in + self?.openNonStrictTokenConfirmationIfNeededOrClose( + token: value as? SwapToken + ) + } .store(in: &subscriptions) return subject.eraseToAnyPublisher() } + // MARK: - Navigation + + private func openNonStrictTokenConfirmationIfNeededOrClose( + token: SwapToken? + ) { + if token?.token.tags.map(\.name).contains("unknown") == true { + nonStrictTokenAlertVC = UIBottomSheetHostingController( + rootView: NonStrictTokenConfirmationView( + token: token + ) { + [weak self] in + self?.nonStrictTokenAlertVC?.dismiss(animated: true) { [weak self] in + self?.close(token: token) + } + }, + shouldIgnoresKeyboard: true + ) + nonStrictTokenAlertVC!.view.layer.cornerRadius = 20 + + // present bottom sheet + navigationController.present(nonStrictTokenAlertVC!, interactiveDismissalType: .standard) + } else { + close(token: token) + } + } + private func close(token: SwapToken?) { navigationController.popViewController(animated: true, completion: {}) subject.send(token) diff --git a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Extensions/SwapToken+ChooseItemSearchableItem.swift b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Extensions/SwapToken+ChooseItemSearchableItem.swift index 456bb11e83..50d900ff57 100644 --- a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Extensions/SwapToken+ChooseItemSearchableItem.swift +++ b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Extensions/SwapToken+ChooseItemSearchableItem.swift @@ -7,6 +7,7 @@ extension SwapToken: ChooseItemSearchableItem { token.symbol.lowercased().hasPrefix(keyword.lowercased()) || token.symbol.lowercased().contains(keyword.lowercased()) || token.name.lowercased().hasPrefix(keyword.lowercased()) || - token.name.lowercased().contains(keyword.lowercased()) + token.name.lowercased().contains(keyword.lowercased()) || + token.mintAddress.lowercased().hasPrefix(keyword.lowercased()) } } diff --git a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Service/ChooseSwapTokenService.swift b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Service/ChooseSwapTokenService.swift index 7cd2519b16..36a501c7f1 100644 --- a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Service/ChooseSwapTokenService.swift +++ b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Service/ChooseSwapTokenService.swift @@ -54,10 +54,14 @@ final class ChooseSwapTokenService: ChooseItemService { guard var tokens = section.items as? [SwapToken] else { return section } tokens = tokens.sorted(by: { lhs, _ in // Put 'start' matches in the beginning of array, 'contains' after - lhs.token.name.lowercased().starts(with: keyword) || lhs.token.symbol.lowercased().starts(with: keyword) + lhs.token.name.lowercased().starts(with: keyword.lowercased()) || + lhs.token.symbol.lowercased().starts(with: keyword.lowercased()) || + lhs.token.mintAddress.lowercased().starts(with: keyword.lowercased()) }) if let index = tokens.firstIndex(where: { - $0.token.name.lowercased().elementsEqual(keyword) || $0.token.symbol.lowercased().elementsEqual(keyword) + $0.token.name.lowercased().elementsEqual(keyword.lowercased()) || + $0.token.symbol.lowercased().elementsEqual(keyword.lowercased()) || + $0.token.mintAddress.lowercased().elementsEqual(keyword.lowercased()) }) { // Put exact match in the first place let exactKeywordToken = tokens.remove(at: index) diff --git a/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Subviews/NonStrictTokenConfirmationView.swift b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Subviews/NonStrictTokenConfirmationView.swift new file mode 100644 index 0000000000..2de90c8324 --- /dev/null +++ b/p2p_wallet/Scenes/Main/Swap/ChooseSwapItem/Subviews/NonStrictTokenConfirmationView.swift @@ -0,0 +1,95 @@ +import SwiftUI + +struct NonStrictTokenConfirmationView: View { + let token: SwapToken? + var onConfirm: () -> Void + + var body: some View { + VStack(alignment: .center) { + RoundedRectangle(cornerRadius: 2) + .fill(Color(.lightGray)) + .frame(width: 31, height: 4) + .padding(.vertical, 6) + + Image(.nonStrictToken) + .padding(.top, 20.88) + + explanationView + .padding(.top, 16) + + buttons + .padding(.top, 28) + .padding(.bottom, 32) + } + } + + // MARK: - ViewBuilders + + @ViewBuilder + private var explanationView: some View { + HStack(alignment: .center, spacing: 16) { + Image(.infoGray20) + .padding(14) + .background(Circle() + .fill(Color(.smoke))) + + VStack(alignment: .leading, spacing: 2) { + Text(L10n.theTokenIsOutOfTheStrictList(token?.token.symbol ?? token?.token.mintAddress.prefix(6) ?? "")) + .foregroundColor(Color(.night)) + .font(uiFont: .font(of: .text1, weight: .semibold)) + .fixedSize(horizontal: false, vertical: true) + + Text(L10n.makeSureTheMintAddressIsCorrectBeforeConfirming(token?.token.mintAddress.shortAddress ?? "")) + .font(uiFont: .font(of: .label1)) + .fixedSize(horizontal: false, vertical: true) + } + .frame(maxWidth: .infinity) + } + .padding(.horizontal, 16) + .padding(.vertical, 12) + .frame(maxWidth: .infinity) + .background(Color(.cloud)) + .cornerRadius(12) + .padding(.horizontal, 16) + } + + @ViewBuilder + private var buttons: some View { + VStack(spacing: 16) { + NewTextButton( + title: L10n.confirmSelection, + size: .large, + style: .primaryWhite, + expandable: true, + action: onConfirm + ) + + // Learn more + } + .frame(maxWidth: .infinity) + .padding(.horizontal, 16) + } +} + +#Preview { + NonStrictTokenConfirmationView( + token: .init( + token: .unsupported( + tags: ["unknown"], + mint: "GWART6ijjvijdihuhvjhhdhjBn78Ee", + decimals: 6, + symbol: "GWART", + supply: 1_000_000_000 + ), + userWallet: nil + ) + ) {} +} + +// MARK: - Helpers + +private extension String { + var shortAddress: String { + "\(prefix(6))...\(suffix(6))" + } +} diff --git a/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensLocalProvider.swift b/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensLocalProvider.swift index b3936c0814..a1bb8e72c9 100644 --- a/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensLocalProvider.swift +++ b/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensLocalProvider.swift @@ -27,6 +27,10 @@ final class JupiterTokensLocalProvider: JupiterTokensProvider { return cacheDirectoryPath.appendingPathComponent("/jupiter-tokens.data") }() + init() { + migrate() + } + func getCachedData() -> JupiterTokensCache? { guard let data = try? Data(contentsOf: cacheFile) else { return nil } let cachedData = (try? JSONDecoder().decode(JupiterTokensCache.self, from: data)) @@ -46,4 +50,14 @@ final class JupiterTokensLocalProvider: JupiterTokensProvider { func clear() { try? FileManager.default.removeItem(at: cacheFile) } + + // MARK: - Helpers + + private func migrate() { + let migrationKey1 = "MigrationKey1" + if !UserDefaults.standard.bool(forKey: migrationKey1) { + clear() + UserDefaults.standard.set(true, forKey: migrationKey1) + } + } } diff --git a/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensRepository.swift b/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensRepository.swift index 9bc32af95f..cbfea2d541 100644 --- a/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensRepository.swift +++ b/p2p_wallet/Scenes/Main/Swap/Providers/JupiterTokensRepository.swift @@ -95,7 +95,9 @@ final class JupiterTokensRepositoryImpl: JupiterTokensRepository { // map solanaTokens to jupiter token jupiterTokens = jupiterTokens.map { jupiterToken in - if let token = solanaTokens[jupiterToken.mintAddress] { + if var token = solanaTokens[jupiterToken.mintAddress] { + // join tags + token.tags = Array(Set(token.tags + jupiterToken.tags)) return token } return jupiterToken diff --git a/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Actions/JupiterSwapBusinessLogic+Initialize.swift b/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Actions/JupiterSwapBusinessLogic+Initialize.swift index ecf13435e7..587f0fac86 100644 --- a/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Actions/JupiterSwapBusinessLogic+Initialize.swift +++ b/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Actions/JupiterSwapBusinessLogic+Initialize.swift @@ -76,7 +76,10 @@ extension JupiterSwapBusinessLogic { // if userWallet found if let userWallet = wallets.first(where: { $0.mintAddress == jupiterToken.mintAddress }) { - return SwapToken(token: userWallet.token, userWallet: userWallet) + // move tags + var token = userWallet.token + token.tags = jupiterToken.tags + return SwapToken(token: token, userWallet: userWallet) } // otherwise return jupiter token with no userWallet diff --git a/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Helpers/JupiterSwapBusinessLogic+UpdatePrices.swift b/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Helpers/JupiterSwapBusinessLogic+UpdatePrices.swift index 1b049d8606..21012223b2 100644 --- a/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Helpers/JupiterSwapBusinessLogic+UpdatePrices.swift +++ b/p2p_wallet/Scenes/Main/Swap/State/BusinessLogic/Helpers/JupiterSwapBusinessLogic+UpdatePrices.swift @@ -26,7 +26,8 @@ extension JupiterSwapBusinessLogic { return state } - // Warning: This method should be refactored as we should not take prices directly from API but from PriceService + // Warning: This method should be refactored as we should not take prices directly from API but from + // PriceService let tokensPriceMap = ((try? await services.pricesAPI.getPrices(tokens: tokens, fiat: Defaults.fiat.code)) ?? [:]) .reduce([String: Double]()) { combined, element in diff --git a/p2p_wallet/Scenes/Main/Swap/Swap/JupiterSwapCoordinator.swift b/p2p_wallet/Scenes/Main/Swap/Swap/JupiterSwapCoordinator.swift index a17a8d30fd..4fcad4c88b 100644 --- a/p2p_wallet/Scenes/Main/Swap/Swap/JupiterSwapCoordinator.swift +++ b/p2p_wallet/Scenes/Main/Swap/Swap/JupiterSwapCoordinator.swift @@ -5,12 +5,17 @@ import SolanaSwift import SwiftUI enum JupiterSwapSource: String { - case actionPanel = "Action_Panel", tapMain = "Tap_Main", tapToken = "Tap_Token", solend = "Solend" + case actionPanel = "Action_Panel", tapMain = "Tap_Main", tapToken = "Tap_Token", solend = "Solend", + deeplink = "Deeplink" } struct JupiterSwapParameters { let preChosenWallet: SolanaAccount? let destinationWallet: SolanaAccount? + + let inputMint: String? + let outputMint: String? + let dismissAfterCompletion: Bool let openKeyboardOnStart: Bool let hideTabBar: Bool @@ -22,10 +27,16 @@ struct JupiterSwapParameters { source: JupiterSwapSource, preChosenWallet: SolanaAccount? = nil, destinationWallet: SolanaAccount? = nil, + inputMint: String? = nil, + outputMint: String? = nil, hideTabBar: Bool = false ) { self.preChosenWallet = preChosenWallet self.destinationWallet = destinationWallet + + self.inputMint = inputMint + self.outputMint = outputMint + self.dismissAfterCompletion = dismissAfterCompletion self.openKeyboardOnStart = openKeyboardOnStart self.source = source @@ -78,7 +89,9 @@ final class JupiterSwapCoordinator: Coordinator { toTokenInputViewModel: toTokenInputViewModel, source: params.source, preChosenWallet: params.preChosenWallet, - destinationWallet: params.destinationWallet + destinationWallet: params.destinationWallet, + inputMint: params.inputMint, + outputMint: params.outputMint ) // view diff --git a/p2p_wallet/Scenes/Main/Swap/Swap/SwapViewModel.swift b/p2p_wallet/Scenes/Main/Swap/Swap/SwapViewModel.swift index 8931a6358f..f5a3b32dc9 100644 --- a/p2p_wallet/Scenes/Main/Swap/Swap/SwapViewModel.swift +++ b/p2p_wallet/Scenes/Main/Swap/Swap/SwapViewModel.swift @@ -63,6 +63,10 @@ final class SwapViewModel: BaseViewModel, ObservableObject { private let preChosenWallet: SolanaAccount? private let destinationWallet: SolanaAccount? + + private var inputMint: String? + private var outputMint: String? + private var timer: Timer? private let source: JupiterSwapSource private var wasMinToastShown = false // Special flag not to show toast again if state has not changed @@ -75,13 +79,20 @@ final class SwapViewModel: BaseViewModel, ObservableObject { toTokenInputViewModel: SwapInputViewModel, source: JupiterSwapSource, preChosenWallet: SolanaAccount? = nil, - destinationWallet: SolanaAccount? = nil + destinationWallet: SolanaAccount? = nil, + inputMint: String? = nil, + outputMint: String? = nil ) { self.fromTokenInputViewModel = fromTokenInputViewModel self.toTokenInputViewModel = toTokenInputViewModel self.stateMachine = stateMachine + self.preChosenWallet = preChosenWallet self.destinationWallet = destinationWallet + + self.inputMint = inputMint + self.outputMint = outputMint + self.source = source super.init() bind() @@ -248,8 +259,9 @@ private extension SwapViewModel { account: userWalletManager.wallet?.account, jupiterTokens: jupiterTokens, routeMap: routeMap, - preChosenFromTokenMintAddress: preChosenWallet?.mintAddress ?? Defaults.fromTokenAddress, - preChosenToTokenMintAddress: destinationWallet?.mintAddress ?? Defaults.toTokenAddress + preChosenFromTokenMintAddress: preChosenWallet?.mintAddress ?? inputMint ?? Defaults + .fromTokenAddress, + preChosenToTokenMintAddress: destinationWallet?.mintAddress ?? outputMint ?? Defaults.toTokenAddress ) ) if source != .tapMain { diff --git a/p2p_wallet/Scenes/Main/TransactionDetailView/Model/RendableDetailTransaction+UserAction.swift b/p2p_wallet/Scenes/Main/TransactionDetailView/Model/RendableDetailTransaction+UserAction.swift index 794bcdeaa1..6a0bb9ac58 100644 --- a/p2p_wallet/Scenes/Main/TransactionDetailView/Model/RendableDetailTransaction+UserAction.swift +++ b/p2p_wallet/Scenes/Main/TransactionDetailView/Model/RendableDetailTransaction+UserAction.swift @@ -5,7 +5,7 @@ import KeyAppKitCore import Send import Wormhole -struct RendableGeneralUserActionTransaction { +enum RendableGeneralUserActionTransaction { static func resolve(userAction: any UserAction) -> RenderableTransactionDetail { switch userAction { case let userAction as WormholeSendUserAction: diff --git a/p2p_wallet/Scenes/TabBar/CustomTabBar.swift b/p2p_wallet/Scenes/TabBar/CustomTabBar.swift index 3d7c24c456..b6fbadf9a0 100644 --- a/p2p_wallet/Scenes/TabBar/CustomTabBar.swift +++ b/p2p_wallet/Scenes/TabBar/CustomTabBar.swift @@ -2,21 +2,6 @@ import Combine import UIKit final class CustomTabBar: UITabBar { - private lazy var middleButton: UIButton! = { - let middleButton = UIButton() - middleButton.frame.size = CGSize(width: 60, height: 60) - middleButton.backgroundColor = .init(resource: .snow) - middleButton.layer.cornerRadius = 30 - middleButton.setImage(UIImage(resource: .tabBarCenter), for: .normal) - middleButton.setImage(UIImage(resource: .tabBarCenter), for: .highlighted) - middleButton.imageView?.contentMode = .scaleAspectFit - middleButton.contentHorizontalAlignment = .fill - middleButton.contentVerticalAlignment = .fill - middleButton.addTarget(self, action: #selector(middleButtonAction), for: .touchUpInside) - addSubview(middleButton) - return middleButton - }() - private lazy var selectedView: UIView! = { let selectedView = UIView() selectedView.frame.size = CGSize(width: 36, height: 4) @@ -40,22 +25,9 @@ final class CustomTabBar: UITabBar { return 14 } - override var clipsToBounds: Bool { - didSet { - middleButton.clipsToBounds = false - } - } - - private let middleButtonClickedSubject = PassthroughSubject() - var middleButtonClicked: AnyPublisher { middleButtonClickedSubject.eraseToAnyPublisher() } - override func layoutSubviews() { super.layoutSubviews() - middleButton.center = CGPoint( - x: frame.width / 2, - y: frame.height / 2 - Self.additionalHeight - inset - ) updateSelectedViewPositionIfNeeded() layer.shadowColor = UIColor(red: 0.043, green: 0.122, blue: 0.208, alpha: 0.1).cgColor @@ -85,15 +57,6 @@ final class CustomTabBar: UITabBar { // MARK: - Actions - @objc func middleButtonAction() { - middleButtonClickedSubject.send() - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - guard !clipsToBounds, !isHidden, alpha > 0 else { return nil } - return middleButton.frame.contains(point) ? middleButton : super.hitTest(point, with: event) - } - func updateSelectedViewPositionIfNeeded() { guard let currentIndex = currentIndex else { return } let buttons = subviews.compactMap { NSStringFromClass(type(of: $0)) == "UITabBarButton" ? $0 : nil } diff --git a/p2p_wallet/Scenes/TabBar/TabBarController.swift b/p2p_wallet/Scenes/TabBar/TabBarController.swift index 93dc8912e2..42fa607878 100644 --- a/p2p_wallet/Scenes/TabBar/TabBarController.swift +++ b/p2p_wallet/Scenes/TabBar/TabBarController.swift @@ -1,6 +1,5 @@ import AnalyticsManager import Combine -import Intercom import Onboarding import Resolver import Sell @@ -11,13 +10,11 @@ final class TabBarController: UITabBarController { // MARK: - Dependencies @Injected private var analyticsManager: AnalyticsManager - @Injected private var helpLauncher: HelpCenterLauncher @Injected private var solanaTracker: SolanaTracker @Injected private var deviceShareMigration: DeviceShareMigrationService // MARK: - Publishers - var middleButtonClicked: AnyPublisher { customTabBar.middleButtonClicked } private let homeTabClickedTwicelySubject = PassthroughSubject() var homeTabClickedTwicely: AnyPublisher { homeTabClickedTwicelySubject.eraseToAnyPublisher() } private let jupiterSwapClickedSubject = PassthroughSubject() @@ -186,12 +183,6 @@ final class TabBarController: UITabBarController { } .store(in: &subscriptions) - pincodeViewModel.infoDidTap - .sink(receiveValue: { [unowned self] in - helpLauncher.launch() - }) - .store(in: &subscriptions) - localAuthVC?.onClose = { [weak self] in self?.viewModel.authenticate(presentationStyle: nil) if authSuccess == false { @@ -261,15 +252,6 @@ final class TabBarController: UITabBarController { }) .store(in: &subscriptions) - viewModel.moveToIntercomSurvey - .sink { id in - guard !id.isEmpty else { return } - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - Intercom.presentSurvey(id) - } - } - .store(in: &subscriptions) - // locking status viewModel.isLockedPublisher .sink(receiveValue: { [weak self] isLocked in @@ -282,28 +264,6 @@ final class TabBarController: UITabBarController { .map { $0 == nil } .assignWeak(to: \.isHidden, on: blurEffectView) .store(in: &subscriptions) - - // Crypto alert on/off - viewModel.transferAccountsPublisher - .removeDuplicates() - .receive(on: DispatchQueue.main) - .sink { [weak self] claimableTransferExist in - let image: ImageResource = claimableTransferExist ? .tabBarCryptoWithAlert : .tabBarCrypto - let selectedImage: ImageResource = claimableTransferExist ? .selectedTabBarCryptoWithAlert : - .tabBarCrypto - self?.viewControllers?[TabItem.crypto.rawValue].tabBarItem.image = .init(resource: image) - self?.viewControllers?[TabItem.crypto.rawValue].tabBarItem - .selectedImage = .init(resource: selectedImage) - } - .store(in: &subscriptions) - - // Wallet balance - viewModel.walletBalancePublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] balanceString in - self?.viewControllers?[TabItem.wallet.rawValue].tabBarItem.title = balanceString - } - .store(in: &subscriptions) } } @@ -321,18 +281,15 @@ extension TabBarController: UITabBarControllerDelegate { if let tabItem = TabItem(rawValue: selectedIndex) { switch tabItem { case .wallet: - viewModel.walletTapped() + viewModel.cryptoTapped() if (viewController as! UINavigationController).viewControllers.count == 1, self.selectedIndex == selectedIndex { homeTabClickedTwicelySubject.send() } - case .crypto: - viewModel.cryptoTapped() - case .send: - viewModel.sendTapped() - return false + case .swap: + viewModel.swapTapped() case .history: viewModel.historyTapped() case .settings: @@ -352,11 +309,9 @@ private extension TabItem { var image: ImageResource? { switch self { case .wallet: - return .tabBarWallet - case .crypto: return .tabBarCrypto - case .send: - return nil + case .swap: + return .tabBarSwap case .history: return .tabBarHistory case .settings: @@ -367,11 +322,9 @@ private extension TabItem { var displayTitle: String { switch self { case .wallet: - return "" - case .crypto: return L10n.crypto - case .send: - return L10n.send + case .swap: + return L10n.swap case .history: return L10n.history case .settings: diff --git a/p2p_wallet/Scenes/TabBar/TabBarCoordinator.swift b/p2p_wallet/Scenes/TabBar/TabBarCoordinator.swift index eff079f2a1..21764c6ac3 100644 --- a/p2p_wallet/Scenes/TabBar/TabBarCoordinator.swift +++ b/p2p_wallet/Scenes/TabBar/TabBarCoordinator.swift @@ -2,6 +2,7 @@ import AnalyticsManager import Combine import Foundation import KeyAppBusiness +import KeyAppKitCore import Resolver import Sell import SolanaSwift @@ -45,8 +46,8 @@ final class TabBarCoordinator: Coordinator { /// Start coordinator override func start() -> AnyPublisher { // set up tabs - let firstTab = setUpHome() - let (secondTab, thirdTab) = setupCryptoAndHistory() + let secondTab = setUpSwap() + let (firstTab, thirdTab) = setupCryptoAndHistory() let forthTab = setUpSettings() // set viewcontrollers @@ -54,7 +55,6 @@ final class TabBarCoordinator: Coordinator { [ firstTab, secondTab, - UINavigationController(), thirdTab, forthTab, ], @@ -95,7 +95,20 @@ final class TabBarCoordinator: Coordinator { } .store(in: &subscriptions) - listenToSendButton() + tabBarViewModel.moveToSwap + .sink { [weak self] url in + guard let self else { return } + guard let vc = UIApplication.topmostViewController()?.navigationController ?? self.tabBarController + .navigationController else { return } + + let urlComponent = URLComponents(url: url, resolvingAgainstBaseURL: true) + let inputMint = urlComponent?.queryItems?.first { $0.name == "inputMint" }?.value + let outputMint = urlComponent?.queryItems?.first { $0.name == "outputMint" }?.value + + self.routeToSwap(nc: vc, source: .tapToken, inputMint: inputMint, outputMint: outputMint) + } + .store(in: &subscriptions) + listenToWallet() } @@ -141,6 +154,26 @@ final class TabBarCoordinator: Coordinator { return (cryptoNavigation, historyNavigation) } + /// Set up Swap scene + private func setUpSwap() -> UIViewController { + let nc = UINavigationController() + let swapCoordinator = JupiterSwapCoordinator( + navigationController: nc, + params: JupiterSwapParameters( + dismissAfterCompletion: false, + openKeyboardOnStart: false, + source: .actionPanel, + hideTabBar: false + ) + ) + jupiterSwapTabCoordinator = swapCoordinator + // coordinate to homeCoordinator + coordinate(to: swapCoordinator) + .sink(receiveValue: {}) + .store(in: &subscriptions) + return nc + } + /// Set up Settings scene private func setUpSettings() -> UIViewController { let settingsNavigation = UINavigationController() @@ -151,44 +184,6 @@ final class TabBarCoordinator: Coordinator { return settingsNavigation } - /// Listen to Send Button - private func listenToSendButton() { - tabBarController.middleButtonClicked - .receive(on: RunLoop.main) - .compactMap { [weak self] in - self?.navigationControllerForSelectedTab() - } - .flatMap { [unowned self] navigationController -> AnyPublisher in - self.coordinate( - to: SendCoordinator( - rootViewController: navigationController, - preChosenWallet: nil, - hideTabBar: true, - allowSwitchingMainAmountType: true - ) - ) - } - .receive(on: RunLoop.main) - .sink(receiveValue: { [weak self] result in - guard let navigationController = self?.navigationControllerForSelectedTab() else { - return - } - switch result { - case let .sent(model): - navigationController.popToRootViewController(animated: true) - self?.showSendTransactionStatus(navigationController: navigationController, model: model) - case let .wormhole(trx): - navigationController.popToRootViewController(animated: true) - self?.showUserAction(userAction: trx) - case .sentViaLink: - navigationController.popToRootViewController(animated: true) - case .cancelled: - break - } - }) - .store(in: &subscriptions) - } - private func listenToWallet() { userWalletManager.$wallet .sink { [weak self] wallet in @@ -244,7 +239,9 @@ final class TabBarCoordinator: Coordinator { private func routeToSwap( nc: UINavigationController, hidesBottomBarWhenPushed: Bool = true, - source: JupiterSwapSource + source: JupiterSwapSource, + inputMint: String? = nil, + outputMint: String? = nil ) { let swapCoordinator = JupiterSwapCoordinator( navigationController: nc, @@ -252,6 +249,8 @@ final class TabBarCoordinator: Coordinator { dismissAfterCompletion: source != .tapMain, openKeyboardOnStart: source != .tapMain, source: source, + inputMint: inputMint, + outputMint: outputMint, hideTabBar: hidesBottomBarWhenPushed ) ) diff --git a/p2p_wallet/Scenes/TabBar/TabBarViewModel.swift b/p2p_wallet/Scenes/TabBar/TabBarViewModel.swift index 7330664c2a..6a08342c62 100644 --- a/p2p_wallet/Scenes/TabBar/TabBarViewModel.swift +++ b/p2p_wallet/Scenes/TabBar/TabBarViewModel.swift @@ -76,8 +76,8 @@ final class TabBarViewModel { analyticsManager.log(event: .mainScreenCryptoClick) } - func sendTapped() { - analyticsManager.log(event: .mainScreenSendClick) + func swapTapped() { + analyticsManager.log(event: .mainScreenSwapBar) } func historyTapped() { @@ -114,41 +114,31 @@ extension TabBarViewModel { .eraseToAnyPublisher() } - var moveToIntercomSurvey: AnyPublisher { - Publishers.Merge( - authenticationHandler - .isLockedPublisher - .filter { value in - GlobalAppState.shared.surveyID != nil && value == false - } - .map { _ in () }, - - viewDidLoad - .filter { [weak self] in - self?.notificationService.showFromLaunch == true - } + var moveToSendViaLinkClaim: AnyPublisher { + Publishers.CombineLatest( + authenticationStatusPublisher, + becomeActiveSubject ) - .map { _ in () } - .map { - GlobalAppState.shared.surveyID ?? "" - } + .debounce(for: .milliseconds(900), scheduler: RunLoop.main) + .filter { $0.0 == nil } + .compactMap { _ in GlobalAppState.shared.sendViaLinkUrl } .handleEvents(receiveOutput: { _ in - GlobalAppState.shared.surveyID = nil + GlobalAppState.shared.sendViaLinkUrl = nil }) .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - var moveToSendViaLinkClaim: AnyPublisher { + var moveToSwap: AnyPublisher { Publishers.CombineLatest( authenticationStatusPublisher, becomeActiveSubject ) .debounce(for: .milliseconds(900), scheduler: RunLoop.main) .filter { $0.0 == nil } - .compactMap { _ in GlobalAppState.shared.sendViaLinkUrl } + .compactMap { _ in GlobalAppState.shared.swapUrl } .handleEvents(receiveOutput: { _ in - GlobalAppState.shared.sendViaLinkUrl = nil + GlobalAppState.shared.swapUrl = nil }) .receive(on: DispatchQueue.main) .eraseToAnyPublisher() @@ -177,24 +167,4 @@ extension TabBarViewModel { } .eraseToAnyPublisher() } - - var walletBalancePublisher: AnyPublisher { - solanaAccountsService.statePublisher - .map { (state: AsyncValueState<[SolanaAccountsService.Account]>) -> String in - let equityValue: CurrencyAmount = state.value - .filter { $0.token.keyAppExtensions.isPositionOnWS ?? false } - .filter { $0.token.keyAppExtensions.calculationOfFinalBalanceOnWS ?? true } - .reduce(CurrencyAmount(usd: 0)) { - $0 + $1.amountInFiat - } - let formatter = CurrencyFormatter( - showSpacingAfterCurrencySymbol: false, - showSpacingAfterCurrencyGroup: false, - showSpacingAfterLessThanOperator: false - ) - return formatter.string(amount: equityValue) - } - .receive(on: RunLoop.main) - .eraseToAnyPublisher() - } } diff --git a/p2p_wallet/Scenes/TabBar/TabItem.swift b/p2p_wallet/Scenes/TabBar/TabItem.swift index ee97c8265a..909525989c 100644 --- a/p2p_wallet/Scenes/TabBar/TabItem.swift +++ b/p2p_wallet/Scenes/TabBar/TabItem.swift @@ -2,8 +2,7 @@ import UIKit enum TabItem: Int, CaseIterable { case wallet = 0 - case crypto - case send + case swap case history case settings } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewController.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewController.swift index d359d1756c..cf5bfcb81e 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewController.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewController.swift @@ -134,7 +134,6 @@ final class PincodeViewController: BaseViewController { private func setupNavBar() { addLeftButton() - addRightButton() } private func addLeftButton() { @@ -164,23 +163,6 @@ final class PincodeViewController: BaseViewController { viewModel.back.send() } - private func addRightButton() { - let infoButton = UIButton() - infoButton.addTarget(self, action: #selector(openInfo), for: .touchUpInside) - infoButton.setImage(.init(resource: .helpOutline), for: .normal) - infoButton.contentMode = .scaleAspectFill - if navigationController != nil { - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: infoButton) - } else { - view.addSubview(infoButton) - infoButton.autoPinToTopRightCornerOfSuperviewSafeArea(xInset: 17, yInset: 3) - } - } - - @objc private func openInfo() { - viewModel.infoDidTap.send() - } - private var transition: PanelTransition? private var forgetPinViewController: UIViewController? private func openForgotPIN( diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewModel.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewModel.swift index 40cdd4b938..8f7b600a5b 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewModel.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/Pincode/PincodeViewModel.swift @@ -28,7 +28,6 @@ final class PincodeViewModel: BaseViewModel, ObservableObject { @Published var showForgotModal: Bool = false let back = PassthroughSubject() - let infoDidTap = PassthroughSubject() let pincodeSuccess = PassthroughSubject() let pincodeFailed = PassthroughSubject() diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/SecuritySetupDelegatedCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/SecuritySetupDelegatedCoordinator.swift index 7ceb7856ea..f877a0714f 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/SecuritySetupDelegatedCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/Common/Pincode/SecuritySetupDelegatedCoordinator.swift @@ -5,8 +5,6 @@ import SwiftUI import UIKit final class SecuritySetupDelegatedCoordinator: DelegatedCoordinator { - @Injected private var helpLauncher: HelpCenterLauncher - override func buildViewController(for state: SecuritySetupState) -> UIViewController? { switch state { case .createPincode: @@ -22,12 +20,6 @@ final class SecuritySetupDelegatedCoordinator: DelegatedCoordinator, Never> = .init() - let outInfo: PassthroughSubject = .init() let outLogin: PassthroughSubject, Never> = .init() init(parameters: SocialSignInParameters) { @@ -42,11 +41,6 @@ final class SocialSignInViewModel: BaseViewModel, ObservableObject { super.init() } - func onInfo() { - guard loading == nil else { return } - outInfo.send() - } - func onBack() { guard loading == nil else { return } outBack.sendProcess() diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BaseOTPViewModel.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BaseOTPViewModel.swift index 5580befbe1..4a453df3b4 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BaseOTPViewModel.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BaseOTPViewModel.swift @@ -9,7 +9,7 @@ class BaseOTPViewModel: BaseViewModel, ObservableObject { @Published var error: String? @MainActor - internal func showError(error: Error?) { + func showError(error: Error?) { var errorText = L10n.SomethingWentWrong.pleaseTryAgain if let error = error as? APIGatewayError { switch error { diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BindingPhoneNumberDelegatedCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BindingPhoneNumberDelegatedCoordinator.swift index f58cc8139a..7807093c35 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BindingPhoneNumberDelegatedCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/BindingPhoneNumberDelegatedCoordinator.swift @@ -7,7 +7,6 @@ import Resolver import SwiftUI class BindingPhoneNumberDelegatedCoordinator: DelegatedCoordinator { - @Injected private var helpLauncher: HelpCenterLauncher @Injected private var analyticsManager: AnalyticsManager override func buildViewController(for state: BindingPhoneNumberState) -> UIViewController? { @@ -32,12 +31,6 @@ class BindingPhoneNumberDelegatedCoordinator: DelegatedCoordinator() private var continueButtonRef = BERef() - private var disableRightButton: Bool - var store = Set() - init(viewModel: EnterSMSCodeViewModel, disableRightButton: Bool = false) { + init(viewModel: EnterSMSCodeViewModel) { self.viewModel = viewModel - self.disableRightButton = disableRightButton super.init() } @@ -166,26 +163,12 @@ final class EnterSMSCodeViewController: BaseOTPViewController { ) backButton.tintColor = .init(resource: .night) navigationItem.leftBarButtonItem = backButton - - if !disableRightButton { - // Right button - let infoButton = UIButton() - infoButton.addTarget(self, action: #selector(onInfo), for: .touchUpInside) - infoButton.setImage(.init(resource: .helpOutline), for: .normal) - infoButton.contentMode = .scaleAspectFill - infoButton.tintColor = .init(resource: .night) - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: infoButton) - } } @objc func onBack() { viewModel.backTapped() } - @objc func onInfo() { - viewModel.infoTapped() - } - private func openKeyboard() { smsInputRef.view?.textField?.becomeFirstResponder() } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/EnterSMSCode/EnterSMSCodeViewModel.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/EnterSMSCode/EnterSMSCodeViewModel.swift index 08bc07bb7a..4ffd738696 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/EnterSMSCode/EnterSMSCodeViewModel.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/EnterPhoneNumber/EnterSMSCode/EnterSMSCodeViewModel.swift @@ -193,8 +193,8 @@ final class EnterSMSCodeViewModel: BaseOTPViewModel { // MARK: - static func format(code: String) -> String { - Self.prepareRawCode(code: code) - .prefix(Self.codeLength) + prepareRawCode(code: code) + .prefix(codeLength) .asString() .separate(every: 3, with: " ") } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInAccountHasBeenUsed/SocialSignInAccountHasBeenUsedView.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInAccountHasBeenUsed/SocialSignInAccountHasBeenUsedView.swift index dc32ad1715..a762c5dc5f 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInAccountHasBeenUsed/SocialSignInAccountHasBeenUsedView.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInAccountHasBeenUsed/SocialSignInAccountHasBeenUsedView.swift @@ -46,8 +46,7 @@ struct SocialSignInAccountHasBeenUsedView: View { } .onboardingNavigationBar( title: L10n.stepOf("1", "3"), - onBack: { [weak viewModel] in viewModel?.back() }, - onInfo: { [weak viewModel] in viewModel?.info() } + onBack: { [weak viewModel] in viewModel?.back() } ) .modifier(OnboardingScreen()) } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInDelegatedCoordiantor.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInDelegatedCoordiantor.swift index b3724c90db..28f70082ff 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInDelegatedCoordiantor.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/CreateWallet/Steps/SocialSignIn/SocialSignInDelegatedCoordiantor.swift @@ -6,7 +6,6 @@ import Resolver import SwiftUI class SocialSignInDelegatedCoordinator: DelegatedCoordinator { - @Injected private var helpLauncher: HelpCenterLauncher @Injected private var analyticsManager: AnalyticsManager override func buildViewController(for state: SocialSignInState) -> UIViewController? { @@ -16,8 +15,6 @@ class SocialSignInDelegatedCoordinator: DelegatedCoordinator let vm = SocialSignInViewModel(parameters: socialSignInParameters()) let vc = SocialSignInView(viewModel: vm) - vc.viewModel.outInfo.sink { [weak self] in self?.openInfo() } - .store(in: &subscriptions) vc.viewModel.outBack.sinkAsync { [stateMachine] process in process.start { try await stateMachine <- .signInBack } @@ -99,10 +96,6 @@ class SocialSignInDelegatedCoordinator: DelegatedCoordinator } } - func openInfo() { - helpLauncher.launch() - } - private func socialSignInParameters() -> SocialSignInParameters { let content = OnboardingContentData( image: .easyToStart, diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/RestoreWalletCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/RestoreWalletCoordinator.swift index 27b725b84e..7fd9d5aeaa 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/RestoreWalletCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/RestoreWalletCoordinator.swift @@ -11,7 +11,6 @@ enum RestoreWalletNavigation { } final class RestoreWalletCoordinator: Coordinator { - @Injected private var helpLauncher: HelpCenterLauncher @Injected private var analyticsManager: AnalyticsManager private let navigationController: OnboardingNavigationController @@ -182,10 +181,6 @@ final class RestoreWalletCoordinator: Coordinator { } } - @objc private func openInfo() { - helpLauncher.launch() - } - private func isBackAvailable() -> Bool { switch navigation { case .root: @@ -222,10 +217,6 @@ private extension RestoreWalletCoordinator { _ = try await stateMachine <- .start } .store(in: &subscriptions) - chooseRestoreOptionViewModel.openInfo.sink { [weak self] in - self?.openInfo() - } - .store(in: &subscriptions) chooseRestoreOptionViewModel.back.sinkAsync { _ = try await stateMachine <- .back } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ChooseRestoreOption/ChooseRestoreOptionView.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ChooseRestoreOption/ChooseRestoreOptionView.swift index 3f0083c2c6..fc989e38e8 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ChooseRestoreOption/ChooseRestoreOptionView.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ChooseRestoreOption/ChooseRestoreOptionView.swift @@ -23,8 +23,7 @@ struct ChooseRestoreOptionView: View { } .onboardingNavigationBar( title: L10n.restoreYourWallet, - onBack: viewModel.isBackAvailable ? { [weak viewModel] in viewModel?.back.send() } : nil, - onInfo: { [weak viewModel] in viewModel?.openInfo.send() } + onBack: viewModel.isBackAvailable ? { [weak viewModel] in viewModel?.back.send() } : nil ) } } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/ICloudRestore/ICloudRestoreScreen.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/ICloudRestore/ICloudRestoreScreen.swift index 81023ab31c..7437ab293f 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/ICloudRestore/ICloudRestoreScreen.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/ICloudRestore/ICloudRestoreScreen.swift @@ -13,8 +13,6 @@ struct ICloudRestoreScreen: View { } .onboardingNavigationBar(title: L10n.restoreYourWallet, onBack: { [weak viewModel] in viewModel?.backPressed() - }, onInfo: { [weak viewModel] in - viewModel?.infoPressed() }) .background(Color(.lime)) .edgesIgnoringSafeArea(.all) diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/RestoreICloudDelegatedCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/RestoreICloudDelegatedCoordinator.swift index d294162e06..116a705013 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/RestoreICloudDelegatedCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/ICloudRestore/RestoreICloudDelegatedCoordinator.swift @@ -4,8 +4,6 @@ import Resolver import SwiftUI final class RestoreICloudDelegatedCoordinator: DelegatedCoordinator { - @Injected private var helpLauncher: HelpCenterLauncher - override func buildViewController(for state: RestoreICloudState) -> UIViewController? { switch state { case .signIn: @@ -16,10 +14,6 @@ final class RestoreICloudDelegatedCoordinator: DelegatedCoordinator { @Injected private var analyticsManager: AnalyticsManager - @Injected private var helpLauncher: HelpCenterLauncher override func buildViewController(for state: RestoreCustomState) -> UIViewController? { switch state { @@ -46,10 +45,6 @@ final class RestoreCustomDelegatedCoordinator: DelegatedCoordinator UIViewController { let view = OnboardingBrokenScreen(title: "", contentData: content, back: { [stateMachine] in Task { _ = try await stateMachine <- .start } - }, info: { [weak self] in - self?.openHelp() - }, help: { [weak self] in - self?.openHelp() }) return UIHostingController(rootView: view) } @@ -282,10 +258,6 @@ private extension RestoreCustomDelegatedCoordinator { _ = try await stateMachine <- .start } .store(in: &subscriptions) - viewModel.openInfo.sink { [weak self] in - self?.openHelp() - } - .store(in: &subscriptions) return UIHostingController(rootView: ChooseRestoreOptionView(viewModel: viewModel)) } else { @@ -296,9 +268,7 @@ private extension RestoreCustomDelegatedCoordinator { ) let view = OnboardingBrokenScreen(title: "", contentData: content, back: { [stateMachine] in Task { _ = try await stateMachine <- .start } - }, info: { [weak self] in - self?.openHelp() - }, help: nil, + }, customActions: { TextButtonView(title: L10n.useAnAnotherPhone, style: .inverted, size: .large) @@ -336,8 +306,7 @@ private extension RestoreCustomDelegatedCoordinator { Task { _ = try await stateMachine <- .enterPhone } }, onTermsOfService: { [weak self] in self?.openTermsOfService() }, - onPrivacyPolicy: { [weak self] in self?.openPrivacyPolicy() }, - onInfo: { [weak self] in self?.openHelp() } + onPrivacyPolicy: { [weak self] in self?.openPrivacyPolicy() } ) return UIHostingController(rootView: view) } @@ -357,8 +326,6 @@ private extension RestoreCustomDelegatedCoordinator { let actionView = RestoreSocialOptionView(viewModel: actionViewModel) let view = OnboardingBrokenScreen(title: "", contentData: content, back: { [stateMachine] in Task { _ = try await stateMachine <- .start } - }, info: { [weak self] in - self?.openHelp() }, customActions: { actionView }) return UIHostingController(rootView: view) } @@ -394,10 +361,6 @@ private extension RestoreCustomDelegatedCoordinator { _ = try await stateMachine <- .start } .store(in: &subscriptions) - chooseRestoreOptionViewModel.openInfo.sink { [weak self] in - self?.openHelp() - } - .store(in: &subscriptions) return UIHostingController(rootView: ChooseRestoreOptionView(viewModel: chooseRestoreOptionViewModel)) } } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/RestoreSocial/RestoreSocialDelegatedCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/RestoreSocial/RestoreSocialDelegatedCoordinator.swift index b70a769619..eebe0bc229 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/RestoreSocial/RestoreSocialDelegatedCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/RestoreSocial/RestoreSocialDelegatedCoordinator.swift @@ -4,8 +4,6 @@ import Resolver import SwiftUI final class RestoreSocialDelegatedCoordinator: DelegatedCoordinator { - @Injected private var helpLauncher: HelpCenterLauncher - override func buildViewController(for state: RestoreSocialState) -> UIViewController? { switch state { case .signIn: @@ -41,10 +39,6 @@ final class RestoreSocialDelegatedCoordinator: DelegatedCoordinator SocialSignInParameters { let content = OnboardingContentData(image: .easyToStart, title: L10n.howToContinue) let parameters = SocialSignInParameters( @@ -62,8 +56,6 @@ private extension RestoreSocialDelegatedCoordinator { func handleSocial() -> UIViewController { let viewModel = SocialSignInViewModel(parameters: socialSignInParameters()) let view = SocialSignInView(viewModel: viewModel) - viewModel.outInfo.sink { [weak self] in self?.openInfo() } - .store(in: &subscriptions) viewModel.outLogin.sinkAsync { [stateMachine] process in process.start { @@ -101,10 +93,6 @@ private extension RestoreSocialDelegatedCoordinator { _ = try await stateMachine <- .start } .store(in: &subscriptions) - chooseRestoreOptionViewModel.openInfo.sink { [weak self] in - self?.openInfo() - } - .store(in: &subscriptions) chooseRestoreOptionViewModel.back.sinkAsync { [stateMachine] in _ = try await stateMachine <- .back } @@ -130,8 +118,6 @@ private extension RestoreSocialDelegatedCoordinator { let actionView = RestoreSocialOptionView(viewModel: actionViewModel) let view = OnboardingBrokenScreen(title: "", contentData: content, back: { [stateMachine] in Task { _ = try await stateMachine <- .start } - }, info: { [weak self] in - self?.openInfo() }, customActions: { actionView }) return UIHostingController(rootView: view) } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/SeedPhraseRestore/RestoreSeedPhraseDelegatedCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/SeedPhraseRestore/RestoreSeedPhraseDelegatedCoordinator.swift index ae44648922..86e1777bbd 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/SeedPhraseRestore/RestoreSeedPhraseDelegatedCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/RestoreWallet/Steps/SeedPhraseRestore/RestoreSeedPhraseDelegatedCoordinator.swift @@ -4,8 +4,6 @@ import Resolver import SwiftUI final class RestoreSeedPhraseDelegatedCoordinator: DelegatedCoordinator { - @Injected private var helpLauncher: HelpCenterLauncher - override func buildViewController(for state: RestoreSeedState) -> UIViewController? { switch state { case .signInSeed: @@ -16,10 +14,6 @@ final class RestoreSeedPhraseDelegatedCoordinator: DelegatedCoordinator Void)? let onTermsOfService: () -> Void let onPrivacyPolicy: () -> Void - let onInfo: (() -> Void)? let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() @@ -67,7 +66,7 @@ struct OnboardingBlockScreen: View { } .background(Color(.lime)) .ignoresSafeArea() - .onboardingNavigationBar(title: "", onInfo: onInfo) + .onboardingNavigationBar(title: "") } private let formatter: DateComponentsFormatter = { @@ -96,6 +95,6 @@ struct OnboardingBlockScreen_Previews: PreviewProvider { primaryButtonAction: "Recovery Kit", contentTitle: L10n.soLetSBreathe, contentSubtitle: { (_: Any) in L10n.YouVeUsedAll5Codes.TryAgainLater.forHelpContactSupport } - ) {} onCompletion: {} onTermsOfService: {} onPrivacyPolicy: {} onInfo: {} + ) {} onCompletion: {} onTermsOfService: {} onPrivacyPolicy: {} } } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/Screen/OnboardingBrokenScreen.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/Screen/OnboardingBrokenScreen.swift index 2336695beb..cbce2b1939 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/Screen/OnboardingBrokenScreen.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/Screen/OnboardingBrokenScreen.swift @@ -6,8 +6,6 @@ struct OnboardingBrokenScreen: View { let contentData: OnboardingContentData let back: (() async throws -> Void)? - let info: (() -> Void)? - let help: (() -> Void)? @ViewBuilder var customActions: CustomActions @@ -17,15 +15,11 @@ struct OnboardingBrokenScreen: View { title: String, contentData: OnboardingContentData, back: (() async throws -> Void)? = nil, - info: (() -> Void)? = nil, - help: (() -> Void)? = nil, @ViewBuilder customActions: () -> CustomActions ) { self.title = title self.contentData = contentData self.back = back - self.info = info - self.help = help self.customActions = customActions() } @@ -41,17 +35,6 @@ struct OnboardingBrokenScreen: View { VStack { customActions - if let help = help { - TextButtonView( - title: L10n.support, - style: .inverted, - size: .large, - leading: UIImage(resource: .newReleasesOutlined), - onPressed: { help() } - ) - .frame(height: TextButton.Size.large.height) - } - if let back = back { TextButtonView( title: L10n.startingScreen, @@ -74,8 +57,7 @@ struct OnboardingBrokenScreen: View { } .onboardingNavigationBar( title: title, - onBack: nil, - onInfo: info != nil ? { info!() } : nil + onBack: nil ) .modifier(OnboardingScreen()) } @@ -86,15 +68,12 @@ extension OnboardingBrokenScreen where CustomActions == SwiftUI.EmptyView { title: String, contentData: OnboardingContentData, back: (() async throws -> Void)? = nil, - info: (() -> Void)? = nil, - help: (() -> Void)? = nil + help _: (() -> Void)? = nil ) { self.init( title: title, contentData: contentData, back: back, - info: info, - help: help, customActions: { SwiftUI.EmptyView() } ) } @@ -110,9 +89,7 @@ struct OnboardingBrokenScreen_Previews: PreviewProvider { title: L10n.easyToStart, subtitle: L10n.createYourAccountIn1Minute ), - back: {}, - info: {}, - help: {} + back: {} ) } } diff --git a/p2p_wallet/Scenes/Web3Auth/Onboarding/View/OnboardingNavigationBar.swift b/p2p_wallet/Scenes/Web3Auth/Onboarding/View/OnboardingNavigationBar.swift index 357e51c972..f65d719b81 100644 --- a/p2p_wallet/Scenes/Web3Auth/Onboarding/View/OnboardingNavigationBar.swift +++ b/p2p_wallet/Scenes/Web3Auth/Onboarding/View/OnboardingNavigationBar.swift @@ -3,8 +3,7 @@ import SwiftUI extension View { func onboardingNavigationBar( title: String, - onBack: (() -> Void)? = nil, - onInfo: (() -> Void)? = nil + onBack: (() -> Void)? = nil ) -> some View { navigationTitle(title) .navigationBarTitleDisplayMode(.inline) @@ -15,13 +14,6 @@ extension View { Image(.arrowBackIos) .foregroundColor(Color(.night)) } - ) : nil, - trailing: onInfo != nil ? Button( - action: { onInfo?() }, - label: { - Image(.helpOutline) - .foregroundColor(Color(.night)) - } ) : nil ) } diff --git a/p2p_wallet/Scenes/Web3Auth/Reauthentication/SubFlow/CustomShare/ReAuthCustomShareDelegatedCoordinator.swift b/p2p_wallet/Scenes/Web3Auth/Reauthentication/SubFlow/CustomShare/ReAuthCustomShareDelegatedCoordinator.swift index 4ef1aadd64..842703a271 100644 --- a/p2p_wallet/Scenes/Web3Auth/Reauthentication/SubFlow/CustomShare/ReAuthCustomShareDelegatedCoordinator.swift +++ b/p2p_wallet/Scenes/Web3Auth/Reauthentication/SubFlow/CustomShare/ReAuthCustomShareDelegatedCoordinator.swift @@ -12,7 +12,7 @@ class ReAuthCustomShareDelegatedCoordinator: DelegatedCoordinator 1 { return false } - if updatedText.components(separatedBy: decimalSeparator).last?.count ?? 0 > maxFractionDigits.wrappedValue { + + if updatedText.contains(decimalSeparator) && updatedText.components(separatedBy: decimalSeparator).last? + .count ?? 0 > maxFractionDigits.wrappedValue + { + return false + } + + if Double(updatedText)?.isLamportsBiggerThanUInt64(decimals: maxFractionDigits.wrappedValue) == true { return false } + return isNotMoreThanMax(text: updatedText.amountFormat( maxAfterComma: maxFractionDigits.wrappedValue, decimalSeparator: decimalSeparator diff --git a/p2p_wallet/UI/UIKit/UISeedPhrasesTextView/UISeedPhrasesTextView.swift b/p2p_wallet/UI/UIKit/UISeedPhrasesTextView/UISeedPhrasesTextView.swift index 4b7a767e32..a07bbad0ec 100644 --- a/p2p_wallet/UI/UIKit/UISeedPhrasesTextView/UISeedPhrasesTextView.swift +++ b/p2p_wallet/UI/UIKit/UISeedPhrasesTextView/UISeedPhrasesTextView.swift @@ -20,13 +20,11 @@ public class UISeedPhrasesTextView: UITextView { }() /// Default typing attributes for text - private static let defaultTypingAttributes: [NSAttributedString.Key: Any] = { - [ - .font: UIFont.font(of: .text3), - .foregroundColor: UIColor(resource: .night), - .paragraphStyle: defaultParagraphStyle, - ] - }() + private static let defaultTypingAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.font(of: .text3), + .foregroundColor: UIColor(resource: .night), + .paragraphStyle: defaultParagraphStyle, + ] private static let defaultIndexAttributes: [NSAttributedString.Key: Any] = { var attributes = defaultTypingAttributes diff --git a/p2p_wallet/p2p_wallet.entitlements b/p2p_wallet/p2p_wallet.entitlements index 04870ebc53..826fc669b6 100644 --- a/p2p_wallet/p2p_wallet.entitlements +++ b/p2p_wallet/p2p_wallet.entitlements @@ -13,6 +13,7 @@ applinks:keyapp-te.onelink.me applinks:keyapp.onelink.me applinks:t.key.app + applinks:s.key.app com.apple.developer.icloud-container-identifiers diff --git a/project.yml b/project.yml index 1589c42ab3..784b9b3a21 100644 --- a/project.yml +++ b/project.yml @@ -18,9 +18,6 @@ packages: SwiftyUserDefaults: url: https://github.com/sunshinejr/SwiftyUserDefaults.git exactVersion: 5.3.0 - Intercom: - url: https://github.com/intercom/intercom-ios-sp - exactVersion: 15.0.3 Down: url: https://github.com/p2p-org/Down.git branch: master @@ -79,7 +76,7 @@ configFiles: settings: base: - MARKETING_VERSION: 2.9.0 + MARKETING_VERSION: 2.10.0 configs: Debug: VALIDATE_PRODUCT: false @@ -256,7 +253,6 @@ targets: product: Reachability - package: KeychainSwift - package: SwiftyUserDefaults - - package: Intercom - package: Down - package: Resolver - package: Kingfisher