Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
aa159f3
bitassets: add settings for slippage, favorites, and price alerts
octobocto Feb 25, 2026
e88c604
bitassets: add asset analytics provider
octobocto Feb 25, 2026
966473c
bitassets: add favorites provider
octobocto Feb 25, 2026
269d845
bitassets: add price alert provider
octobocto Feb 25, 2026
3160c57
bitassets: register analytics, favorites, and price alert providers
octobocto Feb 25, 2026
2dd35ce
bitassets: add slippage tolerance and fee estimates to AMM swap
octobocto Feb 25, 2026
32d20b0
bitassets: add asset explorer and auction browser pages
octobocto Feb 25, 2026
ddc6e34
bitassets: show fee estimate on dutch auction creation
octobocto Feb 25, 2026
9ab866f
bitassets: add portfolio dashboard widget
octobocto Feb 25, 2026
21b742d
bitassets: add AMM analytics widget
octobocto Feb 25, 2026
4d6dc88
bitassets: add asset issuance wizard widget
octobocto Feb 25, 2026
1502696
bitassets: add transaction history widget
octobocto Feb 25, 2026
2cc119a
bitassets: add tests for settings persistence
octobocto Feb 25, 2026
3a0bc7b
bitassets: add tests for favorites provider
octobocto Feb 25, 2026
b94908f
bitassets: add tests for price alert provider
octobocto Feb 25, 2026
6f628fe
bitassets: add widget tests
octobocto Feb 25, 2026
c1493a6
truthcoin: migrate withOpacity to withValues
octobocto Feb 25, 2026
896c627
truthcoin: extract stepper steps to widget classes
octobocto Feb 25, 2026
11de4d3
truthcoin: remove unused crypto utilities from mock RPC
octobocto Feb 25, 2026
f5a9831
add plain-bitassets and photon submodules
octobocto Feb 25, 2026
1c12409
sail_ui: extract deletion progress widgets from build methods
octobocto Feb 25, 2026
9500c78
photon: add miner widget
octobocto Feb 25, 2026
3ec0ce1
photon: add parent chain info widget
octobocto Feb 25, 2026
cbdb8a3
truthcoin: make HeaderSection public in market explorer
octobocto Feb 25, 2026
5f9b66d
photon: add block explorer page
octobocto Feb 25, 2026
c7a70c8
photon: add mempool explorer page
octobocto Feb 25, 2026
69b192d
photon: add withdrawals page
octobocto Feb 25, 2026
1f3ee4b
photon: rename error to errorMessage in view models
octobocto Feb 25, 2026
3d1784a
photon: remove textAlign from block explorer height field
octobocto Feb 25, 2026
f04e285
photon: add outpoint formatter for withdrawal bundle UTXOs
octobocto Feb 25, 2026
4dd2d25
photon: register miner and parent chain info in widget catalog
octobocto Feb 25, 2026
7267688
photon: add explorer navigation pages
octobocto Feb 25, 2026
9787f89
sail_ui: reformat bitwindow health stream listeners
octobocto Feb 25, 2026
0214c16
sail_ui: remove extra blank line in reset confirmation page
octobocto Feb 25, 2026
6259931
clients: release new version
octobocto Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "vendors/plain-bitassets"]
path = vendors/plain-bitassets
url = https://github.com/LayerTwo-Labs/plain-bitassets.git
[submodule "vendors/photon"]
path = vendors/photon
url = https://github.com/LayerTwo-Labs/photon
18 changes: 18 additions & 0 deletions bitassets/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import 'package:bitassets/config/runtime_args.dart';
import 'package:bitassets/gen/version.dart';
import 'package:bitassets/providers/bitassets_conf_provider.dart';
import 'package:bitassets/providers/bitassets_homepage_provider.dart';
import 'package:bitassets/providers/asset_analytics_provider.dart';
import 'package:bitassets/providers/bitassets_provider.dart';
import 'package:bitassets/providers/favorites_provider.dart';
import 'package:bitassets/providers/price_alert_provider.dart';
import 'package:bitassets/routing/router.dart';
import 'package:collection/collection.dart';
import 'package:desktop_multi_window/desktop_multi_window.dart';
Expand Down Expand Up @@ -96,6 +99,21 @@ Future<(Directory, File, Logger)> init(String arguments) async {
() => BitAssetsProvider(),
);

// Register asset analytics provider
GetIt.I.registerLazySingleton<AssetAnalyticsProvider>(
() => AssetAnalyticsProvider(),
);

// Register favorites provider
GetIt.I.registerLazySingleton<FavoritesProvider>(
() => FavoritesProvider(),
);

// Register price alert provider
GetIt.I.registerLazySingleton<PriceAlertProvider>(
() => PriceAlertProvider(),
);

