Skip to content

Commit 7226ece

Browse files
authored
feat: offramp updates (#1143)
1 parent a02f4bb commit 7226ece

File tree

8 files changed

+139
-39
lines changed

8 files changed

+139
-39
lines changed

packages/espressocash_app/lib/data/db/db.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class OutgoingTransferRows extends Table {
2929
Set<Column<Object>> get primaryKey => {id};
3030
}
3131

32-
const int latestVersion = 41;
32+
const int latestVersion = 42;
3333

3434
const _tables = [
3535
OutgoingTransferRows,
@@ -176,6 +176,9 @@ class MyDatabase extends _$MyDatabase {
176176
if (from >= 37 && from < 41) {
177177
await m.addColumn(onRampOrderRows, onRampOrderRows.partner);
178178
}
179+
if (from >= 40 && from < 42) {
180+
await m.addColumn(offRampOrderRows, offRampOrderRows.partner);
181+
}
179182
},
180183
);
181184

@@ -229,6 +232,8 @@ class OffRampOrderRows extends Table with AmountMixin, EntityMixin {
229232
TextColumn get transaction => text()();
230233
TextColumn get depositAddress => text()();
231234
Int64Column get slot => int64()();
235+
TextColumn get partner =>
236+
textEnum<RampPartner>().withDefault(const Constant('kado'))();
232237
}
233238

234239
enum OffRampOrderStatus {

packages/espressocash_app/lib/features/activities/services/pending_activities_repository.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../../outgoing_direct_payments/data/repository.dart';
1010
import '../../outgoing_link_payments/data/repository.dart';
1111
import '../../payment_request/data/repository.dart';
1212
import '../../ramp/data/on_ramp_order_service.dart';
13-
import '../../ramp/services/kado_off_ramp_order_service.dart';
13+
import '../../ramp/services/off_ramp_order_service.dart';
1414
import '../../swap/data/swap_repository.dart';
1515
import '../data/activity_builder.dart';
1616
import '../models/activity.dart';
@@ -27,7 +27,7 @@ class PendingActivitiesRepository {
2727
final MyDatabase _db;
2828
final TokenList _tokens;
2929
final OnRampOrderService _onRampOrderService;
30-
final KadoOffRampOrderService _offRampOrderService;
30+
final OffRampOrderService _offRampOrderService;
3131

3232
Stream<IList<Activity>> watchAll() {
3333
final opr = _db.select(_db.paymentRequestRows)

packages/espressocash_app/lib/features/activities/widgets/off_ramp_tile.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../../../gen/assets.gen.dart';
1010
import '../../../l10n/device_locale.dart';
1111
import '../../../l10n/l10n.dart';
1212
import '../../ramp/screens/off_ramp_order_screen.dart';
13-
import '../../ramp/services/kado_off_ramp_order_service.dart';
13+
import '../../ramp/services/off_ramp_order_service.dart';
1414
import '../models/activity.dart';
1515
import 'activity_tile.dart';
1616

@@ -24,7 +24,7 @@ class OffRampTile extends StatefulWidget {
2424
}
2525

2626
class _OffRampTileState extends State<OffRampTile> {
27-
late final _stream = sl<KadoOffRampOrderService>().watch(widget.activity.id);
27+
late final _stream = sl<OffRampOrderService>().watch(widget.activity.id);
2828

2929
@override
3030
Widget build(BuildContext context) => StreamBuilder<OffRampOrder>(
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import 'dart:async';
2+
3+
import 'package:drift/drift.dart';
4+
import 'package:injectable/injectable.dart';
5+
import 'package:rxdart/rxdart.dart';
6+
7+
import '../../../../data/db/db.dart';
8+
import '../../src/models/ramp_watcher.dart';
9+
import '../data/kado_api_client.dart';
10+
11+
@injectable
12+
class KadoOffRampOrderWatcher implements RampWatcher {
13+
KadoOffRampOrderWatcher(this._db, this._client);
14+
15+
final MyDatabase _db;
16+
final KadoApiClient _client;
17+
18+
StreamSubscription<void>? _subscription;
19+
20+
@override
21+
void watch(String orderId) {
22+
_subscription = Stream<void>.periodic(const Duration(seconds: 10))
23+
.asyncMap(
24+
(_) {
25+
final query = _db.select(_db.offRampOrderRows)
26+
..where(
27+
(tbl) =>
28+
tbl.id.equals(orderId) &
29+
tbl.status
30+
.equals(OffRampOrderStatus.waitingForPartner.name),
31+
);
32+
33+
return query.getSingleOrNull();
34+
},
35+
)
36+
.whereNotNull()
37+
.asyncMap((order) => _client.getOrderStatus(order.partnerOrderId))
38+
.listen((event) async {
39+
// ignore: prefer-early-return, cannot use
40+
if (event.data case final data?) {
41+
final statement = _db.update(_db.offRampOrderRows)
42+
..where(
43+
(tbl) =>
44+
tbl.id.equals(orderId) &
45+
tbl.status
46+
.equals(OffRampOrderStatus.waitingForPartner.name),
47+
);
48+
final isCompleted =
49+
data.machineStatusField == MachineStatus.settled;
50+
51+
if (isCompleted) await _subscription?.cancel();
52+
53+
await statement.write(
54+
OffRampOrderRowsCompanion(
55+
machineStatus: Value(data.machineStatusField.name),
56+
humanStatus: Value(data.humanStatusField),
57+
status: isCompleted
58+
? const Value(OffRampOrderStatus.completed)
59+
: const Value(OffRampOrderStatus.waitingForPartner),
60+
),
61+
);
62+
}
63+
});
64+
}
65+
66+
@override
67+
void close() {
68+
_subscription?.cancel();
69+
}
70+
}

packages/espressocash_app/lib/features/ramp/screens/off_ramp_order_screen.dart

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import '../../../routes.gr.dart';
88
import '../../../ui/button.dart';
99
import '../../../ui/status_screen.dart';
1010
import '../../../ui/status_widget.dart';
11-
import '../services/kado_off_ramp_order_service.dart';
11+
import '../kado/services/off_ramp_order_watcher.dart';
12+
import '../models/ramp_partner.dart';
13+
import '../services/off_ramp_order_service.dart';
14+
import '../src/models/ramp_watcher.dart';
1215

1316
@RoutePage()
1417
class OffRampOrderScreen extends StatefulWidget {
@@ -23,7 +26,37 @@ class OffRampOrderScreen extends StatefulWidget {
2326
}
2427

2528
class _OffRampOrderScreenState extends State<OffRampOrderScreen> {
26-
late final _stream = sl<KadoOffRampOrderService>().watch(widget.orderId);
29+
late final Stream<OffRampOrder> _stream;
30+
RampWatcher? _watcher;
31+
32+
@override
33+
void initState() {
34+
super.initState();
35+
_stream = sl<OffRampOrderService>().watch(widget.orderId);
36+
37+
_initWatcher();
38+
}
39+
40+
Future<void> _initWatcher() async {
41+
if (_watcher != null) return;
42+
43+
final onRamp = await _stream.first;
44+
45+
_watcher = switch (onRamp.partner) {
46+
RampPartner.kado => sl<KadoOffRampOrderWatcher>(),
47+
RampPartner.rampNetwork ||
48+
RampPartner.coinflow ||
49+
RampPartner.guardarian =>
50+
throw ArgumentError('Not implemented'),
51+
}
52+
..watch(widget.orderId);
53+
}
54+
55+
@override
56+
void dispose() {
57+
_watcher?.close();
58+
super.dispose();
59+
}
2760

2861
@override
2962
Widget build(BuildContext context) => StreamBuilder(
@@ -49,7 +82,7 @@ class _OffRampOrderScreenState extends State<OffRampOrderScreen> {
4982
width: double.infinity,
5083
text: context.l10n.retry,
5184
onPressed: () {
52-
sl<KadoOffRampOrderService>().retry(widget.orderId);
85+
sl<OffRampOrderService>().retry(widget.orderId);
5386
},
5487
),
5588
if (order?.status == OffRampOrderStatus.depositTxRequired)
@@ -58,7 +91,7 @@ class _OffRampOrderScreenState extends State<OffRampOrderScreen> {
5891
width: double.infinity,
5992
text: 'Create deposit tx',
6093
onPressed: () {
61-
sl<KadoOffRampOrderService>().retry(widget.orderId);
94+
sl<OffRampOrderService>().retry(widget.orderId);
6295
},
6396
),
6497
],

packages/espressocash_app/lib/features/ramp/services/kado_off_ramp_order_service.dart renamed to packages/espressocash_app/lib/features/ramp/services/off_ramp_order_service.dart

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,24 @@ import '../../authenticated/auth_scope.dart';
2222
import '../../transactions/models/tx_sender.dart';
2323
import '../../transactions/services/resign_tx.dart';
2424
import '../../transactions/services/tx_sender.dart';
25-
import '../kado/data/kado_api_client.dart';
25+
import '../models/ramp_partner.dart';
2626

2727
typedef OffRampOrder = ({
2828
String id,
2929
DateTime created,
3030
OffRampOrderStatus status,
3131
CryptoAmount amount,
32+
RampPartner partner,
3233
});
3334

3435
@Singleton(scope: authScope)
35-
class KadoOffRampOrderService implements Disposable {
36-
KadoOffRampOrderService(
36+
class OffRampOrderService implements Disposable {
37+
OffRampOrderService(
3738
this._account,
3839
this._client,
3940
this._sender,
4041
this._db,
4142
this._tokens,
42-
this._kadoApi,
4343
);
4444

4545
final Map<String, StreamSubscription<void>> _subscriptions = {};
@@ -49,7 +49,6 @@ class KadoOffRampOrderService implements Disposable {
4949
final TxSender _sender;
5050
final MyDatabase _db;
5151
final TokenList _tokens;
52-
final KadoApiClient _kadoApi;
5352

5453
@PostConstruct()
5554
Future<void> init() async {
@@ -94,6 +93,7 @@ class KadoOffRampOrderService implements Disposable {
9493
created: row.created,
9594
status: row.status,
9695
amount: amount,
96+
partner: row.partner,
9797
);
9898
});
9999
}
@@ -142,16 +142,11 @@ class KadoOffRampOrderService implements Disposable {
142142
AsyncResult<String> create({
143143
required String partnerOrderId,
144144
required CryptoAmount amount,
145+
required RampPartner partner,
146+
required String depositAddress,
145147
}) =>
146148
tryEitherAsync((_) async {
147149
{
148-
final partnerOrder = await _kadoApi.getOrderStatus(partnerOrderId);
149-
final depositAddress = partnerOrder.data?.depositAddress;
150-
151-
if (depositAddress == null) {
152-
throw Exception('No deposit address');
153-
}
154-
155150
final order = OffRampOrderRow(
156151
id: const Uuid().v4(),
157152
amount: amount.value,
@@ -164,6 +159,7 @@ class KadoOffRampOrderService implements Disposable {
164159
slot: BigInt.zero,
165160
status: OffRampOrderStatus.depositTxRequired,
166161
depositAddress: depositAddress,
162+
partner: partner,
167163
);
168164

169165
await _db.into(_db.offRampOrderRows).insert(order);
@@ -181,6 +177,7 @@ class KadoOffRampOrderService implements Disposable {
181177
switch (order.status) {
182178
case OffRampOrderStatus.depositTxRequired:
183179
case OffRampOrderStatus.depositError:
180+
case OffRampOrderStatus.waitingForPartner:
184181
return const Stream.empty();
185182
case OffRampOrderStatus.creatingDepositTx:
186183
return Stream.fromFuture(
@@ -204,9 +201,6 @@ class KadoOffRampOrderService implements Disposable {
204201
status: Value(OffRampOrderStatus.sendingDepositTx),
205202
),
206203
);
207-
case OffRampOrderStatus.waitingForPartner:
208-
return Stream<void>.periodic(const Duration(seconds: 10))
209-
.asyncMap((_) => _checkPartnerStatus(order.partnerOrderId));
210204
case OffRampOrderStatus.failure:
211205
case OffRampOrderStatus.completed:
212206
_subscriptions[orderId]?.cancel();
@@ -291,18 +285,6 @@ class KadoOffRampOrderService implements Disposable {
291285
}
292286
}
293287

294-
Future<OffRampOrderRowsCompanion> _checkPartnerStatus(String orderId) async {
295-
final partnerOrder = await _kadoApi.getOrderStatus(orderId);
296-
297-
return OffRampOrderRowsCompanion(
298-
machineStatus: Value(partnerOrder.data?.machineStatusField.name ?? ''),
299-
humanStatus: Value(partnerOrder.data?.humanStatusField ?? ''),
300-
status: partnerOrder.data?.machineStatusField == MachineStatus.settled
301-
? const Value(OffRampOrderStatus.completed)
302-
: const Value(OffRampOrderStatus.waitingForPartner),
303-
);
304-
}
305-
306288
static const _depositError =
307289
OffRampOrderRowsCompanion(status: Value(OffRampOrderStatus.depositError));
308290
}

packages/espressocash_app/lib/features/ramp/src/widgets/partners/kado.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import '../../../../../core/currency.dart';
1010
import '../../../../../di.dart';
1111
import '../../../../../ui/web_view_screen.dart';
1212
import '../../../data/on_ramp_order_service.dart';
13+
import '../../../kado/data/kado_api_client.dart';
1314
import '../../../models/ramp_partner.dart';
1415
import '../../../screens/off_ramp_order_screen.dart';
15-
import '../../../services/kado_off_ramp_order_service.dart';
16+
import '../../../services/off_ramp_order_service.dart';
1617
import '../../models/profile_data.dart';
1718
import '../../models/ramp_type.dart';
1819
import '../../screens/ramp_amount_screen.dart';
@@ -134,18 +135,26 @@ window.addEventListener("message", (event) => {
134135
Future<void> handleLoaded(InAppWebViewController controller) async {
135136
controller.addJavaScriptHandler(
136137
handlerName: 'kado',
137-
callback: (args) {
138+
callback: (args) async {
138139
if (orderWasCreated) return;
139140

140141
if (args.firstOrNull
141142
case <String, dynamic>{
142143
'type': 'RAMP_ORDER_ID',
143144
'payload': {'orderId': final String orderId}
144145
}) {
145-
sl<KadoOffRampOrderService>()
146+
final partnerOrder =
147+
await sl<KadoApiClient>().getOrderStatus(orderId);
148+
final depositAddress = partnerOrder.data?.depositAddress;
149+
150+
if (depositAddress == null) return;
151+
152+
await sl<OffRampOrderService>()
146153
.create(
147154
partnerOrderId: orderId,
148155
amount: submittedAmount,
156+
partner: RampPartner.kado,
157+
depositAddress: depositAddress,
149158
)
150159
.then((order) {
151160
switch (order) {

packages/espressocash_app/moor_schemas/moor_schema_v42.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)