Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.8.3+0] RC: add arbitrum coin type and private key export #2512

Merged
merged 8 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
2 changes: 2 additions & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@
"manageAnalytics": "Manage analytics",
"logs": "Logs",
"resetActivatedCoinsTitle": "Reset Activated Coins",
"privateKeys": "Private Keys",
"copyWarning": "Your Clipboard isn't a safe place for your private key! Copying the seed phrase or private keys can make them vulnerable to clipboard hacks. Please handle with caution and only copy if absolutely necessary.",
smk762 marked this conversation as resolved.
Show resolved Hide resolved
"seedConfirmTitle": "Let's double check your seed phrase",
"seedConfirmDescription": "Your seed phrase is the only way to access Your funds. That's why we want to ensure you saved it safely. Please input your seed phrase into text filed below.",
"standardWallet": "Standard wallet",
Expand Down
1 change: 1 addition & 0 deletions lib/app_config/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Map<String, int> priorityCoinsAbbrMap = {
'DASH': 11,
'MATIC': 10,
'FTM': 10,
'ARB': 10,
'AVAX': 10,
'HT': 10,
'MOVR': 10,
Expand Down
25 changes: 25 additions & 0 deletions lib/bloc/dex_repository.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:rational/rational.dart';
import 'package:web_dex/app_config/app_config.dart';
import 'package:web_dex/mm2/mm2_api/mm2_api.dart';
import 'package:web_dex/mm2/mm2_api/rpc/base.dart';
import 'package:web_dex/mm2/mm2_api/rpc/best_orders/best_orders.dart';
Expand Down Expand Up @@ -139,4 +140,28 @@ class DexRepository {

return Swap.fromJson(response['result']);
}

Future<void> waitOrderbookAvailability({
int retries = 10,
int interval = 300,
}) async {
BestOrders orders;

for (int attempt = 0; attempt < retries; attempt++) {
orders = await getBestOrders(
BestOrdersRequest(
coin: defaultDexCoin,
type: BestOrdersRequestType.number,
number: 1,
action: 'sell',
),
);

if (orders.result?.isNotEmpty ?? false) {
return;
}

await Future.delayed(Duration(milliseconds: interval));
}
}
}
5 changes: 5 additions & 0 deletions lib/bloc/fiat/base_fiat_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Currency {
(t == CoinType.avx20 && symbol == 'AVAX') ||
(t == CoinType.etc && symbol == 'ETC') ||
(t == CoinType.ftm20 && symbol == 'FTM') ||
(t == CoinType.arb20 && symbol == 'ARB') ||
(t == CoinType.hrc20 && symbol == 'ONE') ||
(t == CoinType.plg20 && symbol == 'MATIC') ||
(t == CoinType.mvr20 && symbol == 'MOVR')) return symbol;
Expand Down Expand Up @@ -155,6 +156,8 @@ abstract class BaseFiatProvider {
return 'ETC';
case CoinType.ftm20:
return 'FTM';
case CoinType.arb20:
return 'ARB';
case CoinType.hrc20:
return 'HARMONY';
case CoinType.plg20:
Expand Down Expand Up @@ -261,6 +264,8 @@ abstract class BaseFiatProvider {
return CoinType.etc;
case "FTM":
return CoinType.ftm20;
case "ARB":
return CoinType.arb20;
case "HARMONY":
return CoinType.hrc20;
case "MATIC":
Expand Down
12 changes: 6 additions & 6 deletions lib/bloc/taker_form/taker_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -240,18 +240,18 @@ class TakerBloc extends Bloc<TakerEvent, TakerState> {
TakerSetDefaults event,
Emitter<TakerState> emit,
) async {
if (state.sellCoin == null) await _setDefaultSellCoin();
}

Future<void> _setDefaultSellCoin() async {
final Coin? defaultCoin = _coinsRepo.getCoin(defaultDexCoin);
add(TakerSetSellCoin(defaultCoin));
if (state.sellCoin == null) {
final Coin? defaultCoin = _coinsRepo.getCoin(defaultDexCoin);
add(TakerSetSellCoin(defaultCoin, setOnlyIfNotSet: true));
}
}

Future<void> _onSetSellCoin(
TakerSetSellCoin event,
Emitter<TakerState> emit,
) async {
if (event.setOnlyIfNotSet && state.sellCoin != null) return;

emit(state.copyWith(
sellCoin: () => event.coin,
showCoinSelector: () => false,
Expand Down
4 changes: 3 additions & 1 deletion lib/bloc/taker_form/taker_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ class TakerCoinSelectorClick extends TakerEvent {}
class TakerOrderSelectorClick extends TakerEvent {}

class TakerSetSellCoin extends TakerEvent {
TakerSetSellCoin(this.coin, {this.autoSelectOrderAbbr});
TakerSetSellCoin(this.coin,
{this.autoSelectOrderAbbr, this.setOnlyIfNotSet = false});

final Coin? coin;
final String? autoSelectOrderAbbr;
final bool setOnlyIfNotSet;
}

class TakerSelectOrder extends TakerEvent {
Expand Down
12 changes: 10 additions & 2 deletions lib/blocs/maker_form_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,11 @@ class MakerFormBloc implements BlocBase {
if (amountStr.isEmpty) {
amount = null;
} else {
amount = Rational.parse(amountStr);
try {
amount = Rational.parse(amountStr);
} catch (_) {
amount = null;
}
}

isMaxActive = false;
Expand All @@ -544,7 +548,11 @@ class MakerFormBloc implements BlocBase {
if (amountStr.isEmpty) {
amount = null;
} else {
amount = Rational.parse(amountStr);
try {
amount = Rational.parse(amountStr);
} catch (_) {
amount = null;
}
}

if (amount == buyAmount) return;
Expand Down
2 changes: 2 additions & 0 deletions lib/generated/codegen_loader.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ abstract class LocaleKeys {
static const manageAnalytics = 'manageAnalytics';
static const logs = 'logs';
static const resetActivatedCoinsTitle = 'resetActivatedCoinsTitle';
static const privateKeys = 'privateKeys';
static const copyWarning = 'copyWarning';
static const seedConfirmTitle = 'seedConfirmTitle';
static const seedConfirmDescription = 'seedConfirmDescription';
static const standardWallet = 'standardWallet';
Expand Down
23 changes: 23 additions & 0 deletions lib/mm2/mm2_api/mm2_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import 'package:web_dex/mm2/mm2_api/rpc/rpc_error.dart';
import 'package:web_dex/mm2/mm2_api/rpc/sell/sell_request.dart';
import 'package:web_dex/mm2/mm2_api/rpc/send_raw_transaction/send_raw_transaction_request.dart';
import 'package:web_dex/mm2/mm2_api/rpc/setprice/setprice_request.dart';
import 'package:web_dex/mm2/mm2_api/rpc/show_priv_key/show_priv_key_request.dart';
import 'package:web_dex/mm2/mm2_api/rpc/show_priv_key/show_priv_key_response.dart';
import 'package:web_dex/mm2/mm2_api/rpc/stop/stop_req.dart';
import 'package:web_dex/mm2/mm2_api/rpc/trade_preimage/trade_preimage_request.dart';
import 'package:web_dex/mm2/mm2_api/rpc/trade_preimage/trade_preimage_response.dart';
Expand Down Expand Up @@ -999,4 +1001,25 @@ class Mm2Api {

return response;
}

Future<ShowPrivKeyResponse?> showPrivKey(
ShowPrivKeyRequest request,
) async {
try {
final String response = await _call(request);
final Map<String, dynamic> json = jsonDecode(response);
if (json['error'] != null) {
return null;
}
return ShowPrivKeyResponse.fromJson(json);
} catch (e, s) {
log(
'Error getting privkey ${request.coin}: ${e.toString()}',
path: 'api => showPrivKey',
trace: s,
isError: true,
);
return null;
}
}
Comment on lines +1005 to +1024
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Additional security measures needed for private key handling

The codebase has good foundational security measures like password protection and error logging, but could benefit from:

  1. Adding rate limiting specifically for private key access operations to prevent brute force attempts
  2. Implementing audit logging for successful private key retrievals (currently only errors are logged)

The suggestion about key rotation mechanisms is not applicable for a non-custodial wallet where users manage their own keys.

🔗 Analysis chain

Consider additional security measures for private key handling.

While the implementation follows the class's patterns well, handling private keys requires extra security considerations:

  1. Consider adding rate limiting for private key requests
  2. Add logging for security audit purposes
  3. Consider implementing key rotation or expiry mechanisms
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for other private key handling implementations
ast-grep --pattern 'private_key|priv_key|privkey'

Length of output: 51


Script:

#!/bin/bash
# Search for ShowPrivKey related implementations
ast-grep --pattern 'class ShowPrivKeyRequest {
  $$$
}'

ast-grep --pattern 'class ShowPrivKeyResponse {
  $$$
}'

# Search for rate limiting patterns
rg -i "rate.*limit|throttle" -A 3

# Search for security-related configurations
rg -i "security|auth.*config" -A 3

# Check logging patterns for private key operations
rg "log\(" -A 2

Length of output: 81916

}
19 changes: 19 additions & 0 deletions lib/mm2/mm2_api/rpc/show_priv_key/show_priv_key_request.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:web_dex/mm2/mm2_api/rpc/base.dart';

class ShowPrivKeyRequest implements BaseRequest {
ShowPrivKeyRequest({
required this.coin,
});
@override
late String userpass;
@override
final String method = 'show_priv_key';
final String coin;

@override
Map<String, dynamic> toJson() => <String, dynamic>{
'method': method,
'userpass': userpass,
'coin': coin,
};
}
14 changes: 14 additions & 0 deletions lib/mm2/mm2_api/rpc/show_priv_key/show_priv_key_response.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class ShowPrivKeyResponse {
ShowPrivKeyResponse({
required this.coin,
required this.privKey,
});

factory ShowPrivKeyResponse.fromJson(Map<String, dynamic> json) =>
ShowPrivKeyResponse(
coin: json['result']['coin'] ?? '',
privKey: json['result']['priv_key'] ?? '',
);
final String coin;
final String privKey;
}
6 changes: 6 additions & 0 deletions lib/model/coin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,12 @@ CoinType? getCoinType(String? jsonType, String coinAbbr) {
} else {
continue;
}
case CoinType.arb20:
if (jsonType == 'Arbitrum') {
return value;
} else {
continue;
}
case CoinType.etc:
if (jsonType == 'Ethereum Classic') {
return value;
Expand Down
1 change: 1 addition & 0 deletions lib/model/coin_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum CoinType {
bep20,
qrc20,
ftm20,
arb20,
avx20,
hrc20,
mvr20,
Expand Down
4 changes: 4 additions & 0 deletions lib/model/coin_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ String getCoinTypeName(CoinType type) {
return 'Smart Chain';
case CoinType.ftm20:
return 'FTM-20';
case CoinType.arb20:
return 'ARB-20';
case CoinType.etc:
return 'ETC';
case CoinType.avx20:
Expand Down Expand Up @@ -163,6 +165,8 @@ String getCoinTypeNameLong(CoinType type) {
return 'Smart Chain';
case CoinType.ftm20:
return 'Fantom';
case CoinType.arb20:
return 'Arbitrum';
case CoinType.etc:
return 'Ethereum Classic';
case CoinType.avx20:
Expand Down
13 changes: 12 additions & 1 deletion lib/router/navigators/app_router_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ class AppRouterDelegate extends RouterDelegate<AppRoutePath>
routingState.selectedMenu = MainMenuValue.dex;
routingState.dexState.action = path.action;
routingState.dexState.uuid = path.uuid;
routingState.dexState.fromCurrency = path.fromCurrency;
routingState.dexState.fromAmount = path.fromAmount;
routingState.dexState.toCurrency = path.toCurrency;
routingState.dexState.toAmount = path.toAmount;
routingState.dexState.orderType = path.orderType;
}

void _setNewMarketMakerBotRoutePath(MarketMakerBotRoutePath path) {
Expand Down Expand Up @@ -165,7 +170,13 @@ class AppRouterDelegate extends RouterDelegate<AppRoutePath>
);
}

return DexRoutePath.dex();
return DexRoutePath.dex(
fromAmount: routingState.dexState.fromAmount,
fromCurrency: routingState.dexState.fromCurrency,
toAmount: routingState.dexState.toAmount,
toCurrency: routingState.dexState.toCurrency,
orderType: routingState.dexState.orderType,
);
}

AppRoutePath get _currentMarketMakerBotConfiguration {
Expand Down
9 changes: 9 additions & 0 deletions lib/router/parsers/dex_route_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ class _DexRouteParser implements BaseRouteParser {
}
}

if (uri.pathSegments.length == 1) {
return DexRoutePath.dex(
fromCurrency: uri.queryParameters['from_currency'] ?? '',
fromAmount: uri.queryParameters['from_amount'] ?? '',
toCurrency: uri.queryParameters['to_currency'] ?? '',
toAmount: uri.queryParameters['to_amount'] ?? '',
orderType: uri.queryParameters['order_type'] ?? '',
);
}
return DexRoutePath.dex();
}
}
Expand Down
6 changes: 3 additions & 3 deletions lib/router/parsers/root_route_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class RootRouteInformationParser extends RouteInformationParser<AppRoutePath> {
@override
Future<AppRoutePath> parseRouteInformation(
RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.uri.path);
final BaseRouteParser parser = _getRoutParser(uri);
final BaseRouteParser parser =
_getRoutParser(Uri.parse(routeInformation.uri.path));

return parser.getRoutePath(uri);
return parser.getRoutePath(routeInformation.uri);
}

@override
Expand Down
23 changes: 20 additions & 3 deletions lib/router/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,33 @@ class FiatRoutePath implements AppRoutePath {
}

class DexRoutePath implements AppRoutePath {
DexRoutePath.dex()
: location = '/${firstUriSegment.dex}',
DexRoutePath.dex({
this.fromCurrency = '',
this.fromAmount = '',
this.toCurrency = '',
this.toAmount = '',
this.orderType = '',
}) : location = '/${firstUriSegment.dex}',
uuid = '';

DexRoutePath.swapDetails(this.action, this.uuid)
: location = '/${firstUriSegment.dex}/trading_details/$uuid';
: location = '/${firstUriSegment.dex}/trading_details/$uuid',
fromCurrency = '',
fromAmount = '',
toCurrency = '',
toAmount = '',
orderType = '';

@override
final String location;
final String uuid;
DexAction action = DexAction.none;

final String fromCurrency;
final String fromAmount;
final String toCurrency;
final String toAmount;
final String orderType;
}

class BridgeRoutePath implements AppRoutePath {
Expand Down
Loading
Loading