// Register homepage provider
final bitassetsHomepageProvider = BitAssetsHomepageProvider();
GetIt.I.registerLazySingleton<BitAssetsHomepageProvider>(() => bitassetsHomepageProvider);
Expand Down
145 changes: 141 additions & 4 deletions bitassets/lib/pages/tabs/amm_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:auto_route/auto_route.dart';
import 'package:bitassets/providers/bitassets_provider.dart';
import 'package:bitassets/settings/amm_settings.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:sail_ui/sail_ui.dart';
Expand Down Expand Up @@ -106,15 +107,87 @@ class AmmTabPage extends StatelessWidget {
color: context.sailTheme.colors.backgroundSecondary,
borderRadius: SailStyleValues.borderRadius,
),
child: SailRow(
child: SailColumn(
spacing: SailStyleValues.padding08,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SailText.secondary13('Rate'),
SailText.primary13(model.priceInfo!, monospace: true),
SailRow(
spacing: SailStyleValues.padding08,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SailText.secondary13('Rate'),
SailText.primary13(model.priceInfo!, monospace: true),
],
),
if (model.feeEstimate != null)
SailRow(
spacing: SailStyleValues.padding08,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SailText.secondary13('Swap Fee (0.3%)'),
SailText.primary13('~${model.feeEstimate} sats', monospace: true),
],
),
if (model.minimumReceived != null)
SailRow(
spacing: SailStyleValues.padding08,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SailText.secondary13('Min. received (${model.slippageTolerance}% slippage)'),
SailText.primary13('~${model.minimumReceived}', monospace: true),
],
),
],
),
),

// Advanced settings
ExpansionTile(
title: SailText.secondary13('Advanced Settings'),
tilePadding: EdgeInsets.zero,
childrenPadding: const EdgeInsets.only(bottom: 8),
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: context.sailTheme.colors.backgroundSecondary,
borderRadius: SailStyleValues.borderRadius,
),
child: SailColumn(
spacing: SailStyleValues.padding08,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SailText.secondary12('Slippage Tolerance'),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
_SlippageButton(
value: 0.1,
selected: model.slippageTolerance == 0.1,
onTap: () => model.setSlippage(0.1),
),
_SlippageButton(
value: 0.5,
selected: model.slippageTolerance == 0.5,
onTap: () => model.setSlippage(0.5),
),
_SlippageButton(
value: 1.0,
selected: model.slippageTolerance == 1.0,
onTap: () => model.setSlippage(1.0),
),
_SlippageButton(
value: 2.0,
selected: model.slippageTolerance == 2.0,
onTap: () => model.setSlippage(2.0),
),
],
),
],
),
),
],
),
],
),

Expand Down Expand Up @@ -184,10 +257,47 @@ class AmmTabPage extends StatelessWidget {
}
}

class _SlippageButton extends StatelessWidget {
final double value;
final bool selected;
final VoidCallback onTap;

const _SlippageButton({
required this.value,
required this.selected,
required this.onTap,
});

@override
Widget build(BuildContext context) {
final theme = SailTheme.of(context);

return InkWell(
onTap: onTap,
borderRadius: SailStyleValues.borderRadius,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: selected ? theme.colors.primary : theme.colors.backgroundSecondary,
borderRadius: SailStyleValues.borderRadius,
border: Border.all(
color: selected ? theme.colors.primary : theme.colors.divider,
),
),
child: SailText.primary12(
'$value%',
color: selected ? Colors.white : null,
),
),
);
}
}

class AmmSwapViewModel extends BaseViewModel {
final BitAssetsRPC rpc = GetIt.I.get<BitAssetsRPC>();
final BitAssetsProvider bitAssetsProvider = GetIt.I.get<BitAssetsProvider>();
final NotificationProvider notificationProvider = GetIt.I.get<NotificationProvider>();
final ClientSettings _settings = GetIt.I.get<ClientSettings>();

final TextEditingController amountSpendController = TextEditingController();
final TextEditingController amountReceiveController = TextEditingController();
Expand All @@ -197,11 +307,38 @@ class AmmSwapViewModel extends BaseViewModel {
String? swapError;
String? priceInfo;
bool swapLoading = false;
double slippageTolerance = 0.5;

AmmSwapViewModel() {
bitAssetsProvider.addListener(notifyListeners);
bitAssetsProvider.fetch();
amountSpendController.addListener(_onAmountChanged);
_loadSlippage();
}

Future<void> _loadSlippage() async {
final setting = await _settings.getValue(SlippageToleranceSetting());
slippageTolerance = setting.value;
notifyListeners();
}

void setSlippage(double value) {
slippageTolerance = value;
_settings.setValue(SlippageToleranceSetting(newValue: value));
notifyListeners();
}

int? get feeEstimate {
final amount = int.tryParse(amountSpendController.text);
if (amount == null || amount <= 0) return null;
return (amount * 0.003).round();
}

String? get minimumReceived {
final receiveAmount = int.tryParse(amountReceiveController.text);
if (receiveAmount == null || receiveAmount <= 0) return null;
final minAmount = (receiveAmount * (1 - slippageTolerance / 100)).round();
return minAmount.toString();
}

List<SailDropdownItem<String>> get assetOptions {
Expand Down
Loading
Loading