Skip to content

Commit

Permalink
Improve swap confirmation workflow for OneInch
Browse files Browse the repository at this point in the history
  • Loading branch information
ealymbaev committed Oct 9, 2024
1 parent 04752d8 commit 47ae870
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 92 deletions.
4 changes: 2 additions & 2 deletions UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] {
Expand All @@ -37,15 +39,18 @@ 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
}

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,
Expand All @@ -55,8 +60,6 @@ class OneInchMultiSwapConfirmationQuote: BaseEvmMultiSwapConfirmationQuote {
)
}

let slippage = quote.slippage

if slippage != MultiSwapSlippage.default {
fields.append(
.levelValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
)
Expand All @@ -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")
Expand All @@ -188,9 +183,9 @@ extension OneInchMultiSwapProvider {
case invalidAddress
case invalidAmountIn
case invalidQuote
case invalidSwap
case noEvmKitWrapper
case noGasLimit
case noGasPriceData
}
}

Expand Down

0 comments on commit 47ae870

Please sign in to comment.