Pluginify BTCPayNetworkProvider (#5331)

This commit is contained in:
Nicolas Dorier 2023-11-29 18:51:40 +09:00 committed by GitHub
parent 1081eab9db
commit 04292d09e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
139 changed files with 1251 additions and 1075 deletions

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitAlthash()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("HTML");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Htmlcoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.htmlcoin.com/api/tx/{0}" : "https://explorer.htmlcoin.com/api/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"HTML_X = HTML_USD",
"HTML_USD = hitbtc(HTML_USD)"
},
CryptoImagePath = "imlegacy/althash.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("172'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,30 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitArgoneum()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("AGM");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Argoneum",
BlockExplorerLink = NetworkType == ChainName.Mainnet
? "https://chainz.cryptoid.info/agm/tx.dws?{0}"
: "https://chainz.cryptoid.info/agm-test/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"AGM_X = AGM_BTC * BTC_X",
"AGM_BTC = argoneum(AGM_BTC)"
},
CryptoImagePath = "imlegacy/argoneum.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("421'")
: new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBGold()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTG");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BGold",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://btgexplorer.com/tx/{0}" : "https://testnet.btgexplorer.com/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"BTG_X = BTG_BTC * BTC_X",
"BTG_BTC = gate(BTG_BTC)",
},
CryptoImagePath = "imlegacy/btg.svg",
LightningImagePath = "imlegacy/btg-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("156'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBPlus()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("XBC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BPlus",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"XBC_X = XBC_BTC * BTC_X",
"XBC_BTC = cryptopia(XBC_BTC)"
},
CryptoImagePath = "imlegacy/xbc.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("65'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,29 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBitcore()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTX");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BitCore",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.bitcore.cc/tx/{0}" : "https://explorer.bitcore.cc/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"BTX_X = BTX_BTC * BTC_X",
"BTX_BTC = graviex(BTX_BTC)"
},
CryptoImagePath = "imlegacy/bitcore.svg",
LightningImagePath = "imlegacy/bitcore-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("160'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,32 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitDash()
{
//not needed: NBitcoin.Altcoins.Dash.Instance.EnsureRegistered();
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("DASH");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Dash",
BlockExplorerLink = NetworkType == ChainName.Mainnet
? "https://insight.dash.org/insight/tx/{0}"
: "https://testnet-insight.dashevo.org/insight/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"DASH_X = DASH_BTC * BTC_X",
"DASH_BTC = bitfinex(DSH_BTC)"
},
CryptoImagePath = "imlegacy/dash.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("5'")
: new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitDogecoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("DOGE");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Dogecoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://dogechain.info/tx/{0}" : "https://dogechain.info/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"DOGE_X = DOGE_BTC * BTC_X",
"DOGE_BTC = bittrex(DOGE_BTC)"
},
CryptoImagePath = "imlegacy/dogecoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("3'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitFeathercoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("FTC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Feathercoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.feathercoin.com/tx/{0}" : "https://explorer.feathercoin.com/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"FTC_X = FTC_BTC * BTC_X",
"FTC_BTC = bittrex(FTC_BTC)"
},
CryptoImagePath = "imlegacy/feathercoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("8'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,33 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitGroestlcoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("GRS");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Groestlcoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet
? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm"
: "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"GRS_X = GRS_BTC * BTC_X",
"GRS_BTC = bittrex(GRS_BTC)"
},
CryptoImagePath = "imlegacy/groestlcoin.png",
LightningImagePath = "imlegacy/groestlcoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("17'") : new KeyPath("1'"),
SupportRBF = true,
SupportPayJoin = true,
VaultSupported = true
});
}
}
}

View file

@ -1,46 +0,0 @@
using System.Collections.Generic;
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitLitecoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LTC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Litecoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet
? "https://live.blockcypher.com/ltc/tx/{0}/"
: "http://explorer.litecointools.com/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"LTC_X = LTC_BTC * BTC_X",
"LTC_BTC = coingecko(LTC_BTC)"
},
CryptoImagePath = "imlegacy/litecoin.svg",
LightningImagePath = "imlegacy/litecoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("2'") : new KeyPath("1'"),
//https://github.com/pooler/electrum-ltc/blob/0d6989a9d2fb2edbea421c116e49d1015c7c5a91/electrum_ltc/constants.py
ElectrumMapping = NetworkType == ChainName.Mainnet
? new Dictionary<uint, DerivationType>()
{
{0x0488b21eU, DerivationType.Legacy },
{0x049d7cb2U, DerivationType.SegwitP2SH },
{0x04b24746U, DerivationType.Segwit },
}
: new Dictionary<uint, DerivationType>()
{
{0x043587cfU, DerivationType.Legacy },
{0x044a5262U, DerivationType.SegwitP2SH },
{0x045f1cf6U, DerivationType.Segwit }
}
});
}
}
}

View file

@ -1,29 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitMonacoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("MONA");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Monacoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://mona.insight.monaco-ex.org/insight/tx/{0}" : "https://testnet-mona.insight.monaco-ex.org/insight/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"MONA_X = MONA_BTC * BTC_X",
"MONA_BTC = bittrex(MONA_BTC)"
},
CryptoImagePath = "imlegacy/monacoin.png",
LightningImagePath = "imlegacy/mona-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("22'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitPolis()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("POLIS");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Polis",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://blockbook.polispay.org/tx/{0}" : "https://blockbook.polispay.org/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"POLIS_X = POLIS_BTC * BTC_X",
"POLIS_BTC = polispay(POLIS_BTC)"
},
CryptoImagePath = "imlegacy/polis.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1997'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitUfo()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("UFO");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Ufo",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://chainz.cryptoid.info/ufo/tx.dws?{0}" : "https://chainz.cryptoid.info/ufo/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"UFO_X = UFO_BTC * BTC_X",
"UFO_BTC = coinexchange(UFO_BTC)"
},
CryptoImagePath = "imlegacy/ufo.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("202'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,28 +0,0 @@
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitViacoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("VIA");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Viacoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://explorer.viacoin.org/tx/{0}" : "https://explorer.viacoin.org/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"VIA_X = VIA_BTC * BTC_X",
"VIA_BTC = bittrex(VIA_BTC)"
},
CryptoImagePath = "imlegacy/viacoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("14'") : new KeyPath("1'")
});
}
}
}

View file

@ -1,37 +0,0 @@
#if ALTCOINS
using NBitcoin;
using NBitcoin.Altcoins;
using NBitcoin.Altcoins.Elements;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitLiquid()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
Add(new ElementsBTCPayNetwork()
{
AssetId = NetworkType == ChainName.Mainnet ? ElementsParams<Liquid>.PeggedAssetId : ElementsParams<Liquid.LiquidRegtest>.PeggedAssetId,
CryptoCode = "LBTC",
NetworkCryptoCode = "LBTC",
DisplayName = "Liquid Bitcoin",
DefaultRateRules = new[]
{
"LBTC_X = LBTC_BTC * BTC_X",
"LBTC_BTC = 1",
},
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/liquid.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true
});
}
}
}
#endif

View file

@ -1,83 +0,0 @@
#if ALTCOINS
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitLiquidAssets()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
Add(new ElementsBTCPayNetwork()
{
CryptoCode = "USDt",
NetworkCryptoCode = "LBTC",
ShowSyncSummary = false,
DefaultRateRules = new[]
{
"USDT_UST = 1",
"USDT_X = USDT_BTC * BTC_X",
"USDT_BTC = bitfinex(UST_BTC)",
},
AssetId = NetworkType == ChainName.Regtest? null: new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
DisplayName = "Liquid Tether",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/liquid-tether.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
});
Add(new ElementsBTCPayNetwork()
{
CryptoCode = "ETB",
NetworkCryptoCode = "LBTC",
ShowSyncSummary = false,
DefaultRateRules = new[]
{
"ETB_X = ETB_BTC * BTC_X",
"ETB_BTC = bitpay(ETB_BTC)"
},
Divisibility = 2,
AssetId = NetworkType == ChainName.Regtest? null: new uint256("aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf"),
DisplayName = "Ethiopian Birr",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/etb.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
});
Add(new ElementsBTCPayNetwork()
{
CryptoCode = "LCAD",
NetworkCryptoCode = "LBTC",
ShowSyncSummary = false,
DefaultRateRules = new[]
{
"LCAD_CAD = 1",
"LCAD_X = CAD_BTC * BTC_X",
"LCAD_BTC = bylls(CAD_BTC)",
"CAD_BTC = LCAD_BTC"
},
AssetId = NetworkType == ChainName.Regtest? null: new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
DisplayName = "Liquid CAD",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/lcad.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
});
}
}
}
#endif

View file

@ -1,51 +0,0 @@
#if ALTCOINS
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Common;
using NBitcoin;
using NBXplorer;
using NBXplorer.Models;
namespace BTCPayServer
{
public class ElementsBTCPayNetwork : BTCPayNetwork
{
public string NetworkCryptoCode { get; set; }
public uint256 AssetId { get; set; }
public override bool ReadonlyWallet { get; set; } = true;
public override IEnumerable<(MatchedOutput matchedOutput, OutPoint outPoint)> GetValidOutputs(
NewTransactionEvent evtOutputs)
{
return evtOutputs.Outputs.Where(output =>
(output.Value is not AssetMoney && NetworkCryptoCode.Equals(evtOutputs.CryptoCode, StringComparison.InvariantCultureIgnoreCase)) ||
(output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId)).Select(output =>
{
var outpoint = new OutPoint(evtOutputs.TransactionData.TransactionHash, output.Index);
return (output, outpoint);
});
}
public override List<TransactionInformation> FilterValidTransactions(List<TransactionInformation> transactionInformationSet)
{
return transactionInformationSet.FindAll(information =>
information.Outputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId) ||
information.Inputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId));
}
public override PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, decimal? cryptoInfoDue)
{
//precision 0: 10 = 0.00000010
//precision 2: 10 = 0.00001000
//precision 8: 10 = 10
var money = cryptoInfoDue / (decimal)Math.Pow(10, 8 - Divisibility);
var builder = base.GenerateBIP21(cryptoInfoAddress, money);
builder.QueryParams.Add("assetid", AssetId.ToString());
return builder;
}
}
}
#endif

View file

@ -1,18 +0,0 @@
#if ALTCOINS
using System.Collections.Generic;
using System.Linq;
namespace BTCPayServer
{
public static class LiquidExtensions
{
public static IEnumerable<string> GetAllElementsSubChains(this BTCPayNetworkProvider networkProvider, BTCPayNetworkProvider unfiltered)
{
var elementsBased = networkProvider.GetAll().OfType<ElementsBTCPayNetwork>();
var parentChains = elementsBased.Select(network => network.NetworkCryptoCode.ToUpperInvariant()).Distinct();
return unfiltered.GetAll().OfType<ElementsBTCPayNetwork>()
.Where(network => parentChains.Contains(network.NetworkCryptoCode)).Select(network => network.CryptoCode.ToUpperInvariant());
}
}
}
#endif

View file

@ -1,28 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitMonero()
{
Add(new MoneroLikeSpecificBtcPayNetwork()
{
CryptoCode = "XMR",
DisplayName = "Monero",
Divisibility = 12,
BlockExplorerLink =
NetworkType == ChainName.Mainnet
? "https://www.exploremonero.com/transaction/{0}"
: "https://testnet.xmrchain.net/tx/{0}",
DefaultRateRules = new[]
{
"XMR_X = XMR_BTC * BTC_X",
"XMR_BTC = kraken(XMR_BTC)"
},
CryptoImagePath = "/imlegacy/monero.svg",
UriScheme = "monero"
});
}
}
}

View file

@ -1,8 +0,0 @@
namespace BTCPayServer
{
public class MoneroLikeSpecificBtcPayNetwork : BTCPayNetworkBase
{
public int MaxTrackedConfirmation = 10;
public string UriScheme { get; set; }
}
}

View file

@ -1,29 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
// Change this if you want another zcash coin
public void InitZcash()
{
Add(new ZcashLikeSpecificBtcPayNetwork()
{
CryptoCode = "ZEC",
DisplayName = "Zcash",
Divisibility = 8,
BlockExplorerLink =
NetworkType == ChainName.Mainnet
? "https://www.exploreZcash.com/transaction/{0}"
: "https://testnet.xmrchain.net/tx/{0}",
DefaultRateRules = new[]
{
"ZEC_X = ZEC_BTC * BTC_X",
"ZEC_BTC = kraken(ZEC_BTC)"
},
CryptoImagePath = "/imlegacy/zcash.png",
UriScheme = "zcash"
});
}
}
}

View file

@ -1,8 +0,0 @@
namespace BTCPayServer
{
public class ZcashLikeSpecificBtcPayNetwork : BTCPayNetworkBase
{
public int MaxTrackedConfirmation = 10;
public string UriScheme { get; set; }
}
}

View file

