This repository has been archived by the owner on Dec 2, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IOS-6549: Mantle: error when enter max amount (#760)
- Loading branch information
1 parent
6eadbf4
commit fd12511
Showing
6 changed files
with
185 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
BlockchainSdk/Blockchains/Mantle/MantleWalletAssembly.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// | ||
// MantleWalletAssembly.swift | ||
// BlockchainSdk | ||
// | ||
// Created by Aleksei Muraveinik on 15.07.24. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
struct MantleWalletAssembly: WalletManagerAssembly { | ||
func make(with input: WalletManagerAssemblyInput) throws -> WalletManager { | ||
guard let chainId = input.blockchain.chainId else { | ||
throw EthereumWalletAssemblyError.chainIdNotFound | ||
} | ||
|
||
let providers = networkProviderAssembly.makeEthereumJsonRpcProviders(with: input) | ||
let txBuilder = EthereumTransactionBuilder(chainId: chainId) | ||
let networkService = EthereumNetworkService( | ||
decimals: input.blockchain.decimalCount, | ||
providers: providers, | ||
blockcypherProvider: nil, | ||
abiEncoder: WalletCoreABIEncoder() | ||
) | ||
|
||
let addressConverter = EthereumAddressConverterFactory().makeConverter(for: input.blockchain) | ||
|
||
return MantleWalletManager( | ||
wallet: input.wallet, | ||
addressConverter: addressConverter, | ||
txBuilder: txBuilder, | ||
networkService: networkService, | ||
allowsFeeSelection: input.blockchain.allowsFeeSelection) | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
BlockchainSdk/Blockchains/Mantle/MantleWalletManager.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// | ||
// MantleWalletManager.swift | ||
// BlockchainSdk | ||
// | ||
// Created by Aleksei Muraveinik on 15.07.24. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import BigInt | ||
import Combine | ||
import Foundation | ||
|
||
// This is a workaround for sending a Mantle transaction. | ||
// Unfortunately, Mantle's current implementation does not conform to our existing fee calculation rules. | ||
// https://tangem.slack.com/archives/GMXC6PP71/p1719591856597299?thread_ts=1714215815.690169&cid=GMXC6PP71 | ||
final class MantleWalletManager: EthereumWalletManager { | ||
override func getFee(destination: String, value: String?, data: Data?) -> AnyPublisher<[Fee], any Error> { | ||
let blockchain = wallet.blockchain | ||
|
||
let adjustedValue = value | ||
.flatMap { value in | ||
EthereumUtils.parseEthereumDecimal(value, decimalsCount: blockchain.decimalCount) | ||
} | ||
.flatMap { parsedValue in | ||
Amount( | ||
with: blockchain, | ||
type: .coin, | ||
value: parsedValue - (1 / blockchain.decimalValue) | ||
) | ||
.encodedForSend | ||
} | ||
|
||
return super.getFee(destination: destination, value: adjustedValue, data: data) | ||
.withWeakCaptureOf(self) | ||
.tryMap { walletManager, fees in | ||
try fees.map { fee in | ||
try walletManager.mapMantleFee(fee, gasLimitMultiplier: 1.6) | ||
} | ||
} | ||
.eraseToAnyPublisher() | ||
} | ||
|
||
override func sign(_ transaction: Transaction, signer: any TransactionSigner) -> AnyPublisher<String, any Error> { | ||
var transaction = transaction | ||
do { | ||
transaction.fee = try mapMantleFee(transaction.fee, gasLimitMultiplier: 0.7) | ||
} catch { | ||
return Fail(error: error).eraseToAnyPublisher() | ||
} | ||
return super.sign(transaction, signer: signer) | ||
} | ||
} | ||
|
||
// MARK: - Private | ||
|
||
private extension MantleWalletManager { | ||
func mapMantleFee(_ fee: Fee, gasLimitMultiplier: Double) throws -> Fee { | ||
let parameters: any EthereumFeeParameters = switch fee.parameters { | ||
case let parameters as EthereumEIP1559FeeParameters: | ||
EthereumEIP1559FeeParameters( | ||
gasLimit: BigUInt(ceil(Double(parameters.gasLimit) * gasLimitMultiplier)), | ||
maxFeePerGas: parameters.maxFeePerGas, | ||
priorityFee: parameters.priorityFee | ||
) | ||
case let parameters as EthereumLegacyFeeParameters: | ||
EthereumLegacyFeeParameters( | ||
gasLimit: BigUInt(ceil(Double(parameters.gasLimit) * gasLimitMultiplier)), | ||
gasPrice: parameters.gasPrice | ||
) | ||
default: | ||
throw WalletError.failedToGetFee | ||
} | ||
|
||
let blockchain = wallet.blockchain | ||
let feeValue = parameters.calculateFee(decimalValue: blockchain.decimalValue) | ||
let amount = Amount(with: blockchain, value: feeValue) | ||
|
||
return Fee(amount, parameters: parameters) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// | ||
// MantleTests.swift | ||
// BlockchainSdkTests | ||
// | ||
// Created by Aleksei Muraveinik on 16.07.24. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
@testable import BlockchainSdk | ||
|
||
final class MantleTests: XCTestCase { | ||
private let blockchain = Blockchain.mantle(testnet: false) | ||
|
||
func testDecodeEncodedForSend() throws { | ||
let testCases: [Decimal] = [ | ||
try XCTUnwrap(Decimal(stringValue: "29.618123086712134")), | ||
try XCTUnwrap(Decimal(stringValue: "0.000000000003194")), | ||
try XCTUnwrap(Decimal(stringValue: "84.329847293749302")), | ||
try XCTUnwrap(Decimal(stringValue: "19.287394872934987")), | ||
try XCTUnwrap(Decimal(stringValue: "73.928374982374892")), | ||
try XCTUnwrap(Decimal(stringValue: "1.847392874932748")), | ||
try XCTUnwrap(Decimal(stringValue: "47.832984723984723")), | ||
try XCTUnwrap(Decimal(stringValue: "0.0000000001234567")), | ||
try XCTUnwrap(Decimal(stringValue: "56.392847293847298")) | ||
] | ||
|
||
try testCases.forEach { decimal in | ||
let amount = Amount(with: blockchain, type: .coin, value: decimal) | ||
|
||
let encodedForSend = try XCTUnwrap(amount.encodedForSend) | ||
let decodedValue = EthereumUtils.parseEthereumDecimal(encodedForSend, decimalsCount: blockchain.decimalCount) | ||
|
||
XCTAssertEqual(decodedValue, decimal) | ||
} | ||
} | ||
} |