Cw 451 wallet connect for ethereum (#1049)

* Update Flutter
Update packages

* Feat: Wallet connect for ethereum

* Fix localization issues
Fix UI issues
Update old packages
Update workflow
Update how to build guide

* feat: Wallet connect

* feat: Add wallet connect for ethereum

* chore: Add eth dependencies in configure file

* Minor: `WalletConnect` settings name, not `Wallet connect`

* fix: Merge conflicts

* fix: Issues with test cases on various dApps, introduce Arbitrum rinkerby as suported chain

* ui: Design fixes for WalletConnect flow

* chore: Update repo and comment out send apk to channel in workflow

* fix: Core implementation

* feat: WalletConnect WIP

* feat: WalletConnect WIP

* feat: WalletConnect WIP

* chore: Unused parameters WIP [skip ci]

* fix: Code review fixes

* Feat: WalletConnect feat WIP

* feat: WalletConnect

* feat: WalletConnect

* feat: WalletConnect

* Feat: WalletConnect

* Feat: WalletConnect

* feat: Remove queue support for the bottomsheet

* feat: WalletConnect feature, bug fixes, folder restructuring, localization

* Feat: Add positive feedback prompt on successful transaction

* fix: Delete session bug

* fix: dependencies registration WIP

* feat: Registering dependencies for walletconnect

* chore: Move key data to secrets

* chore: ensure appropriate null checks

* chore: localization

* chore: Remove unused code

* localization

* chore: Remove unused code

* chore: Remove unused code

* chore: Add walletconnect project id key entry

* fix: Revert bash command for linnux support

* fix: Issues with translation in some languages and making unneeded external variable private

* fix: Add bottomsheet listener to desktop dashboard page

* Generalize ethereum not enough gas error check

---------

Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
Co-authored-by: Justin Ehrenhofer <justin.ehrenhofer@gmail.com>
This commit is contained in:
Adegoke David 2023-10-03 15:56:10 +01:00 committed by GitHub
parent ae71f2045b
commit 32643823e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 2819 additions and 314 deletions

View file

@ -6,7 +6,6 @@ on:
jobs: jobs:
PR_test_build: PR_test_build:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env: env:
STORE_PASS: test@cake_wallet STORE_PASS: test@cake_wallet
@ -23,12 +22,12 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-java@v1 - uses: actions/setup-java@v1
with: with:
java-version: '8.x' java-version: "8.x"
- name: Flutter action - name: Flutter action
uses: subosito/flutter-action@v1 uses: subosito/flutter-action@v1
with: with:
flutter-version: '3.10.x' flutter-version: "3.10.x"
channel: stable channel: stable
- name: Install package dependencies - name: Install package dependencies
@ -131,6 +130,7 @@ jobs:
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
- name: Rename app - name: Rename app
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties
@ -171,6 +171,6 @@ jobs:
token: ${{ secrets.SLACK_APP_TOKEN }} token: ${{ secrets.SLACK_APP_TOKEN }}
path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
channel: ${{ secrets.SLACK_APK_CHANNEL }} channel: ${{ secrets.SLACK_APK_CHANNEL }}
title: '${{github.head_ref}}.apk' title: "${{github.head_ref}}.apk"
filename: ${{github.head_ref}}.apk filename: ${{github.head_ref}}.apk
initial_comment: ${{ github.event.head_commit.message }} initial_comment: ${{ github.event.head_commit.message }}

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View file

@ -77,6 +77,8 @@ abstract class EthereumWalletBase
late final EthPrivateKey _ethPrivateKey; late final EthPrivateKey _ethPrivateKey;
EthPrivateKey get ethPrivateKey => _ethPrivateKey;
late EthereumClient _client; late EthereumClient _client;
int? _gasPrice; int? _gasPrice;

View file

@ -0,0 +1,5 @@
abstract class ChainService {
String getNamespace();
String getChainId();
List<String> getEvents();
}

View file

@ -0,0 +1,60 @@
class WCEthereumTransactionModel {
final String from;
final String to;
final String value;
final String? nonce;
final String? gasPrice;
final String? maxFeePerGas;
final String? maxPriorityFeePerGas;
final String? gas;
final String? gasLimit;
final String? data;
WCEthereumTransactionModel({
required this.from,
required this.to,
required this.value,
this.nonce,
this.gasPrice,
this.maxFeePerGas,
this.maxPriorityFeePerGas,
this.gas,
this.gasLimit,
this.data,
});
factory WCEthereumTransactionModel.fromJson(Map<String, dynamic> json) {
return WCEthereumTransactionModel(
from: json['from'] as String,
to: json['to'] as String,
value: json['value'] as String,
nonce: json['nonce'] as String?,
gasPrice: json['gasPrice'] as String?,
maxFeePerGas: json['maxFeePerGas'] as String?,
maxPriorityFeePerGas: json['maxPriorityFeePerGas'] as String?,
gas: json['gas'] as String?,
gasLimit: json['gasLimit'] as String?,
data: json['data'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'from': from,
'to': to,
'value': value,
'nonce': nonce,
'gasPrice': gasPrice,
'maxFeePerGas': maxFeePerGas,
'maxPriorityFeePerGas': maxPriorityFeePerGas,
'gas': gas,
'gasLimit': gasLimit,
'data': data,
};
}
@override
String toString() {
return 'EthereumTransactionModel(from: $from, to: $to, nonce: $nonce, gasPrice: $gasPrice, maxFeePerGas: $maxFeePerGas, maxPriorityFeePerGas: $maxPriorityFeePerGas, gas: $gas, gasLimit: $gasLimit, value: $value, data: $data)';
}
}

View file

@ -0,0 +1,35 @@
import 'package:cake_wallet/core/wallet_connect/evm_chain_service.dart';
enum EVMChainId {
ethereum,
polygon,
goerli,
mumbai,
arbitrum,
}
extension EVMChainIdX on EVMChainId {
String chain() {
String name = '';
switch (this) {
case EVMChainId.ethereum:
name = '1';
break;
case EVMChainId.polygon:
name = '137';
break;
case EVMChainId.goerli:
name = '5';
break;
case EVMChainId.arbitrum:
name = '42161';
break;
case EVMChainId.mumbai:
name = '80001';
break;
}
return '${EvmChainServiceImpl.namespace}:$name';
}
}

View file

@ -0,0 +1,294 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:typed_data';
import 'package:cake_wallet/core/wallet_connect/eth_transaction_model.dart';
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/error_display_widget.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/string_parsing.dart';
import 'package:convert/convert.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:http/http.dart' as http;
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:web3dart/web3dart.dart';
import 'chain_service.dart';
import 'wallet_connect_key_service.dart';
class EvmChainServiceImpl implements ChainService {
final AppStore appStore;
final BottomSheetService bottomSheetService;
final Web3Wallet wallet;
final WalletConnectKeyService wcKeyService;
static const namespace = 'eip155';
static const pSign = 'personal_sign';
static const eSign = 'eth_sign';
static const eSignTransaction = 'eth_signTransaction';
static const eSignTypedData = 'eth_signTypedData_v4';
static const eSendTransaction = 'eth_sendTransaction';
final EVMChainId reference;
final Web3Client ethClient;
EvmChainServiceImpl({
required this.reference,
required this.appStore,
required this.wcKeyService,
required this.bottomSheetService,
required this.wallet,
Web3Client? ethClient,
}) : ethClient = ethClient ??
Web3Client(
appStore.settingsStore.getCurrentNode(WalletType.ethereum).uri.toString(),
http.Client(),
) {
for (final String event in getEvents()) {
wallet.registerEventEmitter(chainId: getChainId(), event: event);
}
wallet.registerRequestHandler(
chainId: getChainId(),
method: pSign,
handler: personalSign,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSign,
handler: ethSign,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSignTransaction,
handler: ethSignTransaction,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSendTransaction,
handler: ethSignTransaction,
);
wallet.registerRequestHandler(
chainId: getChainId(),
method: eSignTypedData,
handler: ethSignTypedData,
);
}
@override
String getNamespace() {
return namespace;
}
@override
String getChainId() {
return reference.chain();
}
@override
List<String> getEvents() {
return ['chainChanged', 'accountsChanged'];
}
Future<String?> requestAuthorization(String? text) async {
// Show the bottom sheet
final bool? isApproved = await bottomSheetService.queueBottomSheet(
widget: Web3RequestModal(
child: ConnectionWidget(
title: S.current.signTransaction,
info: [
ConnectionModel(
text: text,
),
],
),
),
) as bool?;
if (isApproved != null && isApproved == false) {
return 'User rejected signature';
}
return null;
}
Future<String> personalSign(String topic, dynamic parameters) async {
log('received personal sign request: $parameters');
final String message;
if (parameters[0] == null) {
message = '';
} else {
message = parameters[0].toString().utf8Message;
}
final String? authError = await requestAuthorization(message);
if (authError != null) {
return authError;
}
try {
// Load the private key
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final String signature = hex.encode(
credentials.signPersonalMessageToUint8List(Uint8List.fromList(utf8.encode(message))),
);
return '0x$signature';
} catch (e) {
log(e.toString());
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: '${S.current.errorGettingCredentials} ${e.toString()}',
),
);
return 'Failed: Error while getting credentials';
}
}
Future<String> ethSign(String topic, dynamic parameters) async {
log('received eth sign request: $parameters');
final String message;
if (parameters[1] == null) {
message = '';
} else {
message = parameters[1].toString().utf8Message;
}
final String? authError = await requestAuthorization(message);
if (authError != null) {
return authError;
}
try {
// Load the private key
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final EthPrivateKey credentials = EthPrivateKey.fromHex(keys[0].privateKey);
final String signature = hex.encode(
credentials.signPersonalMessageToUint8List(
Uint8List.fromList(utf8.encode(message)),
),
);
log(signature);
return '0x$signature';
} catch (e) {
log('error: ${e.toString()}');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: '${S.current.error}: ${e.toString()}'),
);
return 'Failed';
}
}
Future<String> ethSignTransaction(String topic, dynamic parameters) async {
log('received eth sign transaction request: $parameters');
final paramsData = parameters[0] as Map<String, dynamic>;
final message = _convertToReadable(paramsData);
final String? authError = await requestAuthorization(message);
if (authError != null) {
return authError;
}
// Load the private key
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
final Credentials credentials = EthPrivateKey.fromHex(keys[0].privateKey);
WCEthereumTransactionModel ethTransaction =
WCEthereumTransactionModel.fromJson(parameters[0] as Map<String, dynamic>);
final transaction = Transaction(
from: EthereumAddress.fromHex(ethTransaction.from),
to: EthereumAddress.fromHex(ethTransaction.to),
maxGas: ethTransaction.gasLimit != null ? int.tryParse(ethTransaction.gasLimit ?? "") : null,
gasPrice: ethTransaction.gasPrice != null
? EtherAmount.inWei(BigInt.parse(ethTransaction.gasPrice ?? ""))
: null,
value: EtherAmount.inWei(BigInt.parse(ethTransaction.value)),
data: hexToBytes(ethTransaction.data ?? ""),
nonce: ethTransaction.nonce != null ? int.tryParse(ethTransaction.nonce ?? "") : null,
);
try {
final result = await ethClient.sendTransaction(credentials, transaction);
log('Result: $result');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: S.current.awaitDAppProcessing,
isError: false,
),
);
return result;
} catch (e) {
log('An error has occured while signing transaction: ${e.toString()}');
bottomSheetService.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(
message: '${S.current.errorSigningTransaction}: ${e.toString()}',
),
);
return 'Failed';
}
}
Future<String> ethSignTypedData(String topic, dynamic parameters) async {
log('received eth sign typed data request: $parameters');
final String? data = parameters[1] as String?;
final String? authError = await requestAuthorization(data);
if (authError != null) {
return authError;
}
final List<ChainKeyModel> keys = wcKeyService.getKeysForChain(getChainId());
return EthSigUtil.signTypedData(
privateKey: keys[0].privateKey,
jsonData: data ?? '',
version: TypedDataVersion.V4,
);
}
String _convertToReadable(Map<String, dynamic> data) {
String gas = int.parse((data['gas'] as String).substring(2), radix: 16).toString();
String value = data['value'] != null
? (int.parse((data['value'] as String).substring(2), radix: 16) / 1e18).toString() + ' ETH'
: '0 ETH';
String from = data['from'] as String;
String to = data['to'] as String;
return '''
Gas: $gas\n
Value: $value\n
From: $from\n
To: $to
''';
}
}

View file

@ -0,0 +1,16 @@
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
class AuthRequestModel {
final String iss;
final AuthRequest request;
AuthRequestModel({
required this.iss,
required this.request,
});
@override
String toString() {
return 'AuthRequestModel(iss: $iss, request: $request)';
}
}

View file

@ -0,0 +1,20 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
class BottomSheetQueueItemModel {
final Widget widget;
final bool isModalDismissible;
final Completer<dynamic> completer;
BottomSheetQueueItemModel({
required this.widget,
required this.completer,
this.isModalDismissible = false,
});
@override
String toString() {
return 'BottomSheetQueueItemModel(widget: $widget, completer: $completer)';
}
}

View file

@ -0,0 +1,16 @@
class ChainKeyModel {
final List<String> chains;
final String privateKey;
final String publicKey;
ChainKeyModel({
required this.chains,
required this.privateKey,
required this.publicKey,
});
@override
String toString() {
return 'ChainKeyModel(chains: $chains, privateKey: $privateKey, publicKey: $publicKey)';
}
}

View file

@ -0,0 +1,18 @@
class ConnectionModel {
final String? title;
final String? text;
final List<String>? elements;
final Map<String, void Function()>? elementActions;
ConnectionModel({
this.title,
this.text,
this.elements,
this.elementActions,
});
@override
String toString() {
return 'WalletConnectRequestModel(title: $title, text: $text, elements: $elements, elementActions: $elementActions)';
}
}

View file

@ -0,0 +1,14 @@
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
class SessionRequestModel {
final ProposalData request;
SessionRequestModel({
required this.request,
});
@override
String toString() {
return 'SessionRequestModel(request: $request)';
}
}

View file

@ -0,0 +1,72 @@
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_base.dart';
abstract class WalletConnectKeyService {
/// Returns a list of all the keys.
List<ChainKeyModel> getKeys();
/// Returns a list of all the chain ids.
List<String> getChains();
/// Returns a list of all the keys for a given chain id.
/// If the chain is not found, returns an empty list.
/// - [chain]: The chain to get the keys for.
List<ChainKeyModel> getKeysForChain(String chain);
/// Returns a list of all the accounts in namespace:chainId:address format.
List<String> getAllAccounts();
}
class KeyServiceImpl implements WalletConnectKeyService {
KeyServiceImpl(this.wallet)
: _keys = [
ChainKeyModel(
chains: [
'eip155:1',
'eip155:5',
'eip155:137',
'eip155:42161',
'eip155:80001',
],
privateKey: ethereum!.getPrivateKey(wallet),
publicKey: ethereum!.getPublicKey(wallet),
),
];
late final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
late final List<ChainKeyModel> _keys;
@override
List<String> getChains() {
final List<String> chainIds = [];
for (final ChainKeyModel key in _keys) {
chainIds.addAll(key.chains);
}
return chainIds;
}
@override
List<ChainKeyModel> getKeys() => _keys;
@override
List<ChainKeyModel> getKeysForChain(String chain) {
return _keys.where((e) => e.chains.contains(chain)).toList();
}
@override
List<String> getAllAccounts() {
final List<String> accounts = [];
for (final ChainKeyModel key in _keys) {
for (final String chain in key.chains) {
accounts.add('$chain:${key.publicKey}');
}
}
return accounts;
}
}

View file

@ -0,0 +1,43 @@
import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/models/bottom_sheet_queue_item_model.dart';
import 'package:flutter/material.dart';
abstract class BottomSheetService {
abstract final ValueNotifier<BottomSheetQueueItemModel?> currentSheet;
Future<dynamic> queueBottomSheet({
required Widget widget,
bool isModalDismissible = false,
});
void resetCurrentSheet();
}
class BottomSheetServiceImpl implements BottomSheetService {
@override
final ValueNotifier<BottomSheetQueueItemModel?> currentSheet = ValueNotifier(null);
@override
Future<dynamic> queueBottomSheet({
required Widget widget,
bool isModalDismissible = false,
}) async {
// Create the bottom sheet queue item
final completer = Completer<dynamic>();
final queueItem = BottomSheetQueueItemModel(
widget: widget,
completer: completer,
isModalDismissible: isModalDismissible,
);
currentSheet.value = queueItem;
return await completer.future;
}
@override
void resetCurrentSheet() {
currentSheet.value = null;
}
}

View file