@ -4,6 +4,8 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using BTCPayServer.Common; using BTCPayServer.Common;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin; using NBitcoin;
using NBXplorer; using NBXplorer;
using NBXplorer.Models; using NBXplorer.Models;
@ -62,6 +64,31 @@ namespace BTCPayServer
public KeyPath CoinType { get; set; } public KeyPath CoinType { get; set; }
public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>(); public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>();
public BTCPayNetwork SetDefaultElectrumMapping(ChainName chainName)
{
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
ElectrumMapping = chainName == ChainName.Mainnet
? new Dictionary<uint, DerivationType>()
{
{0x0488b21eU, DerivationType.Legacy }, // xpub
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
{0x04b24746U, DerivationType.Segwit }, //zpub
}
: new Dictionary<uint, DerivationType>()
{
{0x043587cfU, DerivationType.Legacy}, // tpub
{0x044a5262U, DerivationType.SegwitP2SH}, // upub
{0x045f1cf6U, DerivationType.Segwit} // vpub
};
if (!NBitcoinNetwork.Consensus.SupportSegwit)
{
ElectrumMapping =
ElectrumMapping
.Where(kv => kv.Value == DerivationType.Legacy)
.ToDictionary(k => k.Key, k => k.Value);
}
return this;
}
public virtual bool WalletSupported { get; set; } = true; public virtual bool WalletSupported { get; set; } = true;
public virtual bool ReadonlyWallet { get; set; } = false; public virtual bool ReadonlyWallet { get; set; } = false;
@ -107,25 +134,8 @@ namespace BTCPayServer
public abstract class BTCPayNetworkBase public abstract class BTCPayNetworkBase
{ {
private string _blockExplorerLink;
public bool ShowSyncSummary { get; set; } = true; public bool ShowSyncSummary { get; set; } = true;
public string CryptoCode { get; set; } public string CryptoCode { get; set; }
public string BlockExplorerLink
{
get => _blockExplorerLink;
set
{
if (string.IsNullOrEmpty(BlockExplorerLinkDefault))
{
BlockExplorerLinkDefault = value;
}
_blockExplorerLink = value;
}
}
public string BlockExplorerLinkDefault { get; set; }
public string DisplayName { get; set; } public string DisplayName { get; set; }
public int Divisibility { get; set; } = 8; public int Divisibility { get; set; } = 8;
public bool IsBTC public bool IsBTC
@ -153,5 +163,8 @@ namespace BTCPayServer
{ {
return NBitcoin.JsonConverters.Serializer.ToString(obj, null); return NBitcoin.JsonConverters.Serializer.ToString(obj, null);
} }
[Obsolete("Use TransactionLinkProviders service instead")]
public string BlockExplorerLink { get; set; }
} }
} }

View file

@ -1,44 +0,0 @@
using System.Collections.Generic;
using NBitcoin;
using NBXplorer;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBitcoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Bitcoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet ? "https://mempool.space/tx/{0}" :
NetworkType == Bitcoin.Instance.Signet.ChainName ? "https://mempool.space/signet/tx/{0}"
: "https://mempool.space/testnet/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/bitcoin.svg",
LightningImagePath = "imlegacy/bitcoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("0'") : new KeyPath("1'"),
SupportRBF = true,
SupportPayJoin = true,
VaultSupported = true,
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
ElectrumMapping = NetworkType == ChainName.Mainnet
? new Dictionary<uint, DerivationType>()
{
{0x0488b21eU, DerivationType.Legacy }, // xpub
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
{0x04b24746U, DerivationType.Segwit }, //zpub
}
: new Dictionary<uint, DerivationType>()
{
{0x043587cfU, DerivationType.Legacy}, // tpub
{0x044a5262U, DerivationType.SegwitP2SH}, // upub
{0x045f1cf6U, DerivationType.Segwit} // vpub
}
});
}
}
}

View file

