mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-23 19:05:51 +00:00
tezos and various tweaks
This commit is contained in:
parent
700943ada4
commit
391304f6da
8 changed files with 330 additions and 123 deletions
|
@ -443,7 +443,7 @@ class _ConfirmTransactionViewState
|
||||||
"Amount",
|
"Amount",
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
ref.watch(pAmountFormatter(coin)).format(
|
ref.watch(pAmountFormatter(coin)).format(
|
||||||
widget.txData.amount!,
|
widget.txData.amount!,
|
||||||
ethContract: ref
|
ethContract: ref
|
||||||
|
@ -469,7 +469,7 @@ class _ConfirmTransactionViewState
|
||||||
"Transaction fee",
|
"Transaction fee",
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
ref
|
ref
|
||||||
.watch(pAmountFormatter(coin))
|
.watch(pAmountFormatter(coin))
|
||||||
.format(widget.txData.fee!),
|
.format(widget.txData.fee!),
|
||||||
|
@ -495,7 +495,7 @@ class _ConfirmTransactionViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
"~${widget.txData.fee!.raw.toInt() ~/ widget.txData.vSize!}",
|
"~${widget.txData.fee!.raw.toInt() ~/ widget.txData.vSize!}",
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
),
|
),
|
||||||
|
@ -520,7 +520,7 @@ class _ConfirmTransactionViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
widget.txData.noteOnChain!,
|
widget.txData.noteOnChain!,
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
),
|
),
|
||||||
|
@ -543,7 +543,7 @@ class _ConfirmTransactionViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
widget.txData.note!,
|
widget.txData.note!,
|
||||||
style: STextStyles.itemSubtitle12(context),
|
style: STextStyles.itemSubtitle12(context),
|
||||||
),
|
),
|
||||||
|
@ -664,7 +664,7 @@ class _ConfirmTransactionViewState
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
SelectableText(
|
||||||
ref.watch(pAmountFormatter(coin)).format(
|
ref.watch(pAmountFormatter(coin)).format(
|
||||||
amount,
|
amount,
|
||||||
ethContract: ref
|
ethContract: ref
|
||||||
|
@ -687,7 +687,7 @@ class _ConfirmTransactionViewState
|
||||||
context),
|
context),
|
||||||
),
|
),
|
||||||
if (externalCalls)
|
if (externalCalls)
|
||||||
Text(
|
SelectableText(
|
||||||
"~$fiatAmount ${ref.watch(prefsChangeNotifierProvider.select(
|
"~$fiatAmount ${ref.watch(prefsChangeNotifierProvider.select(
|
||||||
(value) => value.currency,
|
(value) => value.currency,
|
||||||
))}",
|
))}",
|
||||||
|
@ -724,7 +724,7 @@ class _ConfirmTransactionViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
widget.isPaynymTransaction
|
widget.isPaynymTransaction
|
||||||
? widget.txData.paynymAccountLite!.nymName
|
? widget.txData.paynymAccountLite!.nymName
|
||||||
: widget.txData.recipients!.first.address,
|
: widget.txData.recipients!.first.address,
|
||||||
|
@ -765,7 +765,7 @@ class _ConfirmTransactionViewState
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final fee = widget.txData.fee!;
|
final fee = widget.txData.fee!;
|
||||||
|
|
||||||
return Text(
|
return SelectableText(
|
||||||
ref
|
ref
|
||||||
.watch(pAmountFormatter(coin))
|
.watch(pAmountFormatter(coin))
|
||||||
.format(fee),
|
.format(fee),
|
||||||
|
@ -884,7 +884,7 @@ class _ConfirmTransactionViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 12,
|
height: 12,
|
||||||
),
|
),
|
||||||
Text(
|
SelectableText(
|
||||||
(coin == Coin.epicCash)
|
(coin == Coin.epicCash)
|
||||||
? "Local Note (optional)"
|
? "Local Note (optional)"
|
||||||
: "Note (optional)",
|
: "Note (optional)",
|
||||||
|
@ -987,7 +987,7 @@ class _ConfirmTransactionViewState
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final fee = widget.txData.fee!;
|
final fee = widget.txData.fee!;
|
||||||
|
|
||||||
return Text(
|
return SelectableText(
|
||||||
ref.watch(pAmountFormatter(coin)).format(fee),
|
ref.watch(pAmountFormatter(coin)).format(fee),
|
||||||
style: STextStyles.itemSubtitle(context),
|
style: STextStyles.itemSubtitle(context),
|
||||||
);
|
);
|
||||||
|
@ -1026,7 +1026,7 @@ class _ConfirmTransactionViewState
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
.textFieldDefaultBG,
|
.textFieldDefaultBG,
|
||||||
child: Text(
|
child: SelectableText(
|
||||||
"~${widget.txData.fee!.raw.toInt() ~/ widget.txData.vSize!}",
|
"~${widget.txData.fee!.raw.toInt() ~/ widget.txData.vSize!}",
|
||||||
style: STextStyles.itemSubtitle(context),
|
style: STextStyles.itemSubtitle(context),
|
||||||
),
|
),
|
||||||
|
@ -1075,7 +1075,7 @@ class _ConfirmTransactionViewState
|
||||||
final fee = widget.txData.fee!;
|
final fee = widget.txData.fee!;
|
||||||
|
|
||||||
final amount = widget.txData.amount!;
|
final amount = widget.txData.amount!;
|
||||||
return Text(
|
return SelectableText(
|
||||||
ref
|
ref
|
||||||
.watch(pAmountFormatter(coin))
|
.watch(pAmountFormatter(coin))
|
||||||
.format(amount + fee),
|
.format(amount + fee),
|
||||||
|
|
|
@ -1486,7 +1486,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
if (coin != Coin.ethereum)
|
if (coin != Coin.ethereum && coin != Coin.tezos)
|
||||||
CustomTextButton(
|
CustomTextButton(
|
||||||
text: "Send all ${coin.ticker}",
|
text: "Send all ${coin.ticker}",
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
@ -1898,7 +1898,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash &&
|
if (coin != Coin.epicCash &&
|
||||||
coin != Coin.nano &&
|
coin != Coin.nano &&
|
||||||
coin != Coin.banano)
|
coin != Coin.banano &&
|
||||||
|
coin != Coin.tezos)
|
||||||
Text(
|
Text(
|
||||||
"Transaction fee (estimated)",
|
"Transaction fee (estimated)",
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
|
@ -1906,13 +1907,15 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash &&
|
if (coin != Coin.epicCash &&
|
||||||
coin != Coin.nano &&
|
coin != Coin.nano &&
|
||||||
coin != Coin.banano)
|
coin != Coin.banano &&
|
||||||
|
coin != Coin.tezos)
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
),
|
),
|
||||||
if (coin != Coin.epicCash &&
|
if (coin != Coin.epicCash &&
|
||||||
coin != Coin.nano &&
|
coin != Coin.nano &&
|
||||||
coin != Coin.banano)
|
coin != Coin.banano &&
|
||||||
|
coin != Coin.tezos)
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
TextField(
|
TextField(
|
||||||
|
|
|
@ -1062,7 +1062,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
if (coin != Coin.ethereum)
|
if (coin != Coin.ethereum && coin != Coin.tezos)
|
||||||
CustomTextButton(
|
CustomTextButton(
|
||||||
text: "Send all ${coin.ticker}",
|
text: "Send all ${coin.ticker}",
|
||||||
onTap: sendAllTapped,
|
onTap: sendAllTapped,
|
||||||
|
@ -1481,7 +1481,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin)))
|
if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos]
|
||||||
|
.contains(coin)))
|
||||||
ConditionalParent(
|
ConditionalParent(
|
||||||
condition: coin.isElectrumXCoin &&
|
condition: coin.isElectrumXCoin &&
|
||||||
!(((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
!(((coin == Coin.firo || coin == Coin.firoTestNet) &&
|
||||||
|
@ -1532,11 +1533,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin)))
|
if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos]
|
||||||
|
.contains(coin)))
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin)))
|
if (!([Coin.nano, Coin.banano, Coin.epicCash, Coin.tezos]
|
||||||
|
.contains(coin)))
|
||||||
if (!isCustomFee)
|
if (!isCustomFee)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
|
|
|
@ -117,7 +117,7 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> {
|
||||||
children: [
|
children: [
|
||||||
FittedBox(
|
FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: Text(
|
child: SelectableText(
|
||||||
ref
|
ref
|
||||||
.watch(pAmountFormatter(coin))
|
.watch(pAmountFormatter(coin))
|
||||||
.format(balanceToShow, ethContract: tokenContract),
|
.format(balanceToShow, ethContract: tokenContract),
|
||||||
|
@ -125,7 +125,7 @@ class _WDesktopWalletSummaryState extends ConsumerState<DesktopWalletSummary> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (externalCalls)
|
if (externalCalls)
|
||||||
Text(
|
SelectableText(
|
||||||
"${Amount.fromDecimal(
|
"${Amount.fromDecimal(
|
||||||
priceTuple.item1 * balanceToShow.decimal,
|
priceTuple.item1 * balanceToShow.decimal,
|
||||||
fractionDigits: 2,
|
fractionDigits: 2,
|
||||||
|
|
58
lib/wallets/api/tezos/tezos_account.dart
Normal file
58
lib/wallets/api/tezos/tezos_account.dart
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
class TezosAccount {
|
||||||
|
final int id;
|
||||||
|
final String type;
|
||||||
|
final String address;
|
||||||
|
final String? publicKey;
|
||||||
|
final bool revealed;
|
||||||
|
final int balance;
|
||||||
|
final int counter;
|
||||||
|
|
||||||
|
TezosAccount({
|
||||||
|
required this.id,
|
||||||
|
required this.type,
|
||||||
|
required this.address,
|
||||||
|
required this.publicKey,
|
||||||
|
required this.revealed,
|
||||||
|
required this.balance,
|
||||||
|
required this.counter,
|
||||||
|
});
|
||||||
|
|
||||||
|
TezosAccount copyWith({
|
||||||
|
int? id,
|
||||||
|
String? type,
|
||||||
|
String? address,
|
||||||
|
String? publicKey,
|
||||||
|
bool? revealed,
|
||||||
|
int? balance,
|
||||||
|
int? counter,
|
||||||
|
}) {
|
||||||
|
return TezosAccount(
|
||||||
|
id: id ?? this.id,
|
||||||
|
type: type ?? this.type,
|
||||||
|
address: address ?? this.address,
|
||||||
|
publicKey: publicKey ?? this.publicKey,
|
||||||
|
revealed: revealed ?? this.revealed,
|
||||||
|
balance: balance ?? this.balance,
|
||||||
|
counter: counter ?? this.counter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory TezosAccount.fromMap(Map<String, dynamic> map) {
|
||||||
|
return TezosAccount(
|
||||||
|
id: map['id'] as int,
|
||||||
|
type: map['type'] as String,
|
||||||
|
address: map['address'] as String,
|
||||||
|
publicKey: map['publicKey'] as String?,
|
||||||
|
revealed: map['revealed'] as bool,
|
||||||
|
balance: map['balance'] as int,
|
||||||
|
counter: map['counter'] as int,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'UserData{id: $id, type: $type, address: $address, '
|
||||||
|
'publicKey: $publicKey, revealed: $revealed,'
|
||||||
|
' balance: $balance, counter: $counter}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import 'package:stackwallet/networking/http.dart';
|
||||||
import 'package:stackwallet/services/tor_service.dart';
|
import 'package:stackwallet/services/tor_service.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/prefs.dart';
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
import 'package:stackwallet/wallets/api/tezos/tezos_account.dart';
|
||||||
import 'package:stackwallet/wallets/api/tezos/tezos_transaction.dart';
|
import 'package:stackwallet/wallets/api/tezos/tezos_transaction.dart';
|
||||||
|
|
||||||
abstract final class TezosAPI {
|
abstract final class TezosAPI {
|
||||||
|
@ -32,6 +33,34 @@ abstract final class TezosAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<TezosAccount> getAccount(String address,
|
||||||
|
{String type = "user"}) async {
|
||||||
|
try {
|
||||||
|
final uriString = "$_baseURL/v1/accounts/$address?legacy=false";
|
||||||
|
final response = await _client.get(
|
||||||
|
url: Uri.parse(uriString),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
proxyInfo: Prefs.instance.useTor
|
||||||
|
? TorService.sharedInstance.getProxyInfo()
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = jsonDecode(response.body) as Map;
|
||||||
|
|
||||||
|
final account = TezosAccount.fromMap(Map<String, dynamic>.from(result));
|
||||||
|
|
||||||
|
print("Get account =================== $account");
|
||||||
|
|
||||||
|
return account;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Error occurred in TezosAPI while getting account for $address: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Future<List<TezosTransaction>> getTransactions(String address) async {
|
static Future<List<TezosTransaction>> getTransactions(String address) async {
|
||||||
try {
|
try {
|
||||||
final transactionsCall =
|
final transactionsCall =
|
||||||
|
|
|
@ -15,8 +15,9 @@ class Tezos extends Bip39Currency {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO: implement genesisHash
|
String get genesisHash => throw UnimplementedError(
|
||||||
String get genesisHash => throw UnimplementedError();
|
"Not used in tezos at the moment",
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get minConfirms => 1;
|
int get minConfirms => 1;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:stackwallet/utilities/default_nodes.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/extensions/impl/string.dart';
|
import 'package:stackwallet/utilities/extensions/impl/string.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/wallets/api/tezos/tezos_account.dart';
|
||||||
import 'package:stackwallet/wallets/api/tezos/tezos_api.dart';
|
import 'package:stackwallet/wallets/api/tezos/tezos_api.dart';
|
||||||
import 'package:stackwallet/wallets/api/tezos/tezos_rpc_api.dart';
|
import 'package:stackwallet/wallets/api/tezos/tezos_rpc_api.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart';
|
||||||
|
@ -20,8 +21,8 @@ import 'package:tezart/tezart.dart' as tezart;
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
// const kDefaultTransactionStorageLimit = 496;
|
// const kDefaultTransactionStorageLimit = 496;
|
||||||
const kDefaultTransactionGasLimit = 10600;
|
// const kDefaultTransactionGasLimit = 10600;
|
||||||
|
//
|
||||||
// const kDefaultKeyRevealFee = 1270;
|
// const kDefaultKeyRevealFee = 1270;
|
||||||
// const kDefaultKeyRevealStorageLimit = 0;
|
// const kDefaultKeyRevealStorageLimit = 0;
|
||||||
// const kDefaultKeyRevealGasLimit = 1100;
|
// const kDefaultKeyRevealGasLimit = 1100;
|
||||||
|
@ -53,45 +54,51 @@ class TezosWallet extends Bip39Wallet {
|
||||||
Future<tezart.OperationsList> _buildSendTransaction({
|
Future<tezart.OperationsList> _buildSendTransaction({
|
||||||
required Amount amount,
|
required Amount amount,
|
||||||
required String address,
|
required String address,
|
||||||
int? customGasLimit,
|
required int counter,
|
||||||
Amount? customFee,
|
// required bool reveal,
|
||||||
|
// int? customGasLimit,
|
||||||
|
// Amount? customFee,
|
||||||
|
// Amount? customRevealFee,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
final sourceKeyStore = await _getKeyStore();
|
final sourceKeyStore = await _getKeyStore();
|
||||||
|
final server = (_xtzNode ?? getCurrentNode()).host;
|
||||||
|
// if (kDebugMode) {
|
||||||
|
// print("SERVER: $server");
|
||||||
|
// print("COUNTER: $counter");
|
||||||
|
// print("customFee: $customFee");
|
||||||
|
// }
|
||||||
final tezartClient = tezart.TezartClient(
|
final tezartClient = tezart.TezartClient(
|
||||||
(_xtzNode ?? getCurrentNode()).host,
|
server,
|
||||||
);
|
);
|
||||||
|
|
||||||
final opList = await tezartClient.transferOperation(
|
final opList = await tezartClient.transferOperation(
|
||||||
source: sourceKeyStore,
|
source: sourceKeyStore,
|
||||||
destination: address,
|
destination: address,
|
||||||
amount: amount.raw.toInt(),
|
amount: amount.raw.toInt(),
|
||||||
customGasLimit: customGasLimit,
|
// customFee: customFee?.raw.toInt(),
|
||||||
customFee: customFee?.raw.toInt(),
|
// customGasLimit: customGasLimit,
|
||||||
|
// reveal: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
final counter = (await TezosAPI.getCounter(
|
// if (reveal) {
|
||||||
(await getCurrentReceivingAddress())!.value,
|
// opList.prependOperation(
|
||||||
)) +
|
// tezart.RevealOperation(
|
||||||
1;
|
// customGasLimit: customGasLimit,
|
||||||
|
// customFee: customRevealFee?.raw.toInt(),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
for (final op in opList.operations) {
|
for (final op in opList.operations) {
|
||||||
if (op is tezart.RevealOperation) {
|
|
||||||
// op.storageLimit = kDefaultKeyRevealStorageLimit;
|
|
||||||
// op.gasLimit = kDefaultKeyRevealGasLimit;
|
|
||||||
// op.fee = kDefaultKeyRevealFee;
|
|
||||||
op.counter = counter;
|
op.counter = counter;
|
||||||
} else if (op is tezart.TransactionOperation) {
|
counter++;
|
||||||
op.counter = counter + 1;
|
|
||||||
// op.storageLimit = kDefaultTransactionStorageLimit;
|
|
||||||
// op.gasLimit = kDefaultTransactionGasLimit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return opList;
|
return opList;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Error in estimateFeeFor() in tezos_wallet.dart: $e\n$s}",
|
"Error in _buildSendTransaction() in tezos_wallet.dart: $e\n$s}",
|
||||||
level: LogLevel.Error,
|
level: LogLevel.Error,
|
||||||
);
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
|
@ -122,6 +129,7 @@ class TezosWallet extends Bip39Wallet {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<TxData> prepareSend({required TxData txData}) async {
|
Future<TxData> prepareSend({required TxData txData}) async {
|
||||||
|
try {
|
||||||
if (txData.recipients == null || txData.recipients!.length != 1) {
|
if (txData.recipients == null || txData.recipients!.length != 1) {
|
||||||
throw Exception("$runtimeType prepareSend requires 1 recipient");
|
throw Exception("$runtimeType prepareSend requires 1 recipient");
|
||||||
}
|
}
|
||||||
|
@ -131,31 +139,60 @@ class TezosWallet extends Bip39Wallet {
|
||||||
if (sendAmount > info.cachedBalance.spendable) {
|
if (sendAmount > info.cachedBalance.spendable) {
|
||||||
throw Exception("Insufficient available balance");
|
throw Exception("Insufficient available balance");
|
||||||
}
|
}
|
||||||
|
final account = await TezosAPI.getAccount(
|
||||||
final bool isSendAll = sendAmount == info.cachedBalance.spendable;
|
(await getCurrentReceivingAddress())!.value,
|
||||||
|
|
||||||
Amount fee = await estimateFeeFor(sendAmount, -1);
|
|
||||||
|
|
||||||
int? customGasLimit;
|
|
||||||
|
|
||||||
if (isSendAll) {
|
|
||||||
//Fee guides for emptying a tz account
|
|
||||||
// https://github.com/TezTech/eztz/blob/master/PROTO_004_FEES.md
|
|
||||||
customGasLimit = kDefaultTransactionGasLimit + 320;
|
|
||||||
fee = Amount(
|
|
||||||
rawValue: BigInt.from(fee.raw.toInt() + 32),
|
|
||||||
fractionDigits: cryptoCurrency.fractionDigits,
|
|
||||||
);
|
);
|
||||||
sendAmount = sendAmount - fee;
|
|
||||||
}
|
// final bool isSendAll = sendAmount == info.cachedBalance.spendable;
|
||||||
|
//
|
||||||
|
// int? customGasLimit;
|
||||||
|
// Amount? fee;
|
||||||
|
// Amount? revealFee;
|
||||||
|
//
|
||||||
|
// if (isSendAll) {
|
||||||
|
// final fees = await _estimate(
|
||||||
|
// account,
|
||||||
|
// txData.recipients!.first.address,
|
||||||
|
// );
|
||||||
|
// //Fee guides for emptying a tz account
|
||||||
|
// // https://github.com/TezTech/eztz/blob/master/PROTO_004_FEES.md
|
||||||
|
// // customGasLimit = kDefaultTransactionGasLimit + 320;
|
||||||
|
// fee = Amount(
|
||||||
|
// rawValue: BigInt.from(fees.transfer + 32),
|
||||||
|
// fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// BigInt rawAmount = sendAmount.raw - fee.raw;
|
||||||
|
//
|
||||||
|
// if (!account.revealed) {
|
||||||
|
// revealFee = Amount(
|
||||||
|
// rawValue: BigInt.from(fees.reveal + 32),
|
||||||
|
// fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// rawAmount = rawAmount - revealFee.raw;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// sendAmount = Amount(
|
||||||
|
// rawValue: rawAmount,
|
||||||
|
// fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
final opList = await _buildSendTransaction(
|
final opList = await _buildSendTransaction(
|
||||||
amount: sendAmount,
|
amount: sendAmount,
|
||||||
address: txData.recipients!.first.address,
|
address: txData.recipients!.first.address,
|
||||||
customFee: fee,
|
counter: account.counter + 1,
|
||||||
customGasLimit: customGasLimit,
|
// reveal: !account.revealed,
|
||||||
|
// customFee: isSendAll ? fee : null,
|
||||||
|
// customRevealFee: isSendAll ? revealFee : null,
|
||||||
|
// customGasLimit: customGasLimit,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await opList.computeLimits();
|
||||||
|
await opList.computeFees();
|
||||||
|
await opList.simulate();
|
||||||
|
|
||||||
return txData.copyWith(
|
return txData.copyWith(
|
||||||
recipients: [
|
recipients: [
|
||||||
(
|
(
|
||||||
|
@ -163,41 +200,8 @@ class TezosWallet extends Bip39Wallet {
|
||||||
address: txData.recipients!.first.address,
|
address: txData.recipients!.first.address,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
fee: fee,
|
// fee: fee,
|
||||||
tezosOperationsList: opList,
|
fee: Amount(
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<TxData> confirmSend({required TxData txData}) async {
|
|
||||||
await txData.tezosOperationsList!.executeAndMonitor();
|
|
||||||
return txData.copyWith(
|
|
||||||
txid: txData.tezosOperationsList!.result.id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
|
|
||||||
if (amount.raw == BigInt.zero) {
|
|
||||||
amount = Amount(
|
|
||||||
rawValue: BigInt.one,
|
|
||||||
fractionDigits: cryptoCurrency.fractionDigits,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final myAddressForSimulation = (await getCurrentReceivingAddress())!.value;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final opList = await _buildSendTransaction(
|
|
||||||
amount: amount,
|
|
||||||
address: myAddressForSimulation,
|
|
||||||
);
|
|
||||||
|
|
||||||
await opList.computeLimits();
|
|
||||||
await opList.computeFees();
|
|
||||||
await opList.simulate();
|
|
||||||
|
|
||||||
final fee = Amount(
|
|
||||||
rawValue: opList.operations
|
rawValue: opList.operations
|
||||||
.map(
|
.map(
|
||||||
(e) => BigInt.from(e.fee),
|
(e) => BigInt.from(e.fee),
|
||||||
|
@ -207,12 +211,121 @@ class TezosWallet extends Bip39Wallet {
|
||||||
(p, e) => p + e,
|
(p, e) => p + e,
|
||||||
),
|
),
|
||||||
fractionDigits: cryptoCurrency.fractionDigits,
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
),
|
||||||
|
tezosOperationsList: opList,
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Error in prepareSend() in tezos_wallet.dart: $e\n$s}",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (e
|
||||||
|
.toString()
|
||||||
|
.contains("(_operationResult['errors']): Must not be null")) {
|
||||||
|
throw Exception("Probably insufficient balance");
|
||||||
|
} else if (e.toString().contains(
|
||||||
|
"The simulation of the operation: \"transaction\" failed with error(s) :"
|
||||||
|
" contract.balance_too_low, tez.subtraction_underflow.",
|
||||||
|
)) {
|
||||||
|
throw Exception("Insufficient balance to pay fees");
|
||||||
|
}
|
||||||
|
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<TxData> confirmSend({required TxData txData}) async {
|
||||||
|
await txData.tezosOperationsList!.inject();
|
||||||
|
await txData.tezosOperationsList!.monitor();
|
||||||
|
return txData.copyWith(
|
||||||
|
txid: txData.tezosOperationsList!.result.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _estCount = 0;
|
||||||
|
|
||||||
|
Future<({int reveal, int transfer})> _estimate(
|
||||||
|
TezosAccount account, String recipientAddress) async {
|
||||||
|
try {
|
||||||
|
final opList = await _buildSendTransaction(
|
||||||
|
amount: Amount(
|
||||||
|
rawValue: BigInt.one,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
),
|
||||||
|
address: recipientAddress,
|
||||||
|
counter: account.counter + 1,
|
||||||
|
// reveal: !account.revealed,
|
||||||
|
);
|
||||||
|
|
||||||
|
await opList.computeLimits();
|
||||||
|
await opList.computeFees();
|
||||||
|
await opList.simulate();
|
||||||
|
|
||||||
|
int reveal = 0;
|
||||||
|
int transfer = 0;
|
||||||
|
|
||||||
|
for (final op in opList.operations) {
|
||||||
|
if (op is tezart.TransactionOperation) {
|
||||||
|
transfer += op.fee;
|
||||||
|
} else if (op is tezart.RevealOperation) {
|
||||||
|
reveal += op.fee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (reveal: reveal, transfer: transfer);
|
||||||
|
} catch (e, s) {
|
||||||
|
if (_estCount > 3) {
|
||||||
|
_estCount = 0;
|
||||||
|
Logging.instance.log(
|
||||||
|
" Error in _estimate in tezos_wallet.dart: $e\n$s}",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
} else {
|
||||||
|
_estCount++;
|
||||||
|
Logging.instance.log(
|
||||||
|
"_estimate() retry _estCount=$_estCount",
|
||||||
|
level: LogLevel.Warning,
|
||||||
|
);
|
||||||
|
return await _estimate(
|
||||||
|
account,
|
||||||
|
recipientAddress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Amount> estimateFeeFor(
|
||||||
|
Amount amount,
|
||||||
|
int feeRate, {
|
||||||
|
String recipientAddress = "tz1MXvDCyXSqBqXPNDcsdmVZKfoxL9FTHmp2",
|
||||||
|
}) async {
|
||||||
|
if (info.cachedBalance.spendable.raw == BigInt.zero) {
|
||||||
|
return Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final account = await TezosAPI.getAccount(
|
||||||
|
(await getCurrentReceivingAddress())!.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final fees = await _estimate(account, recipientAddress);
|
||||||
|
|
||||||
|
final fee = Amount(
|
||||||
|
rawValue: BigInt.from(fees.reveal + fees.transfer),
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
);
|
);
|
||||||
|
|
||||||
return fee;
|
return fee;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Error in estimateFeeFor() in tezos_wallet.dart: $e\n$s}",
|
" Error in estimateFeeFor() in tezos_wallet.dart: $e\n$s}",
|
||||||
level: LogLevel.Error,
|
level: LogLevel.Error,
|
||||||
);
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|
Loading…
Reference in a new issue