mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 03:49:22 +00:00
WIP: Add namecoin
This commit is contained in:
parent
6a418c4215
commit
84694fa1dd
13 changed files with 183 additions and 104 deletions
1
assets/svg/coin_icons/Namecoin.svg
Normal file
1
assets/svg/coin_icons/Namecoin.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#186C9D"/><path fill="#FFF" fill-rule="nonzero" d="M19.261 23.5l.001-.002a1.8 1.8 0 0 0 .458-.05c.876-.205 1.617-.97 1.793-1.796L25 8.556l-2.772-.014-2.286 8.568-6.18-8.597-.004.004.003-.01L12.74 8.5v.001a1.9 1.9 0 0 0-.459.049c-.875.206-1.616.971-1.793 1.796L7 23.445l2.773.012 2.285-8.568 6.18 8.598h.003l1.02.013zm-6.593-10.894l.483-1.81 6.181 8.599-.483 1.81-6.18-8.6z"/></g></svg>
|
After Width: | Height: | Size: 520 B |
|
@ -116,6 +116,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
|
case Coin.namecoin:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
|
@ -528,6 +529,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
|
case Coin.namecoin:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
|
|
@ -3040,6 +3040,36 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
return available - estimatedFee;
|
return available - estimatedFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> generateNewAddress() async {
|
||||||
|
try {
|
||||||
|
await _incrementAddressIndexForChain(
|
||||||
|
0, DerivePathType.bip44); // First increment the receiving index
|
||||||
|
final newReceivingIndex = DB.instance.get<dynamic>(
|
||||||
|
boxName: walletId,
|
||||||
|
key: 'receivingIndexP2PKH') as int; // Check the new receiving index
|
||||||
|
final newReceivingAddress = await _generateAddressForChain(
|
||||||
|
0,
|
||||||
|
newReceivingIndex,
|
||||||
|
DerivePathType
|
||||||
|
.bip44); // Use new index to derive a new receiving address
|
||||||
|
await _addToAddressesArrayForChain(
|
||||||
|
newReceivingAddress,
|
||||||
|
0,
|
||||||
|
DerivePathType
|
||||||
|
.bip44); // Add that new receiving address to the array of receiving addresses
|
||||||
|
_currentReceivingAddressP2PKH = Future(() =>
|
||||||
|
newReceivingAddress); // Set the new receiving address that the service
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Exception rethrown from generateNewAddress(): $e\n$s",
|
||||||
|
level: LogLevel.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bitcoincash Network
|
// Bitcoincash Network
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
|
||||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||||
import 'package:stackwallet/services/coins/monero/monero_wallet.dart';
|
import 'package:stackwallet/services/coins/monero/monero_wallet.dart';
|
||||||
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart';
|
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart';
|
||||||
|
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/prefs.dart';
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
@ -134,6 +135,16 @@ abstract class CoinServiceAPI {
|
||||||
// tracker: tracker,
|
// tracker: tracker,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case Coin.namecoin:
|
||||||
|
return NamecoinWallet(
|
||||||
|
walletId: walletId,
|
||||||
|
walletName: walletName,
|
||||||
|
coin: coin,
|
||||||
|
tracker: tracker,
|
||||||
|
cachedClient: cachedClient,
|
||||||
|
client: client,
|
||||||
|
);
|
||||||
|
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
return DogecoinWallet(
|
return DogecoinWallet(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
|
|
|
@ -46,9 +46,7 @@ const int MINIMUM_CONFIRMATIONS = 3;
|
||||||
const int DUST_LIMIT = 1000000;
|
const int DUST_LIMIT = 1000000;
|
||||||
|
|
||||||
const String GENESIS_HASH_MAINNET =
|
const String GENESIS_HASH_MAINNET =
|
||||||
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
|
"000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770";
|
||||||
const String GENESIS_HASH_TESTNET =
|
|
||||||
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943";
|
|
||||||
|
|
||||||
enum DerivePathType { bip44 }
|
enum DerivePathType { bip44 }
|
||||||
|
|
||||||
|
@ -77,11 +75,11 @@ bip32.BIP32 getBip32NodeFromRoot(
|
||||||
int chain, int index, bip32.BIP32 root, DerivePathType derivePathType) {
|
int chain, int index, bip32.BIP32 root, DerivePathType derivePathType) {
|
||||||
String coinType;
|
String coinType;
|
||||||
switch (root.network.wif) {
|
switch (root.network.wif) {
|
||||||
case 0x80: // bch mainnet wif
|
case 0x80: // nmc mainnet wif
|
||||||
coinType = "145"; // bch mainnet
|
coinType = "7"; // nmc mainnet
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw Exception("Invalid Bitcoincash network type used!");
|
throw Exception("Invalid Namecoin network type used!");
|
||||||
}
|
}
|
||||||
switch (derivePathType) {
|
switch (derivePathType) {
|
||||||
case DerivePathType.bip44:
|
case DerivePathType.bip44:
|
||||||
|
@ -122,7 +120,7 @@ bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
|
||||||
return getBip32Root(args.item1, args.item2);
|
return getBip32Root(args.item1, args.item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
class NamecoinCashWallet extends CoinServiceAPI {
|
class NamecoinWallet extends CoinServiceAPI {
|
||||||
static const integrationTestFlag =
|
static const integrationTestFlag =
|
||||||
bool.fromEnvironment("IS_INTEGRATION_TEST");
|
bool.fromEnvironment("IS_INTEGRATION_TEST");
|
||||||
final _prefs = Prefs.instance;
|
final _prefs = Prefs.instance;
|
||||||
|
@ -134,10 +132,10 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
NetworkType get _network {
|
NetworkType get _network {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoincash:
|
case Coin.namecoin:
|
||||||
return bitcoincash;
|
return namecoin;
|
||||||
default:
|
default:
|
||||||
throw Exception("Bitcoincash network type not set!");
|
throw Exception("Namecoin network type not set!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,14 +296,14 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
final features = await electrumXClient.getServerFeatures();
|
final features = await electrumXClient.getServerFeatures();
|
||||||
Logging.instance.log("features: $features", level: LogLevel.Info);
|
Logging.instance.log("features: $features", level: LogLevel.Info);
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoincash:
|
case Coin.namecoin:
|
||||||
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
|
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
|
||||||
throw Exception("genesis hash does not match main net!");
|
throw Exception("genesis hash does not match main net!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Attempted to generate a BitcoinCashWallet using a non bch coin type: ${coin.name}");
|
"Attempted to generate a NamecoinWallet using a non namecoin coin type: ${coin.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check to make sure we aren't overwriting a mnemonic
|
// check to make sure we aren't overwriting a mnemonic
|
||||||
|
@ -730,9 +728,6 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
/// Refreshes display data for the wallet
|
/// Refreshes display data for the wallet
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
final bchaddr = Bitbox.Address.toCashAddress(await currentReceivingAddress);
|
|
||||||
print("bchaddr: $bchaddr ${await currentReceivingAddress}");
|
|
||||||
|
|
||||||
if (refreshMutex) {
|
if (refreshMutex) {
|
||||||
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
@ -1048,14 +1043,7 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool validateAddress(String address) {
|
bool validateAddress(String address) {
|
||||||
try {
|
return Address.validateAddress(address, _network);
|
||||||
// 0 for bitcoincash: address scheme, 1 for legacy address
|
|
||||||
final format = Bitbox.Address.detectFormat(address);
|
|
||||||
print("format $format");
|
|
||||||
return true;
|
|
||||||
} catch (e, s) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -1082,7 +1070,7 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
late PriceAPI _priceAPI;
|
late PriceAPI _priceAPI;
|
||||||
|
|
||||||
BitcoinCashWallet({
|
NamecoinWallet({
|
||||||
required String walletId,
|
required String walletId,
|
||||||
required String walletName,
|
required String walletName,
|
||||||
required Coin coin,
|
required Coin coin,
|
||||||
|
@ -1222,14 +1210,14 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
final features = await electrumXClient.getServerFeatures();
|
final features = await electrumXClient.getServerFeatures();
|
||||||
Logging.instance.log("features: $features", level: LogLevel.Info);
|
Logging.instance.log("features: $features", level: LogLevel.Info);
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case Coin.bitcoincash:
|
case Coin.namecoin:
|
||||||
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
|
if (features['genesis_hash'] != GENESIS_HASH_MAINNET) {
|
||||||
throw Exception("genesis hash does not match main net!");
|
throw Exception("genesis hash does not match main net!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}");
|
"Attempted to generate a NamecoinWallet using a non namecoin coin type: ${coin.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1840,10 +1828,10 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
/// attempts to convert a string to a valid scripthash
|
/// attempts to convert a string to a valid scripthash
|
||||||
///
|
///
|
||||||
/// Returns the scripthash or throws an exception on invalid bch address
|
/// Returns the scripthash or throws an exception on invalid namecoin address
|
||||||
String _convertToScriptHash(String bchAddress, NetworkType network) {
|
String _convertToScriptHash(String namecoinAddress, NetworkType network) {
|
||||||
try {
|
try {
|
||||||
final output = Address.addressToOutputScript(bchAddress, network);
|
final output = Address.addressToOutputScript(namecoinAddress, network);
|
||||||
final hash = sha256.convert(output.toList(growable: false)).toString();
|
final hash = sha256.convert(output.toList(growable: false)).toString();
|
||||||
|
|
||||||
final chars = hash.split("");
|
final chars = hash.split("");
|
||||||
|
@ -1937,7 +1925,6 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
unconfirmedCachedTransactions
|
unconfirmedCachedTransactions
|
||||||
.removeWhere((key, value) => value.confirmedStatus);
|
.removeWhere((key, value) => value.confirmedStatus);
|
||||||
|
|
||||||
print("CACHED_TRANSACTIONS_IS $cachedTransactions");
|
|
||||||
if (cachedTransactions != null) {
|
if (cachedTransactions != null) {
|
||||||
for (final tx in allTxHashes.toList(growable: false)) {
|
for (final tx in allTxHashes.toList(growable: false)) {
|
||||||
final txHeight = tx["height"] as int;
|
final txHeight = tx["height"] as int;
|
||||||
|
@ -1953,7 +1940,6 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
List<Map<String, dynamic>> allTransactions = [];
|
List<Map<String, dynamic>> allTransactions = [];
|
||||||
|
|
||||||
for (final txHash in allTxHashes) {
|
for (final txHash in allTxHashes) {
|
||||||
Logging.instance.log("bch: $txHash", level: LogLevel.Info);
|
|
||||||
final tx = await cachedElectrumXClient.getTransaction(
|
final tx = await cachedElectrumXClient.getTransaction(
|
||||||
txHash: txHash["tx_hash"] as String,
|
txHash: txHash["tx_hash"] as String,
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
@ -2325,8 +2311,8 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
vSize: vSizeForOneOutput,
|
vSize: vSizeForOneOutput,
|
||||||
feeRatePerKB: selectedTxFeeRate,
|
feeRatePerKB: selectedTxFeeRate,
|
||||||
);
|
);
|
||||||
if (feeForOneOutput < (vSizeForOneOutput + 1)) {
|
if (feeForOneOutput < (vSizeForOneOutput + 1) * 1000) {
|
||||||
feeForOneOutput = (vSizeForOneOutput + 1);
|
feeForOneOutput = (vSizeForOneOutput + 1) * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
|
@ -2382,11 +2368,11 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
||||||
if (feeForOneOutput < (vSizeForOneOutput + 1)) {
|
if (feeForOneOutput < (vSizeForOneOutput + 1) * 1000) {
|
||||||
feeForOneOutput = (vSizeForOneOutput + 1);
|
feeForOneOutput = (vSizeForOneOutput + 1) * 1000;
|
||||||
}
|
}
|
||||||
if (feeForTwoOutputs < ((vSizeForTwoOutPuts + 1))) {
|
if (feeForTwoOutputs < ((vSizeForTwoOutPuts + 1) * 1000)) {
|
||||||
feeForTwoOutputs = ((vSizeForTwoOutPuts + 1));
|
feeForTwoOutputs = ((vSizeForTwoOutPuts + 1) * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2686,76 +2672,45 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
final builder = Bitbox.Bitbox.transactionBuilder();
|
Logging.instance
|
||||||
|
.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
||||||
|
|
||||||
// retrieve address' utxos from the rest api
|
final txb = TransactionBuilder(network: _network);
|
||||||
List<Bitbox.Utxo> _utxos =
|
txb.setVersion(1);
|
||||||
[]; // await Bitbox.Address.utxo(address) as List<Bitbox.Utxo>;
|
|
||||||
utxosToUse.forEach((element) {
|
|
||||||
_utxos.add(Bitbox.Utxo(
|
|
||||||
element.txid,
|
|
||||||
element.vout,
|
|
||||||
Bitbox.BitcoinCash.fromSatoshi(element.value),
|
|
||||||
element.value,
|
|
||||||
0,
|
|
||||||
MINIMUM_CONFIRMATIONS + 1));
|
|
||||||
});
|
|
||||||
Logger.print("bch utxos: ${_utxos}");
|
|
||||||
|
|
||||||
// placeholder for input signatures
|
// Add transaction inputs
|
||||||
final signatures = <Map>[];
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
|
final txid = utxosToUse[i].txid;
|
||||||
// placeholder for total input balance
|
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||||
int totalBalance = 0;
|
utxoSigningData[txid]["output"] as Uint8List);
|
||||||
|
|
||||||
// iterate through the list of address _utxos and use them as inputs for the
|
|
||||||
// withdrawal transaction
|
|
||||||
_utxos.forEach((Bitbox.Utxo utxo) {
|
|
||||||
// add the utxo as an input for the transaction
|
|
||||||
builder.addInput(utxo.txid, utxo.vout);
|
|
||||||
final ec = utxoSigningData[utxo.txid]["keyPair"] as ECPair;
|
|
||||||
|
|
||||||
final bitboxEC = Bitbox.ECPair.fromWIF(ec.toWIF());
|
|
||||||
|
|
||||||
// add a signature to the list to be used later
|
|
||||||
signatures.add({
|
|
||||||
"vin": signatures.length,
|
|
||||||
"key_pair": bitboxEC,
|
|
||||||
"original_amount": utxo.satoshis
|
|
||||||
});
|
|
||||||
|
|
||||||
totalBalance += utxo.satoshis;
|
|
||||||
});
|
|
||||||
|
|
||||||
// calculate the fee based on number of inputs and one expected output
|
|
||||||
final fee =
|
|
||||||
Bitbox.BitcoinCash.getByteCount(signatures.length, recipients.length);
|
|
||||||
|
|
||||||
// calculate how much balance will be left over to spend after the fee
|
|
||||||
final sendAmount = totalBalance - fee;
|
|
||||||
|
|
||||||
// add the output based on the address provided in the testing data
|
|
||||||
for (int i = 0; i < recipients.length; i++) {
|
|
||||||
String recipient = recipients[i];
|
|
||||||
int satoshiAmount = satoshiAmounts[i];
|
|
||||||
builder.addOutput(recipient, satoshiAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sign all inputs
|
// Add transaction output
|
||||||
signatures.forEach((signature) {
|
for (var i = 0; i < recipients.length; i++) {
|
||||||
builder.sign(
|
txb.addOutput(recipients[i], satoshiAmounts[i]);
|
||||||
signature["vin"] as int,
|
}
|
||||||
signature["key_pair"] as Bitbox.ECPair,
|
|
||||||
signature["original_amount"] as int);
|
|
||||||
});
|
|
||||||
|
|
||||||
// build the transaction
|
try {
|
||||||
final tx = builder.build();
|
// Sign the transaction accordingly
|
||||||
final txHex = tx.toHex();
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final vSize = tx.virtualSize();
|
final txid = utxosToUse[i].txid;
|
||||||
Logger.print("bch raw hex: $txHex");
|
txb.sign(
|
||||||
|
vin: i,
|
||||||
|
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||||
|
witnessValue: utxosToUse[i].value,
|
||||||
|
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
||||||
|
level: LogLevel.Error);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
|
||||||
return {"hex": txHex, "vSize": vSize};
|
final builtTx = txb.build();
|
||||||
|
final vSize = builtTx.virtualSize();
|
||||||
|
|
||||||
|
return {"hex": builtTx.toHex(), "vSize": vSize};
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -3018,7 +2973,7 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: correct formula for bch?
|
// TODO: correct formula for nmc?
|
||||||
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||||
return ((181 * inputCount) + (34 * outputCount) + 10) *
|
return ((181 * inputCount) + (34 * outputCount) + 10) *
|
||||||
(feeRatePerKB / 1000).ceil();
|
(feeRatePerKB / 1000).ceil();
|
||||||
|
@ -3039,10 +2994,39 @@ class NamecoinCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
return available - estimatedFee;
|
return available - estimatedFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> generateNewAddress() async {
|
||||||
|
try {
|
||||||
|
await _incrementAddressIndexForChain(
|
||||||
|
0, DerivePathType.bip44); // First increment the receiving index
|
||||||
|
final newReceivingIndex = DB.instance.get<dynamic>(
|
||||||
|
boxName: walletId,
|
||||||
|
key: 'receivingIndexP2PKH') as int; // Check the new receiving index
|
||||||
|
final newReceivingAddress = await _generateAddressForChain(
|
||||||
|
0,
|
||||||
|
newReceivingIndex,
|
||||||
|
DerivePathType
|
||||||
|
.bip44); // Use new index to derive a new receiving address
|
||||||
|
await _addToAddressesArrayForChain(
|
||||||
|
newReceivingAddress,
|
||||||
|
0,
|
||||||
|
DerivePathType
|
||||||
|
.bip44); // Add that new receiving address to the array of receiving addresses
|
||||||
|
_currentReceivingAddressP2PKH = Future(() =>
|
||||||
|
newReceivingAddress); // Set the new receiving address that the service
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Exception rethrown from generateNewAddress(): $e\n$s",
|
||||||
|
level: LogLevel.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bitcoincash Network
|
// Namecoin Network
|
||||||
final bitcoincash = NetworkType(
|
final namecoin = NetworkType(
|
||||||
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
||||||
bech32: 'bc',
|
bech32: 'bc',
|
||||||
bip32: Bip32Type(public: 0x0488b21e, private: 0x0488ade4),
|
bip32: Bip32Type(public: 0x0488b21e, private: 0x0488ade4),
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:flutter_libepiccash/epic_cash.dart';
|
||||||
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
||||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||||
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart';
|
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart';
|
||||||
|
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
|
@ -52,6 +53,8 @@ class AddressUtils {
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) ||
|
return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) ||
|
||||||
RegExp("[a-zA-Z0-9]{106}").hasMatch(address);
|
RegExp("[a-zA-Z0-9]{106}").hasMatch(address);
|
||||||
|
case Coin.namecoin:
|
||||||
|
return Address.validateAddress(address, namecoin);
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return Address.validateAddress(address, testnet);
|
return Address.validateAddress(address, testnet);
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
|
||||||
abstract class Assets {
|
abstract class Assets {
|
||||||
|
@ -110,6 +111,7 @@ class _SVG {
|
||||||
String get epicCash => "assets/svg/coin_icons/EpicCash.svg";
|
String get epicCash => "assets/svg/coin_icons/EpicCash.svg";
|
||||||
String get firo => "assets/svg/coin_icons/Firo.svg";
|
String get firo => "assets/svg/coin_icons/Firo.svg";
|
||||||
String get monero => "assets/svg/coin_icons/Monero.svg";
|
String get monero => "assets/svg/coin_icons/Monero.svg";
|
||||||
|
String get namecoin => "assets/svg/coin_icons/Namecoin.svg";
|
||||||
|
|
||||||
// TODO provide proper assets
|
// TODO provide proper assets
|
||||||
String get bitcoinTestnet => "assets/svg/coin_icons/Bitcoin.svg";
|
String get bitcoinTestnet => "assets/svg/coin_icons/Bitcoin.svg";
|
||||||
|
@ -130,6 +132,8 @@ class _SVG {
|
||||||
return firo;
|
return firo;
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return monero;
|
return monero;
|
||||||
|
case Coin.namecoin:
|
||||||
|
return namecoin;
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return bitcoinTestnet;
|
return bitcoinTestnet;
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
@ -152,6 +156,7 @@ class _PNG {
|
||||||
String get bitcoin => "assets/images/bitcoin.png";
|
String get bitcoin => "assets/images/bitcoin.png";
|
||||||
String get epicCash => "assets/images/epic-cash.png";
|
String get epicCash => "assets/images/epic-cash.png";
|
||||||
String get bitcoincash => "assets/images/bitcoincash.png";
|
String get bitcoincash => "assets/images/bitcoincash.png";
|
||||||
|
String get namecoin => "assets/images/bitcoincash.png";
|
||||||
|
|
||||||
String imageFor({required Coin coin}) {
|
String imageFor({required Coin coin}) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
|
@ -171,6 +176,8 @@ class _PNG {
|
||||||
return firo;
|
return firo;
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return monero;
|
return monero;
|
||||||
|
case Coin.namecoin:
|
||||||
|
return namecoin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,5 +24,7 @@ Uri getBlockExplorerTransactionUrlFor({
|
||||||
return Uri.parse("https://testexplorer.firo.org/tx/$txid");
|
return Uri.parse("https://testexplorer.firo.org/tx/$txid");
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
return Uri.parse("https://blockchair.com/bitcoin-cash/transaction/$txid");
|
return Uri.parse("https://blockchair.com/bitcoin-cash/transaction/$txid");
|
||||||
|
case Coin.namecoin:
|
||||||
|
return Uri.parse("uri");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ class _CoinThemeColor {
|
||||||
Color get dogecoin => const Color(0xFFFFE079);
|
Color get dogecoin => const Color(0xFFFFE079);
|
||||||
Color get epicCash => const Color(0xFFC5C7CB);
|
Color get epicCash => const Color(0xFFC5C7CB);
|
||||||
Color get monero => const Color(0xFFFF9E6B);
|
Color get monero => const Color(0xFFFF9E6B);
|
||||||
|
Color get namecoin => const Color(0xFFFCC17B);
|
||||||
|
|
||||||
Color forCoin(Coin coin) {
|
Color forCoin(Coin coin) {
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
|
@ -29,6 +30,8 @@ class _CoinThemeColor {
|
||||||
return firo;
|
return firo;
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return monero;
|
return monero;
|
||||||
|
case Coin.namecoin:
|
||||||
|
return namecoin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ abstract class Constants {
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
|
case Coin.namecoin:
|
||||||
values.addAll([24, 21, 18, 15, 12]);
|
values.addAll([24, 21, 18, 15, 12]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -79,6 +80,9 @@ abstract class Constants {
|
||||||
|
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return 120;
|
return 120;
|
||||||
|
|
||||||
|
case Coin.namecoin:
|
||||||
|
return 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:stackwallet/models/node_model.dart';
|
import 'package:stackwallet/models/node_model.dart';
|
||||||
|
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
|
||||||
abstract class DefaultNodes {
|
abstract class DefaultNodes {
|
||||||
|
@ -14,6 +15,7 @@ abstract class DefaultNodes {
|
||||||
monero,
|
monero,
|
||||||
epicCash,
|
epicCash,
|
||||||
bitcoincash,
|
bitcoincash,
|
||||||
|
namecoin,
|
||||||
bitcoinTestnet,
|
bitcoinTestnet,
|
||||||
dogecoinTestnet,
|
dogecoinTestnet,
|
||||||
firoTestnet,
|
firoTestnet,
|
||||||
|
@ -93,6 +95,18 @@ abstract class DefaultNodes {
|
||||||
isDown: false,
|
isDown: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static NodeModel get namecoin => NodeModel(
|
||||||
|
host: "46.229.238.187",
|
||||||
|
port: 57002,
|
||||||
|
name: defaultName,
|
||||||
|
id: _nodeId(Coin.namecoin),
|
||||||
|
useSSL: true,
|
||||||
|
enabled: true,
|
||||||
|
coinName: Coin.namecoin.name,
|
||||||
|
isFailover: true,
|
||||||
|
isDown: false,
|
||||||
|
);
|
||||||
|
|
||||||
static NodeModel get bitcoinTestnet => NodeModel(
|
static NodeModel get bitcoinTestnet => NodeModel(
|
||||||
host: "electrumx-testnet.cypherstack.com",
|
host: "electrumx-testnet.cypherstack.com",
|
||||||
port: 51002,
|
port: 51002,
|
||||||
|
@ -149,6 +163,9 @@ abstract class DefaultNodes {
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return monero;
|
return monero;
|
||||||
|
|
||||||
|
case Coin.namecoin:
|
||||||
|
return namecoin;
|
||||||
|
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return bitcoinTestnet;
|
return bitcoinTestnet;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as firo;
|
||||||
import 'package:stackwallet/services/coins/monero/monero_wallet.dart' as xmr;
|
import 'package:stackwallet/services/coins/monero/monero_wallet.dart' as xmr;
|
||||||
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'
|
import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'
|
||||||
as bch;
|
as bch;
|
||||||
|
import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'
|
||||||
|
as nmc;
|
||||||
|
|
||||||
enum Coin {
|
enum Coin {
|
||||||
bitcoin,
|
bitcoin,
|
||||||
|
@ -69,6 +71,8 @@ extension CoinExt on Coin {
|
||||||
return "FIRO";
|
return "FIRO";
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return "XMR";
|
return "XMR";
|
||||||
|
case Coin.namecoin:
|
||||||
|
return "NMC";
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return "tBTC";
|
return "tBTC";
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
@ -93,6 +97,8 @@ extension CoinExt on Coin {
|
||||||
return "firo";
|
return "firo";
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return "monero";
|
return "monero";
|
||||||
|
case Coin.namecoin:
|
||||||
|
return "namecoin";
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
return "bitcoin";
|
return "bitcoin";
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
@ -108,6 +114,7 @@ extension CoinExt on Coin {
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
|
case Coin.namecoin:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
|
@ -141,6 +148,8 @@ extension CoinExt on Coin {
|
||||||
|
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
return xmr.MINIMUM_CONFIRMATIONS;
|
return xmr.MINIMUM_CONFIRMATIONS;
|
||||||
|
case Coin.namecoin:
|
||||||
|
return nmc.MINIMUM_CONFIRMATIONS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +175,9 @@ Coin coinFromPrettyName(String name) {
|
||||||
case "Monero":
|
case "Monero":
|
||||||
case "monero":
|
case "monero":
|
||||||
return Coin.monero;
|
return Coin.monero;
|
||||||
|
case "Namecoin":
|
||||||
|
case "namecoin":
|
||||||
|
return Coin.namecoin;
|
||||||
case "Bitcoin Testnet":
|
case "Bitcoin Testnet":
|
||||||
case "tBitcoin":
|
case "tBitcoin":
|
||||||
case "bitcoinTestNet":
|
case "bitcoinTestNet":
|
||||||
|
@ -198,6 +210,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) {
|
||||||
return Coin.firo;
|
return Coin.firo;
|
||||||
case "xmr":
|
case "xmr":
|
||||||
return Coin.monero;
|
return Coin.monero;
|
||||||
|
case "nmc":
|
||||||
|
return Coin.namecoin;
|
||||||
case "tbtc":
|
case "tbtc":
|
||||||
return Coin.bitcoinTestNet;
|
return Coin.bitcoinTestNet;
|
||||||
case "tfiro":
|
case "tfiro":
|
||||||
|
|
|
@ -271,6 +271,7 @@ flutter:
|
||||||
- assets/svg/coin_icons/EpicCash.svg
|
- assets/svg/coin_icons/EpicCash.svg
|
||||||
- assets/svg/coin_icons/Firo.svg
|
- assets/svg/coin_icons/Firo.svg
|
||||||
- assets/svg/coin_icons/Monero.svg
|
- assets/svg/coin_icons/Monero.svg
|
||||||
|
- assets/svg/coin_icons/Namecoin.svg
|
||||||
# lottie animations
|
# lottie animations
|
||||||
- assets/lottie/test.json
|
- assets/lottie/test.json
|
||||||
- assets/lottie/test2.json
|
- assets/lottie/test2.json
|
||||||
|
|
Loading…
Reference in a new issue