@ -1,8 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using BTCPayServer.Configuration;
using BTCPayServer.Logging;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NBitcoin; using NBitcoin;
using NBXplorer; using NBXplorer;
using StandardConfiguration;
namespace BTCPayServer namespace BTCPayServer
{ {
@ -19,92 +26,39 @@ namespace BTCPayServer
} }
} }
BTCPayNetworkProvider(BTCPayNetworkProvider unfiltered, string[] cryptoCodes)
{
NetworkType = unfiltered.NetworkType;
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(unfiltered.NetworkType);
_Networks = new Dictionary<string, BTCPayNetworkBase>();
cryptoCodes = cryptoCodes.Select(c => c.ToUpperInvariant()).ToArray();
foreach (var network in unfiltered._Networks)
{
if (cryptoCodes.Contains(network.Key))
{
_Networks.Add(network.Key, network.Value);
}
}
}
public ChainName NetworkType { get; private set; } public ChainName NetworkType { get; private set; }
public BTCPayNetworkProvider(ChainName networkType) public BTCPayNetworkProvider(
IEnumerable<BTCPayNetworkBase> networks,
SelectedChains selectedChains,
NBXplorerNetworkProvider nbxplorerNetworkProvider,
Logs logs,
IConfiguration configuration)
{ {
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(networkType); #if !ALTCOINS
NetworkType = networkType; var onlyBTC = networks.Count() == 1 && networks.First().IsBTC;
InitBitcoin(); if (!onlyBTC)
#if ALTCOINS throw new ConfigException($"This build of BTCPay Server does not support altcoins");
InitLiquid(); #endif
InitLiquidAssets();
InitLitecoin();
InitBitcore();
InitDogecoin();
InitBGold();
InitMonacoin();
InitDash();
InitFeathercoin();
InitAlthash();
InitGroestlcoin();
InitViacoin();
InitMonero();
InitZcash();
// InitArgoneum();//their rate source is down 9/15/20.
// InitMonetaryUnit(); Not supported from Bittrex from 11/23/2022, dead shitcoin
// Assume that electrum mappings are same as BTC if not specified _NBXplorerNetworkProvider = nbxplorerNetworkProvider;
foreach (var network in _Networks.Values.OfType<BTCPayNetwork>()) NetworkType = nbxplorerNetworkProvider.NetworkType;
foreach (var network in networks)
{ {
if (network.ElectrumMapping.Count == 0) _Networks.Add(network.CryptoCode.ToUpperInvariant(), network);
{
network.ElectrumMapping = GetNetwork<BTCPayNetwork>("BTC").ElectrumMapping;
if (!network.NBitcoinNetwork.Consensus.SupportSegwit)
{
network.ElectrumMapping =
network.ElectrumMapping
.Where(kv => kv.Value == DerivationType.Legacy)
.ToDictionary(k => k.Key, k => k.Value);
}
}
} }
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586 foreach (var chain in selectedChains.ExplicitlySelected)
//InitBPlus(); {
//InitUfo(); if (GetNetwork<BTCPayNetworkBase>(chain) == null)
#endif throw new ConfigException($"Invalid chains \"{chain}\"");
} }
/// <summary> logs.Configuration.LogInformation(
/// Keep only the specified crypto "Supported chains: " + String.Join(',', _Networks.Select(n => n.Key).ToArray()));
/// </summary>
/// <param name="cryptoCodes">Crypto to support</param>
/// <returns></returns>
public BTCPayNetworkProvider Filter(string[] cryptoCodes)
{
return new BTCPayNetworkProvider(this, cryptoCodes);
} }
public BTCPayNetwork BTC => GetNetwork<BTCPayNetwork>("BTC"); public BTCPayNetwork BTC => GetNetwork<BTCPayNetwork>("BTC");
public BTCPayNetworkBase DefaultNetwork => BTC ?? GetAll().First(); public BTCPayNetworkBase DefaultNetwork => BTC ?? GetAll().First();
public void Add(BTCPayNetwork network)
{
if (network.NBitcoinNetwork == null)
return;
Add(network as BTCPayNetworkBase);
}
public void Add(BTCPayNetworkBase network)
{
_Networks.Add(network.CryptoCode.ToUpperInvariant(), network);
}
public IEnumerable<BTCPayNetworkBase> GetAll() public IEnumerable<BTCPayNetworkBase> GetAll()
{ {
return _Networks.Values.ToArray(); return _Networks.Values.ToArray();

View file

@ -10,4 +10,7 @@
<ItemGroup Condition="'$(Altcoins)' != 'true'"> <ItemGroup Condition="'$(Altcoins)' != 'true'">
<Compile Remove="Altcoins\**\*.cs"></Compile> <Compile Remove="Altcoins\**\*.cs"></Compile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Altcoins\" />
</ItemGroup>
</Project> </Project>

View file

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Bson;
namespace BTCPayServer
{
public class SelectedChains
{
HashSet<string> chains = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
bool all = false;
public SelectedChains(IConfiguration configuration, Logs logs)
{
foreach (var chain in (configuration["chains"] ?? "btc")
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(t => t.ToUpperInvariant()))
{
if (new[] { "ETH", "USDT20", "FAU" }.Contains(chain, StringComparer.OrdinalIgnoreCase))
{
logs.Configuration.LogWarning($"'{chain}' is not anymore supported, please remove it from 'chains'");
continue;
}
if (chain == "*")
{
all = true;
continue;
}
chains.Add(chain);
}
if (chains.Count == 0)
chains.Add("BTC");
if (all)
chains.Clear();
}
public bool Contains(string cryptoCode)
{
return all || chains.Contains(cryptoCode);
}
public void Add(string cryptoCode)
{
chains.Add(cryptoCode);
}
public IEnumerable<string> ExplicitlySelected => chains;
}
}

View file

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using BTCPayServer.Configuration; using BTCPayServer.Configuration;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Models.WalletViewModels; using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Plugins.Altcoins;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
using BTCPayServer.Tests.Logging; using BTCPayServer.Tests.Logging;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View file

@ -10,6 +10,7 @@ using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Configuration; using BTCPayServer.Configuration;
@ -18,9 +19,12 @@ using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Hosting; using BTCPayServer.Hosting;
using BTCPayServer.JsonConverters; using BTCPayServer.JsonConverters;
using BTCPayServer.Logging;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.Plugins;
using BTCPayServer.Plugins.Bitcoin;
using BTCPayServer.Rating; using BTCPayServer.Rating;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
@ -410,7 +414,7 @@ namespace BTCPayServer.Tests
public void CanCalculateDust() public void CanCalculateDust()
{ {
var entity = new InvoiceEntity() { Currency = "USD" }; var entity = new InvoiceEntity() { Currency = "USD" };
entity.Networks = new BTCPayNetworkProvider(ChainName.Regtest); entity.Networks = CreateNetworkProvider(ChainName.Regtest);
#pragma warning disable CS0618 #pragma warning disable CS0618
entity.Payments = new System.Collections.Generic.List<PaymentEntity>(); entity.Payments = new System.Collections.Generic.List<PaymentEntity>();
entity.SetPaymentMethod(new PaymentMethod() entity.SetPaymentMethod(new PaymentMethod()
@ -456,7 +460,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
public void CanCalculateCryptoDue() public void CanCalculateCryptoDue()
{ {
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest); var networkProvider = CreateNetworkProvider(ChainName.Regtest);
var entity = new InvoiceEntity() { Currency = "USD" }; var entity = new InvoiceEntity() { Currency = "USD" };
entity.Networks = networkProvider; entity.Networks = networkProvider;
#pragma warning disable CS0618 #pragma warning disable CS0618
@ -644,7 +648,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
public void CanAcceptInvoiceWithTolerance() public void CanAcceptInvoiceWithTolerance()
{ {
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest); var networkProvider = CreateNetworkProvider(ChainName.Regtest);
var paymentMethodHandlerDictionary = new PaymentMethodHandlerDictionary(new IPaymentMethodHandler[] var paymentMethodHandlerDictionary = new PaymentMethodHandlerDictionary(new IPaymentMethodHandler[]
{ {
new BitcoinLikePaymentHandler(null, networkProvider, null, null, null, null), new BitcoinLikePaymentHandler(null, networkProvider, null, null, null, null),
@ -764,7 +768,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
public async Task CanEnumerateTorServices() public async Task CanEnumerateTorServices()
{ {
var tor = new TorServices(new BTCPayNetworkProvider(ChainName.Regtest), var tor = new TorServices(CreateNetworkProvider(ChainName.Regtest),
new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions() new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions()
{ {
TorrcFile = TestUtils.GetTestDataFullPath("Tor/torrc") TorrcFile = TestUtils.GetTestDataFullPath("Tor/torrc")
@ -776,7 +780,7 @@ namespace BTCPayServer.Tests
Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.RPC)); Assert.Single(tor.Services.Where(t => t.ServiceType == TorServiceType.RPC));
Assert.True(tor.Services.Count(t => t.ServiceType == TorServiceType.Other) > 1); Assert.True(tor.Services.Count(t => t.ServiceType == TorServiceType.Other) > 1);
tor = new TorServices(new BTCPayNetworkProvider(ChainName.Regtest), tor = new TorServices(CreateNetworkProvider(ChainName.Regtest),
new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions() new OptionsWrapper<BTCPayServerOptions>(new BTCPayServerOptions()
{ {
TorrcFile = null, TorrcFile = null,
@ -813,7 +817,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
public void CanParseDerivationSchemes() public void CanParseDerivationSchemes()
{ {
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest); var networkProvider = CreateNetworkProvider(ChainName.Regtest);
var parser = new DerivationSchemeParser(networkProvider.BTC); var parser = new DerivationSchemeParser(networkProvider.BTC);
// xpub // xpub
@ -839,7 +843,7 @@ namespace BTCPayServer.Tests
Assert.Equal(expected, inner.ToString()); Assert.Equal(expected, inner.ToString());
// Output Descriptor // Output Descriptor
networkProvider = new BTCPayNetworkProvider(ChainName.Mainnet); networkProvider = CreateNetworkProvider(ChainName.Mainnet);
parser = new DerivationSchemeParser(networkProvider.BTC); parser = new DerivationSchemeParser(networkProvider.BTC);
var od = "wpkh([8bafd160/49h/0h/0h]xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw/0/*)#9x4vkw48"; var od = "wpkh([8bafd160/49h/0h/0h]xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw/0/*)#9x4vkw48";
(strategyBase, rootedKeyPath) = parser.ParseOutputDescriptor(od); (strategyBase, rootedKeyPath) = parser.ParseOutputDescriptor(od);
@ -881,8 +885,8 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
public void ParseDerivationSchemeSettings() public void ParseDerivationSchemeSettings()
{ {
var testnet = new BTCPayNetworkProvider(ChainName.Testnet).GetNetwork<BTCPayNetwork>("BTC"); var testnet = CreateNetworkProvider(ChainName.Testnet).GetNetwork<BTCPayNetwork>("BTC");
var mainnet = new BTCPayNetworkProvider(ChainName.Mainnet).GetNetwork<BTCPayNetwork>("BTC"); var mainnet = CreateNetworkProvider(ChainName.Mainnet).GetNetwork<BTCPayNetwork>("BTC");
var root = new Mnemonic( var root = new Mnemonic(
"usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage") "usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage")
.DeriveExtKey(); .DeriveExtKey();
@ -1245,7 +1249,7 @@ namespace BTCPayServer.Tests
[Fact] [Fact]
public void HasCurrencyDataForNetworks() public void HasCurrencyDataForNetworks()
{ {
var btcPayNetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest); var btcPayNetworkProvider = CreateNetworkProvider(ChainName.Regtest);
foreach (var network in btcPayNetworkProvider.GetAll()) foreach (var network in btcPayNetworkProvider.GetAll())
{ {
var cd = CurrencyNameTable.Instance.GetCurrencyData(network.CryptoCode, false); var cd = CurrencyNameTable.Instance.GetCurrencyData(network.CryptoCode, false);
@ -1824,8 +1828,7 @@ namespace BTCPayServer.Tests
new KeyValuePair<string, string>("chains", "usdt")} new KeyValuePair<string, string>("chains", "usdt")}
}) })
}); });
var networkProvider = CreateNetworkProvider(config);
var networkProvider = config.ConfigureNetworkProvider(BTCPayLogs);
Assert.NotNull(networkProvider.GetNetwork("LBTC")); Assert.NotNull(networkProvider.GetNetwork("LBTC"));
Assert.NotNull(networkProvider.GetNetwork("USDT")); Assert.NotNull(networkProvider.GetNetwork("USDT"));
} }
@ -1833,9 +1836,9 @@ namespace BTCPayServer.Tests
[Trait("Altcoins", "Altcoins")] [Trait("Altcoins", "Altcoins")]
public void CanParseDerivationScheme() public void CanParseDerivationScheme()
{ {
var testnetNetworkProvider = new BTCPayNetworkProvider(ChainName.Testnet); var testnetNetworkProvider = CreateNetworkProvider(ChainName.Testnet);
var regtestNetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest); var regtestNetworkProvider = CreateNetworkProvider(ChainName.Regtest);
var mainnetNetworkProvider = new BTCPayNetworkProvider(ChainName.Mainnet); var mainnetNetworkProvider = CreateNetworkProvider(ChainName.Mainnet);
var testnetParser = new DerivationSchemeParser(testnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC")); var testnetParser = new DerivationSchemeParser(testnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
var mainnetParser = new DerivationSchemeParser(mainnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC")); var mainnetParser = new DerivationSchemeParser(mainnetNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
NBXplorer.DerivationStrategy.DerivationStrategyBase result; NBXplorer.DerivationStrategy.DerivationStrategyBase result;
@ -2001,7 +2004,7 @@ namespace BTCPayServer.Tests
{ {
#pragma warning disable CS0618 #pragma warning disable CS0618
var dummy = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest).ToString(); var dummy = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.RegTest).ToString();
var networkProvider = new BTCPayNetworkProvider(ChainName.Regtest); var networkProvider = CreateNetworkProvider(ChainName.Regtest);
var networkBTC = networkProvider.GetNetwork("BTC"); var networkBTC = networkProvider.GetNetwork("BTC");
var networkLTC = networkProvider.GetNetwork("LTC"); var networkLTC = networkProvider.GetNetwork("LTC");
InvoiceEntity invoiceEntity = new InvoiceEntity(); InvoiceEntity invoiceEntity = new InvoiceEntity();
@ -2118,7 +2121,7 @@ namespace BTCPayServer.Tests
{ {
["derivationStrategy"] = "tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf" ["derivationStrategy"] = "tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf"
}; };
var scheme = DerivationSchemeSettings.Parse("tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf", new BTCPayNetworkProvider(ChainName.Regtest).BTC); var scheme = DerivationSchemeSettings.Parse("tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf", CreateNetworkProvider(ChainName.Regtest).BTC);
scheme.Source = "ManualDerivationScheme"; scheme.Source = "ManualDerivationScheme";
scheme.AccountOriginal = "tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf"; scheme.AccountOriginal = "tpubDDLQZ1WMdy5YJAJWmRNoTJ3uQkavEPXCXnmD4eAuo9BKbzFUBbJmVHys5M3ku4Qw1C165wGpVWH55gZpHjdsCyntwNzhmCAzGejSL6rzbyf";
@ -2138,7 +2141,7 @@ namespace BTCPayServer.Tests
.Select(o => .Select(o =>
{ {
var entity = JsonConvert.DeserializeObject<InvoiceEntity>(o.ToString()); var entity = JsonConvert.DeserializeObject<InvoiceEntity>(o.ToString());
entity.Networks = new BTCPayNetworkProvider(ChainName.Regtest); entity.Networks = CreateNetworkProvider(ChainName.Regtest);
return entity.DerivationStrategies.ToString(); return entity.DerivationStrategies.ToString();
}) })
.ToHashSet(); .ToHashSet();

View file

@ -5,11 +5,14 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Hosting;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using BTCPayServer.Lightning.CLightning; using BTCPayServer.Lightning.CLightning;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.Tests.Lnd; using BTCPayServer.Tests.Lnd;
using BTCPayServer.Tests.Logging; using BTCPayServer.Tests.Logging;
using Microsoft.Extensions.Configuration.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NBitcoin; using NBitcoin;
using NBitcoin.RPC; using NBitcoin.RPC;
@ -26,7 +29,7 @@ namespace BTCPayServer.Tests
public ILoggerProvider LoggerProvider { get; } public ILoggerProvider LoggerProvider { get; }
internal ILog TestLogs; internal ILog TestLogs;
public ServerTester(string scope, bool newDb, ILog testLogs, ILoggerProvider loggerProvider) public ServerTester(string scope, bool newDb, ILog testLogs, ILoggerProvider loggerProvider, BTCPayNetworkProvider networkProvider)
{ {
LoggerProvider = loggerProvider; LoggerProvider = loggerProvider;
this.TestLogs = testLogs; this.TestLogs = testLogs;
@ -36,7 +39,7 @@ namespace BTCPayServer.Tests
if (!Directory.Exists(_Directory)) if (!Directory.Exists(_Directory))
Directory.CreateDirectory(_Directory); Directory.CreateDirectory(_Directory);
NetworkProvider = new BTCPayNetworkProvider(ChainName.Regtest); NetworkProvider = networkProvider;
ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_BTCRPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork); ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_BTCRPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork);
ExplorerNode.ScanRPCCapabilities(); ExplorerNode.ScanRPCCapabilities();

View file

@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
using OpenQA.Selenium; using OpenQA.Selenium;
using Xunit; using Xunit;
using Xunit.Sdk; using Xunit.Sdk;

View file

@ -300,7 +300,7 @@ retry:
[Fact()] [Fact()]
public void CanSolveTheDogesRatesOnKraken() public void CanSolveTheDogesRatesOnKraken()
{ {
var provider = new BTCPayNetworkProvider(ChainName.Mainnet); var provider = CreateNetworkProvider(ChainName.Mainnet);
var factory = FastTests.CreateBTCPayRateFactory(); var factory = FastTests.CreateBTCPayRateFactory();
var fetcher = new RateFetcher(factory); var fetcher = new RateFetcher(factory);
@ -318,7 +318,7 @@ retry:
{ {
var factory = FastTests.CreateBTCPayRateFactory(); var factory = FastTests.CreateBTCPayRateFactory();
var fetcher = new RateFetcher(factory); var fetcher = new RateFetcher(factory);
var provider = new BTCPayNetworkProvider(ChainName.Mainnet); var provider = CreateNetworkProvider(ChainName.Mainnet);
var b = new StoreBlob(); var b = new StoreBlob();
string[] temporarilyBroken = { "COP", "UGX" }; string[] temporarilyBroken = { "COP", "UGX" };
foreach (var k in StoreBlob.RecommendedExchanges) foreach (var k in StoreBlob.RecommendedExchanges)
@ -351,7 +351,7 @@ retry:
public async Task CanGetRateCryptoCurrenciesByDefault() public async Task CanGetRateCryptoCurrenciesByDefault()
{ {
using var cts = new CancellationTokenSource(60_000); using var cts = new CancellationTokenSource(60_000);
var provider = new BTCPayNetworkProvider(ChainName.Mainnet); var provider = CreateNetworkProvider(ChainName.Mainnet);
var factory = FastTests.CreateBTCPayRateFactory(); var factory = FastTests.CreateBTCPayRateFactory();
var fetcher = new RateFetcher(factory); var fetcher = new RateFetcher(factory);
var pairs = var pairs =

View file

@ -3,8 +3,18 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Hosting;
using BTCPayServer.Logging;
using BTCPayServer.Plugins.Bitcoin;
using BTCPayServer.Plugins;
using BTCPayServer.Tests.Logging; using BTCPayServer.Tests.Logging;
using Microsoft.Extensions.DependencyInjection;
using NBXplorer;
using Xunit.Abstractions; using Xunit.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;
using NBitcoin;
namespace BTCPayServer.Tests namespace BTCPayServer.Tests
{ {
@ -15,7 +25,53 @@ namespace BTCPayServer.Tests
TestLogs = new XUnitLog(helper) { Name = "Tests" }; TestLogs = new XUnitLog(helper) { Name = "Tests" };
TestLogProvider = new XUnitLogProvider(helper); TestLogProvider = new XUnitLogProvider(helper);
BTCPayLogs = new BTCPayServer.Logging.Logs(); BTCPayLogs = new BTCPayServer.Logging.Logs();
BTCPayLogs.Configure(new BTCPayServer.Logging.FuncLoggerFactory((n) => new XUnitLog(helper) { Name = n })); LoggerFactory = new BTCPayServer.Logging.FuncLoggerFactory((n) => new XUnitLog(helper) { Name = n });
BTCPayLogs.Configure(LoggerFactory);
}
public BTCPayNetworkProvider CreateNetworkProvider(ChainName chainName)
{
var conf = new ConfigurationRoot(new List<IConfigurationProvider>()
{
new MemoryConfigurationProvider(new MemoryConfigurationSource()
{
InitialData = new[] {
new KeyValuePair<string, string>("chains", "*"),
new KeyValuePair<string, string>("network", chainName.ToString())
}
})
});
return CreateNetworkProvider(conf);
}
public BTCPayNetworkProvider CreateNetworkProvider(IConfiguration conf = null)
{
conf ??= new ConfigurationRoot(new List<IConfigurationProvider>()
{
new MemoryConfigurationProvider(new MemoryConfigurationSource()
{
InitialData = new[] {
new KeyValuePair<string, string>("chains", "*"),
new KeyValuePair<string, string>("network", "regtest")
}
})
});
var bootstrap = Startup.CreateBootstrap(conf);
var services = new PluginServiceCollection(new ServiceCollection(), bootstrap);
var plugins = new List<BaseBTCPayServerPlugin>() { new BitcoinPlugin() };
#if ALTCOINS
plugins.Add(new BTCPayServer.Plugins.Altcoins.AltcoinsPlugin());
#endif
foreach (var p in plugins)
{
p.Execute(services);
}
services.AddSingleton(services.BootstrapServices.GetRequiredService<SelectedChains>());
services.AddSingleton(services.BootstrapServices.GetRequiredService<NBXplorerNetworkProvider>());
services.AddSingleton(services.BootstrapServices.GetRequiredService<Logs>());
services.AddSingleton(services.BootstrapServices.GetRequiredService<IConfiguration>());
services.AddSingleton<BTCPayNetworkProvider>();
var serviceProvider = services.BuildServiceProvider();
return serviceProvider.GetService<BTCPayNetworkProvider>();
} }
public ILog TestLogs public ILog TestLogs
{ {
@ -26,14 +82,15 @@ namespace BTCPayServer.Tests
get; get;
} }
public BTCPayServer.Logging.Logs BTCPayLogs { get; } public BTCPayServer.Logging.Logs BTCPayLogs { get; }
public FuncLoggerFactory LoggerFactory { get; }
public ServerTester CreateServerTester([CallerMemberNameAttribute] string scope = null, bool newDb = false) public ServerTester CreateServerTester([CallerMemberNameAttribute] string scope = null, bool newDb = false)
{ {
return new ServerTester(scope, newDb, TestLogs, TestLogProvider); return new ServerTester(scope, newDb, TestLogs, TestLogProvider, CreateNetworkProvider());
} }
public SeleniumTester CreateSeleniumTester([CallerMemberNameAttribute] string scope = null, bool newDb = false) public SeleniumTester CreateSeleniumTester([CallerMemberNameAttribute] string scope = null, bool newDb = false)
{ {
return new SeleniumTester() { Server = new ServerTester(scope, newDb, TestLogs, TestLogProvider) }; return new SeleniumTester() { Server = new ServerTester(scope, newDb, TestLogs, TestLogProvider, CreateNetworkProvider()) };
} }
} }
} }

View file

@ -38,6 +38,7 @@
<ItemGroup Condition="'$(Altcoins)' != 'true'"> <ItemGroup Condition="'$(Altcoins)' != 'true'">
<Content Remove="Services\Altcoins\**\*" /> <Content Remove="Services\Altcoins\**\*" />
<Compile Remove="Plugins\Altcoins\**\*" />
<Content Remove="Views\UIMoneroLikeStore\**\*" /> <Content Remove="Views\UIMoneroLikeStore\**\*" />
<Content Remove="Views\UIZcashLikeStore\**\*" /> <Content Remove="Views\UIZcashLikeStore\**\*" />
<Content Remove="Views\Shared\Monero\**\*" /> <Content Remove="Views\Shared\Monero\**\*" />

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Models.StoreViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Labels; using BTCPayServer.Services.Labels;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
@ -26,18 +27,22 @@ public class StoreRecentTransactions : ViewComponent
private readonly BTCPayWalletProvider _walletProvider; private readonly BTCPayWalletProvider _walletProvider;
private readonly WalletRepository _walletRepository; private readonly WalletRepository _walletRepository;
private readonly LabelService _labelService; private readonly LabelService _labelService;
private readonly TransactionLinkProviders _transactionLinkProviders;
public BTCPayNetworkProvider NetworkProvider { get; } public BTCPayNetworkProvider NetworkProvider { get; }
public StoreRecentTransactions( public StoreRecentTransactions(
BTCPayNetworkProvider networkProvider, BTCPayNetworkProvider networkProvider,
BTCPayWalletProvider walletProvider, BTCPayWalletProvider walletProvider,
WalletRepository walletRepository, WalletRepository walletRepository,
LabelService labelService) LabelService labelService,
TransactionLinkProviders transactionLinkProviders)
{ {
NetworkProvider = networkProvider; NetworkProvider = networkProvider;
_walletProvider = walletProvider; _walletProvider = walletProvider;
_walletRepository = walletRepository; _walletRepository = walletRepository;
_labelService = labelService; _labelService = labelService;
_transactionLinkProviders = transactionLinkProviders;
} }
public async Task<IViewComponentResult> InvokeAsync(StoreRecentTransactionsViewModel vm) public async Task<IViewComponentResult> InvokeAsync(StoreRecentTransactionsViewModel vm)
@ -60,7 +65,7 @@ public class StoreRecentTransactions : ViewComponent
var wallet = _walletProvider.GetWallet(network); var wallet = _walletProvider.GetWallet(network);
var allTransactions = await wallet.FetchTransactionHistory(derivationSettings.AccountDerivation, 0, 5, TimeSpan.FromDays(31.0), cancellationToken: this.HttpContext.RequestAborted); var allTransactions = await wallet.FetchTransactionHistory(derivationSettings.AccountDerivation, 0, 5, TimeSpan.FromDays(31.0), cancellationToken: this.HttpContext.RequestAborted);
var walletTransactionsInfo = await _walletRepository.GetWalletTransactionsInfo(vm.WalletId, allTransactions.Select(t => t.TransactionId.ToString()).ToArray()); var walletTransactionsInfo = await _walletRepository.GetWalletTransactionsInfo(vm.WalletId, allTransactions.Select(t => t.TransactionId.ToString()).ToArray());
var pmi = new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike);
transactions = allTransactions transactions = allTransactions
.Select(tx => .Select(tx =>
{ {
@ -73,8 +78,7 @@ public class StoreRecentTransactions : ViewComponent
Balance = tx.BalanceChange.ShowMoney(network), Balance = tx.BalanceChange.ShowMoney(network),
Currency = vm.CryptoCode, Currency = vm.CryptoCode,
IsConfirmed = tx.Confirmations != 0, IsConfirmed = tx.Confirmations != 0,
Link = string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, Link = _transactionLinkProviders.GetTransactionLink(pmi, tx.TransactionId.ToString()),
tx.TransactionId.ToString()),
Timestamp = tx.SeenAt, Timestamp = tx.SeenAt,
Labels = labels Labels = labels
}; };

View file

@ -1,11 +1,20 @@
using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using BTCPayServer.Hosting;
using BTCPayServer.Logging;
using BTCPayServer.Plugins;
using BTCPayServer.Plugins.Bitcoin;
using CommandLine; using CommandLine;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Memory;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin; using NBitcoin;
using NBXplorer;
namespace BTCPayServer.Configuration namespace BTCPayServer.Configuration
{ {
@ -13,7 +22,7 @@ namespace BTCPayServer.Configuration
{ {
protected override CommandLineApplication CreateCommandLineApplicationCore() protected override CommandLineApplication CreateCommandLineApplicationCore()
{ {
var provider = new BTCPayNetworkProvider(ChainName.Mainnet); var provider = CreateBTCPayNetworkProvider(ChainName.Mainnet);
var chains = string.Join(",", provider.GetAll().Select(n => n.CryptoCode.ToLowerInvariant()).ToArray()); var chains = string.Join(",", provider.GetAll().Select(n => n.CryptoCode.ToLowerInvariant()).ToArray());
CommandLineApplication app = new CommandLineApplication(true) CommandLineApplication app = new CommandLineApplication(true)
{ {
@ -134,7 +143,7 @@ namespace BTCPayServer.Configuration
builder.AppendLine("#sqlitefile=sqlite.db"); builder.AppendLine("#sqlitefile=sqlite.db");
builder.AppendLine(); builder.AppendLine();
builder.AppendLine("### NBXplorer settings ###"); builder.AppendLine("### NBXplorer settings ###");
foreach (var n in new BTCPayNetworkProvider(networkType).GetAll().OfType<BTCPayNetwork>()) foreach (var n in CreateBTCPayNetworkProvider(networkType).GetAll().OfType<BTCPayNetwork>())
{ {
builder.AppendLine(CultureInfo.InvariantCulture, $"#{n.CryptoCode}.explorer.url={n.NBXplorerNetwork.DefaultSettings.DefaultUrl}"); builder.AppendLine(CultureInfo.InvariantCulture, $"#{n.CryptoCode}.explorer.url={n.NBXplorerNetwork.DefaultSettings.DefaultUrl}");
builder.AppendLine(CultureInfo.InvariantCulture, $"#{n.CryptoCode}.explorer.cookiefile={n.NBXplorerNetwork.DefaultSettings.DefaultCookieFile}"); builder.AppendLine(CultureInfo.InvariantCulture, $"#{n.CryptoCode}.explorer.cookiefile={n.NBXplorerNetwork.DefaultSettings.DefaultCookieFile}");
@ -148,8 +157,27 @@ namespace BTCPayServer.Configuration
return builder.ToString(); return builder.ToString();
} }
private BTCPayNetworkProvider CreateBTCPayNetworkProvider(ChainName networkType)
{
var collection = new ServiceCollection();
var conf = new ConfigurationBuilder().AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("network", networkType.ToString())
}).Build();
var services = new PluginServiceCollection(collection, Startup.CreateBootstrap(conf));
var p1 = new BitcoinPlugin();
p1.Execute(services);
#if ALTCOINS
var p2 = new Plugins.Altcoins.AltcoinsPlugin();
p2.Execute(services);
#endif
services.AddSingleton(services.BootstrapServices.GetRequiredService<SelectedChains>());
services.AddSingleton(services.BootstrapServices.GetRequiredService<NBXplorerNetworkProvider>());
services.AddSingleton(services.BootstrapServices.GetRequiredService<Logs>());
services.AddSingleton(services.BootstrapServices.GetRequiredService<IConfiguration>());
services.AddSingleton<BTCPayNetworkProvider>();
return services.BuildServiceProvider().GetRequiredService<BTCPayNetworkProvider>();
}
protected override IPEndPoint GetDefaultEndpoint(IConfiguration conf) protected override IPEndPoint GetDefaultEndpoint(IConfiguration conf)
{ {
return new IPEndPoint(IPAddress.Parse("127.0.0.1"), BTCPayDefaultSettings.GetDefaultSettings(GetNetworkType(conf)).DefaultPort); return new IPEndPoint(IPAddress.Parse("127.0.0.1"), BTCPayDefaultSettings.GetDefaultSettings(GetNetworkType(conf)).DefaultPort);

View file

@ -14,6 +14,7 @@ using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Models.WalletViewModels; using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.PayJoin; using BTCPayServer.Payments.PayJoin;
using BTCPayServer.Payments.PayJoin.Sender; using BTCPayServer.Payments.PayJoin.Sender;
using BTCPayServer.Services; using BTCPayServer.Services;
@ -54,6 +55,7 @@ namespace BTCPayServer.Controllers.Greenfield
private readonly WalletReceiveService _walletReceiveService; private readonly WalletReceiveService _walletReceiveService;
private readonly IFeeProviderFactory _feeProviderFactory; private readonly IFeeProviderFactory _feeProviderFactory;
private readonly UTXOLocker _utxoLocker; private readonly UTXOLocker _utxoLocker;
private readonly TransactionLinkProviders _transactionLinkProviders;
public GreenfieldStoreOnChainWalletsController( public GreenfieldStoreOnChainWalletsController(
IAuthorizationService authorizationService, IAuthorizationService authorizationService,
@ -69,7 +71,8 @@ namespace BTCPayServer.Controllers.Greenfield
EventAggregator eventAggregator, EventAggregator eventAggregator,
WalletReceiveService walletReceiveService, WalletReceiveService walletReceiveService,
IFeeProviderFactory feeProviderFactory, IFeeProviderFactory feeProviderFactory,
UTXOLocker utxoLocker UTXOLocker utxoLocker,
TransactionLinkProviders transactionLinkProviders
) )
{ {
_authorizationService = authorizationService; _authorizationService = authorizationService;
@ -86,6 +89,7 @@ namespace BTCPayServer.Controllers.Greenfield
_walletReceiveService = walletReceiveService; _walletReceiveService = walletReceiveService;
_feeProviderFactory = feeProviderFactory; _feeProviderFactory = feeProviderFactory;
_utxoLocker = utxoLocker; _utxoLocker = utxoLocker;
_transactionLinkProviders = transactionLinkProviders;
} }
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)] [Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
@ -312,6 +316,7 @@ namespace BTCPayServer.Controllers.Greenfield
var utxos = await wallet.GetUnspentCoins(derivationScheme.AccountDerivation); var utxos = await wallet.GetUnspentCoins(derivationScheme.AccountDerivation);
var walletTransactionsInfoAsync = await _walletRepository.GetWalletTransactionsInfo(walletId, var walletTransactionsInfoAsync = await _walletRepository.GetWalletTransactionsInfo(walletId,
utxos.SelectMany(GetWalletObjectsQuery.Get).Distinct().ToArray()); utxos.SelectMany(GetWalletObjectsQuery.Get).Distinct().ToArray());
var pmi = new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike);
return Ok(utxos.Select(coin => return Ok(utxos.Select(coin =>
{ {
walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info1); walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info1);
@ -327,8 +332,7 @@ namespace BTCPayServer.Controllers.Greenfield
#pragma warning disable CS0612 // Type or member is obsolete #pragma warning disable CS0612 // Type or member is obsolete
Labels = info?.LegacyLabels ?? new Dictionary<string, LabelData>(), Labels = info?.LegacyLabels ?? new Dictionary<string, LabelData>(),
#pragma warning restore CS0612 // Type or member is obsolete #pragma warning restore CS0612 // Type or member is obsolete
Link = string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, Link = _transactionLinkProviders.GetTransactionLink(pmi, coin.OutPoint.ToString()),
coin.OutPoint.Hash.ToString()),
Timestamp = coin.Timestamp, Timestamp = coin.Timestamp,
KeyPath = coin.KeyPath, KeyPath = coin.KeyPath,
Confirmations = coin.Confirmations, Confirmations = coin.Confirmations,

View file

@ -5,6 +5,7 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Net.Mime; using System.Net.Mime;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Reflection.Metadata;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
@ -236,37 +237,7 @@ namespace BTCPayServer.Controllers
JToken? receiptData = null; JToken? receiptData = null;
i.Metadata?.AdditionalData?.TryGetValue("receiptData", out receiptData); i.Metadata?.AdditionalData?.TryGetValue("receiptData", out receiptData);
var payments = i.GetPayments(true) var payments = ViewPaymentRequestViewModel.PaymentRequestInvoicePayment.GetViewModels(i, _displayFormatter, _transactionLinkProviders);
.Select(paymentEntity =>
{
var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId();
string? link = GetTransactionLink(paymentMethodId, txId);
return new ViewPaymentRequestViewModel.PaymentRequestInvoicePayment
{
Amount = paymentEntity.PaidAmount.Gross,
Paid = paymentEntity.InvoicePaidAmount.Net,
ReceivedDate = paymentEntity.ReceivedTime.DateTime,
AmountFormatted = _displayFormatter.Currency(paymentEntity.PaidAmount.Gross, paymentEntity.PaidAmount.Currency),
PaidFormatted = _displayFormatter.Currency(paymentEntity.InvoicePaidAmount.Net, i.Currency, DisplayFormatter.CurrencyFormat.Symbol),
RateFormatted = _displayFormatter.Currency(paymentEntity.Rate, i.Currency, DisplayFormatter.CurrencyFormat.Symbol),
PaymentMethod = paymentMethodId.ToPrettyString(),
Link = link,
Id = txId,
Destination = paymentData.GetDestination(),
PaymentProof = paymentData.GetPaymentProof(),
PaymentType = paymentData.GetPaymentType()
};
})
.Where(payment => payment != null)
.ToList();
vm.Amount = i.PaidAmount.Net; vm.Amount = i.PaidAmount.Net;
vm.Payments = receipt.ShowPayments is false ? null : payments; vm.Payments = receipt.ShowPayments is false ? null : payments;
@ -275,12 +246,6 @@ namespace BTCPayServer.Controllers
return View(print ? "InvoiceReceiptPrint" : "InvoiceReceipt", vm); return View(print ? "InvoiceReceiptPrint" : "InvoiceReceipt", vm);
} }
private string? GetTransactionLink(PaymentMethodId paymentMethodId, string txId)
{
var network = _NetworkProvider.GetNetwork(paymentMethodId.CryptoCode);
return network == null ? null : paymentMethodId.PaymentType.GetTransactionLink(network, txId);
}
[HttpGet("invoices/{invoiceId}/refund")] [HttpGet("invoices/{invoiceId}/refund")]
[Authorize(Policy = Policies.CanCreateNonApprovedPullPayments, AuthenticationSchemes = AuthenticationSchemes.Cookie)] [Authorize(Policy = Policies.CanCreateNonApprovedPullPayments, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task<IActionResult> Refund([FromServices] IEnumerable<IPayoutHandler> payoutHandlers, string invoiceId, CancellationToken cancellationToken) public async Task<IActionResult> Refund([FromServices] IEnumerable<IPayoutHandler> payoutHandlers, string invoiceId, CancellationToken cancellationToken)

View file

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Services;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
@ -17,7 +18,6 @@ using BTCPayServer.Payments.Bitcoin;
using BTCPayServer.Rating; using BTCPayServer.Rating;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Security.Greenfield; using BTCPayServer.Security.Greenfield;
using BTCPayServer.Services;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.PaymentRequests; using BTCPayServer.Services.PaymentRequests;
@ -55,6 +55,7 @@ namespace BTCPayServer.Controllers
private readonly InvoiceActivator _invoiceActivator; private readonly InvoiceActivator _invoiceActivator;
private readonly LinkGenerator _linkGenerator; private readonly LinkGenerator _linkGenerator;
private readonly IAuthorizationService _authorizationService; private readonly IAuthorizationService _authorizationService;
private readonly TransactionLinkProviders _transactionLinkProviders;
private readonly AppService _appService; private readonly AppService _appService;
private readonly IFileService _fileService; private readonly IFileService _fileService;
@ -82,7 +83,8 @@ namespace BTCPayServer.Controllers
LinkGenerator linkGenerator, LinkGenerator linkGenerator,
AppService appService, AppService appService,
IFileService fileService, IFileService fileService,
IAuthorizationService authorizationService) IAuthorizationService authorizationService,
TransactionLinkProviders transactionLinkProviders)
{ {
_displayFormatter = displayFormatter; _displayFormatter = displayFormatter;
_CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable)); _CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable));
@ -103,6 +105,7 @@ namespace BTCPayServer.Controllers
_invoiceActivator = invoiceActivator; _invoiceActivator = invoiceActivator;
_linkGenerator = linkGenerator; _linkGenerator = linkGenerator;
_authorizationService = authorizationService; _authorizationService = authorizationService;
_transactionLinkProviders = transactionLinkProviders;
_fileService = fileService; _fileService = fileService;
_appService = appService; _appService = appService;
} }

View file

@ -17,7 +17,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Internal;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using Org.BouncyCastle.Ocsp;
using System.Threading; using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;

View file

@ -11,6 +11,8 @@ using BTCPayServer.Models.StoreReportsViewModels;
using BTCPayServer.Services; using BTCPayServer.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using System.Threading; using System.Threading;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -21,12 +23,13 @@ namespace BTCPayServer.Controllers;
public partial class UIReportsController : Controller public partial class UIReportsController : Controller
{ {
public UIReportsController( public UIReportsController(
BTCPayNetworkProvider networkProvider,
ApplicationDbContextFactory dbContextFactory, ApplicationDbContextFactory dbContextFactory,
GreenfieldReportsController api, GreenfieldReportsController api,
ReportService reportService, ReportService reportService,
DisplayFormatter displayFormatter, DisplayFormatter displayFormatter,
BTCPayServerEnvironment env) BTCPayServerEnvironment env,
BTCPayNetworkProvider networkProvider,
TransactionLinkProviders transactionLinkProviders)
{ {
Api = api; Api = api;
ReportService = reportService; ReportService = reportService;
@ -34,6 +37,7 @@ public partial class UIReportsController : Controller
DBContextFactory = dbContextFactory; DBContextFactory = dbContextFactory;
NetworkProvider = networkProvider; NetworkProvider = networkProvider;
DisplayFormatter = displayFormatter; DisplayFormatter = displayFormatter;
TransactionLinkProviders = transactionLinkProviders;
} }
private BTCPayNetworkProvider NetworkProvider { get; } private BTCPayNetworkProvider NetworkProvider { get; }
private DisplayFormatter DisplayFormatter { get; } private DisplayFormatter DisplayFormatter { get; }
@ -41,6 +45,7 @@ public partial class UIReportsController : Controller
public ReportService ReportService { get; } public ReportService ReportService { get; }
public BTCPayServerEnvironment Env { get; } public BTCPayServerEnvironment Env { get; }
public ApplicationDbContextFactory DBContextFactory { get; } public ApplicationDbContextFactory DBContextFactory { get; }
public TransactionLinkProviders TransactionLinkProviders { get; }
[HttpPost("stores/{storeId}/reports")] [HttpPost("stores/{storeId}/reports")]
[AcceptMediaTypeConstraint("application/json")] [AcceptMediaTypeConstraint("application/json")]
@ -67,7 +72,7 @@ public partial class UIReportsController : Controller
var vm = new StoreReportsViewModel var vm = new StoreReportsViewModel
{ {
InvoiceTemplateUrl = Url.Action(nameof(UIInvoiceController.Invoice), "UIInvoice", new { invoiceId = "INVOICE_ID" }), InvoiceTemplateUrl = Url.Action(nameof(UIInvoiceController.Invoice), "UIInvoice", new { invoiceId = "INVOICE_ID" }),
ExplorerTemplateUrls = NetworkProvider.GetAll().ToDictionary(network => network.CryptoCode, network => network.BlockExplorerLink?.Replace("{0}", "TX_ID")), ExplorerTemplateUrls = TransactionLinkProviders.ToDictionary(p => p.Key.CryptoCode, p => p.Value.BlockExplorerLink?.Replace("{0}", "TX_ID")),
Request = new StoreReportRequest { ViewName = viewName ?? "Payments" }, Request = new StoreReportRequest { ViewName = viewName ?? "Payments" },
AvailableViews = ReportService.ReportProviders AvailableViews = ReportService.ReportProviders
.Values .Values

View file

@ -20,6 +20,7 @@ using BTCPayServer.Hosting;
using BTCPayServer.Logging; using BTCPayServer.Logging;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.ServerViewModels; using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Mails; using BTCPayServer.Services.Mails;
@ -68,6 +69,7 @@ namespace BTCPayServer.Controllers
private readonly IEnumerable<IStorageProviderService> _StorageProviderServices; private readonly IEnumerable<IStorageProviderService> _StorageProviderServices;
private readonly LinkGenerator _linkGenerator; private readonly LinkGenerator _linkGenerator;
private readonly EmailSenderFactory _emailSenderFactory; private readonly EmailSenderFactory _emailSenderFactory;
private readonly TransactionLinkProviders _transactionLinkProviders;
public UIServerController( public UIServerController(
UserManager<ApplicationUser> userManager, UserManager<ApplicationUser> userManager,
@ -91,7 +93,8 @@ namespace BTCPayServer.Controllers
LinkGenerator linkGenerator, LinkGenerator linkGenerator,
EmailSenderFactory emailSenderFactory, EmailSenderFactory emailSenderFactory,
IHostApplicationLifetime applicationLifetime, IHostApplicationLifetime applicationLifetime,
IHtmlHelper html IHtmlHelper html,
TransactionLinkProviders transactionLinkProviders
) )
{ {
_policiesSettings = policiesSettings; _policiesSettings = policiesSettings;
@ -116,6 +119,7 @@ namespace BTCPayServer.Controllers
_emailSenderFactory = emailSenderFactory; _emailSenderFactory = emailSenderFactory;
ApplicationLifetime = applicationLifetime; ApplicationLifetime = applicationLifetime;
Html = html; Html = html;
_transactionLinkProviders = transactionLinkProviders;
} }
[Route("server/maintenance")] [Route("server/maintenance")]
@ -328,8 +332,10 @@ namespace BTCPayServer.Controllers
settings.DomainToAppMapping.RemoveAt(index); settings.DomainToAppMapping.RemoveAt(index);
return View(settings); return View(settings);
} }
settings.BlockExplorerLinks = settings.BlockExplorerLinks
settings.BlockExplorerLinks = settings.BlockExplorerLinks.Where(tuple => btcPayNetworkProvider.GetNetwork(tuple.CryptoCode).BlockExplorerLinkDefault != tuple.Link).ToList(); .Where(tuple => _transactionLinkProviders.GetDefaultBlockExplorerLink(PaymentMethodId.Parse(tuple.CryptoCode)) != tuple.Link)
.Where(tuple => tuple.Link is not null)
.ToList();
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
@ -362,7 +368,7 @@ namespace BTCPayServer.Controllers
} }
await _SettingsRepository.UpdateSetting(settings); await _SettingsRepository.UpdateSetting(settings);
BlockExplorerLinkStartupTask.SetLinkOnNetworks(settings.BlockExplorerLinks, btcPayNetworkProvider); _ = _transactionLinkProviders.RefreshTransactionLinkTemplates();
TempData[WellKnownTempData.SuccessMessage] = "Policies updated successfully"; TempData[WellKnownTempData.SuccessMessage] = "Policies updated successfully";
return RedirectToAction(nameof(Policies)); return RedirectToAction(nameof(Policies));
} }

View file

@ -638,7 +638,7 @@ namespace BTCPayServer.Controllers
WalletId = new WalletId(store.Id, paymentMethodId.CryptoCode), WalletId = new WalletId(store.Id, paymentMethodId.CryptoCode),
Enabled = !excludeFilters.Match(paymentMethodId) && strategy != null, Enabled = !excludeFilters.Match(paymentMethodId) && strategy != null,
#if ALTCOINS #if ALTCOINS
Collapsed = network is ElementsBTCPayNetwork elementsBTCPayNetwork && elementsBTCPayNetwork.NetworkCryptoCode != elementsBTCPayNetwork.CryptoCode && string.IsNullOrEmpty(value) Collapsed = network is Plugins.Altcoins.ElementsBTCPayNetwork elementsBTCPayNetwork && elementsBTCPayNetwork.NetworkCryptoCode != elementsBTCPayNetwork.CryptoCode && string.IsNullOrEmpty(value)
#endif #endif
}); });
break; break;

View file

@ -66,6 +66,7 @@ namespace BTCPayServer.Controllers
private readonly DelayedTransactionBroadcaster _broadcaster; private readonly DelayedTransactionBroadcaster _broadcaster;
private readonly PayjoinClient _payjoinClient; private readonly PayjoinClient _payjoinClient;
private readonly LabelService _labelService; private readonly LabelService _labelService;
private readonly TransactionLinkProviders _transactionLinkProviders;
private readonly PullPaymentHostedService _pullPaymentHostedService; private readonly PullPaymentHostedService _pullPaymentHostedService;
private readonly WalletHistogramService _walletHistogramService; private readonly WalletHistogramService _walletHistogramService;
@ -89,10 +90,12 @@ namespace BTCPayServer.Controllers
PayjoinClient payjoinClient, PayjoinClient payjoinClient,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
PullPaymentHostedService pullPaymentHostedService, PullPaymentHostedService pullPaymentHostedService,
LabelService labelService) LabelService labelService,
TransactionLinkProviders transactionLinkProviders)
{ {
_currencyTable = currencyTable; _currencyTable = currencyTable;
_labelService = labelService; _labelService = labelService;
_transactionLinkProviders = transactionLinkProviders;
Repository = repo; Repository = repo;
WalletRepository = walletRepository; WalletRepository = walletRepository;
RateFetcher = rateProvider; RateFetcher = rateProvider;
@ -248,12 +251,12 @@ namespace BTCPayServer.Controllers
} }
else else
{ {
var pmi = new PaymentMethodId(walletId.CryptoCode, PaymentTypes.BTCLike);
foreach (var tx in transactions) foreach (var tx in transactions)
{ {
var vm = new ListTransactionsViewModel.TransactionViewModel(); var vm = new ListTransactionsViewModel.TransactionViewModel();
vm.Id = tx.TransactionId.ToString(); vm.Id = tx.TransactionId.ToString();
vm.Link = string.Format(CultureInfo.InvariantCulture, paymentMethod.Network.BlockExplorerLink, vm.Link = _transactionLinkProviders.GetTransactionLink(pmi, vm.Id);
vm.Id);
vm.Timestamp = tx.SeenAt; vm.Timestamp = tx.SeenAt;
vm.Positive = tx.BalanceChange.GetValue(wallet.Network) >= 0; vm.Positive = tx.BalanceChange.GetValue(wallet.Network) >= 0;
vm.Balance = tx.BalanceChange.ShowMoney(wallet.Network); vm.Balance = tx.BalanceChange.ShowMoney(wallet.Network);
@ -590,7 +593,7 @@ namespace BTCPayServer.Controllers
var utxos = await _walletProvider.GetWallet(network) var utxos = await _walletProvider.GetWallet(network)
.GetUnspentCoins(schemeSettings.AccountDerivation, false, cancellation); .GetUnspentCoins(schemeSettings.AccountDerivation, false, cancellation);
var pmi = new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike);
var walletTransactionsInfoAsync = await this.WalletRepository.GetWalletTransactionsInfo(walletId, var walletTransactionsInfoAsync = await this.WalletRepository.GetWalletTransactionsInfo(walletId,
utxos.SelectMany(GetWalletObjectsQuery.Get).Distinct().ToArray()); utxos.SelectMany(GetWalletObjectsQuery.Get).Distinct().ToArray());
vm.InputsAvailable = utxos.Select(coin => vm.InputsAvailable = utxos.Select(coin =>
@ -605,8 +608,7 @@ namespace BTCPayServer.Controllers
Amount = coin.Value.GetValue(network), Amount = coin.Value.GetValue(network),
Comment = info?.Comment, Comment = info?.Comment,
Labels = _labelService.CreateTransactionTagModels(info, Request), Labels = _labelService.CreateTransactionTagModels(info, Request),
Link = string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, Link = _transactionLinkProviders.GetTransactionLink(pmi, coin.OutPoint.ToString()),
coin.OutPoint.Hash.ToString()),
Confirmations = coin.Confirmations Confirmations = coin.Confirmations
}; };
}).ToArray(); }).ToArray();

View file

@ -37,6 +37,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
private readonly ApplicationDbContextFactory _dbContextFactory; private readonly ApplicationDbContextFactory _dbContextFactory;
private readonly NotificationSender _notificationSender; private readonly NotificationSender _notificationSender;
private readonly Logs Logs; private readonly Logs Logs;
private readonly TransactionLinkProviders _transactionLinkProviders;
public WalletRepository WalletRepository { get; } public WalletRepository WalletRepository { get; }
@ -46,7 +47,8 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
BTCPayNetworkJsonSerializerSettings jsonSerializerSettings, BTCPayNetworkJsonSerializerSettings jsonSerializerSettings,
ApplicationDbContextFactory dbContextFactory, ApplicationDbContextFactory dbContextFactory,
NotificationSender notificationSender, NotificationSender notificationSender,
Logs logs) Logs logs,
TransactionLinkProviders transactionLinkProviders)
{ {
_btcPayNetworkProvider = btcPayNetworkProvider; _btcPayNetworkProvider = btcPayNetworkProvider;
WalletRepository = walletRepository; WalletRepository = walletRepository;
@ -55,6 +57,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
_dbContextFactory = dbContextFactory; _dbContextFactory = dbContextFactory;
_notificationSender = notificationSender; _notificationSender = notificationSender;
this.Logs = logs; this.Logs = logs;
_transactionLinkProviders = transactionLinkProviders;
} }
@ -120,10 +123,9 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
var res = raw.ToObject<PayoutTransactionOnChainBlob>( var res = raw.ToObject<PayoutTransactionOnChainBlob>(
JsonSerializer.Create(_jsonSerializerSettings.GetSerializer(paymentMethodId.CryptoCode))); JsonSerializer.Create(_jsonSerializerSettings.GetSerializer(paymentMethodId.CryptoCode)));
var network = _btcPayNetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode);
if (res == null) if (res == null)
return null; return null;
res.LinkTemplate = network.BlockExplorerLink; res.LinkTemplate = _transactionLinkProviders.GetBlockExplorerLink(paymentMethodId);
return res; return res;
} }
return raw.ToObject<ManualPayoutProof>(); return raw.ToObject<ManualPayoutProof>();

View file

@ -425,42 +425,6 @@ namespace BTCPayServer
return controller.View("PostRedirect", redirectVm); return controller.View("PostRedirect", redirectVm);
} }
public static BTCPayNetworkProvider ConfigureNetworkProvider(this IConfiguration configuration, Logs logs)
{
var _networkType = DefaultConfiguration.GetNetworkType(configuration);
var supportedChains = configuration.GetOrDefault<string>("chains", "btc")
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(t => t.ToUpperInvariant()).ToHashSet();
foreach (var c in supportedChains.ToList())
{
if (new[] { "ETH", "USDT20", "FAU" }.Contains(c, StringComparer.OrdinalIgnoreCase))
{
logs.Configuration.LogWarning($"'{c}' is not anymore supported, please remove it from 'chains'");
supportedChains.Remove(c);
}
}
var networkProvider = new BTCPayNetworkProvider(_networkType);
var filtered = networkProvider.Filter(supportedChains.ToArray());
#if ALTCOINS
supportedChains.AddRange(filtered.GetAllElementsSubChains(networkProvider));
#endif
#if !ALTCOINS
var onlyBTC = supportedChains.Count == 1 && supportedChains.First() == "BTC";
if (!onlyBTC)
throw new ConfigException($"This build of BTCPay Server does not support altcoins");
#endif
var result = networkProvider.Filter(supportedChains.ToArray());
foreach (var chain in supportedChains)
{
if (result.GetNetwork<BTCPayNetworkBase>(chain) == null)
throw new ConfigException($"Invalid chains \"{chain}\"");
}
logs.Configuration.LogInformation(
"Supported chains: " + String.Join(',', supportedChains.ToArray()));
return result;
}
public static DataDirectories Configure(this DataDirectories dataDirectories, IConfiguration configuration) public static DataDirectories Configure(this DataDirectories dataDirectories, IConfiguration configuration)
{ {
var networkType = DefaultConfiguration.GetNetworkType(configuration); var networkType = DefaultConfiguration.GetNetworkType(configuration);

View file

@ -18,7 +18,7 @@ namespace BTCPayServer
return mb.Select(money => money.GetValue(network)).Sum(); return mb.Select(money => money.GetValue(network)).Sum();
#if ALTCOINS #if ALTCOINS
case AssetMoney assetMoney: case AssetMoney assetMoney:
if (network is ElementsBTCPayNetwork elementsBTCPayNetwork) if (network is BTCPayServer.Plugins.Altcoins.ElementsBTCPayNetwork elementsBTCPayNetwork)
{ {
return elementsBTCPayNetwork.AssetId == assetMoney.AssetId return elementsBTCPayNetwork.AssetId == assetMoney.AssetId
? Convert(assetMoney.Quantity, elementsBTCPayNetwork.Divisibility) ? Convert(assetMoney.Quantity, elementsBTCPayNetwork.Divisibility)

View file

@ -225,11 +225,6 @@ namespace BTCPayServer.Hosting
}; };
options.NBXplorerConnectionSettings.Add(setting); options.NBXplorerConnectionSettings.Add(setting);
options.ConnectionString = configuration.GetOrDefault<string>("explorer.postgres", null); options.ConnectionString = configuration.GetOrDefault<string>("explorer.postgres", null);
var blockExplorerLink = configuration.GetOrDefault<string>("blockexplorerlink", null);
if (!string.IsNullOrEmpty(blockExplorerLink))
{
btcPayNetwork.BlockExplorerLink = blockExplorerLink;
}
} }
}); });
services.AddOptions<LightningNetworkOptions>().Configure<BTCPayNetworkProvider, LightningClientFactoryService>( services.AddOptions<LightningNetworkOptions>().Configure<BTCPayNetworkProvider, LightningClientFactoryService>(
@ -306,7 +301,7 @@ namespace BTCPayServer.Hosting
} }
} }
}); });
services.TryAddSingleton(o => configuration.ConfigureNetworkProvider(logs)); services.TryAddSingleton<BTCPayNetworkProvider>();
services.TryAddSingleton<AppService>(); services.TryAddSingleton<AppService>();
services.AddTransient<PluginService>(); services.AddTransient<PluginService>();
@ -355,6 +350,7 @@ namespace BTCPayServer.Hosting
return htmlSanitizer; return htmlSanitizer;
}); });
services.AddSingleton<TransactionLinkProviders>();
services.TryAddSingleton<LightningConfigurationProvider>(); services.TryAddSingleton<LightningConfigurationProvider>();
services.TryAddSingleton<LanguageService>(); services.TryAddSingleton<LanguageService>();
services.TryAddSingleton<ReportService>(); services.TryAddSingleton<ReportService>();
@ -426,7 +422,7 @@ namespace BTCPayServer.Hosting
services.AddSingleton<NotificationManager>(); services.AddSingleton<NotificationManager>();
services.AddScoped<NotificationSender>(); services.AddScoped<NotificationSender>();
services.AddSingleton<IHostedService, NBXplorerWaiters>(); services.AddSingleton<IHostedService, NBXplorerWaiters>();
services.AddSingleton<IHostedService, InvoiceEventSaverService>(); services.AddSingleton<IHostedService, InvoiceEventSaverService>();
services.AddSingleton<IHostedService, BitpayIPNSender>(); services.AddSingleton<IHostedService, BitpayIPNSender>();
@ -569,6 +565,15 @@ namespace BTCPayServer.Hosting
{ {
services.AddSingleton<IRateProvider, T>(); services.AddSingleton<IRateProvider, T>();
} }
public static IServiceCollection AddBTCPayNetwork(this IServiceCollection services, BTCPayNetworkBase network)
{
services.AddSingleton<BTCPayNetworkBase>(network);
return services;
}
public static void AddTransactionLinkProvider(this IServiceCollection services, PaymentMethodId paymentMethodId, TransactionLinkProvider provider)
{
services.AddSingleton<TransactionLinkProviders.Entry>(new TransactionLinkProviders.Entry(paymentMethodId, provider));
}
public static void AddRateProviderExchangeSharp<T>(this IServiceCollection services, RateSourceInfo rateInfo) where T : ExchangeAPI public static void AddRateProviderExchangeSharp<T>(this IServiceCollection services, RateSourceInfo rateInfo) where T : ExchangeAPI
{ {
services.AddSingleton<IRateProvider, ExchangeSharpRateProvider<T>>(o => services.AddSingleton<IRateProvider, ExchangeSharpRateProvider<T>>(o =>

View file

@ -5,41 +5,35 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Services; using BTCPayServer.Services;
using Microsoft.Extensions.Configuration;
namespace BTCPayServer.Hosting namespace BTCPayServer.Hosting
{ {
public class BlockExplorerLinkStartupTask : IStartupTask public class BlockExplorerLinkStartupTask : IStartupTask
{ {
private readonly SettingsRepository _settingsRepository;
private readonly BTCPayNetworkProvider _btcPayNetworkProvider; private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
private readonly TransactionLinkProviders _transactionLinksProviders;
private readonly IConfiguration _configuration;
public BlockExplorerLinkStartupTask(SettingsRepository settingsRepository, public BlockExplorerLinkStartupTask(
BTCPayNetworkProvider btcPayNetworkProvider) BTCPayNetworkProvider btcPayNetworkProvider,
TransactionLinkProviders transactionLinksProviders,
IConfiguration configuration)
{ {
_settingsRepository = settingsRepository;
_btcPayNetworkProvider = btcPayNetworkProvider; _btcPayNetworkProvider = btcPayNetworkProvider;
_transactionLinksProviders = transactionLinksProviders;
_configuration = configuration;
} }
public async Task ExecuteAsync(CancellationToken cancellationToken = default) public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{ {
var settings = await _settingsRepository.GetSettingAsync<PoliciesSettings>(); var blockExplorerLink = _configuration["blockexplorerlink"];
if (settings?.BlockExplorerLinks?.Any() is true) if (!string.IsNullOrEmpty(blockExplorerLink))
{ {
SetLinkOnNetworks(settings.BlockExplorerLinks, _btcPayNetworkProvider); foreach (var prov in _transactionLinksProviders.Values)
} prov.OverrideBlockExplorerLink = blockExplorerLink;
}
public static void SetLinkOnNetworks(List<PoliciesSettings.BlockExplorerOverrideItem> links,
BTCPayNetworkProvider networkProvider)
{
var networks = networkProvider.GetAll();
foreach (var network in networks)
{
var overrideLink = links.SingleOrDefault(item =>
item.CryptoCode.Equals(network.CryptoCode, StringComparison.InvariantCultureIgnoreCase));
network.BlockExplorerLink = overrideLink?.Link ?? network.BlockExplorerLinkDefault;
} }
await _transactionLinksProviders.RefreshTransactionLinkTemplates();
} }
} }
} }

View file

@ -33,8 +33,10 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using NBXplorer;
using NicolasDorier.RateLimits; using NicolasDorier.RateLimits;
namespace BTCPayServer.Hosting namespace BTCPayServer.Hosting
@ -57,8 +59,29 @@ namespace BTCPayServer.Hosting
} }
public ILoggerFactory LoggerFactory { get; } public ILoggerFactory LoggerFactory { get; }
public Logs Logs { get; } public Logs Logs { get; }
public static ServiceProvider CreateBootstrap(IConfiguration conf)
{
return CreateBootstrap(conf, new Logs(), new FuncLoggerFactory(n => NullLogger.Instance));
}
public static ServiceProvider CreateBootstrap(IConfiguration conf, Logs logs, ILoggerFactory loggerFactory)
{
ServiceCollection bootstrapServices = new ServiceCollection();
var networkType = DefaultConfiguration.GetNetworkType(conf);
bootstrapServices.AddSingleton(logs);
bootstrapServices.AddSingleton(loggerFactory);
bootstrapServices.AddSingleton<IConfiguration>(conf);
bootstrapServices.AddSingleton<SelectedChains>();
bootstrapServices.AddSingleton<NBXplorerNetworkProvider>(new NBXplorerNetworkProvider(networkType));
return bootstrapServices.BuildServiceProvider();
}
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
var bootstrapServiceProvider = CreateBootstrap(Configuration, Logs, LoggerFactory);
services.AddSingleton(bootstrapServiceProvider.GetRequiredService<SelectedChains>());
services.AddSingleton(bootstrapServiceProvider.GetRequiredService<NBXplorerNetworkProvider>());
services.AddMemoryCache(); services.AddMemoryCache();
services.AddDataProtection() services.AddDataProtection()
.SetApplicationName("BTCPay Server") .SetApplicationName("BTCPay Server")
@ -143,7 +166,7 @@ namespace BTCPayServer.Hosting
}) })
.AddNewtonsoftJson() .AddNewtonsoftJson()
.AddRazorRuntimeCompilation() .AddRazorRuntimeCompilation()
.AddPlugins(services, Configuration, LoggerFactory) .AddPlugins(services, Configuration, LoggerFactory, bootstrapServiceProvider)
.AddControllersAsServices(); .AddControllersAsServices();
services.AddServerSideBlazor(); services.AddServerSideBlazor();

