diff --git a/FRW.xcodeproj/project.pbxproj b/FRW.xcodeproj/project.pbxproj index 828014c5..1776d568 100644 --- a/FRW.xcodeproj/project.pbxproj +++ b/FRW.xcodeproj/project.pbxproj @@ -1138,6 +1138,8 @@ 4E9532392CD3E4B300AAECD1 /* CustomTokenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9532372CD3E4B300AAECD1 /* CustomTokenManager.swift */; }; 4E95323E2CD5501C00AAECD1 /* CustomTokenDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E95323D2CD5501C00AAECD1 /* CustomTokenDetailView.swift */; }; 4E95323F2CD5501C00AAECD1 /* CustomTokenDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E95323D2CD5501C00AAECD1 /* CustomTokenDetailView.swift */; }; + 4E9532412CDA18FB00AAECD1 /* AddTokenSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9532402CDA18FB00AAECD1 /* AddTokenSheetView.swift */; }; + 4E9532422CDA18FB00AAECD1 /* AddTokenSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9532402CDA18FB00AAECD1 /* AddTokenSheetView.swift */; }; 4E9621D52B984EF3006859AD /* CadenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9621D42B984EF3006859AD /* CadenceManager.swift */; }; 4E9621D62B984EF3006859AD /* CadenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9621D42B984EF3006859AD /* CadenceManager.swift */; }; 4E9621D82B9850CF006859AD /* FRWAPI+Cadence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E9621D72B9850CF006859AD /* FRWAPI+Cadence.swift */; }; @@ -2437,6 +2439,7 @@ 4E9532342CD2196400AAECD1 /* SectionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionItem.swift; sourceTree = ""; }; 4E9532372CD3E4B300AAECD1 /* CustomTokenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTokenManager.swift; sourceTree = ""; }; 4E95323D2CD5501C00AAECD1 /* CustomTokenDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTokenDetailView.swift; sourceTree = ""; }; + 4E9532402CDA18FB00AAECD1 /* AddTokenSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTokenSheetView.swift; sourceTree = ""; }; 4E9621D42B984EF3006859AD /* CadenceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CadenceManager.swift; sourceTree = ""; }; 4E9621D72B9850CF006859AD /* FRWAPI+Cadence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FRWAPI+Cadence.swift"; sourceTree = ""; }; 4E9621DA2B985BAB006859AD /* cloudfunctions.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = cloudfunctions.json; sourceTree = ""; }; @@ -4951,6 +4954,7 @@ 4E9532312CD2089C00AAECD1 /* AddCustomTokenViewModel.swift */, 4E95323D2CD5501C00AAECD1 /* CustomTokenDetailView.swift */, 4E9532372CD3E4B300AAECD1 /* CustomTokenManager.swift */, + 4E9532402CDA18FB00AAECD1 /* AddTokenSheetView.swift */, ); path = CustomToken; sourceTree = ""; @@ -7050,6 +7054,7 @@ 154866F428D0FE8900D012B8 /* ViewCondition.swift in Sources */, 6A46754B28F2D50500F705A8 /* DBManager.swift in Sources */, 4EFBE5DE2BCE61FF0012968A /* WalletConnectEVMHandler.swift in Sources */, + 4E9532422CDA18FB00AAECD1 /* AddTokenSheetView.swift in Sources */, 15DC20DB27819C56000B187A /* VPrimaryButtonState.swift in Sources */, 4E5646622C06073900890E61 /* WalletAccount.swift in Sources */, 6A5D99AF2A4D5E7400C43D36 /* DAppsListViewModel.swift in Sources */, @@ -7845,6 +7850,7 @@ 6A46754A28F2D50500F705A8 /* DBManager.swift in Sources */, 1565FBB728B173960086A652 /* ExploreTabScreen.swift in Sources */, 4EFBE5DD2BCE61FF0012968A /* WalletConnectEVMHandler.swift in Sources */, + 4E9532412CDA18FB00AAECD1 /* AddTokenSheetView.swift in Sources */, 6A5D99AE2A4D5E7400C43D36 /* DAppsListViewModel.swift in Sources */, 4E5646612C06073900890E61 /* WalletAccount.swift in Sources */, 15C58B572868A4EE00BD4FC6 /* ThemeManager.swift in Sources */, diff --git a/FRW/Modules/MultiBackup/View/BackupListView.swift b/FRW/Modules/MultiBackup/View/BackupListView.swift index 8f466ac1..eb94c6a0 100644 --- a/FRW/Modules/MultiBackup/View/BackupListView.swift +++ b/FRW/Modules/MultiBackup/View/BackupListView.swift @@ -160,7 +160,7 @@ struct BackupListView: RouteableView { var phraseView: some View { VStack { HStack { - Text("Seed Phease Backup".localized) + Text("Seed Phrase Backup".localized) .font(.inter(size: 16, weight: .semibold)) .foregroundStyle(Color.Theme.Text.black8) Spacer() diff --git a/FRW/Modules/TrustProvider/TrustJSMessageHandler.swift b/FRW/Modules/TrustProvider/TrustJSMessageHandler.swift index 9d21404f..5aae7bc5 100644 --- a/FRW/Modules/TrustProvider/TrustJSMessageHandler.swift +++ b/FRW/Modules/TrustProvider/TrustJSMessageHandler.swift @@ -140,11 +140,12 @@ extension TrustJSMessageHandler: WKScriptMessageHandler { case .watchAsset: print("[Trust] watchAsset") - guard let data = extractMessage(json: json) else { - log.info("[Trust] data is missing") + guard let obj = extractObject(json: json) + else { + log.info("[Trust] data is missing\(method)") return } - handleWatchAsset(network: network, id: id, data: Data()) + handleWatchAsset(network: network, id: id, json: obj) case .addEthereumChain: log.info("[Trust] addEthereumChain") case .switchEthereumChain: @@ -402,9 +403,31 @@ extension TrustJSMessageHandler { } } - private func handleWatchAsset(network: ProviderNetwork, id: Int64, data: Data) { + private func handleWatchAsset(network: ProviderNetwork, id: Int64, json: [String: Any]) { let manager = WalletManager.shared.customTokenManager - + guard let contract = json["contract"] as? String else { + cancel(id: id) + return + } + Task { + HUD.loading() + guard let token = try await manager.findToken(evmAddress: contract) else { + HUD.dismissLoading() + DispatchQueue.main.async { + self.webVC?.webView.tw + .send(network: .ethereum, result: "false", to: id) + } + return + } + HUD.dismissLoading() + let callback: BoolClosure = { result in + DispatchQueue.main.async { + self.webVC?.webView.tw + .send(network: .ethereum, result: result ? "true" : "false", to: id) + } + } + Router.route(to: RouteMap.Wallet.addTokenSheet(token, callback)) + } } } diff --git a/FRW/Modules/Wallet/CustomToken/AddTokenSheetView.swift b/FRW/Modules/Wallet/CustomToken/AddTokenSheetView.swift new file mode 100644 index 00000000..2c1eb801 --- /dev/null +++ b/FRW/Modules/Wallet/CustomToken/AddTokenSheetView.swift @@ -0,0 +1,149 @@ +// +// AddTokenSheetView.swift +// FRW +// +// Created by cat on 11/5/24. +// + +import SwiftUI +import Kingfisher + +struct AddTokenSheetView: RouteableView & PresentActionDelegate { + var changeHeight: (() -> Void)? + + var title: String { + "" + } + + var isNavigationBarHidden: Bool { + true + } + + let customToken: CustomToken + let callback: (Bool)->() + + var body: some View { + GeometryReader { _ in + VStack(alignment: .leading,spacing: 0) { + ScrollView(showsIndicators: false) { + VStack(spacing: 0) { + HStack { + Text("Add Suggested Token".localized) + .font(.inter(size: 18, weight: .w700)) + .foregroundStyle(Color.LL.Neutrals.text) + .padding(.top, 6) + Spacer() + + Button { + onClose() + } label: { + Image("icon_close_circle_gray") + .resizable() + .frame(width: 24, height: 24) + } + } + .padding(.top, 8) + HStack { + Text("like_import_token".localized) + .font(.inter(size: 14)) + .foregroundStyle(Color.Theme.Text.black3) + .padding(.top, 12) + Spacer() + } + + Divider() + .foregroundStyle(Color.Theme.Line.line) + .padding(.top, 16) + .padding(.bottom, 16) + + tokenView() + .padding(.bottom, 16) + Spacer() + } + .padding(18) + } + } + .backgroundFill(Color.Theme.BG.bg1) + .cornerRadius([.topLeading, .topTrailing], 16) + .edgesIgnoringSafeArea(.bottom) + .overlay(alignment: .bottom) { + VPrimaryButton(model: ButtonStyle.primary, + state: .enabled, + action: { + onAdd() + }, title: "add_token".localized) + .padding(.horizontal, 18) + .padding(.bottom, 8) + } + } + .applyRouteable(self) + } + + func onClose() { + callback(false) + Router.dismiss() + } + + func customViewDidDismiss() { + callback(false) + } + + func onAdd() { + Task { + + let manager = WalletManager.shared.customTokenManager + let isExist = manager.isExist(token: customToken) + if !isExist { + await manager.add(token: customToken) + } + DispatchQueue.main.async { + HUD.success(title: "successful".localized) + self.callback(true) + Router.dismiss() + } + } + } + + func tokenView() -> some View { + HStack { + KFImage.url(URL(string: customToken.icon ?? "")) + .placeholder { + Image("placeholder") + .resizable() + } + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 40, height: 40) + .clipShape(Circle()) + + Text(customToken.name) + .font(.inter(size: 16, weight: .bold)) + .foregroundStyle(Color.Theme.Text.black) + + Spacer() + + Text(customToken.balanceValue + " " + "flow".localized.uppercased()) + .font(.inter(size: 16)) + .foregroundStyle(Color.Theme.Text.black) + } + .padding(16) + .background(Color.Theme.Background.pureWhite) + .cornerRadius(16) + } +} + +#Preview { + AddTokenSheetView( + customToken: CustomToken( + address: "", + decimals: 12, + name: "", + symbol: "", + flowIdentifier: nil, + belong: .evm, + balance: nil, + icon: nil + )) { result in + + } +} diff --git a/FRW/Modules/Wallet/CustomToken/CustomTokenDetailView.swift b/FRW/Modules/Wallet/CustomToken/CustomTokenDetailView.swift index bb620481..3c2c01b4 100644 --- a/FRW/Modules/Wallet/CustomToken/CustomTokenDetailView.swift +++ b/FRW/Modules/Wallet/CustomToken/CustomTokenDetailView.swift @@ -15,7 +15,7 @@ struct CustomTokenDetailView: RouteableView { } var body: some View { - VStack { + VStack(spacing: 12) { CustomTokenDetailView .Item( title: "Token Contract Address".localized, @@ -104,8 +104,7 @@ extension CustomTokenDetailView { decimals: 3, name: "Flow Test", symbol: "FLOW", - userId: "", - belongAddress: "" + belong: .evm ) ) } diff --git a/FRW/Modules/Wallet/CustomToken/CustomTokenManager.swift b/FRW/Modules/Wallet/CustomToken/CustomTokenManager.swift index 50a311f8..10d8ba62 100644 --- a/FRW/Modules/Wallet/CustomToken/CustomTokenManager.swift +++ b/FRW/Modules/Wallet/CustomToken/CustomTokenManager.swift @@ -66,12 +66,19 @@ class CustomTokenManager: ObservableObject { func isExist(token: CustomToken) -> Bool { queue.sync { let result = allTokens.filter { model in - token.belongAddress == model.belongAddress && token.network == model.network && token.belong == model.belong && token.userId == model.userId + token.belongAddress == model.belongAddress && token.network == model.network && token.belong == model.belong && token.userId == model.userId && model.address == token.address } return result.count > 0 } } + func allowDelete(token: CustomToken) -> Bool { + guard !isInWhite(token: token) else { + return false + } + return isExist(token: token) + } + func add(token: CustomToken) async { guard !isExist(token: token) else { return @@ -87,9 +94,22 @@ class CustomTokenManager: ObservableObject { WalletManager.shared.addCustomToken(token: tmpToken) } + func delete(token: CustomToken) { + queue.sync { + allTokens.removeAll { model in + token.belongAddress == model.belongAddress && token.network == model.network && token.belong == model.belong && token.userId == model.userId && model.address == token.address + } + LocalUserDefaults.shared.customToken = allTokens + } + refresh() + WalletManager.shared.deleteCustomToken(token: token) + } + private func update(token: CustomToken) { queue.sync { - let index = allTokens.firstIndex { $0.address == token.address } + let index = allTokens.firstIndex { model in + token.belongAddress == model.belongAddress && token.network == model.network && token.belong == model.belong && token.userId == model.userId && model.address == token.address + } guard let index else { return } @@ -102,9 +122,6 @@ class CustomTokenManager: ObservableObject { extension CustomTokenManager { func findToken(evmAddress: String) async throws -> CustomToken? { let evmAddress = evmAddress.addHexPrefix() - guard let uid = UserManager.shared.activatedUID, let belongAddress = WalletManager.shared.getWatchAddressOrChildAccountAddressOrPrimaryAddress() else { - throw AddCustomTokenError.invalidProfile - } guard let web3 = try await FlowProvider.Web3.default() else{ throw AddCustomTokenError.providerFailed @@ -133,8 +150,6 @@ extension CustomTokenManager { name: name, symbol: symbol, flowIdentifier: flowIdentifier, - userId: uid, - belongAddress: belongAddress, belong: .evm ) return token @@ -201,6 +216,31 @@ struct CustomToken: Codable { var belong: CustomToken.Belong = .flow // not store, var balance: BigUInt? + var icon: String? = nil + + init( + address: String, + decimals: Int, + name: String, + symbol: String, + flowIdentifier: String? = nil, + belong: CustomToken.Belong = .evm, + balance: BigUInt? = nil, + icon: String? = nil + ) { + self.address = address + self.decimals = decimals + self.name = name + self.symbol = symbol + self.belong = belong + self.balance = balance + self.flowIdentifier = flowIdentifier + + self.userId = UserManager.shared.activatedUID ?? "" + self.belongAddress = WalletManager.shared.getWatchAddressOrChildAccountAddressOrPrimaryAddress() ?? "" + self.network = LocalUserDefaults.shared.flowNetwork + + } func toToken() -> TokenModel { TokenModel( @@ -219,6 +259,26 @@ struct CustomToken: Codable { evmAddress: nil ) } + + var balanceValue: String { + let balance = balance ?? BigUInt(0) + let result = Utilities.formatToPrecision( + balance, + units: .custom(decimals), + formattingDecimals: decimals + ) + return result + } +} + +extension TokenModel { + func findCustomToken() -> CustomToken? { + let result = WalletManager.shared.customTokenManager.list + .filter { + $0.address == getAddress() && $0.name == name + }.first + return result + } } enum AddCustomTokenError: Error { diff --git a/FRW/Modules/Wallet/TokenDetail/TokenDetailView.swift b/FRW/Modules/Wallet/TokenDetail/TokenDetailView.swift index 66dbc0d9..4ea0a7bb 100644 --- a/FRW/Modules/Wallet/TokenDetail/TokenDetailView.swift +++ b/FRW/Modules/Wallet/TokenDetail/TokenDetailView.swift @@ -56,6 +56,15 @@ struct TokenDetailView: RouteableView { MoveTokenView(tokenModel: vm.token, isPresent: $vm.showSheet) } } + .navigationBarItems(trailing: HStack(spacing: 6) { + Menu(systemImage: "ellipsis") { + Button("Delete EFT", systemImage: "trash") { + vm.deleteCustomToken() + } + } + .foregroundStyle(Color.Theme.Background.icon) + .visibility(vm.showDeleteToken ? .visible : .gone) + }) } var summaryView: some View { diff --git a/FRW/Modules/Wallet/TokenDetail/TokenDetailViewModel.swift b/FRW/Modules/Wallet/TokenDetail/TokenDetailViewModel.swift index ade1308f..a493f2c4 100644 --- a/FRW/Modules/Wallet/TokenDetail/TokenDetailViewModel.swift +++ b/FRW/Modules/Wallet/TokenDetail/TokenDetailViewModel.swift @@ -115,6 +115,7 @@ class TokenDetailViewModel: ObservableObject { @Published var showSwapButton: Bool = true @Published var showBuyButton: Bool = true + @Published var showDeleteToken: Bool = false @Published var showSheet: Bool = false var buttonAction: TokenDetailViewModel.Action = .none @@ -245,6 +246,14 @@ extension TokenDetailViewModel { showSheet = true } } + + func deleteCustomToken() { + guard let customToken = token.findCustomToken() else { + return + } + WalletManager.shared.customTokenManager.delete(token: customToken) + HUD.success(title: "") + } } // MARK: - Fetch & Refresh @@ -355,7 +364,7 @@ extension TokenDetailViewModel { // Swap if (RemoteConfigManager.shared.config?.features.swap ?? false) == true { // don't show when current is Linked account - if ChildAccountManager.shared.selectedChildAccount != nil { + if ChildAccountManager.shared.selectedChildAccount != nil || ChildAccountManager.shared.selectedChildAccount != nil { showSwapButton = false } else { showSwapButton = true @@ -375,5 +384,8 @@ extension TokenDetailViewModel { } else { showBuyButton = false } + // delete custom token + showDeleteToken = token.findCustomToken() != nil + } } diff --git a/FRW/Resource/en.lproj/Localizable.strings b/FRW/Resource/en.lproj/Localizable.strings index f213b635..09c318c3 100644 --- a/FRW/Resource/en.lproj/Localizable.strings +++ b/FRW/Resource/en.lproj/Localizable.strings @@ -1043,3 +1043,6 @@ Please create backups for your wallet to ensure you retain access to your Flow a "Token Decimal" = "Token Decimal"; "Flow Identifier" = "Flow Identifier"; "Add Custom Token" = "Add Custom Token"; +"Seed Phrase Backup" = "Seed Phrase Backup"; +"Add Suggested Token" = "Add Suggested Token"; +"like_import_token" = "Would you like to import this token?"; diff --git a/FRW/Services/Manager/WalletConnect/WalletConnectChildHandlerProtocol.swift b/FRW/Services/Manager/WalletConnect/WalletConnectChildHandlerProtocol.swift index 98ea1c35..e985cbb7 100644 --- a/FRW/Services/Manager/WalletConnect/WalletConnectChildHandlerProtocol.swift +++ b/FRW/Services/Manager/WalletConnect/WalletConnectChildHandlerProtocol.swift @@ -22,6 +22,7 @@ protocol WalletConnectChildHandlerProtocol { func handlePersonalSignRequest(request: WalletConnectSign.Request, confirm: @escaping (String) -> Void, cancel: @escaping () -> Void) func handleSendTransactionRequest(request: WalletConnectSign.Request, confirm: @escaping (String) -> Void, cancel: @escaping () -> Void) func handleSignTypedDataV4(request: WalletConnectSign.Request, confirm: @escaping (String) -> Void, cancel: @escaping () -> Void) + func handleWatchAsset(request: WalletConnectSign.Request, confirm: @escaping (String) -> Void, cancel: @escaping () -> Void) } extension WalletConnectChildHandlerProtocol { diff --git a/FRW/Services/Manager/WalletConnect/WalletConnectEVMHandler.swift b/FRW/Services/Manager/WalletConnect/WalletConnectEVMHandler.swift index 4660d448..7b884219 100644 --- a/FRW/Services/Manager/WalletConnect/WalletConnectEVMHandler.swift +++ b/FRW/Services/Manager/WalletConnect/WalletConnectEVMHandler.swift @@ -22,6 +22,7 @@ enum WalletConnectEVMMethod: String, Codable, CaseIterable { case signTypedDataV3 = "eth_signTypedData_v3" case signTypedDataV4 = "eth_signTypedData_v4" case switchEthereumChain = "wallet_switchEthereumChain" + case watchAsset = "wallet_watchAsset" } extension Flow.ChainID { @@ -255,6 +256,36 @@ struct WalletConnectEVMHandler: WalletConnectChildHandlerProtocol { cancel() } } + + func handleWatchAsset( + request: Request, + confirm: @escaping (String) -> Void, + cancel: @escaping () -> Void + ) { + guard let model = try? request.params.get(WalletConnectEVMHandler.WatchAsset.self), let address = model.options?.address else { + cancel() + return + } + Task { + + HUD.loading() + let manager = WalletManager.shared.customTokenManager + guard let token = try await manager.findToken(evmAddress: address) else { + HUD.dismissLoading() + DispatchQueue.main.async { + confirm("false") + } + return + } + HUD.dismissLoading() + let callback: BoolClosure = { result in + DispatchQueue.main.async { + confirm(result ? "true" : "false") + } + } + Router.route(to: RouteMap.Wallet.addTokenSheet(token, callback)) + } + } } extension WalletConnectEVMHandler { @@ -268,3 +299,19 @@ extension WalletConnectEVMHandler { return WalletManager.shared.signSync(signableData: data) } } + +extension WalletConnectEVMHandler { + private struct WatchAsset: Codable { + struct Info: Codable { + let address: String? + } + let options: WatchAsset.Info? + let type: String? + + var isERC20: Bool { + type?.lowercased() == "ERC20".lowercased() + } + } + + +} diff --git a/FRW/Services/Manager/WalletConnect/WalletConnectFlowHandler.swift b/FRW/Services/Manager/WalletConnect/WalletConnectFlowHandler.swift index 8844b330..f521d1e9 100644 --- a/FRW/Services/Manager/WalletConnect/WalletConnectFlowHandler.swift +++ b/FRW/Services/Manager/WalletConnect/WalletConnectFlowHandler.swift @@ -54,4 +54,12 @@ struct WalletConnectFlowHandler: WalletConnectChildHandlerProtocol { func handleSignTypedDataV4(request: Request, confirm: @escaping (String) -> Void, cancel: @escaping () -> Void) { cancel() } + + func handleWatchAsset( + request: Request, + confirm: @escaping (String) -> Void, + cancel: @escaping () -> Void + ) { + cancel() + } } diff --git a/FRW/Services/Manager/WalletConnect/WalletConnectHandler.swift b/FRW/Services/Manager/WalletConnect/WalletConnectHandler.swift index a562ac84..e638dfee 100644 --- a/FRW/Services/Manager/WalletConnect/WalletConnectHandler.swift +++ b/FRW/Services/Manager/WalletConnect/WalletConnectHandler.swift @@ -84,6 +84,11 @@ struct WalletConnectHandler { let handle = current(request: request) handle.handleSignTypedDataV4(request: request, confirm: confirm, cancel: cancel) } + + func handleWatchAsset(request: WalletConnectSign.Request,confirm: @escaping (String) -> Void, cancel: @escaping () -> Void) { + let handle = current(request: request) + handle.handleWatchAsset(request: request, confirm: confirm, cancel: cancel) + } } extension WalletConnectHandler { diff --git a/FRW/Services/Manager/WalletConnect/WalletConnectManager.swift b/FRW/Services/Manager/WalletConnect/WalletConnectManager.swift index a5dc8798..86b6d3cb 100644 --- a/FRW/Services/Manager/WalletConnect/WalletConnectManager.swift +++ b/FRW/Services/Manager/WalletConnect/WalletConnectManager.swift @@ -553,6 +553,8 @@ extension WalletConnectManager { handleSignTypedData(sessionRequest) case WalletConnectEVMMethod.signTypedDataV4.rawValue: handleSignTypedData(sessionRequest) + case WalletConnectEVMMethod.watchAsset.rawValue: + handleWatchAsset(sessionRequest) default: rejectRequest(request: sessionRequest, reason: "unspport method") } @@ -602,13 +604,36 @@ extension WalletConnectManager { self.rejectRequest(request: sessionRequest) } } + + private func handleWatchAsset(_ sessionRequest: WalletConnectSign.Request) { + handler.handleWatchAsset(request: sessionRequest) { result in + Task { + do { + try await Sign.instance + .respond( + topic: sessionRequest.topic, + requestId: sessionRequest.id, + response: .response(AnyCodable(result)) + ) + } catch { + self.rejectRequest(request: sessionRequest) + log.error("[EVM] Add Custom Token Error: \(error)") + } + } + + } cancel: { + log.error("[EVM] invalid token") + self.rejectRequest(request: sessionRequest) + } + + } } // MARK: - Action extension WalletConnectManager { private func approveSession(proposal: Session.Proposal) { - guard let account = WalletManager.shared.getPrimaryWalletAddress() else { + guard WalletManager.shared.getPrimaryWalletAddress() != nil else { return } diff --git a/FRW/Services/Manager/WalletManager.swift b/FRW/Services/Manager/WalletManager.swift index 45910d6a..bd0ee46d 100644 --- a/FRW/Services/Manager/WalletManager.swift +++ b/FRW/Services/Manager/WalletManager.swift @@ -782,17 +782,15 @@ extension WalletManager { }) if let result = result { self.activatedCoins.append(result) - } else { - self.activatedCoins.append(item.toTokenModel()) + self.coinBalances[item.symbol] = item.flowBalance } - self.coinBalances[item.symbol] = item.flowBalance } } } } private func fetchCustomBalance() async throws { - guard let evmAddress = EVMAccountManager.shared.selectedAccount?.showAddress else { + guard (EVMAccountManager.shared.selectedAccount?.showAddress) != nil else { return } await customTokenManager.fetchAllEVMBalance() @@ -817,6 +815,15 @@ extension WalletManager { self.coinBalances[token.symbol] = result } } + + func deleteCustomToken(token: CustomToken) { + DispatchQueue.main.async { + self.activatedCoins.removeAll { model in + model.getAddress() == token.address && model.name == token.name + } + self.coinBalances[token.symbol] = nil + } + } func fetchAccessible() async throws { try await accessibleManager.fetchFT() diff --git a/FRW/Services/Router/RouteMap.swift b/FRW/Services/Router/RouteMap.swift index 28cae871..e7fbf5b4 100644 --- a/FRW/Services/Router/RouteMap.swift +++ b/FRW/Services/Router/RouteMap.swift @@ -15,6 +15,7 @@ enum RouteMap {} typealias EmptyClosure = () -> Void typealias SwitchNetworkClosure = (LocalUserDefaults.FlowNetworkType) -> Void +typealias BoolClosure = (Bool) -> Void // MARK: - Restore Login @@ -205,6 +206,7 @@ extension RouteMap { case chooseChild(MoveAccountsViewModel) case addCustomToken case showCustomToken(CustomToken) + case addTokenSheet(CustomToken,BoolClosure) } } @@ -296,6 +298,14 @@ extension RouteMap.Wallet: RouterTarget { navi.push(content: AddCustomTokenView()) case .showCustomToken(let token): navi.push(content: CustomTokenDetailView(token: token)) + case .addTokenSheet(let token, let callback): + let vc = PresentHostingController( + rootView: AddTokenSheetView( + customToken: token, + callback: callback + ) + ) + navi.present(vc, completion: nil) } } }