From 47ae870e14ecb6155413f108fe74a082aa83d045 Mon Sep 17 00:00:00 2001 From: EA Date: Wed, 9 Oct 2024 15:02:53 +0600 Subject: [PATCH] Improve swap confirmation workflow for OneInch --- .../project.pbxproj | 4 +- .../OneInchMultiSwapConfirmationQuote.swift | 25 +-- .../Providers/OneInchMultiSwapProvider.swift | 153 +++++++++--------- 3 files changed, 90 insertions(+), 92 deletions(-) diff --git a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj index 25ad380a1f..bcb8841d8e 100644 --- a/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj +++ b/UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj @@ -12280,7 +12280,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.40; + MARKETING_VERSION = 0.40.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OfficeMode = true; @@ -12352,7 +12352,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.40; + MARKETING_VERSION = 0.40.1; MTL_ENABLE_DEBUG_INFO = NO; OfficeMode = false; SDKROOT = iphoneos; diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapConfirmationQuote.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapConfirmationQuote.swift index 6cee0088f6..40c1ba1329 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapConfirmationQuote.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapConfirmationQuote.swift @@ -4,24 +4,26 @@ import MarketKit import OneInchKit class OneInchMultiSwapConfirmationQuote: BaseEvmMultiSwapConfirmationQuote { - let quote: OneInchMultiSwapQuote - let swap: Swap? + let swap: Swap + let recipient: Address? + let slippage: Decimal let insufficientFeeBalance: Bool - init(quote: OneInchMultiSwapQuote, swap: Swap?, insufficientFeeBalance: Bool, evmFeeData: EvmFeeData?, nonce: Int?) { - self.quote = quote + init(swap: Swap, recipient: Address?, slippage: Decimal, insufficientFeeBalance: Bool, evmFeeData: EvmFeeData, nonce: Int?) { self.swap = swap + self.recipient = recipient + self.slippage = slippage self.insufficientFeeBalance = insufficientFeeBalance - super.init(gasPrice: swap?.transaction.gasPrice, evmFeeData: evmFeeData, nonce: nonce) + super.init(gasPrice: swap.transaction.gasPrice, evmFeeData: evmFeeData, nonce: nonce) } override var amountOut: Decimal { - swap?.amountOut ?? quote.quote.amountOut ?? 0 + swap.amountOut ?? 0 } override var canSwap: Bool { - super.canSwap && swap != nil && !insufficientFeeBalance + super.canSwap && !insufficientFeeBalance } override func cautions(baseToken: MarketKit.Token) -> [CautionNew] { @@ -37,7 +39,10 @@ class OneInchMultiSwapConfirmationQuote: BaseEvmMultiSwapConfirmationQuote { ) } - cautions.append(contentsOf: quote.cautions()) + switch MultiSwapSlippage.validate(slippage: slippage) { + case .none: () + case let .caution(caution): cautions.append(caution.cautionNew(title: "swap.advanced_settings.slippage".localized)) + } return cautions } @@ -45,7 +50,7 @@ class OneInchMultiSwapConfirmationQuote: BaseEvmMultiSwapConfirmationQuote { override func priceSectionFields(tokenIn: MarketKit.Token, tokenOut: MarketKit.Token, baseToken: MarketKit.Token, currency: Currency, tokenInRate: Decimal?, tokenOutRate: Decimal?, baseTokenRate: Decimal?) -> [SendField] { var fields = super.priceSectionFields(tokenIn: tokenIn, tokenOut: tokenOut, baseToken: baseToken, currency: currency, tokenInRate: tokenInRate, tokenOutRate: tokenOutRate, baseTokenRate: baseTokenRate) - if let recipient = quote.recipient { + if let recipient { fields.append( .address( title: "swap.recipient".localized, @@ -55,8 +60,6 @@ class OneInchMultiSwapConfirmationQuote: BaseEvmMultiSwapConfirmationQuote { ) } - let slippage = quote.slippage - if slippage != MultiSwapSlippage.default { fields.append( .levelValue( diff --git a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapProvider.swift b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapProvider.swift index 0301c80d08..d3ab3fb45f 100644 --- a/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapProvider.swift +++ b/UnstoppableWallet/UnstoppableWallet/Modules/MultiSwap/Providers/OneInchMultiSwapProvider.swift @@ -43,57 +43,84 @@ class OneInchMultiSwapProvider: BaseEvmMultiSwapProvider { } override func quote(tokenIn: MarketKit.Token, tokenOut: MarketKit.Token, amountIn: Decimal) async throws -> IMultiSwapQuote { - try await internalQuote(tokenIn: tokenIn, tokenOut: tokenOut, amountIn: amountIn) + let blockchainType = tokenIn.blockchainType + let chain = evmBlockchainManager.chain(blockchainType: blockchainType) + + let addressFrom = try address(token: tokenIn) + let addressTo = try address(token: tokenOut) + + guard let amount = rawAmount(amount: amountIn, token: tokenIn) else { + throw SwapError.invalidAmountIn + } + + let quote = try await kit.quote( + networkManager: networkManager, + chain: chain, + fromToken: addressFrom, + toToken: addressTo, + amount: amount, + fee: commission + ) + + return await OneInchMultiSwapQuote( + quote: quote, + recipient: storage.recipient(blockchainType: blockchainType), + slippage: slippage, + allowanceState: allowanceState(token: tokenIn, amount: amountIn) + ) } override func confirmationQuote(tokenIn: MarketKit.Token, tokenOut: MarketKit.Token, amountIn: Decimal, transactionSettings: TransactionSettings?) async throws -> IMultiSwapConfirmationQuote { - let quote = try await internalQuote(tokenIn: tokenIn, tokenOut: tokenOut, amountIn: amountIn) - let blockchainType = tokenIn.blockchainType - let gasPriceData = transactionSettings?.gasPriceData - var evmFeeData: EvmFeeData? - var resolvedSwap: Swap? - var insufficientFeeBalance = false - - if let evmKitWrapper = evmBlockchainManager.evmKitManager(blockchainType: blockchainType).evmKitWrapper, - let gasPriceData, - let amount = rawAmount(amount: amountIn, token: tokenIn) - { - let evmKit = evmKitWrapper.evmKit - let swap = try await kit.swap( - networkManager: networkManager, - chain: evmKit.chain, - receiveAddress: evmKit.receiveAddress, - fromToken: address(token: tokenIn), - toToken: address(token: tokenOut), - amount: amount, - slippage: slippage, - referrer: commissionAddress, - fee: commission, - recipient: storage.recipient(blockchainType: blockchainType).flatMap { try? EvmKit.Address(hex: $0.raw) }, - gasPrice: gasPriceData.userDefined - ) - - resolvedSwap = swap - - let evmBalance = evmKit.accountState?.balance ?? 0 - let txAmount = swap.transaction.value - let feeAmount = BigUInt(swap.transaction.gasLimit * gasPriceData.userDefined.max) - let totalAmount = txAmount + feeAmount - - insufficientFeeBalance = totalAmount > evmBalance - - evmFeeData = try await evmFeeEstimator.estimateFee( - evmKitWrapper: evmKitWrapper, - transactionData: swap.transactionData, - gasPriceData: gasPriceData, - predefinedGasLimit: swap.transaction.gasLimit - ) + + guard let evmKitWrapper = evmBlockchainManager.evmKitManager(blockchainType: blockchainType).evmKitWrapper else { + throw SwapError.noEvmKitWrapper + } + + guard let gasPriceData = transactionSettings?.gasPriceData else { + throw SwapError.noGasPriceData } + guard let amount = rawAmount(amount: amountIn, token: tokenIn) else { + throw SwapError.invalidAmountIn + } + + let evmKit = evmKitWrapper.evmKit + let recipient = storage.recipient(blockchainType: blockchainType) + let slippage = slippage + + let swap = try await kit.swap( + networkManager: networkManager, + chain: evmKit.chain, + receiveAddress: evmKit.receiveAddress, + fromToken: address(token: tokenIn), + toToken: address(token: tokenOut), + amount: amount, + slippage: slippage, + referrer: commissionAddress, + fee: commission, + recipient: recipient.flatMap { try? EvmKit.Address(hex: $0.raw) }, + gasPrice: gasPriceData.userDefined + ) + + let evmBalance = evmKit.accountState?.balance ?? 0 + let txAmount = swap.transaction.value + let feeAmount = BigUInt(swap.transaction.gasLimit * gasPriceData.userDefined.max) + let totalAmount = txAmount + feeAmount + + let insufficientFeeBalance = totalAmount > evmBalance + + let evmFeeData = try await evmFeeEstimator.estimateFee( + evmKitWrapper: evmKitWrapper, + transactionData: swap.transactionData, + gasPriceData: gasPriceData, + predefinedGasLimit: swap.transaction.gasLimit + ) + return OneInchMultiSwapConfirmationQuote( - quote: quote, - swap: resolvedSwap, + swap: swap, + recipient: recipient, + slippage: slippage, insufficientFeeBalance: insufficientFeeBalance, evmFeeData: evmFeeData, nonce: transactionSettings?.nonce @@ -113,10 +140,6 @@ class OneInchMultiSwapProvider: BaseEvmMultiSwapProvider { throw SwapError.invalidQuote } - guard let swap = quote.swap else { - throw SwapError.invalidSwap - } - guard let gasLimit = quote.evmFeeData?.surchargedGasLimit else { throw SwapError.noGasLimit } @@ -126,8 +149,8 @@ class OneInchMultiSwapProvider: BaseEvmMultiSwapProvider { } _ = try await evmKitWrapper.send( - transactionData: swap.transactionData, - gasPrice: swap.transaction.gasPrice, + transactionData: quote.swap.transactionData, + gasPrice: quote.swap.transaction.gasPrice, gasLimit: gasLimit, nonce: quote.nonce ) @@ -137,34 +160,6 @@ class OneInchMultiSwapProvider: BaseEvmMultiSwapProvider { try OneInchKit.Kit.routerAddress(chain: chain) } - private func internalQuote(tokenIn: MarketKit.Token, tokenOut: MarketKit.Token, amountIn: Decimal) async throws -> OneInchMultiSwapQuote { - let blockchainType = tokenIn.blockchainType - let chain = evmBlockchainManager.chain(blockchainType: blockchainType) - - let addressFrom = try address(token: tokenIn) - let addressTo = try address(token: tokenOut) - - guard let amount = rawAmount(amount: amountIn, token: tokenIn) else { - throw SwapError.invalidAmountIn - } - - let quote = try await kit.quote( - networkManager: networkManager, - chain: chain, - fromToken: addressFrom, - toToken: addressTo, - amount: amount, - fee: commission - ) - - return await OneInchMultiSwapQuote( - quote: quote, - recipient: storage.recipient(blockchainType: blockchainType), - slippage: slippage, - allowanceState: allowanceState(token: tokenIn, amount: amountIn) - ) - } - private func address(token: MarketKit.Token) throws -> EvmKit.Address { switch token.type { case .native: return try EvmKit.Address(hex: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") @@ -188,9 +183,9 @@ extension OneInchMultiSwapProvider { case invalidAddress case invalidAmountIn case invalidQuote - case invalidSwap case noEvmKitWrapper case noGasLimit + case noGasPriceData } }