@ -0,0 +1,277 @@
import 'dart:async';
import 'dart:developer';
import 'dart:typed_data';
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/evm_chain_service.dart';
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/session_request_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_request_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/error_display_widget.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'wc_bottom_sheet_service.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
part 'web3wallet_service.g.dart';
class Web3WalletService = Web3WalletServiceBase with _$Web3WalletService;
abstract class Web3WalletServiceBase with Store {
final AppStore appStore;
final BottomSheetService _bottomSheetHandler;
final WalletConnectKeyService walletKeyService;
late Web3Wallet _web3Wallet;
@observable
bool isInitialized;
/// The list of requests from the dapp
/// Potential types include, but aren't limited to:
/// [SessionProposalEvent], [AuthRequest]
@observable
ObservableList<PairingInfo> pairings;
@observable
ObservableList<SessionData> sessions;
@observable
ObservableList<StoredCacao> auth;
Web3WalletServiceBase(this._bottomSheetHandler, this.walletKeyService, this.appStore)
: pairings = ObservableList<PairingInfo>(),
sessions = ObservableList<SessionData>(),
auth = ObservableList<StoredCacao>(),
isInitialized = false;
@action
void create() {
// Create the web3wallet client
_web3Wallet = Web3Wallet(
core: Core(projectId: secrets.walletConnectProjectId),
metadata: const PairingMetadata(
name: 'Cake Wallet',
description: 'Cake Wallet',
url: 'https://cakewallet.com',
icons: ['https://cakewallet.com/assets/image/cake_logo.png'],
),
);
// Setup our accounts
List<ChainKeyModel> chainKeys = walletKeyService.getKeys();
for (final chainKey in chainKeys) {
for (final chainId in chainKey.chains) {
_web3Wallet.registerAccount(
chainId: chainId,
accountAddress: chainKey.publicKey,
);
}
}
// Setup our listeners
log('Created instance of web3wallet');
_web3Wallet.core.pairing.onPairingInvalid.subscribe(_onPairingInvalid);
_web3Wallet.core.pairing.onPairingCreate.subscribe(_onPairingCreate);
_web3Wallet.core.pairing.onPairingDelete.subscribe(_onPairingDelete);
_web3Wallet.core.pairing.onPairingExpire.subscribe(_onPairingDelete);
_web3Wallet.pairings.onSync.subscribe(_onPairingsSync);
_web3Wallet.onSessionProposal.subscribe(_onSessionProposal);
_web3Wallet.onSessionProposalError.subscribe(_onSessionProposalError);
_web3Wallet.onSessionConnect.subscribe(_onSessionConnect);
_web3Wallet.onAuthRequest.subscribe(_onAuthRequest);
}
@action
Future<void> init() async {
// Await the initialization of the web3wallet
log('Intializing web3wallet');
if (!isInitialized) {
try {
await _web3Wallet.init();
log('Initialized');
isInitialized = true;
} catch (e) {
log('Experimentallllll: $e');
isInitialized = false;
}
}
_refreshPairings();
final newSessions = _web3Wallet.sessions.getAll();
sessions.addAll(newSessions);
final newAuthRequests = _web3Wallet.completeRequests.getAll();
auth.addAll(newAuthRequests);
for (final cId in EVMChainId.values) {
EvmChainServiceImpl(
reference: cId,
appStore: appStore,
wcKeyService: walletKeyService,
bottomSheetService: _bottomSheetHandler,
wallet: _web3Wallet,
);
}
}
@action
FutureOr<void> onDispose() {
log('web3wallet dispose');
_web3Wallet.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid);
_web3Wallet.pairings.onSync.unsubscribe(_onPairingsSync);
_web3Wallet.onSessionProposal.unsubscribe(_onSessionProposal);
_web3Wallet.onSessionProposalError.unsubscribe(_onSessionProposalError);
_web3Wallet.onSessionConnect.unsubscribe(_onSessionConnect);
_web3Wallet.onAuthRequest.unsubscribe(_onAuthRequest);
_web3Wallet.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
_web3Wallet.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
}
Web3Wallet getWeb3Wallet() {
return _web3Wallet;
}
void _onPairingsSync(StoreSyncEvent? args) {
if (args != null) {
_refreshPairings();
}
}
void _onPairingDelete(PairingEvent? event) {
_refreshPairings();
}
@action
void _refreshPairings() {
pairings.clear();
final allPairings = _web3Wallet.pairings.getAll();
pairings.addAll(allPairings);
}
Future<void> _onSessionProposalError(SessionProposalErrorEvent? args) async {
log(args.toString());
}
void _onSessionProposal(SessionProposalEvent? args) async {
if (args != null) {
final Widget modalWidget = Web3RequestModal(
child: ConnectionRequestWidget(
wallet: _web3Wallet,
sessionProposal: SessionRequestModel(request: args.params),
),
);
// show the bottom sheet
final bool? isApproved = await _bottomSheetHandler.queueBottomSheet(
widget: modalWidget,
) as bool?;
if (isApproved != null && isApproved) {
_web3Wallet.approveSession(
id: args.id,
namespaces: args.params.generatedNamespaces!,
);
} else {
_web3Wallet.rejectSession(
id: args.id,
reason: Errors.getSdkError(
Errors.USER_REJECTED,
),
);
}
}
}
@action
void _onPairingInvalid(PairingInvalidEvent? args) {
log('Pairing Invalid Event: $args');
_bottomSheetHandler.queueBottomSheet(
isModalDismissible: true,
widget: BottomSheetMessageDisplayWidget(message: '${S.current.pairingInvalidEvent}: $args'),
);
}
void _onPairingCreate(PairingEvent? args) {
log('Pairing Create Event: $args');
}
@action
void _onSessionConnect(SessionConnect? args) {
if (args != null) {
sessions.add(args.session);
}
}
@action
Future<void> _onAuthRequest(AuthRequest? args) async {
if (args != null) {
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain('eip155:1');
// Create the message to be signed
final String iss = 'did:pkh:eip155:1:${chainKeys.first.publicKey}';
final Widget modalWidget = Web3RequestModal(
child: ConnectionRequestWidget(
wallet: _web3Wallet,
authRequest: AuthRequestModel(iss: iss, request: args),
),
);
final bool? isAuthenticated = await _bottomSheetHandler.queueBottomSheet(
widget: modalWidget,
) as bool?;
if (isAuthenticated != null && isAuthenticated) {
final String message = _web3Wallet.formatAuthMessage(
iss: iss,
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
args.payloadParams,
),
);
final String sig = EthSigUtil.signPersonalMessage(
message: Uint8List.fromList(message.codeUnits),
privateKey: chainKeys.first.privateKey,
);
await _web3Wallet.respondAuthRequest(
id: args.id,
iss: iss,
signature: CacaoSignature(
t: CacaoSignature.EIP191,
s: sig,
),
);
} else {
await _web3Wallet.respondAuthRequest(
id: args.id,
iss: iss,
error: Errors.getSdkError(
Errors.USER_REJECTED_AUTH,
),
);
}
}
}
@action
Future<void> disconnectSession(String topic) async {
final session = sessions.firstWhere((element) => element.pairingTopic == topic);
await _web3Wallet.core.pairing.disconnect(topic: topic);
await _web3Wallet.disconnectSession(
topic: session.topic, reason: Errors.getSdkError(Errors.USER_DISCONNECTED));
}
@action
List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
}
}

View file

@ -3,10 +3,12 @@ import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart'; import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart'; import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart'; import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart'; import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/core/yat_service.dart'; import 'package:cake_wallet/core/yat_service.dart';
import 'package:cake_wallet/entities/background_tasks.dart'; import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart'; import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/entities/receive_page_option.dart'; import 'package:cake_wallet/entities/receive_page_option.dart';
@ -399,6 +401,10 @@ Future<void> setup({
} }
if (appStore.wallet != null) { if (appStore.wallet != null) {
authStore.allowed(); authStore.allowed();
if (appStore.wallet!.type == WalletType.ethereum) {
getIt.get<Web3WalletService>().init();
}
return; return;
} }
@ -419,6 +425,10 @@ Future<void> setup({
} else { } else {
if (appStore.wallet != null) { if (appStore.wallet != null) {
authStore.allowed(); authStore.allowed();
if (appStore.wallet!.type == WalletType.ethereum) {
getIt.get<Web3WalletService>().init();
}
return; return;
} }
@ -438,11 +448,28 @@ Future<void> setup({
}, closable: false); }, closable: false);
}, instanceName: 'login'); }, instanceName: 'login');
getIt.registerSingleton<BottomSheetService>(BottomSheetServiceImpl());
final appStore = getIt.get<AppStore>();
getIt.registerLazySingleton<WalletConnectKeyService>(() => KeyServiceImpl(appStore.wallet!));
getIt.registerLazySingleton<Web3WalletService>(() {
final Web3WalletService web3WalletService = Web3WalletService(
getIt.get<BottomSheetService>(),
getIt.get<WalletConnectKeyService>(),
appStore,
);
web3WalletService.create();
return web3WalletService;
});
getIt.registerFactory(() => BalancePage( getIt.registerFactory(() => BalancePage(
dashboardViewModel: getIt.get<DashboardViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>(),
settingsStore: getIt.get<SettingsStore>())); settingsStore: getIt.get<SettingsStore>()));
getIt.registerFactory<DashboardPage>(() => DashboardPage( getIt.registerFactory<DashboardPage>(() => DashboardPage(
bottomSheetService: getIt.get<BottomSheetService>(),
balancePage: getIt.get<BalancePage>(), balancePage: getIt.get<BalancePage>(),
dashboardViewModel: getIt.get<DashboardViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>(),
addressListViewModel: getIt.get<WalletAddressListViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>(),
@ -459,6 +486,7 @@ Future<void> setup({
}); });
getIt.registerFactoryParam<DesktopDashboardPage, GlobalKey<NavigatorState>, void>( getIt.registerFactoryParam<DesktopDashboardPage, GlobalKey<NavigatorState>, void>(
(desktopKey, _) => DesktopDashboardPage( (desktopKey, _) => DesktopDashboardPage(
bottomSheetService: getIt.get<BottomSheetService>(),
balancePage: getIt.get<BalancePage>(), balancePage: getIt.get<BalancePage>(),
dashboardViewModel: getIt.get<DashboardViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>(),
addressListViewModel: getIt.get<WalletAddressListViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>(),
@ -668,7 +696,9 @@ Future<void> setup({
return NodeListViewModel(_nodeSource, appStore); return NodeListViewModel(_nodeSource, appStore);
}); });
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>())); getIt.registerFactory(
() => ConnectionSyncPage(getIt.get<DashboardViewModel>(), getIt.get<Web3WalletService>()),
);
getIt.registerFactory( getIt.registerFactory(
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>())); () => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
@ -851,9 +881,8 @@ Future<void> setup({
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>())); getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
getIt.registerFactory(() => getIt.registerFactory(() => SupportChatPage(getIt.get<SupportViewModel>(),
SupportChatPage( secureStorage: getIt.get<FlutterSecureStorage>()));
getIt.get<SupportViewModel>(), secureStorage: getIt.get<FlutterSecureStorage>()));
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>())); getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));

View file

@ -15,8 +15,7 @@ class PreferencesKey {
static const disableSellKey = 'disable_sell'; static const disableSellKey = 'disable_sell';
static const defaultBuyProvider = 'default_buy_provider'; static const defaultBuyProvider = 'default_buy_provider';
static const currentFiatApiModeKey = 'current_fiat_api_mode'; static const currentFiatApiModeKey = 'current_fiat_api_mode';
static const allowBiometricalAuthenticationKey = static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication';
'allow_biometrical_authentication';
static const useTOTP2FA = 'use_totp_2fa'; static const useTOTP2FA = 'use_totp_2fa';
static const failedTotpTokenTrials = 'failed_token_trials'; static const failedTotpTokenTrials = 'failed_token_trials';
static const disableExchangeKey = 'disable_exchange'; static const disableExchangeKey = 'disable_exchange';
@ -54,8 +53,7 @@ class PreferencesKey {
static const clearnetDonationLink = 'clearnet_donation_link'; static const clearnetDonationLink = 'clearnet_donation_link';
static const onionDonationLink = 'onion_donation_link'; static const onionDonationLink = 'onion_donation_link';
static const lastSeenAppVersion = 'last_seen_app_version'; static const lastSeenAppVersion = 'last_seen_app_version';
static const shouldShowMarketPlaceInDashboard = static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard';
'should_show_marketplace_in_dashboard';
static const isNewInstall = 'is_new_install'; static const isNewInstall = 'is_new_install';
static const shouldRequireTOTP2FAForAccessingWallet = static const shouldRequireTOTP2FAForAccessingWallet =
'should_require_totp_2fa_for_accessing_wallets'; 'should_require_totp_2fa_for_accessing_wallets';

View file

@ -33,6 +33,20 @@ class CWEthereum extends Ethereum {
@override @override
String getAddress(WalletBase wallet) => (wallet as EthereumWallet).walletAddresses.address; String getAddress(WalletBase wallet) => (wallet as EthereumWallet).walletAddresses.address;
@override
String getPrivateKey(WalletBase wallet) {
final privateKeyHolder = (wallet as EthereumWallet).ethPrivateKey;
String stringKey = bytesToHex(privateKeyHolder.privateKey);
return stringKey;
}
@override
String getPublicKey(WalletBase wallet) {
final privateKeyInUnitInt = (wallet as EthereumWallet).ethPrivateKey;
final publicKey = privateKeyInUnitInt.address.hex;
return publicKey;
}
@override @override
TransactionPriority getDefaultTransactionPriority() => EthereumTransactionPriority.medium; TransactionPriority getDefaultTransactionPriority() => EthereumTransactionPriority.medium;

View file

@ -39,7 +39,6 @@ import 'package:cake_wallet/src/screens/root/root.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/cake_hive.dart';
final navigatorKey = GlobalKey<NavigatorState>(); final navigatorKey = GlobalKey<NavigatorState>();
@ -316,17 +315,17 @@ class _HomeState extends State<_Home> {
super.didChangeDependencies(); super.didChangeDependencies();
} }
void _setOrientation(BuildContext context) { void _setOrientation(BuildContext context) {
final orientation = MediaQuery.of(context).orientation; final orientation = MediaQuery.of(context).orientation;
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height; final height = MediaQuery.of(context).size.height;
if (orientation == Orientation.portrait && width < height) { if (orientation == Orientation.portrait && width < height) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
} else if (orientation == Orientation.landscape && width > height) { } else if (orientation == Orientation.landscape && width > height) {
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); SystemChrome.setPreferredOrientations(
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
} }
} }
@override @override

View file

@ -1,9 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/main_actions.dart'; import 'package:cake_wallet/entities/main_actions.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart'; import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
@ -35,12 +38,14 @@ import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
class DashboardPage extends StatelessWidget { class DashboardPage extends StatelessWidget {
DashboardPage({ DashboardPage({
required this.bottomSheetService,
required this.balancePage, required this.balancePage,
required this.dashboardViewModel, required this.dashboardViewModel,
required this.addressListViewModel, required this.addressListViewModel,
}); });
final BalancePage balancePage; final BalancePage balancePage;
final BottomSheetService bottomSheetService;
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
final WalletAddressListViewModel addressListViewModel; final WalletAddressListViewModel addressListViewModel;
@ -55,12 +60,14 @@ class DashboardPage extends StatelessWidget {
} else { } else {
return _DashboardPageView( return _DashboardPageView(
balancePage: balancePage, balancePage: balancePage,
bottomSheetService: bottomSheetService,
dashboardViewModel: dashboardViewModel, dashboardViewModel: dashboardViewModel,
addressListViewModel: addressListViewModel, addressListViewModel: addressListViewModel,
); );
} }
} else if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) { } else if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) {
return _DashboardPageView( return _DashboardPageView(
bottomSheetService: bottomSheetService,
balancePage: balancePage, balancePage: balancePage,
dashboardViewModel: dashboardViewModel, dashboardViewModel: dashboardViewModel,
addressListViewModel: addressListViewModel, addressListViewModel: addressListViewModel,
@ -76,6 +83,7 @@ class DashboardPage extends StatelessWidget {
class _DashboardPageView extends BasePage { class _DashboardPageView extends BasePage {
_DashboardPageView({ _DashboardPageView({
required this.bottomSheetService,
required this.balancePage, required this.balancePage,
required this.dashboardViewModel, required this.dashboardViewModel,
required this.addressListViewModel, required this.addressListViewModel,
@ -126,6 +134,7 @@ class _DashboardPageView extends BasePage {
} }
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
final BottomSheetService bottomSheetService;
final WalletAddressListViewModel addressListViewModel; final WalletAddressListViewModel addressListViewModel;
int get initialPage => dashboardViewModel.shouldShowMarketPlaceInDashboard ? 1 : 0; int get initialPage => dashboardViewModel.shouldShowMarketPlaceInDashboard ? 1 : 0;
@ -158,6 +167,8 @@ class _DashboardPageView extends BasePage {
return SafeArea( return SafeArea(
minimum: EdgeInsets.only(bottom: 24), minimum: EdgeInsets.only(bottom: 24),
child: BottomSheetListener(
bottomSheetService: bottomSheetService,
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: <Widget>[ children: <Widget>[
@ -208,8 +219,9 @@ class _DashboardPageView extends BasePage {
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor, color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
width: 1, width: 1,
), ),
color: color: Theme.of(context)
Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor, .extension<SyncIndicatorTheme>()!
.syncedBackgroundColor,
), ),
child: Container( child: Container(
padding: EdgeInsets.only(left: 32, right: 32), padding: EdgeInsets.only(left: 32, right: 32),
@ -255,6 +267,7 @@ class _DashboardPageView extends BasePage {
), ),
], ],
), ),
),
); );
} }

View file

@ -1,8 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'; import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/screens/yat_emoji_id.dart'; import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
@ -19,12 +21,14 @@ import 'package:shared_preferences/shared_preferences.dart';
class DesktopDashboardPage extends StatelessWidget { class DesktopDashboardPage extends StatelessWidget {
DesktopDashboardPage({ DesktopDashboardPage({
required this.balancePage, required this.balancePage,
required this.bottomSheetService,
required this.dashboardViewModel, required this.dashboardViewModel,
required this.addressListViewModel, required this.addressListViewModel,
required this.desktopKey, required this.desktopKey,
}); });
final BalancePage balancePage; final BalancePage balancePage;
final BottomSheetService bottomSheetService;
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
final WalletAddressListViewModel addressListViewModel; final WalletAddressListViewModel addressListViewModel;
final GlobalKey<NavigatorState> desktopKey; final GlobalKey<NavigatorState> desktopKey;
@ -36,7 +40,9 @@ class DesktopDashboardPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
_setEffects(context); _setEffects(context);
return Container( return BottomSheetListener(
bottomSheetService: bottomSheetService,
child: Container(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.background,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -62,6 +68,7 @@ class DesktopDashboardPage extends StatelessWidget {
), ),
], ],
), ),
),
); );
} }

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/totp_request_details.dart'; import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/payment_request.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -97,8 +98,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
return; return;
} }
if (!_isInactive && if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) {
widget.authenticationStore.state == AuthenticationState.allowed) {
setState(() => _setInactive(true)); setState(() => _setInactive(true));
} }
@ -125,16 +125,15 @@ class RootState extends State<Root> with WidgetsBindingObserver {
return; return;
} else { } else {
final useTotp = widget.appStore.settingsStore.useTOTP2FA; final useTotp = widget.appStore.settingsStore.useTOTP2FA;
final shouldUseTotp2FAToAccessWallets = widget.appStore final shouldUseTotp2FAToAccessWallets =
.settingsStore.shouldRequireTOTP2FAForAccessingWallet; widget.appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
if (useTotp && shouldUseTotp2FAToAccessWallets) { if (useTotp && shouldUseTotp2FAToAccessWallets) {
_reset(); _reset();
auth.close( auth.close(
route: Routes.totpAuthCodePage, route: Routes.totpAuthCodePage,
arguments: TotpAuthArgumentsModel( arguments: TotpAuthArgumentsModel(
onTotpAuthenticationFinished: onTotpAuthenticationFinished:
(bool isAuthenticatedSuccessfully, (bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
TotpAuthCodePageState totpAuth) {
if (!isAuthenticatedSuccessfully) { if (!isAuthenticatedSuccessfully) {
return; return;
} }
@ -169,7 +168,10 @@ class RootState extends State<Root> with WidgetsBindingObserver {
launchUri = null; launchUri = null;
} }
return WillPopScope(onWillPop: () async => false, child: widget.child); return WillPopScope(
onWillPop: () async => false,
child: widget.child,
);
} }
void _reset() { void _reset() {

View file

@ -1,12 +1,15 @@
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/wallet_connect_button.dart';
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
@ -15,11 +18,12 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
class ConnectionSyncPage extends BasePage { class ConnectionSyncPage extends BasePage {
ConnectionSyncPage(this.dashboardViewModel); ConnectionSyncPage(this.dashboardViewModel, this.web3walletService);
@override @override
String get title => S.current.connection_sync; String get title => S.current.connection_sync;
final Web3WalletService web3walletService;
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
@override @override
@ -66,6 +70,20 @@ class ConnectionSyncPage extends BasePage {
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes), handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
), ),
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
if (dashboardViewModel.wallet.type == WalletType.ethereum) ...[
WalletConnectTile(
onTap: () async {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return WalletConnectConnectionsView(web3walletService: web3walletService);
},
),
);
},
),
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
]
], ],
), ),
); );

