Skip to content

Commit 6283af3

Browse files
Activate Stellar in imported wallets (#1011)
* WIP: activate stellar addresses * WIP: trying to fix context issue * WIP: trying to fix context issue * WIP: remove activation while adding wallet && add activation address in flagsmith * updated price conversion * apply pr comments * update activation fee to be const * WIP: apply pr comments * add balance with wallet name in dropdown * update validation * handle balance if trades are zero * handle case when account already activated * fix failed workflow * handle tft trustline * fix fees to be in xlm * add button inside assets card * update stellar balance to represent if activated or no having tft trustline * Update app/lib/widgets/wallets/balance_tile.dart Co-authored-by: AhmedHanafy725 <41957921+AhmedHanafy725@users.noreply.github.com> * Update app/lib/widgets/wallets/wallet_card.dart Co-authored-by: AhmedHanafy725 <41957921+AhmedHanafy725@users.noreply.github.com> * Update app/lib/widgets/wallets/activate_wallet.dart Co-authored-by: AhmedHanafy725 <41957921+AhmedHanafy725@users.noreply.github.com> * Update app/lib/widgets/wallets/activate_wallet.dart Co-authored-by: AhmedHanafy725 <41957921+AhmedHanafy725@users.noreply.github.com> * Update app/lib/widgets/wallets/activate_wallet.dart Co-authored-by: AhmedHanafy725 <41957921+AhmedHanafy725@users.noreply.github.com> * fix stellarBalance check in all screens * update stellarBalance conditions * update condition for consistency * fix condition in farm details * fix init daily wallet condiotion --------- Co-authored-by: AhmedHanafy725 <41957921+AhmedHanafy725@users.noreply.github.com>
1 parent 7cde342 commit 6283af3

15 files changed

Lines changed: 640 additions & 50 deletions

app/lib/helpers/flags.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ class Flags {
9595
await Flags().hasFlagValueByFeatureName('council-member');
9696
Globals().registrarURL =
9797
(await Flags().getFlagValueByFeatureName('registrar-url')).toString();
98+
99+
Globals().activationServiceAddress = (await Flags()
100+
.getFlagValueByFeatureName('activation-service-address'))
101+
.toString();
102+
98103
}
99104

100105
Future<bool> hasFlagValueByFeatureName(String name) async {

app/lib/helpers/globals.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import 'package:threebotlogin/models/payment_request.dart';
55

66
class NoAnimationTabController extends TabController {
77
NoAnimationTabController(
8-
{super.initialIndex,
9-
required super.length,
10-
required super.vsync});
8+
{super.initialIndex, required super.length, required super.vsync});
119

1210
@override
1311
void animateTo(int value,
@@ -76,6 +74,8 @@ class Globals {
7674
int emailSentOn = 0;
7775
int emailMinutesCoolDown = 1;
7876

77+
String activationServiceAddress = '';
78+
7979
ValueNotifier<bool> hidePhoneButton = ValueNotifier(false);
8080

8181
static final Globals _singleton = Globals._internal();

app/lib/screens/farm_details.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class _FarmDetailsState extends State<FarmDetails> {
7474

7575
try {
7676
final balance = await getBalanceByAccountId(address);
77-
if (balance == '-1') {
77+
if (double.parse(balance) <= -1) {
7878
setState(() {
7979
stellarAddressError = 'Wallet not activated on stellar';
8080
});
@@ -120,7 +120,7 @@ class _FarmDetailsState extends State<FarmDetails> {
120120

121121
try {
122122
final balance = await getBalanceByAccountId(newAddress);
123-
if (balance == '-1') {
123+
if (double.parse(balance) <= -1) {
124124
if (context.mounted) {
125125
ScaffoldMessenger.of(context).clearSnackBars();
126126
ScaffoldMessenger.of(context).showSnackBar(SnackBar(

app/lib/screens/wallets/bridge.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ class _WalletBridgeScreenState extends ConsumerState<WalletBridgeScreen> {
148148
return false;
149149
}
150150
final toAddrBalance = await Stellar.getBalanceByAccountId(toAddress);
151-
if (toAddrBalance == '-1') {
151+
if (double.parse(toAddrBalance) <= -1) {
152152
toAddressError = 'Address must be active and have TFT trustline';
153153
return false;
154154
}
@@ -209,7 +209,8 @@ class _WalletBridgeScreenState extends ConsumerState<WalletBridgeScreen> {
209209
@override
210210
Widget build(BuildContext context) {
211211
List<Wallet> wallets = ref.read(walletsNotifier);
212-
final bool disableDeposit = widget.wallet.stellarBalance == '-1';
212+
final bool disableDeposit =
213+
double.parse(widget.wallet.stellarBalance) <= -1;
213214
if (disableDeposit && !isWithdraw) {
214215
onTransactionChange(BridgeOperation.Withdraw);
215216
}

app/lib/screens/wallets/receive.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class _WalletReceiveScreenState extends State<WalletReceiveScreen> {
8686

8787
@override
8888
Widget build(BuildContext context) {
89-
final bool hideStellar = widget.wallet.stellarBalance == '-1';
89+
final bool hideStellar = double.parse(widget.wallet.stellarBalance) <= -1;
9090
if (hideStellar) {
9191
onChangeChain(ChainType.TFChain);
9292
}

app/lib/screens/wallets/send.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,14 @@ class _WalletSendScreenState extends ConsumerState<WalletSendScreen> {
145145
wallets.where((wallet) => wallet.stellarAddress == toAddress);
146146
final Wallet? wallet =
147147
matchingWallets.isNotEmpty ? matchingWallets.first : null;
148-
if (wallet != null && wallet.stellarBalance == '-1') {
148+
if (wallet != null && double.parse(wallet.stellarBalance) <= -1) {
149149
setState(() {
150150
toAddressError = 'Wallet not activated on stellar';
151151
});
152152
return false;
153153
} else {
154154
final balance = await Stellar.getBalanceByAccountId(toAddress);
155-
if (balance == '-1') {
155+
if (double.parse(balance) <= -1) {
156156
setState(() {
157157
toAddressError = 'Wallet not activated on stellar';
158158
});
@@ -218,7 +218,7 @@ class _WalletSendScreenState extends ConsumerState<WalletSendScreen> {
218218

219219
@override
220220
Widget build(BuildContext context) {
221-
final bool hideStellar = widget.wallet.stellarBalance == '-1';
221+
final bool hideStellar = double.parse(widget.wallet.stellarBalance) <= -1;
222222
if (hideStellar && chainType == ChainType.Stellar) {
223223
onChangeChain(ChainType.TFChain);
224224
}

app/lib/screens/wallets/transactions.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class _WalletTransactionsWidgetState extends State<WalletTransactionsWidget> {
6767
@override
6868
void initState() {
6969
super.initState();
70-
if (widget.wallet.stellarBalance != '-1') {
70+
if (double.parse(widget.wallet.stellarBalance) > -1) {
7171
_pagingController.addPageRequestListener(_listTransactions);
7272
}
7373
}
@@ -80,7 +80,7 @@ class _WalletTransactionsWidgetState extends State<WalletTransactionsWidget> {
8080

8181
@override
8282
Widget build(BuildContext context) {
83-
if (widget.wallet.stellarBalance == '-1') {
83+
if (double.parse(widget.wallet.stellarBalance) <= -1) {
8484
return Center(
8585
child: Text(
8686
'No transactions yet.',

app/lib/screens/wallets/wallet_assets.dart

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:threebotlogin/screens/wallets/bridge.dart';
99
import 'package:threebotlogin/screens/wallets/receive.dart';
1010
import 'package:threebotlogin/screens/wallets/send.dart';
1111
import 'package:threebotlogin/services/stellar_service.dart' as Stellar;
12+
import 'package:threebotlogin/widgets/wallets/activate_wallet.dart';
1213
import 'package:threebotlogin/widgets/wallets/arrow_inward.dart';
1314
import 'package:threebotlogin/widgets/wallets/balance_tile.dart';
1415

@@ -59,6 +60,18 @@ class _WalletAssetsWidgetState extends State<WalletAssetsWidget> {
5960
super.dispose();
6061
}
6162

63+
_openActivateStellarOverlay() {
64+
showModalBottomSheet(
65+
isScrollControlled: true,
66+
useSafeArea: true,
67+
isDismissible: false,
68+
constraints: const BoxConstraints(maxWidth: double.infinity),
69+
context: context,
70+
builder: (ctx) => ActivateWalletWidget(
71+
wallet: widget.wallet,
72+
));
73+
}
74+
6275
@override
6376
Widget build(BuildContext context) {
6477
List<Widget> vestWidgets = [];
@@ -210,9 +223,14 @@ class _WalletAssetsWidgetState extends State<WalletAssetsWidget> {
210223
balance: formatAmount(widget.wallet.tfchainBalance),
211224
loading: tfchainBalaceLoading,
212225
),
213-
const SizedBox(
214-
height: 20,
215-
),
226+
const SizedBox(height: 10),
227+
if (double.parse(widget.wallet.stellarBalance) <= -1)
228+
WalletBalanceTileWidget(
229+
name: ChainType.Stellar,
230+
balance: widget.wallet.stellarBalance,
231+
loading: false,
232+
onActivate: _openActivateStellarOverlay,
233+
),
216234
...vestWidgets
217235
],
218236
),

app/lib/services/stellar_service.dart

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import 'dart:convert';
12
import 'dart:typed_data';
23

34
import 'package:stellar_client/models/transaction.dart';
45
import 'package:stellar_client/models/vesting_account.dart';
56
import 'package:stellar_client/stellar_client.dart';
67
import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart';
78
import 'package:threebotlogin/helpers/logger.dart';
9+
import 'package:http/http.dart' as http;
810

911
bool isValidStellarSecret(String seed) {
1012
try {
@@ -37,7 +39,10 @@ Future<String> getBalanceByClient(Client client) async {
3739
}
3840
} catch (e) {
3941
logger.i("Couldn't load the account balance due to $e");
42+
// -2 means that the account not activated on stellar
43+
return '-2';
4044
}
45+
// -1 means that account activated but no TFT trustline
4146
return '-1';
4247
}
4348

@@ -77,9 +82,9 @@ Future<void> transfer(String secret, String dest, String amount,
7782
);
7883
}
7984

80-
Future<void> initialize(String secret) async {
85+
Future<bool> initialize(String secret) async {
8186
final client = Client(NetworkType.PUBLIC, secret);
82-
await client.activateThroughThreefoldService();
87+
return await client.activateThroughThreefoldService();
8388
}
8489

8590
Future<String> getBalanceByAccountId(String accountId) async {
@@ -94,6 +99,54 @@ Future<String> getBalanceByAccountId(String accountId) async {
9499
}
95100
} catch (e) {
96101
logger.i("Couldn't load the account balance due to $e");
102+
return '-2';
97103
}
98104
return '-1';
99105
}
106+
107+
Future<int> getTFTPriceFromXLM() async {
108+
const String baseUrl = 'https://horizon.stellar.org';
109+
const String counterAssetCode = 'TFT';
110+
const String counterAssetIssuer =
111+
'GBOVQKJYHXRR3DX6NOX2RRYFRCUMSADGDESTDNBDS6CDVLGVESRTAC47';
112+
final String requestUrl = '$baseUrl/trades?base_asset_type=native'
113+
'&counter_asset_type=credit_alphanum4'
114+
'&counter_asset_code=$counterAssetCode'
115+
'&counter_asset_issuer=$counterAssetIssuer'
116+
'&order=desc&limit=1';
117+
118+
try {
119+
final response = await http.get(Uri.parse(requestUrl));
120+
121+
if (response.statusCode == 200) {
122+
final data = jsonDecode(response.body);
123+
final List<dynamic> trades = data['_embedded']?['records'] ?? [];
124+
125+
if (trades.isNotEmpty) {
126+
final trade = trades[0];
127+
final double baseAmount = double.parse(trade['base_amount']);
128+
final double counterAmount = double.parse(trade['counter_amount']);
129+
130+
final double pricePerTFT = counterAmount / baseAmount;
131+
logger.i('Last traded price for 1 XLM in TFT: $pricePerTFT');
132+
final int roundedPrice = pricePerTFT.ceil();
133+
134+
return roundedPrice;
135+
} else {
136+
logger.i('No recent trades found.');
137+
return 0;
138+
}
139+
} else {
140+
logger.e('Error fetching last traded price: ${response.statusCode}');
141+
throw Exception('Error getting price');
142+
}
143+
} catch (e) {
144+
logger.e('Error: $e');
145+
throw Exception('Error getting price');
146+
}
147+
}
148+
149+
Future<bool> addTFTTrustline(String secret, String assetCode) async {
150+
final client = Client(NetworkType.PUBLIC, secret);
151+
return await client.addTrustLineThroughThreefoldService(assetCode);
152+
}

app/lib/services/tfchain_service.dart

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Future<Map<String, List<Proposal>>> getProposals() async {
107107
return proposals;
108108
} catch (e) {
109109
throw Exception('Failed to get DAO proposals due to $e');
110-
} finally{
110+
} finally {
111111
if (proposals != null) {
112112
await client.disconnect();
113113
}
@@ -324,3 +324,16 @@ Future<Votes> getCouncilProposalVotes(String chainUrl, String hash) async {
324324
await client.disconnect();
325325
}
326326
}
327+
328+
Future<int> getTFTPrice(String chainUrl) async {
329+
final client = TFChain.QueryClient(chainUrl);
330+
try {
331+
await client.connect();
332+
final price = await client.price.get();
333+
return price;
334+
} catch (e) {
335+
throw Exception('Failed to get TFT price due to $e');
336+
} finally {
337+
await client.disconnect();
338+
}
339+
}

0 commit comments

Comments
 (0)