CW948: feat: bitcoin view-only (#2261)
* feat: bitcoin view-only * fix: add UR to cw_bitcoin, fix payjoin issue * feat: add unsignedPsbt to PendingBitcoinTransaction * wip * feat: xpub restore from bitcoin URI QR * feat(dev): debug UR codes [skip ci] * fix: master fingerprint default in create bitcoin transaction * fix: handle empty private key in bitcoin transaction building * fix: show success dialog after btc ur transaction * fix(ui): remove SP from UI in view only wallet * fix(cw_bitcoin): tx sending on non-airgap * fix(cw_bitcoin): disable all non-segwit addresses * feat(ur): support BBQR for coldcard qr * flutter 3.27.0 -> 3.27.4 * feat: raw xpub qr support for coldcard q * fix: update ledger_bitcoin fix: update switching button * fix: restore button not showing up after scanning * feat: commit raw tx (from coldcard Q) * feat: legacy crypto-psbt support for seed signer * chore: address comments from review * fix(cw_bitcoin): disable sp and payjoin for cupcake * feat: enable DNSSEC BIP353 in PSBT (#2397) * feat: enable DNSSEC BIP353 in PSBT * chore: put bitcoin view only behind a featureflag * fix: update Monero wallet to work with new internal URQR return format * feat: add "Restore from Cupcake App" option with localized strings * feat: enable DNSSEC BIP353 in PSBT using dnssec-prover (#2401) * fix: use dnssec-prover chore: bump ndk to r28c * fix: validate DNSSEC proof before updating the UI * fix: rename button to copy debug info to not hide actions on URQR widget --------- Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
@@ -9,7 +9,7 @@ jobs:
|
||||
PR_test_build:
|
||||
runs-on: linux-amd64
|
||||
container:
|
||||
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
|
||||
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly
|
||||
env:
|
||||
STORE_PASS: test@cake_wallet
|
||||
KEY_PASS: test@cake_wallet
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
PR_test_build:
|
||||
runs-on: linux-amd64
|
||||
container:
|
||||
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
|
||||
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly
|
||||
env:
|
||||
STORE_PASS: test@cake_wallet
|
||||
KEY_PASS: test@cake_wallet
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# docker buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
|
||||
# docker buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly
|
||||
|
||||
# Heavily inspired by cirrusci images
|
||||
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
|
||||
@@ -15,7 +15,7 @@ LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet
|
||||
ENV GOLANG_VERSION=1.24.1
|
||||
|
||||
# Pin Flutter version to latest known-working version
|
||||
ENV FLUTTER_VERSION=3.27.0
|
||||
ENV FLUTTER_VERSION=3.27.4
|
||||
|
||||
# Pin Android Studio, platform, and build tools versions to latest known-working version
|
||||
# Comes from https://developer.android.com/studio/#command-tools
|
||||
@@ -138,11 +138,12 @@ RUN ARCH=$(uname -m) && \
|
||||
"build-tools;35.0.0"
|
||||
|
||||
# Install extra NDK dependency for sp_scanner
|
||||
ENV ANDROID_NDK_VERSION=27.2.12479018
|
||||
ENV ANDROID_NDK_VERSION=28.2.13676358
|
||||
RUN ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" != "x86_64" ]; then exit 0; fi \
|
||||
&& yes | sdkmanager "ndk;$ANDROID_NDK_VERSION" \
|
||||
"ndk;27.0.12077973"
|
||||
"ndk;27.0.12077973" \
|
||||
"ndk;27.2.12479018"
|
||||
|
||||
# Install dependencies for tests
|
||||
# Comes from https://github.com/ReactiveCircus/android-emulator-runner
|
||||
|
||||
@@ -94,7 +94,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
ndkVersion "27.0.12077973"
|
||||
ndkVersion "28.2.13676358"
|
||||
}
|
||||
|
||||
flutter {
|
||||
|
||||
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 88 KiB |
@@ -28,6 +28,16 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||
BitcoinReceivePageOption.p2pkh
|
||||
];
|
||||
|
||||
static const allViewOnly = [
|
||||
BitcoinReceivePageOption.p2wpkh,
|
||||
// TODO: uncomment this after we properly derive keys and not use m/84 for
|
||||
// all of them (as this breaks cupcake)
|
||||
// BitcoinReceivePageOption.p2tr,
|
||||
// BitcoinReceivePageOption.p2wsh,
|
||||
// BitcoinReceivePageOption.p2sh,
|
||||
// BitcoinReceivePageOption.p2pkh
|
||||
];
|
||||
|
||||
static const allLitecoin = [
|
||||
BitcoinReceivePageOption.p2wpkh,
|
||||
BitcoinReceivePageOption.mweb,
|
||||
|
||||
@@ -21,9 +21,11 @@ import 'package:cw_bitcoin/psbt/v0_deserialize.dart';
|
||||
import 'package:cw_bitcoin/psbt/v0_finalizer.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:cw_core/payjoin_session.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_keys_file.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -32,6 +34,9 @@ import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||
import 'package:ledger_bitcoin/psbt.dart';
|
||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:ur/cbor_lite.dart';
|
||||
import 'package:ur/ur.dart';
|
||||
import 'package:ur/ur_decoder.dart';
|
||||
|
||||
part 'bitcoin_wallet.g.dart';
|
||||
|
||||
@@ -280,6 +285,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
|
||||
Future<PsbtV2> buildPsbt({
|
||||
required List<BitcoinBaseOutput> outputs,
|
||||
required List<OutputInfo> cwOutputs,
|
||||
required BigInt fee,
|
||||
required BasedUtxoNetwork network,
|
||||
required List<UtxoWithAddress> utxos,
|
||||
@@ -308,7 +314,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
}
|
||||
|
||||
return PSBTTransactionBuild(
|
||||
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF)
|
||||
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF, cwOutputs: cwOutputs)
|
||||
.psbt;
|
||||
}
|
||||
|
||||
@@ -318,6 +324,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
required BigInt fee,
|
||||
required BasedUtxoNetwork network,
|
||||
required List<UtxoWithAddress> utxos,
|
||||
required List<OutputInfo> cwOutputs,
|
||||
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
||||
String? memo,
|
||||
bool enableRBF = false,
|
||||
@@ -331,6 +338,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
fee: fee,
|
||||
network: network,
|
||||
utxos: utxos,
|
||||
cwOutputs: cwOutputs,
|
||||
publicKeys: publicKeys,
|
||||
masterFingerprint: masterFingerprint,
|
||||
memo: memo,
|
||||
@@ -351,7 +359,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
as PendingBitcoinTransaction;
|
||||
|
||||
final payjoinUri = credentials.payjoinUri;
|
||||
if (payjoinUri == null) return tx;
|
||||
if (payjoinUri == null && !tx.shouldCommitUR()) return tx;
|
||||
|
||||
final transaction = await buildPsbt(
|
||||
utxos: tx.utxos,
|
||||
@@ -363,20 +371,26 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
isChange: e.isChange,
|
||||
))
|
||||
.toList(),
|
||||
cwOutputs: credentials.outputs,
|
||||
fee: BigInt.from(tx.fee),
|
||||
network: network,
|
||||
memo: credentials.outputs.first.memo,
|
||||
outputOrdering: BitcoinOrdering.none,
|
||||
enableRBF: true,
|
||||
publicKeys: tx.publicKeys!,
|
||||
masterFingerprint: Uint8List(0));
|
||||
masterFingerprint: Uint8List.fromList([0, 0, 0, 0]));
|
||||
|
||||
final originalPsbt = await signPsbt(
|
||||
base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys());
|
||||
if (tx.shouldCommitUR()) {
|
||||
tx.unsignedPsbt = transaction.asPsbtV0();
|
||||
return tx;
|
||||
}
|
||||
|
||||
final originalPsbt =
|
||||
await signPsbt(base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys());
|
||||
|
||||
tx.commitOverride = () async {
|
||||
final sender = await payjoinManager.initSender(
|
||||
payjoinUri, originalPsbt, int.parse(tx.feeRate));
|
||||
final sender =
|
||||
await payjoinManager.initSender(payjoinUri!, originalPsbt, int.parse(tx.feeRate));
|
||||
payjoinManager.spawnNewSender(
|
||||
sender: sender, pjUrl: payjoinUri, amount: BigInt.from(tx.amount));
|
||||
};
|
||||
@@ -404,6 +418,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
feeRate: "",
|
||||
network: network,
|
||||
hasChange: true,
|
||||
isViewOnly: false,
|
||||
).commit();
|
||||
}
|
||||
|
||||
@@ -429,6 +444,44 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||
return base64Encode(psbt.asPsbtV0());
|
||||
}
|
||||
|
||||
Future<void> commitPsbtUR(List<String> urCodes) async {
|
||||
if (urCodes.isEmpty) throw Exception("No QR code got scanned");
|
||||
bool isUr = urCodes.any((str) {
|
||||
return str.startsWith("ur:psbt/");
|
||||
});
|
||||
if (isUr) {
|
||||
final ur = URDecoder();
|
||||
for (final inp in urCodes) {
|
||||
ur.receivePart(inp);
|
||||
}
|
||||
final result = (ur.result as UR);
|
||||
final cbor = result.cbor;
|
||||
final cborDecoder = CBORDecoder(cbor);
|
||||
final out = cborDecoder.decodeBytes();
|
||||
final bytes = out.$1;
|
||||
final base64psbt = base64Encode(bytes);
|
||||
final psbt = PsbtV2()..deserializeV0(base64Decode(base64psbt));
|
||||
|
||||
// psbt.finalize();
|
||||
final finalized = base64Encode(psbt.serialize());
|
||||
await commitPsbt(finalized);
|
||||
} else {
|
||||
final btcTx = BtcTransaction.fromRaw(urCodes.first);
|
||||
|
||||
return PendingBitcoinTransaction(
|
||||
btcTx,
|
||||
type,
|
||||
electrumClient: electrumClient,
|
||||
amount: 0,
|
||||
fee: 0,
|
||||
feeRate: "",
|
||||
network: network,
|
||||
hasChange: true,
|
||||
isViewOnly: false,
|
||||
).commit();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> signMessage(String message, {String? address = null}) async {
|
||||
if (walletInfo.isHardwareWallet) {
|
||||
|
||||
@@ -54,6 +54,17 @@ class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials {
|
||||
final String wif;
|
||||
}
|
||||
|
||||
class BitcoinWalletFromKeysCredentials extends WalletCredentials {
|
||||
BitcoinWalletFromKeysCredentials({
|
||||
required String name,
|
||||
required String password,
|
||||
required this.xpub,
|
||||
WalletInfo? walletInfo,
|
||||
}) : super(name: name, password: password, walletInfo: walletInfo);
|
||||
|
||||
final String xpub;
|
||||
}
|
||||
|
||||
class BitcoinRestoreWalletFromHardware extends WalletCredentials {
|
||||
BitcoinRestoreWalletFromHardware({
|
||||
required String name,
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
class BitcoinWalletKeys {
|
||||
const BitcoinWalletKeys({required this.wif, required this.privateKey, required this.publicKey});
|
||||
const BitcoinWalletKeys({required this.wif, required this.privateKey, required this.publicKey, required this.xpub});
|
||||
|
||||
final String wif;
|
||||
final String privateKey;
|
||||
final String publicKey;
|
||||
final String xpub;
|
||||
|
||||
Map<String, String> toJson() => {
|
||||
'wif': wif,
|
||||
'privateKey': privateKey,
|
||||
'publicKey': publicKey,
|
||||
'xpub': xpub
|
||||
};
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import 'package:bip39/bip39.dart' as bip39;
|
||||
class BitcoinWalletService extends WalletService<
|
||||
BitcoinNewWalletCredentials,
|
||||
BitcoinRestoreWalletFromSeedCredentials,
|
||||
BitcoinRestoreWalletFromWIFCredentials,
|
||||
BitcoinWalletFromKeysCredentials,
|
||||
BitcoinRestoreWalletFromHardware> {
|
||||
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource,
|
||||
this.payjoinSessionSource, this.isDirect);
|
||||
@@ -165,9 +165,25 @@ class BitcoinWalletService extends WalletService<
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
|
||||
{bool? isTestnet}) async =>
|
||||
throw UnimplementedError();
|
||||
Future<BitcoinWallet> restoreFromKeys(BitcoinWalletFromKeysCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
||||
credentials.walletInfo?.network = network.value;
|
||||
|
||||
final wallet = await BitcoinWallet(
|
||||
password: credentials.password!,
|
||||
xpub: credentials.xpub,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
networkParam: network,
|
||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||
payjoinBox: payjoinSessionSource,
|
||||
);
|
||||
|
||||
await wallet.save();
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
||||
|
||||
@@ -42,6 +42,7 @@ import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_keys_file.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_core/unspent_coin_type.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||
@@ -216,7 +217,7 @@ abstract class ElectrumWalletBase
|
||||
@override
|
||||
bool isTestnet;
|
||||
|
||||
bool get hasSilentPaymentsScanning => type == WalletType.bitcoin;
|
||||
bool get hasSilentPaymentsScanning => type == WalletType.bitcoin && keys.privateKey.isNotEmpty;
|
||||
|
||||
@observable
|
||||
bool nodeSupportsSilentPayments = true;
|
||||
@@ -282,11 +283,26 @@ abstract class ElectrumWalletBase
|
||||
}
|
||||
|
||||
@override
|
||||
BitcoinWalletKeys get keys => BitcoinWalletKeys(
|
||||
wif: WifEncoder.encode(hd.privateKey.raw, netVer: network.wifNetVer),
|
||||
privateKey: hd.privateKey.toHex(),
|
||||
publicKey: hd.publicKey.toHex(),
|
||||
);
|
||||
BitcoinWalletKeys get keys {
|
||||
String? wif;
|
||||
String? privateKey;
|
||||
String? publicKey;
|
||||
try {
|
||||
wif = WifEncoder.encode(hd.privateKey.raw, netVer: network.wifNetVer);
|
||||
} catch (_) {}
|
||||
try {
|
||||
privateKey = hd.privateKey.toHex();
|
||||
} catch (_) {}
|
||||
try {
|
||||
publicKey = hd.publicKey.toHex();
|
||||
} catch (_) {}
|
||||
return BitcoinWalletKeys(
|
||||
wif: wif ?? '',
|
||||
privateKey: privateKey ?? '',
|
||||
publicKey: publicKey ?? '',
|
||||
xpub: xpub,
|
||||
);
|
||||
}
|
||||
|
||||
String _password;
|
||||
List<BitcoinUnspent> unspentCoins;
|
||||
@@ -672,7 +688,7 @@ abstract class ElectrumWalletBase
|
||||
);
|
||||
spendsSilentPayment = true;
|
||||
isSilentPayment = true;
|
||||
} else if (!isHardwareWallet) {
|
||||
} else if (!isHardwareWallet && keys.privateKey.isNotEmpty) {
|
||||
privkey =
|
||||
generateECPrivate(hd: hd, index: utx.bitcoinAddressRecord.index, network: network);
|
||||
}
|
||||
@@ -1120,6 +1136,7 @@ abstract class ElectrumWalletBase
|
||||
memo: estimatedTx.memo,
|
||||
outputOrdering: BitcoinOrdering.none,
|
||||
enableRBF: true,
|
||||
cwOutputs: transactionCredentials.outputs,
|
||||
);
|
||||
|
||||
return PendingBitcoinTransaction(
|
||||
@@ -1132,7 +1149,8 @@ abstract class ElectrumWalletBase
|
||||
network: network,
|
||||
hasChange: estimatedTx.hasChange,
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: false, // ToDo: (Konsti) Support Taproot
|
||||
hasTaprootInputs: false, // ToDo: (Konsti) Support Taproot,
|
||||
isViewOnly: false,
|
||||
)..addListener((transaction) async {
|
||||
transactionHistory.addOne(transaction);
|
||||
await updateBalance();
|
||||
@@ -1166,6 +1184,7 @@ abstract class ElectrumWalletBase
|
||||
bool hasTaprootInputs = false;
|
||||
|
||||
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
|
||||
if (keys.privateKey.isEmpty) return "";
|
||||
String error = "Cannot find private key.";
|
||||
|
||||
ECPrivateInfo? key;
|
||||
@@ -1203,18 +1222,21 @@ abstract class ElectrumWalletBase
|
||||
}
|
||||
});
|
||||
|
||||
return PendingBitcoinTransaction(transaction, type,
|
||||
electrumClient: electrumClient,
|
||||
amount: estimatedTx.amount,
|
||||
fee: estimatedTx.fee,
|
||||
feeRate: feeRateInt.toString(),
|
||||
network: network,
|
||||
hasChange: estimatedTx.hasChange,
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: hasTaprootInputs,
|
||||
utxos: estimatedTx.utxos,
|
||||
publicKeys: estimatedTx.publicKeys)
|
||||
..addListener((transaction) async {
|
||||
return PendingBitcoinTransaction(
|
||||
transaction,
|
||||
type,
|
||||
electrumClient: electrumClient,
|
||||
amount: estimatedTx.amount,
|
||||
fee: estimatedTx.fee,
|
||||
feeRate: feeRateInt.toString(),
|
||||
network: network,
|
||||
hasChange: estimatedTx.hasChange,
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: hasTaprootInputs,
|
||||
utxos: estimatedTx.utxos,
|
||||
publicKeys: estimatedTx.publicKeys,
|
||||
isViewOnly: keys.privateKey.isEmpty,
|
||||
)..addListener((transaction) async {
|
||||
transactionHistory.addOne(transaction);
|
||||
if (estimatedTx.spendsSilentPayment) {
|
||||
transactionHistory.transactions.values.forEach((tx) {
|
||||
@@ -1242,6 +1264,7 @@ abstract class ElectrumWalletBase
|
||||
required BigInt fee,
|
||||
required BasedUtxoNetwork network,
|
||||
required List<UtxoWithAddress> utxos,
|
||||
required List<OutputInfo> cwOutputs,
|
||||
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
||||
String? memo,
|
||||
bool enableRBF = false,
|
||||
@@ -1379,6 +1402,8 @@ abstract class ElectrumWalletBase
|
||||
@action
|
||||
@override
|
||||
Future<void> rescan({required int height, bool? doSingleScan}) async {
|
||||
if (keys.privateKey.isEmpty) return;
|
||||
|
||||
silentPaymentsScanningActive = true;
|
||||
_setListeners(height, doSingleScan: doSingleScan);
|
||||
}
|
||||
@@ -1875,6 +1900,7 @@ abstract class ElectrumWalletBase
|
||||
network: network,
|
||||
hasChange: changeOutputs.isNotEmpty,
|
||||
feeRate: newFee.toString(),
|
||||
isViewOnly: keys.privateKey.isEmpty,
|
||||
)..addListener((transaction) async {
|
||||
transactionHistory.transactions.values.forEach((tx) {
|
||||
if (tx.id == hash) {
|
||||
|
||||
@@ -38,6 +38,7 @@ import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_keys_file.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@@ -1383,6 +1384,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||
required BigInt fee,
|
||||
required BasedUtxoNetwork network,
|
||||
required List<UtxoWithAddress> utxos,
|
||||
required List<OutputInfo> cwOutputs,
|
||||
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
||||
String? memo,
|
||||
bool enableRBF = false,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bbqrdart/bbqrdart.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:cw_bitcoin/exceptions.dart';
|
||||
@@ -11,6 +15,9 @@ import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_mweb/cw_mweb.dart';
|
||||
import 'package:cw_mweb/mwebd.pb.dart';
|
||||
import 'package:ur/cbor_lite.dart';
|
||||
import 'package:ur/ur.dart';
|
||||
import 'package:ur/ur_encoder.dart';
|
||||
|
||||
class PendingBitcoinTransaction with PendingTransaction {
|
||||
PendingBitcoinTransaction(
|
||||
@@ -28,6 +35,8 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
this.utxos = const [],
|
||||
this.publicKeys,
|
||||
this.commitOverride,
|
||||
this.unsignedPsbt,
|
||||
required this.isViewOnly,
|
||||
}) : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
|
||||
|
||||
final WalletType type;
|
||||
@@ -40,6 +49,7 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
final bool isSendAll;
|
||||
final bool hasChange;
|
||||
final bool hasTaprootInputs;
|
||||
final bool isViewOnly;
|
||||
List<UtxoWithAddress> utxos;
|
||||
bool isMweb;
|
||||
String? changeAddressOverride;
|
||||
@@ -49,6 +59,8 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
final Map<String, PublicKeyWithDerivationPath>? publicKeys;
|
||||
Future<void> Function()? commitOverride;
|
||||
|
||||
Uint8List? unsignedPsbt;
|
||||
|
||||
@override
|
||||
String get id => idOverride ?? _tx.txId();
|
||||
|
||||
@@ -89,9 +101,11 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
try {
|
||||
final change = _tx.outputs.firstWhere((out) => out.isChange);
|
||||
if (changeAddressOverride != null) {
|
||||
return PendingChange(changeAddressOverride!, BtcUtils.fromSatoshi(change.amount));
|
||||
return PendingChange(
|
||||
changeAddressOverride!, BtcUtils.fromSatoshi(change.amount));
|
||||
}
|
||||
return PendingChange(change.scriptPubKey.toAddress(), BtcUtils.fromSatoshi(change.amount));
|
||||
return PendingChange(
|
||||
change.scriptPubKey.toAddress(), BtcUtils.fromSatoshi(change.amount));
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
@@ -140,12 +154,14 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
|
||||
Future<void> _ltcCommit() async {
|
||||
try {
|
||||
final resp = await CwMweb.broadcast(BroadcastRequest(rawTx: BytesUtils.fromHexString(hex)));
|
||||
final resp = await CwMweb.broadcast(
|
||||
BroadcastRequest(rawTx: BytesUtils.fromHexString(hex)));
|
||||
idOverride = resp.txid;
|
||||
} on GrpcError catch (e) {
|
||||
throw BitcoinTransactionCommitFailed(errorMessage: e.message);
|
||||
} catch (e) {
|
||||
throw BitcoinTransactionCommitFailed(errorMessage: "Unknown error: ${e.toString()}");
|
||||
throw BitcoinTransactionCommitFailed(
|
||||
errorMessage: "Unknown error: ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +180,8 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
_listeners.forEach((listener) => listener(transactionInfo()));
|
||||
}
|
||||
|
||||
void addListener(void Function(ElectrumTransactionInfo transaction) listener) =>
|
||||
void addListener(
|
||||
void Function(ElectrumTransactionInfo transaction) listener) =>
|
||||
_listeners.add(listener);
|
||||
|
||||
ElectrumTransactionInfo transactionInfo() => ElectrumTransactionInfo(type,
|
||||
@@ -179,9 +196,40 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
inputAddresses: _tx.inputs.map((input) => input.txId).toList(),
|
||||
outputAddresses: outputAddresses,
|
||||
fee: fee);
|
||||
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
throw UnimplementedError();
|
||||
bool shouldCommitUR() => isViewOnly;
|
||||
|
||||
@override
|
||||
Future<Map<String, String>> commitUR() {
|
||||
var sourceBytes = unsignedPsbt!;
|
||||
var cborEncoder = CBOREncoder();
|
||||
cborEncoder.encodeBytes(sourceBytes);
|
||||
var ur = UR("psbt", cborEncoder.getBytes());
|
||||
var urLegacy = UR("crypto-psbt", cborEncoder.getBytes());
|
||||
// var ur = UR("psbt", Uint8List.fromList(List.generate(64*1024, (int x) => x % 256)));
|
||||
var encoded = UREncoder(ur, 120);
|
||||
var encodedLegacy = UREncoder(urLegacy, 120);
|
||||
List<String> values = [];
|
||||
List<String> valuesLegacy = [];
|
||||
while (!encoded.isComplete) {
|
||||
values.add(encoded.nextPart());
|
||||
valuesLegacy.add(encodedLegacy.nextPart());
|
||||
}
|
||||
|
||||
final bbqrObj = BBQRPsbt.fromUint8List(sourceBytes);
|
||||
List<String> bbqr = [
|
||||
bbqrObj.asString(),
|
||||
];
|
||||
while (!bbqrObj.isDone) {
|
||||
bbqrObj.next();
|
||||
bbqr.add(bbqrObj.asString());
|
||||
}
|
||||
|
||||
return Future.value({
|
||||
"PSBT (bcur)": values.join("\n"),
|
||||
"PSBT (bbqr)": bbqr.join("\n"),
|
||||
"PSBT (bcur legacy)": valuesLegacy.join("\n"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:convert/convert.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:ledger_bitcoin/psbt.dart';
|
||||
|
||||
@@ -9,7 +11,7 @@ class PSBTTransactionBuild {
|
||||
final PsbtV2 psbt = PsbtV2();
|
||||
|
||||
PSBTTransactionBuild(
|
||||
{required List<PSBTReadyUtxoWithAddress> inputs, required List<BitcoinBaseOutput> outputs, bool enableRBF = true}) {
|
||||
{required List<PSBTReadyUtxoWithAddress> inputs, required List<BitcoinBaseOutput> outputs, required List<OutputInfo> cwOutputs, bool enableRBF = true}) {
|
||||
psbt.setGlobalTxVersion(2);
|
||||
psbt.setGlobalInputCount(inputs.length);
|
||||
psbt.setGlobalOutputCount(outputs.length);
|
||||
@@ -24,7 +26,7 @@ class PSBTTransactionBuild {
|
||||
psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
|
||||
psbt.setInputOutputIndex(i, input.utxo.vout);
|
||||
psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff);
|
||||
|
||||
|
||||
|
||||
if (input.utxo.isSegwit()) {
|
||||
setInputSegwit(i, input);
|
||||
@@ -43,6 +45,33 @@ class PSBTTransactionBuild {
|
||||
if (output is BitcoinOutput) {
|
||||
psbt.setOutputScript(i, Uint8List.fromList(output.address.toScriptPubKey().toBytes()));
|
||||
psbt.setOutputAmount(i, output.value.toInt());
|
||||
if (cwOutputs.isNotEmpty) {
|
||||
try {
|
||||
final cwOutput = cwOutputs
|
||||
.where((e) => [e.address, e.extractedAddress]
|
||||
.map((e) => e?.toLowerCase())
|
||||
.contains(output.address.toAddress().toLowerCase()))
|
||||
.firstOrNull;
|
||||
if (cwOutput != null) {
|
||||
final bip353Name = utf8.encode(cwOutput.extra['bip353_name'] as String);
|
||||
final bip353Proof = base64.decode(cwOutput.extra['bip353_proof'] as String);
|
||||
|
||||
if (bip353Name.length > 255) {
|
||||
printV('BIP353 name is too long, skipping');
|
||||
continue;
|
||||
}
|
||||
final proof = Uint8List.fromList([
|
||||
bip353Name.length,
|
||||
...bip353Name,
|
||||
...bip353Proof,
|
||||
]);
|
||||
|
||||
psbt.setOutputDNSSECProof(i, proof);
|
||||
}
|
||||
} catch (e) {
|
||||
printV('Error setting DNSSEC proof: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,15 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
bbqrdart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: b0f3f72911221bafed0ab77359fccd64bc79d524
|
||||
resolved-ref: b0f3f72911221bafed0ab77359fccd64bc79d524
|
||||
url: "https://github.com/mrcyjanek/bbqrdart"
|
||||
source: git
|
||||
version: "1.0.0"
|
||||
bech32:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -588,8 +597,8 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/ledger-bitcoin"
|
||||
ref: trunk
|
||||
resolved-ref: e93254f3ff3f996fb91f65a1e7ceffb9f510b4c8
|
||||
ref: e8ab1a98493dfdd2277edde07a66b8d378ca70f6
|
||||
resolved-ref: e8ab1a98493dfdd2277edde07a66b8d378ca70f6
|
||||
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
||||
source: git
|
||||
version: "0.0.3"
|
||||
@@ -1101,6 +1110,15 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
ur:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "5738f70d0ec3d50977ac3dd01fed62939600238b"
|
||||
resolved-ref: "5738f70d0ec3d50977ac3dd01fed62939600238b"
|
||||
url: "https://github.com/bukata-sa/bc-ur-dart"
|
||||
source: git
|
||||
version: "0.1.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1182,5 +1200,5 @@ packages:
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
sdks:
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
dart: ">=3.6.2 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
|
||||
@@ -49,7 +49,7 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||
path: packages/ledger-bitcoin
|
||||
ref: trunk
|
||||
ref: e8ab1a98493dfdd2277edde07a66b8d378ca70f6
|
||||
ledger_litecoin:
|
||||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||
@@ -58,6 +58,14 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/sneurlax/socks_socket
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
ur:
|
||||
git:
|
||||
url: https://github.com/bukata-sa/bc-ur-dart
|
||||
ref: 5738f70d0ec3d50977ac3dd01fed62939600238b
|
||||
bbqrdart:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/bbqrdart
|
||||
ref: b0f3f72911221bafed0ab77359fccd64bc79d524
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -89,7 +89,7 @@ class PendingBitcoinCashTransaction with PendingTransaction {
|
||||
isReplaced: false,
|
||||
);
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ class OutputInfo {
|
||||
this.fiatAmount,
|
||||
this.note,
|
||||
this.extractedAddress,
|
||||
this.memo});
|
||||
this.memo,
|
||||
this.extra = const {}});
|
||||
|
||||
final String? fiatAmount;
|
||||
final String? cryptoAmount;
|
||||
@@ -19,4 +20,5 @@ class OutputInfo {
|
||||
final bool isParsedAddress;
|
||||
final int? formattedCryptoAmount;
|
||||
final String? memo;
|
||||
final Map<String, dynamic> extra;
|
||||
}
|
||||
@@ -18,5 +18,5 @@ mixin PendingTransaction {
|
||||
bool shouldCommitUR() => false;
|
||||
|
||||
Future<void> commit();
|
||||
Future<String?> commitUR();
|
||||
Future<Map<String, String>> commitUR();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class DecredPendingTransaction with PendingTransaction {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class PendingEVMChainTransaction with PendingTransaction {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,14 +354,23 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||
return retStatus;
|
||||
}
|
||||
|
||||
String exportOutputsUR(bool all) {
|
||||
final str = currentWallet!.exportOutputsUR(all: all);
|
||||
final status = currentWallet!.status();
|
||||
Map<String, String> exportOutputsUR() {
|
||||
final str = currentWallet!.exportOutputsUR(all: false);
|
||||
int status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = currentWallet!.errorString();
|
||||
throw MoneroTransactionCreationException("unable to export UR: $err");
|
||||
throw MoneroTransactionCreationException("unable to export outputs: $err");
|
||||
}
|
||||
return str;
|
||||
final strAll = currentWallet!.exportOutputsUR(all: true);
|
||||
status = currentWallet!.status();
|
||||
if (status != 0) {
|
||||
final err = currentWallet!.errorString();
|
||||
throw MoneroTransactionCreationException("unable to export outputs: $err");
|
||||
}
|
||||
return {
|
||||
"Outputs (partial)": str,
|
||||
"Outputs (all)": strAll,
|
||||
};
|
||||
}
|
||||
|
||||
bool needExportOutputs(int amount) {
|
||||
|
||||
@@ -42,6 +42,7 @@ class PendingMoneroTransaction with PendingTransaction {
|
||||
String get feeFormattedValue => AmountConverter.amountIntToString(
|
||||
CryptoCurrency.xmr, pendingTransactionDescription.fee);
|
||||
|
||||
@override
|
||||
bool shouldCommitUR() => isViewOnly;
|
||||
|
||||
@override
|
||||
@@ -67,7 +68,7 @@ class PendingMoneroTransaction with PendingTransaction {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() async {
|
||||
Future<Map<String, String>> commitUR() async {
|
||||
try {
|
||||
final ret = await monero_transaction_history.commitTransactionFromPointerAddress(
|
||||
address: pendingTransactionDescription.pointerAddress,
|
||||
@@ -77,7 +78,10 @@ class PendingMoneroTransaction with PendingTransaction {
|
||||
await Future.delayed(const Duration(milliseconds: 250));
|
||||
await wallet.fetchTransactions();
|
||||
}());
|
||||
return ret;
|
||||
if (ret == null) return {};
|
||||
return {
|
||||
"xmr-txsigned": ret,
|
||||
};
|
||||
} catch (e) {
|
||||
final message = e.toString();
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class PendingNanoTransaction with PendingTransaction {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class PendingSolanaTransaction with PendingTransaction {
|
||||
String get id => '';
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class PendingTronTransaction with PendingTransaction {
|
||||
String get id => '';
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class PendingWowneroTransaction with PendingTransaction {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class PendingZanoTransaction with PendingTransaction {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> commitUR() {
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ In order to build the latest version of Cake Wallet, simply run the following:
|
||||
git clone --branch main https://github.com/cake-tech/cake_wallet.git
|
||||
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
|
||||
cd cake_wallet
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly bash -x << EOF
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly bash -x << EOF
|
||||
set -x -e
|
||||
pushd scripts/android
|
||||
source ./app_env.sh cakewallet
|
||||
|
||||
@@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your iOS devi
|
||||
```txt
|
||||
macOS 15.3.1
|
||||
Xcode 16.2
|
||||
Flutter 3.27.0
|
||||
Flutter 3.27.4
|
||||
```
|
||||
|
||||
NOTE: Newer versions of macOS and Xcode may also work, but have not been confirmed to work by the Cake team.
|
||||
@@ -43,9 +43,9 @@ To enable iOS build support for Xcode, perform the following:
|
||||
|
||||
### 3. Installing Flutter
|
||||
|
||||
Install Flutter, specifically version `3.27.0` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
|
||||
NOTE: as `3.27.0` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
|
||||
### 4. Installing Rust
|
||||
|
||||
@@ -65,7 +65,7 @@ The output of this command should appear like this, indicating successful instal
|
||||
|
||||
```zsh
|
||||
Doctor summary (to see all details, run flutter doctor -v):
|
||||
[✓] Flutter (Channel stable, 3.27.0, on macOS 15.x.x)
|
||||
[✓] Flutter (Channel stable, 3.27.4, on macOS 15.x.x)
|
||||
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
|
||||
```
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ In order to build the latest version of Cake Wallet, simply run the following:
|
||||
git clone --branch main https://github.com/cake-tech/cake_wallet.git
|
||||
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
|
||||
cd cake_wallet
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run --privileged -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly bash -x << EOF
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run --privileged -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly bash -x << EOF
|
||||
set -x -e
|
||||
pushd scripts
|
||||
./gen_android_manifest.sh
|
||||
|
||||
@@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your macOS de
|
||||
```txt
|
||||
macOS 15.3.1
|
||||
Xcode 16.2
|
||||
Flutter 3.27.0
|
||||
Flutter 3.27.4
|
||||
```
|
||||
|
||||
### 1. Installing dependencies
|
||||
@@ -34,9 +34,9 @@ sudo xcodebuild -runFirstLaunch
|
||||
|
||||
### 3. Installing Flutter
|
||||
|
||||
Install Flutter, specifically version `3.27.0` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
|
||||
NOTE: as `3.27.0` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
|
||||
### 4. Installing Rust
|
||||
|
||||
@@ -56,7 +56,7 @@ The output of this command should appear like this, indicating successful instal
|
||||
|
||||
```zsh
|
||||
Doctor summary (to see all details, run flutter doctor -v):
|
||||
[✓] Flutter (Channel stable, 3.27.0, on macOS 15.x.x)
|
||||
[✓] Flutter (Channel stable, 3.27.4, on macOS 15.x.x)
|
||||
...
|
||||
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
|
||||
...
|
||||
|
||||
@@ -6,18 +6,18 @@ The following are the system requirements to build Cake Wallet for your Windows
|
||||
|
||||
```txt
|
||||
Windows 10 or later (64-bit), x86-64 based
|
||||
Flutter 3.27.0
|
||||
Flutter 3.27.4
|
||||
```
|
||||
|
||||
### 1. Installing Flutter
|
||||
|
||||
Install Flutter, specifically version `3.27.0` by following the [official docs](https://docs.flutter.dev/get-started/install/windows).
|
||||
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/windows).
|
||||
|
||||
In order for Flutter to function, you'll also need to enable Developer Mode:
|
||||
|
||||
Start Menu > search for "Run" > type `ms-settings:developers`, and turn on Developer Mode.
|
||||
|
||||
NOTE: as `3.27.0` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
|
||||
### 2. Install Development Tools
|
||||
|
||||
|
||||
@@ -18,6 +18,14 @@ class CWBitcoin extends Bitcoin {
|
||||
passphrase: passphrase,
|
||||
);
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinWalletFromKeys({
|
||||
required String name,
|
||||
required String password,
|
||||
required String xpub,
|
||||
}) =>
|
||||
BitcoinWalletFromKeysCredentials(name: name, password: password, xpub: xpub);
|
||||
|
||||
@override
|
||||
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
|
||||
{required String name,
|
||||
@@ -62,11 +70,7 @@ class CWBitcoin extends Bitcoin {
|
||||
final bitcoinWallet = wallet as ElectrumWallet;
|
||||
final keys = bitcoinWallet.keys;
|
||||
|
||||
return <String, String>{
|
||||
'wif': keys.wif,
|
||||
'privateKey': keys.privateKey,
|
||||
'publicKey': keys.publicKey
|
||||
};
|
||||
return bitcoinWallet.keys.toJson();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -126,7 +130,8 @@ class CWBitcoin extends Bitcoin {
|
||||
extractedAddress: out.extractedAddress,
|
||||
isParsedAddress: out.isParsedAddress,
|
||||
formattedCryptoAmount: out.formattedCryptoAmount,
|
||||
memo: out.memo))
|
||||
memo: out.memo,
|
||||
extra: out.extra))
|
||||
.toList(),
|
||||
priority: priority as BitcoinTransactionPriority,
|
||||
feeRate: bitcoinFeeRate,
|
||||
@@ -275,7 +280,14 @@ class CWBitcoin extends Bitcoin {
|
||||
}
|
||||
|
||||
@override
|
||||
List<ReceivePageOption> getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all;
|
||||
List<ReceivePageOption> getBitcoinReceivePageOptions(Object wallet) {
|
||||
final bitcoinWallet = wallet as ElectrumWallet;
|
||||
final keys = bitcoinWallet.keys;
|
||||
if (keys.privateKey.isEmpty) {
|
||||
return BitcoinReceivePageOption.allViewOnly;
|
||||
}
|
||||
return BitcoinReceivePageOption.all;
|
||||
}
|
||||
|
||||
@override
|
||||
List<ReceivePageOption> getLitecoinReceivePageOptions() {
|
||||
@@ -727,6 +739,12 @@ class CWBitcoin extends Bitcoin {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> commitPsbtUR(Object wallet, List<String> urCodes) {
|
||||
final _wallet = wallet as BitcoinWalletBase;
|
||||
return _wallet.commitPsbtUR(urCodes);
|
||||
}
|
||||
|
||||
@override
|
||||
String getPayjoinEndpoint(Object wallet) {
|
||||
final _wallet = wallet as ElectrumWallet;
|
||||
|
||||
@@ -978,7 +978,7 @@ Future<void> setup({
|
||||
|
||||
getIt.registerFactory(() => AnimatedURModel(getIt.get<AppStore>()));
|
||||
|
||||
getIt.registerFactoryParam<AnimatedURPage, String, void>((String urQr, _) =>
|
||||
getIt.registerFactoryParam<AnimatedURPage, Map<String, String>, void>((Map<String, String> urQr, _) =>
|
||||
AnimatedURPage(getIt.get<AnimatedURModel>(), urQr: urQr));
|
||||
|
||||
getIt.registerFactoryParam<ContactViewModel, ContactRecord?, void>(
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_picker_option.dart';
|
||||
@@ -5,6 +8,7 @@ import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:dnssec_proof/dnssec_proof.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Bip353Record {
|
||||
@@ -22,6 +26,19 @@ class Bip353Record {
|
||||
'address': 'On-Chain Address',
|
||||
};
|
||||
|
||||
static Future<String?> fetchDnsProof(String bip353Name) async {
|
||||
if (bip353Name.startsWith('₿')) {
|
||||
bip353Name = bip353Name.substring(1);
|
||||
}
|
||||
final parts = bip353Name.split('@');
|
||||
if (parts.length != 2) return null;
|
||||
final userPart = parts[0];
|
||||
final domainPart = parts[1];
|
||||
final bip353Domain = '$userPart.user._bitcoin-payment.$domainPart.';
|
||||
final proof = await Isolate.run(() => DnsProver.getTxtProof(bip353Domain));
|
||||
return base64.encode(proof);
|
||||
}
|
||||
|
||||
static Future<Map<String, String>?> fetchUriByCryptoCurrency(
|
||||
String bip353Name, String asset) async {
|
||||
try {
|
||||
@@ -30,7 +47,10 @@ class Bip353Record {
|
||||
|
||||
if (parts.length != 2) return null;
|
||||
|
||||
final userPart = parts[0];
|
||||
String userPart = parts[0];
|
||||
if (userPart.startsWith('₿')) {
|
||||
userPart = userPart.substring(1);
|
||||
}
|
||||
final domainPart = parts[1];
|
||||
|
||||
// 2. Construct the correct subdomain: "user._bitcoin-payment.domain"
|
||||
@@ -42,6 +62,10 @@ class Bip353Record {
|
||||
RRecordType.TXT,
|
||||
dnssec: true,
|
||||
);
|
||||
final proof = await fetchDnsProof(bip353Name);
|
||||
if (proof == null) {
|
||||
throw Exception('DNSSEC proof not found');
|
||||
}
|
||||
|
||||
if (txtRecords == null) return null;
|
||||
|
||||
|
||||
@@ -344,7 +344,13 @@ class AddressResolver {
|
||||
if (bip353AddressMap != null && bip353AddressMap.isNotEmpty) {
|
||||
final chosenAddress = await Bip353Record.pickBip353AddressChoice(context, text, bip353AddressMap);
|
||||
if (chosenAddress != null) {
|
||||
return ParsedAddress.fetchBip353AddressAddress(address: chosenAddress, name: text);
|
||||
try {
|
||||
final dnsProof = await Bip353Record.fetchDnsProof(text);
|
||||
return ParsedAddress.fetchBip353AddressAddress(address: chosenAddress, name: text, dnsProof: dnsProof);
|
||||
} catch (e) {
|
||||
printV('Bip353Record.fetchBip353AddressAddress error: $e');
|
||||
return ParsedAddress.fetchBip353AddressAddress(address: chosenAddress, name: text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class ParsedAddress {
|
||||
this.profileImageUrl = '',
|
||||
this.profileName = '',
|
||||
this.parseFrom = ParseFrom.notParsed,
|
||||
this.bip353DnsProof,
|
||||
});
|
||||
|
||||
factory ParsedAddress.fetchEmojiAddress({
|
||||
@@ -59,11 +60,13 @@ class ParsedAddress {
|
||||
factory ParsedAddress.fetchBip353AddressAddress ({
|
||||
required String address,
|
||||
required String name,
|
||||
String? dnsProof,
|
||||
}) {
|
||||
return ParsedAddress(
|
||||
addresses: [address],
|
||||
name: name,
|
||||
parseFrom: ParseFrom.bip353,
|
||||
bip353DnsProof: dnsProof,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -178,4 +181,5 @@ class ParsedAddress {
|
||||
final String profileImageUrl;
|
||||
final String profileName;
|
||||
final ParseFrom parseFrom;
|
||||
final String? bip353DnsProof;
|
||||
}
|
||||
|
||||
@@ -399,9 +399,9 @@ class CWMonero extends Monero {
|
||||
}
|
||||
|
||||
@override
|
||||
String exportOutputsUR(Object wallet, bool all) {
|
||||
Map<String, String> exportOutputsUR(Object wallet) {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
return moneroWallet.exportOutputsUR(all);
|
||||
return moneroWallet.exportOutputsUR();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -115,7 +115,8 @@ class QRWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
if (addressListViewModel.isPayjoinUnavailable &&
|
||||
!addressListViewModel.isSilentPayments) ...[
|
||||
!addressListViewModel.isSilentPayments &&
|
||||
!addressListViewModel.isCupcake) ...[
|
||||
GestureDetector(
|
||||
onTap: () => _onPayjoinInactivePressed(context),
|
||||
child: Row(
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/permission_handler.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
@@ -53,13 +54,40 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
||||
return true;
|
||||
}
|
||||
|
||||
String get imageRestoreHWPath =>
|
||||
widget.themeType == ThemeType.dark
|
||||
? 'assets/images/restore_hw_dark.png'
|
||||
: 'assets/images/restore_hw.png';
|
||||
|
||||
String get imageRestoreCupcakePath =>
|
||||
widget.themeType == ThemeType.dark
|
||||
? 'assets/images/restore_cupcake_dark.png'
|
||||
: 'assets/images/restore_cupcake.png';
|
||||
|
||||
String get imageRestoreQRPath =>
|
||||
widget.themeType == ThemeType.dark
|
||||
? 'assets/images/restore_qr_dark.png'
|
||||
: 'assets/images/restore_qr.png';
|
||||
|
||||
|
||||
String get imageRestoreHotWalletPath =>
|
||||
widget.themeType == ThemeType.dark
|
||||
? 'assets/images/restore_hot_wallet_dark.png'
|
||||
: 'assets/images/restore_hot_wallet.png';
|
||||
|
||||
|
||||
String get imageRestoreBackupPath =>
|
||||
widget.themeType == ThemeType.dark
|
||||
? 'assets/images/restore_backup_dark.png'
|
||||
: 'assets/images/restore_backup.png';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final imageColor = Theme.of(context).colorScheme.primary;
|
||||
final imageLedger = Image.asset('assets/images/hardware_wallet/ledger_nano_x.png',
|
||||
width: 40, color: imageColor);
|
||||
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png', color: imageColor);
|
||||
final imageBackup = Image.asset('assets/images/backup.png', color: imageColor);
|
||||
final imageRestoreHW = Image.asset(imageRestoreHWPath, width: 55);
|
||||
final imageRestoreCupcake = Image.asset(imageRestoreCupcakePath, width: 55);
|
||||
final imageRestoreQR = Image.asset(imageRestoreQRPath, width: 55);
|
||||
final imageSeedKeys = Image.asset(imageRestoreHotWalletPath, width: 55);
|
||||
final imageRestoreBackup = Image.asset(imageRestoreBackupPath, width: 55);
|
||||
|
||||
return Center(
|
||||
child: Container(
|
||||
@@ -76,15 +104,16 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
description: S.of(context).restore_description_from_seed_keys,
|
||||
),
|
||||
if (widget.isNewInstall)
|
||||
if (FeatureFlag.hasBitcoinViewOnly && DeviceInfo.instance.isMobile)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
key: ValueKey('restore_options_from_backup_button_key'),
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreFromBackup),
|
||||
image: imageBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
description: S.of(context).restore_description_from_backup,
|
||||
key: ValueKey('restore_options_from_cupcake_button_key'),
|
||||
onPressed: () => _onScanQRCode(context),
|
||||
image: imageRestoreCupcake,
|
||||
title: S.of(context).restore_title_from_cupcake,
|
||||
description: S.of(context).restore_description_from_cupcake,
|
||||
tag: S.of(context).new_tag,
|
||||
),
|
||||
),
|
||||
if (_doesSupportHardwareWallets)
|
||||
@@ -94,25 +123,33 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
|
||||
key: ValueKey('restore_options_from_hardware_wallet_button_key'),
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context, Routes.restoreWalletFromHardwareWallet),
|
||||
image: imageLedger,
|
||||
image: imageRestoreHW,
|
||||
title: S.of(context).restore_title_from_hardware_wallet,
|
||||
description: S.of(context).restore_description_from_hardware_wallet,
|
||||
),
|
||||
),
|
||||
if (widget.isNewInstall)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
key: ValueKey('restore_options_from_backup_button_key'),
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreFromBackup),
|
||||
image: imageRestoreBackup,
|
||||
title: S.of(context).restore_title_from_backup,
|
||||
description: S.of(context).restore_description_from_backup,
|
||||
),
|
||||
),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
key: ValueKey('restore_options_from_qr_button_key'),
|
||||
onPressed: () => _onScanQRCode(context),
|
||||
icon: Icon(
|
||||
Icons.qr_code_rounded,
|
||||
color: imageColor,
|
||||
size: 50,
|
||||
),
|
||||
image: imageRestoreQR,
|
||||
title: S.of(context).scan_qr_code,
|
||||
description: S.of(context).cold_or_recover_wallet),
|
||||
)
|
||||
description: S.of(context).cold_or_recover_wallet,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
|
||||
@@ -198,14 +198,14 @@ class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> {
|
||||
Widget _restoreFromKeysFormFields() {
|
||||
// Decred can only restore a view only wallet with an account pubkey. Other
|
||||
// fields are not used.
|
||||
if (widget.walletRestoreViewModel.type == WalletType.decred) {
|
||||
if (widget.walletRestoreViewModel.onlyViewKeyRestore) {
|
||||
return Column(
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
controller: viewKeyController,
|
||||
hintText: S.of(context).view_key_public,
|
||||
maxLines: null,
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -253,13 +253,14 @@ class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> {
|
||||
maxLines: null,
|
||||
),
|
||||
),
|
||||
BlockchainHeightWidget(
|
||||
key: blockchainHeightKey,
|
||||
hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven,
|
||||
onHeightChange: (_) => null,
|
||||
onHeightOrDateEntered: widget.onHeightOrDateEntered,
|
||||
walletType: widget.walletRestoreViewModel.type,
|
||||
),
|
||||
if (widget.walletRestoreViewModel.hasBlockchainHeightSelector)
|
||||
BlockchainHeightWidget(
|
||||
key: blockchainHeightKey,
|
||||
hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven,
|
||||
onHeightChange: (_) => null,
|
||||
onHeightOrDateEntered: widget.onHeightOrDateEntered,
|
||||
walletType: widget.walletRestoreViewModel.type,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ class WalletRestorePage extends BasePage {
|
||||
credentials['seed'] =
|
||||
walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text;
|
||||
|
||||
if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
|
||||
if (walletRestoreViewModel.hasBlockchainHeightSelector) {
|
||||
credentials['height'] =
|
||||
walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState?.height ??
|
||||
-1;
|
||||
@@ -219,7 +219,7 @@ class WalletRestorePage extends BasePage {
|
||||
credentials['name'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
|
||||
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
|
||||
if (walletRestoreViewModel.type != WalletType.decred) {
|
||||
if (!walletRestoreViewModel.onlyViewKeyRestore) {
|
||||
credentials['address'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['spendKey'] =
|
||||
@@ -519,7 +519,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
}
|
||||
},
|
||||
onViewKeyEntered: (bool entered) {
|
||||
if (walletRestoreViewModel.type == WalletType.decred) {
|
||||
if (widget.walletRestoreViewModel.onlyViewKeyRestore) {
|
||||
walletRestoreViewModel.isButtonEnabled = entered;
|
||||
}
|
||||
},
|
||||
@@ -536,7 +536,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
key: widget.walletRestoreFromSeedFormKey,
|
||||
restoredWallet: walletRestoreViewModel.restoredWallet,
|
||||
seedSettingsViewModel: widget.seedSettingsViewModel,
|
||||
displayBlockHeightSelector: widget.walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||
displayBlockHeightSelector: widget.walletRestoreViewModel.hasBlockchainHeightSelector,
|
||||
displayLanguageSelector: widget.walletRestoreViewModel.hasSeedLanguageSelector,
|
||||
type: widget.walletRestoreViewModel.type,
|
||||
blockHeightFocusNode: widget.blockHeightFocusNode,
|
||||
@@ -563,7 +563,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||
}
|
||||
|
||||
void _validateOnChange({bool isPolyseed = false}) {
|
||||
if (!isPolyseed && walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
|
||||
if (!isPolyseed && walletRestoreViewModel.hasBlockchainHeightSelector) {
|
||||
final hasHeight = walletRestoreFromSeedFormKey
|
||||
.currentState?.blockchainHeightKey.currentState?.restoreHeightController.text.isNotEmpty;
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ class SendPage extends BasePage {
|
||||
}
|
||||
if (monero!.needExportOutputs(sendViewModel.wallet, amount)) {
|
||||
await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage,
|
||||
arguments: 'export-outputs');
|
||||
arguments: monero!.exportOutputsUR(sendViewModel.wallet));
|
||||
await Future.delayed(
|
||||
Duration(seconds: 1)); // wait for monero to refresh the state
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bbqrdart/bbqrdart.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
@@ -7,31 +9,49 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/animated_ur_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
// ur:xmr-txunsigned - unsigned transaction
|
||||
// should show a scanner afterwards.
|
||||
|
||||
class AnimatedURPage extends BasePage {
|
||||
final bool isAll;
|
||||
AnimatedURPage(this.animatedURmodel, {required String urQr, this.isAll = false}) {
|
||||
if (urQr == "export-outputs") {
|
||||
this.urQr = monero!.exportOutputsUR(animatedURmodel.wallet, false);
|
||||
} else if (urQr == "export-outputs-all") {
|
||||
this.urQr = monero!.exportOutputsUR(animatedURmodel.wallet, true);
|
||||
} else {
|
||||
this.urQr = urQr;
|
||||
AnimatedURPage(this.animatedURmodel, {
|
||||
required Map<String, String> this.urQr,
|
||||
this.isAll = false,
|
||||
}) {
|
||||
if (urQr.keys.first.startsWith("export-outputs") && animatedURmodel.wallet.type == WalletType.monero) {
|
||||
if (animatedURmodel.wallet.type == WalletType.monero) {
|
||||
urQr = monero!.exportOutputsUR(animatedURmodel.wallet);
|
||||
} else {
|
||||
throw UnimplementedError("unable to handle UR: ${urQr.keys.first}");
|
||||
}
|
||||
}
|
||||
for (var key in urQr.keys) {
|
||||
if (key.isEmpty || urQr[key]!.isEmpty) {
|
||||
urQr.remove(key);
|
||||
continue;
|
||||
}
|
||||
urQr[key] = urQr[key]!.trim();
|
||||
}
|
||||
}
|
||||
|
||||
late String urQr;
|
||||
Map<String, String> urQr = {};
|
||||
|
||||
|
||||
final AnimatedURModel animatedURmodel;
|
||||
|
||||
String get urQrType {
|
||||
final first = urQr.trim().split("\n")[0];
|
||||
if (urQr.values.first.trim().substring(0, 2) == BBQR.header) {
|
||||
return BBQR.header;
|
||||
}
|
||||
if (urQr.isEmpty) return "unknown";
|
||||
final first = urQr.values.first.trim().split("\n")[0];
|
||||
return first.split('/')[0];
|
||||
}
|
||||
|
||||
@@ -43,11 +63,11 @@ class AnimatedURPage extends BasePage {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 64.0),
|
||||
child: URQR(
|
||||
frames: urQr.trim().split("\n"),
|
||||
urqr: urQr,
|
||||
),
|
||||
),
|
||||
if (["ur:xmr-txunsigned", "ur:xmr-output", "ur:psbt", BBQR.header].contains(urQrType)) ...{
|
||||
SizedBox(height: 32),
|
||||
if (urQrType == "ur:xmr-txunsigned" || urQrType == "ur:xmr-output")
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: SizedBox(
|
||||
@@ -60,30 +80,8 @@ class AnimatedURPage extends BasePage {
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 32),
|
||||
if (urQrType == "ur:xmr-output" && !isAll) Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: PrimaryButton(
|
||||
onPressed: () => _exportAll(context),
|
||||
text: "Export all",
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _exportAll(BuildContext context) {
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return AnimatedURPage(animatedURmodel, urQr: "export-outputs-all", isAll: true);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,6 +104,11 @@ class AnimatedURPage extends BasePage {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
break;
|
||||
case "ur:psbt": // psbt
|
||||
final ur = await presentQRScanner(context);
|
||||
if (ur == null) return;
|
||||
await bitcoin!.commitPsbtUR(animatedURmodel.wallet, ur.trim().split("\n"));
|
||||
Navigator.of(context).pop(true);
|
||||
default:
|
||||
throw UnimplementedError("unable to handle UR: ${urQrType}");
|
||||
}
|
||||
@@ -124,9 +127,9 @@ class AnimatedURPage extends BasePage {
|
||||
}
|
||||
|
||||
class URQR extends StatefulWidget {
|
||||
URQR({super.key, required this.frames});
|
||||
URQR({super.key, required this.urqr});
|
||||
|
||||
List<String> frames;
|
||||
final Map<String, String> urqr;
|
||||
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
@@ -160,6 +163,24 @@ class _URQRState extends State<URQR> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
late String selected = (widget.urqr.isEmpty) ? "unknown" : widget.urqr.keys.first;
|
||||
int selectedInt = 0;
|
||||
|
||||
List<String> get frames {
|
||||
return widget.urqr[selected]?.split("\n") ?? [];
|
||||
}
|
||||
|
||||
late String nextLabel = widget.urqr.keys.toList()[(selectedInt + 1) % widget.urqr.length] ;
|
||||
|
||||
void next() {
|
||||
final keys = widget.urqr.keys.toList();
|
||||
setState(() {
|
||||
selectedInt++;
|
||||
nextLabel = keys[(selectedInt + 1) % keys.length];
|
||||
selected = keys[(selectedInt) % keys.length];
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
@@ -168,10 +189,37 @@ class _URQRState extends State<URQR> {
|
||||
children: [
|
||||
Center(
|
||||
child: QrImage(
|
||||
data: widget.frames[frame % widget.frames.length], version: -1,
|
||||
data: frames[frame % frames.length],
|
||||
version: -1,
|
||||
size: 400,
|
||||
),
|
||||
),
|
||||
if (widget.urqr.values.length > 1)
|
||||
SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: PrimaryButton(
|
||||
onPressed: next,
|
||||
text: nextLabel,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (FeatureFlag.hasDevOptions) ...{
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: """Current frame (${frame % frames.length}): ${frames[frame % frames.length]},
|
||||
All frames:
|
||||
- ${frames.join("\n - ")}"""));
|
||||
},
|
||||
child: Text("[dev] copy debug info"),
|
||||
),
|
||||
}
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class _WalletKeysPageBodyState extends State<WalletKeysPageBody>
|
||||
showLegacySeedTab = widget.walletKeysViewModel.legacySeedSplit.isNotEmpty;
|
||||
isLegacySeedOnly = widget.walletKeysViewModel.isLegacySeedOnly;
|
||||
|
||||
final totalTabs = 1 + (showKeyTab ? 1 : 0) + (showLegacySeedTab ? 1 : 0);
|
||||
final totalTabs = (_hasSeeds ? 1 : 0) + (showKeyTab ? 1 : 0) + (showLegacySeedTab ? 1 : 0);
|
||||
|
||||
_tabController = TabController(length: totalTabs, vsync: this);
|
||||
}
|
||||
@@ -126,7 +126,7 @@ class _WalletKeysPageBodyState extends State<WalletKeysPageBody>
|
||||
dividerColor: Colors.transparent,
|
||||
padding: EdgeInsets.zero,
|
||||
tabs: [
|
||||
Tab(text: S.of(context).widgets_seed, key: ValueKey('wallet_keys_page_seed')),
|
||||
if (_hasSeeds) Tab(text: S.of(context).widgets_seed, key: ValueKey('wallet_keys_page_seed')),
|
||||
if (showKeyTab) Tab(text: S.of(context).keys, key: ValueKey('wallet_keys_page_keys'),),
|
||||
if (showLegacySeedTab) Tab(text: S.of(context).legacy, key: ValueKey('wallet_keys_page_seed_legacy')),
|
||||
],
|
||||
@@ -137,10 +137,11 @@ class _WalletKeysPageBodyState extends State<WalletKeysPageBody>
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 22, right: 22),
|
||||
child: _buildSeedTab(context, false),
|
||||
),
|
||||
if (_hasSeeds)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 22, right: 22),
|
||||
child: _buildSeedTab(context, false),
|
||||
),
|
||||
if (showKeyTab)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 22, right: 22),
|
||||
|
||||
@@ -7,6 +7,7 @@ class OptionTile extends StatelessWidget {
|
||||
this.icon,
|
||||
required this.title,
|
||||
required this.description,
|
||||
this.tag,
|
||||
super.key,
|
||||
}) : assert(image != null || icon != null);
|
||||
|
||||
@@ -15,6 +16,7 @@ class OptionTile extends StatelessWidget {
|
||||
final Icon? icon;
|
||||
final String title;
|
||||
final String description;
|
||||
final String? tag;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -36,25 +38,34 @@ class OptionTile extends StatelessWidget {
|
||||
icon ?? image!,
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 220),
|
||||
child: Text(title, style: Theme.of(context).textTheme.titleMedium),
|
||||
),
|
||||
if (tag != null) Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 5),
|
||||
margin: EdgeInsets.only(left: 5),
|
||||
child: Text(tag!))
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
description,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -45,7 +45,7 @@ class SettingActions {
|
||||
name: (context) => S.of(context).export_outputs,
|
||||
image: 'assets/images/monero_menu.png',
|
||||
onTap: (BuildContext context) {
|
||||
Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: 'export-outputs');
|
||||
Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: {'export-outputs': 'export-outputs'});
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -9,4 +9,5 @@ class FeatureFlag {
|
||||
static final bool isInAppTorEnabled = (Platform.isAndroid);
|
||||
static const int verificationWordsCount = kDebugMode ? 0 : 2;
|
||||
static const bool hasDevOptions = bool.fromEnvironment('hasDevOptions', defaultValue: kDebugMode);
|
||||
static const bool hasBitcoinViewOnly = true;
|
||||
}
|
||||
|
||||
@@ -536,7 +536,10 @@ abstract class DashboardViewModelBase with Store {
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get hasSilentPayments => wallet.type == WalletType.bitcoin && !wallet.isHardwareWallet;
|
||||
bool get hasSilentPayments =>
|
||||
wallet.type == WalletType.bitcoin &&
|
||||
(bitcoin!.getWalletKeys(wallet)["privateKey"] ?? "").isNotEmpty &&
|
||||
!wallet.isHardwareWallet;
|
||||
|
||||
@computed
|
||||
bool get showSilentPaymentsCard => hasSilentPayments && settingsStore.silentPaymentsCardDisplay;
|
||||
|
||||
@@ -22,7 +22,7 @@ abstract class ReceiveOptionViewModelBase with Store {
|
||||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
_options = [
|
||||
...bitcoin!.getBitcoinReceivePageOptions(),
|
||||
...bitcoin!.getBitcoinReceivePageOptions(_wallet),
|
||||
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
|
||||
];
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,7 @@ class RestoredWallet {
|
||||
|
||||
factory RestoredWallet.fromKey(Map<String, dynamic> json) {
|
||||
try {
|
||||
final codeParsed = jsonDecode(json['raw_qr'].toString());
|
||||
final codeParsed = jsonDecode(json['raw_qr'].toString());
|
||||
if (codeParsed["version"] == 0) {
|
||||
json['address'] = codeParsed["primaryAddress"];
|
||||
json['view_key'] = codeParsed["privateViewKey"];
|
||||
@@ -44,6 +44,7 @@ class RestoredWallet {
|
||||
} catch (e) {
|
||||
// fine, we don't care, it is only for monero anyway
|
||||
}
|
||||
json['view_key'] ??= json['xpub'];
|
||||
final height = json['height'] as String?;
|
||||
return RestoredWallet(
|
||||
restoreMode: json['mode'] as WalletRestoreMode,
|
||||
@@ -51,7 +52,7 @@ class RestoredWallet {
|
||||
address: json['address'] as String?,
|
||||
spendKey: json['spend_key'] as String?,
|
||||
viewKey: json['view_key'] as String?,
|
||||
height: height != null ? int.tryParse(height)??0 : 0,
|
||||
height: height != null ? int.tryParse(height) ?? 0 : 0,
|
||||
privateKey: json['private_key'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ class WalletRestoreFromQRCode {
|
||||
|
||||
final extracted = sortedKeys.firstWhereOrNull((key) => code.toLowerCase().contains(key));
|
||||
|
||||
if (code.startsWith("xpub")) return WalletType.bitcoin;
|
||||
|
||||
if (extracted == null) {
|
||||
// Special case for view-only monero wallet
|
||||
try {
|
||||
@@ -117,11 +119,15 @@ class WalletRestoreFromQRCode {
|
||||
|
||||
formattedUri = seedPhrase != null
|
||||
? '$walletType:?seed=$seedPhrase'
|
||||
: throw Exception('Failed to determine valid seed phrase');
|
||||
: code.startsWith('xpub')
|
||||
? '$walletType:?xpub=$code'
|
||||
: throw Exception('Failed to determine valid seed phrase');
|
||||
} else {
|
||||
final index = code.indexOf(':');
|
||||
final query = code.substring(index + 1).replaceAll('?', '&');
|
||||
formattedUri = '$walletType:?$query';
|
||||
formattedUri = code.startsWith('xpub')
|
||||
? '$walletType:?xpub=$code'
|
||||
:'$walletType:?$query';
|
||||
}
|
||||
|
||||
final uri = Uri.parse(formattedUri);
|
||||
@@ -158,6 +164,10 @@ class WalletRestoreFromQRCode {
|
||||
throw Exception('Unexpected restore mode: tx_payment_id is invalid');
|
||||
}
|
||||
|
||||
if (credentials.containsKey("xpub")) {
|
||||
return WalletRestoreMode.keys;
|
||||
}
|
||||
|
||||
if (credentials['seed'] != null) {
|
||||
final seedValue = credentials['seed'] as String;
|
||||
final words = SeedValidator.getWordList(type: type, language: 'english');
|
||||
|
||||
@@ -289,6 +289,15 @@ abstract class OutputBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> get extra {
|
||||
final fields = <String, dynamic>{};
|
||||
if (parsedAddress.parseFrom == ParseFrom.bip353) {
|
||||
fields['bip353_name'] = parsedAddress.name;
|
||||
fields['bip353_proof'] = parsedAddress.bip353DnsProof;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
void _setCryptoNumMaximumFractionDigits() {
|
||||
var maximumFractionDigits = 0;
|
||||
|
||||
|
||||
@@ -603,6 +603,11 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||
bool get isSilentPayments =>
|
||||
wallet.type == WalletType.bitcoin && bitcoin!.hasSelectedSilentPayments(wallet);
|
||||
|
||||
@computed
|
||||
bool get isCupcake =>
|
||||
wallet.type == WalletType.bitcoin &&
|
||||
(bitcoin!.getWalletKeys(wallet)["privateKey"] ?? "").isEmpty;
|
||||
|
||||
@computed
|
||||
bool get isAutoGenerateSubaddressEnabled =>
|
||||
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled &&
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
@@ -162,18 +163,21 @@ abstract class WalletKeysViewModelBase with Store {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||
|
||||
items.addAll([
|
||||
if ((keys['wif']??'').isNotEmpty)
|
||||
StandartListItem(title: "WIF", value: keys['wif']!),
|
||||
if ((keys['privateKey']??'').isNotEmpty)
|
||||
StandartListItem(title: S.current.private_key, value: keys['privateKey']!),
|
||||
if (keys['publicKey'] != null)
|
||||
StandartListItem(title: S.current.public_key, value: keys['publicKey']!),
|
||||
if (keys['xpub'] != null)
|
||||
StandartListItem(title: "xPub", value: keys['xpub']!),
|
||||
]);
|
||||
break;
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||
//
|
||||
// items.addAll([
|
||||
// if (keys['wif'] != null)
|
||||
// StandartListItem(title: "WIF", value: keys['wif']!),
|
||||
// if (keys['privateKey'] != null)
|
||||
// StandartListItem(title: S.current.private_key, value: keys['privateKey']!),
|
||||
// if (keys['publicKey'] != null)
|
||||
// StandartListItem(title: S.current.public_key, value: keys['publicKey']!),
|
||||
// ]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/decred/decred.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
@@ -32,17 +33,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource, SeedSettingsViewModel seedSettingsViewModel,
|
||||
{required WalletType type, this.restoredWallet})
|
||||
: hasSeedLanguageSelector =
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
|
||||
hasBlockchainHeightLanguageSelector =
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
|
||||
hasRestoreFromPrivateKey = type == WalletType.ethereum ||
|
||||
type == WalletType.polygon ||
|
||||
type == WalletType.nano ||
|
||||
type == WalletType.banano ||
|
||||
type == WalletType.solana ||
|
||||
type == WalletType.tron,
|
||||
isButtonEnabled = false,
|
||||
: isButtonEnabled = restoredWallet != null,
|
||||
hasPassphrase = false,
|
||||
mode = restoredWallet?.restoreMode ?? WalletRestoreMode.seed,
|
||||
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
|
||||
@@ -60,9 +51,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
case WalletType.decred:
|
||||
case WalletType.bitcoin:
|
||||
availableModes = [WalletRestoreMode.seed, WalletRestoreMode.keys];
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.zano:
|
||||
@@ -82,9 +73,32 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
static const decredSeedMnemonicLength = 15;
|
||||
|
||||
late List<WalletRestoreMode> availableModes;
|
||||
final bool hasSeedLanguageSelector;
|
||||
final bool hasBlockchainHeightLanguageSelector;
|
||||
final bool hasRestoreFromPrivateKey;
|
||||
late final bool hasSeedLanguageSelector = [
|
||||
WalletType.monero,
|
||||
WalletType.haven,
|
||||
WalletType.wownero
|
||||
].contains(type);
|
||||
|
||||
late final bool hasBlockchainHeightSelector = [
|
||||
WalletType.monero,
|
||||
WalletType.haven,
|
||||
WalletType.wownero
|
||||
].contains(type);
|
||||
|
||||
late final bool hasRestoreFromPrivateKey = [
|
||||
WalletType.ethereum,
|
||||
WalletType.polygon,
|
||||
WalletType.nano,
|
||||
WalletType.banano,
|
||||
WalletType.solana,
|
||||
WalletType.tron
|
||||
].contains(type);
|
||||
|
||||
late final bool onlyViewKeyRestore = [
|
||||
if (FeatureFlag.hasBitcoinViewOnly) WalletType.bitcoin,
|
||||
WalletType.decred
|
||||
].contains(type);
|
||||
|
||||
final RestoredWallet? restoredWallet;
|
||||
|
||||
@observable
|
||||
@@ -198,6 +212,13 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
final address = options['address'] as String?;
|
||||
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinWalletFromKeys(
|
||||
name: name,
|
||||
password: password,
|
||||
xpub: viewKey!,
|
||||
);
|
||||
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
@@ -276,8 +297,9 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||
case WalletType.litecoin:
|
||||
String? mnemonic = credentials['seed'] as String?;
|
||||
String? passphrase = credentials['passphrase'] as String?;
|
||||
if (mnemonic == null) break;
|
||||
return bitcoin!.getDerivationsFromMnemonic(
|
||||
mnemonic: mnemonic!,
|
||||
mnemonic: mnemonic,
|
||||
node: node,
|
||||
passphrase: passphrase,
|
||||
);
|
||||
|
||||
@@ -130,6 +130,18 @@ dependencies:
|
||||
url: https://github.com/MrCyjaneK/flutter_daemon
|
||||
ref: c24ee99f2f3070ea02d8108bbdd7727d73f7e5f1
|
||||
flutter_local_notifications: ^19.0.0
|
||||
ur:
|
||||
git:
|
||||
url: https://github.com/bukata-sa/bc-ur-dart
|
||||
ref: 5738f70d0ec3d50977ac3dd01fed62939600238b
|
||||
bbqrdart:
|
||||
git:
|
||||
url: https://github.com/mrcyjanek/bbqrdart
|
||||
ref: b0f3f72911221bafed0ab77359fccd64bc79d524
|
||||
dnssec_proof:
|
||||
git:
|
||||
url: https://github.com/MrCyjaneK/dnssec_proof.git
|
||||
ref: a2b0bdac343afc14fc38dfb81f28147eab50be05
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "اختر ممثلًا جديدًا",
|
||||
"nanogpt_subtitle": "جميع النماذج الأحدث (GPT-4 ، Claude). \\ nno اشتراك ، ادفع مع Crypto.",
|
||||
"narrow": "ضيق",
|
||||
"new_tag": "جديد",
|
||||
"new_first_wallet_text": "الحفاظ على سلامة التشفير الخاص بك هو قطعة من الكعكة",
|
||||
"new_node_testing": "تجربة العقدة الجديدة",
|
||||
"new_subaddress_create": "إنشاء",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "قم باستعادة محفظتك من كود مكون من 24 كلمة",
|
||||
"restore_bitcoin_title_from_keys": "استعادة من WIF",
|
||||
"restore_description_from_backup": "يمكنك استعادة تطبيق Cake Wallet بالكامل من ملف النسخ الاحتياطي",
|
||||
"restore_description_from_cupcake": "ارتباط بتطبيقنا المصاحب للهواء ، مثبتًا على هاتف ثانٍ.",
|
||||
"restore_description_from_hardware_wallet": "استعادة من محفظة أجهزة دفتر الأستاذ",
|
||||
"restore_description_from_keys": "قم باستعادة محفظتك من ضغطات المفاتيح المولدة المحفوظة من مفاتيحك الخاصة",
|
||||
"restore_description_from_seed": "قم باستعادة محفظتك من الرمز المكون من 25 كلمة أو 13 كلمة",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "استعادة السييد / المفاتيح",
|
||||
"restore_spend_key_private": "مفتاح الإنفاق (خاص)",
|
||||
"restore_title_from_backup": "استعادة من النسخة الاحتياطية",
|
||||
"restore_title_from_cupcake": "تطبيق كب كيك",
|
||||
"restore_title_from_hardware_wallet": "استعادة من محفظة الأجهزة",
|
||||
"restore_title_from_keys": "استعادة من المفاتيح",
|
||||
"restore_title_from_seed": "استعادة من السييد",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "تحويل من",
|
||||
"youCanGoBackToYourDapp": "يمكنك العودة إلى DAPP الخاص بك الآن",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Изберете нов представител",
|
||||
"nanogpt_subtitle": "Всички най-нови модели (GPT-4, Claude). \\ Nno абонамент, платете с Crypto.",
|
||||
"narrow": "Тесен",
|
||||
"new_tag": "Ново",
|
||||
"new_first_wallet_text": "Запазването на криптовалутата ви е парче торта",
|
||||
"new_node_testing": "Тестване на нов node",
|
||||
"new_subaddress_create": "Създаване",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Възстановяване на портфейл чрез код от 24 думи",
|
||||
"restore_bitcoin_title_from_keys": "Възстановяване от WIF",
|
||||
"restore_description_from_backup": "Можете да възстановите цялото приложение Cake Wallet от своя резервен файл",
|
||||
"restore_description_from_cupcake": "Връзка с нашето придружително приложение за въздух, инсталирано на втори телефон.",
|
||||
"restore_description_from_hardware_wallet": "Възстановяване от хардуерния портфейл на главната книга",
|
||||
"restore_description_from_keys": "Възстановяване на портфейл от генерираните от Вашите тайни ключове клавиши",
|
||||
"restore_description_from_seed": "Възстановяване на портфейл от кода от 13 или 25 думи",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Възстановяне от Seed/Keys",
|
||||
"restore_spend_key_private": "Spend key (публичен)",
|
||||
"restore_title_from_backup": "Възстановяване от резервно копие",
|
||||
"restore_title_from_cupcake": "Приложение за кекс",
|
||||
"restore_title_from_hardware_wallet": "Възстановяване от хардуерния портфейл",
|
||||
"restore_title_from_keys": "Възстановяване от keys",
|
||||
"restore_title_from_seed": "Възстановяване от seed",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "Обръщане от",
|
||||
"youCanGoBackToYourDapp": "Можете да се върнете при вашия Dapp сега",
|
||||
"yy": "гг"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Vyberte nového zástupce",
|
||||
"nanogpt_subtitle": "Všechny nejnovější modely (GPT-4, Claude). \\ Nno předplatné, plaťte krypto.",
|
||||
"narrow": "Úzký",
|
||||
"new_tag": "Nový",
|
||||
"new_first_wallet_text": "Udržování svého kryptového v bezpečí je kus dortu",
|
||||
"new_node_testing": "Testování nového uzlu",
|
||||
"new_subaddress_create": "Vytvořit",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Obnovte svou peněženku pomocí kombinace 24 slov",
|
||||
"restore_bitcoin_title_from_keys": "Obnovit z WIF",
|
||||
"restore_description_from_backup": "Můžete obnovit celou Cake Wallet aplikaci ze souboru se zálohou",
|
||||
"restore_description_from_cupcake": "Odkaz na naši doprovodnou aplikaci Air-mezerou nainstalovanou na druhém telefonu.",
|
||||
"restore_description_from_hardware_wallet": "Obnovit z peněženky hardwaru knihy",
|
||||
"restore_description_from_keys": "Obnovte svou peněženku pomocí generovaných stisků kláves uložených z vašich soukromých klíčů",
|
||||
"restore_description_from_seed": "Obnovte svou peněženku pomocí kombinace 25, nebo 13 slov",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Obnovit ze seedu/klíčů",
|
||||
"restore_spend_key_private": "Klíč pro platby (soukromý)",
|
||||
"restore_title_from_backup": "Obnovit ze zálohy",
|
||||
"restore_title_from_cupcake": "Cupcake App",
|
||||
"restore_title_from_hardware_wallet": "Obnovit z hardwarové peněženky",
|
||||
"restore_title_from_keys": "Obnovit z klíčů",
|
||||
"restore_title_from_seed": "Obnovit ze seedu",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "Směnit z",
|
||||
"youCanGoBackToYourDapp": "Nyní se můžete vrátit do svého dappu",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Wählen Sie einen neuen Vertreter aus",
|
||||
"nanogpt_subtitle": "Alle neuesten Modelle (GPT-4, Claude).",
|
||||
"narrow": "Eng",
|
||||
"new_tag": "Neu",
|
||||
"new_first_wallet_text": "Wenn Sie Ihren Krypto schützen, ist ein Kinderspiel",
|
||||
"new_node_testing": "Neuen Knoten testen",
|
||||
"new_subaddress_create": "Erstellen",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Stellen Sie Ihre Wallet aus dem 24-Wort-Kombinationscode wieder her",
|
||||
"restore_bitcoin_title_from_keys": "Aus WIF wiederherstellen",
|
||||
"restore_description_from_backup": "Sie können die gesamte Cake Wallet-App aus Ihrer Sicherungsdatei wiederherstellen",
|
||||
"restore_description_from_cupcake": "Links mit unserer air-gapped Begleitapp, die auf einem zweiten Telefon installiert ist.",
|
||||
"restore_description_from_hardware_wallet": "Stellen Sie eine Wallet von Ledger wieder her",
|
||||
"restore_description_from_keys": "Stellen Sie Ihr Wallet aus generierten Tastenanschlägen her, die von Ihren privaten Schlüsseln gespeichert wurden",
|
||||
"restore_description_from_seed": "Stellen Sie Ihre Wallet aus den 25 Wörtern oder dem 13-Wort-Kombinationscode wieder her",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Seed/Schlüssel wiederherstellen",
|
||||
"restore_spend_key_private": "Spend Key (geheim)",
|
||||
"restore_title_from_backup": "Aus einer Sicherungsdatei wiederherstellen",
|
||||
"restore_title_from_cupcake": "Cupcake App",
|
||||
"restore_title_from_hardware_wallet": "Von Hardware-Wallet wiederherstellen",
|
||||
"restore_title_from_keys": "Aus Schlüsseln wiederherstellen",
|
||||
"restore_title_from_seed": "Aus Seed wiederherstellen",
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Pick a new representative",
|
||||
"nanogpt_subtitle": "All the newest models (GPT-4, Claude).\\nNo subscription, pay with crypto.",
|
||||
"narrow": "Narrow",
|
||||
"new_tag": "New",
|
||||
"new_first_wallet_text": "Keeping your crypto safe is a piece of cake",
|
||||
"new_node_testing": "New node testing",
|
||||
"new_subaddress_create": "Create",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Restore your wallet from 24 word combination code",
|
||||
"restore_bitcoin_title_from_keys": "Restore from WIF",
|
||||
"restore_description_from_backup": "You can restore the whole Cake Wallet app from your back-up file",
|
||||
"restore_description_from_cupcake": "Link with our companion air-gapped app, installed on a second phone.",
|
||||
"restore_description_from_hardware_wallet": "Restore from a Ledger hardware wallet",
|
||||
"restore_description_from_keys": "Restore your wallet from generated keystrokes saved from your private keys",
|
||||
"restore_description_from_seed": "Restore your wallet from either the 25 word or 13 word combination code",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Seed/Keys Restore",
|
||||
"restore_spend_key_private": "Spend key (private)",
|
||||
"restore_title_from_backup": "Restore from backup",
|
||||
"restore_title_from_cupcake": "Cupcake App",
|
||||
"restore_title_from_hardware_wallet": "Restore from hardware wallet",
|
||||
"restore_title_from_keys": "Restore from keys",
|
||||
"restore_title_from_seed": "Restore from seed",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "Convert from",
|
||||
"youCanGoBackToYourDapp": "You can go back to your dApp now",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Elija un nuevo representante",
|
||||
"nanogpt_subtitle": "Todos los modelos más nuevos (GPT-4, Claude). \\nSin suscripción, pague con cripto.",
|
||||
"narrow": "Angosto",
|
||||
"new_tag": "Nuevo",
|
||||
"new_first_wallet_text": "Mantener su criptografía a salvo es un pedazo de pastel",
|
||||
"new_node_testing": "Prueba nuevos nodos",
|
||||
"new_subaddress_create": "Crear",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Restaure su billetera a partir del código de combinación de 24 palabras",
|
||||
"restore_bitcoin_title_from_keys": "Restaurar desde WIF",
|
||||
"restore_description_from_backup": "Puede restaurar toda la aplicación Cake Wallet desde ysu archivo de respaldo",
|
||||
"restore_description_from_cupcake": "Enlace con nuestra aplicación complementaria de Airpaped, instalada en un segundo teléfono.",
|
||||
"restore_description_from_hardware_wallet": "Restaurar desde una billetera de hardware Ledger",
|
||||
"restore_description_from_keys": "Restaure su billetera de las pulsaciones de teclas generadas guardadas de sus claves privadas",
|
||||
"restore_description_from_seed": "Restaure su billetera desde el código de combinación de 25 palabras i de 13 palabras",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Restauración de semillas / llaves",
|
||||
"restore_spend_key_private": "Llave de gasto (privada)",
|
||||
"restore_title_from_backup": "Restaurar desde un archivo de respaldo",
|
||||
"restore_title_from_cupcake": "Aplicación de cupcakes",
|
||||
"restore_title_from_hardware_wallet": "Restaurar desde una cartera fría",
|
||||
"restore_title_from_keys": "Usando las claves",
|
||||
"restore_title_from_seed": "Usando la semilla",
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Choisissez un nouveau représentant",
|
||||
"nanogpt_subtitle": "Tous les modèles les plus récents (GPT-4, Claude).\nPas d'abonnement, payez avec vos crypto-monnaies.",
|
||||
"narrow": "Rédruit",
|
||||
"new_tag": "Nouveau",
|
||||
"new_first_wallet_text": "Garder vos crypto-monnaies en sécurité est un jeu d'enfant.",
|
||||
"new_node_testing": "Test du nouveau nœud",
|
||||
"new_subaddress_create": "Créer",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Restaurer votre portefeuille (wallet) à l'aide d'une phrase secrète (seed) de 24 mots",
|
||||
"restore_bitcoin_title_from_keys": "Restaurer à partir de WIF",
|
||||
"restore_description_from_backup": "Vous pouvez restaurer l'intégralité de l'application Cake Wallet depuis un fichier de sauvegarde",
|
||||
"restore_description_from_cupcake": "Lien avec notre application complémentaire à air, installée sur un deuxième téléphone.",
|
||||
"restore_description_from_hardware_wallet": "Restaurer depuis un portefeuille matériel Ledger",
|
||||
"restore_description_from_keys": "Restaurer votre portefeuille (wallet) d'après les séquences de touches générées d'après vos clefs privées",
|
||||
"restore_description_from_seed": "Restaurer votre portefeuille (wallet) depuis une phrase secrète (seed) de 25 ou 13 mots",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Restaurer depuis Phrase secrète (seed)/Clefs",
|
||||
"restore_spend_key_private": "Clef de dépense (spend key) (privée)",
|
||||
"restore_title_from_backup": "Restaurer depuis une sauvegarde",
|
||||
"restore_title_from_cupcake": "Application de cupcake",
|
||||
"restore_title_from_hardware_wallet": "Restaurer à partir du portefeuille matériel",
|
||||
"restore_title_from_keys": "Restaurer depuis des clefs",
|
||||
"restore_title_from_seed": "Restaurer depuis une phrase secrète (seed)",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "Convertir depuis",
|
||||
"youCanGoBackToYourDapp": "Vous pouvez retourner à votre Dapp maintenant",
|
||||
"yy": "AA"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Dauki sabon wakili",
|
||||
"nanogpt_subtitle": "Duk sabbin samfuran (GPT-4, CLODE). \\ NNO biyan kuɗi, biya tare da crypto.",
|
||||
"narrow": "kunkuntar",
|
||||
"new_tag": "Sabo",
|
||||
"new_first_wallet_text": "Tsayawa kayatar da lafiya",
|
||||
"new_node_testing": "Sabbin gwajin kumburi",
|
||||
"new_subaddress_create": "Ƙirƙiri",
|
||||
@@ -689,6 +690,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Dawo da kwalinku daga 24 lambar haɗin kalma",
|
||||
"restore_bitcoin_title_from_keys": "Dawo daga WIF",
|
||||
"restore_description_from_backup": "Kuna iya dawo da duk aikace-aikacen Wallet ɗin Cake daga fayil ɗin ajiyar ku",
|
||||
"restore_description_from_cupcake": "Haɗi tare da App na Aikace-aikacen Babi na Aikace-aikacen, shigar a kan wayar ta biyu.",
|
||||
"restore_description_from_hardware_wallet": "Maidowa da walatware mai wanki",
|
||||
"restore_description_from_keys": "Maido da walat ɗin ku daga maɓallan maɓalli da aka ƙera da aka ajiye daga maɓallan ku na sirri",
|
||||
"restore_description_from_seed": "Dawo da kwalinku daga 25 ko 13 lambar haɗin kalma",
|
||||
@@ -703,6 +705,7 @@
|
||||
"restore_seed_keys_restore": "Mayar da iri/Maɓallai",
|
||||
"restore_spend_key_private": "Maɓallin kashewa (key kalmar sirri)",
|
||||
"restore_title_from_backup": "Dawo daga madadin",
|
||||
"restore_title_from_cupcake": "Appoake App",
|
||||
"restore_title_from_hardware_wallet": "Dawowa daga walatware mai wuya",
|
||||
"restore_title_from_keys": "Dawo daga maɓallai",
|
||||
"restore_title_from_seed": "Maidowa daga iri",
|
||||
@@ -1128,4 +1131,4 @@
|
||||
"you_will_send": "Maida daga",
|
||||
"youCanGoBackToYourDapp": "Kuna iya komawa zuwa DPP ɗinku yanzu",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "एक नया प्रतिनिधि चुनें",
|
||||
"nanogpt_subtitle": "सभी नवीनतम मॉडल (GPT-4, क्लाउड)। \\ nno सदस्यता, क्रिप्टो के साथ भुगतान करें।",
|
||||
"narrow": "सँकरा",
|
||||
"new_tag": "नया",
|
||||
"new_first_wallet_text": "अपने क्रिप्टो को सुरक्षित रखना केक का एक टुकड़ा है",
|
||||
"new_node_testing": "नई नोड परीक्षण",
|
||||
"new_subaddress_create": "सर्जन करना",
|
||||
@@ -689,6 +690,7 @@
|
||||
"restore_bitcoin_description_from_seed": "24 शब्द संयोजन कोड से अपने वॉलेट को पुनर्स्थापित करें",
|
||||
"restore_bitcoin_title_from_keys": "WIF से पुनर्स्थापित करें",
|
||||
"restore_description_from_backup": "आप से पूरे केक वॉलेट एप्लिकेशन को पुनर्स्थापित कर सकते हैं आपकी बैक-अप फ़ाइल",
|
||||
"restore_description_from_cupcake": "एक दूसरे फोन पर इंस्टॉल किए गए हमारे साथी एयर-गपड़ी ऐप के साथ लिंक।",
|
||||
"restore_description_from_hardware_wallet": "एक लेजर हार्डवेयर वॉलेट से पुनर्स्थापित करें",
|
||||
"restore_description_from_keys": "अपने वॉलेट को जेनरेट से पुनर्स्थापित करें आपकी निजी कुंजी से कीस्ट्रोक्स सहेजे गए",
|
||||
"restore_description_from_seed": "या तो 25 शब्द से अपने वॉलेट को पुनर्स्थापित करें या 13 शब्द संयोजन कोड",
|
||||
@@ -703,6 +705,7 @@
|
||||
"restore_seed_keys_restore": "बीज / कुंजी पुनर्स्थापित करें",
|
||||
"restore_spend_key_private": "कुंजी खर्च करें (निजीe)",
|
||||
"restore_title_from_backup": "बैक-अप फ़ाइल से पुनर्स्थापित करें",
|
||||
"restore_title_from_cupcake": "कपकेक ऐप",
|
||||
"restore_title_from_hardware_wallet": "हार्डवेयर वॉलेट से पुनर्स्थापित करें",
|
||||
"restore_title_from_keys": "कुंजी से पुनर्स्थापित करें",
|
||||
"restore_title_from_seed": "बीज से पुनर्स्थापित करें",
|
||||
@@ -1127,4 +1130,4 @@
|
||||
"you_will_send": "से रूपांतरित करें",
|
||||
"youCanGoBackToYourDapp": "अब आप अपने DAPP पर वापस जा सकते हैं",
|
||||
"yy": "वाईवाई"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Odaberite novog predstavnika",
|
||||
"nanogpt_subtitle": "Svi najnoviji modeli (GPT-4, Claude). \\ NNO pretplata, plaćajte kripto.",
|
||||
"narrow": "Usko",
|
||||
"new_tag": "Novi",
|
||||
"new_first_wallet_text": "Čuvanje kriptovaluta je komad torte",
|
||||
"new_node_testing": "Provjera novog nodea",
|
||||
"new_subaddress_create": "Izradi",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Oporavi novčanik pomoću koda od 12 riječi",
|
||||
"restore_bitcoin_title_from_keys": "Oporavi pomoću formata uvoza novčanika (WIF)",
|
||||
"restore_description_from_backup": "Možete oporaviti cijelu Cake Wallet aplikaciju pomoću vlastite datoteke sa sigurnosnom kopijom",
|
||||
"restore_description_from_cupcake": "Link s našom pratećom aplikacijom koja se bavi zrakom, instaliranom na drugi telefon.",
|
||||
"restore_description_from_hardware_wallet": "Vratite se iz novčanice od knjige",
|
||||
"restore_description_from_keys": "Oporavi novčanik pomoću generiranih pritisaka na tipke spremljenih od vlastitih privatnih ključeva (keys)",
|
||||
"restore_description_from_seed": "Oporavi novčanik pomoću koda koji sadrži kombinaciju od 25 ili 13 riječi",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Oporavak pomoću pristupnog izraza/ključa",
|
||||
"restore_spend_key_private": "Spend key (privatni)",
|
||||
"restore_title_from_backup": "Oporavak pomoću sigurnosne kopije",
|
||||
"restore_title_from_cupcake": "Cupcake App",
|
||||
"restore_title_from_hardware_wallet": "Vrati iz hardverskog novčanika",
|
||||
"restore_title_from_keys": "Oporavi pomoću ključa",
|
||||
"restore_title_from_seed": "Oporavi pomoću pristupnog izraza",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "Razmijeni iz",
|
||||
"youCanGoBackToYourDapp": "Sada se možete vratiti na svoj dapp",
|
||||
"yy": "GG"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Ընտրեք նոր ներկայացուցիչ",
|
||||
"nanogpt_subtitle": "Բոլոր ամենանոր մոդելներ (GPT-4, Claude).\\nԱռանց բաժանորդագրության, վճարեք կրիպտոարժույթով",
|
||||
"narrow": "Նեղ",
|
||||
"new_tag": "Նոր",
|
||||
"new_first_wallet_text": "Ձեր ծպտյալ անվտանգ պահելը տորթի մի կտոր է",
|
||||
"new_node_testing": "Նոր հանգույցի փորձարկում",
|
||||
"new_subaddress_create": "Ստեղծել",
|
||||
@@ -686,6 +687,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Վերականգնեք ձեր դրամապանակը 24 բառերի համադրությամբ",
|
||||
"restore_bitcoin_title_from_keys": "Վերականգնել WIF-ից",
|
||||
"restore_description_from_backup": "Դուք կարող եք վերականգնել ամբողջ Cake Wallet հավելվածը ձեր կրկնօրինակ ֆայլից",
|
||||
"restore_description_from_cupcake": "Հղում մեր ուղեկից օդային բացված ծրագրի հետ, տեղադրված երկրորդ հեռախոսով:",
|
||||
"restore_description_from_hardware_wallet": "Վերականգնեք Ledger հարդվերային դրամապանակից",
|
||||
"restore_description_from_keys": "Վերականգնեք ձեր դրամապանակը ձեր գախտնի բանալիների հիման վրա ստեղծված մուտքագրումներից",
|
||||
"restore_description_from_seed": "Վերականգնեք ձեր դրամապպանակը 25 բառերի կամ 13 բառերի համադրությամբ",
|
||||
@@ -700,6 +702,7 @@
|
||||
"restore_seed_keys_restore": "Սերմ/բանալիներ վերականգնել",
|
||||
"restore_spend_key_private": "Վճարման բանալի (գախտնի)",
|
||||
"restore_title_from_backup": "Վերականգնել կրկնօրինակ ֆայլից",
|
||||
"restore_title_from_cupcake": "Cupcake ծրագիրը",
|
||||
"restore_title_from_hardware_wallet": "Վերականգնել հարդվերային դրամապանակից",
|
||||
"restore_title_from_keys": "Վերականգնել բանալիներից",
|
||||
"restore_title_from_seed": "Վերականգնել սերմից",
|
||||
@@ -1123,4 +1126,4 @@
|
||||
"you_will_send": "Փոխանակեք",
|
||||
"youCanGoBackToYourDapp": "Այժմ կարող եք վերադառնալ ձեր DAPP- ին",
|
||||
"yy": "ՏՏ"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Pilih perwakilan baru",
|
||||
"nanogpt_subtitle": "Semua model terbaru (GPT-4, Claude). \\ Nno langganan, bayar dengan crypto.",
|
||||
"narrow": "Sempit",
|
||||
"new_tag": "Baru",
|
||||
"new_first_wallet_text": "Menjaga crypto Anda aman adalah sepotong kue",
|
||||
"new_node_testing": "Pengujian node baru",
|
||||
"new_subaddress_create": "Buat",
|
||||
@@ -689,6 +690,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Pulihkan dompet Anda dari kombinasi kode 24 kata",
|
||||
"restore_bitcoin_title_from_keys": "Pulihkan dari WIF",
|
||||
"restore_description_from_backup": "Anda dapat memulihkan seluruh aplikasi Cake Wallet dari file cadangan Anda",
|
||||
"restore_description_from_cupcake": "Tautkan dengan aplikasi pendamping udara kami, diinstal pada telepon kedua.",
|
||||
"restore_description_from_hardware_wallet": "Kembalikan dari dompet perangkat keras Ledger",
|
||||
"restore_description_from_keys": "Pulihkan dompet Anda dari tombol yang dihasilkan yang disimpan dari kunci pribadi Anda",
|
||||
"restore_description_from_seed": "Pulihkan dompet Anda dari kombinasi kode 25 atau 13 kata",
|
||||
@@ -704,6 +706,7 @@
|
||||
"restore_seed_keys_restore": "Pulihkan Seed/Kunci",
|
||||
"restore_spend_key_private": "Habiskan kunci (pribadi)",
|
||||
"restore_title_from_backup": "Pulihkan dari cadangan",
|
||||
"restore_title_from_cupcake": "Aplikasi Cupcake",
|
||||
"restore_title_from_hardware_wallet": "Kembalikan dari dompet perangkat keras",
|
||||
"restore_title_from_keys": "Pulihkan dari kunci",
|
||||
"restore_title_from_seed": "Pulihkan dari seed",
|
||||
@@ -1128,4 +1131,4 @@
|
||||
"you_will_send": "Konversi dari",
|
||||
"youCanGoBackToYourDapp": "Anda dapat kembali ke dapp Anda sekarang",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Scegli un nuovo rappresentante",
|
||||
"nanogpt_subtitle": "Tutti i modelli più recenti (GPT-4, Claude). Nessun abbonamento, paga con cripto.",
|
||||
"narrow": "Stretto",
|
||||
"new_tag": "Nuovo",
|
||||
"new_first_wallet_text": "Mantenere la tua criptovaluta è un gioco da ragazzi",
|
||||
"new_node_testing": "Test novo nodo",
|
||||
"new_subaddress_create": "Crea",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Recupera il tuo portafoglio da una combinazione di 12 parole",
|
||||
"restore_bitcoin_title_from_keys": "Recupera da WIF",
|
||||
"restore_description_from_backup": "Puoi recuperare l'app Cake Wallet per intero dal tuo file di backup",
|
||||
"restore_description_from_cupcake": "Collegamento con la nostra app per gap ad aria accompagnata, installata su un secondo telefono.",
|
||||
"restore_description_from_hardware_wallet": "Ripristina da un portafoglio hardware Ledger",
|
||||
"restore_description_from_keys": "Recupera il tuo portafoglio da una sequenza di caratteri generati dalle tue chiavi private",
|
||||
"restore_description_from_seed": "Recupera il tuo portafoglio da una combinazione di 25 o 13 parole",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Recupera Seme/Chiavi",
|
||||
"restore_spend_key_private": "Chiave di Spesa (privata)",
|
||||
"restore_title_from_backup": "Recupera da backup",
|
||||
"restore_title_from_cupcake": "App Cupcake",
|
||||
"restore_title_from_hardware_wallet": "Ripristina dal portafoglio hardware",
|
||||
"restore_title_from_keys": "Recupera dalle chiavi",
|
||||
"restore_title_from_seed": "Recupera dal seme",
|
||||
@@ -1128,4 +1131,4 @@
|
||||
"you_will_send": "Conveti da",
|
||||
"youCanGoBackToYourDapp": "Puoi tornare al tuo DApp ora",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
"nano_pick_new_rep": "新しい代表者を選びます",
|
||||
"nanogpt_subtitle": "すべての最新モデル(GPT-4、Claude)。\\ nnoサブスクリプション、暗号で支払います。",
|
||||
"narrow": "狭い",
|
||||
"new_tag": "新しい",
|
||||
"new_first_wallet_text": "暗号を安全に保つことはケーキです",
|
||||
"new_node_testing": "新しいノードのテスト",
|
||||
"new_subaddress_create": "作成する",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "24ワードの組み合わせコードからウォレットを復元する",
|
||||
"restore_bitcoin_title_from_keys": "WIFから復元",
|
||||
"restore_description_from_backup": "Cake Walletアプリ全体を復元できますバックアップファイル",
|
||||
"restore_description_from_cupcake": "2番目の電話にインストールされたコンパニオンギャップアプリにリンクします。",
|
||||
"restore_description_from_hardware_wallet": "元帳ハードウェアウォレットから復元します",
|
||||
"restore_description_from_keys": "生成されたウォレットを復元します秘密鍵から保存されたキーストローク",
|
||||
"restore_description_from_seed": "25ワードからウォレットを復元しますまたは13ワードの組み合わせコード",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "シード/キーの復元",
|
||||
"restore_spend_key_private": "キーを使う (プライベート)",
|
||||
"restore_title_from_backup": "バックアップファイルから復元する",
|
||||
"restore_title_from_cupcake": "カップケーキアプリ",
|
||||
"restore_title_from_hardware_wallet": "ハードウェアウォレットから復元します",
|
||||
"restore_title_from_keys": "キーから復元する",
|
||||
"restore_title_from_seed": "シードから復元",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "から変換",
|
||||
"youCanGoBackToYourDapp": "あなたは今あなたのダップに戻ることができます",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "새 대표자 선택",
|
||||
"nanogpt_subtitle": "모든 최신 모델 (GPT-4, Claude).\n구독 없이 암호화폐로 결제.",
|
||||
"narrow": "좁게",
|
||||
"new_tag": "새로운",
|
||||
"new_first_wallet_text": "암호화폐를 안전하게 보관하는 것은 식은 죽 먹기",
|
||||
"new_node_testing": "새 노드 테스트 중",
|
||||
"new_subaddress_create": "생성",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "24단어 조합 코드로 지갑 복구",
|
||||
"restore_bitcoin_title_from_keys": "WIF에서 복구",
|
||||
"restore_description_from_backup": "백업 파일에서 전체 Cake Wallet 앱을 복구할 수 있습니다",
|
||||
"restore_description_from_cupcake": "두 번째 전화에 설치된 동반자 에어 갭 앱과 링크하십시오.",
|
||||
"restore_description_from_hardware_wallet": "Ledger 하드웨어 지갑에서 복구",
|
||||
"restore_description_from_keys": "개인 키에서 저장된 키 입력으로 지갑 복구",
|
||||
"restore_description_from_seed": "25단어 또는 13단어 조합 코드로 지갑 복구",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "시드/키 복구",
|
||||
"restore_spend_key_private": "지출 키 (개인)",
|
||||
"restore_title_from_backup": "백업에서 복구",
|
||||
"restore_title_from_cupcake": "컵 케이크 앱",
|
||||
"restore_title_from_hardware_wallet": "하드웨어 지갑에서 복구",
|
||||
"restore_title_from_keys": "키에서 복구",
|
||||
"restore_title_from_seed": "시드에서 복구",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "전환 출처",
|
||||
"youCanGoBackToYourDapp": "이제 dApp으로 돌아갈 수 있습니다",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "အသစ်တစ်ခုကိုရွေးပါ",
|
||||
"nanogpt_subtitle": "အားလုံးနောက်ဆုံးပေါ်မော်ဒယ်များ (GPT-4, Claude) ။ \\ nno subscription, crypto နှင့်အတူပေးဆောင်။",
|
||||
"narrow": "ကျဉ်းသော",
|
||||
"new_tag": "သစ်သော",
|
||||
"new_first_wallet_text": "သင်၏ Crypto Safe ကိုလုံခြုံအောင်ပြုလုပ်ခြင်းသည်ကိတ်မုန့်တစ်မျိုးဖြစ်သည်",
|
||||
"new_node_testing": "နှာခေါင်း အသစ်စမ်းသပ်ခြင်း။",
|
||||
"new_subaddress_create": "ဖန်တီးပါ။",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "24 စကားလုံးပေါင်းစပ်ကုဒ်မှ သင့်ပိုက်ဆံအိတ်ကို ပြန်ယူပါ။",
|
||||
"restore_bitcoin_title_from_keys": "WIF မှ ပြန်လည်ရယူပါ။",
|
||||
"restore_description_from_backup": "သင့်အရန်ဖိုင်မှ Cake Wallet အက်ပ်တစ်ခုလုံးကို သင်ပြန်လည်ရယူနိုင်သည်။",
|
||||
"restore_description_from_cupcake": "ဒုတိယဖုန်းတွင်တပ်ဆင်ထားသောကျွန်ုပ်တို့၏အဖော် Air-Gensess App နှင့်ချိတ်ဆက်ပါ။",
|
||||
"restore_description_from_hardware_wallet": "Ledger ဟာ့ဒ်ဝဲပိုက်ဆံအိတ်မှ Restore",
|
||||
"restore_description_from_keys": "သင့်ကိုယ်ပိုင်သော့များမှ သိမ်းဆည်းထားသော ထုတ်ပေးထားသော သော့ချက်များမှ သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူပါ။",
|
||||
"restore_description_from_seed": "25 စကားလုံး သို့မဟုတ် 13 စကားလုံးပေါင်းစပ်ကုဒ်မှ သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူပါ။",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "မျိုးစေ့/သော့များ ပြန်လည်ရယူပါ။",
|
||||
"restore_spend_key_private": "သော့သုံးရန် (သီးသန့်)",
|
||||
"restore_title_from_backup": "အရန်သိမ်းခြင်းမှ ပြန်လည်ရယူပါ။",
|
||||
"restore_title_from_cupcake": "Cupcake app",
|
||||
"restore_title_from_hardware_wallet": "ဟာ့ဒ်ဝဲပိုက်ဆံအိတ်မှ restore",
|
||||
"restore_title_from_keys": "သော့များမှ ပြန်လည်ရယူပါ။",
|
||||
"restore_title_from_seed": "မျိုးစေ့မှပြန်လည်ရယူပါ။",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "မှပြောင်းပါ။",
|
||||
"youCanGoBackToYourDapp": "သငျသညျယခုသင်၏ dapp ကိုပြန်သွားနိုင်ပါတယ်",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Kies een nieuwe vertegenwoordiger",
|
||||
"nanogpt_subtitle": "Alle nieuwste modellen (GPT-4, Claude). \\ Nno-abonnement, betalen met crypto.",
|
||||
"narrow": "Smal",
|
||||
"new_tag": "Nieuw",
|
||||
"new_first_wallet_text": "Je crypto veilig houden is een fluitje van een cent",
|
||||
"new_node_testing": "Nieuwe knooppunttest",
|
||||
"new_subaddress_create": "Creëren",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Herstel uw portemonnee met een combinatiecode van 24 woorden",
|
||||
"restore_bitcoin_title_from_keys": "Herstel van WIF",
|
||||
"restore_description_from_backup": "Je kunt de hele Cake Wallet-app herstellen van uw back-upbestand",
|
||||
"restore_description_from_cupcake": "Link met onze bijbehorende air-happed-app, geïnstalleerd op een tweede telefoon.",
|
||||
"restore_description_from_hardware_wallet": "Herstel van een grootboekhardware -portemonnee",
|
||||
"restore_description_from_keys": "Herstel uw portemonnee van gegenereerd toetsaanslagen opgeslagen van uw privésleutels",
|
||||
"restore_description_from_seed": "Herstel uw portemonnee van het 25 woord of 13 woord combinatiecode",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Zaad / sleutels herstellen",
|
||||
"restore_spend_key_private": "Sleutel uitgeven (privaat)",
|
||||
"restore_title_from_backup": "Herstellen vanuit een back-upbestand",
|
||||
"restore_title_from_cupcake": "Cupcake -app",
|
||||
"restore_title_from_hardware_wallet": "Herstel van de hardware -portemonnee",
|
||||
"restore_title_from_keys": "Herstel van sleutels",
|
||||
"restore_title_from_seed": "Herstel van zaad",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "Converteren van",
|
||||
"youCanGoBackToYourDapp": "U kunt nu terug naar uw DApp gaan",
|
||||
"yy": "JJ"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Wybierz nowego przedstawiciela",
|
||||
"nanogpt_subtitle": "Wszystkie najnowsze modele (GPT-4, Claude). \\ Nno subskrypcja, płacą za pomocą kryptografii.",
|
||||
"narrow": "Wąski",
|
||||
"new_tag": "Nowy",
|
||||
"new_first_wallet_text": "Zachowanie bezpieczeństwa kryptograficznego jest kawałkiem ciasta",
|
||||
"new_node_testing": "Testowanie nowych węzłów",
|
||||
"new_subaddress_create": "Stwórz",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Przywróć swój portfel z frazy seed złożonej z 24 słów",
|
||||
"restore_bitcoin_title_from_keys": "Przywróć z klucza prywatnego",
|
||||
"restore_description_from_backup": "Możesz przywrócić całą aplikację Cake Wallet z pliku kopii zapasowej",
|
||||
"restore_description_from_cupcake": "Połącz z naszą towarzyszącą aplikacją powietrzną, zainstalowaną na drugim telefonie.",
|
||||
"restore_description_from_hardware_wallet": "Przywróć z portfela sprzętowego księgi",
|
||||
"restore_description_from_keys": "Przywróć swój portfel z kluczy prywatnych",
|
||||
"restore_description_from_seed": "Przywróć swój portfel z 25 lub 13-słownej frazy seed",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Przywracanie z frazy seed / kluczy",
|
||||
"restore_spend_key_private": "Podaj prywatny klucz wglądu (view key)",
|
||||
"restore_title_from_backup": "Przywróć z pliku kopii zapasowej",
|
||||
"restore_title_from_cupcake": "Aplikacja Cupcake",
|
||||
"restore_title_from_hardware_wallet": "Przywróć z portfela sprzętowego",
|
||||
"restore_title_from_keys": "Przywróć z kluczy",
|
||||
"restore_title_from_seed": "Przywróć z frazy seed",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "Konwertuj z",
|
||||
"youCanGoBackToYourDapp": "Możesz teraz wrócić do swojego dapp",
|
||||
"yy": "RR"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
"nano_pick_new_rep": "Escolha um novo representante",
|
||||
"nanogpt_subtitle": "Todos os modelos mais recentes (GPT-4, Claude). \\nSem assinatura, pague com criptomoeda.",
|
||||
"narrow": "Estreito",
|
||||
"new_tag": "Novo",
|
||||
"new_first_wallet_text": "Manter sua cripto segura é um pedaço de bolo",
|
||||
"new_node_testing": "Teste de novo nó",
|
||||
"new_subaddress_create": "Criar",
|
||||
@@ -689,6 +690,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Restaure sua carteira a partir de um código de combinação de 24 palavras",
|
||||
"restore_bitcoin_title_from_keys": "Restaurar de WIF",
|
||||
"restore_description_from_backup": "Você pode restaurar todo o aplicativo Cake Wallet de seu arquivo de backup",
|
||||
"restore_description_from_cupcake": "Link para nosso aplicativo Companion Air-Gapped, instalado em um segundo telefone.",
|
||||
"restore_description_from_hardware_wallet": "Restaurar de uma carteira de hardware do Ledger",
|
||||
"restore_description_from_keys": "Restaure sua carteira a partir de suas chaves privadas",
|
||||
"restore_description_from_seed": "Restaure sua carteira a partir de semente com 25 palavras ou 13 palavras",
|
||||
@@ -703,6 +705,7 @@
|
||||
"restore_seed_keys_restore": "Restauração com sementes/chaves",
|
||||
"restore_spend_key_private": "Chave de gastos (privada)",
|
||||
"restore_title_from_backup": "Restaurar a partir de um arquivo de backup",
|
||||
"restore_title_from_cupcake": "Aplicativo de cupcake",
|
||||
"restore_title_from_hardware_wallet": "Restaurar da carteira de hardware",
|
||||
"restore_title_from_keys": "Restaurar a partir de chaves",
|
||||
"restore_title_from_seed": "Restaurar a partir de semente",
|
||||
@@ -1128,4 +1131,4 @@
|
||||
"you_will_send": "Converter de",
|
||||
"youCanGoBackToYourDapp": "Você pode voltar para o seu dapp agora",
|
||||
"yy": "aa"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Выберите нового представителя",
|
||||
"nanogpt_subtitle": "Все новейшие модели (GPT-4, Claude). \\ Nno Подписка, платите с крипто.",
|
||||
"narrow": "Узкий",
|
||||
"new_tag": "Новый",
|
||||
"new_first_wallet_text": "Сохранение вашего криптографии - это кусок торта",
|
||||
"new_node_testing": "Тестирование новой ноды",
|
||||
"new_subaddress_create": "Создать",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Вы можете восстановить кошелёк используя 24-ти значную мнемоническую фразу",
|
||||
"restore_bitcoin_title_from_keys": "Восстановить с помощью WIF",
|
||||
"restore_description_from_backup": "Вы можете восстановить Cake Wallet из вашего back-up файла",
|
||||
"restore_description_from_cupcake": "Ссылка с нашим приложением с авиакомпаниями, установленным на втором телефоне.",
|
||||
"restore_description_from_hardware_wallet": "Восстановите из оборудования",
|
||||
"restore_description_from_keys": "Вы можете восстановить кошелёк с помощью приватных ключей",
|
||||
"restore_description_from_seed": "Вы можете восстановить кошелёк используя 25-ти значную мнемоническую фразу",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Восстановить из мнемонической фразы/ключей",
|
||||
"restore_spend_key_private": "Приватный ключ траты",
|
||||
"restore_title_from_backup": "Восстановить из back-up файла",
|
||||
"restore_title_from_cupcake": "Приложение кекса",
|
||||
"restore_title_from_hardware_wallet": "Восстановить из аппаратного кошелька",
|
||||
"restore_title_from_keys": "Восстановить с помощью ключей",
|
||||
"restore_title_from_seed": "Восстановить из мнемонической фразы",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "Конвертировать из",
|
||||
"youCanGoBackToYourDapp": "Вы можете вернуться к своему даппу сейчас",
|
||||
"yy": "ГГ"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "เลือกตัวแทนใหม่",
|
||||
"nanogpt_subtitle": "รุ่นใหม่ล่าสุดทั้งหมด (GPT-4, Claude). การสมัครสมาชิก \\ nno, จ่ายด้วย crypto",
|
||||
"narrow": "แคบ",
|
||||
"new_tag": "ใหม่",
|
||||
"new_first_wallet_text": "การรักษา crypto ของคุณให้ปลอดภัยเป็นเค้กชิ้นหนึ่ง",
|
||||
"new_node_testing": "การทดสอบโหนดใหม่",
|
||||
"new_subaddress_create": "สร้าง",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "กู้กระเป๋าของคุณจากรหัสผสมของ 24 คำ",
|
||||
"restore_bitcoin_title_from_keys": "กู้จาก WIF",
|
||||
"restore_description_from_backup": "คุณสามารถกู้แอพ Cake Wallet ทั้งหมดจากไฟล์สำรองข้อมูลของคุณ",
|
||||
"restore_description_from_cupcake": "เชื่อมโยงกับแอพที่มี Gapped Air-Gapped ของเราติดตั้งบนโทรศัพท์เครื่องที่สอง",
|
||||
"restore_description_from_hardware_wallet": "กู้คืนจากกระเป๋าเงินฮาร์ดแวร์บัญชีแยกประเภท",
|
||||
"restore_description_from_keys": "กู้กระเป๋าของคุณจากการกดปุ่มที่สร้างขึ้นจาก private keys ของคุณที่บันทึกไว้",
|
||||
"restore_description_from_seed": "กู้กระเป๋าของคุณจากรหัสผสมของ 25 คำหรือ 13 คำ",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "กู้จาก Seed/Keys",
|
||||
"restore_spend_key_private": "คีย์สำหรับใช้ (ส่วนตัว)",
|
||||
"restore_title_from_backup": "กู้จากการสำรองข้อมูล",
|
||||
"restore_title_from_cupcake": "แอพคัพเค้ก",
|
||||
"restore_title_from_hardware_wallet": "กู้คืนจากกระเป๋าเงินฮาร์ดแวร์",
|
||||
"restore_title_from_keys": "กู้จาก keys",
|
||||
"restore_title_from_seed": "กู้จาก seed",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "แปลงจาก",
|
||||
"youCanGoBackToYourDapp": "คุณสามารถกลับไปที่ dapp ของคุณได้ทันที",
|
||||
"yy": "ปี"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Pumili ng isang bagong representative",
|
||||
"nanogpt_subtitle": "Ang lahat ng mga pinakabagong modelo (GPT-4, Claude). \nNo subscription, magbayad gamit ang crypto.",
|
||||
"narrow": "Makitid",
|
||||
"new_tag": "Bago",
|
||||
"new_first_wallet_text": "Ang pagpapanatiling ligtas sa iyong crypto ay isang piraso ng cake",
|
||||
"new_node_testing": "Bagong node testing",
|
||||
"new_subaddress_create": "Lumikha",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Ibalik ang iyong wallet mula sa 24 na salita na seed",
|
||||
"restore_bitcoin_title_from_keys": "Ibalik mula sa WIF",
|
||||
"restore_description_from_backup": "Maari mong ibalik ang buong Cake Wallet app sa iyong backup file",
|
||||
"restore_description_from_cupcake": "Mag-link sa aming kasamang naka-air-gapped app, na naka-install sa isang pangalawang telepono.",
|
||||
"restore_description_from_hardware_wallet": "Ibalik mula sa isang Ledger hardware wallet",
|
||||
"restore_description_from_keys": "Ibalik ang iyong wallet mula sa nabuong mga keystrokes na na-save mula sa iyong mga private key",
|
||||
"restore_description_from_seed": "Ibalik ang iyong wallet mula sa alinman sa 25 na salita o 13 na salita na seed",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Ibalik mula sa Seed/Keys",
|
||||
"restore_spend_key_private": "Spend key (private)",
|
||||
"restore_title_from_backup": "Ibalik mula sa backup",
|
||||
"restore_title_from_cupcake": "Cupcake app",
|
||||
"restore_title_from_hardware_wallet": "Ibalik mula sa hardware wallet",
|
||||
"restore_title_from_keys": "Ibalik mula sa keys",
|
||||
"restore_title_from_seed": "Ibalik mula sa seed",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "I-convert mula sa",
|
||||
"youCanGoBackToYourDapp": "Maaari kang bumalik sa iyong dapp ngayon",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Yeni bir temsilci seçin",
|
||||
"nanogpt_subtitle": "En yeni modeller (GPT-4, Claude). \\ Nno aboneliği, kripto ile ödeme yapın.",
|
||||
"narrow": "Dar",
|
||||
"new_tag": "Yeni",
|
||||
"new_first_wallet_text": "Kripto'nuzu güvende tutmak bir parça kek",
|
||||
"new_node_testing": "Yeni düğüm test ediliyor",
|
||||
"new_subaddress_create": "Oluştur",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Cüzdanınızı 24 kelimelik kombinasyon kodundan geri yükle",
|
||||
"restore_bitcoin_title_from_keys": "WIF'den geri yükle",
|
||||
"restore_description_from_backup": "Yedek dosyandan tüm Cake Wallet uygulamasını geri döndürebilirsin",
|
||||
"restore_description_from_cupcake": "İkinci bir telefona yüklü eşlik eden hava kaplı uygulamamızla bağlantı kurun.",
|
||||
"restore_description_from_hardware_wallet": "Bir defter donanım cüzdanından geri yükleyin",
|
||||
"restore_description_from_keys": "Cüzdanınızı özel anahtarlarınızdan kaydedilen oluşturulmuş tuş vuruşlarından geri yükleyin",
|
||||
"restore_description_from_seed": "Cüzdanınızı 25 veya 13 kelimelik kombinasyon kodundan geri döndürün",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "Tohumu/Anahtarları Geri Döndür",
|
||||
"restore_spend_key_private": "Harcama anahtarı (Özel)",
|
||||
"restore_title_from_backup": "Yedekten geri döndür",
|
||||
"restore_title_from_cupcake": "Cupcake uygulaması",
|
||||
"restore_title_from_hardware_wallet": "Donanım cüzdanından geri yükleme",
|
||||
"restore_title_from_keys": "Anahtarlardan geri döndür",
|
||||
"restore_title_from_seed": "Tohumdan geri döndür",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "Biçiminden dönüştür:",
|
||||
"youCanGoBackToYourDapp": "Şimdi Dapp'ınıza geri dönebilirsin",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "Виберіть нового представника",
|
||||
"nanogpt_subtitle": "Усі найновіші моделі (GPT-4, Claude). \\ Nno підписка, оплата криптовалютою.",
|
||||
"narrow": "вузькі",
|
||||
"new_tag": "Новачок",
|
||||
"new_first_wallet_text": "Зберігання вашої криптовалюти це просто як шматок торта",
|
||||
"new_node_testing": "Тестування нового вузла",
|
||||
"new_subaddress_create": "Створити",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Ви можете відновити гаманець використовуючи 24-ти слівну мнемонічну фразу",
|
||||
"restore_bitcoin_title_from_keys": "Відновити за допомогою WIF",
|
||||
"restore_description_from_backup": "Ви можете відновити Cake Wallet з вашого резервного файлу",
|
||||
"restore_description_from_cupcake": "Зв'язок з нашим супутничим додатком, встановленим на другому телефоні.",
|
||||
"restore_description_from_hardware_wallet": "Відновлення з апаратного гаманця",
|
||||
"restore_description_from_keys": "Ви можете відновити гаманець за допомогою приватних ключів",
|
||||
"restore_description_from_seed": "Ви можете відновити гаманець використовуючи 25-ти слівну мнемонічну фразу",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Відновити за допомогою мнемонічної фрази/ключів",
|
||||
"restore_spend_key_private": "Приватний ключ витрати",
|
||||
"restore_title_from_backup": "Відновити із резервного файлу",
|
||||
"restore_title_from_cupcake": "Додаток для кексів",
|
||||
"restore_title_from_hardware_wallet": "Відновити з апаратного гаманця",
|
||||
"restore_title_from_keys": "Відновити за допомогою ключів",
|
||||
"restore_title_from_seed": "Відновити з мнемонічної фрази",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "Конвертувати з",
|
||||
"youCanGoBackToYourDapp": "Ви можете повернутися до свого DAPP зараз",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "ایک نیا نمائندہ منتخب کریں",
|
||||
"nanogpt_subtitle": "تمام تازہ ترین ماڈل (GPT-4 ، کلاڈ)۔ n n no سبسکرپشن ، کریپٹو کے ساتھ ادائیگی کریں۔",
|
||||
"narrow": "تنگ",
|
||||
"new_tag": "نیا",
|
||||
"new_first_wallet_text": "اپنے کریپٹو کو محفوظ رکھنا کیک کا ایک ٹکڑا ہے",
|
||||
"new_node_testing": "نیا نوڈ ٹیسٹنگ",
|
||||
"new_subaddress_create": "بنانا",
|
||||
@@ -689,6 +690,7 @@
|
||||
"restore_bitcoin_description_from_seed": "24 الفاظ کے مجموعہ کوڈ سے اپنے بٹوے کو بحال کریں۔",
|
||||
"restore_bitcoin_title_from_keys": "WIF سے بحال کریں۔",
|
||||
"restore_description_from_backup": "آپ اپنی بیک اپ فائل سے پوری کیک والیٹ ایپ کو بحال کر سکتے ہیں۔",
|
||||
"restore_description_from_cupcake": "دوسرے فون پر نصب ، ہمارے ساتھی ایئر گیپڈ ایپ کے ساتھ لنک کریں۔",
|
||||
"restore_description_from_hardware_wallet": "لیجر ہارڈ ویئر پرس سے بحال کریں",
|
||||
"restore_description_from_keys": "اپنے بٹوے کو اپنی نجی کلیدوں سے محفوظ کردہ کی اسٹروکس سے بحال کریں۔",
|
||||
"restore_description_from_seed": "اپنے بٹوے کو 25 لفظ یا 13 الفاظ کے مجموعہ کوڈ سے بحال کریں۔",
|
||||
@@ -703,6 +705,7 @@
|
||||
"restore_seed_keys_restore": "بیج/کیز کی بحالی",
|
||||
"restore_spend_key_private": "خرچ کی کلید (نجی)",
|
||||
"restore_title_from_backup": "بیک اپ سے بحال کریں۔",
|
||||
"restore_title_from_cupcake": "کپ کیک ایپ",
|
||||
"restore_title_from_hardware_wallet": "ہارڈ ویئر پرس سے بحال کریں",
|
||||
"restore_title_from_keys": "چابیاں سے بحال کریں۔",
|
||||
"restore_title_from_seed": "بیج سے بحال کریں۔",
|
||||
@@ -1127,4 +1130,4 @@
|
||||
"you_will_send": "سے تبدیل کریں۔",
|
||||
"youCanGoBackToYourDapp": "اب آپ اپنے ڈی اے پی پی پر واپس جاسکتے ہیں",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,6 +521,7 @@
|
||||
"nano_pick_new_rep": "Chọn đại diện mới",
|
||||
"nanogpt_subtitle": "Tất cả các mẫu mới nhất (GPT-4, Claude).\\nKhông cần đăng ký, thanh toán bằng tiền điện tử.",
|
||||
"narrow": "Hẹp",
|
||||
"new_tag": "Mới",
|
||||
"new_first_wallet_text": "Giữ tiền điện tử của bạn an toàn là một miếng bánh",
|
||||
"new_node_testing": "Đang thử nghiệm nút mới",
|
||||
"new_subaddress_create": "Tạo",
|
||||
@@ -685,6 +686,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Khôi phục ví của bạn từ mã kết hợp 24 từ",
|
||||
"restore_bitcoin_title_from_keys": "Khôi phục từ WIF",
|
||||
"restore_description_from_backup": "Bạn có thể khôi phục toàn bộ ứng dụng Cake Wallet từ tệp sao lưu của bạn",
|
||||
"restore_description_from_cupcake": "Liên kết với Ứng dụng Air Air của chúng tôi, được cài đặt trên điện thoại thứ hai.",
|
||||
"restore_description_from_hardware_wallet": "Khôi phục từ ví phần cứng Ledger",
|
||||
"restore_description_from_keys": "Khôi phục ví của bạn từ các thao tác nhập được lưu từ khóa riêng của bạn",
|
||||
"restore_description_from_seed": "Khôi phục ví của bạn từ mã kết hợp 25 từ hoặc 13 từ",
|
||||
@@ -699,6 +701,7 @@
|
||||
"restore_seed_keys_restore": "Khôi phục hạt giống/khóa",
|
||||
"restore_spend_key_private": "Khóa chi tiêu (riêng tư)",
|
||||
"restore_title_from_backup": "Khôi phục từ sao lưu",
|
||||
"restore_title_from_cupcake": "Ứng dụng Cupcake",
|
||||
"restore_title_from_hardware_wallet": "Khôi phục từ ví phần cứng",
|
||||
"restore_title_from_keys": "Khôi phục từ khóa",
|
||||
"restore_title_from_seed": "Khôi phục từ hạt giống",
|
||||
@@ -1122,4 +1125,4 @@
|
||||
"you_will_send": "Chuyển đổi từ",
|
||||
"youCanGoBackToYourDapp": "Bạn có thể quay lại DAPP của mình ngay bây giờ",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
"nano_pick_new_rep": "Mu aṣoju tuntun kan",
|
||||
"nanogpt_subtitle": "Gbogbo awọn awoṣe tuntun (GPT-4, Claude). \\ Nno alabapin kan, sanwo pẹlu Crypto.",
|
||||
"narrow": "Taara",
|
||||
"new_tag": "Tuntun",
|
||||
"new_first_wallet_text": "Tọju ẹrọ ti o ni aabo rẹ jẹ nkan ti akara oyinbo kan",
|
||||
"new_node_testing": "A ń dán apẹka títun wò",
|
||||
"new_subaddress_create": "Ṣe é",
|
||||
@@ -688,6 +689,7 @@
|
||||
"restore_bitcoin_description_from_seed": "Mú àpamọ́wọ́ yín padà láti àkànpọ̀ ọlọ́rọ̀ ẹ̀ẹ̀mẹrinlélógun",
|
||||
"restore_bitcoin_title_from_keys": "Mú padà láti WIF",
|
||||
"restore_description_from_backup": "Ẹ lè fi ẹ̀dà nípamọ́ yín mú odindi Cake Wallet áàpù padà.",
|
||||
"restore_description_from_cupcake": "Ọna asopọ pẹlu Ohun elo Wa-ilẹ wa, ti o fi sori foonu keji.",
|
||||
"restore_description_from_hardware_wallet": "Mu pada kuro ninu apamọwọ ohun elo ti o yanilenu",
|
||||
"restore_description_from_keys": "Mú àpamọ́wọ́ yín padà láti àwọn àtẹ̀ nípamọ́ láti àwọn kọ́kọ́rọ́ àdáni yín",
|
||||
"restore_description_from_seed": "Ẹ mú àpamọ́wọ́ yín padà láti àkànpọ̀ ọlọ́rọ̀ ẹ̀ẹ̀marùndínlọgbọ̀n tàbí ti mẹ́talá.",
|
||||
@@ -702,6 +704,7 @@
|
||||
"restore_seed_keys_restore": "Mú hóró/kọ́kọ́rọ́ padà",
|
||||
"restore_spend_key_private": "kọ́kọ́rọ́ àdáni fún níná",
|
||||
"restore_title_from_backup": "Fi ẹ̀dà nípamọ́ mú padà",
|
||||
"restore_title_from_cupcake": "Ohun elo app",
|
||||
"restore_title_from_hardware_wallet": "Mu pada kuro ninu apamọwọ ohun elo",
|
||||
"restore_title_from_keys": "Fi kọ́kọ́rọ́ ṣẹ̀dá",
|
||||
"restore_title_from_seed": "Fi hóró mú padà",
|
||||
@@ -1126,4 +1129,4 @@
|
||||
"you_will_send": "Ṣe pàṣípààrọ̀ láti",
|
||||
"youCanGoBackToYourDapp": "O le pada si tapla rẹ bayi",
|
||||
"yy": "Ọd"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +522,7 @@
|
||||
"nano_pick_new_rep": "选择新代表",
|
||||
"nanogpt_subtitle": "所有最新型号(GPT-4,Claude)。\\ nno订阅,用加密货币付款。",
|
||||
"narrow": "狭窄的",
|
||||
"new_tag": "新的",
|
||||
"new_first_wallet_text": "保持加密货币是一件小菜一碟",
|
||||
"new_node_testing": "新节点测试",
|
||||
"new_subaddress_create": "创建",
|
||||
@@ -687,6 +688,7 @@
|
||||
"restore_bitcoin_description_from_seed": "从24个文字的组成码恢复您的钱包",
|
||||
"restore_bitcoin_title_from_keys": "从WIF还原",
|
||||
"restore_description_from_backup": "您可以从还原整个Cake Wallet应用您的备份文件",
|
||||
"restore_description_from_cupcake": "与我们的配套空调应用程序链接,安装在第二台手机上。",
|
||||
"restore_description_from_hardware_wallet": "从分类帐硬件钱包还原",
|
||||
"restore_description_from_keys": "使用私钥恢复钱包",
|
||||
"restore_description_from_seed": "从25个字中恢复您的钱包或13个字的组合码",
|
||||
@@ -701,6 +703,7 @@
|
||||
"restore_seed_keys_restore": "种子/密钥还原",
|
||||
"restore_spend_key_private": "Spend私钥",
|
||||
"restore_title_from_backup": "从备份文件还原",
|
||||
"restore_title_from_cupcake": "蛋糕应用",
|
||||
"restore_title_from_hardware_wallet": "从硬件钱包还原",
|
||||
"restore_title_from_keys": "从密钥还原",
|
||||
"restore_title_from_seed": "从种子还原",
|
||||
@@ -1125,4 +1128,4 @@
|
||||
"you_will_send": "转换自",
|
||||
"youCanGoBackToYourDapp": "您现在可以回到DAPP",
|
||||
"yy": "YY"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ cd "$SCRIPT_DIR"
|
||||
BUILD_AMD64=false
|
||||
BUILD_ARM64=false
|
||||
APP_TYPE="cakewallet"
|
||||
DOCKER_IMAGE="ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly"
|
||||
DOCKER_IMAGE="ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-ndkr28-go1.24.1-ruststablenightly"
|
||||
|
||||
# Parse arguments
|
||||
for arg in "$@"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
FROM mcr.microsoft.com/windows/servercore:ltsc2022
|
||||
|
||||
ENV FLUTTER_VERSION=3.27.0
|
||||
ENV FLUTTER_VERSION=3.27.4
|
||||
ENV GIT_VERSION=2.47.1
|
||||
ENV VS_INSTALLED_DIR="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"
|
||||
ENV PATH="C:\Users\ContainerAdministrator\.cargo\bin;C:\ProgramData\chocolatey\bin;C:\flutter\flutter\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Users\ContainerAdministrator\AppData\Local\Microsoft\WindowsApps"
|
||||
|
||||
@@ -163,6 +163,7 @@ abstract class Bitcoin {
|
||||
String? passphrase,
|
||||
});
|
||||
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo});
|
||||
WalletCredentials createBitcoinWalletFromKeys({required String name, required String password, required String xpub});
|
||||
WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo, String? password, String? passphrase, String? mnemonic});
|
||||
WalletCredentials createBitcoinHardwareWalletCredentials({required String name, required HardwareAccountData accountData, WalletInfo? walletInfo});
|
||||
List<String> getWordList();
|
||||
@@ -206,7 +207,7 @@ abstract class Bitcoin {
|
||||
Map<DerivationType, List<DerivationInfo>> getElectrumDerivations();
|
||||
Future<void> setAddressType(Object wallet, dynamic option);
|
||||
ReceivePageOption getSelectedAddressType(Object wallet);
|
||||
List<ReceivePageOption> getBitcoinReceivePageOptions();
|
||||
List<ReceivePageOption> getBitcoinReceivePageOptions(Object wallet);
|
||||
List<ReceivePageOption> getLitecoinReceivePageOptions();
|
||||
BitcoinAddressType getBitcoinAddressType(ReceivePageOption option);
|
||||
bool isPayjoinAvailable(Object wallet);
|
||||
@@ -246,6 +247,7 @@ abstract class Bitcoin {
|
||||
bool getMwebEnabled(Object wallet);
|
||||
String? getUnusedMwebAddress(Object wallet);
|
||||
String? getUnusedSegwitAddress(Object wallet);
|
||||
Future<void> commitPsbtUR(Object wallet, List<String> urCodes);
|
||||
|
||||
void updatePayjoinState(Object wallet, bool state);
|
||||
String getPayjoinEndpoint(Object wallet);
|
||||
@@ -401,7 +403,7 @@ abstract class Monero {
|
||||
|
||||
Future<bool> commitTransactionUR(Object wallet, String ur);
|
||||
|
||||
String exportOutputsUR(Object wallet, bool all);
|
||||
Map<String, String> exportOutputsUR(Object wallet);
|
||||
|
||||
bool needExportOutputs(Object wallet, int amount);
|
||||
|
||||
|
||||