From 6584ee2e169c32cdc5b67c93f63d610b976f578b Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 5 Sep 2024 11:07:34 -0400 Subject: [PATCH] remove nonce, gasPrice, gasFee, maxFeePerGas --- .../dydxCartera/Contracts/ERC20Token.swift | 16 +++---- .../Ethereum/EthereumInteractor.swift | 15 ------- .../project.pbxproj | 12 ----- .../Deposit/V4/DepositTransactionV4.swift | 37 +++------------ .../SharedSteps/ERC20ApprovalStep.swift | 44 ++++-------------- .../SharedSteps/EthEstimateGasStep.swift | 45 ------------------- .../SharedSteps/EthGetGasPriceStep.swift | 42 ----------------- .../SharedSteps/EthGetNonceStep.swift | 44 ------------------ 8 files changed, 21 insertions(+), 234 deletions(-) delete mode 100644 dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthEstimateGasStep.swift delete mode 100644 dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetGasPriceStep.swift delete mode 100644 dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetNonceStep.swift diff --git a/dydx/dydxCartera/dydxCartera/Contracts/ERC20Token.swift b/dydx/dydxCartera/dydxCartera/Contracts/ERC20Token.swift index 610bc96ed..da4b655d9 100644 --- a/dydx/dydxCartera/dydxCartera/Contracts/ERC20Token.swift +++ b/dydx/dydxCartera/dydxCartera/Contracts/ERC20Token.swift @@ -18,8 +18,8 @@ public struct ERC20AllowanceFunction: ContractFunction { } public static let name = "allowance" - public let gasPrice: BigUInt? = BigUInt(0) - public let gasLimit: BigUInt? = BigUInt(0) + public let gasPrice: BigUInt? = nil + public let gasLimit: BigUInt? = nil public let contract: EthereumAddress public let from: EthereumAddress? @@ -32,9 +32,7 @@ public struct ERC20AllowanceFunction: ContractFunction { } public struct ERC20ApproveFunction: ContractFunction { - public init(gasPrice: BigUInt? = nil, gasLimit: BigUInt? = nil, contract: EthereumAddress, from: EthereumAddress? = nil, spender: EthereumAddress, amount: BigUInt = BigUInt("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", radix: 16)!) { - self.gasPrice = gasPrice - self.gasLimit = gasLimit + public init(contract: EthereumAddress, from: EthereumAddress? = nil, spender: EthereumAddress, amount: BigUInt = BigUInt("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", radix: 16)!) { self.contract = contract self.from = from self.spender = spender @@ -42,8 +40,8 @@ public struct ERC20ApproveFunction: ContractFunction { } public static let name = "approve" - public let gasPrice: BigUInt? - public let gasLimit: BigUInt? + public let gasPrice: BigUInt? = nil + public let gasLimit: BigUInt? = nil public let contract: EthereumAddress public let from: EthereumAddress? @@ -58,8 +56,8 @@ public struct ERC20ApproveFunction: ContractFunction { public struct ERC20BalanceOfFunction: ContractFunction { public static let name = "balanceOf" - public let gasPrice: BigUInt? = BigUInt(0) - public let gasLimit: BigUInt? = BigUInt(0) + public let gasPrice: BigUInt? = nil + public let gasLimit: BigUInt? = nil public let contract: EthereumAddress public let from: EthereumAddress? diff --git a/dydx/dydxCartera/dydxCartera/Ethereum/EthereumInteractor.swift b/dydx/dydxCartera/dydxCartera/Ethereum/EthereumInteractor.swift index e15dbe823..2736adf16 100644 --- a/dydx/dydxCartera/dydxCartera/Ethereum/EthereumInteractor.swift +++ b/dydx/dydxCartera/dydxCartera/Ethereum/EthereumInteractor.swift @@ -53,21 +53,6 @@ public final class EthereumInteractor { } } - public func eth_gasPrice(completion: @escaping EthereumBigUIntCompletion) { - queue.async { [weak self] in - self?.client?.eth_gasPrice { result in - DispatchQueue.main.async { - switch result { - case .success(let value): - completion(nil, value) - case .failure(let error): - completion(error, nil) - } - } - } - } - } - public func eth_blockNumber(completion: @escaping EthereumIntCompletion) { queue.async { [weak self] in self?.client?.eth_blockNumber { result in diff --git a/dydx/dydxStateManager/dydxStateManager.xcodeproj/project.pbxproj b/dydx/dydxStateManager/dydxStateManager.xcodeproj/project.pbxproj index 8e006d117..9c3568085 100644 --- a/dydx/dydxStateManager/dydxStateManager.xcodeproj/project.pbxproj +++ b/dydx/dydxStateManager/dydxStateManager.xcodeproj/project.pbxproj @@ -10,15 +10,12 @@ 021385BD28DBD21600A9BCA5 /* ThreadRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021385BC28DBD21600A9BCA5 /* ThreadRunner.swift */; }; 021385BF28DBD22100A9BCA5 /* WebsocketConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021385BE28DBD22100A9BCA5 /* WebsocketConnection.swift */; }; 021385C128DBD74700A9BCA5 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021385C028DBD74700A9BCA5 /* Utils.swift */; }; - 0219D8C82AD36CD700EF31EF /* EthGetNonceStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0219D8C72AD36CD700EF31EF /* EthGetNonceStep.swift */; }; 022A81042BE18C51000BF2DD /* AbacusPresentationImp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022A81032BE18C51000BF2DD /* AbacusPresentationImp.swift */; }; 022E928828EA4FD80096CDA9 /* Models+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022E928728EA4FD80096CDA9 /* Models+Ext.swift */; }; 022EDB70299EF054003D59A7 /* dydxWalletState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022EDB6F299EF054003D59A7 /* dydxWalletState.swift */; }; 023BFFD02ABBB25300D3ED5C /* ERC20AllowanceStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023BFFCF2ABBB25300D3ED5C /* ERC20AllowanceStep.swift */; }; 023BFFD72ABBBAA900D3ED5C /* EnableERC20TokenStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023BFFD62ABBBAA900D3ED5C /* EnableERC20TokenStep.swift */; }; 023BFFD92ABBC4C000D3ED5C /* ERC20ApprovalStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023BFFD82ABBC4C000D3ED5C /* ERC20ApprovalStep.swift */; }; - 023BFFDB2ABBECB100D3ED5C /* EthEstimateGasStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023BFFDA2ABBECB100D3ED5C /* EthEstimateGasStep.swift */; }; - 023BFFDD2ABBEEFA00D3ED5C /* EthGetGasPriceStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023BFFDC2ABBEEFA00D3ED5C /* EthGetGasPriceStep.swift */; }; 0260350929EF30EE00DFFD11 /* WalletSwitchChainStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0260350829EF30EE00DFFD11 /* WalletSwitchChainStep.swift */; }; 0260351029EF3C2E00DFFD11 /* WalletSendTransactionStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0260350F29EF3C2E00DFFD11 /* WalletSendTransactionStep.swift */; }; 02603B9129F1A95E00DFFD11 /* dydxClientState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02603B9029F1A95E00DFFD11 /* dydxClientState.swift */; }; @@ -131,15 +128,12 @@ 021385BC28DBD21600A9BCA5 /* ThreadRunner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadRunner.swift; sourceTree = ""; }; 021385BE28DBD22100A9BCA5 /* WebsocketConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebsocketConnection.swift; sourceTree = ""; }; 021385C028DBD74700A9BCA5 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; - 0219D8C72AD36CD700EF31EF /* EthGetNonceStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthGetNonceStep.swift; sourceTree = ""; }; 022A81032BE18C51000BF2DD /* AbacusPresentationImp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbacusPresentationImp.swift; sourceTree = ""; }; 022E928728EA4FD80096CDA9 /* Models+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Models+Ext.swift"; sourceTree = ""; }; 022EDB6F299EF054003D59A7 /* dydxWalletState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxWalletState.swift; sourceTree = ""; }; 023BFFCF2ABBB25300D3ED5C /* ERC20AllowanceStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ERC20AllowanceStep.swift; sourceTree = ""; }; 023BFFD62ABBBAA900D3ED5C /* EnableERC20TokenStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnableERC20TokenStep.swift; sourceTree = ""; }; 023BFFD82ABBC4C000D3ED5C /* ERC20ApprovalStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ERC20ApprovalStep.swift; sourceTree = ""; }; - 023BFFDA2ABBECB100D3ED5C /* EthEstimateGasStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthEstimateGasStep.swift; sourceTree = ""; }; - 023BFFDC2ABBEEFA00D3ED5C /* EthGetGasPriceStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthGetGasPriceStep.swift; sourceTree = ""; }; 0260350829EF30EE00DFFD11 /* WalletSwitchChainStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSwitchChainStep.swift; sourceTree = ""; }; 0260350F29EF3C2E00DFFD11 /* WalletSendTransactionStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSendTransactionStep.swift; sourceTree = ""; }; 02603B9029F1A95E00DFFD11 /* dydxClientState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxClientState.swift; sourceTree = ""; }; @@ -217,9 +211,6 @@ children = ( 0260350829EF30EE00DFFD11 /* WalletSwitchChainStep.swift */, 0260350F29EF3C2E00DFFD11 /* WalletSendTransactionStep.swift */, - 023BFFDA2ABBECB100D3ED5C /* EthEstimateGasStep.swift */, - 0219D8C72AD36CD700EF31EF /* EthGetNonceStep.swift */, - 023BFFDC2ABBEEFA00D3ED5C /* EthGetGasPriceStep.swift */, 023BFFCF2ABBB25300D3ED5C /* ERC20AllowanceStep.swift */, 023BFFD82ABBC4C000D3ED5C /* ERC20ApprovalStep.swift */, ); @@ -649,7 +640,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0219D8C82AD36CD700EF31EF /* EthGetNonceStep.swift in Sources */, 27B957EF2B97C11400EF9304 /* dydxRatingService.swift in Sources */, 6473ACB42A65B18B00BBC01F /* AbacusRestImp.swift in Sources */, 023BFFD72ABBBAA900D3ED5C /* EnableERC20TokenStep.swift in Sources */, @@ -665,7 +655,6 @@ 6473AE412A65D3E700BBC01F /* AbacusChainImp.swift in Sources */, 02E7DD7F28CFAFF000727949 /* AbacusStateManager.swift in Sources */, 6473ACC02A65B1FD00BBC01F /* AbacusFormatterImp.swift in Sources */, - 023BFFDB2ABBECB100D3ED5C /* EthEstimateGasStep.swift in Sources */, 6473ACBC2A65B1D300BBC01F /* AbacusWebSocketImp.swift in Sources */, 022A81042BE18C51000BF2DD /* AbacusPresentationImp.swift in Sources */, 023BFFD02ABBB25300D3ED5C /* ERC20AllowanceStep.swift in Sources */, @@ -673,7 +662,6 @@ 278765A42C17C529000119D2 /* Kotlin+Ext.swift in Sources */, 021385C128DBD74700A9BCA5 /* Utils.swift in Sources */, 02A8962128E65FBD006F1658 /* AbacusState+Combine.swift in Sources */, - 023BFFDD2ABBEEFA00D3ED5C /* EthGetGasPriceStep.swift in Sources */, 02E7DD8C28CFB1C600727949 /* HttpCall.swift in Sources */, 027CB28E29EF02C50069781A /* DepositTransaction.swift in Sources */, 0260351029EF3C2E00DFFD11 /* WalletSendTransactionStep.swift in Sources */, diff --git a/dydx/dydxStateManager/dydxStateManager/Transactions/Deposit/V4/DepositTransactionV4.swift b/dydx/dydxStateManager/dydxStateManager/Transactions/Deposit/V4/DepositTransactionV4.swift index cfc0aff8f..51eea89f0 100644 --- a/dydx/dydxStateManager/dydxStateManager/Transactions/Deposit/V4/DepositTransactionV4.swift +++ b/dydx/dydxStateManager/dydxStateManager/Transactions/Deposit/V4/DepositTransactionV4.swift @@ -61,38 +61,16 @@ struct DepositTransactionV4: AsyncStep { } return Empty, Never>().eraseToAnyPublisher() } - .flatMap { event -> AnyPublisher, Never> in + .flatMap { event -> AnyPublisher, Never> in if case let .result(enabled, error) = event { if enabled == true { - return EthGetNonceStep(chainRpc: chainRpc, - address: EthereumAddress(walletAddress)) - .run() - - } else if let error = error { - return Just(AsyncEvent.result(nil, error)).eraseToAnyPublisher() - } else { - let error = NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Token not enabled"]) - return Just(AsyncEvent.result(nil, error)).eraseToAnyPublisher() - } - } - return Empty, Never>().eraseToAnyPublisher() - } - .flatMap { event -> AnyPublisher, Never> in - if case let .result(nonce, error) = event { - if nonce != nil { - let transaction = EthereumTransactionRequest(transaction: ethereumTransactionRequest.transaction, - gasPrice: ethereumTransactionRequest.gasPrice, - gas: ethereumTransactionRequest.gas, - nonce: nonce, - maxPriorityFeePerGas: ethereumTransactionRequest.maxPriorityFeePerGas, - maxFeePerGas: ethereumTransactionRequest.maxFeePerGas) + let transaction = EthereumTransactionRequest(transaction: ethereumTransactionRequest.transaction) return WalletSendTransactionStep(transaction: transaction, chainIdInt: chainIdInt, provider: provider, walletAddress: walletAddress, walletId: walletId) .run() - } else if let error = error { return Just(AsyncEvent.result(nil, error)).eraseToAnyPublisher() } else { @@ -138,16 +116,11 @@ private extension EthereumTransactionRequest { value: requestPayload.value?.asBigUInt, data: data.web3.hexData, nonce: nil, - gasPrice: requestPayload.gasPrice?.asBigUInt, - gasLimit: requestPayload.gasLimit?.asBigUInt, + gasPrice: nil, + gasLimit: nil, chainId: chainId) - self.init(transaction: transaction, - gasPrice: requestPayload.gasPrice?.asBigUInt, - gas: requestPayload.gasLimit?.asBigUInt, - nonce: nil, - maxPriorityFeePerGas: requestPayload.maxPriorityFeePerGas?.asBigUInt, - maxFeePerGas: requestPayload.maxFeePerGas?.asBigUInt) + self.init(transaction: transaction) } } diff --git a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/ERC20ApprovalStep.swift b/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/ERC20ApprovalStep.swift index 1c2924df9..588af43af 100644 --- a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/ERC20ApprovalStep.swift +++ b/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/ERC20ApprovalStep.swift @@ -41,9 +41,7 @@ struct ERC20ApprovalStep: AsyncStep { } func run() -> AnyPublisher, Never> { - let function = ERC20ApproveFunction(gasPrice: nil, - gasLimit: nil, - contract: EthereumAddress(tokenAddress), + let function = ERC20ApproveFunction(contract: EthereumAddress(tokenAddress), from: EthereumAddress(ethereumAddress), spender: EthereumAddress(spenderAddress), amount: amount) @@ -51,38 +49,14 @@ struct ERC20ApprovalStep: AsyncStep { return Just(AsyncEvent.result(false, nil)).eraseToAnyPublisher() } - // Run in parallel - return Publishers.Zip3( - EthGetGasPriceStep(chainRpc: chainRpc).run(), - EthEstimateGasStep(chainRpc: chainRpc, transaction: transaction).run(), - EthGetNonceStep(chainRpc: chainRpc, address: EthereumAddress(ethereumAddress)).run() - ) - .flatMap { (gasPriceEvent, estimateGasEvent, nonceEvent) -> AnyPublisher, Never> in - if case .result(let gasPrice, let gasPriceError) = gasPriceEvent, - case .result(let gas, let gasError) = estimateGasEvent, - case .result(let nonce, let nonceError) = nonceEvent { - if let gasPrice = gasPrice, let gas = gas, let nonce = nonce { - let ethereumTransactionRequest = EthereumTransactionRequest(transaction: transaction, gasPrice: gasPrice, gas: gas, nonce: nonce) - - return WalletSendTransactionStep(transaction: ethereumTransactionRequest, - chainIdInt: chainIdInt, - provider: provider, - walletAddress: ethereumAddress, - walletId: walletId) - .run() - } else { - if let gasPriceError = gasPriceError { - return Just(AsyncEvent.result(nil, gasPriceError)).eraseToAnyPublisher() - } else if let gasError = gasError { - return Just(AsyncEvent.result(nil, gasError)).eraseToAnyPublisher() - } else if let nonceError = nonceError { - return Just(AsyncEvent.result(nil, nonceError)).eraseToAnyPublisher() - } - } - } - let error = NSError(domain: "", code: -1, userInfo: [ NSLocalizedDescriptionKey: "Invalid gas or gasPrice"]) - return Just(AsyncEvent.result(nil, error)).eraseToAnyPublisher() - } + let ethereumTransactionRequest = EthereumTransactionRequest(transaction: transaction) + + return WalletSendTransactionStep(transaction: ethereumTransactionRequest, + chainIdInt: chainIdInt, + provider: provider, + walletAddress: ethereumAddress, + walletId: walletId) + .run() .flatMap { event -> AnyPublisher, Never> in if case .result(let value, let error) = event { if let amount = Parser.standard.asUInt256(value), amount > BigInt.zero { diff --git a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthEstimateGasStep.swift b/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthEstimateGasStep.swift deleted file mode 100644 index 7dbdf768b..000000000 --- a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthEstimateGasStep.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// EthEstimateGasStep.swift -// dydxStateManager -// -// Created by Rui Huang on 9/20/23. -// - -import Utilities -import Combine -import Abacus -import Cartera -import BigInt -import web3 -import dydxCartera - -struct EthEstimateGasStep: AsyncStep { - typealias ProgressType = Void - typealias ResultType = BigUInt - - let transaction: EthereumTransaction - - private let ethereumInteractor: EthereumInteractor - - init(chainRpc: String, transaction: EthereumTransaction) { - self.transaction = transaction - self.ethereumInteractor = EthereumInteractor(url: chainRpc) - } - - func run() -> AnyPublisher, Never> { - return AnyPublisher, Never>.create { subscriber in - ethereumInteractor.eth_estimateGas(transaction) { error, value in - if let value = value { - _ = subscriber.receive(.result(value * 11 / 10, error)) - } else if let error = error { - _ = subscriber.receive(.result(nil, error)) - } - } - - return AnyCancellable { - // Imperative cancellation implementation - } - } - .eraseToAnyPublisher() - } -} diff --git a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetGasPriceStep.swift b/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetGasPriceStep.swift deleted file mode 100644 index 38c820b44..000000000 --- a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetGasPriceStep.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// EthGetGasPriceStep.swift -// dydxStateManager -// -// Created by Rui Huang on 9/20/23. -// - -import Utilities -import Combine -import Abacus -import Cartera -import BigInt -import web3 -import dydxCartera - -struct EthGetGasPriceStep: AsyncStep { - typealias ProgressType = Void - typealias ResultType = BigUInt - - private let ethereumInteractor: EthereumInteractor - - init(chainRpc: String) { - self.ethereumInteractor = EthereumInteractor(url: chainRpc) - } - - func run() -> AnyPublisher, Never> { - return AnyPublisher, Never>.create { subscriber in - ethereumInteractor.eth_gasPrice { error, gasPrice in - if let gasPrice = gasPrice { - _ = subscriber.receive(.result(gasPrice, error)) - } else if let error = error { - _ = subscriber.receive(.result(nil, error)) - } - } - - return AnyCancellable { - // Imperative cancellation implementation - } - } - .eraseToAnyPublisher() - } -} diff --git a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetNonceStep.swift b/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetNonceStep.swift deleted file mode 100644 index d59575d35..000000000 --- a/dydx/dydxStateManager/dydxStateManager/Transactions/SharedSteps/EthGetNonceStep.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// EthGetNonceStep.swift -// dydxStateManager -// -// Created by Rui Huang on 10/8/23. -// - -import Utilities -import Combine -import Cartera -import BigInt -import web3 -import dydxCartera - -struct EthGetNonceStep: AsyncStep { - typealias ProgressType = Void - typealias ResultType = Int - - let address: EthereumAddress - - private let ethereumInteractor: EthereumInteractor - - init(chainRpc: String, address: EthereumAddress) { - self.address = address - self.ethereumInteractor = EthereumInteractor(url: chainRpc) - } - - func run() -> AnyPublisher, Never> { - return AnyPublisher, Never>.create { subscriber in - ethereumInteractor.eth_getTransactionCount(address: address, block: .Pending) { error, value in - if let value = value { - _ = subscriber.receive(.result(value, error)) - } else if let error = error { - _ = subscriber.receive(.result(nil, error)) - } - } - - return AnyCancellable { - // Imperative cancellation implementation - } - } - .eraseToAnyPublisher() - } -}