mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
peercoin WIP
This commit is contained in:
parent
d92b712146
commit
667560372d
17 changed files with 612 additions and 2 deletions
|
@ -169,6 +169,8 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.bitcoinFrost:
|
case Coin.bitcoinFrost:
|
||||||
case Coin.bitcoinFrostTestNet:
|
case Coin.bitcoinFrostTestNet:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
|
@ -221,7 +223,8 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
try {
|
try {
|
||||||
RpcClient rpcClient;
|
RpcClient rpcClient;
|
||||||
if (formData.host!.startsWith("http") || formData.host!.startsWith("https")) {
|
if (formData.host!.startsWith("http") ||
|
||||||
|
formData.host!.startsWith("https")) {
|
||||||
rpcClient = RpcClient("${formData.host}:${formData.port}");
|
rpcClient = RpcClient("${formData.host}:${formData.port}");
|
||||||
} else {
|
} else {
|
||||||
rpcClient = RpcClient("http://${formData.host}:${formData.port}");
|
rpcClient = RpcClient("http://${formData.host}:${formData.port}");
|
||||||
|
@ -761,6 +764,8 @@ class _NodeFormState extends ConsumerState<NodeForm> {
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.tezos:
|
case Coin.tezos:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
|
|
|
@ -142,6 +142,8 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.bitcoinTestNet:
|
case Coin.bitcoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
|
|
|
@ -13,6 +13,7 @@ import 'package:stackwallet/wallets/crypto_currency/coins/monero.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/namecoin.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/nano.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/nano.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/coins/peercoin.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/stellar.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart';
|
||||||
|
@ -52,6 +53,8 @@ class SupportedCoins {
|
||||||
return Monero(CryptoCurrencyNetwork.main);
|
return Monero(CryptoCurrencyNetwork.main);
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return Particl(CryptoCurrencyNetwork.main);
|
return Particl(CryptoCurrencyNetwork.main);
|
||||||
|
case Coin.peercoin:
|
||||||
|
return Peercoin(CryptoCurrencyNetwork.main);
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return Solana(CryptoCurrencyNetwork.main);
|
return Solana(CryptoCurrencyNetwork.main);
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -80,6 +83,8 @@ class SupportedCoins {
|
||||||
return Dogecoin(CryptoCurrencyNetwork.test);
|
return Dogecoin(CryptoCurrencyNetwork.test);
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return Stellar(CryptoCurrencyNetwork.test);
|
return Stellar(CryptoCurrencyNetwork.test);
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return Peercoin(CryptoCurrencyNetwork.test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ class CoinThemeColorDefault {
|
||||||
Color get namecoin => const Color(0xFF91B1E1);
|
Color get namecoin => const Color(0xFF91B1E1);
|
||||||
Color get wownero => const Color(0xFFED80C1);
|
Color get wownero => const Color(0xFFED80C1);
|
||||||
Color get particl => const Color(0xFF8175BD);
|
Color get particl => const Color(0xFF8175BD);
|
||||||
|
Color get peercoin => const Color(0xFF3CB054);
|
||||||
Color get solana => const Color(0xFFC696FF);
|
Color get solana => const Color(0xFFC696FF);
|
||||||
Color get stellar => const Color(0xFF6600FF);
|
Color get stellar => const Color(0xFF6600FF);
|
||||||
Color get nano => const Color(0xFF209CE9);
|
Color get nano => const Color(0xFF209CE9);
|
||||||
|
@ -67,6 +68,10 @@ class CoinThemeColorDefault {
|
||||||
return wownero;
|
return wownero;
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return particl;
|
return particl;
|
||||||
|
case Coin.peercoin:
|
||||||
|
return peercoin;
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return peercoin;
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return solana;
|
return solana;
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
|
|
@ -1709,6 +1709,9 @@ class StackColors extends ThemeExtension<StackColors> {
|
||||||
return _coin.wownero;
|
return _coin.wownero;
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return _coin.particl;
|
return _coin.particl;
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return _coin.peercoin;
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return _coin.solana;
|
return _coin.solana;
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
|
|
@ -32,6 +32,8 @@ import 'package:stackwallet/wallets/crypto_currency/coins/tezos.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/wownero.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
|
||||||
|
import '../wallets/crypto_currency/coins/peercoin.dart';
|
||||||
|
|
||||||
class AddressUtils {
|
class AddressUtils {
|
||||||
static String condenseAddress(String address) {
|
static String condenseAddress(String address) {
|
||||||
return '${address.substring(0, 5)}...${address.substring(address.length - 5)}';
|
return '${address.substring(0, 5)}...${address.substring(address.length - 5)}';
|
||||||
|
@ -68,6 +70,8 @@ class AddressUtils {
|
||||||
return Namecoin(CryptoCurrencyNetwork.main).validateAddress(address);
|
return Namecoin(CryptoCurrencyNetwork.main).validateAddress(address);
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return Particl(CryptoCurrencyNetwork.main).validateAddress(address);
|
return Particl(CryptoCurrencyNetwork.main).validateAddress(address);
|
||||||
|
case Coin.peercoin:
|
||||||
|
return Peercoin(CryptoCurrencyNetwork.main).validateAddress(address);
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return Solana(CryptoCurrencyNetwork.main).validateAddress(address);
|
return Solana(CryptoCurrencyNetwork.main).validateAddress(address);
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -91,6 +95,8 @@ class AddressUtils {
|
||||||
return Firo(CryptoCurrencyNetwork.test).validateAddress(address);
|
return Firo(CryptoCurrencyNetwork.test).validateAddress(address);
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
return Dogecoin(CryptoCurrencyNetwork.test).validateAddress(address);
|
return Dogecoin(CryptoCurrencyNetwork.test).validateAddress(address);
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return Peercoin(CryptoCurrencyNetwork.test).validateAddress(address);
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return Stellar(CryptoCurrencyNetwork.test).validateAddress(address);
|
return Stellar(CryptoCurrencyNetwork.test).validateAddress(address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ enum AmountUnit {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.litecoin:
|
case Coin.litecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.bitcoinFrost:
|
case Coin.bitcoinFrost:
|
||||||
case Coin.bitcoinFrostTestNet:
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
@ -47,6 +48,7 @@ enum AmountUnit {
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.bitcoin:
|
case Coin.bitcoin:
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
|
|
|
@ -68,6 +68,11 @@ Uri getDefaultBlockExplorerUrlFor({
|
||||||
return Uri.parse("https://tzstats.com/$txid");
|
return Uri.parse("https://tzstats.com/$txid");
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return Uri.parse("https://explorer.solana.com/tx/$txid");
|
return Uri.parse("https://explorer.solana.com/tx/$txid");
|
||||||
|
case Coin.peercoin:
|
||||||
|
return Uri.parse("https://chainz.cryptoid.info/ppc/tx.dws?$txid.htm");
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return Uri.parse(
|
||||||
|
"https://chainz.cryptoid.info/ppc-test/search.dws?q=$txid.htm");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ abstract class Constants {
|
||||||
static final BigInt _satsPerCoin = BigInt.from(100000000);
|
static final BigInt _satsPerCoin = BigInt.from(100000000);
|
||||||
static final BigInt _satsPerCoinTezos = BigInt.from(1000000);
|
static final BigInt _satsPerCoinTezos = BigInt.from(1000000);
|
||||||
static final BigInt _satsPerCoinSolana = BigInt.from(1000000000);
|
static final BigInt _satsPerCoinSolana = BigInt.from(1000000000);
|
||||||
|
static final BigInt _satsPerCoinPeercoin = BigInt.from(1000000); // 1*10^6.
|
||||||
static const int _decimalPlaces = 8;
|
static const int _decimalPlaces = 8;
|
||||||
static const int _decimalPlacesNano = 30;
|
static const int _decimalPlacesNano = 30;
|
||||||
static const int _decimalPlacesBanano = 29;
|
static const int _decimalPlacesBanano = 29;
|
||||||
|
@ -57,6 +58,7 @@ abstract class Constants {
|
||||||
static const int _decimalPlacesStellar = 7;
|
static const int _decimalPlacesStellar = 7;
|
||||||
static const int _decimalPlacesTezos = 6;
|
static const int _decimalPlacesTezos = 6;
|
||||||
static const int _decimalPlacesSolana = 9;
|
static const int _decimalPlacesSolana = 9;
|
||||||
|
static const int _decimalPlacesPeercoin = 6;
|
||||||
|
|
||||||
static const int notificationsMax = 0xFFFFFFFF;
|
static const int notificationsMax = 0xFFFFFFFF;
|
||||||
static const Duration networkAliveTimerDuration = Duration(seconds: 10);
|
static const Duration networkAliveTimerDuration = Duration(seconds: 10);
|
||||||
|
@ -114,6 +116,10 @@ abstract class Constants {
|
||||||
|
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return _satsPerCoinSolana;
|
return _satsPerCoinSolana;
|
||||||
|
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return _satsPerCoinPeercoin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +169,10 @@ abstract class Constants {
|
||||||
|
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return _decimalPlacesSolana;
|
return _decimalPlacesSolana;
|
||||||
|
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return _decimalPlacesPeercoin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +194,8 @@ abstract class Constants {
|
||||||
case Coin.ethereum:
|
case Coin.ethereum:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
values.addAll([12, 24]);
|
||||||
|
break;
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
case Coin.nano:
|
case Coin.nano:
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -206,6 +218,10 @@ abstract class Constants {
|
||||||
case Coin.bitcoinFrost:
|
case Coin.bitcoinFrost:
|
||||||
case Coin.bitcoinFrostTestNet:
|
case Coin.bitcoinFrostTestNet:
|
||||||
throw ArgumentError("Frost mnemonic lengths unsupported");
|
throw ArgumentError("Frost mnemonic lengths unsupported");
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
values.addAll([12, /*15, 18, 21,*/ 24]); // TODO [prio=low]: Test rest.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
@ -220,6 +236,8 @@ abstract class Constants {
|
||||||
case Coin.bitcoincash:
|
case Coin.bitcoincash:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
return 600;
|
return 600;
|
||||||
|
|
||||||
case Coin.dogecoin:
|
case Coin.dogecoin:
|
||||||
|
@ -291,6 +309,8 @@ abstract class Constants {
|
||||||
case Coin.nano:
|
case Coin.nano:
|
||||||
case Coin.banano:
|
case Coin.banano:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
|
case Coin.peercoin: // TODO [prio=low]: Verify default seed length.
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
case Coin.tezos:
|
case Coin.tezos:
|
||||||
|
|
|
@ -30,6 +30,7 @@ abstract class DefaultNodes {
|
||||||
namecoin,
|
namecoin,
|
||||||
wownero,
|
wownero,
|
||||||
particl,
|
particl,
|
||||||
|
peercoin,
|
||||||
stellar,
|
stellar,
|
||||||
nano,
|
nano,
|
||||||
banano,
|
banano,
|
||||||
|
@ -188,8 +189,21 @@ abstract class DefaultNodes {
|
||||||
isDown: false,
|
isDown: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static NodeModel get peercoin => NodeModel(
|
||||||
|
host: "electrum.peercoinexplorer.net",
|
||||||
|
port: 50004,
|
||||||
|
name: DefaultNodes.defaultName,
|
||||||
|
id: DefaultNodes.buildId(Coin.peercoin),
|
||||||
|
useSSL: true,
|
||||||
|
enabled: true,
|
||||||
|
coinName: Coin.peercoin.name,
|
||||||
|
isFailover: true,
|
||||||
|
isDown: false,
|
||||||
|
);
|
||||||
|
|
||||||
static NodeModel get solana => NodeModel(
|
static NodeModel get solana => NodeModel(
|
||||||
host: "https://api.mainnet-beta.solana.com", // TODO: Change this to stack wallet one
|
host:
|
||||||
|
"https://api.mainnet-beta.solana.com", // TODO: Change this to stack wallet one
|
||||||
port: 443,
|
port: 443,
|
||||||
name: DefaultNodes.defaultName,
|
name: DefaultNodes.defaultName,
|
||||||
id: DefaultNodes.buildId(Coin.solana),
|
id: DefaultNodes.buildId(Coin.solana),
|
||||||
|
@ -309,6 +323,18 @@ abstract class DefaultNodes {
|
||||||
isDown: false,
|
isDown: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static NodeModel get peercoinTestNet => NodeModel(
|
||||||
|
host: "testnet-electrum.peercoinexplorer.net",
|
||||||
|
port: 50009,
|
||||||
|
name: DefaultNodes.defaultName,
|
||||||
|
id: DefaultNodes.buildId(Coin.peercoinTestNet),
|
||||||
|
useSSL: true,
|
||||||
|
enabled: true,
|
||||||
|
coinName: Coin.peercoinTestNet.name,
|
||||||
|
isFailover: true,
|
||||||
|
isDown: false,
|
||||||
|
);
|
||||||
|
|
||||||
static NodeModel get stellarTestnet => NodeModel(
|
static NodeModel get stellarTestnet => NodeModel(
|
||||||
host: "https://horizon-testnet.stellar.org/",
|
host: "https://horizon-testnet.stellar.org/",
|
||||||
port: 50022,
|
port: 50022,
|
||||||
|
@ -360,6 +386,12 @@ abstract class DefaultNodes {
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return particl;
|
return particl;
|
||||||
|
|
||||||
|
case Coin.peercoin:
|
||||||
|
return peercoin;
|
||||||
|
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return peercoinTestNet;
|
||||||
|
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return solana;
|
return solana;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ enum Coin {
|
||||||
namecoin,
|
namecoin,
|
||||||
nano,
|
nano,
|
||||||
particl,
|
particl,
|
||||||
|
peercoin,
|
||||||
solana,
|
solana,
|
||||||
stellar,
|
stellar,
|
||||||
tezos,
|
tezos,
|
||||||
|
@ -42,6 +43,7 @@ enum Coin {
|
||||||
dogecoinTestNet,
|
dogecoinTestNet,
|
||||||
firoTestNet,
|
firoTestNet,
|
||||||
litecoinTestNet,
|
litecoinTestNet,
|
||||||
|
peercoinTestNet,
|
||||||
stellarTestnet,
|
stellarTestnet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +72,8 @@ extension CoinExt on Coin {
|
||||||
return "Monero";
|
return "Monero";
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return "Particl";
|
return "Particl";
|
||||||
|
case Coin.peercoin:
|
||||||
|
return "Peercoin";
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return "Solana";
|
return "Solana";
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -96,6 +100,8 @@ extension CoinExt on Coin {
|
||||||
return "tFiro";
|
return "tFiro";
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
return "tDogecoin";
|
return "tDogecoin";
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return "tPeercoin";
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return "tStellar";
|
return "tStellar";
|
||||||
}
|
}
|
||||||
|
@ -124,6 +130,8 @@ extension CoinExt on Coin {
|
||||||
return "XMR";
|
return "XMR";
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return "PART";
|
return "PART";
|
||||||
|
case Coin.peercoin:
|
||||||
|
return "PPC";
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return "SOL";
|
return "SOL";
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -149,6 +157,8 @@ extension CoinExt on Coin {
|
||||||
return "tFIRO";
|
return "tFIRO";
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
return "tDOGE";
|
return "tDOGE";
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return "tPPC";
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return "tXLM";
|
return "tXLM";
|
||||||
}
|
}
|
||||||
|
@ -178,6 +188,8 @@ extension CoinExt on Coin {
|
||||||
return "monero";
|
return "monero";
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return "particl";
|
return "particl";
|
||||||
|
case Coin.peercoin:
|
||||||
|
return "peercoin";
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return "solana";
|
return "solana";
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -203,6 +215,8 @@ extension CoinExt on Coin {
|
||||||
return "firo";
|
return "firo";
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
return "dogecoin";
|
return "dogecoin";
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return "peercoin";
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return "stellar";
|
return "stellar";
|
||||||
}
|
}
|
||||||
|
@ -222,6 +236,8 @@ extension CoinExt on Coin {
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.ethereum:
|
case Coin.ethereum:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
case Coin.stellar:
|
case Coin.stellar:
|
||||||
|
@ -255,6 +271,8 @@ extension CoinExt on Coin {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
|
@ -284,6 +302,7 @@ extension CoinExt on Coin {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.ethereum:
|
case Coin.ethereum:
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
|
@ -302,6 +321,7 @@ extension CoinExt on Coin {
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.bitcoincashTestnet:
|
case Coin.bitcoincashTestnet:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -328,6 +348,7 @@ extension CoinExt on Coin {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
case Coin.epicCash:
|
case Coin.epicCash:
|
||||||
case Coin.ethereum:
|
case Coin.ethereum:
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
|
@ -358,6 +379,9 @@ extension CoinExt on Coin {
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
return Coin.firo;
|
return Coin.firo;
|
||||||
|
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return Coin.peercoin;
|
||||||
|
|
||||||
case Coin.stellarTestnet:
|
case Coin.stellarTestnet:
|
||||||
return Coin.stellar;
|
return Coin.stellar;
|
||||||
}
|
}
|
||||||
|
@ -387,6 +411,8 @@ extension CoinExt on Coin {
|
||||||
case Coin.firo:
|
case Coin.firo:
|
||||||
case Coin.firoTestNet:
|
case Coin.firoTestNet:
|
||||||
case Coin.dogecoinTestNet:
|
case Coin.dogecoinTestNet:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
return AddressType.p2pkh;
|
return AddressType.p2pkh;
|
||||||
|
|
||||||
case Coin.monero:
|
case Coin.monero:
|
||||||
|
@ -462,6 +488,15 @@ Coin coinFromPrettyName(String name) {
|
||||||
case "particl":
|
case "particl":
|
||||||
return Coin.particl;
|
return Coin.particl;
|
||||||
|
|
||||||
|
case "Peercoin":
|
||||||
|
case "peercoin":
|
||||||
|
return Coin.peercoin;
|
||||||
|
|
||||||
|
case "tPeercoin":
|
||||||
|
case "Peercoin Testnet":
|
||||||
|
case "peercoinTestNet":
|
||||||
|
return Coin.peercoinTestNet;
|
||||||
|
|
||||||
case "Solana":
|
case "Solana":
|
||||||
case "solana":
|
case "solana":
|
||||||
return Coin.solana;
|
return Coin.solana;
|
||||||
|
|
|
@ -63,6 +63,8 @@ extension DerivePathTypeExt on DerivePathType {
|
||||||
case Coin.litecoinTestNet:
|
case Coin.litecoinTestNet:
|
||||||
case Coin.namecoin:
|
case Coin.namecoin:
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
return DerivePathType.bip84;
|
return DerivePathType.bip84;
|
||||||
|
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
|
|
186
lib/wallets/crypto_currency/coins/peercoin.dart
Normal file
186
lib/wallets/crypto_currency/coins/peercoin.dart
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
import 'package:coinlib/src/network.dart';
|
||||||
|
import 'package:coinlib_flutter/coinlib_flutter.dart' as coinlib;
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
|
||||||
|
import 'package:stackwallet/models/node_model.dart';
|
||||||
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
|
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_hd_currency.dart';
|
||||||
|
|
||||||
|
class Peercoin extends Bip39HDCurrency {
|
||||||
|
Peercoin(super.network) {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
coin = Coin.peercoin;
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
coin = Coin.peercoinTestNet;
|
||||||
|
default:
|
||||||
|
throw Exception("Unsupported network: $network");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get minConfirms => 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get torSupport => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String constructDerivePath(
|
||||||
|
{required DerivePathType derivePathType,
|
||||||
|
int account = 0,
|
||||||
|
required int chain,
|
||||||
|
required int index}) {
|
||||||
|
String coinType;
|
||||||
|
switch (networkParams.wifPrefix) {
|
||||||
|
case 183: // PPC mainnet wif.
|
||||||
|
coinType = "10"; // PPC mainnet.
|
||||||
|
break;
|
||||||
|
// TODO: [prio=low] Add testnet.
|
||||||
|
default:
|
||||||
|
throw Exception("Invalid Peercoin network wif used!");
|
||||||
|
}
|
||||||
|
|
||||||
|
int purpose;
|
||||||
|
switch (derivePathType) {
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
purpose = 44;
|
||||||
|
break;
|
||||||
|
case DerivePathType.bip84:
|
||||||
|
purpose = 84;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception("DerivePathType $derivePathType not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "m/$purpose'/$coinType'/$account'/$chain/$index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
NodeModel get defaultNode {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
return NodeModel(
|
||||||
|
host: "electrum.peercoinexplorer.net",
|
||||||
|
port: 50004,
|
||||||
|
name: DefaultNodes.defaultName,
|
||||||
|
id: DefaultNodes.buildId(Coin.peercoin),
|
||||||
|
useSSL: true,
|
||||||
|
enabled: true,
|
||||||
|
coinName: Coin.peercoin.name,
|
||||||
|
isFailover: true,
|
||||||
|
isDown: false,
|
||||||
|
);
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
return NodeModel(
|
||||||
|
host: "testnet-electrum.peercoinexplorer.net",
|
||||||
|
port: 50009,
|
||||||
|
name: DefaultNodes.defaultName,
|
||||||
|
id: DefaultNodes.buildId(Coin.peercoinTestNet),
|
||||||
|
useSSL: false, // TODO [prio=med]: Is this safe?
|
||||||
|
enabled: true,
|
||||||
|
coinName: Coin.peercoinTestNet.name,
|
||||||
|
isFailover: true,
|
||||||
|
isDown: false,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Amount get dustLimit => Amount(
|
||||||
|
rawValue: BigInt.from(294),
|
||||||
|
fractionDigits: Coin.peercoin.decimals,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get genesisHash {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
return "0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3";
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
return "00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06";
|
||||||
|
default:
|
||||||
|
throw Exception("Unsupported network: $network");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
({coinlib.Address address, AddressType addressType}) getAddressForPublicKey(
|
||||||
|
{required coinlib.ECPublicKey publicKey,
|
||||||
|
required DerivePathType derivePathType}) {
|
||||||
|
switch (derivePathType) {
|
||||||
|
// case DerivePathType.bip16:
|
||||||
|
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
final addr = coinlib.P2PKHAddress.fromPublicKey(
|
||||||
|
publicKey,
|
||||||
|
version: networkParams.p2pkhPrefix,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (address: addr, addressType: AddressType.p2pkh);
|
||||||
|
|
||||||
|
case DerivePathType.bip49:
|
||||||
|
final p2wpkhScript = coinlib.P2WPKHAddress.fromPublicKey(
|
||||||
|
publicKey,
|
||||||
|
hrp: networkParams.bech32Hrp,
|
||||||
|
).program.script;
|
||||||
|
|
||||||
|
final addr = coinlib.P2SHAddress.fromRedeemScript(
|
||||||
|
p2wpkhScript,
|
||||||
|
version: networkParams.p2shPrefix,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (address: addr, addressType: AddressType.p2sh);
|
||||||
|
|
||||||
|
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
|
||||||
|
coinlib.Network get networkParams {
|
||||||
|
switch (network) {
|
||||||
|
case CryptoCurrencyNetwork.main:
|
||||||
|
return Network.mainnet;
|
||||||
|
case CryptoCurrencyNetwork.test:
|
||||||
|
return Network.testnet;
|
||||||
|
default:
|
||||||
|
throw Exception("Unsupported network: $network");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<DerivePathType> get supportedDerivationPathTypes => [
|
||||||
|
DerivePathType.bip44,
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool validateAddress(String address) {
|
||||||
|
try {
|
||||||
|
coinlib.Address.fromString(address, networkParams);
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is Peercoin && other.network == network;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(Peercoin, network);
|
||||||
|
}
|
292
lib/wallets/wallet/impl/peercoin_wallet.dart
Normal file
292
lib/wallets/wallet/impl/peercoin_wallet.dart
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/v2/input_v2.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
|
||||||
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/wallets/crypto_currency/coins/peercoin.dart';
|
||||||
|
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';
|
||||||
|
|
||||||
|
class PeercoinWallet extends Bip39HDWallet
|
||||||
|
with ElectrumXInterface, CoinControlInterface {
|
||||||
|
@override
|
||||||
|
int get isarTransactionVersion => 2;
|
||||||
|
|
||||||
|
PeercoinWallet(CryptoCurrencyNetwork network) : super(Peercoin(network));
|
||||||
|
|
||||||
|
@override
|
||||||
|
FilterOperation? get changeAddressFilterOperation =>
|
||||||
|
FilterGroup.and(standardChangeAddressFilters);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FilterOperation? get receivingAddressFilterOperation =>
|
||||||
|
FilterGroup.and(standardReceivingAddressFilters);
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<Address>> fetchAddressesForElectrumXScan() async {
|
||||||
|
final allAddresses = await mainDB
|
||||||
|
.getAddresses(walletId)
|
||||||
|
.filter()
|
||||||
|
.not()
|
||||||
|
.group(
|
||||||
|
(q) => q
|
||||||
|
.typeEqualTo(AddressType.nonWallet)
|
||||||
|
.or()
|
||||||
|
.subTypeEqualTo(AddressSubType.nonWallet),
|
||||||
|
)
|
||||||
|
.findAll();
|
||||||
|
return allAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
@override
|
||||||
|
Amount roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) {
|
||||||
|
return Amount(
|
||||||
|
rawValue: BigInt.from(
|
||||||
|
((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() *
|
||||||
|
(feeRatePerKB / 1000).ceil()),
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int estimateTxFee({required int vSize, required int feeRatePerKB}) {
|
||||||
|
return vSize * (feeRatePerKB / 1000).ceil();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<
|
||||||
|
({
|
||||||
|
bool blocked,
|
||||||
|
String? blockedReason,
|
||||||
|
String? utxoLabel,
|
||||||
|
})> checkBlockUTXO(
|
||||||
|
Map<String, dynamic> jsonUTXO,
|
||||||
|
String? scriptPubKeyHex,
|
||||||
|
Map<String, dynamic> jsonTX,
|
||||||
|
String? utxoOwnerAddress,
|
||||||
|
) async {
|
||||||
|
// TODO [prio=high]: Check if Peercoin has outputs (eg stakes etc) to block.
|
||||||
|
return (blocked: false, blockedReason: null, utxoLabel: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateTransactions() async {
|
||||||
|
// Get all addresses.
|
||||||
|
List<Address> allAddressesOld = await fetchAddressesForElectrumXScan();
|
||||||
|
|
||||||
|
// Separate receiving and change addresses.
|
||||||
|
Set<String> receivingAddresses = allAddressesOld
|
||||||
|
.where((e) => e.subType == AddressSubType.receiving)
|
||||||
|
.map((e) => e.value)
|
||||||
|
.toSet();
|
||||||
|
Set<String> changeAddresses = allAddressesOld
|
||||||
|
.where((e) => e.subType == AddressSubType.change)
|
||||||
|
.map((e) => e.value)
|
||||||
|
.toSet();
|
||||||
|
|
||||||
|
// Remove duplicates.
|
||||||
|
final allAddressesSet = {...receivingAddresses, ...changeAddresses};
|
||||||
|
|
||||||
|
// Fetch history from ElectrumX.
|
||||||
|
final List<Map<String, dynamic>> allTxHashes =
|
||||||
|
await fetchHistory(allAddressesSet);
|
||||||
|
|
||||||
|
// Only parse new txs (not in db yet).
|
||||||
|
List<Map<String, dynamic>> allTransactions = [];
|
||||||
|
for (final txHash in allTxHashes) {
|
||||||
|
// Check for duplicates by searching for tx by tx_hash in db.
|
||||||
|
final storedTx = await mainDB.isar.transactionV2s
|
||||||
|
.where()
|
||||||
|
.txidWalletIdEqualTo(txHash["tx_hash"] as String, walletId)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (storedTx == null ||
|
||||||
|
storedTx.height == null ||
|
||||||
|
(storedTx.height != null && storedTx.height! <= 0)) {
|
||||||
|
// Tx not in db yet.
|
||||||
|
final tx = await electrumXCachedClient.getTransaction(
|
||||||
|
txHash: txHash["tx_hash"] as String,
|
||||||
|
verbose: true,
|
||||||
|
coin: cryptoCurrency.coin,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Only tx to list once.
|
||||||
|
if (allTransactions
|
||||||
|
.indexWhere((e) => e["txid"] == tx["txid"] as String) ==
|
||||||
|
-1) {
|
||||||
|
tx["height"] = txHash["height"];
|
||||||
|
allTransactions.add(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse all new txs.
|
||||||
|
final List<TransactionV2> txns = [];
|
||||||
|
for (final txData in allTransactions) {
|
||||||
|
bool wasSentFromThisWallet = false;
|
||||||
|
// Set to true if any inputs were detected as owned by this wallet.
|
||||||
|
|
||||||
|
bool wasReceivedInThisWallet = false;
|
||||||
|
// Set to true if any outputs were detected as owned by this wallet.
|
||||||
|
|
||||||
|
// Parse inputs.
|
||||||
|
BigInt amountReceivedInThisWallet = BigInt.zero;
|
||||||
|
BigInt changeAmountReceivedInThisWallet = BigInt.zero;
|
||||||
|
final List<InputV2> inputs = [];
|
||||||
|
for (final jsonInput in txData["vin"] as List) {
|
||||||
|
final map = Map<String, dynamic>.from(jsonInput as Map);
|
||||||
|
|
||||||
|
final List<String> addresses = [];
|
||||||
|
String valueStringSats = "0";
|
||||||
|
OutpointV2? outpoint;
|
||||||
|
|
||||||
|
final coinbase = map["coinbase"] as String?;
|
||||||
|
|
||||||
|
if (coinbase == null) {
|
||||||
|
// Not a coinbase (ie a typical input).
|
||||||
|
final txid = map["txid"] as String;
|
||||||
|
final vout = map["vout"] as int;
|
||||||
|
|
||||||
|
final inputTx = await electrumXCachedClient.getTransaction(
|
||||||
|
txHash: txid,
|
||||||
|
coin: cryptoCurrency.coin,
|
||||||
|
);
|
||||||
|
|
||||||
|
final prevOutJson = Map<String, dynamic>.from(
|
||||||
|
(inputTx["vout"] as List).firstWhere((e) => e["n"] == vout)
|
||||||
|
as Map);
|
||||||
|
|
||||||
|
final prevOut = OutputV2.fromElectrumXJson(
|
||||||
|
prevOutJson,
|
||||||
|
decimalPlaces: cryptoCurrency.fractionDigits,
|
||||||
|
isFullAmountNotSats: true,
|
||||||
|
walletOwns: false, // Doesn't matter here as this is not saved.
|
||||||
|
);
|
||||||
|
|
||||||
|
outpoint = OutpointV2.isarCantDoRequiredInDefaultConstructor(
|
||||||
|
txid: txid,
|
||||||
|
vout: vout,
|
||||||
|
);
|
||||||
|
valueStringSats = prevOut.valueStringSats;
|
||||||
|
addresses.addAll(prevOut.addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputV2 input = InputV2.isarCantDoRequiredInDefaultConstructor(
|
||||||
|
scriptSigHex: map["scriptSig"]?["hex"] as String?,
|
||||||
|
scriptSigAsm: map["scriptSig"]?["asm"] as String?,
|
||||||
|
sequence: map["sequence"] as int?,
|
||||||
|
outpoint: outpoint,
|
||||||
|
valueStringSats: valueStringSats,
|
||||||
|
addresses: addresses,
|
||||||
|
witness: map["witness"] as String?,
|
||||||
|
coinbase: coinbase,
|
||||||
|
innerRedeemScriptAsm: map["innerRedeemscriptAsm"] as String?,
|
||||||
|
// Need addresses before we can know if the wallet owns this input.
|
||||||
|
walletOwns: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if input was from this wallet.
|
||||||
|
if (allAddressesSet.intersection(input.addresses.toSet()).isNotEmpty) {
|
||||||
|
wasSentFromThisWallet = true;
|
||||||
|
input = input.copyWith(walletOwns: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.add(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse outputs.
|
||||||
|
final List<OutputV2> outputs = [];
|
||||||
|
for (final outputJson in txData["vout"] as List) {
|
||||||
|
OutputV2 output = OutputV2.fromElectrumXJson(
|
||||||
|
Map<String, dynamic>.from(outputJson as Map),
|
||||||
|
decimalPlaces: cryptoCurrency.fractionDigits,
|
||||||
|
isFullAmountNotSats: true,
|
||||||
|
// Need addresses before we can know if the wallet owns this input.
|
||||||
|
walletOwns: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
// If output was to my wallet, add value to amount received.
|
||||||
|
if (receivingAddresses
|
||||||
|
.intersection(output.addresses.toSet())
|
||||||
|
.isNotEmpty) {
|
||||||
|
wasReceivedInThisWallet = true;
|
||||||
|
amountReceivedInThisWallet += output.value;
|
||||||
|
output = output.copyWith(walletOwns: true);
|
||||||
|
} else if (changeAddresses
|
||||||
|
.intersection(output.addresses.toSet())
|
||||||
|
.isNotEmpty) {
|
||||||
|
wasReceivedInThisWallet = true;
|
||||||
|
changeAmountReceivedInThisWallet += output.value;
|
||||||
|
output = output.copyWith(walletOwns: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputs.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
final totalOut = outputs
|
||||||
|
.map((e) => e.value)
|
||||||
|
.fold(BigInt.zero, (value, element) => value + element);
|
||||||
|
|
||||||
|
TransactionType type;
|
||||||
|
TransactionSubType subType = TransactionSubType.none;
|
||||||
|
|
||||||
|
// At least one input was owned by this wallet.
|
||||||
|
if (wasSentFromThisWallet) {
|
||||||
|
type = TransactionType.outgoing;
|
||||||
|
|
||||||
|
if (wasReceivedInThisWallet) {
|
||||||
|
if (changeAmountReceivedInThisWallet + amountReceivedInThisWallet ==
|
||||||
|
totalOut) {
|
||||||
|
// Definitely sent all to self.
|
||||||
|
type = TransactionType.sentToSelf;
|
||||||
|
} else if (amountReceivedInThisWallet == BigInt.zero) {
|
||||||
|
// Most likely just a typical send, do nothing here yet.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namecoin doesn't have special outputs like tokens, ordinals, etc.
|
||||||
|
// But this is where you'd check for special outputs.
|
||||||
|
}
|
||||||
|
} else if (wasReceivedInThisWallet) {
|
||||||
|
// Only found outputs owned by this wallet.
|
||||||
|
type = TransactionType.incoming;
|
||||||
|
} else {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Unexpected tx found (ignoring it): $txData",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final tx = TransactionV2(
|
||||||
|
walletId: walletId,
|
||||||
|
blockHash: txData["blockhash"] as String?,
|
||||||
|
hash: txData["hash"] as String,
|
||||||
|
txid: txData["txid"] as String,
|
||||||
|
height: txData["height"] as int?,
|
||||||
|
version: txData["version"] as int,
|
||||||
|
timestamp: txData["blocktime"] as int? ??
|
||||||
|
DateTime.timestamp().millisecondsSinceEpoch ~/ 1000,
|
||||||
|
inputs: List.unmodifiable(inputs),
|
||||||
|
outputs: List.unmodifiable(outputs),
|
||||||
|
type: type,
|
||||||
|
subType: subType,
|
||||||
|
otherData: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
txns.add(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
await mainDB.updateOrPutTransactionV2s(txns);
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ import 'package:stackwallet/wallets/wallet/impl/monero_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/namecoin_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/namecoin_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/nano_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/nano_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/particl_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/particl_wallet.dart';
|
||||||
|
import 'package:stackwallet/wallets/wallet/impl/peercoin_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/solana_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/solana_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/stellar_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/stellar_wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/impl/sub_wallets/eth_token_wallet.dart';
|
import 'package:stackwallet/wallets/wallet/impl/sub_wallets/eth_token_wallet.dart';
|
||||||
|
@ -363,6 +364,11 @@ abstract class Wallet<T extends CryptoCurrency> {
|
||||||
case Coin.particl:
|
case Coin.particl:
|
||||||
return ParticlWallet(CryptoCurrencyNetwork.main);
|
return ParticlWallet(CryptoCurrencyNetwork.main);
|
||||||
|
|
||||||
|
case Coin.peercoin:
|
||||||
|
return PeercoinWallet(CryptoCurrencyNetwork.main);
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
|
return PeercoinWallet(CryptoCurrencyNetwork.test);
|
||||||
|
|
||||||
case Coin.solana:
|
case Coin.solana:
|
||||||
return SolanaWallet(CryptoCurrencyNetwork.main);
|
return SolanaWallet(CryptoCurrencyNetwork.main);
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,8 @@ class _NodeCardState extends ConsumerState<NodeCard> {
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
case Coin.bitcoinFrost:
|
case Coin.bitcoinFrost:
|
||||||
case Coin.bitcoinFrostTestNet:
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
try {
|
try {
|
||||||
testPassed = await checkElectrumServer(
|
testPassed = await checkElectrumServer(
|
||||||
host: node.host,
|
host: node.host,
|
||||||
|
|
|
@ -154,6 +154,8 @@ class NodeOptionsSheet extends ConsumerWidget {
|
||||||
case Coin.eCash:
|
case Coin.eCash:
|
||||||
case Coin.bitcoinFrost:
|
case Coin.bitcoinFrost:
|
||||||
case Coin.bitcoinFrostTestNet:
|
case Coin.bitcoinFrostTestNet:
|
||||||
|
case Coin.peercoin:
|
||||||
|
case Coin.peercoinTestNet:
|
||||||
try {
|
try {
|
||||||
testPassed = await checkElectrumServer(
|
testPassed = await checkElectrumServer(
|
||||||
host: node.host,
|
host: node.host,
|
||||||
|
|
Loading…
Reference in a new issue