Skip to content

Commit

Permalink
Refactor(tx history): Fix misrepresented fees field
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlVS committed Dec 2, 2024
1 parent 488aa1e commit 33611b7
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ export 'activation/tokens_request.dart';
export 'activation/utxo_merge_params.dart';
export 'general/address_format.dart';
export 'general/balance_info.dart';
export 'general/fee_info.dart';
export 'general/new_address_info.dart';
export 'general/scan_address_info.dart';
export 'general/sync_status.dart';
export 'general/token_balance.dart';
export 'general/wallet_info.dart';
export 'general/withdraw_fee.dart';
export 'hd_wallet/account_balance_info.dart';
export 'hd_wallet/address_info.dart';
export 'hd_wallet/derivation_method.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:decimal/decimal.dart';
import 'package:komodo_defi_types/komodo_defi_types.dart';

class FeeInfo {
const FeeInfo._({
required this.type,
required this.amount,
this.gas,
this.gasPrice,
});

FeeInfo.utxoFixed(Decimal amount)
: this._(type: WithdrawalFeeType.utxo, amount: amount);

factory FeeInfo.erc20(Decimal gasPrice, int gasLimit) {
final totalFee = _calculateTotalFee(gasPrice, gasLimit);
return FeeInfo._(
type: WithdrawalFeeType.eth,
gas: gasLimit,
gasPrice: gasPrice.toString(),
amount: totalFee,
);
}

factory FeeInfo.fromJson(Map<String, dynamic> json) {
final type = WithdrawalFeeType.parse(json.value<String>('type'));
final gas = json.valueOrNull<int>('gas');
final gasPriceString = json.valueOrNull<String>('gas_price');

// For ERC20-type fees, calculate total from gas if available
if (type == WithdrawalFeeType.eth &&
gas != null &&
gasPriceString != null) {
final gasPrice = Decimal.parse(gasPriceString);
final totalFee = _calculateTotalFee(gasPrice, gas);
return FeeInfo._(
type: type,
amount: totalFee,
gas: gas,
gasPrice: gasPriceString,
);
}

// For other types or when gas details aren't available
return FeeInfo._(
type: type,
amount: Decimal.parse(
json.valueOrNull<String>('amount') ?? json.value('total_fee'),
),
gas: gas,
gasPrice: gasPriceString,
);
}

final WithdrawalFeeType type;
final Decimal amount;
final int? gas;
final String? gasPrice;

/// Gets the total fee amount in the native coin unit
Decimal get totalFee => amount;

/// Gets the gas price in Gwei if available
Decimal? get gasPriceInGwei =>
gasPrice != null ? Decimal.parse(gasPrice!) : null;

/// Calculate total fee from gas parameters (gas price in Gwei)
static Decimal _calculateTotalFee(Decimal gasPriceGwei, int gasUnits) {
return (gasPriceGwei.toRational() *
(Decimal.fromInt(gasUnits).toRational() /
Decimal.fromInt(1000000000).toRational()))
.toDecimal(scaleOnInfinitePrecision: 18);
}

Map<String, dynamic> toJson() {
return {
'type': type.toString(),
'amount': amount.toString(),
'total_fee': amount.toString(),
if (gas != null) 'gas': gas,
if (gasPrice != null) 'gas_price': gasPrice,
};
}

@override
String toString() => toJson().toString();
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class TransactionInfo {
confirmations: json.value<int>('confirmations'),
timestamp: json.value<int>('timestamp'),
feeDetails: json.containsKey('fee_details')
? WithdrawFee.fromJson(json.value('fee_details'))
? FeeInfo.fromJson(json.value('fee_details'))
: null,
transactionFee: json.valueOrNull<String>('transaction_fee'),
coin: json.value<String>('coin'),
Expand All @@ -47,7 +47,7 @@ class TransactionInfo {
final int blockHeight;
final int confirmations;
final int timestamp;
final WithdrawFee? feeDetails;
final FeeInfo? feeDetails;
final String? transactionFee;
final String coin;
final String internalId;
Expand Down Expand Up @@ -82,7 +82,7 @@ class TransactionInfo {
blockHeight: blockHeight,
from: from,
to: to,
fee: feeDetails?.amount,
fee: feeDetails,
txHash: txHash,
memo: memo,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class WithdrawLegacyRequest
final String coin;
final String to;
final Decimal amount;
final WithdrawFee? fee;
final FeeInfo? fee;
final WithdrawalSource? from;
final String? memo;
final bool max;
Expand Down Expand Up @@ -82,7 +82,7 @@ class WithdrawInitRequest
final String coin;
final String to;
final String? amount;
final WithdrawFee? fee;
final FeeInfo? fee;
final WithdrawalSource? from;
final String? memo;
final bool max;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {

PubkeyInfo? _selectedFromAddress;
bool _isMaxAmount = false;
WithdrawFee? _selectedFee;
FeeInfo? _selectedFee;
WithdrawalPreview? _preview;
String? _error;
bool _isIbcTransfer = false;
Expand Down Expand Up @@ -81,7 +81,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {

setState(() {
_preview = preview;
_selectedFee = preview.feeDetails;
_selectedFee = preview.fee;
});

await _showPreviewDialog(params);
Expand All @@ -106,7 +106,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {
children: [
Text('Amount: ${_preview!.totalAmount} ${widget.asset.id.id}'),
Text('To: ${_preview!.to.first}'),
_buildFeeDetails(_preview!.feeDetails),
_buildFeeDetails(_preview!.fee),
if (_preview!.kmdRewards != null) ...[
const SizedBox(height: 8),
Text(
Expand Down Expand Up @@ -144,7 +144,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {
}
}

Widget _buildFeeDetails(WithdrawFee details) {
Widget _buildFeeDetails(FeeInfo details) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand Down Expand Up @@ -247,7 +247,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {
final gasPrice = Decimal.tryParse(value);
if (gasPrice != null) {
setState(() {
_selectedFee = WithdrawFee.erc20(
_selectedFee = FeeInfo.erc20(
gasPrice,
_selectedFee?.gas ?? 21000,
);
Expand All @@ -269,7 +269,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {
final gasLimit = int.tryParse(value);
if (gasLimit != null) {
setState(() {
_selectedFee = WithdrawFee.erc20(
_selectedFee = FeeInfo.erc20(
Decimal.parse(_selectedFee?.gasPrice ?? '1'),
gasLimit,
);
Expand Down Expand Up @@ -314,7 +314,7 @@ class _WithdrawalScreenState extends State<WithdrawalScreen> {
? null
: (value) {
setState(() {
_selectedFee = WithdrawFee.utxoFixed(value.first);
_selectedFee = FeeInfo.utxoFixed(value.first);
});
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class EtherscanTransactionStrategy extends TransactionHistoryStrategy {
confirmations: tx.value<int>('confirmations'),
timestamp: tx.value<int>('timestamp'),
feeDetails: tx.valueOrNull<JsonMap>('fee_details') != null
? WithdrawFee.fromJson(
? FeeInfo.fromJson(
tx.value<JsonMap>('fee_details')
..setIfAbsentOrEmpty('type', 'Eth'),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class WithdrawalManager {
amount: Decimal.parse(details.totalAmount),
coin: parameters.asset,
toAddress: parameters.toAddress,
fee: Decimal.parse(details.feeDetails.toString()),
fee: details.fee,
kmdRewardsEligible: details.kmdRewards != null &&
(details.kmdRewards?.amount ?? '0') != '0',
),
Expand Down Expand Up @@ -100,7 +100,7 @@ class WithdrawalManager {
amount: Decimal.parse(result.totalAmount),
coin: result.coin,
toAddress: result.to.first,
fee: result.feeDetails.amount,
fee: result.fee,
kmdRewardsEligible: result.kmdRewards != null,
),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// TODO: Put public facing types in this file.

export 'package:komodo_defi_rpc_methods/komodo_defi_rpc_methods.dart'
show WithdrawFee;
show FeeInfo;

typedef LogCallback = void Function(String message);
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ class Transaction extends Equatable {
from: List<String>.from(json.value('from')),
to: List<String>.from(json.value('to')),
txHash: json.valueOrNull<String>('tx_hash'),
fee: json.valueOrNull<String>('fee') != null
? Decimal.parse(json.value<String>('fee'))
fee: json.containsKey('fee')
? FeeInfo.fromJson(json.value('fee'))
: null,
memo: json.valueOrNull<String>('memo'),
);
Expand All @@ -52,7 +52,7 @@ class Transaction extends Equatable {
// Null for cases such as SIA coin. TODO: Consider if there is a better way
// represent this property usin
final String? txHash;
final Decimal? fee;
final FeeInfo? fee;
final String? memo;

bool get isIncoming => amount > Decimal.zero;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class WithdrawResult {
required this.myBalanceChange,
required this.blockHeight,
required this.timestamp,
required this.feeDetails,
required this.fee,
required this.coin,
this.internalId,
this.kmdRewards,
Expand All @@ -34,7 +34,7 @@ class WithdrawResult {
myBalanceChange: json.value<String>('my_balance_change'),
blockHeight: json.value<int>('block_height'),
timestamp: json.value<int>('timestamp'),
feeDetails: WithdrawFee.fromJson(json.value<JsonMap>('fee_details')),
fee: FeeInfo.fromJson(json.value<JsonMap>('fee_details')),
coin: json.value<String>('coin'),
internalId: json.valueOrNull<String>('internal_id'),
kmdRewards: json.containsKey('kmd_rewards')
Expand All @@ -54,7 +54,7 @@ class WithdrawResult {
final String myBalanceChange;
final int blockHeight;
final int timestamp;
final WithdrawFee feeDetails;
final FeeInfo fee;
final String coin;
final String? internalId;
final KmdRewards? kmdRewards;
Expand All @@ -71,7 +71,7 @@ class WithdrawResult {
'my_balance_change': myBalanceChange,
'block_height': blockHeight,
'timestamp': timestamp,
'fee_details': feeDetails.toJson(),
'fee_details': fee.toJson(),
'coin': coin,
if (internalId != null) 'internal_id': internalId,
if (kmdRewards != null) 'kmd_rewards': kmdRewards!.toJson(),
Expand Down Expand Up @@ -110,7 +110,7 @@ class WithdrawalResult {
final Decimal amount;
final String coin;
final String toAddress;
final Decimal fee;
final FeeInfo fee;
final bool kmdRewardsEligible;
}

Expand Down Expand Up @@ -160,7 +160,7 @@ class WithdrawParameters {
final String asset;
final String toAddress;
final Decimal? amount;
final WithdrawFee? fee;
final FeeInfo? fee;
final WithdrawalSource? from;
final String? memo;
final bool? ibcTransfer;
Expand Down
1 change: 1 addition & 0 deletions packages/komodo_defi_types/lib/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export 'src/exceptions/http_exceptions.dart';
export 'src/generic/result.dart';
export 'src/generic/sync_status.dart';
export 'src/komodo_defi_types_base.dart';
export 'src/legacy/legacy_coin_model.dart';
export 'src/protocols/base/exceptions.dart';
export 'src/protocols/base/protocol_class.dart';
export 'src/protocols/erc20/erc20_protocol.dart';
Expand Down

0 comments on commit 33611b7

Please sign in to comment.