Skip to content

Commit

Permalink
feat: show incoming link amount (#1610)
Browse files Browse the repository at this point in the history
  • Loading branch information
justinenerio authored Nov 28, 2024
1 parent 8e8e052 commit 936e2c4
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 12 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 @@ -24,7 +24,7 @@ class OutgoingTransferRows extends Table {
Set<Column<Object>> get primaryKey => {id};
}

const int latestVersion = 59;
const int latestVersion = 60;

const _tables = [
OutgoingTransferRows,
Expand Down Expand Up @@ -168,6 +168,9 @@ class MyDatabase extends _$MyDatabase {
await m.addColumn(offRampOrderRows, offRampOrderRows.priorityFee);
await m.addColumn(offRampOrderRows, offRampOrderRows.gasFee);
}
if (from >= 39 && from < 60) {
await m.addColumn(iLPRows, iLPRows.receiveAmount);
}
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ class AnalyticsManager {
properties: {'amount': amount.toDouble()},
);

void singleLinkReceived() => _analytics.track('singleLinkReceived');
void singleLinkReceived({
required Decimal? amount,
}) =>
_analytics.track(
'singleLinkReceived',
properties: amount != null ? {'amount': amount.toDouble()} : {},
);

void directPaymentSent({
required Decimal amount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class ILPRows extends Table with EntityMixin, TxStatusMixin {
IntColumn get status => intEnum<ILPStatusDto>()();

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

enum ILPStatusDto {
Expand Down Expand Up @@ -105,12 +106,19 @@ extension on ILPStatusDto {
);
case ILPStatusDto.success:
final feeAmount = row.feeAmount;
final receiveAmount = row.receiveAmount;

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ sealed class ILPStatus with _$ILPStatus {
const factory ILPStatus.success({
required SignedTx tx,
required CryptoAmount? fee,
required CryptoAmount? receiveAmount,
}) = ILPStatusSuccess;

/// Failed to create the tx, a new tx should be created.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,20 @@ class _IncomingLinkPaymentScreenState extends State<IncomingLinkPaymentScreen> {
onBack: () => Navigator.pop(context),
)
: payment.status.maybeMap(
success: (e) => TransferSuccess(
onBack: () => Navigator.pop(context),
onOkPressed: () => Navigator.pop(context),
content: e.fee?.let(_FeeNotice.new),
statusContent: context.l10n.moneyReceived,
),
success: (e) {
final receiveAmount = e.receiveAmount?.let(
(e) => e.format(context.locale, maxDecimals: 2),
);

return TransferSuccess(
onBack: () => Navigator.pop(context),
onOkPressed: () => Navigator.pop(context),
content: e.fee?.let(_FeeNotice.new),
statusContent: receiveAmount != null
? context.l10n.moneyReceivedAmount(receiveAmount)
: context.l10n.moneyReceived,
);
},
txFailure: (it) => it.reason == TxFailureReason.escrowFailure
? const InvalidEscrowErrorWidget()
: TransferError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import 'package:espressocash_api/espressocash_api.dart';
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'package:rxdart/rxdart.dart';
import 'package:solana/dto.dart';
import 'package:solana/encoder.dart';
import 'package:solana/solana.dart';
import 'package:uuid/uuid.dart';

import '../../accounts/auth_scope.dart';
import '../../accounts/models/ec_wallet.dart';
import '../../analytics/analytics_manager.dart';
import '../../balances/services/refresh_balance.dart';
import '../../currency/models/amount.dart';
import '../../currency/models/currency.dart';
import '../../escrow/models/escrow_private_key.dart';
import '../../escrow_payments/create_incoming_escrow.dart';
import '../../escrow_payments/escrow_exception.dart';
import '../../tokens/token.dart';
import '../../transactions/models/tx_results.dart';
import '../../transactions/services/resign_tx.dart';
import '../../transactions/services/tx_confirm.dart';
Expand All @@ -31,13 +34,19 @@ class ILPService implements Disposable {
this._ecClient,
this._refreshBalance,
this._txConfirm,
this._solanaClient,
this._wallet,
this._analytics,
);

final ILPRepository _repository;
final CreateIncomingEscrow _createIncomingEscrow;
final EspressoCashClient _ecClient;
final RefreshBalance _refreshBalance;
final TxConfirm _txConfirm;
final SolanaClient _solanaClient;
final ECWallet _wallet;
final AnalyticsManager _analytics;

final Map<String, StreamSubscription<void>> _subscriptions = {};

Expand Down Expand Up @@ -147,6 +156,8 @@ class ILPService implements Disposable {

await _txConfirm(txId: status.signature);

final receiveAmount = await _getUsdcAmount(status.signature);

int? fee;
try {
fee = status.tx.containsAta
Expand All @@ -158,16 +169,68 @@ class ILPService implements Disposable {

_refreshBalance();

_analytics.singleLinkReceived(amount: receiveAmount?.decimal);

return payment.copyWith(
status: ILPStatus.success(
tx: status.tx,
receiveAmount: receiveAmount,
fee: fee?.let(
(fee) => CryptoAmount(value: fee, cryptoCurrency: Currency.usdc),
),
),
);
}

Future<CryptoAmount?> _getUsdcAmount(String signature) async {
try {
final details = await _solanaClient.rpcClient.getTransaction(
signature,
encoding: Encoding.base64,
commitment: Commitment.confirmed,
);

if (details == null) return null;

final usdcTokenAddress = await findAssociatedTokenAddress(
owner: _wallet.publicKey,
mint: Ed25519HDPublicKey.fromBase58(Token.usdc.address),
);

final rawTx = details.transaction as RawTransaction;
final tx = SignedTx.fromBytes(rawTx.data);

final accountIndex = tx.compiledMessage.accountKeys
.indexWhere((e) => e == usdcTokenAddress);

final postTokenBalance = details.meta?.postTokenBalances
.where((e) => e.mint == Token.usdc.address)
.where((e) => e.accountIndex == accountIndex)
.firstOrNull;

if (postTokenBalance == null) return null;

final preTokenBalance = details.meta?.preTokenBalances
.where((e) => e.mint == Token.usdc.address)
.where((e) => e.accountIndex == accountIndex)
.firstOrNull;

final preAmount = preTokenBalance?.uiTokenAmount.amount ?? '0';
final postAmount = postTokenBalance.uiTokenAmount.amount;

final rawAmount = int.parse(postAmount) - int.parse(preAmount);

if (rawAmount <= 0) return null;

return CryptoAmount(
value: rawAmount,
cryptoCurrency: Currency.usdc,
);
} on Exception {
return null;
}
}

@override
Future<void> onDispose() async {
await Future.wait(_subscriptions.values.map((it) => it.cancel()));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';

import '../../../di.dart';
import '../../accounts/models/wallet.dart';
import '../../analytics/analytics_manager.dart';
import '../../dynamic_links/widgets/dynamic_link_handler.dart';
import '../../link_payments/models/link_payment.dart';
import '../screens/incoming_link_payment_screen.dart';
Expand Down Expand Up @@ -36,7 +34,6 @@ class _PendingILPListenerState extends State<PendingILPListener>
final payment = LinkPayment.tryParse(uri);

if (payment != null) {
sl<AnalyticsManager>().singleLinkReceived();
_processLink(payment);

return true;
Expand Down
8 changes: 8 additions & 0 deletions packages/espressocash_app/lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@
"@mobileWalletTitle": {},
"moneyReceived": "Money has been received",
"@moneyReceived": {},
"moneyReceivedAmount": "{amount} Transaction successful received",
"@moneyReceivedAmount": {
"placeholders": {
"amount": {
"type": "String"
}
}
},
"moreDetails": "View more details",
"@moreDetails": {},
"next": "Next",
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/espressocash_app/test/stub_analytics_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class StubAnalyticsManager implements AnalyticsManager {
void singleLinkCreated({required Decimal amount}) {}

@override
void singleLinkReceived() {}
void singleLinkReceived({required Decimal? amount}) {}

@override
void swapTransactionCreated({
Expand Down

0 comments on commit 936e2c4

Please sign in to comment.