View file

@ -5,6 +5,7 @@ using System.Linq;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Services;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using BTCPayServer.Validation; using BTCPayServer.Validation;
@ -212,6 +213,44 @@ namespace BTCPayServer.Models.PaymentRequestViewModels
public class PaymentRequestInvoicePayment public class PaymentRequestInvoicePayment
{ {
public static List<ViewPaymentRequestViewModel.PaymentRequestInvoicePayment>
GetViewModels(
InvoiceEntity invoice,
DisplayFormatter displayFormatter,
TransactionLinkProviders txLinkProvider)
{
return invoice
.GetPayments(true)
.Select(paymentEntity =>
{
var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId();
string link = txLinkProvider.GetTransactionLink(paymentMethodId, txId);
return new ViewPaymentRequestViewModel.PaymentRequestInvoicePayment
{
Amount = paymentEntity.PaidAmount.Gross,
Paid = paymentEntity.InvoicePaidAmount.Net,
ReceivedDate = paymentEntity.ReceivedTime.DateTime,
AmountFormatted = displayFormatter.Currency(paymentEntity.PaidAmount.Gross, paymentEntity.PaidAmount.Currency, DisplayFormatter.CurrencyFormat.None),
PaidFormatted = displayFormatter.Currency(paymentEntity.InvoicePaidAmount.Net, invoice.Currency, DisplayFormatter.CurrencyFormat.Symbol),
RateFormatted = displayFormatter.Currency(paymentEntity.Rate, invoice.Currency, DisplayFormatter.CurrencyFormat.Symbol),
PaymentMethod = paymentMethodId.ToPrettyString(),
Link = link,
Id = txId,
Destination = paymentData.GetDestination(),
PaymentProof = paymentData.GetPaymentProof(),
PaymentType = paymentData.GetPaymentType()
};
})
.Where(payment => payment != null)
.ToList();
}
public string PaymentMethod { get; set; } public string PaymentMethod { get; set; }
public decimal Amount { get; set; } public decimal Amount { get; set; }
public string AmountFormatted { get; set; } public string AmountFormatted { get; set; }

View file

@ -20,6 +20,7 @@ namespace BTCPayServer.PaymentRequest
private readonly BTCPayNetworkProvider _BtcPayNetworkProvider; private readonly BTCPayNetworkProvider _BtcPayNetworkProvider;
private readonly InvoiceRepository _invoiceRepository; private readonly InvoiceRepository _invoiceRepository;
private readonly CurrencyNameTable _currencies; private readonly CurrencyNameTable _currencies;
private readonly TransactionLinkProviders _transactionLinkProviders;
private readonly DisplayFormatter _displayFormatter; private readonly DisplayFormatter _displayFormatter;
public PaymentRequestService( public PaymentRequestService(
@ -27,12 +28,14 @@ namespace BTCPayServer.PaymentRequest
BTCPayNetworkProvider btcPayNetworkProvider, BTCPayNetworkProvider btcPayNetworkProvider,
InvoiceRepository invoiceRepository, InvoiceRepository invoiceRepository,
DisplayFormatter displayFormatter, DisplayFormatter displayFormatter,
CurrencyNameTable currencies) CurrencyNameTable currencies,
TransactionLinkProviders transactionLinkProviders)
{ {
_PaymentRequestRepository = paymentRequestRepository; _PaymentRequestRepository = paymentRequestRepository;
_BtcPayNetworkProvider = btcPayNetworkProvider; _BtcPayNetworkProvider = btcPayNetworkProvider;
_invoiceRepository = invoiceRepository; _invoiceRepository = invoiceRepository;
_currencies = currencies; _currencies = currencies;
_transactionLinkProviders = transactionLinkProviders;
_displayFormatter = displayFormatter; _displayFormatter = displayFormatter;
} }
@ -116,36 +119,7 @@ namespace BTCPayServer.PaymentRequest
Invoices = new ViewPaymentRequestViewModel.InvoiceList(invoices.Select(entity => Invoices = new ViewPaymentRequestViewModel.InvoiceList(invoices.Select(entity =>
{ {
var state = entity.GetInvoiceState(); var state = entity.GetInvoiceState();
var payments = entity var payments = ViewPaymentRequestViewModel.PaymentRequestInvoicePayment.GetViewModels(entity, _displayFormatter, _transactionLinkProviders);
.GetPayments(true)
.Select(paymentEntity =>
{
var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId();
string link = GetTransactionLink(paymentMethodId, txId);
return new ViewPaymentRequestViewModel.PaymentRequestInvoicePayment
{
Amount = paymentEntity.PaidAmount.Gross,
Paid = paymentEntity.InvoicePaidAmount.Net,
ReceivedDate = paymentEntity.ReceivedTime.DateTime,
AmountFormatted = _displayFormatter.Currency(paymentEntity.PaidAmount.Gross, paymentEntity.PaidAmount.Currency),
PaidFormatted = _displayFormatter.Currency(paymentEntity.InvoicePaidAmount.Net, blob.Currency, DisplayFormatter.CurrencyFormat.Symbol),
RateFormatted = _displayFormatter.Currency(paymentEntity.Rate, blob.Currency, DisplayFormatter.CurrencyFormat.Symbol),
PaymentMethod = paymentMethodId.ToPrettyString(),
Link = link,
Id = txId,
Destination = paymentData.GetDestination()
};
})
.Where(payment => payment != null)
.ToList();
if (state.Status == InvoiceStatusLegacy.Invalid || if (state.Status == InvoiceStatusLegacy.Invalid ||
state.Status == InvoiceStatusLegacy.Expired && !payments.Any()) state.Status == InvoiceStatusLegacy.Expired && !payments.Any())
@ -166,13 +140,5 @@ namespace BTCPayServer.PaymentRequest
.Where(invoice => invoice != null)) .Where(invoice => invoice != null))
}; };
} }
private string GetTransactionLink(PaymentMethodId paymentMethodId, string txId)
{
var network = _BtcPayNetworkProvider.GetNetwork(paymentMethodId.CryptoCode);
if (network == null)
return null;
return paymentMethodId.PaymentType.GetTransactionLink(network, txId);
}
} }
} }

