From 621aff47969761014e0a6c4e699cb637d5687ab3 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Mon, 8 Jan 2024 20:30:17 -0600 Subject: [PATCH 1/4] fee estimation --- .../coins/namecoin/namecoin_wallet.dart | 22 +++++++++---------- lib/wallets/wallet/impl/namecoin_wallet.dart | 12 ++++++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/services/coins/namecoin/namecoin_wallet.dart b/lib/services/coins/namecoin/namecoin_wallet.dart index 44a16c802..a51ecd808 100644 --- a/lib/services/coins/namecoin/namecoin_wallet.dart +++ b/lib/services/coins/namecoin/namecoin_wallet.dart @@ -2329,9 +2329,9 @@ class NamecoinWallet extends CoinServiceAPI } } - int estimateTxFee({required int vSize, required int feeRatePerKB}) { - return vSize * (feeRatePerKB / 1000).ceil(); - } + // int estimateTxFee({required int vSize, required int feeRatePerKB}) { + // return vSize * (feeRatePerKB / 1000).ceil(); + // } /// The coinselection algorithm decides whether or not the user is eligible to make the transaction /// with [satoshiAmountToSend] and [selectedTxFeeRate]. If so, it will call buildTrasaction() and return @@ -3405,14 +3405,14 @@ class NamecoinWallet extends CoinServiceAPI } // TODO: Check if this is the correct formula for namecoin - Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { - return Amount( - rawValue: BigInt.from( - ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * - (feeRatePerKB / 1000).ceil()), - fractionDigits: coin.decimals, - ); - } + // Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { + // return Amount( + // rawValue: BigInt.from( + // ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * + // (feeRatePerKB / 1000).ceil()), + // fractionDigits: coin.decimals, + // ); + // } Future sweepAllEstimate(int feeRate) async { int available = 0; diff --git a/lib/wallets/wallet/impl/namecoin_wallet.dart b/lib/wallets/wallet/impl/namecoin_wallet.dart index 7ee1d233f..5bc2410b3 100644 --- a/lib/wallets/wallet/impl/namecoin_wallet.dart +++ b/lib/wallets/wallet/impl/namecoin_wallet.dart @@ -53,14 +53,18 @@ class NamecoinWallet extends Bip39HDWallet @override int estimateTxFee({required int vSize, required int feeRatePerKB}) { - // TODO: implement estimateTxFee - throw UnimplementedError(); + return vSize * (feeRatePerKB / 1000).ceil(); } + // TODO: [prio=low] Check if this is the correct formula for namecoin. ECF @override Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { - // TODO: implement roughFeeEstimate - throw UnimplementedError(); + return Amount( + rawValue: BigInt.from( + ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * + (feeRatePerKB / 1000).ceil()), + fractionDigits: cryptoCurrency.fractionDigits, + ); } @override From 02305755755c06cdd2a24b6b5c1c9592bc5fc084 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Tue, 9 Jan 2024 16:57:32 -0600 Subject: [PATCH 2/4] implement more namecoin methods --- .../crypto_currency/coins/namecoin.dart | 118 +++++++++++++++--- lib/wallets/wallet/impl/namecoin_wallet.dart | 30 +++-- 2 files changed, 123 insertions(+), 25 deletions(-) diff --git a/lib/wallets/crypto_currency/coins/namecoin.dart b/lib/wallets/crypto_currency/coins/namecoin.dart index 486901964..cfe36d46b 100644 --- a/lib/wallets/crypto_currency/coins/namecoin.dart +++ b/lib/wallets/crypto_currency/coins/namecoin.dart @@ -19,18 +19,43 @@ class Namecoin extends Bip39HDCurrency { } @override - // TODO: implement minConfirms - int get minConfirms => throw UnimplementedError(); + // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L58 + int get minConfirms => 2; @override + // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L80 String constructDerivePath({ required DerivePathType derivePathType, int account = 0, required int chain, required int index, }) { - // TODO: implement constructDerivePath - throw UnimplementedError(); + String coinType; + switch (networkParams.wifPrefix) { + case 0xb4: // NMC mainnet wif. + coinType = "7"; // NMC mainnet. + break; + // TODO: [prio=low] Add testnet support. + default: + throw Exception("Invalid Namecoin network wif used!"); + } + + int purpose; + switch (derivePathType) { + case DerivePathType.bip44: + purpose = 44; + break; + case DerivePathType.bip49: + purpose = 49; + break; + case DerivePathType.bip84: + purpose = 84; + break; + default: + throw Exception("DerivePathType $derivePathType not supported"); + } + + return "m/$purpose'/$coinType'/$account'/$chain/$index"; } @override @@ -48,40 +73,97 @@ class Namecoin extends Bip39HDCurrency { isFailover: true, isDown: false, ); - + // case CryptoCurrencyNetwork.test: + // TODO: [prio=low] Add testnet support. default: throw UnimplementedError(); } } @override - // TODO: implement dustLimit - Amount get dustLimit => throw UnimplementedError(); + // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L60 + Amount get dustLimit => + Amount(rawValue: BigInt.from(546), fractionDigits: Coin.particl.decimals); @override - // TODO: implement genesisHash - String get genesisHash => throw UnimplementedError(); + // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L6 + String get genesisHash { + switch (network) { + case CryptoCurrencyNetwork.main: + return "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770"; + case CryptoCurrencyNetwork.test: + return "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"; + default: + throw Exception("Unsupported network: $network"); + } + } @override ({coinlib.Address address, AddressType addressType}) getAddressForPublicKey( {required coinlib.ECPublicKey publicKey, required DerivePathType derivePathType}) { - // TODO: implement getAddressForPublicKey - throw UnimplementedError(); + switch (derivePathType) { + // case DerivePathType.bip16: // TODO: [prio=low] Add P2SH support. + + case DerivePathType.bip44: + final addr = coinlib.P2PKHAddress.fromPublicKey( + publicKey, + version: networkParams.p2pkhPrefix, + ); + + return (address: addr, addressType: AddressType.p2pkh); + + // case DerivePathType.bip49: + + case DerivePathType.bip84: + final addr = coinlib.P2WPKHAddress.fromPublicKey( + publicKey, + hrp: networkParams.bech32Hrp, + ); + + return (address: addr, addressType: AddressType.p2wpkh); + + default: + throw Exception("DerivePathType $derivePathType not supported"); + } } @override - // TODO: implement networkParams - coinlib.NetworkParams get networkParams => throw UnimplementedError(); + // See https://github.com/cypherstack/stack_wallet/blob/621aff47969761014e0a6c4e699cb637d5687ab3/lib/services/coins/namecoin/namecoin_wallet.dart#L3474 + coinlib.NetworkParams get networkParams { + switch (network) { + case CryptoCurrencyNetwork.main: + return const coinlib.NetworkParams( + wifPrefix: 0xb4, // From 180. + p2pkhPrefix: 0x34, // From 52. + p2shPrefix: 0x0d, // From 13. + privHDPrefix: 0x0488ade4, + pubHDPrefix: 0x0488b21e, + bech32Hrp: "nc", + messagePrefix: '\x18Namecoin Signed Message:\n', + ); + // case CryptoCurrencyNetwork.test: + // TODO: [prio=low] Add testnet support. + default: + throw Exception("Unsupported network: $network"); + } + } @override - // TODO: implement supportedDerivationPathTypes - List get supportedDerivationPathTypes => - throw UnimplementedError(); + List get supportedDerivationPathTypes => [ + // DerivePathType.bip16, // TODO: [prio=low] Add P2SH support. + DerivePathType.bip44, + // DerivePathType.bip49, + DerivePathType.bip84, + ]; @override bool validateAddress(String address) { - // TODO: implement validateAddress - throw UnimplementedError(); + try { + coinlib.Address.fromString(address, networkParams); + return true; + } catch (_) { + return false; + } } } diff --git a/lib/wallets/wallet/impl/namecoin_wallet.dart b/lib/wallets/wallet/impl/namecoin_wallet.dart index 5bc2410b3..40905c693 100644 --- a/lib/wallets/wallet/impl/namecoin_wallet.dart +++ b/lib/wallets/wallet/impl/namecoin_wallet.dart @@ -6,6 +6,7 @@ import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:stackwallet/wallets/wallet/intermediate/bip39_hd_wallet.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/coin_control_interface.dart'; import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/electrumx_interface.dart'; +import 'package:tuple/tuple.dart'; class NamecoinWallet extends Bip39HDWallet with ElectrumXInterface, CoinControlInterface { @@ -46,9 +47,9 @@ class NamecoinWallet extends Bip39HDWallet @override Future<({bool blocked, String? blockedReason, String? utxoLabel})> checkBlockUTXO(Map jsonUTXO, String? scriptPubKeyHex, - Map jsonTX, String? utxoOwnerAddress) { - // TODO: implement checkBlockUTXO - throw UnimplementedError(); + Map jsonTX, String? utxoOwnerAddress) async { + // Namecoin doesn't have special outputs like tokens, ordinals, etc. + return (blocked: false, blockedReason: null, utxoLabel: null); } @override @@ -56,7 +57,7 @@ class NamecoinWallet extends Bip39HDWallet return vSize * (feeRatePerKB / 1000).ceil(); } - // TODO: [prio=low] Check if this is the correct formula for namecoin. ECF + // TODO: Check if this is the correct formula for namecoin. @override Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { return Amount( @@ -68,8 +69,23 @@ class NamecoinWallet extends Bip39HDWallet } @override - Future updateTransactions() { - // TODO: implement updateTransactions - throw UnimplementedError(); + Future updateTransactions() async { + final currentChainHeight = await fetchChainHeight(); + + // TODO: [prio=a] switch to V2 transactions + final data = await fetchTransactionsV1( + addresses: await fetchAddressesForElectrumXScan(), + currentChainHeight: currentChainHeight, + ); + + await mainDB.addNewTransactionData( + data + .map((e) => Tuple2( + e.transaction, + e.address, + )) + .toList(), + walletId, + ); } } From 2e3f559bf72527d05fb71c0b9cce551ce270634d Mon Sep 17 00:00:00 2001 From: sneurlax Date: Tue, 9 Jan 2024 16:57:53 -0600 Subject: [PATCH 3/4] uncomment code needed to run TODO: recomment? --- .../coins/namecoin/namecoin_wallet.dart | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/services/coins/namecoin/namecoin_wallet.dart b/lib/services/coins/namecoin/namecoin_wallet.dart index a51ecd808..44a16c802 100644 --- a/lib/services/coins/namecoin/namecoin_wallet.dart +++ b/lib/services/coins/namecoin/namecoin_wallet.dart @@ -2329,9 +2329,9 @@ class NamecoinWallet extends CoinServiceAPI } } - // int estimateTxFee({required int vSize, required int feeRatePerKB}) { - // return vSize * (feeRatePerKB / 1000).ceil(); - // } + int estimateTxFee({required int vSize, required int feeRatePerKB}) { + return vSize * (feeRatePerKB / 1000).ceil(); + } /// The coinselection algorithm decides whether or not the user is eligible to make the transaction /// with [satoshiAmountToSend] and [selectedTxFeeRate]. If so, it will call buildTrasaction() and return @@ -3405,14 +3405,14 @@ class NamecoinWallet extends CoinServiceAPI } // TODO: Check if this is the correct formula for namecoin - // Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { - // return Amount( - // rawValue: BigInt.from( - // ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * - // (feeRatePerKB / 1000).ceil()), - // fractionDigits: coin.decimals, - // ); - // } + Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { + return Amount( + rawValue: BigInt.from( + ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * + (feeRatePerKB / 1000).ceil()), + fractionDigits: coin.decimals, + ); + } Future sweepAllEstimate(int feeRate) async { int available = 0; From ef15382c13e7c8ea8ecef3ca8bf478efcb5dbcc1 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Tue, 9 Jan 2024 17:25:33 -0600 Subject: [PATCH 4/4] typofix --- lib/wallets/wallet/impl/namecoin_wallet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallets/wallet/impl/namecoin_wallet.dart b/lib/wallets/wallet/impl/namecoin_wallet.dart index 40905c693..f1358f15b 100644 --- a/lib/wallets/wallet/impl/namecoin_wallet.dart +++ b/lib/wallets/wallet/impl/namecoin_wallet.dart @@ -72,7 +72,7 @@ class NamecoinWallet extends Bip39HDWallet Future updateTransactions() async { final currentChainHeight = await fetchChainHeight(); - // TODO: [prio=a] switch to V2 transactions + // TODO: [prio=low] switch to V2 transactions. final data = await fetchTransactionsV1( addresses: await fetchAddressesForElectrumXScan(), currentChainHeight: currentChainHeight,