mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 03:29:36 +00:00
Nano-GPT (#1336)
* init * updates * nano updates * updates * updates * [skipci] wip deep link changes * fix deep links * minor fix * add reminder message on buy and exchange routes * [skip ci] font fixes * review updates * [skip ci] minor fix * save * fixes * minor code cleanup * minor potential fix
This commit is contained in:
parent
e5be737236
commit
baad7f7469
46 changed files with 486 additions and 195 deletions
1
.github/workflows/pr_test_build.yml
vendored
1
.github/workflows/pr_test_build.yml
vendored
|
@ -151,6 +151,7 @@ jobs:
|
|||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||
echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
||||
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -94,6 +94,7 @@ android/app/key.jks
|
|||
**/tool/.evm-secrets-config.json
|
||||
**/tool/.ethereum-secrets-config.json
|
||||
**/tool/.solana-secrets-config.json
|
||||
**/tool/.nano-secrets-config.json
|
||||
**/tool/.tron-secrets-config.json
|
||||
**/lib/.secrets.g.dart
|
||||
**/cw_evm/lib/.secrets.g.dart
|
||||
|
|
|
@ -91,6 +91,13 @@
|
|||
<data android:scheme="tron-wallet" />
|
||||
<data android:scheme="tron_wallet" />
|
||||
</intent-filter>
|
||||
<!-- nano-gpt link scheme -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="nano-gpt" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
|
|
5
assets/banano_node_list.yml
Normal file
5
assets/banano_node_list.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
-
|
||||
uri: kaliumapi.appditto.com
|
||||
path: /api
|
||||
useSSL: true
|
||||
is_default: true
|
|
@ -259,10 +259,16 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
element.tag == walletCurrency?.tag));
|
||||
} catch (_) {}
|
||||
|
||||
// search by fullName if not found by title:
|
||||
try {
|
||||
return CryptoCurrency.all.firstWhere((element) => element.fullName?.toLowerCase() == name);
|
||||
} catch (_) {}
|
||||
|
||||
if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
|
||||
final s = 'Unexpected token: $name for CryptoCurrency fromString';
|
||||
throw ArgumentError.value(name, 'name', s);
|
||||
}
|
||||
|
||||
return CryptoCurrency._nameCurrencyMap[name.toLowerCase()]!;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
import 'package:cw_core/balance.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
BigInt stringAmountToBigIntBanano(String amount) {
|
||||
return BigInt.parse(NanoAmounts.getAmountAsRaw(amount, NanoAmounts.rawPerBanano));
|
||||
}
|
||||
|
||||
class BananoBalance extends Balance {
|
||||
final BigInt currentBalance;
|
||||
final BigInt receivableBalance;
|
||||
|
||||
BananoBalance({required this.currentBalance, required this.receivableBalance}) : super(0, 0);
|
||||
|
||||
BananoBalance.fromFormattedString(
|
||||
{required String formattedCurrentBalance, required String formattedReceivableBalance})
|
||||
: currentBalance = stringAmountToBigIntBanano(formattedCurrentBalance),
|
||||
receivableBalance = stringAmountToBigIntBanano(formattedReceivableBalance),
|
||||
super(0, 0);
|
||||
|
||||
BananoBalance.fromRawString(
|
||||
{required String currentBalance, required String receivableBalance})
|
||||
: currentBalance = BigInt.parse(currentBalance),
|
||||
receivableBalance = BigInt.parse(receivableBalance),
|
||||
super(0, 0);
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance {
|
||||
return NanoAmounts.getRawAsUsableString(currentBalance.toString(), NanoAmounts.rawPerBanano);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cw_core/balance.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
|
||||
BigInt stringAmountToBigInt(String amount) {
|
||||
BigInt stringAmountToBigIntNano(String amount) {
|
||||
return BigInt.parse(NanoAmounts.getAmountAsRaw(amount, NanoAmounts.rawPerNano));
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@ class NanoBalance extends Balance {
|
|||
|
||||
NanoBalance.fromFormattedString(
|
||||
{required String formattedCurrentBalance, required String formattedReceivableBalance})
|
||||
: currentBalance = stringAmountToBigInt(formattedCurrentBalance),
|
||||
receivableBalance = stringAmountToBigInt(formattedReceivableBalance),
|
||||
: currentBalance = stringAmountToBigIntNano(formattedCurrentBalance),
|
||||
receivableBalance = stringAmountToBigIntNano(formattedReceivableBalance),
|
||||
super(0, 0);
|
||||
|
||||
NanoBalance.fromRawString(
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:nanodart/nanodart.dart';
|
|||
import 'package:cw_core/node.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cw_nano/.secrets.g.dart' as secrets;
|
||||
|
||||
class NanoClient {
|
||||
static const Map<String, String> CAKE_HEADERS = {
|
||||
|
@ -52,10 +53,19 @@ class NanoClient {
|
|||
}
|
||||
}
|
||||
|
||||
Map<String, String> getHeaders() {
|
||||
if (_node!.uri == "https://rpc.nano.to") {
|
||||
return CAKE_HEADERS..addAll({
|
||||
"key": secrets.nano2ApiKey,
|
||||
});
|
||||
}
|
||||
return CAKE_HEADERS;
|
||||
}
|
||||
|
||||
Future<NanoBalance> getBalance(String address) async {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: jsonEncode(
|
||||
{
|
||||
"action": "account_balance",
|
||||
|
@ -82,7 +92,7 @@ class NanoClient {
|
|||
try {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: jsonEncode(
|
||||
{
|
||||
"action": "account_info",
|
||||
|
@ -94,7 +104,7 @@ class NanoClient {
|
|||
final data = await jsonDecode(response.body);
|
||||
return AccountInfoResponse.fromJson(data as Map<String, dynamic>);
|
||||
} catch (e) {
|
||||
print("error while getting account info");
|
||||
print("error while getting account info $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +159,7 @@ class NanoClient {
|
|||
Future<String> requestWork(String hash) async {
|
||||
final response = await http.post(
|
||||
_powNode!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: json.encode(
|
||||
{
|
||||
"action": "work_generate",
|
||||
|
@ -192,7 +202,7 @@ class NanoClient {
|
|||
|
||||
final processResponse = await http.post(
|
||||
_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: processBody,
|
||||
);
|
||||
|
||||
|
@ -351,7 +361,7 @@ class NanoClient {
|
|||
});
|
||||
final processResponse = await http.post(
|
||||
_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: processBody,
|
||||
);
|
||||
|
||||
|
@ -367,7 +377,7 @@ class NanoClient {
|
|||
required String privateKey,
|
||||
}) async {
|
||||
final receivableResponse = await http.post(_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: jsonEncode({
|
||||
"action": "receivable",
|
||||
"account": destinationAddress,
|
||||
|
@ -417,7 +427,7 @@ class NanoClient {
|
|||
Future<List<NanoTransactionModel>> fetchTransactions(String address) async {
|
||||
try {
|
||||
final response = await http.post(_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(),
|
||||
body: jsonEncode({
|
||||
"action": "account_history",
|
||||
"account": address,
|
||||
|
|
|
@ -140,6 +140,16 @@
|
|||
<string>nano-wallet</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>nano-gpt</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>nano-gpt</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
|
|
145
lib/di.dart
145
lib/di.dart
|
@ -26,6 +26,7 @@ import 'package:cake_wallet/entities/contact.dart';
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
|
@ -268,6 +269,7 @@ Future<void> setup({
|
|||
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||
required FlutterSecureStorage secureStorage,
|
||||
required GlobalKey<NavigatorState> navigatorKey,
|
||||
}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
|
@ -429,68 +431,89 @@ Future<void> setup({
|
|||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory<AuthPage>(() {
|
||||
return AuthPage(getIt.get<AuthViewModel>(),
|
||||
getIt.registerLazySingleton<LinkViewModel>(() {
|
||||
return LinkViewModel(
|
||||
appStore: getIt.get<AppStore>(),
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
authenticationStore: getIt.get<AuthenticationStore>(),
|
||||
navigatorKey: navigatorKey,
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactory<AuthPage>(instanceName: 'login', () {
|
||||
return AuthPage(getIt.get<AuthViewModel>(), closable: false,
|
||||
onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) {
|
||||
if (!isAuthenticated) {
|
||||
return;
|
||||
} else {
|
||||
final authStore = getIt.get<AuthenticationStore>();
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final useTotp = appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
authPageState.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
onTotpAuthenticationFinished: (bool isAuthenticatedSuccessfully,
|
||||
TotpAuthCodePageState totpAuthPageState) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
totpAuthPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
authPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, closable: false);
|
||||
}, instanceName: 'login');
|
||||
final authStore = getIt.get<AuthenticationStore>();
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final useTotp = appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
authPageState.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuthPageState) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
totpAuthPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// wallet is already loaded:
|
||||
if (appStore.wallet != null) {
|
||||
// goes to the dashboard:
|
||||
authStore.allowed();
|
||||
// trigger any deep links:
|
||||
final linkViewModel = getIt.get<LinkViewModel>();
|
||||
if (linkViewModel.currentLink != null) {
|
||||
linkViewModel.handleLink();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// load the wallet:
|
||||
|
||||
authPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
final linkViewModel = getIt.get<LinkViewModel>();
|
||||
if (linkViewModel.currentLink != null) {
|
||||
linkViewModel.handleLink();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
getIt.registerSingleton<BottomSheetService>(BottomSheetServiceImpl());
|
||||
|
||||
|
@ -849,8 +872,10 @@ Future<void> setup({
|
|||
tradesStore: getIt.get<TradesStore>(),
|
||||
sendViewModel: getIt.get<SendViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ExchangePage(getIt.get<ExchangeViewModel>(), getIt.get<AuthService>()));
|
||||
getIt.registerFactoryParam<ExchangePage, PaymentRequest?, void>(
|
||||
(PaymentRequest? paymentRequest, __) {
|
||||
return ExchangePage(getIt.get<ExchangeViewModel>(), getIt.get<AuthService>(), paymentRequest);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => ExchangeConfirmPage(tradesStore: getIt.get<TradesStore>()));
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cake_wallet/locales/locale.dart';
|
|||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cw_core/address_info.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
|
@ -205,18 +206,20 @@ Future<void> initialSetup(
|
|||
nodes: nodes,
|
||||
powNodes: powNodes);
|
||||
await setup(
|
||||
walletInfoSource: walletInfoSource,
|
||||
nodeSource: nodes,
|
||||
powNodeSource: powNodes,
|
||||
contactSource: contactSource,
|
||||
tradesSource: tradesSource,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions,
|
||||
ordersSource: ordersSource,
|
||||
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
secureStorage: secureStorage);
|
||||
walletInfoSource: walletInfoSource,
|
||||
nodeSource: nodes,
|
||||
powNodeSource: powNodes,
|
||||
contactSource: contactSource,
|
||||
tradesSource: tradesSource,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions,
|
||||
ordersSource: ordersSource,
|
||||
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
secureStorage: secureStorage,
|
||||
navigatorKey: navigatorKey,
|
||||
);
|
||||
await bootstrap(navigatorKey);
|
||||
monero?.onStartup();
|
||||
}
|
||||
|
@ -287,6 +290,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
|||
return Observer(builder: (BuildContext context) {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final authService = getIt.get<AuthService>();
|
||||
final linkViewModel = getIt.get<LinkViewModel>();
|
||||
final settingsStore = appStore.settingsStore;
|
||||
final statusBarColor = Colors.transparent;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
|
@ -309,6 +313,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
|||
authenticationStore: authenticationStore,
|
||||
navigatorKey: navigatorKey,
|
||||
authService: authService,
|
||||
linkViewModel: linkViewModel,
|
||||
child: MaterialApp(
|
||||
navigatorObservers: [routeObserver],
|
||||
navigatorKey: navigatorKey,
|
||||
|
|
|
@ -221,7 +221,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<SetupPinCodePage>(
|
||||
param1: (PinCodeState<PinCodeWidget> context, dynamic _) =>
|
||||
Navigator.of(context.context).pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: false),
|
||||
Navigator.of(context.context)
|
||||
.pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: false),
|
||||
),
|
||||
fullscreenDialog: true,
|
||||
);
|
||||
|
@ -231,9 +232,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
builder: (_) => ConnectDevicePage(
|
||||
ConnectDevicePageParams(
|
||||
walletType: availableWalletTypes.first,
|
||||
onConnectDevice: (BuildContext context, _) =>
|
||||
Navigator.of(context).pushNamed(Routes.chooseHardwareWalletAccount,
|
||||
arguments: [availableWalletTypes.first]),
|
||||
onConnectDevice: (BuildContext context, _) => Navigator.of(context).pushNamed(
|
||||
Routes.chooseHardwareWalletAccount,
|
||||
arguments: [availableWalletTypes.first]),
|
||||
),
|
||||
getIt.get<LedgerViewModel>(),
|
||||
));
|
||||
|
@ -243,9 +244,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
param1: (BuildContext context, WalletType type) {
|
||||
final arguments = ConnectDevicePageParams(
|
||||
walletType: type,
|
||||
onConnectDevice: (BuildContext context, _) =>
|
||||
Navigator.of(context).pushNamed(Routes.chooseHardwareWalletAccount,
|
||||
arguments: [type]),
|
||||
onConnectDevice: (BuildContext context, _) => Navigator.of(context)
|
||||
.pushNamed(Routes.chooseHardwareWalletAccount, arguments: [type]),
|
||||
);
|
||||
|
||||
Navigator.of(context).pushNamed(Routes.connectDevices, arguments: arguments);
|
||||
|
@ -308,8 +308,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.bumpFeePage:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) =>
|
||||
getIt.get<RBFDetailsPage>(param1: settings.arguments as TransactionInfo));
|
||||
builder: (_) => getIt.get<RBFDetailsPage>(param1: settings.arguments as TransactionInfo));
|
||||
|
||||
case Routes.newSubaddress:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
@ -461,7 +460,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.exchange:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<ExchangePage>());
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<ExchangePage>(param1: settings.arguments as PaymentRequest?),
|
||||
);
|
||||
|
||||
case Routes.exchangeTemplate:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<ExchangeTemplatePage>());
|
||||
|
|
|
@ -59,12 +59,15 @@ class MarketPlacePage extends StatelessWidget {
|
|||
// ),
|
||||
SizedBox(height: 20),
|
||||
DashBoardRoundedCardWidget(
|
||||
onTap: () => launchUrl(
|
||||
Uri.https("buy.cakepay.com"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
title: S.of(context).cake_pay_web_cards_title,
|
||||
subTitle: S.of(context).cake_pay_web_cards_subtitle,
|
||||
onTap: () => _launchMarketPlaceUrl("buy.cakepay.com"),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
DashBoardRoundedCardWidget(
|
||||
title: "NanoGPT",
|
||||
subTitle: S.of(context).nanogpt_subtitle,
|
||||
onTap: () => _launchMarketPlaceUrl("cake.nano-gpt.com"),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -76,6 +79,17 @@ class MarketPlacePage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
void _launchMarketPlaceUrl(String url) async {
|
||||
try {
|
||||
launchUrl(
|
||||
Uri.https(url),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove ionia flow/files if we will discard it
|
||||
void _navigatorToGiftCardsPage(BuildContext context) {
|
||||
final walletType = dashboardViewModel.type;
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/src/widgets/add_template_button.dart';
|
|||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/debounce.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -43,7 +44,7 @@ import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
|
||||
|
||||
class ExchangePage extends BasePage {
|
||||
ExchangePage(this.exchangeViewModel, this.authService) {
|
||||
ExchangePage(this.exchangeViewModel, this.authService, this.initialPaymentRequest) {
|
||||
depositWalletName = exchangeViewModel.depositCurrency == CryptoCurrency.xmr
|
||||
? exchangeViewModel.wallet.name
|
||||
: null;
|
||||
|
@ -54,6 +55,7 @@ class ExchangePage extends BasePage {
|
|||
|
||||
final ExchangeViewModel exchangeViewModel;
|
||||
final AuthService authService;
|
||||
final PaymentRequest? initialPaymentRequest;
|
||||
final depositKey = GlobalKey<ExchangeCardState>();
|
||||
final receiveKey = GlobalKey<ExchangeCardState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
@ -543,6 +545,12 @@ class ExchangePage extends BasePage {
|
|||
// amount: depositAmountController.text);
|
||||
});
|
||||
|
||||
if (initialPaymentRequest != null) {
|
||||
exchangeViewModel.receiveCurrency = CryptoCurrency.fromString(initialPaymentRequest!.scheme);
|
||||
exchangeViewModel.depositAmount = initialPaymentRequest!.amount;
|
||||
exchangeViewModel.receiveAddress = initialPaymentRequest!.address;
|
||||
}
|
||||
|
||||
_isReactionsSet = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -25,6 +26,7 @@ class Root extends StatefulWidget {
|
|||
required this.child,
|
||||
required this.navigatorKey,
|
||||
required this.authService,
|
||||
required this.linkViewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final AuthenticationStore authenticationStore;
|
||||
|
@ -32,6 +34,7 @@ class Root extends StatefulWidget {
|
|||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
final AuthService authService;
|
||||
final Widget child;
|
||||
final LinkViewModel linkViewModel;
|
||||
|
||||
@override
|
||||
RootState createState() => RootState();
|
||||
|
@ -53,7 +56,6 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
StreamSubscription<Uri?>? stream;
|
||||
ReactionDisposer? _walletReactionDisposer;
|
||||
ReactionDisposer? _deepLinksReactionDisposer;
|
||||
Uri? launchUri;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -98,7 +100,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
void handleDeepLinking(Uri? uri) async {
|
||||
if (uri == null || !mounted) return;
|
||||
|
||||
launchUri = uri;
|
||||
widget.linkViewModel.currentLink = uri;
|
||||
|
||||
bool requireAuth = await widget.authService.requireAuth();
|
||||
|
||||
|
@ -112,7 +114,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
(AuthenticationState state) {
|
||||
if (state == AuthenticationState.allowed) {
|
||||
if (widget.appStore.wallet == null) {
|
||||
waitForWalletInstance(context, launchUri!);
|
||||
waitForWalletInstance(context);
|
||||
} else {
|
||||
_navigateToDeepLinkScreen();
|
||||
}
|
||||
|
@ -150,6 +152,8 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// this only happens when the app has been in the background for some time
|
||||
// this does NOT trigger when the app is started from the "closed" state!
|
||||
if (_isInactive && !_postFrameCallback && _requestAuth) {
|
||||
_postFrameCallback = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
@ -158,40 +162,38 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
final useTotp = widget.appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
widget.appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
_reset();
|
||||
totpAuth.close(
|
||||
route: widget.linkViewModel.getRouteToGo(),
|
||||
arguments: widget.linkViewModel.getRouteArgs(),
|
||||
);
|
||||
widget.linkViewModel.currentLink = null;
|
||||
},
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final useTotp = widget.appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
widget.appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
_reset();
|
||||
totpAuth.close(
|
||||
route: _getRouteToGo(),
|
||||
arguments:
|
||||
isWalletConnectLink ? launchUri : PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
},
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: _getRouteToGo(),
|
||||
arguments: isWalletConnectLink ? launchUri : PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
}
|
||||
_reset();
|
||||
auth.close(
|
||||
route: widget.linkViewModel.getRouteToGo(),
|
||||
arguments: widget.linkViewModel.getRouteArgs(),
|
||||
);
|
||||
widget.linkViewModel.currentLink = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -216,36 +218,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
_isInactiveController.add(value);
|
||||
}
|
||||
|
||||
bool _isValidPaymentUri() => launchUri?.path.isNotEmpty ?? false;
|
||||
|
||||
bool get isWalletConnectLink => launchUri?.authority == 'wc';
|
||||
|
||||
String? _getRouteToGo() {
|
||||
if (isWalletConnectLink) {
|
||||
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
|
||||
_nonETHWalletErrorToast(S.current.switchToEVMCompatibleWallet);
|
||||
return null;
|
||||
}
|
||||
return Routes.walletConnectConnectionsListing;
|
||||
} else if (_isValidPaymentUri()) {
|
||||
return Routes.send;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _nonETHWalletErrorToast(String message) async {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.SNACKBAR,
|
||||
backgroundColor: Colors.black,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
void waitForWalletInstance(BuildContext context, Uri tempLaunchUri) {
|
||||
void waitForWalletInstance(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (context.mounted) {
|
||||
_walletReactionDisposer = reaction(
|
||||
|
@ -263,14 +236,6 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
}
|
||||
|
||||
void _navigateToDeepLinkScreen() {
|
||||
if (_getRouteToGo() != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.navigatorKey.currentState?.pushNamed(
|
||||
_getRouteToGo()!,
|
||||
arguments: isWalletConnectLink ? launchUri : PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
});
|
||||
}
|
||||
widget.linkViewModel.handleLink();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class SendPage extends BasePage {
|
||||
SendPage({
|
||||
|
@ -420,12 +422,10 @@ class SendPage extends BasePage {
|
|||
}
|
||||
|
||||
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||
|
||||
if (dialogContext != null && dialogContext?.mounted == true) {
|
||||
Navigator.of(dialogContext!).pop();
|
||||
}
|
||||
|
||||
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
|
@ -460,10 +460,10 @@ class SendPage extends BasePage {
|
|||
outputs: sendViewModel.outputs,
|
||||
rightButtonText: S.of(_dialogContext).send,
|
||||
leftButtonText: S.of(_dialogContext).cancel,
|
||||
actionRightButton: () {
|
||||
actionRightButton: () async {
|
||||
Navigator.of(_dialogContext).pop();
|
||||
sendViewModel.commitTransaction();
|
||||
showPopUp<void>(
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext _dialogContext) {
|
||||
return Observer(builder: (_) {
|
||||
|
@ -481,12 +481,14 @@ class SendPage extends BasePage {
|
|||
sendViewModel.selectedCryptoCurrency.toString());
|
||||
|
||||
final waitMessage = sendViewModel.walletType == WalletType.solana
|
||||
? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' : '';
|
||||
? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}'
|
||||
: '';
|
||||
|
||||
final newContactMessage = newContactAddress != null
|
||||
? '\n${S.of(_dialogContext).add_contact_to_address_book}' : '';
|
||||
? '\n${S.of(_dialogContext).add_contact_to_address_book}'
|
||||
: '';
|
||||
|
||||
final alertContent =
|
||||
String alertContent =
|
||||
"$successMessage$waitMessage$newContactMessage";
|
||||
|
||||
if (newContactAddress != null) {
|
||||
|
@ -509,6 +511,10 @@ class SendPage extends BasePage {
|
|||
newContactAddress = null;
|
||||
});
|
||||
} else {
|
||||
if (initialPaymentRequest?.callbackMessage?.isNotEmpty ??
|
||||
false) {
|
||||
alertContent = initialPaymentRequest!.callbackMessage!;
|
||||
}
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: alertContent,
|
||||
|
@ -523,6 +529,20 @@ class SendPage extends BasePage {
|
|||
return Offstage();
|
||||
});
|
||||
});
|
||||
if (state is TransactionCommitted) {
|
||||
if (initialPaymentRequest?.callbackUrl?.isNotEmpty ?? false) {
|
||||
// wait a second so it's not as jarring:
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
try {
|
||||
launchUrl(
|
||||
Uri.parse(initialPaymentRequest!.callbackUrl!),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(_dialogContext).pop());
|
||||
});
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
|
||||
class PaymentRequest {
|
||||
PaymentRequest(this.address, this.amount, this.note, this.scheme);
|
||||
PaymentRequest(this.address, this.amount, this.note, this.scheme, {this.callbackUrl, this.callbackMessage});
|
||||
|
||||
factory PaymentRequest.fromUri(Uri? uri) {
|
||||
var address = "";
|
||||
var amount = "";
|
||||
var note = "";
|
||||
var scheme = "";
|
||||
String? callbackUrl;
|
||||
String? callbackMessage;
|
||||
|
||||
if (uri != null) {
|
||||
address = uri.path;
|
||||
address = uri.queryParameters['address'] ?? uri.path;
|
||||
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
|
||||
note = uri.queryParameters['tx_description'] ?? uri.queryParameters['message'] ?? "";
|
||||
scheme = uri.scheme;
|
||||
callbackUrl = uri.queryParameters['callback'];
|
||||
callbackMessage = uri.queryParameters['callbackMessage'];
|
||||
}
|
||||
|
||||
if (scheme == "nano-gpt") {
|
||||
// treat as nano so filling out the address works:
|
||||
scheme = "nano";
|
||||
}
|
||||
|
||||
if (nano != null) {
|
||||
|
@ -26,11 +36,20 @@ class PaymentRequest {
|
|||
}
|
||||
}
|
||||
|
||||
return PaymentRequest(address, amount, note, scheme);
|
||||
return PaymentRequest(
|
||||
address,
|
||||
amount,
|
||||
note,
|
||||
scheme,
|
||||
callbackUrl: callbackUrl,
|
||||
callbackMessage: callbackMessage,
|
||||
);
|
||||
}
|
||||
|
||||
final String address;
|
||||
final String amount;
|
||||
final String note;
|
||||
final String scheme;
|
||||
final String? callbackUrl;
|
||||
final String? callbackMessage;
|
||||
}
|
||||
|
|
118
lib/view_model/link_view_model.dart
Normal file
118
lib/view_model/link_view_model.dart
Normal file
|
@ -0,0 +1,118 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/authentication_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'link_view_model.g.dart';
|
||||
|
||||
class LinkViewModel = LinkViewModelBase with _$LinkViewModel;
|
||||
|
||||
abstract class LinkViewModelBase with Store {
|
||||
LinkViewModelBase({
|
||||
required this.settingsStore,
|
||||
required this.appStore,
|
||||
required this.authenticationStore,
|
||||
required this.navigatorKey,
|
||||
}) {}
|
||||
|
||||
final SettingsStore settingsStore;
|
||||
final AppStore appStore;
|
||||
final AuthenticationStore authenticationStore;
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
Uri? currentLink;
|
||||
|
||||
bool get _isValidPaymentUri => currentLink?.path.isNotEmpty ?? false;
|
||||
bool get isWalletConnectLink => currentLink?.authority == 'wc';
|
||||
bool get isNanoGptLink => currentLink?.scheme == 'nano-gpt';
|
||||
|
||||
String? getRouteToGo() {
|
||||
if (isWalletConnectLink) {
|
||||
if (!isEVMCompatibleChain(appStore.wallet!.type)) {
|
||||
_errorToast(S.current.switchToEVMCompatibleWallet);
|
||||
return null;
|
||||
}
|
||||
return Routes.walletConnectConnectionsListing;
|
||||
}
|
||||
|
||||
if (authenticationStore.state == AuthenticationState.uninitialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isNanoGptLink) {
|
||||
switch (currentLink?.authority ?? '') {
|
||||
case "exchange":
|
||||
return Routes.exchange;
|
||||
case "send":
|
||||
return Routes.send;
|
||||
case "buy":
|
||||
return Routes.buySellPage;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isValidPaymentUri) {
|
||||
return Routes.send;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
dynamic getRouteArgs() {
|
||||
if (isWalletConnectLink) {
|
||||
return currentLink;
|
||||
}
|
||||
|
||||
if (isNanoGptLink) {
|
||||
switch (currentLink?.authority ?? '') {
|
||||
case "exchange":
|
||||
case "send":
|
||||
return PaymentRequest.fromUri(currentLink);
|
||||
case "buy":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isValidPaymentUri) {
|
||||
return PaymentRequest.fromUri(currentLink);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> _errorToast(String message, {double fontSize = 16}) async {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.SNACKBAR,
|
||||
backgroundColor: Colors.black,
|
||||
textColor: Colors.white,
|
||||
fontSize: fontSize,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> handleLink() async {
|
||||
String? route = getRouteToGo();
|
||||
dynamic args = getRouteArgs();
|
||||
if (route != null) {
|
||||
if (appStore.wallet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNanoGptLink) {
|
||||
if (route == Routes.buySellPage || route == Routes.exchange) {
|
||||
await _errorToast(S.current.nano_gpt_thanks_message, fontSize: 14);
|
||||
}
|
||||
}
|
||||
currentLink = null;
|
||||
navigatorKey.currentState?.pushNamed(
|
||||
route,
|
||||
arguments: args,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "يجب أن تكون قيمة المبلغ أكبر من أو تساوي ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "المزيد من الخيارات",
|
||||
"name": "ﻢﺳﺍ",
|
||||
"nano_gpt_thanks_message": "شكرا لاستخدام nanogpt! تذكر أن تعود إلى المتصفح بعد اكتمال معاملتك!",
|
||||
"nanogpt_subtitle": "جميع النماذج الأحدث (GPT-4 ، Claude). \\ nno اشتراك ، ادفع مع Crypto.",
|
||||
"nano_current_rep": "الممثل الحالي",
|
||||
"nano_pick_new_rep": "اختر ممثلًا جديدًا",
|
||||
"narrow": "ضيق",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Сумата трябва да бъде най-малко ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Още настройки",
|
||||
"name": "Име",
|
||||
"nano_gpt_thanks_message": "Благодаря, че използвахте Nanogpt! Не забравяйте да се върнете обратно към браузъра, след като транзакцията ви приключи!",
|
||||
"nanogpt_subtitle": "Всички най-нови модели (GPT-4, Claude). \\ Nno абонамент, платете с Crypto.",
|
||||
"nano_current_rep": "Настоящ представител",
|
||||
"nano_pick_new_rep": "Изберете нов представител",
|
||||
"narrow": "Тесен",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Částka musí být větší nebo rovna ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Více možností",
|
||||
"name": "název",
|
||||
"nano_gpt_thanks_message": "Děkujeme za používání Nanogpt! Nezapomeňte se po dokončení transakce vydat zpět do prohlížeče!",
|
||||
"nanogpt_subtitle": "Všechny nejnovější modely (GPT-4, Claude). \\ Nno předplatné, plaťte krypto.",
|
||||
"nano_current_rep": "Současný zástupce",
|
||||
"nano_pick_new_rep": "Vyberte nového zástupce",
|
||||
"narrow": "Úzký",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
|
||||
"more_options": "Weitere Optionen",
|
||||
"name": "Name",
|
||||
"nano_gpt_thanks_message": "Danke, dass du Nanogpt benutzt hast! Denken Sie daran, nach Abschluss Ihrer Transaktion zurück zum Browser zu gehen!",
|
||||
"nanogpt_subtitle": "Alle neuesten Modelle (GPT-4, Claude).",
|
||||
"nano_current_rep": "Aktueller Vertreter",
|
||||
"nano_pick_new_rep": "Wählen Sie einen neuen Vertreter aus",
|
||||
"narrow": "Eng",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "More Options",
|
||||
"name": "Name",
|
||||
"nano_gpt_thanks_message": "Thanks for using NanoGPT! Remember to head back to the browser after your transaction completes!",
|
||||
"nanogpt_subtitle": "All the newest models (GPT-4, Claude).\\nNo subscription, pay with crypto.",
|
||||
"nano_current_rep": "Current Representative",
|
||||
"nano_pick_new_rep": "Pick a new representative",
|
||||
"narrow": "Narrow",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Más Opciones",
|
||||
"name": "Nombre",
|
||||
"nano_gpt_thanks_message": "¡Gracias por usar nanogpt! ¡Recuerde regresar al navegador después de que se complete su transacción!",
|
||||
"nanogpt_subtitle": "Todos los modelos más nuevos (GPT-4, Claude). \\ Nno suscripción, pague con cripto.",
|
||||
"nano_current_rep": "Representante actual",
|
||||
"nano_pick_new_rep": "Elija un nuevo representante",
|
||||
"narrow": "Angosto",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Le montant doit être au moins égal à ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Plus d'options",
|
||||
"name": "Nom",
|
||||
"nano_gpt_thanks_message": "Merci d'avoir utilisé Nanogpt! N'oubliez pas de retourner au navigateur une fois votre transaction terminée!",
|
||||
"nanogpt_subtitle": "Tous les modèles les plus récents (GPT-4, Claude). \\ NNO abonnement, payez avec crypto.",
|
||||
"nano_current_rep": "Représentant actuel",
|
||||
"nano_pick_new_rep": "Choisissez un nouveau représentant",
|
||||
"narrow": "Étroit",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Ƙarin Zaɓuɓɓuka",
|
||||
"name": "Suna",
|
||||
"nano_gpt_thanks_message": "Na gode da amfani da Nanogpt! Ka tuna da komawa zuwa mai bincike bayan ma'amalar ka ta cika!",
|
||||
"nanogpt_subtitle": "Duk sabbin samfuran (GPT-4, CLODE). \\ NNO biyan kuɗi, biya tare da crypto.",
|
||||
"nano_current_rep": "Wakilin Yanzu",
|
||||
"nano_pick_new_rep": "Dauki sabon wakili",
|
||||
"narrow": "kunkuntar",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "और विकल्प",
|
||||
"name": "नाम",
|
||||
"nano_gpt_thanks_message": "Nanogpt का उपयोग करने के लिए धन्यवाद! अपने लेन -देन के पूरा होने के बाद ब्राउज़र पर वापस जाना याद रखें!",
|
||||
"nanogpt_subtitle": "सभी नवीनतम मॉडल (GPT-4, क्लाउड)। \\ nno सदस्यता, क्रिप्टो के साथ भुगतान करें।",
|
||||
"nano_current_rep": "वर्तमान प्रतिनिधि",
|
||||
"nano_pick_new_rep": "एक नया प्रतिनिधि चुनें",
|
||||
"narrow": "सँकरा",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Više opcija",
|
||||
"name": "Ime",
|
||||
"nano_gpt_thanks_message": "Hvala što ste koristili nanogpt! Ne zaboravite da se vratite u preglednik nakon što vam se transakcija završi!",
|
||||
"nanogpt_subtitle": "Svi najnoviji modeli (GPT-4, Claude). \\ NNO pretplata, plaćajte kripto.",
|
||||
"nano_current_rep": "Trenutni predstavnik",
|
||||
"nano_pick_new_rep": "Odaberite novog predstavnika",
|
||||
"narrow": "Usko",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Nilai jumlah harus lebih atau sama dengan ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Opsi Lainnya",
|
||||
"name": "Nama",
|
||||
"nano_gpt_thanks_message": "Terima kasih telah menggunakan Nanogpt! Ingatlah untuk kembali ke browser setelah transaksi Anda selesai!",
|
||||
"nanogpt_subtitle": "Semua model terbaru (GPT-4, Claude). \\ Nno langganan, bayar dengan crypto.",
|
||||
"nano_current_rep": "Perwakilan saat ini",
|
||||
"nano_pick_new_rep": "Pilih perwakilan baru",
|
||||
"narrow": "Sempit",
|
||||
|
|
|
@ -367,6 +367,8 @@
|
|||
"moonpay_alert_text": "Il valore dell'importo deve essere maggiore o uguale a ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Altre opzioni",
|
||||
"name": "Nome",
|
||||
"nano_gpt_thanks_message": "Grazie per aver usato il nanogpt! Ricorda di tornare al browser dopo il completamento della transazione!",
|
||||
"nanogpt_subtitle": "Tutti i modelli più recenti (GPT-4, Claude). Abbonamento nno, paga con cripto.",
|
||||
"nano_current_rep": "Rappresentante attuale",
|
||||
"nano_pick_new_rep": "Scegli un nuovo rappresentante",
|
||||
"narrow": "Stretto",
|
||||
|
|
|
@ -367,6 +367,8 @@
|
|||
"moonpay_alert_text": "金額の値は以上でなければなりません ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "その他のオプション",
|
||||
"name": "名前",
|
||||
"nano_gpt_thanks_message": "NanoGptを使用してくれてありがとう!トランザクションが完了したら、ブラウザに戻ることを忘れないでください!",
|
||||
"nanogpt_subtitle": "すべての最新モデル(GPT-4、Claude)。\\ nnoサブスクリプション、暗号で支払います。",
|
||||
"nano_current_rep": "現在の代表",
|
||||
"nano_pick_new_rep": "新しい代表者を選びます",
|
||||
"narrow": "狭い",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "금액은 다음보다 크거나 같아야합니다 ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "추가 옵션",
|
||||
"name": "이름",
|
||||
"nano_gpt_thanks_message": "Nanogpt를 사용해 주셔서 감사합니다! 거래가 완료된 후 브라우저로 돌아가는 것을 잊지 마십시오!",
|
||||
"nanogpt_subtitle": "모든 최신 모델 (GPT-4, Claude). \\ nno 구독, Crypto로 지불하십시오.",
|
||||
"nano_current_rep": "현재 대표",
|
||||
"nano_pick_new_rep": "새로운 담당자를 선택하십시오",
|
||||
"narrow": "좁은",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "ပမာဏ၏တန်ဖိုးသည် ${minAmount} ${fiatCurrency} နှင့် ပိုနေရမည်",
|
||||
"more_options": "နောက်ထပ် ရွေးချယ်စရာများ",
|
||||
"name": "နာမည်",
|
||||
"nano_gpt_thanks_message": "nanogpt ကိုသုံးပြီးကျေးဇူးတင်ပါတယ် သင်၏ငွေပေးငွေယူပြီးနောက် browser သို့ပြန်သွားရန်သတိရပါ။",
|
||||
"nanogpt_subtitle": "အားလုံးနောက်ဆုံးပေါ်မော်ဒယ်များ (GPT-4, Claude) ။ \\ nno subscription, crypto နှင့်အတူပေးဆောင်။",
|
||||
"nano_current_rep": "လက်ရှိကိုယ်စားလှယ်",
|
||||
"nano_pick_new_rep": "အသစ်တစ်ခုကိုရွေးပါ",
|
||||
"narrow": "ကျဉ်းသော",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Waarde van het bedrag moet meer of gelijk zijn aan ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Meer opties",
|
||||
"name": "Naam",
|
||||
"nano_gpt_thanks_message": "Bedankt voor het gebruik van Nanogpt! Vergeet niet om terug te gaan naar de browser nadat uw transactie is voltooid!",
|
||||
"nanogpt_subtitle": "Alle nieuwste modellen (GPT-4, Claude). \\ Nno-abonnement, betalen met crypto.",
|
||||
"nano_current_rep": "Huidige vertegenwoordiger",
|
||||
"nano_pick_new_rep": "Kies een nieuwe vertegenwoordiger",
|
||||
"narrow": "Smal",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Wartość kwoty musi być większa lub równa ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Więcej opcji",
|
||||
"name": "Nazwa",
|
||||
"nano_gpt_thanks_message": "Dzięki za użycie Nanogpt! Pamiętaj, aby wrócić do przeglądarki po zakończeniu transakcji!",
|
||||
"nanogpt_subtitle": "Wszystkie najnowsze modele (GPT-4, Claude). \\ Nno subskrypcja, płacą za pomocą kryptografii.",
|
||||
"nano_current_rep": "Obecny przedstawiciel",
|
||||
"nano_pick_new_rep": "Wybierz nowego przedstawiciela",
|
||||
"narrow": "Wąski",
|
||||
|
|
|
@ -367,6 +367,8 @@
|
|||
"moonpay_alert_text": "O valor do montante deve ser maior ou igual a ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Mais opções",
|
||||
"name": "Nome",
|
||||
"nano_gpt_thanks_message": "Obrigado por usar o Nanogpt! Lembre -se de voltar para o navegador após a conclusão da transação!",
|
||||
"nanogpt_subtitle": "Todos os modelos mais recentes (GPT-4, Claude). \\ Nno assinatura, pagam com criptografia.",
|
||||
"nano_current_rep": "Representante atual",
|
||||
"nano_pick_new_rep": "Escolha um novo representante",
|
||||
"narrow": "Estreito",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Сумма должна быть больше или равна ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Дополнительные параметры",
|
||||
"name": "Имя",
|
||||
"nano_gpt_thanks_message": "Спасибо за использование Nanogpt! Не забудьте вернуться в браузер после завершения транзакции!",
|
||||
"nanogpt_subtitle": "Все новейшие модели (GPT-4, Claude). \\ Nno Подписка, платите с крипто.",
|
||||
"nano_current_rep": "Нынешний представитель",
|
||||
"nano_pick_new_rep": "Выберите нового представителя",
|
||||
"narrow": "Узкий",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "มูลค่าของจำนวนต้องมากกว่าหรือเท่ากับ ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "ตัวเลือกเพิ่มเติม",
|
||||
"name": "ชื่อ",
|
||||
"nano_gpt_thanks_message": "ขอบคุณที่ใช้ Nanogpt! อย่าลืมกลับไปที่เบราว์เซอร์หลังจากการทำธุรกรรมของคุณเสร็จสิ้น!",
|
||||
"nanogpt_subtitle": "รุ่นใหม่ล่าสุดทั้งหมด (GPT-4, Claude). การสมัครสมาชิก \\ nno, จ่ายด้วย crypto",
|
||||
"nano_current_rep": "ตัวแทนปัจจุบัน",
|
||||
"nano_pick_new_rep": "เลือกตัวแทนใหม่",
|
||||
"narrow": "แคบ",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Ang halaga ng halaga ay dapat na higit pa o katumbas ng ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Higit pang mga pagpipilian",
|
||||
"name": "Pangalan",
|
||||
"nano_gpt_thanks_message": "Salamat sa paggamit ng nanogpt! Tandaan na bumalik sa browser matapos makumpleto ang iyong transaksyon!",
|
||||
"nanogpt_subtitle": "Ang lahat ng mga pinakabagong modelo (GPT-4, Claude). \\ Nno subscription, magbayad gamit ang crypto.",
|
||||
"nano_current_rep": "Kasalukuyang kinatawan",
|
||||
"nano_pick_new_rep": "Pumili ng isang bagong kinatawan",
|
||||
"narrow": "Makitid",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Tutar ${minAmount} ${fiatCurrency} miktarına eşit veya daha fazla olmalıdır",
|
||||
"more_options": "Daha Fazla Seçenek",
|
||||
"name": "İsim",
|
||||
"nano_gpt_thanks_message": "Nanogpt kullandığınız için teşekkürler! İşleminiz tamamlandıktan sonra tarayıcıya geri dönmeyi unutmayın!",
|
||||
"nanogpt_subtitle": "En yeni modeller (GPT-4, Claude). \\ Nno aboneliği, kripto ile ödeme yapın.",
|
||||
"nano_current_rep": "Mevcut temsilci",
|
||||
"nano_pick_new_rep": "Yeni bir temsilci seçin",
|
||||
"narrow": "Dar",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "Значення суми має бути більшим або дорівнювати ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Більше параметрів",
|
||||
"name": "Ім'я",
|
||||
"nano_gpt_thanks_message": "Дякуємо за використання наногпта! Не забудьте повернутися до браузера після завершення транзакції!",
|
||||
"nanogpt_subtitle": "Усі найновіші моделі (GPT-4, Claude). \\ Nno підписка, оплата криптовалютою.",
|
||||
"nano_current_rep": "Поточний представник",
|
||||
"nano_pick_new_rep": "Виберіть нового представника",
|
||||
"narrow": "вузькі",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "رقم کی قدر ${minAmount} ${fiatCurrency} کے برابر یا زیادہ ہونی چاہیے۔",
|
||||
"more_options": "مزید زرائے",
|
||||
"name": "ﻡﺎﻧ",
|
||||
"nano_gpt_thanks_message": "نانوگپٹ استعمال کرنے کا شکریہ! اپنے لین دین کی تکمیل کے بعد براؤزر کی طرف واپس جانا یاد رکھیں!",
|
||||
"nanogpt_subtitle": "تمام تازہ ترین ماڈل (GPT-4 ، کلاڈ)۔ n n no سبسکرپشن ، کریپٹو کے ساتھ ادائیگی کریں۔",
|
||||
"nano_current_rep": "موجودہ نمائندہ",
|
||||
"nano_pick_new_rep": "ایک نیا نمائندہ منتخب کریں",
|
||||
"narrow": "تنگ",
|
||||
|
|
|
@ -367,6 +367,8 @@
|
|||
"moonpay_alert_text": "Iye owó kò gbọ́dọ̀ kéré ju ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "Ìyàn àfikún",
|
||||
"name": "Oruko",
|
||||
"nano_gpt_thanks_message": "O ṣeun fun lilo Nonnogt! Ranti lati tẹle pada si ẹrọ lilọ kiri ayelujara lẹhin iṣowo rẹ pari!",
|
||||
"nanogpt_subtitle": "Gbogbo awọn awoṣe tuntun (GPT-4, Claude). \\ Nno alabapin kan, sanwo pẹlu Crypto.",
|
||||
"nano_current_rep": "Aṣoju lọwọlọwọ",
|
||||
"nano_pick_new_rep": "Mu aṣoju tuntun kan",
|
||||
"narrow": "Taara",
|
||||
|
|
|
@ -366,6 +366,8 @@
|
|||
"moonpay_alert_text": "金额的价值必须大于或等于 ${minAmount} ${fiatCurrency}",
|
||||
"more_options": "更多选项",
|
||||
"name": "姓名",
|
||||
"nano_gpt_thanks_message": "感谢您使用Nanogpt!事务完成后,请记住回到浏览器!",
|
||||
"nanogpt_subtitle": "所有最新型号(GPT-4,Claude)。\\ nno订阅,用加密货币付款。",
|
||||
"nano_current_rep": "当前代表",
|
||||
"nano_pick_new_rep": "选择新代表",
|
||||
"narrow": "狭窄的",
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'utils/utils.dart';
|
|||
const configPath = 'tool/.secrets-config.json';
|
||||
const evmChainsConfigPath = 'tool/.evm-secrets-config.json';
|
||||
const solanaConfigPath = 'tool/.solana-secrets-config.json';
|
||||
const nanoConfigPath = 'tool/.nano-secrets-config.json';
|
||||
const tronConfigPath = 'tool/.tron-secrets-config.json';
|
||||
|
||||
Future<void> main(List<String> args) async => generateSecretsConfig(args);
|
||||
|
@ -21,6 +22,7 @@ Future<void> generateSecretsConfig(List<String> args) async {
|
|||
final configFile = File(configPath);
|
||||
final evmChainsConfigFile = File(evmChainsConfigPath);
|
||||
final solanaConfigFile = File(solanaConfigPath);
|
||||
final nanoConfigFile = File(nanoConfigPath);
|
||||
final tronConfigFile = File(tronConfigPath);
|
||||
|
||||
final secrets = <String, dynamic>{};
|
||||
|
@ -42,45 +44,48 @@ Future<void> generateSecretsConfig(List<String> args) async {
|
|||
}
|
||||
}
|
||||
|
||||
// base:
|
||||
SecretKey.base.forEach((sec) {
|
||||
if (secrets[sec.name] != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
secrets[sec.name] = sec.generate();
|
||||
});
|
||||
|
||||
var secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
await configFile.writeAsString(secretsJson);
|
||||
|
||||
secrets.clear();
|
||||
|
||||
// evm chains:
|
||||
SecretKey.evmChainsSecrets.forEach((sec) {
|
||||
if (secrets[sec.name] != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
secrets[sec.name] = sec.generate();
|
||||
});
|
||||
|
||||
secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
|
||||
await evmChainsConfigFile.writeAsString(secretsJson);
|
||||
|
||||
secrets.clear();
|
||||
|
||||
// solana:
|
||||
SecretKey.solanaSecrets.forEach((sec) {
|
||||
if (secrets[sec.name] != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
secrets[sec.name] = sec.generate();
|
||||
});
|
||||
|
||||
secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
|
||||
await solanaConfigFile.writeAsString(secretsJson);
|
||||
secrets.clear();
|
||||
|
||||
// nano:
|
||||
SecretKey.nanoSecrets.forEach((sec) {
|
||||
if (secrets[sec.name] != null) {
|
||||
return;
|
||||
}
|
||||
secrets[sec.name] = sec.generate();
|
||||
});
|
||||
secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
await nanoConfigFile.writeAsString(secretsJson);
|
||||
secrets.clear();
|
||||
|
||||
SecretKey.tronSecrets.forEach((sec) {
|
||||
|
@ -90,8 +95,7 @@ Future<void> generateSecretsConfig(List<String> args) async {
|
|||
|
||||
secrets[sec.name] = sec.generate();
|
||||
});
|
||||
|
||||
secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
|
||||
await tronConfigFile.writeAsString(secretsJson);
|
||||
secrets.clear();
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ class SecretKey {
|
|||
SecretKey('ankrApiKey', () => ''),
|
||||
];
|
||||
|
||||
static final nanoSecrets = [
|
||||
SecretKey('nano2ApiKey', () => ''),
|
||||
];
|
||||
|
||||
static final tronSecrets = [
|
||||
SecretKey('tronGridApiKey', () => ''),
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue