diff --git a/.github/workflows/deploy_appstore.yml b/.github/workflows/deploy_appstore.yml index 815fa3d215..3b0e06403e 100644 --- a/.github/workflows/deploy_appstore.yml +++ b/.github/workflows/deploy_appstore.yml @@ -73,3 +73,4 @@ jobs: XCCONFIG_PROD_SHARED_CLOUD_CONTAINER_ID: ${{ secrets.XCCONFIG_PROD_SHARED_CLOUD_CONTAINER_ID }} XCCONFIG_PROD_PRIVATE_CLOUD_CONTAINER_ID: ${{ secrets.XCCONFIG_PROD_PRIVATE_CLOUD_CONTAINER_ID }} XCCONFIG_PROD_OPEN_SEA_API_KEY: ${{ secrets.XCCONFIG_PROD_OPEN_SEA_API_KEY }} + XCCONFIG_PROD_COINZIX_HCAPTCHA_KEY: ${{ secrets.XCCONFIG_PROD_COINZIX_HCAPTCHA_KEY }} diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index 88ae70f1da..3b315a9a85 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -74,3 +74,4 @@ jobs: XCCONFIG_DEV_SHARED_CLOUD_CONTAINER_ID: ${{ secrets.XCCONFIG_DEV_SHARED_CLOUD_CONTAINER_ID }} XCCONFIG_DEV_PRIVATE_CLOUD_CONTAINER_ID: ${{ secrets.XCCONFIG_DEV_PRIVATE_CLOUD_CONTAINER_ID }} XCCONFIG_DEV_OPEN_SEA_API_KEY: ${{ secrets.XCCONFIG_DEV_OPEN_SEA_API_KEY }} + XCCONFIG_DEV_COINZIX_HCAPTCHA_KEY: ${{ secrets.XCCONFIG_DEV_COINZIX_HCAPTCHA_KEY }} diff --git a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj index d089689403..32bb8c0c8d 100644 --- a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj +++ b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ @@ -2199,6 +2199,14 @@ D008CA63267C8DFD00001E0A /* SwapTransactionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = D008CA61267C8DFD00001E0A /* SwapTransactionRecord.swift */; }; D008CA66267C8E1800001E0A /* ApproveTransactionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = D008CA65267C8E1800001E0A /* ApproveTransactionRecord.swift */; }; D008CA67267C8E1800001E0A /* ApproveTransactionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = D008CA65267C8E1800001E0A /* ApproveTransactionRecord.swift */; }; + D020B38B2A3B2316007F3B6B /* RestoreCoinzixModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B38A2A3B2316007F3B6B /* RestoreCoinzixModule.swift */; }; + D020B38C2A3B2316007F3B6B /* RestoreCoinzixModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B38A2A3B2316007F3B6B /* RestoreCoinzixModule.swift */; }; + D020B38E2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B38D2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift */; }; + D020B38F2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B38D2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift */; }; + D020B3912A3C6086007F3B6B /* RestoreCoinzixService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B3902A3C6086007F3B6B /* RestoreCoinzixService.swift */; }; + D020B3922A3C6086007F3B6B /* RestoreCoinzixService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B3902A3C6086007F3B6B /* RestoreCoinzixService.swift */; }; + D020B3942A3C60C3007F3B6B /* RestoreCoinzixViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B3932A3C60C3007F3B6B /* RestoreCoinzixViewController.swift */; }; + D020B3952A3C60C3007F3B6B /* RestoreCoinzixViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020B3932A3C60C3007F3B6B /* RestoreCoinzixViewController.swift */; }; D023D2632A249E59004F65B0 /* TronKit in Frameworks */ = {isa = PBXBuildFile; productRef = D023D2622A249E59004F65B0 /* TronKit */; }; D023D2652A24B9DC004F65B0 /* TronKit in Frameworks */ = {isa = PBXBuildFile; productRef = D023D2642A24B9DC004F65B0 /* TronKit */; }; D023D2672A24BBC6004F65B0 /* TronAddressParserItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D023D2662A24BBC6004F65B0 /* TronAddressParserItem.swift */; }; @@ -2305,6 +2313,8 @@ D0DA740F272A6EFC0072BE86 /* UnicodeURL in Frameworks */ = {isa = PBXBuildFile; productRef = D0DA740E272A6EFC0072BE86 /* UnicodeURL */; }; D0DA7411272A6F180072BE86 /* IDNSDK in Frameworks */ = {isa = PBXBuildFile; productRef = D0DA7410272A6F180072BE86 /* IDNSDK */; }; D0DA7413272A6F180072BE86 /* UnicodeURL in Frameworks */ = {isa = PBXBuildFile; productRef = D0DA7412272A6F180072BE86 /* UnicodeURL */; }; + D0EC34DB2A4450B100BB308B /* HCaptcha in Frameworks */ = {isa = PBXBuildFile; productRef = D0EC34DA2A4450B100BB308B /* HCaptcha */; }; + D0EC34DD2A4450D200BB308B /* HCaptcha in Frameworks */ = {isa = PBXBuildFile; productRef = D0EC34DC2A4450D200BB308B /* HCaptcha */; }; D31C4760238BF176008CB818 /* MnemonicDerivation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31C4759238BF175008CB818 /* MnemonicDerivation.swift */; }; D31C4761238BF176008CB818 /* MnemonicDerivation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31C4759238BF175008CB818 /* MnemonicDerivation.swift */; }; D31C4763238BF176008CB818 /* FeeRateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31C475A238BF175008CB818 /* FeeRateState.swift */; }; @@ -3652,6 +3662,10 @@ D008CA61267C8DFD00001E0A /* SwapTransactionRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapTransactionRecord.swift; sourceTree = ""; }; D008CA65267C8E1800001E0A /* ApproveTransactionRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApproveTransactionRecord.swift; sourceTree = ""; }; D008CA69267C8E5E00001E0A /* ContractCallTransactionRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContractCallTransactionRecord.swift; sourceTree = ""; }; + D020B38A2A3B2316007F3B6B /* RestoreCoinzixModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreCoinzixModule.swift; sourceTree = ""; }; + D020B38D2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreCoinzixViewModel.swift; sourceTree = ""; }; + D020B3902A3C6086007F3B6B /* RestoreCoinzixService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreCoinzixService.swift; sourceTree = ""; }; + D020B3932A3C60C3007F3B6B /* RestoreCoinzixViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreCoinzixViewController.swift; sourceTree = ""; }; D023D2662A24BBC6004F65B0 /* TronAddressParserItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronAddressParserItem.swift; sourceTree = ""; }; D023D2692A24CD16004F65B0 /* BaseTronAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTronAdapter.swift; sourceTree = ""; }; D023D26C2A24CD4F004F65B0 /* TronKitManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronKitManager.swift; sourceTree = ""; }; @@ -3783,6 +3797,7 @@ D3604E9A28F03DC00066C366 /* Chart in Frameworks */, D3604E8E28F03DBF0066C366 /* LitecoinKit in Frameworks */, D3AF5A8F29FFD87400C1399E /* RxCocoa in Frameworks */, + D0EC34DD2A4450D200BB308B /* HCaptcha in Frameworks */, D38405B9218317DF007D50AD /* AVFoundation.framework in Frameworks */, D3604E5B28F02B280066C366 /* OneInchKit in Frameworks */, D3604EA028F03DC00066C366 /* DashKit in Frameworks */, @@ -3827,6 +3842,7 @@ D3604E4A28F02A8C0066C366 /* Eip20Kit in Frameworks */, D3C187DE290FCFE400FE1900 /* StorageKit in Frameworks */, D3604E4328F02A020066C366 /* EvmKit in Frameworks */, + D0EC34DB2A4450B100BB308B /* HCaptcha in Frameworks */, D3604E7028F03AC80066C366 /* MarketKit in Frameworks */, D36E0C2A28D084AB00B622B9 /* CollectionViewCenteredFlowLayout in Frameworks */, D3604E6628F02D9A0066C366 /* BitcoinKit in Frameworks */, @@ -5433,6 +5449,7 @@ ABC9A7E9EAE24647C0700B39 /* RestoreCloud */, 11B3523C40F1CBF81E0DAEEF /* RestoreCex */, 11B35E01AEC520D297193770 /* RestoreBinance */, + D020B3892A3B22DD007F3B6B /* RestoreCoinzix */, ); path = RestoreAccount; sourceTree = ""; @@ -6878,6 +6895,17 @@ path = TransactionRecords; sourceTree = ""; }; + D020B3892A3B22DD007F3B6B /* RestoreCoinzix */ = { + isa = PBXGroup; + children = ( + D020B38A2A3B2316007F3B6B /* RestoreCoinzixModule.swift */, + D020B3902A3C6086007F3B6B /* RestoreCoinzixService.swift */, + D020B38D2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift */, + D020B3932A3C60C3007F3B6B /* RestoreCoinzixViewController.swift */, + ); + path = RestoreCoinzix; + sourceTree = ""; + }; D023D26F2A25CF18004F65B0 /* Tron */ = { isa = PBXGroup; children = ( @@ -7210,6 +7238,7 @@ D3AF5A9029FFD87500C1399E /* RxRelay */, D3AF5A9229FFD87500C1399E /* RxSwift */, D023D2642A24B9DC004F65B0 /* TronKit */, + D0EC34DC2A4450D200BB308B /* HCaptcha */, ); productName = Wallet; productReference = D38405CE218317DF007D50AD /* Unstoppable D.app */; @@ -7273,6 +7302,7 @@ D3AF5A8A29FFD85800C1399E /* RxRelay */, D3AF5A8C29FFD85800C1399E /* RxSwift */, D023D2622A249E59004F65B0 /* TronKit */, + D0EC34DA2A4450B100BB308B /* HCaptcha */, ); productName = Wallet; productReference = D38406BE21831B3D007D50AD /* Unstoppable.app */; @@ -7284,8 +7314,9 @@ D3285F3A20BD158E00644076 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 1240; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = Grouvi; TargetAttributes = { D38404E1218317DF007D50AD = { @@ -7320,42 +7351,43 @@ D3BF1E61274CBBCE00229A00 /* XCRemoteSwiftPackageReference "DeepDiff" */, 500F1D0F27AA87BC002AA419 /* XCRemoteSwiftPackageReference "AlignedCollectionViewFlowLayout" */, D36E0C2828D084AB00B622B9 /* XCRemoteSwiftPackageReference "CollectionViewCenteredFlowLayout" */, - D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit.Swift" */, - D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit.Swift" */, - D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit.Swift" */, - D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit.Swift" */, - D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit.Swift" */, - D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit.Swift" */, - D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit.Swift" */, - D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit.Swift" */, - D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit.Swift" */, - D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit.Swift" */, - D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit.Swift" */, - D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit.Swift" */, - D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit.Swift" */, - D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart.Swift" */, - D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit.Swift" */, - D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit.Swift" */, - D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit.Swift" */, + D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit" */, + D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit" */, + D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit" */, + D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit" */, + D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit" */, + D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit" */, + D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit" */, + D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit" */, + D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit" */, + D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit" */, + D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit" */, + D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit" */, + D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit" */, + D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart" */, + D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit" */, + D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit" */, + D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit" */, D3993D9C28F41F5C008720FB /* XCRemoteSwiftPackageReference "wallet-connect-swift" */, D3993DA328F4229F008720FB /* XCRemoteSwiftPackageReference "ZcashLightClientKit" */, D3993DAA28F42549008720FB /* XCRemoteSwiftPackageReference "WalletConnectSwiftV2" */, - D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet.Swift" */, + D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet" */, D3993DC028F42992008720FB /* XCRemoteSwiftPackageReference "resolution-swift" */, - D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit.Swift" */, + D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit" */, D3C187B82907CFAB00FE1900 /* XCRemoteSwiftPackageReference "Checkpoints" */, - D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit.Swift" */, - D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit.Swift" */, - D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD.Swift" */, - D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit.Swift" */, - D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView.Swift" */, - D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit.Swift" */, - D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit.Swift" */, - 6B423FD22913785800EE5E70 /* XCRemoteSwiftPackageReference "BitcoinCore.Swift" */, + D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit" */, + D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit" */, + D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD" */, + D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit" */, + D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView" */, + D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit" */, + D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit" */, + 6B423FD22913785800EE5E70 /* XCRemoteSwiftPackageReference "BitcoinCore" */, 6BDA29A929D6EA9B003847ED /* XCRemoteSwiftPackageReference "ECashKit.Swift" */, 6BDA29AE29D6F934003847ED /* XCRemoteSwiftPackageReference "HsToolKit.Swift" */, D3AF5A8729FFD85800C1399E /* XCRemoteSwiftPackageReference "RxSwift" */, D023D2612A249E59004F65B0 /* XCRemoteSwiftPackageReference "TronKit.Swift" */, + D0EC34D92A4450B100BB308B /* XCRemoteSwiftPackageReference "HCaptcha-ios-sdk" */, ); productRefGroup = D3285F4320BD158E00644076 /* Products */; projectDirPath = ""; @@ -7796,6 +7828,7 @@ 11B353521013A50A7029634D /* CoinSettingsView.swift in Sources */, 11B35E3B729B4492425FF4C3 /* CoinSettingsService.swift in Sources */, 11B355BDB9EDD68DEC7237FC /* CoinSettingsViewModel.swift in Sources */, + D020B38F2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift in Sources */, 11B35F79E8B3DED443D2825A /* BottomMultiSelectorViewController.swift in Sources */, D02A67C0272A7460009B2C1C /* TweetsProvider.swift in Sources */, 11B358F6083936E4A6C9D021 /* CoinSettingType.swift in Sources */, @@ -8070,6 +8103,7 @@ 1A564776B26828610A295FDF /* DashAddressParserItem.swift in Sources */, 1A5648D3EC31C2E267FB97DD /* BinanceAddressParserItem.swift in Sources */, 1A56408B1A402BC99846F141 /* ZcashAddressParserItem.swift in Sources */, + D020B38C2A3B2316007F3B6B /* RestoreCoinzixModule.swift in Sources */, 11B35EE0660C0CE24235E4DF /* NftDatabaseStorage.swift in Sources */, 11B359F28FAF97AD4F7F6424 /* NftPriceRecord.swift in Sources */, 11B35D24B98C73BD43CCD80B /* NftAssetRecord.swift in Sources */, @@ -8348,6 +8382,7 @@ 11B35494E4BA9BF6A3DAA6D6 /* NftMetadataService.swift in Sources */, 11B35A4CBD60780E0870E77C /* NftAssetBriefMetadata.swift in Sources */, ABC9A63EC83A82A76E67778B /* SendNftModule.swift in Sources */, + D020B3922A3C6086007F3B6B /* RestoreCoinzixService.swift in Sources */, ABC9A36297D869E49C152CAB /* SwapRevokeConfirmationViewController.swift in Sources */, 11B35E4EC7EE205F679FE42C /* NftDoubleCell.swift in Sources */, 11B3545120AAFA7D63864614 /* NftImageView.swift in Sources */, @@ -8469,6 +8504,7 @@ 2FA5D20BC28280786A0FC3FE /* DropDownListCell.swift in Sources */, 2FA5D707CD9B268FA3CA8D8F /* TimeLockViewModel.swift in Sources */, 2FA5D06916F84E180B2AF357 /* InputOutputOrderService.swift in Sources */, + D020B3952A3C60C3007F3B6B /* RestoreCoinzixViewController.swift in Sources */, 2FA5DBD4F56DCAE4CDCAAB61 /* InputOutputOrderDataSource.swift in Sources */, 2FA5D10288617C877FDA2522 /* InputOutputOrderViewModel.swift in Sources */, 2FA5D7FD72BD25A4BE7F92D2 /* FeeRateDataSource.swift in Sources */, @@ -9002,6 +9038,7 @@ 11B35328067C30C80DF244DF /* BackupVerifyWordsViewModel.swift in Sources */, 11B354460024FA6EDB8B27DC /* BackupVerifyWordsService.swift in Sources */, 11B3508A67A63E5580A177FD /* BackupVerifyWordsViewController.swift in Sources */, + D020B38E2A3C604D007F3B6B /* RestoreCoinzixViewModel.swift in Sources */, 11B357F031383D358D4AC864 /* BackupVerifyWordsModule.swift in Sources */, 11B35D9BB292A1D23E87CED2 /* CoinSettingsView.swift in Sources */, 11B352ACA6E26098A8D28C04 /* CoinSettingsService.swift in Sources */, @@ -9276,6 +9313,7 @@ 11B35CFD84BE04CC93DE7DF9 /* UnlinkWatchViewController.swift in Sources */, 58AAAE0E85B0DFB61C94E14D /* BitcoinAddressParserItem.swift in Sources */, 1A5645C7334EED7FF57FFD47 /* DashAddressParserItem.swift in Sources */, + D020B38B2A3B2316007F3B6B /* RestoreCoinzixModule.swift in Sources */, 1A564AB8471E098F68FDB9D7 /* BinanceAddressParserItem.swift in Sources */, 1A5643C73BEDA01E4E378BEF /* ZcashAddressParserItem.swift in Sources */, 11B35837076F6B350DFA89E7 /* NftDatabaseStorage.swift in Sources */, @@ -9554,6 +9592,7 @@ ABC9AF4D82ACDFBFBDC2D23C /* MarketCardView.swift in Sources */, 11B35DC7CD9E62F3B47ECB98 /* LogoHeaderCell.swift in Sources */, 11B3516976C6C67E1EFFBD56 /* NftMetadataService.swift in Sources */, + D020B3912A3C6086007F3B6B /* RestoreCoinzixService.swift in Sources */, 11B35210D072735192AD9BC8 /* NftAssetBriefMetadata.swift in Sources */, ABC9ABA70CEF664E8E01FA7A /* SendNftModule.swift in Sources */, ABC9A8D8709EC2B40D74A97A /* SwapRevokeConfirmationViewController.swift in Sources */, @@ -9675,6 +9714,7 @@ 2FA5D10D571F6D9E3BECAF9E /* DropDownListCell.swift in Sources */, 2FA5D62A6A421EEDFE784615 /* TimeLockViewModel.swift in Sources */, 2FA5DDD1C1B4F6A483D9F089 /* InputOutputOrderService.swift in Sources */, + D020B3942A3C60C3007F3B6B /* RestoreCoinzixViewController.swift in Sources */, 2FA5D715FCD64E7FD500BC27 /* InputOutputOrderDataSource.swift in Sources */, 2FA5D75976344172376327E2 /* InputOutputOrderViewModel.swift in Sources */, 2FA5D2C0B49B98F1C55DCBF3 /* FeeRateDataSource.swift in Sources */, @@ -10108,7 +10148,7 @@ kind = branch; }; }; - 6B423FD22913785800EE5E70 /* XCRemoteSwiftPackageReference "BitcoinCore.Swift" */ = { + 6B423FD22913785800EE5E70 /* XCRemoteSwiftPackageReference "BitcoinCore" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/BitcoinCore.Swift"; requirement = { @@ -10148,7 +10188,15 @@ minimumVersion = 0.1.0; }; }; - D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit.Swift" */ = { + D0EC34D92A4450B100BB308B /* XCRemoteSwiftPackageReference "HCaptcha-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/horizontalsystems/HCaptcha-ios-sdk.git"; + requirement = { + kind = exactVersion; + version = 1.0.0; + }; + }; + D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/HsCryptoKit.Swift"; requirement = { @@ -10156,7 +10204,7 @@ version = 1.2.1; }; }; - D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit.Swift" */ = { + D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/EvmKit.Swift"; requirement = { @@ -10164,7 +10212,7 @@ version = 2.0.6; }; }; - D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit.Swift" */ = { + D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/Eip20Kit.Swift"; requirement = { @@ -10172,7 +10220,7 @@ version = 2.0.0; }; }; - D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit.Swift" */ = { + D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/NftKit.Swift"; requirement = { @@ -10180,7 +10228,7 @@ version = 2.0.0; }; }; - D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit.Swift" */ = { + D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/UniswapKit.Swift"; requirement = { @@ -10188,7 +10236,7 @@ version = 2.0.4; }; }; - D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit.Swift" */ = { + D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/OneInchKit.Swift"; requirement = { @@ -10196,7 +10244,7 @@ version = 2.0.0; }; }; - D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit.Swift" */ = { + D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/BitcoinKit.Swift"; requirement = { @@ -10204,7 +10252,7 @@ version = 2.0.0; }; }; - D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit.Swift" */ = { + D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/BitcoinCashKit.Swift"; requirement = { @@ -10212,7 +10260,7 @@ version = 2.0.0; }; }; - D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit.Swift" */ = { + D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/LitecoinKit.Swift"; requirement = { @@ -10220,7 +10268,7 @@ version = 2.0.0; }; }; - D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit.Swift" */ = { + D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/MarketKit.Swift"; requirement = { @@ -10228,7 +10276,7 @@ version = 2.0.10; }; }; - D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit.Swift" */ = { + D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/ScanQrKit.Swift"; requirement = { @@ -10236,7 +10284,7 @@ version = 2.0.0; }; }; - D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit.Swift" */ = { + D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/PinKit.Swift"; requirement = { @@ -10244,7 +10292,7 @@ version = 2.0.3; }; }; - D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit.Swift" */ = { + D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/ModuleKit.Swift"; requirement = { @@ -10252,7 +10300,7 @@ version = 2.0.0; }; }; - D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit.Swift" */ = { + D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/CurrencyKit.Swift"; requirement = { @@ -10260,7 +10308,7 @@ version = 2.0.1; }; }; - D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart.Swift" */ = { + D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/Chart.Swift"; requirement = { @@ -10268,7 +10316,7 @@ version = 1.0.5; }; }; - D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit.Swift" */ = { + D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/FeeRateKit.Swift"; requirement = { @@ -10276,7 +10324,7 @@ version = 2.0.0; }; }; - D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit.Swift" */ = { + D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/BinanceChainKit.Swift"; requirement = { @@ -10284,7 +10332,7 @@ version = 2.0.0; }; }; - D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit.Swift" */ = { + D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/DashKit.Swift"; requirement = { @@ -10324,7 +10372,7 @@ version = 1.5.7; }; }; - D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet.Swift" */ = { + D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/ActionSheet.Swift"; requirement = { @@ -10364,7 +10412,7 @@ minimumVersion = 2.3.3; }; }; - D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit.Swift" */ = { + D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/HdWalletKit.Swift"; requirement = { @@ -10380,7 +10428,7 @@ version = 1.0.11; }; }; - D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit.Swift" */ = { + D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/ThemeKit.Swift"; requirement = { @@ -10388,7 +10436,7 @@ version = 2.0.0; }; }; - D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit.Swift" */ = { + D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/ComponentKit.Swift"; requirement = { @@ -10396,7 +10444,7 @@ version = 2.0.2; }; }; - D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD.Swift" */ = { + D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/HUD.Swift"; requirement = { @@ -10404,7 +10452,7 @@ version = 2.0.0; }; }; - D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit.Swift" */ = { + D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/LanguageKit.Swift"; requirement = { @@ -10412,7 +10460,7 @@ version = 1.0.0; }; }; - D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView.Swift" */ = { + D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/SectionsTableView.Swift"; requirement = { @@ -10420,7 +10468,7 @@ version = 1.0.0; }; }; - D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit.Swift" */ = { + D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/StorageKit.Swift"; requirement = { @@ -10428,7 +10476,7 @@ version = 2.0.0; }; }; - D3E1D0092990D9BE00C68F00 /* XCRemoteSwiftPackageReference "Hodler.Swift" */ = { + D3E1D0092990D9BE00C68F00 /* XCRemoteSwiftPackageReference "Hodler" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/horizontalsystems/Hodler.Swift"; requirement = { @@ -10451,7 +10499,7 @@ }; 6B423FD32913785800EE5E70 /* BitcoinCore */ = { isa = XCSwiftPackageProductDependency; - package = 6B423FD22913785800EE5E70 /* XCRemoteSwiftPackageReference "BitcoinCore.Swift" */; + package = 6B423FD22913785800EE5E70 /* XCRemoteSwiftPackageReference "BitcoinCore" */; productName = BitcoinCore; }; 6BDA29AA29D6F37C003847ED /* ECashKit */ = { @@ -10499,184 +10547,194 @@ package = D0DA740B272A6EFC0072BE86 /* XCRemoteSwiftPackageReference "UnicodeURL" */; productName = UnicodeURL; }; + D0EC34DA2A4450B100BB308B /* HCaptcha */ = { + isa = XCSwiftPackageProductDependency; + package = D0EC34D92A4450B100BB308B /* XCRemoteSwiftPackageReference "HCaptcha-ios-sdk" */; + productName = HCaptcha; + }; + D0EC34DC2A4450D200BB308B /* HCaptcha */ = { + isa = XCSwiftPackageProductDependency; + package = D0EC34D92A4450B100BB308B /* XCRemoteSwiftPackageReference "HCaptcha-ios-sdk" */; + productName = HCaptcha; + }; D339A93C29126D0F00B895BE /* HsCryptoKit */ = { isa = XCSwiftPackageProductDependency; - package = D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit.Swift" */; + package = D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit" */; productName = HsCryptoKit; }; D339A93E29126D2A00B895BE /* HsCryptoKit */ = { isa = XCSwiftPackageProductDependency; - package = D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit.Swift" */; + package = D339A93B29126D0E00B895BE /* XCRemoteSwiftPackageReference "HsCryptoKit" */; productName = HsCryptoKit; }; D3604E4228F02A020066C366 /* EvmKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit.Swift" */; + package = D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit" */; productName = EvmKit; }; D3604E4428F02A260066C366 /* EvmKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit.Swift" */; + package = D3604E4128F02A020066C366 /* XCRemoteSwiftPackageReference "EvmKit" */; productName = EvmKit; }; D3604E4928F02A8C0066C366 /* Eip20Kit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit.Swift" */; + package = D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit" */; productName = Eip20Kit; }; D3604E4C28F02AB40066C366 /* NftKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit.Swift" */; + package = D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit" */; productName = NftKit; }; D3604E4F28F02AE70066C366 /* UniswapKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit.Swift" */; + package = D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit" */; productName = UniswapKit; }; D3604E5228F02B150066C366 /* OneInchKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit.Swift" */; + package = D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit" */; productName = OneInchKit; }; D3604E5428F02B280066C366 /* Eip20Kit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit.Swift" */; + package = D3604E4828F02A8B0066C366 /* XCRemoteSwiftPackageReference "Eip20Kit" */; productName = Eip20Kit; }; D3604E5628F02B280066C366 /* NftKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit.Swift" */; + package = D3604E4B28F02AB40066C366 /* XCRemoteSwiftPackageReference "NftKit" */; productName = NftKit; }; D3604E5828F02B280066C366 /* UniswapKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit.Swift" */; + package = D3604E4E28F02AE60066C366 /* XCRemoteSwiftPackageReference "UniswapKit" */; productName = UniswapKit; }; D3604E5A28F02B280066C366 /* OneInchKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit.Swift" */; + package = D3604E5128F02B150066C366 /* XCRemoteSwiftPackageReference "OneInchKit" */; productName = OneInchKit; }; D3604E6528F02D9A0066C366 /* BitcoinKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit.Swift" */; + package = D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit" */; productName = BitcoinKit; }; D3604E6828F02DF30066C366 /* BitcoinCashKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit.Swift" */; + package = D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit" */; productName = BitcoinCashKit; }; D3604E6B28F02E3F0066C366 /* LitecoinKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit.Swift" */; + package = D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit" */; productName = LitecoinKit; }; D3604E6F28F03AC80066C366 /* MarketKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit.Swift" */; + package = D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit" */; productName = MarketKit; }; D3604E7228F03B0A0066C366 /* ScanQrKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit.Swift" */; + package = D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit" */; productName = ScanQrKit; }; D3604E7528F03B5E0066C366 /* PinKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit.Swift" */; + package = D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit" */; productName = PinKit; }; D3604E7828F03B9F0066C366 /* ModuleKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit.Swift" */; + package = D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit" */; productName = ModuleKit; }; D3604E7B28F03BD20066C366 /* CurrencyKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit.Swift" */; + package = D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit" */; productName = CurrencyKit; }; D3604E7E28F03C1D0066C366 /* Chart */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart.Swift" */; + package = D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart" */; productName = Chart; }; D3604E8128F03C6B0066C366 /* FeeRateKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit.Swift" */; + package = D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit" */; productName = FeeRateKit; }; D3604E8428F03CDC0066C366 /* BinanceChainKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit.Swift" */; + package = D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit" */; productName = BinanceChainKit; }; D3604E8728F03D9E0066C366 /* DashKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit.Swift" */; + package = D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit" */; productName = DashKit; }; D3604E8928F03DBF0066C366 /* BitcoinKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit.Swift" */; + package = D3604E6428F02D9A0066C366 /* XCRemoteSwiftPackageReference "BitcoinKit" */; productName = BitcoinKit; }; D3604E8B28F03DBF0066C366 /* BitcoinCashKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit.Swift" */; + package = D3604E6728F02DF30066C366 /* XCRemoteSwiftPackageReference "BitcoinCashKit" */; productName = BitcoinCashKit; }; D3604E8D28F03DBF0066C366 /* LitecoinKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit.Swift" */; + package = D3604E6A28F02E3F0066C366 /* XCRemoteSwiftPackageReference "LitecoinKit" */; productName = LitecoinKit; }; D3604E8F28F03DC00066C366 /* MarketKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit.Swift" */; + package = D3604E6E28F03AC70066C366 /* XCRemoteSwiftPackageReference "MarketKit" */; productName = MarketKit; }; D3604E9128F03DC00066C366 /* ScanQrKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit.Swift" */; + package = D3604E7128F03B0A0066C366 /* XCRemoteSwiftPackageReference "ScanQrKit" */; productName = ScanQrKit; }; D3604E9328F03DC00066C366 /* PinKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit.Swift" */; + package = D3604E7428F03B5E0066C366 /* XCRemoteSwiftPackageReference "PinKit" */; productName = PinKit; }; D3604E9528F03DC00066C366 /* ModuleKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit.Swift" */; + package = D3604E7728F03B9F0066C366 /* XCRemoteSwiftPackageReference "ModuleKit" */; productName = ModuleKit; }; D3604E9728F03DC00066C366 /* CurrencyKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit.Swift" */; + package = D3604E7A28F03BD20066C366 /* XCRemoteSwiftPackageReference "CurrencyKit" */; productName = CurrencyKit; }; D3604E9928F03DC00066C366 /* Chart */ = { isa = XCSwiftPackageProductDependency; - package = D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart.Swift" */; + package = D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart" */; productName = Chart; }; D3604E9B28F03DC00066C366 /* FeeRateKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit.Swift" */; + package = D3604E8028F03C6B0066C366 /* XCRemoteSwiftPackageReference "FeeRateKit" */; productName = FeeRateKit; }; D3604E9D28F03DC00066C366 /* BinanceChainKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit.Swift" */; + package = D3604E8328F03CDC0066C366 /* XCRemoteSwiftPackageReference "BinanceChainKit" */; productName = BinanceChainKit; }; D3604E9F28F03DC00066C366 /* DashKit */ = { isa = XCSwiftPackageProductDependency; - package = D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit.Swift" */; + package = D3604E8628F03D9E0066C366 /* XCRemoteSwiftPackageReference "DashKit" */; productName = DashKit; }; D36E0C2928D084AB00B622B9 /* CollectionViewCenteredFlowLayout */ = { @@ -10721,12 +10779,12 @@ }; D3993DBA28F4277E008720FB /* ActionSheet */ = { isa = XCSwiftPackageProductDependency; - package = D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet.Swift" */; + package = D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet" */; productName = ActionSheet; }; D3993DBC28F4278F008720FB /* ActionSheet */ = { isa = XCSwiftPackageProductDependency; - package = D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet.Swift" */; + package = D3993DB928F4277E008720FB /* XCRemoteSwiftPackageReference "ActionSheet" */; productName = ActionSheet; }; D3993DC128F42992008720FB /* UnstoppableDomainsResolution */ = { @@ -10791,12 +10849,12 @@ }; D3C187B22907A60800FE1900 /* HdWalletKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit.Swift" */; + package = D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit" */; productName = HdWalletKit; }; D3C187B42907A63600FE1900 /* HdWalletKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit.Swift" */; + package = D3C187B12907A60700FE1900 /* XCRemoteSwiftPackageReference "HdWalletKit" */; productName = HdWalletKit; }; D3C187B92907CFAB00FE1900 /* Checkpoints */ = { @@ -10811,72 +10869,72 @@ }; D3C187CE290FCF2D00FE1900 /* ThemeKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit.Swift" */; + package = D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit" */; productName = ThemeKit; }; D3C187D1290FCF3D00FE1900 /* ComponentKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit.Swift" */; + package = D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit" */; productName = ComponentKit; }; D3C187D4290FCF7D00FE1900 /* HUD */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD.Swift" */; + package = D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD" */; productName = HUD; }; D3C187D7290FCF9C00FE1900 /* LanguageKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit.Swift" */; + package = D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit" */; productName = LanguageKit; }; D3C187DA290FCFBC00FE1900 /* SectionsTableView */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView.Swift" */; + package = D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView" */; productName = SectionsTableView; }; D3C187DD290FCFE400FE1900 /* StorageKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit.Swift" */; + package = D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit" */; productName = StorageKit; }; D3C187DF290FD00E00FE1900 /* ThemeKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit.Swift" */; + package = D3C187CD290FCF2D00FE1900 /* XCRemoteSwiftPackageReference "ThemeKit" */; productName = ThemeKit; }; D3C187E1290FD00E00FE1900 /* ComponentKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit.Swift" */; + package = D3C187D0290FCF3D00FE1900 /* XCRemoteSwiftPackageReference "ComponentKit" */; productName = ComponentKit; }; D3C187E3290FD00E00FE1900 /* HUD */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD.Swift" */; + package = D3C187D3290FCF7D00FE1900 /* XCRemoteSwiftPackageReference "HUD" */; productName = HUD; }; D3C187E5290FD00E00FE1900 /* LanguageKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit.Swift" */; + package = D3C187D6290FCF9C00FE1900 /* XCRemoteSwiftPackageReference "LanguageKit" */; productName = LanguageKit; }; D3C187E7290FD00E00FE1900 /* SectionsTableView */ = { isa = XCSwiftPackageProductDependency; - package = D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView.Swift" */; + package = D3C187D9290FCFBC00FE1900 /* XCRemoteSwiftPackageReference "SectionsTableView" */; productName = SectionsTableView; }; D3C187E9290FD00E00FE1900 /* StorageKit */ = { isa = XCSwiftPackageProductDependency; - package = D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit.Swift" */; + package = D3C187DC290FCFE400FE1900 /* XCRemoteSwiftPackageReference "StorageKit" */; productName = StorageKit; }; D3E1D00A2990D9BE00C68F00 /* Hodler */ = { isa = XCSwiftPackageProductDependency; - package = D3E1D0092990D9BE00C68F00 /* XCRemoteSwiftPackageReference "Hodler.Swift" */; + package = D3E1D0092990D9BE00C68F00 /* XCRemoteSwiftPackageReference "Hodler" */; productName = Hodler; }; D3E1D00C2990DA0400C68F00 /* Hodler */ = { isa = XCSwiftPackageProductDependency; - package = D3E1D0092990D9BE00C68F00 /* XCRemoteSwiftPackageReference "Hodler.Swift" */; + package = D3E1D0092990D9BE00C68F00 /* XCRemoteSwiftPackageReference "Hodler" */; productName = Hodler; }; /* End XCSwiftPackageProductDependency section */ diff --git a/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig b/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig index 0bf3ba7953..d534ccdf03 100644 --- a/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig +++ b/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig @@ -14,6 +14,7 @@ market_api_url = https:/$()/api-dev.blocksdecoded.com hs_provider_api_key = trongrid_api_key = wallet_connect_v2_project_key = +coinzix_hcaptcha_key = default_words = shared_cloud_container_id = private_cloud_container_id = diff --git a/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig b/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig index 51e68f0928..896f36c17c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig +++ b/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig @@ -14,6 +14,7 @@ market_api_url = https:/$()/api.blocksdecoded.com hs_provider_api_key = trongrid_api_key = wallet_connect_v2_project_key = +coinzix_hcaptcha_key = shared_cloud_container_id = private_cloud_container_id = open_sea_api_key = diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfigProvider.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfigProvider.swift index 1b70e76b7e..2db3450ab9 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfigProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfigProvider.swift @@ -83,6 +83,10 @@ class AppConfigProvider { (Bundle.main.object(forInfoDictionaryKey: "WallectConnectV2ProjectKey") as? String).flatMap { $0.isEmpty ? nil : $0 } } + var coinzixHCaptchaKey: String? { + (Bundle.main.object(forInfoDictionaryKey: "CoinzixHCaptchaKey") as? String).flatMap { $0.isEmpty ? nil : $0 } + } + var defaultWords: String { Bundle.main.object(forInfoDictionaryKey: "DefaultWords") as? String ?? "" } diff --git a/UnstoppableWallet/UnstoppableWallet/Info.plist b/UnstoppableWallet/UnstoppableWallet/Info.plist index ad633d5f1a..064875ec2e 100644 --- a/UnstoppableWallet/UnstoppableWallet/Info.plist +++ b/UnstoppableWallet/UnstoppableWallet/Info.plist @@ -2,6 +2,8 @@ + CoinzixHCaptchaKey + ${coinzix_hcaptcha_key} ArbiscanApiKey ${arbiscan_api_key} BscscanApiKey diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCex/RestoreCexViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCex/RestoreCexViewController.swift index b64636f20e..a8a1f141ff 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCex/RestoreCexViewController.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCex/RestoreCexViewController.swift @@ -48,14 +48,16 @@ class RestoreCexViewController: ThemeViewController { } private func openRestore(cex: Cex) { - let viewController: UIViewController + let viewController: UIViewController? switch cex { case .binance: viewController = RestoreBinanceModule.viewController(returnViewController: returnViewController) - case .coinzix: viewController = RestoreBinanceModule.viewController(returnViewController: returnViewController) + case .coinzix: viewController = RestoreCoinzixModule.viewController(returnViewController: returnViewController) } - navigationController?.pushViewController(viewController, animated: true) + if let viewController = viewController { + navigationController?.pushViewController(viewController, animated: true) + } } } diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixModule.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixModule.swift new file mode 100644 index 0000000000..18a18d0391 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixModule.swift @@ -0,0 +1,20 @@ +import UIKit + +struct RestoreCoinzixModule { + + static func viewController(returnViewController: UIViewController?) -> UIViewController? { + guard let hCaptchaKey = App.shared.appConfigProvider.coinzixHCaptchaKey else { + return nil + } + + let service = RestoreCoinzixService( + networkManager: App.shared.networkManager, + accountFactory: App.shared.accountFactory, + accountManager: App.shared.accountManager + ) + let viewModel = RestoreCoinzixViewModel(service: service) + + return RestoreCoinzixViewController(hCaptchaKey: hCaptchaKey, viewModel: viewModel, returnViewController: returnViewController) + } + +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixService.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixService.swift new file mode 100644 index 0000000000..46a05d3bb3 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixService.swift @@ -0,0 +1,74 @@ +import Combine +import ObjectMapper +import HsToolKit +import HsExtensions + +class RestoreCoinzixService { + private let networkManager: NetworkManager + private let accountFactory: AccountFactory + private let accountManager: AccountManager + private var tasks = Set() + + var username: String = "" { + didSet { + syncState() + } + } + + var password: String = "" { + didSet { + syncState() + } + } + + @PostPublished private(set) var state: State = .notReady + + init(networkManager: NetworkManager, accountFactory: AccountFactory, accountManager: AccountManager) { + self.networkManager = networkManager + self.accountFactory = accountFactory + self.accountManager = accountManager + } + + private func syncState() { + state = username.trimmingCharacters(in: .whitespaces).isEmpty || password.trimmingCharacters(in: .whitespaces).isEmpty ? .notReady : .idle(error: nil) + } + + private func createAccount(secretKey: String, token: String) { + let type: AccountType = .cex(type: .coinzix(authToken: token, secret: secretKey)) + let name = accountFactory.nextAccountName(cex: .coinzix) + let account = accountFactory.account(type: type, origin: .restored, backedUp: true, name: name) + + accountManager.save(account: account) + + state = .loggedIn + } + +} + +extension RestoreCoinzixService { + + func login(captchaToken: String) { + state = .loggingIn + + Task { [weak self, username, password, networkManager] in + do { + let (secretKey, token) = try await CoinzixCexProvider.login(username: username, password: password, captchaToken: captchaToken, networkManager: networkManager) + self?.createAccount(secretKey: secretKey, token: token) + } catch { + self?.state = .idle(error: error) + } + }.store(in: &tasks) + } + +} + +extension RestoreCoinzixService { + + enum State { + case notReady + case idle(error: Error?) + case loggingIn + case loggedIn + } + +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixViewController.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixViewController.swift new file mode 100644 index 0000000000..9fe4e4110e --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixViewController.swift @@ -0,0 +1,217 @@ +import Combine +import UIKit +import SnapKit +import ThemeKit +import ComponentKit +import SectionsTableView +import HUD +import HCaptcha + +class RestoreCoinzixViewController: KeyboardAwareViewController { + private let wrapperViewHeight: CGFloat = .heightButton + .margin16 + .heightButton + private let hcaptcha: HCaptcha + private let viewModel: RestoreCoinzixViewModel + private var webView: UIView? + private var cancellables = Set() + + private weak var returnViewController: UIViewController? + + private let tableView = SectionsTableView(style: .grouped) + + private let usernameCell = TextFieldCell() + private let passwordCell = PasswordInputCell() + + private let buttonsHolder = BottomGradientHolder() + private let loginButton = PrimaryButton() + private let logginInButton = PrimaryButton() + + private var isLoaded = false + + init?(hCaptchaKey: String, viewModel: RestoreCoinzixViewModel, returnViewController: UIViewController?) { + guard let hcaptcha = try? HCaptcha(apiKey: hCaptchaKey, baseURL: URL(string: "https://api.coinzix.com")) else { + return nil + } + + self.hcaptcha = hcaptcha + self.viewModel = viewModel + self.returnViewController = returnViewController + + super.init(scrollViews: [tableView], accessoryView: buttonsHolder) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + title = Cex.coinzix.title + + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "button.cancel".localized, style: .plain, target: self, action: #selector(onTapCancel)) + + view.addSubview(tableView) + tableView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + tableView.registerCell(forClass: DescriptionCell.self) + tableView.sectionDataSource = self + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + + usernameCell.inputPlaceholder = "restore.coinzix.sample_username".localized + usernameCell.autocapitalizationType = .none + usernameCell.onChangeText = { [weak self] in self?.viewModel.onChange(username: $0 ?? "") } + + passwordCell.set(textSecure: true) + passwordCell.onTextSecurityChange = { [weak self] in self?.passwordCell.set(textSecure: $0) } + passwordCell.inputPlaceholder = "restore.coinzix.sample_password".localized + passwordCell.onChangeText = { [weak self] in self?.viewModel.onChange(password: $0 ?? "") } + + + view.addSubview(buttonsHolder) + buttonsHolder.snp.makeConstraints { make in + make.height.equalTo(wrapperViewHeight).priority(.high) + make.leading.trailing.bottom.equalToSuperview() + } + + let stackView = UIStackView() + buttonsHolder.addSubview(stackView) + stackView.snp.makeConstraints { make in + make.edges.equalToSuperview().inset(CGFloat.margin24) + } + + stackView.axis = .vertical + stackView.spacing = .margin16 + + stackView.addArrangedSubview(loginButton) + loginButton.set(style: .yellow) + loginButton.setTitle("restore.coinzix.login".localized, for: .normal) + loginButton.addTarget(self, action: #selector(onTapLogin), for: .touchUpInside) + + stackView.addArrangedSubview(logginInButton) + logginInButton.set(style: .yellow, accessoryType: .spinner) + logginInButton.isEnabled = false + logginInButton.setTitle("restore.coinzix.login".localized, for: .normal) + + let signUpButton = PrimaryButton() + stackView.addArrangedSubview(signUpButton) + signUpButton.set(style: .transparent) + signUpButton.setTitle("restore.coinzix.sign_up".localized, for: .normal) + signUpButton.addTarget(self, action: #selector(onTapSignUp), for: .touchUpInside) + + viewModel.$loginEnabled + .receive(on: DispatchQueue.main) + .sink { [weak self] enabled in self?.loginButton.isEnabled = enabled } + .store(in: &cancellables) + + viewModel.$loginVisible + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.loginButton.isHidden = !visible } + .store(in: &cancellables) + + viewModel.$logginInVisible + .receive(on: DispatchQueue.main) + .sink { [weak self] visible in self?.logginInButton.isHidden = !visible } + .store(in: &cancellables) + + viewModel.errorPublisher + .receive(on: DispatchQueue.main) + .sink { text in HudHelper.instance.showErrorBanner(title: text) } + .store(in: &cancellables) + + viewModel.successPublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] in + HudHelper.instance.show(banner: .imported) + (self?.returnViewController ?? self)?.dismiss(animated: true) + } + .store(in: &cancellables) + + additionalContentInsets = UIEdgeInsets(top: 0, left: 0, bottom: -.margin16, right: 0) + additionalInsetsOnlyForClosedKeyboard = false + ignoreSafeAreaForAccessoryView = false + + tableView.buildSections() + isLoaded = true + + hcaptcha.configureWebView { [weak self] webview in + webview.frame = self?.view.bounds ?? CGRect.zero + self?.webView = webview + } + } + + @objc private func onTapCancel() { + dismiss(animated: true) + } + + @objc private func onTapLogin() { + view.endEditing(true) + + hcaptcha.validate(on: self.view) { [weak self] result in + do { + self?.viewModel.login(captchaToken: try result.dematerialize()) + } catch { + print("ERROR: \(error)") + } + + self?.webView?.removeFromSuperview() + } + } + + @objc private func onTapSignUp() { + UrlManager.open(url: "https://coinzix.com/sign-up") + } + +} + +extension RestoreCoinzixViewController: SectionsDataSource { + + func buildSections() -> [SectionProtocol] { + [ + Section( + id: "description", + headerState: .margin(height: .margin12), + footerState: .margin(height: .margin32), + rows: [ + Row( + id: "description-cell", + dynamicHeight: { containerWidth in + DescriptionCell.height(containerWidth: containerWidth, text: "restore.coinzix.description".localized, font: .subhead2, ignoreBottomMargin: true) + }, + bind: { cell, _ in + cell.label.text = "restore.coinzix.description".localized + cell.label.font = .subhead2 + cell.label.textColor = .themeGray + } + ) + ] + ), + Section( + id: "username", + headerState: .margin(height: .margin12), + rows: [ + StaticRow( + cell: usernameCell, + id: "username", + height: .heightSingleLineCell + ) + ] + ), + Section( + id: "password", + headerState: .margin(height: .margin16), + footerState: .margin(height: .margin32), + rows: [ + StaticRow( + cell: passwordCell, + id: "password", + height: .heightSingleLineCell + ) + ] + ) + ] + } + +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixViewModel.swift new file mode 100644 index 0000000000..57a07c9a6c --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Modules/RestoreAccount/RestoreCoinzix/RestoreCoinzixViewModel.swift @@ -0,0 +1,70 @@ +import Combine + +class RestoreCoinzixViewModel { + private let service: RestoreCoinzixService + private var cancellables = Set() + + @Published private(set) var loginEnabled = false + @Published private(set) var loginVisible = true + @Published private(set) var logginInVisible = false + + private let errorSubject = PassthroughSubject() + private let successSubject = PassthroughSubject() + + init(service: RestoreCoinzixService) { + self.service = service + + service.$state + .sink { [weak self] in self?.sync(state: $0) } + .store(in: &cancellables) + + sync(state: service.state) + } + + private func sync(state: RestoreCoinzixService.State) { + switch state { + case .notReady: + loginEnabled = false + loginVisible = true + logginInVisible = false + case .idle(let error): + loginEnabled = true + loginVisible = true + logginInVisible = false + + if error != nil { + errorSubject.send("restore.coinzix.failed_to_login".localized) + } + case .loggingIn: + loginVisible = false + logginInVisible = true + case .loggedIn: + successSubject.send() + } + } + +} + +extension RestoreCoinzixViewModel { + + var errorPublisher: AnyPublisher { + errorSubject.eraseToAnyPublisher() + } + + var successPublisher: AnyPublisher { + successSubject.eraseToAnyPublisher() + } + + func onChange(username: String) { + service.username = username + } + + func onChange(password: String) { + service.password = password + } + + func login(captchaToken: String) { + service.login(captchaToken: captchaToken) + } + +} diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/CoinzixCexProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/CoinzixCexProvider.swift index 324f28841f..417ed4d12b 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/CoinzixCexProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/Wallet/CoinzixCexProvider.swift @@ -6,7 +6,7 @@ import MarketKit import HsToolKit class CoinzixCexProvider { - private let baseUrl = "https://api.coinzix.com" + private static let baseUrl = "https://api.coinzix.com" private let networkManager: NetworkManager private let authToken: String @@ -53,7 +53,7 @@ class CoinzixCexProvider { ]) return try await networkManager.fetch( - url: baseUrl + path, + url: Self.baseUrl + path, method: .post, parameters: parameters, encoding: JSONEncoding.default, @@ -99,6 +99,32 @@ extension CoinzixCexProvider: ICexProvider { } +extension CoinzixCexProvider { + + static func login(username: String, password: String, captchaToken: String, networkManager: NetworkManager) async throws -> (String, String) { + let parameters: Parameters = [ + "username": username, + "password": password, + "g-recaptcha-response": captchaToken + ] + + let response: LoginResult = try await networkManager.fetch( + url: baseUrl + "/api/user/login", + method: .post, + parameters: parameters, + encoding: JSONEncoding.default + ) + + guard let secret = response.secret, let token = response.token, + response.status == true else { + throw LoginError.loginFailed(message: response.message ?? response.requestError ?? "") + } + + return (secret, token) + } + +} + extension CoinzixCexProvider { private struct BalancesResponse: ImmutableMappable { @@ -127,8 +153,28 @@ extension CoinzixCexProvider { } } + private struct LoginResult: ImmutableMappable { + let status: Bool + let message: String? + let requestError: String? + let secret: String? + let token: String? + + init(map: Map) throws { + status = try map.value("status") + message = try map.value("message") + requestError = try map.value("errors.request") + secret = try map.value("data.secret") + token = try map.value("token") + } + } + enum RequestError: Error { case invalidSignatureData } + enum LoginError: Error { + case loginFailed(message: String) + } + } diff --git a/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings b/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings index e3bd20ec60..ae1952145f 100644 --- a/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings +++ b/UnstoppableWallet/UnstoppableWallet/en.lproj/Localizable.strings @@ -156,6 +156,15 @@ Go to Settings - > Unstoppable and allow access to the camera."; "restore.binance.failed_to_connect" = "Failed to connect your API Key"; "restore.binance.invalid_qr_code" = "Invalid QR Code"; +// Restore Coinzix + +"restore.coinzix.description" = "Enter your email and password from Coinzix Account"; +"restore.coinzix.sign_up" = "Sign Up"; +"restore.coinzix.login" = "Log In"; +"restore.coinzix.sample_username" = "Email"; +"restore.coinzix.sample_password" = "Password"; +"restore.coinzix.failed_to_login" = "Failed to log in"; + // Coin Settings "coin_settings.title" = "Blockchain Settings"; diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 848e087c9e..b0e6313dbc 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -28,6 +28,7 @@ XCCONFIG_DEV_TWITTER_BEARER_TOKEN = ENV["XCCONFIG_DEV_TWITTER_BEARER_TOKEN"] XCCONFIG_DEV_HS_PROVIDER_API_KEY = ENV["XCCONFIG_DEV_HS_PROVIDER_API_KEY"] XCCONFIG_DEV_WALLET_CONNECT_V2_PROJECT_KEY = ENV["XCCONFIG_DEV_WALLET_CONNECT_V2_PROJECT_KEY"] XCCONFIG_DEV_OPEN_SEA_API_KEY = ENV["XCCONFIG_DEV_OPEN_SEA_API_KEY"] +XCCONFIG_DEV_COINZIX_HCAPTCHA_KEY = ENV["XCCONFIG_DEV_COINZIX_HCAPTCHA_KEY"] XCCONFIG_DEV_SHARED_CLOUD_CONTAINER_ID = ENV["XCCONFIG_DEV_SHARED_CLOUD_CONTAINER_ID"] XCCONFIG_DEV_PRIVATE_CLOUD_CONTAINER_ID = ENV["XCCONFIG_DEV_PRIVATE_CLOUD_CONTAINER_ID"] @@ -47,6 +48,7 @@ XCCONFIG_PROD_TWITTER_BEARER_TOKEN = ENV["XCCONFIG_PROD_TWITTER_BEARER_TOKEN"] XCCONFIG_PROD_HS_PROVIDER_API_KEY = ENV["XCCONFIG_PROD_HS_PROVIDER_API_KEY"] XCCONFIG_PROD_WALLET_CONNECT_V2_PROJECT_KEY = ENV["XCCONFIG_PROD_WALLET_CONNECT_V2_PROJECT_KEY"] XCCONFIG_PROD_OPEN_SEA_API_KEY = ENV["XCCONFIG_PROD_OPEN_SEA_API_KEY"] +XCCONFIG_PROD_COINZIX_HCAPTCHA_KEY = ENV["XCCONFIG_PROD_COINZIX_HCAPTCHA_KEY"] XCCONFIG_PROD_SHARED_CLOUD_CONTAINER_ID = ENV["XCCONFIG_PROD_SHARED_CLOUD_CONTAINER_ID"] XCCONFIG_PROD_PRIVATE_CLOUD_CONTAINER_ID = ENV["XCCONFIG_PROD_PRIVATE_CLOUD_CONTAINER_ID"] @@ -125,6 +127,7 @@ def apply_dev_xcconfig update_dev_xcconfig('shared_cloud_container_id', XCCONFIG_DEV_SHARED_CLOUD_CONTAINER_ID) update_dev_xcconfig('private_cloud_container_id', XCCONFIG_DEV_PRIVATE_CLOUD_CONTAINER_ID) update_dev_xcconfig('open_sea_api_key', XCCONFIG_DEV_OPEN_SEA_API_KEY) + update_dev_xcconfig('coinzix_hcaptcha_key', XCCONFIG_DEV_COINZIX_HCAPTCHA_KEY) end def apply_prod_xcconfig @@ -145,6 +148,7 @@ def apply_prod_xcconfig update_prod_xcconfig('shared_cloud_container_id', XCCONFIG_PROD_SHARED_CLOUD_CONTAINER_ID) update_prod_xcconfig('private_cloud_container_id', XCCONFIG_PROD_PRIVATE_CLOUD_CONTAINER_ID) update_prod_xcconfig('open_sea_api_key', XCCONFIG_PROD_OPEN_SEA_API_KEY) + update_prod_xcconfig('coinzix_hcaptcha_key', XCCONFIG_PROD_COINZIX_HCAPTCHA_KEY) end def force_update_devices(type, username)