View file

@ -0,0 +1,46 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
import 'package:flutter/material.dart';
class WalletConnectTile extends StatelessWidget {
const WalletConnectTile({required this.onTap});
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Padding(
padding: EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/images/walletconnect_logo.png',
height: 24,
width: 24,
),
SizedBox(width: 16),
Expanded(
child: Text(
S.current.walletConnect,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
),
Image.asset(
'assets/images/select_arrow.png',
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
)
],
),
),
);
}
}

View file

@ -0,0 +1,71 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
class ConnectionWidgetBuilder {
static List<ConnectionWidget> buildFromRequiredNamespaces(
Map<String, RequiredNamespace> requiredNamespaces,
) {
final List<ConnectionWidget> views = [];
for (final key in requiredNamespaces.keys) {
RequiredNamespace ns = requiredNamespaces[key]!;
final List<ConnectionModel> models = [];
// If the chains property is present, add the chain data to the models
if (ns.chains != null) {
models.add(ConnectionModel(title: S.current.chains, elements: ns.chains!));
}
models.add(ConnectionModel(title: S.current.methods, elements: ns.methods));
models.add(ConnectionModel(title: S.current.events, elements: ns.events));
views.add(ConnectionWidget(title: key, info: models));
}
return views;
}
static List<ConnectionWidget> buildFromNamespaces(
String topic,
Map<String, Namespace> namespaces,
Web3Wallet web3wallet,
) {
final List<ConnectionWidget> views = [];
for (final key in namespaces.keys) {
final Namespace ns = namespaces[key]!;
final List<ConnectionModel> models = [];
// If the chains property is present, add the chain data to the models
models.add(
ConnectionModel(
title: S.current.chains,
elements: ns.accounts,
),
);
models.add(ConnectionModel(
title: S.current.methods,
elements: ns.methods,
));
Map<String, void Function()> actions = {};
for (final String event in ns.events) {
actions[event] = () async {
final String chainId = NamespaceUtils.isValidChainId(key)
? key
: NamespaceUtils.getChainFromAccount(ns.accounts.first);
await web3wallet.emitSessionEvent(
topic: topic,
chainId: chainId,
event: SessionEventParams(name: event, data: '${S.current.event}: $event'),
);
};
}
models.add(
ConnectionModel(title: S.current.events, elements: ns.events, elementActions: actions),
);
views.add(ConnectionWidget(title: key, info: models));
}
return views;
}
}

View file

@ -0,0 +1,16 @@
import 'dart:convert';
import 'package:convert/convert.dart';
extension StringParsing on String {
String get utf8Message {
if (startsWith('0x')) {
final List<int> decoded = hex.decode(
substring(2),
);
return utf8.decode(decoded);
}
return this;
}
}

View file

@ -0,0 +1,142 @@
import 'dart:developer';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'widgets/pairing_item_widget.dart';
import 'wc_pairing_detail_page.dart';
class WalletConnectConnectionsView extends StatelessWidget {
final Web3WalletService web3walletService;
WalletConnectConnectionsView({required this.web3walletService, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WCPairingsWidget(web3walletService: web3walletService);
}
}
class WCPairingsWidget extends BasePage {
WCPairingsWidget({required this.web3walletService, Key? key})
: web3wallet = web3walletService.getWeb3Wallet();
final Web3Wallet web3wallet;
final Web3WalletService web3walletService;
@override
String get title => S.current.walletConnect;
Future<void> _onScanQrCode(BuildContext context, Web3Wallet web3Wallet) async {
final String? uri = await presentQRScanner();
if (uri == null) return _invalidUriToast(context, S.current.nullURIError);
try {
log('_onFoundUri: $uri');
final Uri uriData = Uri.parse(uri);
await web3Wallet.pair(uri: uriData);
} on WalletConnectError catch (e) {
await _invalidUriToast(context, e.message);
} catch (e) {
await _invalidUriToast(context, e.toString());
}
}
Future<void> _invalidUriToast(BuildContext context, String message) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: message,
buttonText: S.of(context).ok,
buttonAction: Navigator.of(context).pop,
alertBarrierDismissible: false,
);
},
);
}
@override
Widget body(BuildContext context) {
return Observer(
builder: (context) {
return Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
children: [
SizedBox(height: 24),
Text(
S.current.connectWalletPrompt,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
SizedBox(height: 16),
PrimaryButton(
text: S.current.newConnection,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
onPressed: () => _onScanQrCode(context, web3wallet),
),
],
),
),
SizedBox(height: 48),
Expanded(
child: Visibility(
visible: web3walletService.pairings.isEmpty,
child: Center(
child: Text(
S.current.activeConnectionsPrompt,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
),
replacement: ListView.builder(
itemCount: web3walletService.pairings.length,
itemBuilder: (BuildContext context, int index) {
final pairing = web3walletService.pairings[index];
return PairingItemWidget(
key: ValueKey(pairing.topic),
pairing: pairing,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WalletConnectPairingDetailsPage(
pairing: pairing,
web3walletService: web3walletService,
),
),
);
},
);
},
),
),
),
SizedBox(height: 48),
],
);
},
);
}
}

View file

@ -0,0 +1,186 @@
import 'dart:developer';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'utils/namespace_model_builder.dart';
class WalletConnectPairingDetailsPage extends StatefulWidget {
final PairingInfo pairing;
final Web3WalletService web3walletService;
const WalletConnectPairingDetailsPage({
required this.pairing,
required this.web3walletService,
super.key,
});
@override
WalletConnectPairingDetailsPageState createState() => WalletConnectPairingDetailsPageState();
}
class WalletConnectPairingDetailsPageState extends State<WalletConnectPairingDetailsPage> {
List<Widget> sessionWidgets = [];
late String expiryDate;
@override
void initState() {
super.initState();
initDateTime();
initSessions();
}
void initDateTime() {
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(widget.pairing.expiry * 1000);
int year = dateTime.year;
int month = dateTime.month;
int day = dateTime.day;
expiryDate = '$year-${month.toString().padLeft(2, '0')}-${day.toString().padLeft(2, '0')}';
}
void initSessions() {
List<SessionData> sessions = widget.web3walletService.getSessionsForPairingInfo(widget.pairing);
for (final SessionData session in sessions) {
List<Widget> namespaceWidget = ConnectionWidgetBuilder.buildFromNamespaces(
session.topic,
session.namespaces,
widget.web3walletService.getWeb3Wallet(),
);
// Loop through and add the namespace widgets, but put 20 pixels between each one
for (int i = 0; i < namespaceWidget.length; i++) {
sessionWidgets.add(namespaceWidget[i]);
if (i != namespaceWidget.length - 1) {
sessionWidgets.add(const SizedBox(height: 20.0));
}
}
}
}
@override
Widget build(BuildContext context) {
return WCCDetailsWidget(
widget.pairing,
expiryDate,
sessionWidgets,
widget.web3walletService,
);
}
}
class WCCDetailsWidget extends BasePage {
WCCDetailsWidget(
this.pairing,
this.expiryDate,
this.sessionWidgets,
this.web3walletService,
);
final PairingInfo pairing;
final String expiryDate;
final List<Widget> sessionWidgets;
final Web3WalletService web3walletService;
@override
Widget body(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: CircleAvatar(
backgroundImage: (pairing.peerMetadata!.icons.isNotEmpty
? NetworkImage(pairing.peerMetadata!.icons[0])
: const AssetImage('assets/images/default_icon.png'))
as ImageProvider<Object>,
),
),
const SizedBox(height: 20.0),
Text(
pairing.peerMetadata!.name,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
const SizedBox(height: 16.0),
Text(
pairing.peerMetadata!.url,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
const SizedBox(height: 8.0),
Text(
'${S.current.expiresOn}: $expiryDate',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
const SizedBox(height: 20.0),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: sessionWidgets,
),
const SizedBox(height: 20.0),
PrimaryButton(
onPressed: () =>
_onDeleteButtonPressed(context, pairing.peerMetadata!.name, web3walletService),
text: S.current.delete,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
),
],
),
),
),
);
}
Future<void> _onDeleteButtonPressed(
BuildContext context, String dAppName, Web3WalletService web3walletService) async {
bool confirmed = false;
await showPopUp<void>(
context: context,
builder: (BuildContext dialogContext) {
return AlertWithTwoActions(
alertTitle: S.of(context).delete,
alertContent: '${S.current.deleteConnectionConfirmationPrompt} $dAppName?',
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).delete,
actionLeftButton: () => Navigator.of(dialogContext).pop(),
actionRightButton: () {
confirmed = true;
Navigator.of(dialogContext).pop();
},
);
},
);
if (confirmed) {
try {
await web3walletService.disconnectSession(pairing.topic);
Navigator.of(context).pop();
} catch (e) {
log(e.toString());
}
}
}
}

View file

@ -0,0 +1,102 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
class ConnectionItemWidget extends StatelessWidget {
const ConnectionItemWidget({required this.model, Key? key}) : super(key: key);
final ConnectionModel model;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.all(8),
margin: const EdgeInsetsDirectional.only(top: 8),
child: Visibility(
visible: model.elements != null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
model.title ?? '',
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
if (model.elements != null)
Wrap(
spacing: 4,
runSpacing: 4,
direction: Axis.horizontal,
children: model.elements!
.map((e) => _ModelElementWidget(model: model, modelElement: e))
.toList(),
),
],
),
replacement: _NoModelElementWidget(model: model),
),
);
}
}
class _NoModelElementWidget extends StatelessWidget {
const _NoModelElementWidget({required this.model});
final ConnectionModel model;
@override
Widget build(BuildContext context) {
return Text(
model.text!,
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 14,
fontWeight: FontWeight.w600,
),
);
}
}
class _ModelElementWidget extends StatelessWidget {
const _ModelElementWidget({
required this.model,
required this.modelElement,
});
final ConnectionModel model;
final String modelElement;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: model.elementActions != null ? model.elementActions![modelElement] : null,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.all(8),
child: Text(
modelElement,
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 14,
fontWeight: FontWeight.w600,
),
maxLines: 10,
overflow: TextOverflow.ellipsis,
),
),
);
}
}

View file

@ -0,0 +1,166 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter/material.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import '../../../../core/wallet_connect/models/auth_request_model.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
import '../../../../core/wallet_connect/models/session_request_model.dart';
import '../utils/namespace_model_builder.dart';
import 'connection_widget.dart';
class ConnectionRequestWidget extends StatefulWidget {
const ConnectionRequestWidget({
required this.wallet,
this.authRequest,
this.sessionProposal,
Key? key,
}) : super(key: key);
final Web3Wallet wallet;
final AuthRequestModel? authRequest;
final SessionRequestModel? sessionProposal;
@override
State<ConnectionRequestWidget> createState() => _ConnectionRequestWidgetState();
}
class _ConnectionRequestWidgetState extends State<ConnectionRequestWidget> {
ConnectionMetadata? metadata;
@override
void initState() {
super.initState();
// Get the connection metadata
metadata = widget.authRequest?.request.requester ?? widget.sessionProposal?.request.proposer;
}
@override
Widget build(BuildContext context) {
if (metadata == null) {
return Text(
S.current.error,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
);
}
return _ConnectionMetadataDisplayWidget(
metadata: metadata,
authRequest: widget.authRequest,
sessionProposal: widget.sessionProposal,
wallet: widget.wallet,
);
}
}
class _ConnectionMetadataDisplayWidget extends StatelessWidget {
const _ConnectionMetadataDisplayWidget({
required this.metadata,
required this.wallet,
this.authRequest,
required this.sessionProposal,
});
final ConnectionMetadata? metadata;
final Web3Wallet wallet;
final AuthRequestModel? authRequest;
final SessionRequestModel? sessionProposal;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Color.fromARGB(255, 18, 18, 19),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
metadata!.metadata.name,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
textAlign: TextAlign.center,
),
Text(
S.current.wouoldLikeToConnect,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
metadata!.metadata.url,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Visibility(
visible: authRequest != null,
child: _AuthRequestWidget(wallet: wallet, authRequest: authRequest),
//If authRequest is null, sessionProposal is not null.
replacement: _SessionProposalWidget(sessionProposal: sessionProposal!),
),
],
),
);
}
}
class _AuthRequestWidget extends StatelessWidget {
const _AuthRequestWidget({required this.wallet, this.authRequest});
final Web3Wallet wallet;
final AuthRequestModel? authRequest;
@override
Widget build(BuildContext context) {
final model = ConnectionModel(
text: wallet.formatAuthMessage(
iss: 'did:pkh:eip155:1:${authRequest!.iss}',
cacaoPayload: CacaoRequestPayload.fromPayloadParams(
authRequest!.request.payloadParams,
),
),
);
return ConnectionWidget(
title: S.current.message,
info: [model],
);
}
}
class _SessionProposalWidget extends StatelessWidget {
const _SessionProposalWidget({required this.sessionProposal});
final SessionRequestModel sessionProposal;
@override
Widget build(BuildContext context) {
// Create the connection models using the required and optional namespaces provided by the proposal data
// The key is the title and the list of values is the data
final List<ConnectionWidget> views = ConnectionWidgetBuilder.buildFromRequiredNamespaces(
sessionProposal.request.requiredNamespaces,
);
return Column(children: views);
}
}

