mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-18 16:55:58 +00:00
Fee estimation
This commit is contained in:
parent
404672f10f
commit
4abe70062f
5 changed files with 100 additions and 30 deletions
|
@ -331,14 +331,19 @@ class ElectrumClient {
|
|||
// "height": 520481,
|
||||
// "hex": "00000020890208a0ae3a3892aa047c5468725846577cfcd9b512b50000000000000000005dc2b02f2d297a9064ee103036c14d678f9afc7e3d9409cf53fd58b82e938e8ecbeca05a2d2103188ce804c4"
|
||||
// }
|
||||
Future<int?> getCurrentBlockChainTip() =>
|
||||
call(method: 'blockchain.headers.subscribe').then((result) {
|
||||
if (result is Map<String, dynamic>) {
|
||||
return result["height"] as int;
|
||||
}
|
||||
BehaviorSubject<Map<String, dynamic>>? tipListener;
|
||||
int? currentTip;
|
||||
|
||||
return null;
|
||||
});
|
||||
Future<int?> getCurrentBlockChainTip() async {
|
||||
final method = 'blockchain.headers.subscribe';
|
||||
final cb = (result) => currentTip = result['height'] as int;
|
||||
if (tipListener == null) {
|
||||
tipListener = subscribe(id: method, method: method);
|
||||
tipListener?.listen(cb);
|
||||
cb(await call(method: method));
|
||||
}
|
||||
return currentTip;
|
||||
}
|
||||
|
||||
BehaviorSubject<Object>? scripthashUpdate(String scripthash) {
|
||||
_id += 1;
|
||||
|
@ -424,6 +429,12 @@ class ElectrumClient {
|
|||
|
||||
void _methodHandler({required String method, required Map<String, dynamic> request}) {
|
||||
switch (method) {
|
||||
case 'blockchain.headers.subscribe':
|
||||
final params = request['params'] as List<dynamic>;
|
||||
final id = 'blockchain.headers.subscribe';
|
||||
|
||||
_tasks[id]?.subject?.add(params.last);
|
||||
break;
|
||||
case 'blockchain.scripthash.subscribe':
|
||||
final params = request['params'] as List<dynamic>;
|
||||
final scripthash = params.first as String?;
|
||||
|
|
|
@ -392,24 +392,13 @@ abstract class ElectrumWalletBase
|
|||
value: BigInt.from(amountLeftForChangeAndFee),
|
||||
));
|
||||
|
||||
int estimatedSize;
|
||||
if (network is BitcoinCashNetwork) {
|
||||
estimatedSize = ForkedTransactionBuilder.estimateTransactionSize(
|
||||
utxos: utxos,
|
||||
outputs: outputs,
|
||||
network: network as BitcoinCashNetwork,
|
||||
memo: memo,
|
||||
);
|
||||
} else {
|
||||
estimatedSize = BitcoinTransactionBuilder.estimateTransactionSize(
|
||||
utxos: utxos,
|
||||
outputs: outputs,
|
||||
network: network,
|
||||
memo: memo,
|
||||
);
|
||||
}
|
||||
|
||||
int fee = feeAmountWithFeeRate(feeRate, 0, 0, size: estimatedSize);
|
||||
int fee = await calcFee(
|
||||
utxos: utxos,
|
||||
outputs: outputs,
|
||||
network: network,
|
||||
memo: memo,
|
||||
feeRate: feeRate,
|
||||
);
|
||||
|
||||
if (fee == 0) {
|
||||
throw BitcoinTransactionNoFeeException();
|
||||
|
@ -499,6 +488,33 @@ abstract class ElectrumWalletBase
|
|||
);
|
||||
}
|
||||
|
||||
Future<int> calcFee({
|
||||
required List<UtxoWithAddress> utxos,
|
||||
required List<BitcoinBaseOutput> outputs,
|
||||
required BasedUtxoNetwork network,
|
||||
String? memo,
|
||||
required int feeRate}) async {
|
||||
|
||||
int estimatedSize;
|
||||
if (network is BitcoinCashNetwork) {
|
||||
estimatedSize = ForkedTransactionBuilder.estimateTransactionSize(
|
||||
utxos: utxos,
|
||||
outputs: outputs,
|
||||
network: network,
|
||||
memo: memo,
|
||||
);
|
||||
} else {
|
||||
estimatedSize = BitcoinTransactionBuilder.estimateTransactionSize(
|
||||
utxos: utxos,
|
||||
outputs: outputs,
|
||||
network: network,
|
||||
memo: memo,
|
||||
);
|
||||
}
|
||||
|
||||
return feeAmountWithFeeRate(feeRate, 0, 0, size: estimatedSize);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
try {
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:convert/convert.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
|
@ -279,4 +282,45 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> calcFee({
|
||||
required List<UtxoWithAddress> utxos,
|
||||
required List<BitcoinBaseOutput> outputs,
|
||||
required BasedUtxoNetwork network,
|
||||
String? memo,
|
||||
required int feeRate}) async {
|
||||
|
||||
final txb = BitcoinTransactionBuilder(utxos: utxos,
|
||||
outputs: outputs, fee: BigInt.zero, network: network);
|
||||
final scanSecret = mwebHd.derive(0x80000000).privKey!;
|
||||
final spendSecret = mwebHd.derive(0x80000001).privKey!;
|
||||
final stub = await CwMweb.stub();
|
||||
final resp = await stub.create(CreateRequest(
|
||||
rawTx: txb.buildTransaction((a, b, c, d) => '').toBytes(),
|
||||
scanSecret: hex.decode(scanSecret),
|
||||
spendSecret: hex.decode(spendSecret),
|
||||
feeRatePerKb: Int64(feeRate * 1000),
|
||||
dryRun: true));
|
||||
final tx = BtcTransaction.fromRaw(hex.encode(resp.rawTx));
|
||||
final posUtxos = utxos.where((utxo) => tx.inputs.any((input) =>
|
||||
input.txId == utxo.utxo.txHash && input.txIndex == utxo.utxo.vout)).toList();
|
||||
final preOutputSum = outputs.fold<int>(0, (acc, output) => acc + output.toOutput.amount.toInt());
|
||||
final posOutputSum = tx.outputs.fold<int>(0, (acc, output) => acc + output.amount.toInt());
|
||||
final mwebInputSum = utxos.sumOfUtxosValue() - posUtxos.sumOfUtxosValue();
|
||||
final expectedPegin = max(0, preOutputSum - mwebInputSum.toInt());
|
||||
var fee = posOutputSum - expectedPegin;
|
||||
if (expectedPegin > 0) {
|
||||
fee += await super.calcFee(utxos: posUtxos, outputs: tx.outputs.map((output) =>
|
||||
BitcoinScriptOutput(script: output.scriptPubKey, value: output.amount)).toList(),
|
||||
network: network, memo: memo, feeRate: feeRate) + feeRate * 41;
|
||||
}
|
||||
return fee;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
final tx = await super.createTransaction(credentials);
|
||||
return tx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler {
|
|||
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
|
||||
/// when the Flutter Engine is detached from the Activity
|
||||
private lateinit var channel : MethodChannel
|
||||
private var port: Long? = null
|
||||
|
||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_mweb")
|
||||
|
@ -26,7 +27,8 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler {
|
|||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||
if (call.method == "start") {
|
||||
val dataDir = call.argument("dataDir") ?: ""
|
||||
result.success(Mwebd.newServer("", dataDir, "").start(0))
|
||||
port = port ?: Mwebd.newServer("", dataDir, "").start(0)
|
||||
result.success(port)
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
|
|
|
@ -4,13 +4,10 @@ import 'cw_mweb_platform_interface.dart';
|
|||
import 'mwebd.pbgrpc.dart';
|
||||
|
||||
class CwMweb {
|
||||
static Future<int?>? port;
|
||||
|
||||
static Future<RpcClient> stub() async {
|
||||
final appDir = await getApplicationSupportDirectory();
|
||||
port ??= CwMwebPlatform.instance.start(appDir.path);
|
||||
return RpcClient(ClientChannel('127.0.0.1',
|
||||
port: await port ?? 0,
|
||||
port: await CwMwebPlatform.instance.start(appDir.path) ?? 0,
|
||||
options: const ChannelOptions(
|
||||
credentials: ChannelCredentials.insecure())));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue