Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
[release] Update BraveCore to v1.62.140, uplift #8590, uplift #8603 (#…
Browse files Browse the repository at this point in the history
…8652)

* Fix #8590: Wallet Swap Service Refactor also Bump Core to 1.63.90 (#8613)

* Fix #8603: Jupiter v4 to v6 migration & BraveCore bump to v1.63.107 (#8633)

* Update `SwapTokenStore` & `SwapTokenStoreTests` for Jupiter v6 changes.

* Update BraveCore to v1.62.140

---------

Co-authored-by: Nuo Xu <[email protected]>
  • Loading branch information
StephenHeaps and nuo-xu authored Jan 15, 2024
1 parent db23627 commit 2fd31c3
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 149 deletions.
129 changes: 60 additions & 69 deletions Sources/BraveWallet/Crypto/Stores/SwapTokenStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
didSet {
if sellAmount != oldValue {
// sell amount changed, new quotes are needed
swapResponse = nil
zeroExQuote = nil
jupiterQuote = nil
braveFee = nil
// price quote requested for a different amount
Expand Down Expand Up @@ -117,9 +117,9 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
@Published var isUpdatingPriceQuote = false
/// The brave fee for the current price quote
@Published var braveFee: BraveWallet.BraveSwapFeeResponse?
/// The SwapResponse / price quote currently being displayed for Ethereum swap.
/// The ZeroExQuote / price quote currently being displayed for Ethereum swap.
/// The quote needs preserved to know when to show `protocolFeesForDisplay` fees.
@Published var swapResponse: BraveWallet.SwapResponse?
@Published var zeroExQuote: BraveWallet.ZeroExQuote?

/// If the Brave Fee is voided for this swap.
var isBraveFeeVoided: Bool {
Expand Down Expand Up @@ -150,7 +150,7 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
guard let braveFee,
let protocolFeePct = Double(braveFee.protocolFeePct),
!protocolFeePct.isZero else { return nil }
if let swapResponse, swapResponse.fees.zeroExFee == nil {
if let zeroExQuote, zeroExQuote.fees.zeroExFee == nil {
// `protocolFeePct` should only be surfaced to users if `zeroExFee` is non-null.
return nil
}
Expand Down Expand Up @@ -308,10 +308,10 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
}
}

private func swapParameters(
private func swapQuoteParameters(
for base: SwapParamsBase,
in network: BraveWallet.NetworkInfo
) -> BraveWallet.SwapParams? {
) -> BraveWallet.SwapQuoteParams? {
guard
let accountInfo = accountInfo,
let sellToken = selectedFromToken,
Expand Down Expand Up @@ -340,18 +340,22 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
sellAmountInWei = ""
buyAmountInWei = weiFormatter.weiString(from: buyAmount.normalizedDecimals, radix: .decimal, decimals: Int(buyToken.decimals)) ?? "0"
}
let swapParams = BraveWallet.SwapParams(
chainId: network.chainId,
takerAddress: accountInfo.address,
sellAmount: sellAmountInWei,
buyAmount: buyAmountInWei,
buyToken: buyAddress,
sellToken: sellAddress,
slippagePercentage: slippage,
gasPrice: ""
// We store 0.5% as 0.005, so multiply by 100 to get 0.5
let slippagePercentage = slippage * 100
let swapQuoteParams = BraveWallet.SwapQuoteParams(
from: accountInfo.accountId,
fromChainId: network.chainId,
fromToken: sellAddress,
fromAmount: sellAmountInWei,
to: accountInfo.accountId,
toChainId: network.chainId,
toToken: buyAddress,
toAmount: buyAmountInWei,
slippagePercentage: "\(slippagePercentage)",
routePriority: .recommended
)

return swapParams
return swapQuoteParams
}

@MainActor private func createEthSwapTransaction() async -> Bool {
Expand All @@ -364,13 +368,13 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
defer { self.isMakingTx = false }
let coin = accountInfo.coin
let network = await rpcService.network(coin, origin: nil)
guard let swapParams = self.swapParameters(for: .perSellAsset, in: network) else {
guard let swapQuoteParams = self.swapQuoteParameters(for: .perSellAsset, in: network) else {
self.state = .error(Strings.Wallet.unknownError)
self.clearAllAmount()
return false
}
let (swapResponse, _, _) = await swapService.transactionPayload(swapParams)
guard let swapResponse = swapResponse else {
let (swapTransactionUnion, _, _) = await swapService.transaction(.init(zeroExTransactionParams: swapQuoteParams))
guard let swapResponse = swapTransactionUnion?.zeroExTransaction else {
self.state = .error(Strings.Wallet.unknownError)
self.clearAllAmount()
return false
Expand Down Expand Up @@ -427,9 +431,9 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {

/// Update price market and sell/buy amount fields based on `SwapParamsBase`
@MainActor private func handleEthPriceQuoteResponse(
_ response: BraveWallet.SwapResponse,
_ response: BraveWallet.ZeroExQuote,
base: SwapParamsBase,
swapParams: BraveWallet.SwapParams
swapQuoteParams: BraveWallet.SwapQuoteParams
) async {
let weiFormatter = WeiFormatter(decimalFormatStyle: .decimals(precision: 18))
switch base {
Expand Down Expand Up @@ -465,12 +469,14 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
}
}

self.swapResponse = response
self.zeroExQuote = response
let network = await rpcService.network(selectedFromToken?.coin ?? .eth, origin: nil)
let (braveSwapFeeResponse, _) = await swapService.braveFee(
.init(
chainId: network.chainId,
swapParams: swapParams
inputToken: swapQuoteParams.fromToken,
outputToken: swapQuoteParams.toToken,
taker: swapQuoteParams.fromAccountId.address
)
)
if let braveSwapFeeResponse {
Expand Down Expand Up @@ -576,7 +582,7 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
return bumpedValue.rounded().asString(radix: 16)
}

@MainActor private func checkBalanceShowError(swapResponse: BraveWallet.SwapResponse) async {
@MainActor private func checkBalanceShowError(swapResponse: BraveWallet.ZeroExQuote) async {
guard
let accountInfo = accountInfo,
let sellAmountValue = BDouble(sellAmount.normalizedDecimals),
Expand Down Expand Up @@ -647,26 +653,16 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
}

@MainActor private func fetchSolPriceQuote(
swapParams: BraveWallet.SwapParams,
swapQuoteParams: BraveWallet.SwapQuoteParams,
network: BraveWallet.NetworkInfo
) async {
// 0.5% is 50bps. We store 0.5% as 0.005, so multiply by 10_000
let slippageBps = Int32(swapParams.slippagePercentage * 10_000)
let jupiterQuoteParams: BraveWallet.JupiterQuoteParams = .init(
chainId: network.chainId,
inputMint: swapParams.sellToken,
outputMint: swapParams.buyToken,
amount: swapParams.sellAmount,
slippageBps: slippageBps,
userPublicKey: swapParams.takerAddress
)
self.isUpdatingPriceQuote = true
let (jupiterQuote, swapErrorResponse, _) = await swapService.jupiterQuote(jupiterQuoteParams)
let (swapQuoteUnion, swapQuoteErrorUnion, _) = await swapService.quote(swapQuoteParams)
defer { self.isUpdatingPriceQuote = false }
guard !Task.isCancelled else { return }
if let jupiterQuote {
await self.handleSolPriceQuoteResponse(jupiterQuote, swapParams: swapParams)
} else if let swapErrorResponse {
if let jupiterQuote = swapQuoteUnion?.jupiterQuote {
await self.handleSolPriceQuoteResponse(jupiterQuote, swapQuoteParams: swapQuoteParams)
} else if let swapErrorResponse = swapQuoteErrorUnion?.jupiterError {
// check balance first because error can be caused by insufficient balance
if let sellTokenBalance = self.selectedFromTokenBalance,
let sellAmountValue = BDouble(self.sellAmount.normalizedDecimals),
Expand All @@ -689,22 +685,21 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {

@MainActor private func handleSolPriceQuoteResponse(
_ response: BraveWallet.JupiterQuote,
swapParams: BraveWallet.SwapParams
swapQuoteParams: BraveWallet.SwapQuoteParams
) async {
guard let route = response.routes.first else { return }
self.jupiterQuote = response

let formatter = WeiFormatter(decimalFormatStyle: .balance)
if let selectedToToken {
buyAmount = formatter.decimalString(for: "\(route.otherAmountThreshold)", radix: .decimal, decimals: Int(selectedToToken.decimals)) ?? ""
buyAmount = formatter.decimalString(for: response.outAmount, radix: .decimal, decimals: Int(selectedToToken.decimals)) ?? ""
}

// No exchange rate is returned by Jupiter API, so we estimate it from the quote.
if let selectedFromToken,
let newFromAmount = formatter.decimalString(for: "\(route.inAmount)", radix: .decimal, decimals: Int(selectedFromToken.decimals)),
let newFromAmount = formatter.decimalString(for: response.inAmount, radix: .decimal, decimals: Int(selectedFromToken.decimals)),
let newFromAmountWrapped = BDouble(newFromAmount),
let selectedToToken,
let newToAmount = formatter.decimalString(for: "\(route.otherAmountThreshold)", radix: .decimal, decimals: Int(selectedToToken.decimals)),
let newToAmount = formatter.decimalString(for: response.outAmount, radix: .decimal, decimals: Int(selectedToToken.decimals)),
let newToAmountWrapped = BDouble(newToAmount),
newFromAmountWrapped != 0 {
let rate = newToAmountWrapped / newFromAmountWrapped
Expand All @@ -715,8 +710,9 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
let (braveSwapFeeResponse, _) = await swapService.braveFee(
.init(
chainId: network.chainId,
swapParams: swapParams
)
inputToken: swapQuoteParams.fromToken,
outputToken: swapQuoteParams.toToken,
taker: swapQuoteParams.fromAccountId.address)
)
if let braveSwapFeeResponse {
self.braveFee = braveSwapFeeResponse
Expand Down Expand Up @@ -745,24 +741,20 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {

@MainActor private func createSolSwapTransaction() async -> Bool {
guard let jupiterQuote,
let route = jupiterQuote.routes.first,
let accountInfo = self.accountInfo,
let selectedToToken,
let selectedFromToken else {
let accountInfo = self.accountInfo else {
return false
}
self.isMakingTx = true
defer { self.isMakingTx = false }
let network = await rpcService.network(.sol, origin: nil)
let jupiterSwapParams: BraveWallet.JupiterSwapParams = .init(

let jupiterTransactionParams: BraveWallet.JupiterTransactionParams = .init(
quote: jupiterQuote,
chainId: network.chainId,
route: route,
userPublicKey: accountInfo.address,
inputMint: selectedFromToken.contractAddress(in: network),
outputMint: selectedToToken.contractAddress(in: network)
userPublicKey: accountInfo.address
)
let (swapTransactions, errorResponse, _) = await swapService.jupiterSwapTransactions(jupiterSwapParams)
guard let swapTransactions else {
let (swapTransactionUnion, errorResponseUnion, _) = await swapService.transaction(.init(jupiterTransactionParams: jupiterTransactionParams))
guard let jupiterTransaction = swapTransactionUnion?.jupiterTransaction else {
// check balance first because error can cause by insufficient balance
if let sellTokenBalance = self.selectedFromTokenBalance,
let sellAmountValue = BDouble(self.sellAmount.normalizedDecimals),
Expand All @@ -771,15 +763,15 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
return false
}
// check if jupiterQuote fails due to insufficient liquidity
if errorResponse?.isInsufficientLiquidity == true {
if let errorResponse = errorResponseUnion?.jupiterError, errorResponse.isInsufficientLiquidity == true {
self.state = .error(Strings.Wallet.insufficientLiquidity)
return false
}
self.state = .error(Strings.Wallet.unknownError)
return false
}
let (solTxData, status, _) = await solTxManagerProxy.makeTxData(
fromBase64EncodedTransaction: swapTransactions.swapTransaction,
fromBase64EncodedTransaction: jupiterTransaction,
txType: .solanaSwap,
send: .init(
maxRetries: .init(maxRetries: 2),
Expand Down Expand Up @@ -841,7 +833,7 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
priceQuoteTask?.cancel()
priceQuoteTask = Task { @MainActor in
// reset quotes before fetching new quote
swapResponse = nil
zeroExQuote = nil
jupiterQuote = nil
braveFee = nil
guard let accountInfo else {
Expand All @@ -853,7 +845,7 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
// Entering a buy amount is disabled for Solana swaps, always use
// `SwapParamsBase.perSellAsset` to fetch quote based on the sell amount.
// `SwapParamsBase.perBuyAsset` is sent when `selectedToToken` is changed.
guard let swapParams = self.swapParameters(
guard let swapQuoteParams = self.swapQuoteParameters(
for: accountInfo.coin == .sol ? .perSellAsset : base,
in: network
) else {
Expand All @@ -862,9 +854,9 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {
}
switch accountInfo.coin {
case .eth:
await fetchEthPriceQuote(base: base, swapParams: swapParams, network: network)
await fetchEthPriceQuote(base: base, swapQuoteParams: swapQuoteParams, network: network)
case .sol:
await fetchSolPriceQuote(swapParams: swapParams, network: network)
await fetchSolPriceQuote(swapQuoteParams: swapQuoteParams, network: network)
default:
break
}
Expand All @@ -873,16 +865,15 @@ public class SwapTokenStore: ObservableObject, WalletObserverStore {

@MainActor private func fetchEthPriceQuote(
base: SwapParamsBase,
swapParams: BraveWallet.SwapParams,
swapQuoteParams: BraveWallet.SwapQuoteParams,
network: BraveWallet.NetworkInfo
) async {
self.isUpdatingPriceQuote = true
defer { self.isUpdatingPriceQuote = false }
let (swapResponse, swapErrorResponse, _) = await swapService.priceQuote(swapParams)
guard !Task.isCancelled else { return }
if let swapResponse = swapResponse {
await self.handleEthPriceQuoteResponse(swapResponse, base: base, swapParams: swapParams)
} else if let swapErrorResponse = swapErrorResponse {
let (swapQuoteUnion, swapQuoteErrorUnion, _) = await swapService.quote(swapQuoteParams)
if let swapResponse = swapQuoteUnion?.zeroExQuote {
await self.handleEthPriceQuoteResponse(swapResponse, base: base, swapQuoteParams: swapQuoteParams)
} else if let swapErrorResponse = swapQuoteErrorUnion?.zeroExError {
// check balance first because error can cause by insufficient balance
if let sellTokenBalance = self.selectedFromTokenBalance,
let sellAmountValue = BDouble(self.sellAmount.normalizedDecimals),
Expand Down
11 changes: 0 additions & 11 deletions Sources/BraveWallet/Extensions/BraveWalletExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -523,17 +523,6 @@ extension BraveWallet.KeyringId {
}
}

extension BraveWallet.BraveSwapFeeParams {
convenience init(chainId: String, swapParams: BraveWallet.SwapParams) {
self.init(
chainId: chainId,
inputToken: swapParams.sellToken,
outputToken: swapParams.buyToken,
taker: swapParams.takerAddress
)
}
}

public extension String {
/// Returns true if the string ends with a supported ENS extension.
var endsWithSupportedENSExtension: Bool {
Expand Down
24 changes: 4 additions & 20 deletions Sources/BraveWallet/Preview Content/MockSwapService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,12 @@ class MockSwapService: BraveWalletSwapService {
completion(true)
}

func transactionPayload(_ params: BraveWallet.SwapParams, completion: @escaping (BraveWallet.SwapResponse?, BraveWallet.SwapErrorResponse?, String) -> Void) {
completion(.init(price: "", guaranteedPrice: "", to: "", data: "", value: "", gas: "", estimatedGas: "", gasPrice: "", protocolFee: "", minimumProtocolFee: "", buyTokenAddress: "", sellTokenAddress: "", buyAmount: "", sellAmount: "", allowanceTarget: "", sellTokenToEthRate: "", buyTokenToEthRate: "", estimatedPriceImpact: "", sources: [], fees: .init(zeroExFee: nil)), nil, "")
func transaction(_ params: BraveWallet.SwapTransactionParamsUnion, completion: @escaping (BraveWallet.SwapTransactionUnion?, BraveWallet.SwapErrorUnion?, String) -> Void) {
completion(.init(zeroExTransaction: .init(price: "", guaranteedPrice: "", to: "", data: "", value: "", gas: "", estimatedGas: "", gasPrice: "", protocolFee: "", minimumProtocolFee: "", buyTokenAddress: "", sellTokenAddress: "", buyAmount: "", sellAmount: "", allowanceTarget: "", sellTokenToEthRate: "", buyTokenToEthRate: "", estimatedPriceImpact: "", sources: [], fees: .init(zeroExFee: nil))), nil, "")
}

func priceQuote(_ params: BraveWallet.SwapParams, completion: @escaping (BraveWallet.SwapResponse?, BraveWallet.SwapErrorResponse?, String) -> Void) {
completion(.init(price: "", guaranteedPrice: "", to: "", data: "", value: "", gas: "", estimatedGas: "", gasPrice: "", protocolFee: "", minimumProtocolFee: "", buyTokenAddress: "", sellTokenAddress: "", buyAmount: "", sellAmount: "", allowanceTarget: "", sellTokenToEthRate: "", buyTokenToEthRate: "", estimatedPriceImpact: "", sources: [], fees: .init(zeroExFee: nil)), nil, "")
}

func jupiterQuote(_ params: BraveWallet.JupiterQuoteParams, completion: @escaping (BraveWallet.JupiterQuote?, BraveWallet.JupiterErrorResponse?, String) -> Void) {
completion(nil, nil, "")
}

func jupiterSwapTransactions(_ params: BraveWallet.JupiterSwapParams, completion: @escaping (Bool, BraveWallet.JupiterSwapTransactions?, String?) -> Void) {
completion(false, nil, nil)
}

func hasJupiterFees(forTokenMint mint: String, completion: @escaping (Bool) -> Void) {
completion(false)
}

func jupiterSwapTransactions(_ params: BraveWallet.JupiterSwapParams, completion: @escaping (BraveWallet.JupiterSwapTransactions?, BraveWallet.JupiterErrorResponse?, String) -> Void) {
completion(nil, .init(statusCode: "0", error: "Error", message: "Error Message", isInsufficientLiquidity: false), "")
func quote(_ params: BraveWallet.SwapQuoteParams, completion: @escaping (BraveWallet.SwapQuoteUnion?, BraveWallet.SwapErrorUnion?, String) -> Void) {
completion(.init(zeroExQuote: .init(price: "", guaranteedPrice: "", to: "", data: "", value: "", gas: "", estimatedGas: "", gasPrice: "", protocolFee: "", minimumProtocolFee: "", buyTokenAddress: "", sellTokenAddress: "", buyAmount: "", sellAmount: "", allowanceTarget: "", sellTokenToEthRate: "", buyTokenToEthRate: "", estimatedPriceImpact: "", sources: [], fees: .init(zeroExFee: nil))), nil, "")
}

func braveFee(_ params: BraveWallet.BraveSwapFeeParams, completion: @escaping (BraveWallet.BraveSwapFeeResponse?, String) -> Void) {
Expand Down
Loading

0 comments on commit 2fd31c3

Please sign in to comment.