View file

@ -0,0 +1,45 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
import '../../../../core/wallet_connect/models/connection_model.dart';
import 'connection_item_widget.dart';
class ConnectionWidget extends StatelessWidget {
const ConnectionWidget({required this.title, required this.info, super.key});
final String title;
final List<ConnectionModel> info;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColorLight,
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
),
const SizedBox(height: 8),
...info.map((e) => ConnectionItemWidget(model: e)),
],
),
);
}
}

View file

@ -0,0 +1,36 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter/material.dart';
class BottomSheetMessageDisplayWidget extends StatelessWidget {
final String message;
final bool isError;
const BottomSheetMessageDisplayWidget({super.key, required this.message, this.isError = true});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
isError ? S.current.error : S.current.successful,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.white,
),
),
SizedBox(height: 8),
Text(
message,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.white,
),
),
],
);
}
}

View file

@ -0,0 +1,62 @@
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:flutter/material.dart';
import '../../../../../core/wallet_connect/models/bottom_sheet_queue_item_model.dart';
class BottomSheetListener extends StatefulWidget {
final BottomSheetService bottomSheetService;
final Widget child;
const BottomSheetListener({
required this.child,
required this.bottomSheetService,
super.key,
});
@override
BottomSheetListenerState createState() => BottomSheetListenerState();
}
class BottomSheetListenerState extends State<BottomSheetListener> {
@override
void initState() {
super.initState();
widget.bottomSheetService.currentSheet.addListener(_showBottomSheet);
}
@override
void dispose() {
widget.bottomSheetService.currentSheet.removeListener(_showBottomSheet);
super.dispose();
}
Future<void> _showBottomSheet() async {
if (widget.bottomSheetService.currentSheet.value != null) {
BottomSheetQueueItemModel item = widget.bottomSheetService.currentSheet.value!;
final value = await showModalBottomSheet(
context: context,
isDismissible: item.isModalDismissible,
backgroundColor: Color.fromARGB(0, 0, 0, 0),
isScrollControlled: true,
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
builder: (context) {
return Container(
decoration: const BoxDecoration(
color: Color.fromARGB(255, 18, 18, 19),
borderRadius: BorderRadius.all(Radius.circular(16)),
),
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.all(16),
child: item.widget,
);
},
);
item.completer.complete(value);
widget.bottomSheetService.resetCurrentSheet();
}
}
@override
Widget build(BuildContext context) => widget.child;
}

View file

@ -0,0 +1,48 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:flutter/material.dart';
class Web3RequestModal extends StatelessWidget {
const Web3RequestModal({required this.child, this.onAccept, this.onReject, super.key});
final Widget child;
final VoidCallback? onAccept;
final VoidCallback? onReject;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
child,
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: PrimaryButton(
onPressed: onReject ?? () => Navigator.of(context).pop(false),
text: S.current.reject,
color: Theme.of(context).colorScheme.error,
textColor: Theme.of(context).colorScheme.onError,
),
),
const SizedBox(width: 16),
Expanded(
child: PrimaryButton(
onPressed: onAccept ?? () => Navigator.of(context).pop(true),
text: S.current.approve,
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
],
),
],
),
);
}
}

View file

@ -0,0 +1,82 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
import 'package:flutter/material.dart';
import 'package:walletconnect_flutter_v2/apis/core/pairing/utils/pairing_models.dart';
class PairingItemWidget extends StatelessWidget {
const PairingItemWidget({required this.pairing, required this.onTap, super.key});
final PairingInfo pairing;
final void Function() onTap;
@override
Widget build(BuildContext context) {
PairingMetadata? metadata = pairing.peerMetadata;
if (metadata == null) {
return SizedBox.shrink();
}
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(pairing.expiry * 1000);
int year = dateTime.year;
int month = dateTime.month;
int day = dateTime.day;
String expiryDate =
'$year-${month.toString().padLeft(2, '0')}-${day.toString().padLeft(2, '0')}';
return ListTile(
leading: CircleAvatar(
backgroundImage: (metadata.icons.isNotEmpty
? NetworkImage(metadata.icons[0])
: const AssetImage(
'assets/images/default_icon.png',
)) as ImageProvider<Object>,
),
title: Text(
metadata.name,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w700,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
metadata.url,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w700,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
Text(
'${S.current.expiresOn}: $expiryDate',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w700,
color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
),
),
],
),
trailing: Container(
height: 40,
width: 44,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsBackgroundColor,
),
child: Icon(
Icons.edit,
size: 14,
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
),
),
onTap: onTap,
);
}
}

View file