View file

@ -57,15 +57,6 @@ namespace BTCPayServer.Payments
return DerivationSchemeSettings.Parse(((JValue)value).Value<string>(), net); return DerivationSchemeSettings.Parse(((JValue)value).Value<string>(), net);
} }
public override string GetTransactionLink(BTCPayNetworkBase network, string txId)
{
ArgumentNullException.ThrowIfNull(txId);
if (network?.BlockExplorerLink == null)
return null;
txId = txId.Split('-').First();
return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId);
}
public override string GetPaymentLink(BTCPayNetworkBase network, InvoiceEntity invoice, IPaymentMethodDetails paymentMethodDetails, public override string GetPaymentLink(BTCPayNetworkBase network, InvoiceEntity invoice, IPaymentMethodDetails paymentMethodDetails,
decimal cryptoInfoDue, string serverUri) decimal cryptoInfoDue, string serverUri)
{ {

View file

@ -47,11 +47,6 @@ namespace BTCPayServer.Payments
return JsonConvert.DeserializeObject<LightningSupportedPaymentMethod>(value.ToString()); return JsonConvert.DeserializeObject<LightningSupportedPaymentMethod>(value.ToString());
} }
public override string GetTransactionLink(BTCPayNetworkBase network, string txId)
{
return null;
}
public override string GetPaymentLink(BTCPayNetworkBase network, InvoiceEntity invoice, IPaymentMethodDetails paymentMethodDetails, public override string GetPaymentLink(BTCPayNetworkBase network, InvoiceEntity invoice, IPaymentMethodDetails paymentMethodDetails,
decimal cryptoInfoDue, string serverUri) decimal cryptoInfoDue, string serverUri)
{ {

View file

@ -83,7 +83,6 @@ namespace BTCPayServer.Payments
public abstract IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str); public abstract IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str);
public abstract string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details); public abstract string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details);
public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value); public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value);
public abstract string GetTransactionLink(BTCPayNetworkBase network, string txId);
public abstract string GetPaymentLink(BTCPayNetworkBase network, InvoiceEntity invoice, IPaymentMethodDetails paymentMethodDetails, public abstract string GetPaymentLink(BTCPayNetworkBase network, InvoiceEntity invoice, IPaymentMethodDetails paymentMethodDetails,
decimal cryptoInfoDue, string serverUri); decimal cryptoInfoDue, string serverUri);
public abstract string InvoiceViewPaymentPartialName { get; } public abstract string InvoiceViewPaymentPartialName { get; }

