Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IOS-7809 Show provider slippage #3971

Merged
merged 6 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class ReceiveCurrencyViewModel: ObservableObject, Identifiable {
@Published private(set) var expressCurrencyViewModel: ExpressCurrencyViewModel
@Published private(set) var cryptoAmountState: LoadableTextView.State

private(set) var expectAmount: Decimal = 0
private(set) var expectAmountDecimals: Int = 0
Vyachesl0ve marked this conversation as resolved.
Show resolved Hide resolved

init(
expressCurrencyViewModel: ExpressCurrencyViewModel,
cryptoAmountState: LoadableTextView.State = .initialized
Expand All @@ -31,10 +34,15 @@ class ReceiveCurrencyViewModel: ObservableObject, Identifiable {

guard let expectAmount else {
update(cryptoAmountState: .loaded(text: "0"))
self.expectAmount = 0
Vyachesl0ve marked this conversation as resolved.
Show resolved Hide resolved
expectAmountDecimals = 0
return
}

self.expectAmount = expectAmount

let decimals = tokenItem?.decimalCount ?? 8
expectAmountDecimals = decimals
let formatter = DecimalNumberFormatter(maximumFractionDigits: decimals)
let formatted: String = formatter.format(value: expectAmount)
update(cryptoAmountState: .loaded(text: formatted))
Expand Down
131 changes: 120 additions & 11 deletions Tangem/Modules/ExpressView/ExpressViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,37 @@ final class ExpressViewModel: ObservableObject {
}

func userDidTapPriceChangeInfoButton(isBigLoss: Bool) {
runTask(in: self) { viewModel in
guard let providerType = await viewModel.interactor.getSelectedProvider()?.provider.type else {
runTask(in: self) { [weak self] viewModel in
guard
let selectedProvider = await viewModel.interactor.getSelectedProvider()?.provider,
let tokenItemSymbol = viewModel.interactor.getDestination()?.tokenItem.currencySymbol
else {
return
}

let message: String = {
switch providerType {
let message: String = { [weak self] in

guard let self else { return "" }

let slippage = Provider(rawValue: selectedProvider.name).maxSlippage
let formattedAmountAfterSlippage = formattedAmountAfterSlippage(for: selectedProvider.name)

switch selectedProvider.type {
case .cex:
let tokenItemSymbol = viewModel.interactor.getDestination()?.tokenItem.currencySymbol ?? ""
return Localization.swappingAlertCexDescription(tokenItemSymbol)
return formSlippageMessage(
tokenItemSymbol: tokenItemSymbol,
slippage: slippage,
providerName: selectedProvider.name,
formattedAmountAfterSlippage
)
case .dex, .dexBridge:
if isBigLoss {
return "\(Localization.swappingHighPriceImpactDescription)\n\n\(Localization.swappingAlertDexDescription)"
}

return Localization.swappingAlertDexDescription
return formSlippageMessage(
tokenItemSymbol: tokenItemSymbol,
slippage: slippage,
isBigLoss: isBigLoss,
providerName: selectedProvider.name,
formattedAmountAfterSlippage
)
}
}()

Expand Down Expand Up @@ -166,6 +181,100 @@ final class ExpressViewModel: ObservableObject {
}
}

// MARK: - Provider slippage message

extension ExpressViewModel {
Vyachesl0ve marked this conversation as resolved.
Show resolved Hide resolved
// TODO: Should be removed into IOS-8137
enum Provider {
case changenow
case changelly
case simpleswap
case changehero
case oneInch
case okxOnchain
case okxCrossChain
case unknown

init(rawValue: String) {
switch rawValue.lowercased() {
case "changenow": self = .changenow
case "changelly": self = .changelly
case "simpleswap": self = .simpleswap
case "changehero": self = .changehero
case "1inch": self = .oneInch
case "okx onchain": self = .okxOnchain
case "okx crosschain": self = .okxCrossChain
default: self = .unknown
}
}

var maxSlippage: Decimal {
switch self {
case .changenow: 3
case .changelly, .simpleswap, .changehero: 5
case .oneInch, .okxOnchain: 2
case .okxCrossChain: 3.5
default: 0
}
}
}
}

private extension ExpressViewModel {
func fetchAmountAfterSlippage(for providerName: String, expectAmount: Decimal) -> Decimal {
let providerSlippage = Provider(rawValue: providerName).maxSlippage
let slippagePercent = (100 - providerSlippage) / 100

return expectAmount * slippagePercent
}

func formattedAmountAfterSlippage(for providerName: String) -> String {
let formatter = DecimalNumberFormatter(
maximumFractionDigits: receiveCurrencyViewModel?.expectAmountDecimals ?? 8
)
let expectAmount = receiveCurrencyViewModel?.expectAmount ?? 0

return formatter.format(
value: fetchAmountAfterSlippage(for: providerName, expectAmount: expectAmount)
)
}

func formSlippageMessage(
tokenItemSymbol: String,
slippage: Decimal,
providerName: String,
_ formattedAmountAfterSlippage: String
) -> String {
if case .unknown = Provider(rawValue: providerName) {
return Localization.swappingAlertCexDescriptionWithoutSlippage(tokenItemSymbol)
} else {
return Localization.swappingAlertCexDescription(tokenItemSymbol, "\(slippage)%", formattedAmountAfterSlippage)
}
}

func formSlippageMessage(
tokenItemSymbol: String,
slippage: Decimal,
isBigLoss: Bool,
providerName: String,
_ formattedAmountAfterSlippage: String
) -> String {
let swappingAlertDexDescription: String = {
if case .unknown = Provider(rawValue: providerName) {
Localization.swappingAlertDexDescriptionWithoutSlippage
} else {
Localization.swappingAlertDexDescription("\(slippage)%", formattedAmountAfterSlippage)
}
}()

if isBigLoss {
return "\(Localization.swappingHighPriceImpactDescription)\n\n\(swappingAlertDexDescription)"
}

return swappingAlertDexDescription
}
}

// MARK: - Navigation

private extension ExpressViewModel {
Expand Down
6 changes: 4 additions & 2 deletions Tangem/Resources/Localizations/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,10 @@
"story_web3_title" = "Web 3.0-kompatibel";
"swap_promo_text" = "Tausche mehr Token zu besseren Kursen direkt in deiner Brieftasche.";
"swap_promo_title" = "Neuer Swap-Anbieter verfügbar!";
"swapping_alert_cex_description" = "Der Betrag umfasst:\n- Gebühr des Dienstanbieters\n- Netzgebühr für die Rücksendung von %@ von der Vermittlungsstelle an die Adresse des Nutzers.";
"swapping_alert_dex_description" = "Der Betrag enthält die Gebühren des Dienstleisters.";
"swapping_alert_cex_description" = "Der Betrag beinhaltet:\n• Honorar des Dienstleisters\n• Netzwerkgebühr für das Senden %@ von der Börse zurück an die Adresse des Benutzers. \n\n Provider-Slippage kann bis zu %@ \n Bei maximaler Abweichung beträgt der zu erhaltende Betrag %@";
"swapping_alert_cex_description_without_slippage" = "Der Betrag beinhaltet:\n• Honorar des Dienstleisters\n• Netzwerkgebühr für das Senden %@ von der Börse zurück an die Adresse des Benutzers. \n\n Provider-Slippage kann bis zu %@ \n Bei maximaler Abweichung beträgt der zu erhaltende Betrag %@";
"swapping_alert_dex_description" = "The amount includes the service provider's fee. \n\nProvider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_dex_description_without_slippage" = "Der Betrag enthält die Gebühren des Dienstleisters.";
"swapping_alert_title" = "Gebühren";
"swapping_approve_information_text" = "Alle dezentralen Börsen benötigen Genehmigungen, um zu verhindern, dass intelligente Verträge ohne Ihre Erlaubnis auf Ihre Geldbörse zugreifen. Smart Contracts können nicht auf Ihre Token zugreifen, wenn Sie nicht zustimmen. Indem Sie Ihre Token \"freischalten\", ermächtigen Sie den 1-Zoll-Smart-Contract, sie auszugeben. Die Miner des Netzwerks erhalten eine (von Ihnen bezahlte) Gasgebühr, um diese Aktion in der Blockchain aufzuzeichnen. Sie können Ihre Token tauschen, nachdem Sie Ihre Zustimmung gegeben haben.";
"swapping_approve_information_title" = "Genehmigen";
Expand Down
6 changes: 4 additions & 2 deletions Tangem/Resources/Localizations/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,10 @@
"story_web3_title" = "Web 3.0 Compatible";
"swap_promo_text" = "Exchange more tokens at better rates directly in your wallet.";
"swap_promo_title" = "New Swap Provider Available!";
"swapping_alert_cex_description" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address.";
"swapping_alert_dex_description" = "The amount includes the service provider's fee.";
"swapping_alert_cex_description" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address. \n\n Provider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_cex_description_without_slippage" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address.";
"swapping_alert_dex_description" = "The amount includes the service provider's fee. \n\nProvider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_dex_description_without_slippage" = "The amount includes the service provider's fee.";
"swapping_alert_title" = "Fees";
"swapping_approve_information_text" = "All decentralized exchanges require approvals to prevent smart contracts from accessing your wallet without your permission. By design, smart contracts can't access your tokens unless you approve. By \"unlocking\" your tokens, you authorize the 1-inch smart contract to spend them. The network's miners receive a gas fee (paid by you) to record this action on the blockchain. You can swap your token after giving approval.";
"swapping_approve_information_title" = "Approve";
Expand Down
6 changes: 4 additions & 2 deletions Tangem/Resources/Localizations/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,10 @@
"story_web3_title" = "Compatible con Web 3.0";
"swap_promo_text" = "Intercambie más tokens a mejores tasas directamente en su billetera.";
"swap_promo_title" = "¡Nuevo proveedor de intercambio disponible!";
"swapping_alert_cex_description" = "El monto incluye:\n• Tarifas del proveedor de servicios\n• Tarifas de red por enviar %@ desde el intercambio a la dirección del usuario.";
"swapping_alert_dex_description" = "El importe incluye los honorarios del proveedor de servicios.";
"swapping_alert_cex_description" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address. \n\n Provider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_cex_description_without_slippage" = "El monto incluye:\n• Tarifas del proveedor de servicios\n• Tarifas de red por enviar %@ desde el intercambio a la dirección del usuario.";
"swapping_alert_dex_description" = "The amount includes the service provider's fee. \n\nProvider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_dex_description_without_slippage" = "El importe incluye los honorarios del proveedor de servicios.";
"swapping_alert_title" = "Tarifa";
"swapping_approve_information_text" = "Todos los exchanges descentralizados requieren aprobaciones para evitar que los smart contracts accedan a su billetera sin su permiso. Por diseño, los smart contracts no pueden acceder a tus tokens a menos que lo apruebes. Al \"desbloquear\" sus tokens, autoriza al smart contract de 1-inch a gastarlos. Los mineros de la red reciben una tarifa de gas (pagada por voz) para registrar esta acción en la blockchain. Puede intercambiar su token después de dar la aprobación.";
"swapping_approve_information_title" = "Aprobar";
Expand Down
6 changes: 4 additions & 2 deletions Tangem/Resources/Localizations/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,10 @@
"story_web3_title" = "Compatible avec Web 3.0";
"swap_promo_text" = "Échangez plus de jetons à de meilleurs taux directement dans votre portefeuille.";
"swap_promo_title" = "Nouveau fournisseur d'échange disponible !";
"swapping_alert_cex_description" = "Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l'envoi de %@ depuis l'échange vers l'adresse de l'utilisateur.";
"swapping_alert_dex_description" = "Le montant comprend les frais du fournisseur de services.";
"swapping_alert_cex_description" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address. \n\n Provider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_cex_description_without_slippage" = "Le montant comprend :\n• les frais du fournisseur de services\n• les frais de réseau pour l'envoi de %@ depuis l'échange vers l'adresse de l'utilisateur.";
"swapping_alert_dex_description" = "The amount includes the service provider's fee. \n\nProvider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_dex_description_without_slippage" = "Le montant comprend les frais du fournisseur de services.";
"swapping_alert_title" = "Frais";
"swapping_approve_information_text" = "Tous les échanges décentralisés nécessitent des approbations pour empêcher les smart contracts d'accéder à votre portefeuille sans votre permission. Par conception, les smart contracts ne peuvent pas accéder à vos jetons sans votre approbation. En « déverrouillant » vos jetons, vous autorisez le smart contract 1-inch à les dépenser. Les mineurs du réseau reçoivent des frais de gaz (payés par vous) pour enregistrer cette action sur la blockchain. Vous pouvez échanger votre jeton après avoir donné votre approbation.";
"swapping_approve_information_title" = "Approuver";
Expand Down
6 changes: 4 additions & 2 deletions Tangem/Resources/Localizations/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,10 @@
"story_web3_title" = "Web 3.0 Compatible";
"swap_promo_text" = "Exchange more tokens at better rates directly in your wallet.";
"swap_promo_title" = "New Swap Provider Available!";
"swapping_alert_cex_description" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address.";
"swapping_alert_dex_description" = "The amount includes the service provider's fee.";
"swapping_alert_cex_description" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address. \n\n Provider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_cex_description_without_slippage" = "The amount includes:\n• service provider's fee\n• network fee for sending %@ from the exchange back to the user's address.";
"swapping_alert_dex_description" = "The amount includes the service provider's fee. \n\nProvider slippage is up to %@ \n At maximum slippage, the amount to be received will be %@";
"swapping_alert_dex_description_without_slippage" = "The amount includes the service provider's fee.";
"swapping_alert_title" = "Fees";
"swapping_approve_information_text" = "All decentralized exchanges require approvals to prevent smart contracts from accessing your wallet without your permission. By design, smart contracts can't access your tokens unless you approve. By \"unlocking\" your tokens, you authorize the 1-inch smart contract to spend them. The network's miners receive a gas fee (paid by you) to record this action on the blockchain. You can swap your token after giving approval.";
"swapping_approve_information_title" = "Approve";
Expand Down
6 changes: 4 additions & 2 deletions Tangem/Resources/Localizations/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,10 @@
"story_web3_title" = "Web3.0対応";
"swap_promo_text" = "より多くのトークンをより良いレートで、ウォレット内にて直接交換します。";
"swap_promo_title" = "新しいスワッププロバイダーが利用可能になりました!";
"swapping_alert_cex_description" = "この金額には以下が含まれます:\n- サービスプロバイダーの手数料\n- 取引所からユーザーのアドレスに%@ を送り返すためのネットワーク手数料。";
"swapping_alert_dex_description" = "この金額には、サービスプロバイダーの手数料が含まれています。";
"swapping_alert_cex_description" = "金額には以下が含まれます: \n • サービス プロバイダーの手数料\n • 取引所からユーザーのアドレスに%@を送金するためのネットワーク手数料。 \n\nプロバイダーのスリッページは最大%@です\n最大スリッページの場合、受け取る金額は%@になります。";
"swapping_alert_cex_description_without_slippage" = "この金額には以下が含まれます:\n- サービスプロバイダーの手数料\n- 取引所からユーザーのアドレスに%@ を送り返すためのネットワーク手数料。";
"swapping_alert_dex_description" = "金額にはサービスプロバイダーの手数料が含まれます。 \n\nプロバイダーのスリッページは最大%@です\n。最大スリッページの場合、受け取る金額は%@になります。";
"swapping_alert_dex_description_without_slippage" = "この金額には、サービスプロバイダーの手数料が含まれています。";
"swapping_alert_title" = "手数料";
"swapping_approve_information_text" = "すべての分散型取引所は、スマートコントラクトがあなたの許可なくウォレットにアクセスするのを防ぐために承認を必要とします。設計上、スマートコントラクトは承認なしでトークンにアクセスできません。トークンを「ロック解除」することで、あなたは1-inchのスマートコントラクトがトークンを使うことを承認します。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためのガス料金(あなたが支払う)を受け取ります。承認後、トークンを交換することができます。";
"swapping_approve_information_title" = "承認";
Expand Down
Loading
Loading