@ -595,8 +595,7 @@ abstract class SettingsStoreBase with Store {
SortBalanceBy.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? 0]; SortBalanceBy.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? 0];
final pinNativeTokenAtTop = final pinNativeTokenAtTop =
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true; sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
final useEtherscan = final useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
// If no value // If no value
if (pinLength == null || pinLength == 0) { if (pinLength == null || pinLength == 0) {

View file

@ -77,33 +77,33 @@ abstract class DashboardViewModelBase with Store {
FilterItem( FilterItem(
value: () => tradeFilterStore.displayAllTrades, value: () => tradeFilterStore.displayAllTrades,
caption: S.current.all_trades, caption: S.current.all_trades,
onChanged: () => tradeFilterStore onChanged: () =>
.toggleDisplayExchange(ExchangeProviderDescription.all)), tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.all)),
FilterItem( FilterItem(
value: () => tradeFilterStore.displayChangeNow, value: () => tradeFilterStore.displayChangeNow,
caption: ExchangeProviderDescription.changeNow.title, caption: ExchangeProviderDescription.changeNow.title,
onChanged: () => tradeFilterStore onChanged: () =>
.toggleDisplayExchange(ExchangeProviderDescription.changeNow)), tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
FilterItem( FilterItem(
value: () => tradeFilterStore.displaySideShift, value: () => tradeFilterStore.displaySideShift,
caption: ExchangeProviderDescription.sideShift.title, caption: ExchangeProviderDescription.sideShift.title,
onChanged: () => tradeFilterStore onChanged: () =>
.toggleDisplayExchange(ExchangeProviderDescription.sideShift)), tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.sideShift)),
FilterItem( FilterItem(
value: () => tradeFilterStore.displaySimpleSwap, value: () => tradeFilterStore.displaySimpleSwap,
caption: ExchangeProviderDescription.simpleSwap.title, caption: ExchangeProviderDescription.simpleSwap.title,
onChanged: () => tradeFilterStore onChanged: () =>
.toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)), tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)),
FilterItem( FilterItem(
value: () => tradeFilterStore.displayTrocador, value: () => tradeFilterStore.displayTrocador,
caption: ExchangeProviderDescription.trocador.title, caption: ExchangeProviderDescription.trocador.title,
onChanged: () => tradeFilterStore onChanged: () =>
.toggleDisplayExchange(ExchangeProviderDescription.trocador)), tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.trocador)),
FilterItem( FilterItem(
value: () => tradeFilterStore.displayExolix, value: () => tradeFilterStore.displayExolix,
caption: ExchangeProviderDescription.exolix.title, caption: ExchangeProviderDescription.exolix.title,
onChanged: () => tradeFilterStore onChanged: () =>
.toggleDisplayExchange(ExchangeProviderDescription.exolix)), tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.exolix)),
] ]
}, },
subname = '', subname = '',
@ -125,15 +125,17 @@ abstract class DashboardViewModelBase with Store {
if (_wallet.type == WalletType.monero) { if (_wallet.type == WalletType.monero) {
subname = monero!.getCurrentAccount(_wallet).label; subname = monero!.getCurrentAccount(_wallet).label;
_onMoneroAccountChangeReaction = reaction((_) => monero!.getMoneroWalletDetails(wallet) _onMoneroAccountChangeReaction = reaction(
.account, (Account account) => _onMoneroAccountChange(_wallet)); (_) => monero!.getMoneroWalletDetails(wallet).account,
(Account account) => _onMoneroAccountChange(_wallet));
_onMoneroBalanceChangeReaction = reaction((_) => monero!.getMoneroWalletDetails(wallet).balance, _onMoneroBalanceChangeReaction = reaction(
(_) => monero!.getMoneroWalletDetails(wallet).balance,
(MoneroBalance balance) => _onMoneroTransactionsUpdate(_wallet)); (MoneroBalance balance) => _onMoneroTransactionsUpdate(_wallet));
final _accountTransactions = _wallet final _accountTransactions = _wallet.transactionHistory.transactions.values
.transactionHistory.transactions.values .where((tx) =>
.where((tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id) monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
.toList(); .toList();
transactions = ObservableList.of(_accountTransactions.map((transaction) => transactions = ObservableList.of(_accountTransactions.map((transaction) =>
@ -142,9 +144,8 @@ abstract class DashboardViewModelBase with Store {
balanceViewModel: balanceViewModel, balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore))); settingsStore: appStore.settingsStore)));
} else { } else {
transactions = ObservableList.of(wallet transactions = ObservableList.of(wallet.transactionHistory.transactions.values.map(
.transactionHistory.transactions.values (transaction) => TransactionListItem(
.map((transaction) => TransactionListItem(
transaction: transaction, transaction: transaction,
balanceViewModel: balanceViewModel, balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore))); settingsStore: appStore.settingsStore)));
@ -158,15 +159,15 @@ abstract class DashboardViewModelBase with Store {
(TransactionInfo? transaction) => TransactionListItem( (TransactionInfo? transaction) => TransactionListItem(
transaction: transaction!, transaction: transaction!,
balanceViewModel: balanceViewModel, balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore), settingsStore: appStore.settingsStore), filter: (TransactionInfo? transaction) {
filter: (TransactionInfo? transaction) {
if (transaction == null) { if (transaction == null) {
return false; return false;
} }
final wallet = _wallet; final wallet = _wallet;
if (wallet.type == WalletType.monero) { if (wallet.type == WalletType.monero) {
return monero!.getTransactionInfoAccountId(transaction) == monero!.getCurrentAccount(wallet).id; return monero!.getTransactionInfoAccountId(transaction) ==
monero!.getCurrentAccount(wallet).id;
} }
return true; return true;
@ -216,8 +217,7 @@ abstract class DashboardViewModelBase with Store {
} }
@computed @computed
BalanceDisplayMode get balanceDisplayMode => BalanceDisplayMode get balanceDisplayMode => appStore.settingsStore.balanceDisplayMode;
appStore.settingsStore.balanceDisplayMode;
@computed @computed
bool get shouldShowMarketPlaceInDashboard { bool get shouldShowMarketPlaceInDashboard {
@ -225,14 +225,12 @@ abstract class DashboardViewModelBase with Store {
} }
@computed @computed
List<TradeListItem> get trades => tradesStore.trades List<TradeListItem> get trades =>
.where((trade) => trade.trade.walletId == wallet.id) tradesStore.trades.where((trade) => trade.trade.walletId == wallet.id).toList();
.toList();
@computed @computed
List<OrderListItem> get orders => ordersStore.orders List<OrderListItem> get orders =>
.where((item) => item.order.walletId == wallet.id) ordersStore.orders.where((item) => item.order.walletId == wallet.id).toList();
.toList();
@computed @computed
List<AnonpayTransactionListItem> get anonpayTransactons => anonpayTransactionsStore.transactions List<AnonpayTransactionListItem> get anonpayTransactons => anonpayTransactionsStore.transactions
@ -250,7 +248,8 @@ abstract class DashboardViewModelBase with Store {
List<ActionListItem> get items { List<ActionListItem> get items {
final _items = <ActionListItem>[]; final _items = <ActionListItem>[];
_items.addAll(transactionFilterStore.filtered(transactions: [...transactions, ...anonpayTransactons])); _items.addAll(
transactionFilterStore.filtered(transactions: [...transactions, ...anonpayTransactons]));
_items.addAll(tradeFilterStore.filtered(trades: trades, wallet: wallet)); _items.addAll(tradeFilterStore.filtered(trades: trades, wallet: wallet));
_items.addAll(orders); _items.addAll(orders);
@ -258,8 +257,7 @@ abstract class DashboardViewModelBase with Store {
} }
@observable @observable
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
wallet;
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven; bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
@ -283,7 +281,6 @@ abstract class DashboardViewModelBase with Store {
Map<String, List<FilterItem>> filterItems; Map<String, List<FilterItem>> filterItems;
BuyProviderType get defaultBuyProvider => settingsStore.defaultBuyProvider; BuyProviderType get defaultBuyProvider => settingsStore.defaultBuyProvider;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled; bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
@ -291,8 +288,7 @@ abstract class DashboardViewModelBase with Store {
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup; bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
@action @action
void furtherShowYatPopup(bool shouldShow) => void furtherShowYatPopup(bool shouldShow) => settingsStore.shouldShowYatPopup = shouldShow;
settingsStore.shouldShowYatPopup = shouldShow;
@computed @computed
bool get isEnabledExchangeAction => settingsStore.exchangeStatus != ExchangeApiMode.disabled; bool get isEnabledExchangeAction => settingsStore.exchangeStatus != ExchangeApiMode.disabled;
@ -301,8 +297,7 @@ abstract class DashboardViewModelBase with Store {
bool hasExchangeAction; bool hasExchangeAction;
@computed @computed
bool get isEnabledBuyAction => bool get isEnabledBuyAction => !settingsStore.disableBuy && wallet.type != WalletType.haven;
!settingsStore.disableBuy && wallet.type != WalletType.haven;
@observable @observable
bool hasBuyAction; bool hasBuyAction;
@ -330,9 +325,7 @@ abstract class DashboardViewModelBase with Store {
@action @action
void _onWalletChange( void _onWalletChange(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>? wallet) {
TransactionInfo>?
wallet) {
if (wallet == null) { if (wallet == null) {
return; return;
} }
@ -350,10 +343,12 @@ abstract class DashboardViewModelBase with Store {
_onMoneroAccountChangeReaction?.reaction.dispose(); _onMoneroAccountChangeReaction?.reaction.dispose();
_onMoneroBalanceChangeReaction?.reaction.dispose(); _onMoneroBalanceChangeReaction?.reaction.dispose();
_onMoneroAccountChangeReaction = reaction((_) => monero!.getMoneroWalletDetails(wallet) _onMoneroAccountChangeReaction = reaction(
.account, (Account account) => _onMoneroAccountChange(wallet)); (_) => monero!.getMoneroWalletDetails(wallet).account,
(Account account) => _onMoneroAccountChange(wallet));
_onMoneroBalanceChangeReaction = reaction((_) => monero!.getMoneroWalletDetails(wallet).balance, _onMoneroBalanceChangeReaction = reaction(
(_) => monero!.getMoneroWalletDetails(wallet).balance,
(MoneroBalance balance) => _onMoneroTransactionsUpdate(wallet)); (MoneroBalance balance) => _onMoneroTransactionsUpdate(wallet));
_onMoneroTransactionsUpdate(wallet); _onMoneroTransactionsUpdate(wallet);
@ -364,8 +359,8 @@ abstract class DashboardViewModelBase with Store {
transactions.clear(); transactions.clear();
transactions.addAll(wallet.transactionHistory.transactions.values.map( transactions.addAll(wallet.transactionHistory.transactions.values.map((transaction) =>
(transaction) => TransactionListItem( TransactionListItem(
transaction: transaction, transaction: transaction,
balanceViewModel: balanceViewModel, balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore))); settingsStore: appStore.settingsStore)));
@ -374,12 +369,10 @@ abstract class DashboardViewModelBase with Store {
connectMapToListWithTransform( connectMapToListWithTransform(
appStore.wallet!.transactionHistory.transactions, appStore.wallet!.transactionHistory.transactions,
transactions, transactions,
(TransactionInfo? transaction) (TransactionInfo? transaction) => TransactionListItem(
=> TransactionListItem(
transaction: transaction!, transaction: transaction!,
balanceViewModel: balanceViewModel, balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore), settingsStore: appStore.settingsStore), filter: (TransactionInfo? tx) {
filter: (TransactionInfo? tx) {
if (tx == null) { if (tx == null) {
return false; return false;
} }
@ -402,12 +395,15 @@ abstract class DashboardViewModelBase with Store {
void _onMoneroTransactionsUpdate(WalletBase wallet) { void _onMoneroTransactionsUpdate(WalletBase wallet) {
transactions.clear(); transactions.clear();
final _accountTransactions = monero!.getTransactionHistory(wallet).transactions.values final _accountTransactions = monero!
.where((tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id) .getTransactionHistory(wallet)
.transactions
.values
.where(
(tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
.toList(); .toList();
transactions.addAll(_accountTransactions.map((transaction) => transactions.addAll(_accountTransactions.map((transaction) => TransactionListItem(
TransactionListItem(
transaction: transaction, transaction: transaction,
balanceViewModel: balanceViewModel, balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore))); settingsStore: appStore.settingsStore)));

View file

@ -417,7 +417,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
String translateErrorMessage(String error, WalletType walletType, CryptoCurrency currency,) { String translateErrorMessage(String error, WalletType walletType, CryptoCurrency currency,) {
if (walletType == WalletType.ethereum || walletType == WalletType.haven) { if (walletType == WalletType.ethereum || walletType == WalletType.haven) {
if (error.contains('gas required exceeds allowance (0)') || error.contains('insufficient funds for gas')) { if (error.contains('gas required exceeds allowance') || error.contains('insufficient funds for gas')) {
return S.current.do_not_have_enough_gas_asset(currency.toString()); return S.current.do_not_have_enough_gas_asset(currency.toString());
} }
} }

View file

@ -82,6 +82,8 @@ dependencies:
shared_preferences_android: 2.0.17 shared_preferences_android: 2.0.17
url_launcher_android: 6.0.24 url_launcher_android: 6.0.24
sensitive_clipboard: ^1.0.0 sensitive_clipboard: ^1.0.0
walletconnect_flutter_v2: ^2.1.4
eth_sig_util: ^0.0.9
bitcoin_flutter: bitcoin_flutter:
git: git:
url: https://github.com/cake-tech/bitcoin_flutter.git url: https://github.com/cake-tech/bitcoin_flutter.git

View file

@ -689,8 +689,27 @@
"default_buy_provider": "مزود شراء الافتراضي", "default_buy_provider": "مزود شراء الافتراضي",
"ask_each_time": "اسأل في كل مرة", "ask_each_time": "اسأل في كل مرة",
"buy_provider_unavailable": "مزود حاليا غير متوفر.", "buy_provider_unavailable": "مزود حاليا غير متوفر.",
"signTransaction": " ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ",
"errorGettingCredentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻰﻠﻋ ﻝﻮﺼﺤﻟﺍ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ :ﻞﺸﻓ",
"errorSigningTransaction": "ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ",
"pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ",
"chains": "ﻞﺳﻼﺴﻟﺍ",
"methods": " ﻕﺮﻃُ",
"events": "ﺙﺍﺪﺣﻷﺍ",
"reject": "ﺾﻓﺮﻳ",
"approve": "ﺪﻤﺘﻌﻳ",
"expiresOn": "ﻲﻓ ﻪﺘﻴﺣﻼﺻ ﻲﻬﺘﻨﺗ",
"walletConnect": "WalletConnect",
"nullURIError": "ﻍﺭﺎﻓ (URI) ﻢﻈﺘﻨﻤﻟﺍ ﺩﺭﺍﻮﻤﻟﺍ ﻑﺮﻌﻣ",
"connectWalletPrompt": "ﺕﻼﻣﺎﻌﻤﻟﺍ ءﺍﺮﺟﻹ WalletConnect ﻊﻣ ﻚﺘﻈﻔﺤﻣ ﻞﻴﺻﻮﺘﺑ ﻢﻗ",
"newConnection": "ﺪﻳﺪﺟ ﻝﺎﺼﺗﺍ",
"activeConnectionsPrompt": "ﺎﻨﻫ ﺔﻄﺸﻨﻟﺍ ﺕﻻﺎﺼﺗﻻﺍ ﺮﻬﻈﺘﺳ",
"deleteConnectionConfirmationPrompt": "ـﺑ ﻝﺎﺼﺗﻻﺍ ﻑﺬﺣ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ",
"event": "ﺙﺪﺣ",
"successful": "ﺢﺟﺎﻧ",
"wouoldLikeToConnect": "ﻝﺎﺼﺗﻻﺍ ﻲﻓ ﺐﻏﺮﺗ",
"message": "ﺔﻟﺎﺳﺭ",
"do_not_have_enough_gas_asset": "ليس لديك ما يكفي من ${currency} لإجراء معاملة وفقًا لشروط شبكة blockchain الحالية. أنت بحاجة إلى المزيد من ${currency} لدفع رسوم شبكة blockchain، حتى لو كنت ترسل أصلًا مختلفًا.", "do_not_have_enough_gas_asset": "ليس لديك ما يكفي من ${currency} لإجراء معاملة وفقًا لشروط شبكة blockchain الحالية. أنت بحاجة إلى المزيد من ${currency} لدفع رسوم شبكة blockchain، حتى لو كنت ترسل أصلًا مختلفًا.",
"totp_auth_url": " TOTP ﺔﻗﺩﺎﺼﻤﻟ URL ﻥﺍﻮﻨﻋ" "totp_auth_url": "TOTP ﺔﻗﺩﺎﺼﻤﻟ URL ﻥﺍﻮﻨﻋ",
"awaitDAppProcessing": ".ﺔﺠﻟﺎﻌﻤﻟﺍ ﻦﻣ dApp ﻲﻬﺘﻨﻳ ﻰﺘﺣ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ"
} }

View file

@ -685,6 +685,27 @@
"default_buy_provider": "Доставчик по подразбиране купува", "default_buy_provider": "Доставчик по подразбиране купува",
"ask_each_time": "Питайте всеки път", "ask_each_time": "Питайте всеки път",
"buy_provider_unavailable": "Понастоящем доставчик не е наличен.", "buy_provider_unavailable": "Понастоящем доставчик не е наличен.",
"signTransaction": "Подпишете транзакция",
"errorGettingCredentials": "Неуспешно: Грешка при получаване на идентификационни данни",
"errorSigningTransaction": "Възникна грешка при подписване на транзакция",
"pairingInvalidEvent": "Невалидно събитие при сдвояване",
"chains": "Вериги",
"methods": "Методи",
"events": "събития",
"reject": "Отхвърляне",
"approve": "Одобряване",
"expiresOn": "Изтича на",
"walletConnect": "WalletConnect",
"nullURIError": "URI е нула",
"connectWalletPrompt": "Свържете портфейла си с WalletConnect, за да извършвате транзакции",
"newConnection": "Нова връзка",
"activeConnectionsPrompt": "Тук ще се появят активни връзки",
"deleteConnectionConfirmationPrompt": "Сигурни ли сте, че искате да изтриете връзката към",
"event": "Събитие",
"successful": "Успешен",
"wouoldLikeToConnect": "иска да се свърже",
"message": "Съобщение",
"do_not_have_enough_gas_asset": "Нямате достатъчно ${currency}, за да извършите транзакция с текущите условия на блокчейн мрежата. Имате нужда от повече ${currency}, за да платите таксите за блокчейн мрежа, дори ако изпращате различен актив.", "do_not_have_enough_gas_asset": "Нямате достатъчно ${currency}, за да извършите транзакция с текущите условия на блокчейн мрежата. Имате нужда от повече ${currency}, за да платите таксите за блокчейн мрежа, дори ако изпращате различен актив.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Моля, изчакайте dApp да завърши обработката."
} }

View file

@ -685,6 +685,27 @@
"default_buy_provider": "Výchozí poskytovatel nákupu", "default_buy_provider": "Výchozí poskytovatel nákupu",
"ask_each_time": "Zeptejte se pokaždé", "ask_each_time": "Zeptejte se pokaždé",
"buy_provider_unavailable": "Poskytovatel aktuálně nedostupný.", "buy_provider_unavailable": "Poskytovatel aktuálně nedostupný.",
"signTransaction": "Podepsat transakci",
"errorGettingCredentials": "Selhalo: Chyba při získávání přihlašovacích údajů",
"errorSigningTransaction": "Při podepisování transakce došlo k chybě",
"pairingInvalidEvent": "Neplatná událost párování",
"chains": "Řetězy",
"methods": "Metody",
"events": "Události",
"reject": "Odmítnout",
"approve": "Schvalovat",
"expiresOn": "Vyprší dne",
"walletConnect": "WalletConnect",
"nullURIError": "URI je nulové",
"connectWalletPrompt": "Propojte svou peněženku s WalletConnect a provádějte transakce",
"newConnection": "Nové připojení",
"activeConnectionsPrompt": "Zde se zobrazí aktivní připojení",
"deleteConnectionConfirmationPrompt": "Jste si jisti, že chcete smazat připojení k?",
"event": "událost",
"successful": "Úspěšný",
"wouoldLikeToConnect": "by se chtělo připojit",
"message": "Zpráva",
"do_not_have_enough_gas_asset": "Nemáte dostatek ${currency} k provedení transakce s aktuálními podmínkami blockchainové sítě. K placení poplatků za blockchainovou síť potřebujete více ${currency}, i když posíláte jiné aktivum.", "do_not_have_enough_gas_asset": "Nemáte dostatek ${currency} k provedení transakce s aktuálními podmínkami blockchainové sítě. K placení poplatků za blockchainovou síť potřebujete více ${currency}, i když posíláte jiné aktivum.",
"totp_auth_url": "URL AUTH TOTP" "totp_auth_url": "URL AUTH TOTP",
"awaitDAppProcessing": "Počkejte, až dApp dokončí zpracování."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Standard-Kaufanbieter", "default_buy_provider": "Standard-Kaufanbieter",
"ask_each_time": "Jedes Mal fragen", "ask_each_time": "Jedes Mal fragen",
"buy_provider_unavailable": "Anbieter derzeit nicht verfügbar.", "buy_provider_unavailable": "Anbieter derzeit nicht verfügbar.",
"signTransaction": "Transaktion unterzeichnen",
"errorGettingCredentials": "Fehlgeschlagen: Fehler beim Abrufen der Anmeldeinformationen",
"errorSigningTransaction": "Beim Signieren der Transaktion ist ein Fehler aufgetreten",
"pairingInvalidEvent": "Paarung ungültiges Ereignis",
"chains": "Ketten",
"methods": "Methoden",
"events": "Veranstaltungen",
"reject": "Ablehnen",
"approve": "Genehmigen",
"expiresOn": "Läuft aus am",
"walletConnect": "WalletConnect",
"nullURIError": "URI ist null",
"connectWalletPrompt": "Verbinden Sie Ihr Wallet mit WalletConnect, um Transaktionen durchzuführen",
"newConnection": "Neue Verbindung",
"activeConnectionsPrompt": "Hier werden aktive Verbindungen angezeigt",
"deleteConnectionConfirmationPrompt": "Sind Sie sicher, dass Sie die Verbindung zu löschen möchten?",
"event": "Ereignis",
"successful": "Erfolgreich",
"wouoldLikeToConnect": "möchte mich gerne vernetzen",
"message": "Nachricht",
"do_not_have_enough_gas_asset": "Sie verfügen nicht über genügend ${currency}, um eine Transaktion unter den aktuellen Bedingungen des Blockchain-Netzwerks durchzuführen. Sie benötigen mehr ${currency}, um die Gebühren für das Blockchain-Netzwerk zu bezahlen, auch wenn Sie einen anderen Vermögenswert senden.", "do_not_have_enough_gas_asset": "Sie verfügen nicht über genügend ${currency}, um eine Transaktion unter den aktuellen Bedingungen des Blockchain-Netzwerks durchzuführen. Sie benötigen mehr ${currency}, um die Gebühren für das Blockchain-Netzwerk zu bezahlen, auch wenn Sie einen anderen Vermögenswert senden.",
"totp_auth_url": "TOTP-Auth-URL" "totp_auth_url": "TOTP-Auth-URL",
"awaitDAppProcessing": "Bitte warten Sie, bis die dApp die Verarbeitung abgeschlossen hat."
} }

View file

@ -694,6 +694,27 @@
"ask_each_time": "Ask each time", "ask_each_time": "Ask each time",
"robinhood_option_description": "Buy and transfer instantly using your debit card, bank account, or Robinhood balance. USA only.", "robinhood_option_description": "Buy and transfer instantly using your debit card, bank account, or Robinhood balance. USA only.",
"buy_provider_unavailable": "Provider currently unavailable.", "buy_provider_unavailable": "Provider currently unavailable.",
"signTransaction": "Sign Transaction",
"errorGettingCredentials": "Failed: Error while getting credentials",
"errorSigningTransaction": "An error has occured while signing transaction",
"pairingInvalidEvent": "Pairing Invalid Event",
"chains": "Chains",
"methods": "Methods",
"events": "Events",
"reject": "Reject",
"approve": "Approve",
"expiresOn": "Expires on",
"walletConnect": "WalletConnect",
"nullURIError": "URI is null",
"connectWalletPrompt": "Connect your wallet with WalletConnect to make transactions",
"newConnection": "New Connection",
"activeConnectionsPrompt": "Active connections will appear here",
"deleteConnectionConfirmationPrompt": "Are you sure that you want to delete the connection to",
"event": "Event",
"successful": "Successful",
"wouoldLikeToConnect": "would like to connect",
"message": "Message",
"do_not_have_enough_gas_asset": "You do not have enough ${currency} to make a transaction with the current blockchain network conditions. You need more ${currency} to pay blockchain network fees, even if you are sending a different asset.", "do_not_have_enough_gas_asset": "You do not have enough ${currency} to make a transaction with the current blockchain network conditions. You need more ${currency} to pay blockchain network fees, even if you are sending a different asset.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Kindly wait for the dApp to finish processing."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Proveedor de compra predeterminado", "default_buy_provider": "Proveedor de compra predeterminado",
"ask_each_time": "Pregunta cada vez", "ask_each_time": "Pregunta cada vez",
"buy_provider_unavailable": "Proveedor actualmente no disponible.", "buy_provider_unavailable": "Proveedor actualmente no disponible.",
"signTransaction": "Firmar transacción",
"errorGettingCredentials": "Error: error al obtener las credenciales",
"errorSigningTransaction": "Se ha producido un error al firmar la transacción.",
"pairingInvalidEvent": "Evento de emparejamiento no válido",
"chains": "Cadenas",
"methods": "Métodos",
"events": "Eventos",
"reject": "Rechazar",
"approve": "Aprobar",
"expiresOn": "Expira el",
"walletConnect": "MonederoConectar",
"nullURIError": "URI es nula",
"connectWalletPrompt": "Conecte su billetera con WalletConnect para realizar transacciones",
"newConnection": "Nueva conexión",
"activeConnectionsPrompt": "Las conexiones activas aparecerán aquí",
"deleteConnectionConfirmationPrompt": "¿Está seguro de que desea eliminar la conexión a",
"event": "Evento",
"successful": "Exitoso",
"wouoldLikeToConnect": "quisiera conectar",
"message": "Mensaje",
"do_not_have_enough_gas_asset": "No tienes suficiente ${currency} para realizar una transacción con las condiciones actuales de la red blockchain. Necesita más ${currency} para pagar las tarifas de la red blockchain, incluso si envía un activo diferente.", "do_not_have_enough_gas_asset": "No tienes suficiente ${currency} para realizar una transacción con las condiciones actuales de la red blockchain. Necesita más ${currency} para pagar las tarifas de la red blockchain, incluso si envía un activo diferente.",
"totp_auth_url": "URL de autenticación TOTP" "totp_auth_url": "URL de autenticación TOTP",
"awaitDAppProcessing": "Espere a que la dApp termine de procesarse."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Fournisseur d'achat par défaut", "default_buy_provider": "Fournisseur d'achat par défaut",
"ask_each_time": "Demandez à chaque fois", "ask_each_time": "Demandez à chaque fois",
"buy_provider_unavailable": "Fournisseur actuellement indisponible.", "buy_provider_unavailable": "Fournisseur actuellement indisponible.",
"signTransaction": "Signer une transaction",
"errorGettingCredentials": "Échec : erreur lors de l'obtention des informations d'identification",
"errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction",
"pairingInvalidEvent": "Événement de couplage non valide",
"chains": "Chaînes",
"methods": "Méthodes",
"events": "Événements",
"reject": "Rejeter",
"approve": "Approuver",
"expiresOn": "Expire le",
"walletConnect": "PortefeuilleConnect",
"nullURIError": "L'URI est nul",
"connectWalletPrompt": "Connectez votre portefeuille avec WalletConnect pour effectuer des transactions",
"newConnection": "Nouvelle connexion",
"activeConnectionsPrompt": "Les connexions actives apparaîtront ici",
"deleteConnectionConfirmationPrompt": "Êtes-vous sûr de vouloir supprimer la connexion à",
"event": "Événement",
"successful": "Réussi",
"wouoldLikeToConnect": "je voudrais me connecter",
"message": "Message",
"do_not_have_enough_gas_asset": "Vous n'avez pas assez de ${currency} pour effectuer une transaction avec les conditions actuelles du réseau blockchain. Vous avez besoin de plus de ${currency} pour payer les frais du réseau blockchain, même si vous envoyez un actif différent.", "do_not_have_enough_gas_asset": "Vous n'avez pas assez de ${currency} pour effectuer une transaction avec les conditions actuelles du réseau blockchain. Vous avez besoin de plus de ${currency} pour payer les frais du réseau blockchain, même si vous envoyez un actif différent.",
"totp_auth_url": "URL D'AUTORISATION TOTP" "totp_auth_url": "URL D'AUTORISATION TOTP",
"awaitDAppProcessing": "Veuillez attendre que le dApp termine le traitement."
} }

View file

@ -671,6 +671,27 @@
"default_buy_provider": "Tsohuwar Siyarwa", "default_buy_provider": "Tsohuwar Siyarwa",
"ask_each_time": "Tambaya kowane lokaci", "ask_each_time": "Tambaya kowane lokaci",
"buy_provider_unavailable": "Mai ba da kyauta a halin yanzu babu.", "buy_provider_unavailable": "Mai ba da kyauta a halin yanzu babu.",
"signTransaction": "Sa hannu Ma'amala",
"errorGettingCredentials": "Ba a yi nasara ba: Kuskure yayin samun takaddun shaida",
"errorSigningTransaction": "An sami kuskure yayin sanya hannu kan ciniki",
"pairingInvalidEvent": "Haɗa Lamarin mara inganci",
"chains": "Sarkoki",
"methods": "Hanyoyin",
"events": "Abubuwan da suka faru",
"reject": "Ƙi",
"approve": "Amincewa",
"expiresOn": "Yana ƙarewa",
"walletConnect": "WalletConnect",
"nullURIError": "URI banza ne",
"connectWalletPrompt": "Haɗa walat ɗin ku tare da WalletConnect don yin ma'amala",
"newConnection": "Sabuwar Haɗi",
"activeConnectionsPrompt": "Haɗin kai mai aiki zai bayyana a nan",
"deleteConnectionConfirmationPrompt": "Shin kun tabbata cewa kuna son share haɗin zuwa",
"event": "Lamarin",
"successful": "Nasara",
"wouoldLikeToConnect": "ina son haɗi",
"message": "Sako",
"do_not_have_enough_gas_asset": "Ba ku da isassun ${currency} don yin ma'amala tare da yanayin cibiyar sadarwar blockchain na yanzu. Kuna buƙatar ƙarin ${currency} don biyan kuɗaɗen cibiyar sadarwar blockchain, koda kuwa kuna aika wata kadara daban.", "do_not_have_enough_gas_asset": "Ba ku da isassun ${currency} don yin ma'amala tare da yanayin cibiyar sadarwar blockchain na yanzu. Kuna buƙatar ƙarin ${currency} don biyan kuɗaɗen cibiyar sadarwar blockchain, koda kuwa kuna aika wata kadara daban.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Da fatan za a jira dApp ya gama aiki."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "डिफ़ॉल्ट खरीद प्रदाता", "default_buy_provider": "डिफ़ॉल्ट खरीद प्रदाता",
"ask_each_time": "हर बार पूछें", "ask_each_time": "हर बार पूछें",
"buy_provider_unavailable": "वर्तमान में प्रदाता अनुपलब्ध है।", "buy_provider_unavailable": "वर्तमान में प्रदाता अनुपलब्ध है।",
"signTransaction": "लेन-देन पर हस्ताक्षर करें",
"errorGettingCredentials": "विफल: क्रेडेंशियल प्राप्त करते समय त्रुटि",
"errorSigningTransaction": "लेन-देन पर हस्ताक्षर करते समय एक त्रुटि उत्पन्न हुई है",
"pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना",
"chains": "चेन",
"methods": "तरीकों",
"events": "आयोजन",
"reject": "अस्वीकार करना",
"approve": "मंज़ूरी देना",
"expiresOn": "पर समय सीमा समाप्त",
"walletConnect": "वॉलेटकनेक्ट",
"nullURIError": "यूआरआई शून्य है",
"connectWalletPrompt": "लेन-देन करने के लिए अपने वॉलेट को वॉलेटकनेक्ट से कनेक्ट करें",
"newConnection": "नया कनेक्शन",
"activeConnectionsPrompt": "सक्रिय कनेक्शन यहां दिखाई देंगे",
"deleteConnectionConfirmationPrompt": "क्या आप वाकई कनेक्शन हटाना चाहते हैं?",
"event": "आयोजन",
"successful": "सफल",
"wouoldLikeToConnect": "जुड़ना चाहेंगे",
"message": "संदेश",
"do_not_have_enough_gas_asset": "वर्तमान ब्लॉकचेन नेटवर्क स्थितियों में लेनदेन करने के लिए आपके पास पर्याप्त ${currency} नहीं है। ब्लॉकचेन नेटवर्क शुल्क का भुगतान करने के लिए आपको अधिक ${currency} की आवश्यकता है, भले ही आप एक अलग संपत्ति भेज रहे हों।", "do_not_have_enough_gas_asset": "वर्तमान ब्लॉकचेन नेटवर्क स्थितियों में लेनदेन करने के लिए आपके पास पर्याप्त ${currency} नहीं है। ब्लॉकचेन नेटवर्क शुल्क का भुगतान करने के लिए आपको अधिक ${currency} की आवश्यकता है, भले ही आप एक अलग संपत्ति भेज रहे हों।",
"totp_auth_url": "TOTP प्रामाणिक यूआरएल" "totp_auth_url": "TOTP प्रामाणिक यूआरएल",
"awaitDAppProcessing": "कृपया डीएपी की प्रोसेसिंग पूरी होने तक प्रतीक्षा करें।"
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Zadani davatelj kupnje", "default_buy_provider": "Zadani davatelj kupnje",
"ask_each_time": "Pitajte svaki put", "ask_each_time": "Pitajte svaki put",
"buy_provider_unavailable": "Davatelj trenutno nije dostupan.", "buy_provider_unavailable": "Davatelj trenutno nije dostupan.",
"signTransaction": "Potpišite transakciju",
"errorGettingCredentials": "Neuspješno: Pogreška prilikom dobivanja vjerodajnica",
"errorSigningTransaction": "Došlo je do pogreške prilikom potpisivanja transakcije",
"pairingInvalidEvent": "Nevažeći događaj uparivanja",
"chains": "Lanci",
"methods": "Metode",
"events": "Događaji",
"reject": "Odbiti",
"approve": "Odobriti",
"expiresOn": "Istječe",
"walletConnect": "WalletConnect",
"nullURIError": "URI je nula",
"connectWalletPrompt": "Povežite svoj novčanik s WalletConnectom za obavljanje transakcija",
"newConnection": "Nova veza",
"activeConnectionsPrompt": "Ovdje će se pojaviti aktivne veze",
"deleteConnectionConfirmationPrompt": "Jeste li sigurni da želite izbrisati vezu s",
"event": "Događaj",
"successful": "Uspješno",
"wouoldLikeToConnect": "želio bi se povezati",
"message": "Poruka",
"do_not_have_enough_gas_asset": "Nemate dovoljno ${currency} da izvršite transakciju s trenutačnim uvjetima blockchain mreže. Trebate više ${currency} da platite naknade za blockchain mrežu, čak i ako šaljete drugu imovinu.", "do_not_have_enough_gas_asset": "Nemate dovoljno ${currency} da izvršite transakciju s trenutačnim uvjetima blockchain mreže. Trebate više ${currency} da platite naknade za blockchain mrežu, čak i ako šaljete drugu imovinu.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Molimo pričekajte da dApp završi obradu."
} }

View file

@ -681,6 +681,27 @@
"default_buy_provider": "Penyedia beli default", "default_buy_provider": "Penyedia beli default",
"ask_each_time": "Tanyakan setiap kali", "ask_each_time": "Tanyakan setiap kali",
"buy_provider_unavailable": "Penyedia saat ini tidak tersedia.", "buy_provider_unavailable": "Penyedia saat ini tidak tersedia.",
"signTransaction": "Tandatangani Transaksi",
"errorGettingCredentials": "Gagal: Terjadi kesalahan saat mendapatkan kredensial",
"errorSigningTransaction": "Terjadi kesalahan saat menandatangani transaksi",
"pairingInvalidEvent": "Menyandingkan Acara Tidak Valid",
"chains": "Rantai",
"methods": "Metode",
"events": "Acara",
"reject": "Menolak",
"approve": "Menyetujui",
"expiresOn": "Kadaluarsa pada",
"walletConnect": "DompetConnect",
"nullURIError": "URI adalah nol",
"connectWalletPrompt": "Hubungkan dompet Anda dengan WalletConnect untuk melakukan transaksi",
"newConnection": "Koneksi Baru",
"activeConnectionsPrompt": "Koneksi aktif akan muncul di sini",
"deleteConnectionConfirmationPrompt": "Apakah Anda yakin ingin menghapus koneksi ke",
"event": "Peristiwa",
"successful": "Berhasil",
"wouoldLikeToConnect": "ingin terhubung",
"message": "Pesan",
"do_not_have_enough_gas_asset": "Anda tidak memiliki cukup ${currency} untuk melakukan transaksi dengan kondisi jaringan blockchain saat ini. Anda memerlukan lebih banyak ${currency} untuk membayar biaya jaringan blockchain, meskipun Anda mengirimkan aset yang berbeda.", "do_not_have_enough_gas_asset": "Anda tidak memiliki cukup ${currency} untuk melakukan transaksi dengan kondisi jaringan blockchain saat ini. Anda memerlukan lebih banyak ${currency} untuk membayar biaya jaringan blockchain, meskipun Anda mengirimkan aset yang berbeda.",
"totp_auth_url": "URL Otentikasi TOTP" "totp_auth_url": "URL Otentikasi TOTP",
"awaitDAppProcessing": "Mohon tunggu hingga dApp menyelesaikan pemrosesan."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Provider di acquisto predefinito", "default_buy_provider": "Provider di acquisto predefinito",
"ask_each_time": "Chiedi ogni volta", "ask_each_time": "Chiedi ogni volta",
"buy_provider_unavailable": "Provider attualmente non disponibile.", "buy_provider_unavailable": "Provider attualmente non disponibile.",
"signTransaction": "Firma la transazione",
"errorGettingCredentials": "Non riuscito: errore durante il recupero delle credenziali",
"errorSigningTransaction": "Si è verificato un errore durante la firma della transazione",
"pairingInvalidEvent": "Associazione evento non valido",
"chains": "Catene",
"methods": "Metodi",
"events": "Eventi",
"reject": "Rifiutare",
"approve": "Approvare",
"expiresOn": "Scade il",
"walletConnect": "PortafoglioConnetti",
"nullURIError": "L'URI è nullo",
"connectWalletPrompt": "Collega il tuo portafoglio con WalletConnect per effettuare transazioni",
"newConnection": "Nuova connessione",
"activeConnectionsPrompt": "Le connessioni attive verranno visualizzate qui",
"deleteConnectionConfirmationPrompt": "Sei sicuro di voler eliminare la connessione a",
"event": "Evento",
"successful": "Riuscito",
"wouoldLikeToConnect": "vorrei connettermi",
"message": "Messaggio",
"do_not_have_enough_gas_asset": "Non hai abbastanza ${currency} per effettuare una transazione con le attuali condizioni della rete blockchain. Hai bisogno di più ${currency} per pagare le commissioni della rete blockchain, anche se stai inviando una risorsa diversa.", "do_not_have_enough_gas_asset": "Non hai abbastanza ${currency} per effettuare una transazione con le attuali condizioni della rete blockchain. Hai bisogno di più ${currency} per pagare le commissioni della rete blockchain, anche se stai inviando una risorsa diversa.",
"totp_auth_url": "URL DI AUT. TOTP" "totp_auth_url": "URL DI AUT. TOTP",
"awaitDAppProcessing": "Attendi gentilmente che la dApp termini l'elaborazione."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "デフォルトの購入プロバイダー", "default_buy_provider": "デフォルトの購入プロバイダー",
"ask_each_time": "毎回尋ねてください", "ask_each_time": "毎回尋ねてください",
"buy_provider_unavailable": "現在、プロバイダーは利用できません。", "buy_provider_unavailable": "現在、プロバイダーは利用できません。",
"signTransaction": "トランザクションに署名する",
"errorGettingCredentials": "失敗: 認証情報の取得中にエラーが発生しました",
"errorSigningTransaction": "トランザクションの署名中にエラーが発生しました",
"pairingInvalidEvent": "ペアリング無効イベント",
"chains": "チェーン",
"methods": "メソッド",
"events": "イベント",
"reject": "拒否する",
"approve": "承認する",
"expiresOn": "有効期限は次のとおりです",
"walletConnect": "ウォレットコネクト",
"nullURIError": "URIがnullです",
"connectWalletPrompt": "ウォレットを WalletConnect に接続して取引を行う",
"newConnection": "新しい接続",
"activeConnectionsPrompt": "アクティブな接続がここに表示されます",
"deleteConnectionConfirmationPrompt": "への接続を削除してもよろしいですか?",
"event": "イベント",
"successful": "成功",
"wouoldLikeToConnect": "接続したいです",
"message": "メッセージ",
"do_not_have_enough_gas_asset": "現在のブロックチェーン ネットワークの状況では、トランザクションを行うのに十分な ${currency} がありません。別のアセットを送信する場合でも、ブロックチェーン ネットワーク料金を支払うにはさらに ${currency} が必要です。", "do_not_have_enough_gas_asset": "現在のブロックチェーン ネットワークの状況では、トランザクションを行うのに十分な ${currency} がありません。別のアセットを送信する場合でも、ブロックチェーン ネットワーク料金を支払うにはさらに ${currency} が必要です。",
"totp_auth_url": "TOTP認証URL" "totp_auth_url": "TOTP認証URL",
"awaitDAppProcessing": "dAppの処理が完了するまでお待ちください。"
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "기본 구매 제공자", "default_buy_provider": "기본 구매 제공자",
"ask_each_time": "매번 물어보십시오", "ask_each_time": "매번 물어보십시오",
"buy_provider_unavailable": "제공자는 현재 사용할 수 없습니다.", "buy_provider_unavailable": "제공자는 현재 사용할 수 없습니다.",
"signTransaction": "거래 서명",
"errorGettingCredentials": "실패: 자격 증명을 가져오는 중 오류가 발생했습니다.",
"errorSigningTransaction": "거래에 서명하는 동안 오류가 발생했습니다.",
"pairingInvalidEvent": "잘못된 이벤트 페어링",
"chains": "쇠사슬",
"methods": "행동 양식",
"events": "이벤트",
"reject": "거부하다",
"approve": "승인하다",
"expiresOn": "만료 날짜",
"walletConnect": "월렛커넥트",
"nullURIError": "URI가 null입니다.",
"connectWalletPrompt": "거래를 하려면 WalletConnect에 지갑을 연결하세요.",
"newConnection": "새로운 연결",
"activeConnectionsPrompt": "활성 연결이 여기에 표시됩니다",
"deleteConnectionConfirmationPrompt": "다음 연결을 삭제하시겠습니까?",
"event": "이벤트",
"successful": "성공적인",
"wouoldLikeToConnect": "연결하고 싶습니다",
"message": "메시지",
"do_not_have_enough_gas_asset": "현재 블록체인 네트워크 조건으로 거래를 하기에는 ${currency}이(가) 충분하지 않습니다. 다른 자산을 보내더라도 블록체인 네트워크 수수료를 지불하려면 ${currency}가 더 필요합니다.", "do_not_have_enough_gas_asset": "현재 블록체인 네트워크 조건으로 거래를 하기에는 ${currency}이(가) 충분하지 않습니다. 다른 자산을 보내더라도 블록체인 네트워크 수수료를 지불하려면 ${currency}가 더 필요합니다.",
"totp_auth_url": "TOTP 인증 URL" "totp_auth_url": "TOTP 인증 URL",
"awaitDAppProcessing": "dApp이 처리를 마칠 때까지 기다려주세요."
} }

View file

@ -691,6 +691,27 @@
"default_buy_provider": "Default Provider ကိုဝယ်ပါ", "default_buy_provider": "Default Provider ကိုဝယ်ပါ",
"ask_each_time": "တစ်ခုချင်းစီကိုအချိန်မေးပါ", "ask_each_time": "တစ်ခုချင်းစီကိုအချိန်မေးပါ",
"buy_provider_unavailable": "လက်ရှိတွင်လက်ရှိမရနိုင်ပါ။", "buy_provider_unavailable": "လက်ရှိတွင်လက်ရှိမရနိုင်ပါ။",
"signTransaction": "ငွေလွှဲဝင်ပါ။",
"errorGettingCredentials": "မအောင်မြင်ပါ- အထောက်အထားများ ရယူနေစဉ် အမှားအယွင်း",
"errorSigningTransaction": "ငွေပေးငွေယူ လက်မှတ်ထိုးစဉ် အမှားအယွင်းတစ်ခု ဖြစ်ပေါ်ခဲ့သည်။",
"pairingInvalidEvent": "မမှန်ကန်သောဖြစ်ရပ်ကို တွဲချိတ်ခြင်း။",
"chains": "ဆွဲကြိုး",
"methods": "နည်းလမ်းများ",
"events": "အဲ့ဒါနဲ့",
"reject": "ငြင်းပယ်ပါ။",
"approve": "လက်မခံပါ။",
"expiresOn": "သက်တမ်းကုန်သည်။",
"walletConnect": "Wallet ချိတ်ဆက်မှု",
"nullURIError": "URI သည် null ဖြစ်သည်။",
"connectWalletPrompt": "အရောင်းအဝယ်ပြုလုပ်ရန် သင့်ပိုက်ဆံအိတ်ကို WalletConnect နှင့် ချိတ်ဆက်ပါ။",
"newConnection": "ချိတ်ဆက်မှုအသစ်",
"activeConnectionsPrompt": "လက်ရှိချိတ်ဆက်မှုများ ဤနေရာတွင် ပေါ်လာပါမည်။",
"deleteConnectionConfirmationPrompt": "ချိတ်ဆက်မှုကို ဖျက်လိုသည်မှာ သေချာပါသလား။",
"event": "ပွဲ",
"successful": "အောင်မြင်တယ်။",
"wouoldLikeToConnect": "ချိတ်ဆက်ချင်ပါတယ်။",
"message": "မက်ဆေ့ချ်",
"do_not_have_enough_gas_asset": "လက်ရှိ blockchain ကွန်ရက်အခြေအနေများနှင့် အရောင်းအဝယ်ပြုလုပ်ရန် သင့်တွင် ${currency} လုံလောက်မှုမရှိပါ။ သင်သည် မတူညီသော ပိုင်ဆိုင်မှုတစ်ခုကို ပေးပို့နေသော်လည်း blockchain ကွန်ရက်အခကြေးငွေကို ပေးဆောင်ရန် သင်သည် နောက်ထပ် ${currency} လိုအပ်ပါသည်။", "do_not_have_enough_gas_asset": "လက်ရှိ blockchain ကွန်ရက်အခြေအနေများနှင့် အရောင်းအဝယ်ပြုလုပ်ရန် သင့်တွင် ${currency} လုံလောက်မှုမရှိပါ။ သင်သည် မတူညီသော ပိုင်ဆိုင်မှုတစ်ခုကို ပေးပို့နေသော်လည်း blockchain ကွန်ရက်အခကြေးငွေကို ပေးဆောင်ရန် သင်သည် နောက်ထပ် ${currency} လိုအပ်ပါသည်။",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "ကျေးဇူးပြု၍ dApp ကို စီမံလုပ်ဆောင်ခြင်း အပြီးသတ်ရန် စောင့်ပါ။"
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Standaard Koopprovider", "default_buy_provider": "Standaard Koopprovider",
"ask_each_time": "Vraag het elke keer", "ask_each_time": "Vraag het elke keer",
"buy_provider_unavailable": "Provider momenteel niet beschikbaar.", "buy_provider_unavailable": "Provider momenteel niet beschikbaar.",
"signTransaction": "Transactie ondertekenen",
"errorGettingCredentials": "Mislukt: fout bij het ophalen van inloggegevens",
"errorSigningTransaction": "Er is een fout opgetreden tijdens het ondertekenen van de transactie",
"pairingInvalidEvent": "Koppelen Ongeldige gebeurtenis",
"chains": "Ketens",
"methods": "Methoden",
"events": "Evenementen",
"reject": "Afwijzen",
"approve": "Goedkeuren",
"expiresOn": "Verloopt op",
"walletConnect": "WalletConnect",
"nullURIError": "URI is nul",
"connectWalletPrompt": "Verbind uw portemonnee met WalletConnect om transacties uit te voeren",
"newConnection": "Nieuwe verbinding",
"activeConnectionsPrompt": "Actieve verbindingen worden hier weergegeven",
"deleteConnectionConfirmationPrompt": "Weet u zeker dat u de verbinding met",
"event": "Evenement",
"successful": "Succesvol",
"wouoldLikeToConnect": "wil graag verbinden",
"message": "Bericht",
"do_not_have_enough_gas_asset": "U heeft niet genoeg ${currency} om een transactie uit te voeren met de huidige blockchain-netwerkomstandigheden. U heeft meer ${currency} nodig om blockchain-netwerkkosten te betalen, zelfs als u een ander item verzendt.", "do_not_have_enough_gas_asset": "U heeft niet genoeg ${currency} om een transactie uit te voeren met de huidige blockchain-netwerkomstandigheden. U heeft meer ${currency} nodig om blockchain-netwerkkosten te betalen, zelfs als u een ander item verzendt.",
"totp_auth_url": "TOTP AUTH-URL" "totp_auth_url": "TOTP AUTH-URL",
"awaitDAppProcessing": "Wacht tot de dApp klaar is met verwerken."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Domyślny dostawca zakupu", "default_buy_provider": "Domyślny dostawca zakupu",
"ask_each_time": "Zapytaj za każdym razem", "ask_each_time": "Zapytaj za każdym razem",
"buy_provider_unavailable": "Dostawca obecnie niedostępny.", "buy_provider_unavailable": "Dostawca obecnie niedostępny.",
"signTransaction": "Podpisz transakcję",
"errorGettingCredentials": "Niepowodzenie: Błąd podczas uzyskiwania poświadczeń",
"errorSigningTransaction": "Wystąpił błąd podczas podpisywania transakcji",
"pairingInvalidEvent": "Nieprawidłowe zdarzenie parowania",
"chains": "Więzy",
"methods": "Metody",
"events": "Wydarzenia",
"reject": "Odrzucić",
"approve": "Zatwierdzić",
"expiresOn": "Upływa w dniu",
"walletConnect": "PortfelPołącz",
"nullURIError": "URI ma wartość zerową",
"connectWalletPrompt": "Połącz swój portfel z WalletConnect, aby dokonywać transakcji",
"newConnection": "Nowe połączenie",
"activeConnectionsPrompt": "Tutaj pojawią się aktywne połączenia",
"deleteConnectionConfirmationPrompt": "Czy na pewno chcesz usunąć połączenie z",
"event": "Wydarzenie",
"successful": "Udany",
"wouoldLikeToConnect": "chciałbym się połączyć",
"message": "Wiadomość",
"do_not_have_enough_gas_asset": "Nie masz wystarczającej ilości ${currency}, aby dokonać transakcji przy bieżących warunkach sieci blockchain. Potrzebujesz więcej ${currency}, aby uiścić opłaty za sieć blockchain, nawet jeśli wysyłasz inny zasób.", "do_not_have_enough_gas_asset": "Nie masz wystarczającej ilości ${currency}, aby dokonać transakcji przy bieżących warunkach sieci blockchain. Potrzebujesz więcej ${currency}, aby uiścić opłaty za sieć blockchain, nawet jeśli wysyłasz inny zasób.",
"totp_auth_url": "Adres URL TOTP AUTH" "totp_auth_url": "Adres URL TOTP AUTH",
"awaitDAppProcessing": "Poczekaj, aż dApp zakończy przetwarzanie."
} }

View file

@ -692,6 +692,27 @@
"default_buy_provider": "Provedor de compra padrão", "default_buy_provider": "Provedor de compra padrão",
"ask_each_time": "Pergunte cada vez", "ask_each_time": "Pergunte cada vez",
"buy_provider_unavailable": "Provedor atualmente indisponível.", "buy_provider_unavailable": "Provedor atualmente indisponível.",
"signTransaction": "Assinar transação",
"errorGettingCredentials": "Falha: Erro ao obter credenciais",
"errorSigningTransaction": "Ocorreu um erro ao assinar a transação",
"pairingInvalidEvent": "Emparelhamento de evento inválido",
"chains": "Correntes",
"methods": "Métodos",
"events": "Eventos",
"reject": "Rejeitar",
"approve": "Aprovar",
"expiresOn": "Expira em",
"walletConnect": "CarteiraConectada",
"nullURIError": "URI é nulo",
"connectWalletPrompt": "Conecte sua carteira ao WalletConnect para fazer transações",
"newConnection": "Nova conexão",
"activeConnectionsPrompt": "Conexões ativas aparecerão aqui",
"deleteConnectionConfirmationPrompt": "Tem certeza de que deseja excluir a conexão com",
"event": "Evento",
"successful": "Bem-sucedido",
"wouoldLikeToConnect": "gostaria de me conectar",
"message": "Mensagem",
"do_not_have_enough_gas_asset": "Você não tem ${currency} suficiente para fazer uma transação com as condições atuais da rede blockchain. Você precisa de mais ${currency} para pagar as taxas da rede blockchain, mesmo se estiver enviando um ativo diferente.", "do_not_have_enough_gas_asset": "Você não tem ${currency} suficiente para fazer uma transação com as condições atuais da rede blockchain. Você precisa de mais ${currency} para pagar as taxas da rede blockchain, mesmo se estiver enviando um ativo diferente.",
"totp_auth_url": "URL de autenticação TOTP" "totp_auth_url": "URL de autenticação TOTP",
"awaitDAppProcessing": "Aguarde até que o dApp termine o processamento."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "По умолчанию поставщик покупки", "default_buy_provider": "По умолчанию поставщик покупки",
"ask_each_time": "Спросите каждый раз", "ask_each_time": "Спросите каждый раз",
"buy_provider_unavailable": "Поставщик в настоящее время недоступен.", "buy_provider_unavailable": "Поставщик в настоящее время недоступен.",
"signTransaction": "Подписать транзакцию",
"errorGettingCredentials": "Не удалось: ошибка при получении учетных данных.",
"errorSigningTransaction": "Произошла ошибка при подписании транзакции",
"pairingInvalidEvent": "Недействительное событие сопряжения",
"chains": "Цепи",
"methods": "Методы",
"events": "События",
"reject": "Отклонять",
"approve": "Утвердить",
"expiresOn": "Годен до",
"walletConnect": "КошелекПодключиться",
"nullURIError": "URI имеет значение null",
"connectWalletPrompt": "Подключите свой кошелек к WalletConnect для совершения транзакций.",
"newConnection": "Новое соединение",
"activeConnectionsPrompt": "Здесь появятся активные подключения",
"deleteConnectionConfirmationPrompt": "Вы уверены, что хотите удалить подключение к",
"event": "Событие",
"successful": "Успешный",
"wouoldLikeToConnect": "хотел бы подключиться",
"message": "Сообщение",
"do_not_have_enough_gas_asset": "У вас недостаточно ${currency} для совершения транзакции при текущих условиях сети блокчейн. Вам нужно больше ${currency} для оплаты комиссий за сеть блокчейна, даже если вы отправляете другой актив.", "do_not_have_enough_gas_asset": "У вас недостаточно ${currency} для совершения транзакции при текущих условиях сети блокчейн. Вам нужно больше ${currency} для оплаты комиссий за сеть блокчейна, даже если вы отправляете другой актив.",
"totp_auth_url": "URL-адрес TOTP-АВТОРИЗАЦИИ" "totp_auth_url": "URL-адрес TOTP-АВТОРИЗАЦИИ",
"awaitDAppProcessing": "Пожалуйста, подождите, пока dApp завершит обработку."
} }

View file

@ -691,6 +691,27 @@
"default_buy_provider": "ผู้ให้บริการซื้อเริ่มต้น", "default_buy_provider": "ผู้ให้บริการซื้อเริ่มต้น",
"ask_each_time": "ถามทุกครั้ง", "ask_each_time": "ถามทุกครั้ง",
"buy_provider_unavailable": "ผู้ให้บริการไม่สามารถใช้งานได้ในปัจจุบัน", "buy_provider_unavailable": "ผู้ให้บริการไม่สามารถใช้งานได้ในปัจจุบัน",
"signTransaction": "ลงนามในการทำธุรกรรม",
"errorGettingCredentials": "ล้มเหลว: เกิดข้อผิดพลาดขณะรับข้อมูลรับรอง",
"errorSigningTransaction": "เกิดข้อผิดพลาดขณะลงนามธุรกรรม",
"pairingInvalidEvent": "การจับคู่เหตุการณ์ที่ไม่ถูกต้อง",
"chains": "ห่วงโซ่",
"methods": "วิธีการ",
"events": "กิจกรรม",
"reject": "ปฏิเสธ",
"approve": "อนุมัติ",
"expiresOn": "หมดอายุวันที่",
"walletConnect": "WalletConnect",
"nullURIError": "URI เป็นโมฆะ",
"connectWalletPrompt": "เชื่อมต่อกระเป๋าเงินของคุณด้วย WalletConnect เพื่อทำธุรกรรม",
"newConnection": "การเชื่อมต่อใหม่",
"activeConnectionsPrompt": "การเชื่อมต่อที่ใช้งานอยู่จะปรากฏที่นี่",
"deleteConnectionConfirmationPrompt": "คุณแน่ใจหรือไม่ว่าต้องการลบการเชื่อมต่อไปยัง",
"event": "เหตุการณ์",
"successful": "ประสบความสำเร็จ",
"wouoldLikeToConnect": "ต้องการเชื่อมต่อ",
"message": "ข้อความ",
"do_not_have_enough_gas_asset": "คุณมี ${currency} ไม่เพียงพอที่จะทำธุรกรรมกับเงื่อนไขเครือข่ายบล็อคเชนในปัจจุบัน คุณต้องมี ${currency} เพิ่มขึ้นเพื่อชำระค่าธรรมเนียมเครือข่ายบล็อคเชน แม้ว่าคุณจะส่งสินทรัพย์อื่นก็ตาม", "do_not_have_enough_gas_asset": "คุณมี ${currency} ไม่เพียงพอที่จะทำธุรกรรมกับเงื่อนไขเครือข่ายบล็อคเชนในปัจจุบัน คุณต้องมี ${currency} เพิ่มขึ้นเพื่อชำระค่าธรรมเนียมเครือข่ายบล็อคเชน แม้ว่าคุณจะส่งสินทรัพย์อื่นก็ตาม",
"totp_auth_url": "URL การตรวจสอบสิทธิ์ TOTP" "totp_auth_url": "URL การตรวจสอบสิทธิ์ TOTP",
"awaitDAppProcessing": "โปรดรอให้ dApp ประมวลผลเสร็จสิ้น"
} }

View file

@ -688,6 +688,33 @@
"support_description_other_links": "Sumali sa aming mga komunidad o maabot sa amin ang aming mga kasosyo sa pamamagitan ng iba pang mga pamamaraan", "support_description_other_links": "Sumali sa aming mga komunidad o maabot sa amin ang aming mga kasosyo sa pamamagitan ng iba pang mga pamamaraan",
"select_destination": "Mangyaring piliin ang patutunguhan para sa backup file.", "select_destination": "Mangyaring piliin ang patutunguhan para sa backup file.",
"save_to_downloads": "I -save sa mga pag -download", "save_to_downloads": "I -save sa mga pag -download",
"select_buy_provider_notice": "Pumili ng provider ng pagbili sa itaas. Maaari mong laktawan ang screen na ito sa pamamagitan ng pagtatakda ng iyong default na provider ng pagbili sa mga setting ng app.",
"onramper_option_description": "Mabilis na bumili ng crypto na may maraming paraan ng pagbabayad. Available sa karamihan ng mga bansa. Iba-iba ang mga spread at bayarin.",
"default_buy_provider": "Default na Provider ng Pagbili",
"ask_each_time": "Magtanong sa bawat oras",
"robinhood_option_description": "Bumili at ilipat kaagad gamit ang iyong debit card, bank account, o balanse ng Robinhood. USA lang.",
"buy_provider_unavailable": "Kasalukuyang hindi available ang provider.",
"signTransaction": "Mag-sign Transaksyon",
"errorGettingCredentials": "Nabigo: Error habang kumukuha ng mga kredensyal",
"errorSigningTransaction": "May naganap na error habang pinipirmahan ang transaksyon",
"pairingInvalidEvent": "Pagpares ng Di-wastong Kaganapan",
"chains": "Mga tanikala",
"methods": "Paraan",
"events": "Mga kaganapan",
"reject": "Tanggihan",
"approve": "Aprubahan",
"expiresOn": "Mag-e-expire sa",
"walletConnect": "WalletConnect",
"nullURIError": "Ang URI ay null",
"connectWalletPrompt": "Ikonekta ang iyong wallet sa WalletConnect upang gumawa ng mga transaksyon",
"newConnection": "Bagong Koneksyon",
"activeConnectionsPrompt": "Lalabas dito ang mga aktibong koneksyon",
"deleteConnectionConfirmationPrompt": "Sigurado ka bang gusto mong tanggalin ang koneksyon sa",
"event": "Kaganapan",
"successful": "Matagumpay",
"wouoldLikeToConnect": "gustong kumonekta",
"message": "Mensahe",
"do_not_have_enough_gas_asset": "Wala kang sapat na ${currency} para gumawa ng transaksyon sa kasalukuyang kundisyon ng network ng blockchain. Kailangan mo ng higit pang ${currency} upang magbayad ng mga bayarin sa network ng blockchain, kahit na nagpapadala ka ng ibang asset.", "do_not_have_enough_gas_asset": "Wala kang sapat na ${currency} para gumawa ng transaksyon sa kasalukuyang kundisyon ng network ng blockchain. Kailangan mo ng higit pang ${currency} upang magbayad ng mga bayarin sa network ng blockchain, kahit na nagpapadala ka ng ibang asset.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Pakihintay na matapos ang pagproseso ng dApp."
} }

View file

@ -691,6 +691,27 @@
"default_buy_provider": "Varsayılan Satın Alma Sağlayıcısı", "default_buy_provider": "Varsayılan Satın Alma Sağlayıcısı",
"ask_each_time": "Her seferinde sor", "ask_each_time": "Her seferinde sor",
"buy_provider_unavailable": "Sağlayıcı şu anda kullanılamıyor.", "buy_provider_unavailable": "Sağlayıcı şu anda kullanılamıyor.",
"signTransaction": "İşlem İmzala",
"errorGettingCredentials": "Başarısız: Kimlik bilgileri alınırken hata oluştu",
"errorSigningTransaction": "İşlem imzalanırken bir hata oluştu",
"pairingInvalidEvent": "Geçersiz Etkinliği Eşleştirme",
"chains": "Zincirler",
"methods": "Yöntemler",
"events": "Olaylar",
"reject": "Reddetmek",
"approve": "Onaylamak",
"expiresOn": "Tarihinde sona eriyor",
"walletConnect": "WalletConnect",
"nullURIError": "URI boş",
"connectWalletPrompt": "İşlem yapmak için cüzdanınızı WalletConnect'e bağlayın",
"newConnection": "Yeni bağlantı",
"activeConnectionsPrompt": "Aktif bağlantılar burada görünecek",
"deleteConnectionConfirmationPrompt": "Bağlantıyı silmek istediğinizden emin misiniz?",
"event": "Etkinlik",
"successful": "Başarılı",
"wouoldLikeToConnect": "bağlanmak istiyorum",
"message": "İleti",
"do_not_have_enough_gas_asset": "Mevcut blockchain ağ koşullarıyla işlem yapmak için yeterli ${currency} paranız yok. Farklı bir varlık gönderiyor olsanız bile blockchain ağ ücretlerini ödemek için daha fazla ${currency} miktarına ihtiyacınız var.", "do_not_have_enough_gas_asset": "Mevcut blockchain ağ koşullarıyla işlem yapmak için yeterli ${currency} paranız yok. Farklı bir varlık gönderiyor olsanız bile blockchain ağ ücretlerini ödemek için daha fazla ${currency} miktarına ihtiyacınız var.",
"totp_auth_url": "TOTP YETKİ URL'si" "totp_auth_url": "TOTP YETKİ URL'si",
"awaitDAppProcessing": "Lütfen dApp'in işlemeyi bitirmesini bekleyin."
} }

View file

@ -693,6 +693,27 @@
"default_buy_provider": "Постачальник покупки за замовчуванням", "default_buy_provider": "Постачальник покупки за замовчуванням",
"ask_each_time": "Запитайте кожен раз", "ask_each_time": "Запитайте кожен раз",
"buy_provider_unavailable": "В даний час постачальник недоступний.", "buy_provider_unavailable": "В даний час постачальник недоступний.",
"signTransaction": "Підписати транзакцію",
"errorGettingCredentials": "Помилка: помилка під час отримання облікових даних",
"errorSigningTransaction": "Під час підписання транзакції сталася помилка",
"pairingInvalidEvent": "Недійсна подія сполучення",
"chains": "Ланцюги",
"methods": "методи",
"events": "Події",
"reject": "Відхиляти",
"approve": "Затвердити",
"expiresOn": "Термін дії закінчується",
"walletConnect": "WalletConnect",
"nullURIError": "URI нульовий",
"connectWalletPrompt": "Підключіть свій гаманець до WalletConnect, щоб здійснювати транзакції",
"newConnection": "Нове підключення",
"activeConnectionsPrompt": "Тут з’являться активні підключення",
"deleteConnectionConfirmationPrompt": "Ви впевнені, що хочете видалити з’єднання з",
"event": "Подія",
"successful": "Успішний",
"wouoldLikeToConnect": "хотів би підключитися",
"message": "повідомлення",
"do_not_have_enough_gas_asset": "У вас недостатньо ${currency}, щоб здійснити трансакцію з поточними умовами мережі блокчейн. Вам потрібно більше ${currency}, щоб сплатити комісію мережі блокчейн, навіть якщо ви надсилаєте інший актив.", "do_not_have_enough_gas_asset": "У вас недостатньо ${currency}, щоб здійснити трансакцію з поточними умовами мережі блокчейн. Вам потрібно більше ${currency}, щоб сплатити комісію мережі блокчейн, навіть якщо ви надсилаєте інший актив.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Зачекайте, доки dApp завершить обробку."
} }

View file

@ -685,6 +685,27 @@
"default_buy_provider": "پہلے سے طے شدہ خریدنے والا", "default_buy_provider": "پہلے سے طے شدہ خریدنے والا",
"ask_each_time": "ہر بار پوچھیں", "ask_each_time": "ہر بار پوچھیں",
"buy_provider_unavailable": "فراہم کنندہ فی الحال دستیاب نہیں ہے۔", "buy_provider_unavailable": "فراہم کنندہ فی الحال دستیاب نہیں ہے۔",
"signTransaction": "۔ﮟﯾﺮﮐ ﻂﺨﺘﺳﺩ ﺮﭘ ﻦﯾﺩ ﻦﯿﻟ",
"errorGettingCredentials": "۔ﯽﺑﺍﺮﺧ ﮟﯿﻣ ﮯﻧﺮﮐ ﻞﺻﺎﺣ ﺩﺎﻨﺳﺍ :ﻡﺎﮐﺎﻧ",
"errorSigningTransaction": "۔ﮯﮨ ﯽﺌﮔﺁ ﺶﯿﭘ ﯽﺑﺍﺮﺧ ﮏﯾﺍ ﺖﻗﻭ ﮯﺗﺮﮐ ﻂﺨﺘﺳﺩ ﺮﭘ ﻦﯾﺩ ﻦﯿﻟ",
"pairingInvalidEvent": "ﭧﻧﻮﯾﺍ ﻂﻠﻏ ﺎﻧﺎﻨﺑ ﺍﮌﻮﺟ",
"chains": "ﮟﯾﺮﯿﺠﻧﺯ",
"methods": "ﮯﻘﯾﺮﻃ",
"events": "ﺕﺎﺒﯾﺮﻘﺗ",
"reject": "ﺎﻧﺮﮐ ﺩﺭ",
"approve": "ﻭﺮﮐ ﺭﻮﻈﻨﻣ",
"expiresOn": "ﺩﺎﻌﯿﻣ ﯽﻣﺎﺘﺘﺧﺍ",
"walletConnect": "WalletConnect",
"nullURIError": "URI ۔ﮯﮨ ﻡﺪﻌﻟﺎﮐ",
"connectWalletPrompt": "۔ﮟﯾﮌﻮﺟ ﮫﺗﺎﺳ ﮯﮐ WalletConnect ﻮﮐ ﮮﻮﭩﺑ ﮯﻨﭘﺍ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﻦﯾﺩ ﻦﯿﻟ",
"newConnection": "ﻦﺸﮑﻨﮐ ﺎﯿﻧ",
"activeConnectionsPrompt": "۔ﮯﮔ ﮞﻮﮨ ﺮﮨﺎﻇ ﮞﺎﮩﯾ ﺰﻨﺸﮑﻨﮐ ﻝﺎﻌﻓ",
"deleteConnectionConfirmationPrompt": "۔ﮟﯿﮨ ﮯﺘﮨﺎﭼ ﺎﻧﺮﮐ ﻑﺬﺣ ﻮﮐ ﻦﺸﮑﻨﮐ ﭖﺁ ﮧﮐ ﮯﮨ ﻦﯿﻘﯾ ﻮﮐ ﭖﺁ ﺎﯿﮐ",
"event": "ﺐﯾﺮﻘﺗ",
"successful": "ﺏﺎﯿﻣﺎﮐ",
"wouoldLikeToConnect": "؟ﮯﮔ ﮟﯿﮨﺎﭼ ﺎﻧﮍﺟ",
"message": "ﻡﺎﻐﯿﭘ",
"do_not_have_enough_gas_asset": "آپ کے پاس موجودہ بلاکچین نیٹ ورک کی شرائط کے ساتھ لین دین کرنے کے لیے کافی ${currency} نہیں ہے۔ آپ کو بلاکچین نیٹ ورک کی فیس ادا کرنے کے لیے مزید ${currency} کی ضرورت ہے، چاہے آپ کوئی مختلف اثاثہ بھیج رہے ہوں۔", "do_not_have_enough_gas_asset": "آپ کے پاس موجودہ بلاکچین نیٹ ورک کی شرائط کے ساتھ لین دین کرنے کے لیے کافی ${currency} نہیں ہے۔ آپ کو بلاکچین نیٹ ورک کی فیس ادا کرنے کے لیے مزید ${currency} کی ضرورت ہے، چاہے آپ کوئی مختلف اثاثہ بھیج رہے ہوں۔",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "۔ﮟﯾﺮﮐ ﺭﺎﻈﺘﻧﺍ ﺎﮐ ﮯﻧﻮﮨ ﻞﻤﮑﻣ ﮓﻨﺴﯿﺳﻭﺮﭘ ﮯﮐ dApp ﻡﺮﮐ ﮦﺍﺮﺑ"
} }

View file

@ -687,6 +687,27 @@
"default_buy_provider": "Aiyipada Ra Olupese", "default_buy_provider": "Aiyipada Ra Olupese",
"ask_each_time": "Beere lọwọ kọọkan", "ask_each_time": "Beere lọwọ kọọkan",
"buy_provider_unavailable": "Olupese lọwọlọwọ ko si.", "buy_provider_unavailable": "Olupese lọwọlọwọ ko si.",
"signTransaction": "Wole Idunadura",
"errorGettingCredentials": "Kuna: Aṣiṣe lakoko gbigba awọn iwe-ẹri",
"errorSigningTransaction": "Aṣiṣe kan ti waye lakoko ti o fowo si iṣowo",
"pairingInvalidEvent": "Pipọpọ Iṣẹlẹ Ti ko tọ",
"chains": "Awọn ẹwọn",
"methods": "Awọn ọna",
"events": "Awọn iṣẹlẹ",
"reject": "Kọ",
"approve": "Fi ọwọ si",
"expiresOn": "Ipari lori",
"walletConnect": "Asopọmọra apamọwọ",
"nullURIError": "URI jẹ asan",
"connectWalletPrompt": "So apamọwọ rẹ pọ pẹlu WalletConnect lati ṣe awọn iṣowo",
"newConnection": "Tuntun Asopọ",
"activeConnectionsPrompt": "Awọn asopọ ti nṣiṣe lọwọ yoo han nibi",
"deleteConnectionConfirmationPrompt": "Ṣe o da ọ loju pe o fẹ paarẹ asopọ si",
"event": "Iṣẹlẹ",
"successful": "Aseyori",
"wouoldLikeToConnect": "yoo fẹ lati sopọ",
"message": "Ifiranṣẹ",
"do_not_have_enough_gas_asset": "O ko ni to ${currency} lati ṣe idunadura kan pẹlu awọn ipo nẹtiwọki blockchain lọwọlọwọ. O nilo diẹ sii ${currency} lati san awọn owo nẹtiwọọki blockchain, paapaa ti o ba nfi dukia miiran ranṣẹ.", "do_not_have_enough_gas_asset": "O ko ni to ${currency} lati ṣe idunadura kan pẹlu awọn ipo nẹtiwọki blockchain lọwọlọwọ. O nilo diẹ sii ${currency} lati san awọn owo nẹtiwọọki blockchain, paapaa ti o ba nfi dukia miiran ranṣẹ.",
"totp_auth_url": "TOTP AUTH URL" "totp_auth_url": "TOTP AUTH URL",
"awaitDAppProcessing": "Fi inurere duro fun dApp lati pari sisẹ."
} }

View file

@ -692,6 +692,27 @@
"default_buy_provider": "默认购买提供商", "default_buy_provider": "默认购买提供商",
"ask_each_time": "每次问", "ask_each_time": "每次问",
"buy_provider_unavailable": "提供者目前不可用。", "buy_provider_unavailable": "提供者目前不可用。",
"signTransaction": "签署交易",
"errorGettingCredentials": "失败:获取凭据时出错",
"errorSigningTransaction": "签署交易时发生错误",
"pairingInvalidEvent": "配对无效事件",
"chains": "链条",
"methods": "方法",
"events": "活动",
"reject": "拒绝",
"approve": "批准",
"expiresOn": "到期",
"walletConnect": "钱包连接",
"nullURIError": "URI 为空",
"connectWalletPrompt": "将您的钱包与 WalletConnect 连接以进行交易",
"newConnection": "新连接",
"activeConnectionsPrompt": "活动连接将出现在这里",
"deleteConnectionConfirmationPrompt": "您确定要删除与",
"event": "事件",
"successful": "成功的",
"wouoldLikeToConnect": "想要连接",
"message": "信息",
"do_not_have_enough_gas_asset": "您没有足够的 ${currency} 来在当前的区块链网络条件下进行交易。即使您发送的是不同的资产,您也需要更多的 ${currency} 来支付区块链网络费用。", "do_not_have_enough_gas_asset": "您没有足够的 ${currency} 来在当前的区块链网络条件下进行交易。即使您发送的是不同的资产,您也需要更多的 ${currency} 来支付区块链网络费用。",
"totp_auth_url": "TOTP 授权 URL" "totp_auth_url": "TOTP 授权 URL",
"awaitDAppProcessing": "请等待 dApp 处理完成。"
} }