View file

@ -0,0 +1,35 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitBGold(IServiceCollection services)
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTG");
var network = new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BGold",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"BTG_X = BTG_BTC * BTC_X",
"BTG_BTC = gate(BTG_BTC)",
},
CryptoImagePath = "imlegacy/btg.svg",
LightningImagePath = "imlegacy/btg-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("156'") : new KeyPath("1'")
}.SetDefaultElectrumMapping(ChainName);
var blockExplorerLink = ChainName == ChainName.Mainnet ? "https://btgexplorer.com/tx/{0}" : "https://testnet.btgexplorer.com/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,38 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitDash(IServiceCollection services)
{
//not needed: NBitcoin.Altcoins.Dash.Instance.EnsureRegistered();
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("DASH");
var network = new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Dash",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"DASH_X = DASH_BTC * BTC_X",
"DASH_BTC = bitfinex(DSH_BTC)"
},
CryptoImagePath = "imlegacy/dash.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("5'")
: new KeyPath("1'")
}.SetDefaultElectrumMapping(ChainName);
var blockExplorerLink = ChainName == ChainName.Mainnet
? "https://insight.dash.org/insight/tx/{0}"
: "https://testnet-insight.dashevo.org/insight/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,36 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
using NBXplorer;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitDogecoin(IServiceCollection services)
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("DOGE");
var network = new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Dogecoin",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"DOGE_X = DOGE_BTC * BTC_X",
"DOGE_BTC = bittrex(DOGE_BTC)"
},
CryptoImagePath = "imlegacy/dogecoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("3'") : new KeyPath("1'")
}.SetDefaultElectrumMapping(ChainName);
var blockExplorerLink = ChainName == ChainName.Mainnet ? "https://dogechain.info/tx/{0}" : "https://dogechain.info/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,40 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitGroestlcoin(IServiceCollection services)
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("GRS");
var network = new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Groestlcoin",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"GRS_X = GRS_BTC * BTC_X",
"GRS_BTC = bittrex(GRS_BTC)"
},
CryptoImagePath = "imlegacy/groestlcoin.png",
LightningImagePath = "imlegacy/groestlcoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("17'") : new KeyPath("1'"),
SupportRBF = true,
SupportPayJoin = true,
VaultSupported = true
}.SetDefaultElectrumMapping(ChainName);
var blockExplorerLink = ChainName == ChainName.Mainnet
? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm"
: "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,53 @@
using System.Collections.Generic;
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
using NBXplorer;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitLitecoin(IServiceCollection services)
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LTC");
var network = new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Litecoin",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"LTC_X = LTC_BTC * BTC_X",
"LTC_BTC = coingecko(LTC_BTC)"
},
CryptoImagePath = "imlegacy/litecoin.svg",
LightningImagePath = "imlegacy/litecoin-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("2'") : new KeyPath("1'"),
//https://github.com/pooler/electrum-ltc/blob/0d6989a9d2fb2edbea421c116e49d1015c7c5a91/electrum_ltc/constants.py
ElectrumMapping = ChainName == ChainName.Mainnet
? new Dictionary<uint, DerivationType>()
{
{0x0488b21eU, DerivationType.Legacy },
{0x049d7cb2U, DerivationType.SegwitP2SH },
{0x04b24746U, DerivationType.Segwit },
}
: new Dictionary<uint, DerivationType>()
{
{0x043587cfU, DerivationType.Legacy },
{0x044a5262U, DerivationType.SegwitP2SH },
{0x045f1cf6U, DerivationType.Segwit }
}
};
var blockExplorerLinks = ChainName == ChainName.Mainnet
? "https://live.blockcypher.com/ltc/tx/{0}/"
: "http://explorer.litecointools.com/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLinks));
}
}

