From 2fa88c44a34f85d7fd9d8c868a89af581552566d Mon Sep 17 00:00:00 2001 From: Esenbek Date: Mon, 30 Dec 2024 17:07:28 +0600 Subject: [PATCH] Add Chainalysis sanctioned address check --- .github/workflows/deploy_appstore.yml | 1 + .github/workflows/deploy_dev.yml | 1 + .../project.pbxproj | 6 ++ .../Development.template.xcconfig | 1 + .../Production.template.xcconfig | 1 + .../Address/AddressSecurityCheckerChain.swift | 11 ++-- .../Address/ChainalysisAddressValidator.swift | 57 +++++++++++++++++++ .../Core/Address/SpamAddressDetector.swift | 6 +- .../AddressSecurityCheckerFactory.swift | 2 + .../Core/Providers/AppConfig.swift | 4 ++ .../UnstoppableWallet/Info.plist | 2 + .../AddressView/AddressViewModelNew.swift | 14 ++--- .../AddressMultiSwapSettingsViewModel.swift | 2 +- fastlane/Fastfile | 6 +- 14 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 UnstoppableWallet/UnstoppableWallet/Core/Address/ChainalysisAddressValidator.swift diff --git a/.github/workflows/deploy_appstore.yml b/.github/workflows/deploy_appstore.yml index ab08d1c43c..f2ee662cc7 100644 --- a/.github/workflows/deploy_appstore.yml +++ b/.github/workflows/deploy_appstore.yml @@ -68,6 +68,7 @@ jobs: XCCONFIG_PROD_OPEN_SEA_API_KEY: ${{ secrets.XCCONFIG_PROD_OPEN_SEA_API_KEY }} XCCONFIG_PROD_TRONGRID_API_KEY: ${{ secrets.XCCONFIG_PROD_TRONGRID_API_KEY }} XCCONFIG_PROD_UNSTOPPABLE_DOMAINS_API_KEY: ${{ secrets.XCCONFIG_PROD_UNSTOPPABLE_DOMAINS_API_KEY }} + XCCONFIG_PROD_CHAINALYSIS_API_KEY: ${{ secrets.XCCONFIG_PROD_CHAINALYSIS_API_KEY }} XCCONFIG_PROD_ONE_INCH_API_KEY: ${{ secrets.XCCONFIG_PROD_ONE_INCH_API_KEY }} XCCONFIG_PROD_ONE_INCH_COMMISSION: ${{ secrets.XCCONFIG_PROD_ONE_INCH_COMMISSION }} XCCONFIG_PROD_ONE_INCH_COMMISSION_ADDRESS: ${{ secrets.XCCONFIG_PROD_ONE_INCH_COMMISSION_ADDRESS }} diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index 4363343837..bd512b90eb 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -69,6 +69,7 @@ jobs: XCCONFIG_DEV_OPEN_SEA_API_KEY: ${{ secrets.XCCONFIG_DEV_OPEN_SEA_API_KEY }} XCCONFIG_DEV_TRONGRID_API_KEY: ${{ secrets.XCCONFIG_DEV_TRONGRID_API_KEY }} XCCONFIG_DEV_UNSTOPPABLE_DOMAINS_API_KEY: ${{ secrets.XCCONFIG_DEV_UNSTOPPABLE_DOMAINS_API_KEY }} + XCCONFIG_DEV_CHAINALYSIS_API_KEY: ${{ secrets.XCCONFIG_DEV_CHAINALYSIS_API_KEY }} XCCONFIG_DEV_ONE_INCH_API_KEY: ${{ secrets.XCCONFIG_DEV_ONE_INCH_API_KEY }} XCCONFIG_DEV_ONE_INCH_COMMISSION: ${{ secrets.XCCONFIG_DEV_ONE_INCH_COMMISSION }} XCCONFIG_DEV_ONE_INCH_COMMISSION_ADDRESS: ${{ secrets.XCCONFIG_DEV_ONE_INCH_COMMISSION_ADDRESS }} diff --git a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj index e525b3219c..ddace4f67b 100644 --- a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj +++ b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj @@ -2552,6 +2552,8 @@ D0532CC52B149E450015DF40 /* WatchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0532CC32B149E450015DF40 /* WatchService.swift */; }; D054DAE32BE5123F0040B7C9 /* InitialTransactionSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054DAE22BE5123F0040B7C9 /* InitialTransactionSettings.swift */; }; D054DAE42BE5123F0040B7C9 /* InitialTransactionSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D054DAE22BE5123F0040B7C9 /* InitialTransactionSettings.swift */; }; + D05C8E8A2D22931A006EE778 /* ChainalysisAddressValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05C8E892D22931A006EE778 /* ChainalysisAddressValidator.swift */; }; + D05C8E8B2D22931A006EE778 /* ChainalysisAddressValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05C8E892D22931A006EE778 /* ChainalysisAddressValidator.swift */; }; D05E968D2A25D6C6002CCD71 /* Trc20Adapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05E968C2A25D6C6002CCD71 /* Trc20Adapter.swift */; }; D05E968E2A25D6C6002CCD71 /* Trc20Adapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05E968C2A25D6C6002CCD71 /* Trc20Adapter.swift */; }; D05E96902A261D82002CCD71 /* TronTransactionAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05E968F2A261D82002CCD71 /* TronTransactionAdapter.swift */; }; @@ -4536,6 +4538,7 @@ D0532CC02B149E110015DF40 /* WatchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchViewController.swift; sourceTree = ""; }; D0532CC32B149E450015DF40 /* WatchService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchService.swift; sourceTree = ""; }; D054DAE22BE5123F0040B7C9 /* InitialTransactionSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialTransactionSettings.swift; sourceTree = ""; }; + D05C8E892D22931A006EE778 /* ChainalysisAddressValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainalysisAddressValidator.swift; sourceTree = ""; }; D05E968C2A25D6C6002CCD71 /* Trc20Adapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trc20Adapter.swift; sourceTree = ""; }; D05E968F2A261D82002CCD71 /* TronTransactionAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronTransactionAdapter.swift; sourceTree = ""; }; D05E96922A261DC1002CCD71 /* TronTransactionConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronTransactionConverter.swift; sourceTree = ""; }; @@ -7102,6 +7105,7 @@ 58AAA0C31F14444C22ACF393 /* Address */ = { isa = PBXGroup; children = ( + D05C8E892D22931A006EE778 /* ChainalysisAddressValidator.swift */, D0F766CE2D1AD36200E409AD /* SpamAddressDetector.swift */, D06F60012D195FBC0033A288 /* AddressSecurityCheckerChain.swift */, 58AAA7305EF2A12D3DC82B32 /* AddressParserChain.swift */, @@ -9878,6 +9882,7 @@ D087627729815DAE00E6FFD4 /* ChooseWatchViewModel.swift in Sources */, 11B35FBC1AFDCF0DB8362C88 /* CoinAnalyticsModule.swift in Sources */, D0118E4C2B7CC63300D55CE6 /* ResendBitcoinViewController.swift in Sources */, + D05C8E8A2D22931A006EE778 /* ChainalysisAddressValidator.swift in Sources */, D389BC4D2C0DDCF500724504 /* MarketAdvancedSearchBlockchainsView.swift in Sources */, 11B3518BEA8865CADA5DA684 /* LaunchScreenManager.swift in Sources */, D07157DC2A2DD968006F141F /* SendTronModule.swift in Sources */, @@ -11367,6 +11372,7 @@ D36DE0E4272FD887000BC916 /* OneInchService.swift in Sources */, D05E969A2A26278D002CCD71 /* TronApproveTransactionRecord.swift in Sources */, D05E969D2A2627AF002CCD71 /* TronContractCallTransactionRecord.swift in Sources */, + D05C8E8B2D22931A006EE778 /* ChainalysisAddressValidator.swift in Sources */, D36DE0C9272FD864000BC916 /* UniswapProvider.swift in Sources */, D00DAE452B626C2900F48E1D /* GasPrice.swift in Sources */, D087627629815DAE00E6FFD4 /* ChooseWatchViewModel.swift in Sources */, diff --git a/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig b/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig index 8a6156620b..a0f4beb9a7 100644 --- a/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig +++ b/UnstoppableWallet/UnstoppableWallet/Configuration/Development.template.xcconfig @@ -18,6 +18,7 @@ private_cloud_container_id = iCloud.io.horizontalsystems.bank-wallet.dev open_sea_api_key = unstoppable_domains_api_key = one_inch_api_key = +chainalysis_api_key = one_inch_commission = one_inch_commission_address = swap_enabled = true diff --git a/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig b/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig index aa8cbd451b..7eacc00149 100644 --- a/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig +++ b/UnstoppableWallet/UnstoppableWallet/Configuration/Production.template.xcconfig @@ -17,6 +17,7 @@ shared_cloud_container_id = iCloud.io.horizontalsystems.bank-wallet.shared private_cloud_container_id = iCloud.io.horizontalsystems.bank-wallet open_sea_api_key = unstoppable_domains_api_key = +chainalysis_api_key = one_inch_api_key = one_inch_commission = one_inch_commission_address = diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressSecurityCheckerChain.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressSecurityCheckerChain.swift index 39298cf995..a803046d56 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressSecurityCheckerChain.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/AddressSecurityCheckerChain.swift @@ -5,7 +5,7 @@ import RxRelay import RxSwift protocol IAddressSecurityCheckerItem: AnyObject { - func handle(address: Address) -> Single + func handle(address: Address) -> Single } class AddressSecurityCheckerChain { @@ -24,22 +24,21 @@ extension AddressSecurityCheckerChain { return self } - func handle(address: Address) -> Single<[SecurityCheckResult]> { - Single.zip(handlers.map { handler -> Single in + func handle(address: Address) -> Single<[SecurityIssue]> { + Single.zip(handlers.map { handler -> Single in handler.handle(address: address) }) + .map { $0.compactMap { $0 } } } } extension AddressSecurityCheckerChain { - public enum SecurityCheckResult { - case valid + public enum SecurityIssue { case spam(transactionHash: String) case sanctioned(description: String) public var description: String? { switch self { - case .valid: return nil case let .spam(transactionHash): return "Possibly phishing address. Transaction hash: \(transactionHash)" case let .sanctioned(description): return description } diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/ChainalysisAddressValidator.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/ChainalysisAddressValidator.swift new file mode 100644 index 0000000000..c847f19114 --- /dev/null +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/ChainalysisAddressValidator.swift @@ -0,0 +1,57 @@ +import Alamofire +import Foundation +import HsToolKit +import ObjectMapper +import RxSwift + +class ChainalysisAddressValidator { + private let baseUrl = "https://public.chainalysis.com/api/v1/address/" + private let networkManager: NetworkManager + private let headers: HTTPHeaders + + init(networkManager: NetworkManager) { + self.networkManager = networkManager + + headers = HTTPHeaders([ + HTTPHeader(name: "X-API-KEY", value: AppConfig.chainalysisApiKey), + HTTPHeader(name: "Accept", value: "application/json"), + ]) + } +} + +extension ChainalysisAddressValidator: IAddressSecurityCheckerItem { + func handle(address: Address) -> Single { + let request = networkManager.session.request("\(baseUrl)\(address.raw)", headers: headers) + let response: Single = networkManager.single(request: request) + + return response.map { + if $0.identifications.isEmpty { + return nil + } + + return .sanctioned(description: "Sanctioned address. \($0.identifications.count) identifications found.") + } + } +} + +public struct ChainalysisAddressValidatorResponse: ImmutableMappable { + public let identifications: [Identification] + + public init(map: Map) throws { + identifications = try map.value("identifications") + } + + public struct Identification: ImmutableMappable { + public let category: String + public let name: String? + public let description: String? + public let url: String? + + public init(map: Map) throws { + category = try map.value("category") + name = try map.value("name") + description = try map.value("description") + url = try map.value("url") + } + } +} diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Address/SpamAddressDetector.swift b/UnstoppableWallet/UnstoppableWallet/Core/Address/SpamAddressDetector.swift index ec90e60738..9f06b8d7b5 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Address/SpamAddressDetector.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Address/SpamAddressDetector.swift @@ -9,14 +9,12 @@ class SpamAddressDetector { } extension SpamAddressDetector: IAddressSecurityCheckerItem { - func handle(address: Address) -> Single { - let result: AddressSecurityCheckerChain.SecurityCheckResult + func handle(address: Address) -> Single { + var result: AddressSecurityCheckerChain.SecurityIssue? = nil let spamAddress = spamAddressManager.find(address: address.raw.uppercased()) if let spamAddress { result = .spam(transactionHash: spamAddress.transactionHash.hs.hexString) - } else { - result = .valid } return Single.just(result) diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressSecurityCheckerFactory.swift b/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressSecurityCheckerFactory.swift index 85ea2cc9bf..421d549045 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressSecurityCheckerFactory.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Factories/AddressSecurityCheckerFactory.swift @@ -5,9 +5,11 @@ enum AddressSecurityCheckerFactory { switch blockchainType { case .ethereum, .gnosis, .fantom, .polygon, .arbitrumOne, .avalanche, .optimism, .binanceSmartChain, .base: let evmAddressSecurityCheckerItem = SpamAddressDetector() + let chainalysisAddressValidator = ChainalysisAddressValidator(networkManager: App.shared.networkManager) var handlers = [IAddressSecurityCheckerItem]() handlers.append(evmAddressSecurityCheckerItem) + handlers.append(chainalysisAddressValidator) return handlers default: diff --git a/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift b/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift index cf4fa7d58f..f394e6354d 100644 --- a/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift +++ b/UnstoppableWallet/UnstoppableWallet/Core/Providers/AppConfig.swift @@ -172,6 +172,10 @@ enum AppConfig { (Bundle.main.object(forInfoDictionaryKey: "OpenSeaApiKey") as? String) ?? "" } + static var chainalysisApiKey: String { + (Bundle.main.object(forInfoDictionaryKey: "ChainalysisApiKey") as? String) ?? "" + } + static var swapEnabled: Bool { Bundle.main.object(forInfoDictionaryKey: "SwapEnabled") as? String == "true" } diff --git a/UnstoppableWallet/UnstoppableWallet/Info.plist b/UnstoppableWallet/UnstoppableWallet/Info.plist index 2c801cddb9..ee5355676c 100644 --- a/UnstoppableWallet/UnstoppableWallet/Info.plist +++ b/UnstoppableWallet/UnstoppableWallet/Info.plist @@ -140,6 +140,8 @@ ${swap_enabled} TronGridApiKey ${trongrid_api_key} + ChainalysisApiKey + ${chainalysis_api_key} TwitterBearerToken ${twitter_bearer_token} UIApplicationSceneManifest diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/AddressView/AddressViewModelNew.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/AddressView/AddressViewModelNew.swift index badc983dd5..911d3456cc 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/AddressView/AddressViewModelNew.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/AddressView/AddressViewModelNew.swift @@ -85,7 +85,7 @@ class AddressViewModelNew: ObservableObject { .handle(address: address) .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) .observeOn(MainScheduler.instance) - .flatMap { [weak self] parsedAddress -> Single<(Address?, [AddressSecurityCheckerChain.SecurityCheckResult])> in + .flatMap { [weak self] parsedAddress -> Single<(Address?, [AddressSecurityCheckerChain.SecurityIssue])> in guard let _address = parsedAddress, let securityCheckerChain = self?.securityCheckerChain else { return .just((parsedAddress, [])) } @@ -93,9 +93,9 @@ class AddressViewModelNew: ObservableObject { return securityCheckerChain.handle(address: _address).map { (_address, $0) } } .subscribe( - onSuccess: { [weak self] parsedAddress, securityCheckResults in - print("securityCheckResults: \(securityCheckResults)") - self?.sync(parsedAddress, uri: uri, securityCheckResults: securityCheckResults) + onSuccess: { [weak self] parsedAddress, securityIssues in + print("securityIssues: \(securityIssues)") + self?.sync(parsedAddress, uri: uri, securityIssues: securityIssues) }, onError: { [weak self] in self?.sync($0, text: text) } ) @@ -113,13 +113,13 @@ class AddressViewModelNew: ObservableObject { } } - private func sync(_ address: Address?, uri: AddressUri?, securityCheckResults: [AddressSecurityCheckerChain.SecurityCheckResult]) { + private func sync(_ address: Address?, uri: AddressUri?, securityIssues: [AddressSecurityCheckerChain.SecurityIssue]) { guard let address else { result = .idle return } - result = .valid(.init(address: address, uri: uri, securityCheckResults: securityCheckResults)) + result = .valid(.init(address: address, uri: uri, securityIssues: securityIssues)) } private func sync(_ error: Error, text: String) { @@ -191,7 +191,7 @@ enum AddressInput { struct Success: Equatable { let address: Address let uri: AddressUri? - let securityCheckResults: [AddressSecurityCheckerChain.SecurityCheckResult] + let securityIssues: [AddressSecurityCheckerChain.SecurityIssue] static func == (lhs: AddressInput.Success, rhs: AddressInput.Success) -> Bool { lhs.address == rhs.address && lhs.uri == rhs.uri diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/BaseMultiSwap/MultiSwapSettings/AddressMultiSwapSettingsViewModel.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/BaseMultiSwap/MultiSwapSettings/AddressMultiSwapSettingsViewModel.swift index 258136c2bc..05fd74f440 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/BaseMultiSwap/MultiSwapSettings/AddressMultiSwapSettingsViewModel.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/BaseMultiSwap/MultiSwapSettings/AddressMultiSwapSettingsViewModel.swift @@ -35,7 +35,7 @@ class AddressMultiSwapSettingsViewModel: ObservableObject, IMultiSwapSettingsFie if let initialAddress { address = initialAddress.title - addressResult = .valid(.init(address: initialAddress, uri: nil, securityCheckResults: [])) + addressResult = .valid(.init(address: initialAddress, uri: nil, securityIssues: [])) } } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 805ac6657c..5c74154472 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -26,6 +26,7 @@ XCCONFIG_DEV_OPEN_SEA_API_KEY = ENV["XCCONFIG_DEV_OPEN_SEA_API_KEY"] XCCONFIG_DEV_TRONGRID_API_KEY = ENV["XCCONFIG_DEV_TRONGRID_API_KEY"] XCCONFIG_DEV_UNSTOPPABLE_DOMAINS_API_KEY = ENV["XCCONFIG_DEV_UNSTOPPABLE_DOMAINS_API_KEY"] XCCONFIG_DEV_ONE_INCH_API_KEY = ENV["XCCONFIG_DEV_ONE_INCH_API_KEY"] +XCCONFIG_DEV_CHAINALYSIS_API_KEY = ENV["XCCONFIG_DEV_CHAINALYSIS_API_KEY"] XCCONFIG_DEV_ONE_INCH_COMMISSION = ENV["XCCONFIG_DEV_ONE_INCH_COMMISSION"] XCCONFIG_DEV_ONE_INCH_COMMISSION_ADDRESS = ENV["XCCONFIG_DEV_ONE_INCH_COMMISSION_ADDRESS"] XCCONFIG_DEV_REFERRAL_APP_SERVER_URL = ENV["XCCONFIG_DEV_REFERRAL_APP_SERVER_URL"] @@ -47,6 +48,7 @@ XCCONFIG_PROD_OPEN_SEA_API_KEY = ENV["XCCONFIG_PROD_OPEN_SEA_API_KEY"] XCCONFIG_PROD_TRONGRID_API_KEY = ENV["XCCONFIG_PROD_TRONGRID_API_KEY"] XCCONFIG_PROD_UNSTOPPABLE_DOMAINS_API_KEY = ENV["XCCONFIG_PROD_UNSTOPPABLE_DOMAINS_API_KEY"] XCCONFIG_PROD_ONE_INCH_API_KEY = ENV["XCCONFIG_PROD_ONE_INCH_API_KEY"] +XCCONFIG_PROD_CHAINALYSIS_API_KEY = ENV["XCCONFIG_PROD_CHAINALYSIS_API_KEY"] XCCONFIG_PROD_ONE_INCH_COMMISSION = ENV["XCCONFIG_PROD_ONE_INCH_COMMISSION"] XCCONFIG_PROD_ONE_INCH_COMMISSION_ADDRESS = ENV["XCCONFIG_PROD_ONE_INCH_COMMISSION_ADDRESS"] XCCONFIG_PROD_REFERRAL_APP_SERVER_URL = ENV["XCCONFIG_PROD_REFERRAL_APP_SERVER_URL"] @@ -130,6 +132,7 @@ def apply_dev_xcconfig update_dev_xcconfig('trongrid_api_key', XCCONFIG_DEV_TRONGRID_API_KEY) update_dev_xcconfig('unstoppable_domains_api_key', XCCONFIG_DEV_UNSTOPPABLE_DOMAINS_API_KEY) update_dev_xcconfig('one_inch_api_key', XCCONFIG_DEV_ONE_INCH_API_KEY) + update_dev_xcconfig('chainalysis_api_key', XCCONFIG_DEV_CHAINALYSIS_API_KEY) update_dev_xcconfig('one_inch_commission', XCCONFIG_DEV_ONE_INCH_COMMISSION) update_dev_xcconfig('one_inch_commission_address', XCCONFIG_DEV_ONE_INCH_COMMISSION_ADDRESS) update_dev_xcconfig('referral_app_server_url', XCCONFIG_DEV_REFERRAL_APP_SERVER_URL) @@ -154,7 +157,8 @@ def apply_prod_xcconfig(swap_enabled, donate_enabled) update_prod_xcconfig('open_sea_api_key', XCCONFIG_PROD_OPEN_SEA_API_KEY) update_prod_xcconfig('trongrid_api_key', XCCONFIG_PROD_TRONGRID_API_KEY) update_prod_xcconfig('unstoppable_domains_api_key', XCCONFIG_PROD_UNSTOPPABLE_DOMAINS_API_KEY) - update_prod_xcconfig('one_inch_api_key', XCCONFIG_PROD_ONE_INCH_API_KEY) + update_prod_xcconfig('one_inch_api_key', XCCONFIG_PROD_ONE_INCH_API_KEY) + update_prod_xcconfig('chainalysis_api_key', XCCONFIG_PROD_CHAINALYSIS_API_KEY) update_prod_xcconfig('one_inch_commission', XCCONFIG_PROD_ONE_INCH_COMMISSION) update_prod_xcconfig('one_inch_commission_address', XCCONFIG_PROD_ONE_INCH_COMMISSION_ADDRESS) update_prod_xcconfig('referral_app_server_url', XCCONFIG_PROD_REFERRAL_APP_SERVER_URL)