View file

@ -477,6 +477,7 @@ import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_credentials.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
"""; """;
const ethereumCWHeaders = """ const ethereumCWHeaders = """
@ -498,6 +499,8 @@ abstract class Ethereum {
WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password}); WalletCredentials createEthereumRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password}); WalletCredentials createEthereumRestoreWalletFromPrivateKey({required String name, required String privateKey, required String password});
String getAddress(WalletBase wallet); String getAddress(WalletBase wallet);
String getPrivateKey(WalletBase wallet);
String getPublicKey(WalletBase wallet);
TransactionPriority getDefaultTransactionPriority(); TransactionPriority getDefaultTransactionPriority();
List<TransactionPriority> getTransactionPriorities(); List<TransactionPriority> getTransactionPriorities();
TransactionPriority deserializeEthereumTransactionPriority(int raw); TransactionPriority deserializeEthereumTransactionPriority(int raw);

View file

@ -35,6 +35,7 @@ class SecretKey {
SecretKey('exolixApiKey', () => ''), SecretKey('exolixApiKey', () => ''),
SecretKey('robinhoodApplicationId', () => ''), SecretKey('robinhoodApplicationId', () => ''),
SecretKey('robinhoodCIdApiSecret', () => ''), SecretKey('robinhoodCIdApiSecret', () => ''),
SecretKey('walletConnectProjectId', () => ''),
]; ];
static final ethereumSecrets = [ static final ethereumSecrets = [