View file

@ -0,0 +1,36 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
using NBXplorer;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitMonacoin(IServiceCollection services)
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("MONA");
var network = new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Monacoin",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"MONA_X = MONA_BTC * BTC_X",
"MONA_BTC = bittrex(MONA_BTC)"
},
CryptoImagePath = "imlegacy/monacoin.png",
LightningImagePath = "imlegacy/mona-lightning.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("22'") : new KeyPath("1'")
}.SetDefaultElectrumMapping(ChainName);
var blockExplorerLink = ChainName == ChainName.Mainnet ? "https://mona.insight.monaco-ex.org/insight/tx/{0}" : "https://testnet-mona.insight.monaco-ex.org/insight/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Hosting;
using BTCPayServer.Logging;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NBitcoin;
using NBitcoin.Protocol;
using NBXplorer;
namespace BTCPayServer.Plugins.Altcoins
{
public partial class AltcoinsPlugin : BaseBTCPayServerPlugin
{
public override string Identifier => "BTCPayServer.Plugins.Altcoins";
public override string Name => "Altcoins";
public override string Description => "Add altcoins support";
public ChainName ChainName { get; private set; }
public NBXplorerNetworkProvider NBXplorerNetworkProvider { get; private set; }
public override void Execute(IServiceCollection applicationBuilder)
{
var services = (PluginServiceCollection)applicationBuilder;
var onChain = new Payments.PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike);
NBXplorerNetworkProvider = services.BootstrapServices.GetRequiredService<NBXplorerNetworkProvider>();
ChainName = NBXplorerNetworkProvider.NetworkType;
var selectedChains = services.BootstrapServices.GetRequiredService<SelectedChains>();
if (NBXplorerNetworkProvider.GetFromCryptoCode("LBTC") is { } liquidNBX)
{
if (selectedChains.Contains("LBTC"))
{
// Activating LBTC automatically activate the other liquid assets
InitUSDT(services, selectedChains, liquidNBX);
InitETB(services, selectedChains, liquidNBX);
InitLCAD(services, selectedChains, liquidNBX);
}
else
{
if (selectedChains.Contains("USDT"))
InitUSDT(services, selectedChains, liquidNBX);
if (selectedChains.Contains("ETB"))
InitETB(services, selectedChains, liquidNBX);
if (selectedChains.Contains("LCAD"))
InitLCAD(services, selectedChains, liquidNBX);
}
if (selectedChains.Contains("LBTC"))
InitLiquid(services, liquidNBX);
}
if (selectedChains.Contains("LTC"))
InitLitecoin(services);
if (selectedChains.Contains("DOGE"))
InitDogecoin(services);
if (selectedChains.Contains("BTG"))
InitBGold(services);
if (selectedChains.Contains("MONA"))
InitMonacoin(services);
if (selectedChains.Contains("DASH"))
InitDash(services);
if (selectedChains.Contains("GRS"))
InitGroestlcoin(services);
if (selectedChains.Contains("XMR"))
InitMonero(services);
if (selectedChains.Contains("ZEC"))
InitZcash(services);
}
}
}

