Skip to content

Commit

Permalink
feat: dynamic first incoming fee (#1197)
Browse files Browse the repository at this point in the history
  • Loading branch information
ookami-kb authored Dec 30, 2023
1 parent e2ba008 commit 7415667
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 16 deletions.
5 changes: 4 additions & 1 deletion packages/espressocash_app/lib/data/db/db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class OutgoingTransferRows extends Table {
Set<Column<Object>> get primaryKey => {id};
}

const int latestVersion = 45;
const int latestVersion = 46;

const _tables = [
OutgoingTransferRows,
Expand Down Expand Up @@ -200,6 +200,9 @@ class MyDatabase extends _$MyDatabase {
);
await m.addColumn(onRampOrderRows, onRampOrderRows.fiatSymbol);
}
if (from >= 39 && from < 46) {
await m.addColumn(iLPRows, iLPRows.feeAmount);
}
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:solana/base58.dart';
import 'package:solana/encoder.dart';

import '../../../core/amount.dart';
import '../../../core/currency.dart';
import '../../../core/escrow_private_key.dart';
import '../../../data/db/db.dart';
import '../../../data/db/mixins.dart';
Expand Down Expand Up @@ -77,6 +79,8 @@ class ILPRows extends Table with EntityMixin, TxStatusMixin {

TextColumn get privateKey => text()();
IntColumn get status => intEnum<ILPStatusDto>()();

IntColumn get feeAmount => integer().nullable()();
}

enum ILPStatusDto {
Expand Down Expand Up @@ -113,8 +117,13 @@ extension on ILPStatusDto {
slot: slot ?? BigInt.zero,
);
case ILPStatusDto.success:
final feeAmount = row.feeAmount;

return ILPStatus.success(
tx: tx ?? StubSignedTx(txId!),
fee: feeAmount != null
? CryptoAmount(value: feeAmount, cryptoCurrency: Currency.usdc)
: null,
);
case ILPStatusDto.txFailure:
return ILPStatus.txFailure(
Expand All @@ -134,6 +143,10 @@ extension on IncomingLinkPayment {
txId: status.toTxId(),
slot: status.toSlot().toString(),
txFailureReason: status.toTxFailureReason(),
feeAmount: switch (status) {
ILPStatusSuccess(:final fee) => fee?.value,
_ => null,
},
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:solana/encoder.dart';

import '../../../core/amount.dart';
import '../../../core/escrow_private_key.dart';
import '../../transactions/models/tx_results.dart';

Expand All @@ -17,7 +18,7 @@ class IncomingLinkPayment with _$IncomingLinkPayment {
}

@freezed
class ILPStatus with _$ILPStatus {
sealed class ILPStatus with _$ILPStatus {
/// Tx is successfully created and ready to be sent.
const factory ILPStatus.txCreated(
SignedTx tx, {
Expand All @@ -33,6 +34,7 @@ class ILPStatus with _$ILPStatus {
/// Final state. Tx is successfully confirmed and payment is claimed.
const factory ILPStatus.success({
required SignedTx tx,
required CryptoAmount? fee,
}) = ILPStatusSuccess;

/// Failed to create the tx, a new tx should be created.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import 'package:auto_route/auto_route.dart';
import 'package:dfunc/dfunc.dart';
import 'package:flutter/material.dart';

import '../../../core/amount.dart';
import '../../../core/presentation/format_amount.dart';
import '../../../di.dart';
import '../../../l10n/device_locale.dart';
import '../../../l10n/l10n.dart';
import '../../../routes.gr.dart';
import '../../../ui/colors.dart';
Expand All @@ -13,7 +17,6 @@ import '../../transactions/widgets/transfer_progress.dart';
import '../../transactions/widgets/transfer_success.dart';
import '../data/ilp_repository.dart';
import '../models/incoming_link_payment.dart';
import '../services/tx_sent_watcher.dart';
import '../widgets/extensions.dart';
import '../widgets/invalid_escrow_error_widget.dart';

Expand Down Expand Up @@ -56,7 +59,7 @@ class _IncomingLinkPaymentScreenState extends State<IncomingLinkPaymentScreen> {
success: (e) => TransferSuccess(
onBack: () => context.router.pop(),
onOkPressed: () => context.router.pop(),
content: e.tx.containsAta ? const _FeeNotice() : null,
content: e.fee?.let(_FeeNotice.new),
statusContent: context.l10n.moneyReceived,
),
txFailure: (it) => it.reason == TxFailureReason.escrowFailure
Expand All @@ -74,7 +77,9 @@ class _IncomingLinkPaymentScreenState extends State<IncomingLinkPaymentScreen> {
}

class _FeeNotice extends StatelessWidget {
const _FeeNotice();
const _FeeNotice(this.amount);

final CryptoAmount amount;

@override
Widget build(BuildContext context) => Expanded(
Expand All @@ -96,7 +101,8 @@ class _FeeNotice extends StatelessWidget {
const SizedBox(width: 16),
Expanded(
child: Text(
context.l10n.incomingUsdcFeeNotice,
context.l10n
.incomingUsdcFeeNotice(amount.format(context.locale)),
style: const TextStyle(
color: Colors.white,
fontSize: 14.50,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import 'dart:async';

import 'package:dfunc/dfunc.dart';
import 'package:espressocash_api/espressocash_api.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:injectable/injectable.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:solana/encoder.dart';
import 'package:solana/solana.dart';

import '../../../core/amount.dart';
import '../../../core/cancelable_job.dart';
import '../../../core/currency.dart';
import '../../transactions/models/tx_results.dart';
import '../../transactions/services/tx_sender.dart';
import '../data/ilp_repository.dart';
Expand All @@ -18,15 +21,16 @@ import 'payment_watcher.dart';
/// confirmed.
@injectable
class TxSentWatcher extends PaymentWatcher {
TxSentWatcher(super._repository, this._sender);
TxSentWatcher(super._repository, this._sender, this._cryptopleaseClient);

final TxSender _sender;
final CryptopleaseClient _cryptopleaseClient;

@override
CancelableJob<IncomingLinkPayment> createJob(
IncomingLinkPayment payment,
) =>
_ILPTxSentJob(payment, _sender);
_ILPTxSentJob(payment, _sender, _cryptopleaseClient);

@override
Stream<IList<IncomingLinkPayment>> watchPayments(
Expand All @@ -36,10 +40,11 @@ class TxSentWatcher extends PaymentWatcher {
}

class _ILPTxSentJob extends CancelableJob<IncomingLinkPayment> {
const _ILPTxSentJob(this.payment, this.sender);
const _ILPTxSentJob(this.payment, this.sender, this._cryptopleaseClient);

final IncomingLinkPayment payment;
final TxSender sender;
final CryptopleaseClient _cryptopleaseClient;

@override
Future<IncomingLinkPayment?> process() async {
Expand All @@ -50,13 +55,30 @@ class _ILPTxSentJob extends CancelableJob<IncomingLinkPayment> {

final tx = await sender.wait(status.tx, minContextSlot: status.slot);

final newStatus = tx.map(
success: (_) => ILPStatus.success(tx: status.tx),
failure: (_) => const ILPStatus.txFailure(
final newStatus = await tx.map(
success: (_) async {
try {
final fee = status.tx.containsAta
? await _cryptopleaseClient
.getFees()
.then((value) => value.escrowPaymentAtaFee)
: null;

return ILPStatus.success(
tx: status.tx,
fee: fee?.let(
(fee) => CryptoAmount(value: fee, cryptoCurrency: Currency.usdc),
),
);
} on Object {
return null;
}
},
failure: (_) async => const ILPStatus.txFailure(
reason: TxFailureReason.escrowFailure,
),
networkError: (_) {
Sentry.addBreadcrumb(Breadcrumb(message: 'Network error'));
networkError: (_) async {
await Sentry.addBreadcrumb(Breadcrumb(message: 'Network error'));
},
);

Expand Down
10 changes: 8 additions & 2 deletions packages/espressocash_app/lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,14 @@
},
"onRampAwaitingFunds": "Hang tight. Your order is being processed.",
"@onRampAwaitingFunds": {},
"incomingUsdcFeeNotice": "You were charged a one time $0.10 fee for your first incoming transaction.",
"@incomingUsdcFeeNotice": {},
"incomingUsdcFeeNotice": "You were charged a one time {amount} fee for your first incoming transaction.",
"@incomingUsdcFeeNotice": {
"placeholders": {
"amount": {
"type": "String"
}
}
},
"depositTitle": "Add Cash",
"@depositTitle": {},
"depositInstruction1": "Transfer money from your bank account to our local partner:",
Expand Down

Large diffs are not rendered by default.

0 comments on commit 7415667

Please sign in to comment.