View file

@ -0,0 +1,37 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
using NBitcoin.Altcoins;
using NBitcoin.Altcoins.Elements;
using NBXplorer;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitLiquid(IServiceCollection services, NBXplorer.NBXplorerNetwork nbxplorerNetwork)
{
var network = new ElementsBTCPayNetwork()
{
AssetId = ChainName == ChainName.Mainnet ? ElementsParams<Liquid>.PeggedAssetId : ElementsParams<Liquid.LiquidRegtest>.PeggedAssetId,
CryptoCode = "LBTC",
NetworkCryptoCode = "LBTC",
DisplayName = "Liquid Bitcoin",
DefaultRateRules = new[]
{
"LBTC_X = LBTC_BTC * BTC_X",
"LBTC_BTC = 1",
},
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/liquid.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true
}.SetDefaultElectrumMapping(ChainName);
var blockExplorerLink = ChainName == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(nbxplorerNetwork.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,97 @@
using System.Threading;
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
private void InitUSDT(IServiceCollection services, SelectedChains selectedChains, NBXplorer.NBXplorerNetwork nbxplorerNetwork)
{
var network = new ElementsBTCPayNetwork()
{
CryptoCode = "USDt",
NetworkCryptoCode = "LBTC",
ShowSyncSummary = false,
DefaultRateRules = new[]
{
"USDT_UST = 1",
"USDT_X = USDT_BTC * BTC_X",
"USDT_BTC = bitfinex(UST_BTC)",
},
AssetId = new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
DisplayName = "Liquid Tether",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/liquid-tether.svg",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
}.SetDefaultElectrumMapping(ChainName);
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(LiquidBlockExplorer));
selectedChains.Add("LBTC");
}
private void InitETB(IServiceCollection services, SelectedChains selectedChains, NBXplorer.NBXplorerNetwork nbxplorerNetwork)
{
var network = new ElementsBTCPayNetwork()
{
CryptoCode = "ETB",
NetworkCryptoCode = "LBTC",
ShowSyncSummary = false,
DefaultRateRules = new[]
{
"ETB_X = ETB_BTC * BTC_X",
"ETB_BTC = bitpay(ETB_BTC)"
},
Divisibility = 2,
AssetId = new uint256("aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf"),
DisplayName = "Ethiopian Birr",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/etb.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
}.SetDefaultElectrumMapping(ChainName);
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(LiquidBlockExplorer));
selectedChains.Add("LBTC");
}
string LiquidBlockExplorer => ChainName == ChainName.Mainnet ? "https://liquid.network/tx/{0}" : "https://liquid.network/testnet/tx/{0}";
private void InitLCAD(IServiceCollection services, SelectedChains selectedChains, NBXplorer.NBXplorerNetwork nbxplorerNetwork)
{
var network = new ElementsBTCPayNetwork()
{
CryptoCode = "LCAD",
NetworkCryptoCode = "LBTC",
ShowSyncSummary = false,
DefaultRateRules = new[]
{
"LCAD_CAD = 1",
"LCAD_X = CAD_BTC * BTC_X",
"LCAD_BTC = bylls(CAD_BTC)",
"CAD_BTC = LCAD_BTC"
},
AssetId = new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
DisplayName = "Liquid CAD",
NBXplorerNetwork = nbxplorerNetwork,
CryptoImagePath = "imlegacy/lcad.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(ChainName),
CoinType = ChainName == ChainName.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
SupportRBF = true,
SupportLightning = false
}.SetDefaultElectrumMapping(ChainName);
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike), new DefaultTransactionLinkProvider(LiquidBlockExplorer));
selectedChains.Add("LBTC");
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Common;
using NBitcoin;
using NBXplorer;
using NBXplorer.Models;
namespace BTCPayServer.Plugins.Altcoins;
public class ElementsBTCPayNetwork : BTCPayNetwork
{
public string NetworkCryptoCode { get; set; }
public uint256 AssetId { get; set; }
public override bool ReadonlyWallet { get; set; } = true;
public bool IsNativeAsset => NetworkCryptoCode == CryptoCode;
public override IEnumerable<(MatchedOutput matchedOutput, OutPoint outPoint)> GetValidOutputs(
NewTransactionEvent evtOutputs)
{
return evtOutputs.Outputs.Where(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId).Select(output =>
{
var outpoint = new OutPoint(evtOutputs.TransactionData.TransactionHash, output.Index);
return (output, outpoint);
});
}
public override List<TransactionInformation> FilterValidTransactions(List<TransactionInformation> transactionInformationSet)
{
return transactionInformationSet.FindAll(information =>
information.Outputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId) ||
information.Inputs.Any(output =>
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId));
}
public override PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, decimal? cryptoInfoDue)
{
//precision 0: 10 = 0.00000010
//precision 2: 10 = 0.00001000
//precision 8: 10 = 10
var money = cryptoInfoDue / (decimal)Math.Pow(10, 8 - Divisibility);
var builder = base.GenerateBIP21(cryptoInfoAddress, money);
builder.QueryParams.Add("assetid", AssetId.ToString());
return builder;
}
}

View file

@ -0,0 +1,33 @@
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using NBitcoin;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
public void InitMonero(IServiceCollection services)
{
var network = new MoneroLikeSpecificBtcPayNetwork()
{
CryptoCode = "XMR",
DisplayName = "Monero",
Divisibility = 12,
DefaultRateRules = new[]
{
"XMR_X = XMR_BTC * BTC_X",
"XMR_BTC = kraken(XMR_BTC)"
},
CryptoImagePath = "/imlegacy/monero.svg",
UriScheme = "monero"
};
var blockExplorerLink = ChainName == ChainName.Mainnet
? "https://www.exploremonero.com/transaction/{0}"
: "https://testnet.xmrchain.net/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new Payments.PaymentMethodId("XMR", PaymentTypes.BTCLike), new SimpleTransactionLinkProvider(blockExplorerLink));
}
}

View file

@ -0,0 +1,8 @@
namespace BTCPayServer.Plugins.Altcoins;
public class MoneroLikeSpecificBtcPayNetwork : BTCPayNetworkBase
{
public int MaxTrackedConfirmation = 10;
public string UriScheme { get; set; }
}

View file

@ -0,0 +1,51 @@
#nullable enable
using BTCPayServer.Services;
using System.Globalization;
using System.Linq;
using NBitcoin;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using BTCPayServer.Hosting;
using BTCPayServer.Payments;
namespace BTCPayServer.Plugins.Altcoins;
public partial class AltcoinsPlugin
{
// Change this if you want another zcash coin
public void InitZcash(IServiceCollection services)
{
var network = new ZcashLikeSpecificBtcPayNetwork()
{
CryptoCode = "ZEC",
DisplayName = "Zcash",
Divisibility = 8,
DefaultRateRules = new[]
{
"ZEC_X = ZEC_BTC * BTC_X",
"ZEC_BTC = kraken(ZEC_BTC)"
},
CryptoImagePath = "/imlegacy/zcash.png",
UriScheme = "zcash"
};
var blockExplorerLink = ChainName == ChainName.Mainnet
? "https://www.exploreZcash.com/transaction/{0}"
: "https://testnet.xmrchain.net/tx/{0}";
services.AddBTCPayNetwork(network)
.AddTransactionLinkProvider(new Payments.PaymentMethodId("ZEC", PaymentTypes.BTCLike), new SimpleTransactionLinkProvider(blockExplorerLink));
}
class SimpleTransactionLinkProvider : DefaultTransactionLinkProvider
{
public SimpleTransactionLinkProvider(string blockExplorerLink) : base(blockExplorerLink)
{
}
public override string? GetTransactionLink(string paymentId)
{
if (string.IsNullOrEmpty(BlockExplorerLink))
return null;
return string.Format(CultureInfo.InvariantCulture, BlockExplorerLink, paymentId);
}
}
}

Some files were not shown because too many files have changed in this diff Show more