/// <summary> /// Initializes an instance of the <see cref="ScriptPubKey"/> class. /// </summary> /// <param name="script">The script.</param> /// <param name="network">The network where the transaction was conducted.</param> public ScriptPubKey(NBitcoin.Script script, Network network) : base(script) { var destinations = new List <TxDestination> { script.GetDestination(network) }; this.Type = this.GetScriptType(script.FindTemplate(network)); if (destinations[0] == null) { destinations = script.GetDestinationPublicKeys(network).Select(p => p.Hash).ToList <TxDestination>(); } // TODO: We do not want to put the cold staking addresses into the 'addresses' element due to the high potential for confusion. Maybe introduce an additional element? if (destinations.Count == 1) { this.ReqSigs = 1; this.Addresses = new List <string> { destinations[0].GetAddress(network).ToString() }; } else if (destinations.Count > 1) { PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script) ?? PayToFederationTemplate.Instance.ExtractScriptPubKeyParameters(script, network); if (multi != null) { this.ReqSigs = multi.SignatureCount; this.Addresses = multi.PubKeys.Select(m => m.GetAddress(network).ToString()).ToList(); } } }
/// <summary> /// Initializes an instance of the <see cref="ScriptPubKey"/> class. /// </summary> /// <param name="script">The script.</param> /// <param name="network">The network where the transaction was conducted.</param> public ScriptPubKey(NBitcoin.Script script, Network network) : base(script) { var destinations = new List <TxDestination> { script.GetDestination(network) }; this.Type = this.GetScriptType(script.FindTemplate(network)); if (destinations[0] == null) { destinations = script.GetDestinationPublicKeys(network).Select(p => p.Hash).ToList <TxDestination>(); } if (destinations.Count == 1) { this.ReqSigs = 1; this.Addresses = new List <string> { destinations[0].GetAddress(network).ToString() }; } else if (destinations.Count > 1) { PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script); this.ReqSigs = multi.SignatureCount; this.Addresses = multi.PubKeys.Select(m => m.GetAddress(network).ToString()).ToList(); } }
/// <summary> /// Initializes an instance of the <see cref="ScriptPubKey"/> class. /// </summary> /// <param name="script">The script.</param> /// <param name="network">The network where the transaction was conducted.</param> public ScriptPubKey(NBitcoin.Script script, Network network) : base(script) { this.Type = this.GetScriptType(script.FindTemplate(network)); // To avoid modifying the very low-level GetDestination logic, check for a cold staking script first. // The decision to show the cold pubkey's address in the 'addresses' list is based on the following: // 1. It seems more intuitive from a user's perspective that their balance will appear against this address. // 2. A balance should never appear against a hot address from an exchange's perspective, as they have no guarantee they will be able to spend those funds. // It is also presumed that it is preferable to show an address rather than not, as a block explorer would then have to show only a relatively meaningless raw script as the output's destination. // Another considered alternative was to show both addresses, but with a modified version byte. The underlying pubkey hashes would be the same, but the resulting addresses would be visually distinct from regular P2PKH. // This may have caused user confusion, however, as the modified addresses would not look like those they used to configure the cold staking setup, making searching for them on a block explorer more difficult. if (script.IsScriptType(ScriptType.ColdStaking)) { var coldPubKeyHash = new KeyId(script.ToBytes(true).SafeSubarray(28, 20)); this.ReqSigs = 1; this.Addresses = new List <string> { coldPubKeyHash.GetAddress(network).ToString() }; return; } var destinations = new List <TxDestination> { script.GetDestination(network) }; if (destinations[0] == null) { destinations = script.GetDestinationPublicKeys(network).Select(p => p.Hash).ToList <TxDestination>(); } // TODO: We do not want to put the cold staking addresses into the 'addresses' element due to the high potential for confusion. Maybe introduce an additional element? if (destinations.Count == 1) { this.ReqSigs = 1; this.Addresses = new List <string> { destinations[0].GetAddress(network).ToString() }; } else if (destinations.Count > 1) { PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script) ?? PayToFederationTemplate.Instance.ExtractScriptPubKeyParameters(script, network); if (multi != null) { this.ReqSigs = multi.SignatureCount; this.Addresses = multi.PubKeys.Select(m => m.GetAddress(network).ToString()).ToList(); } } }
public static bool IsSolvable(this ISigningRepository repo, Script scriptPubKey) { var temp = scriptPubKey.FindTemplate(); if (temp is PayToPubkeyTemplate p2pkT) { var pk = p2pkT.ExtractScriptPubKeyParameters(scriptPubKey) !; if (repo.TryGetPubKey(pk.Hash, out var _)) { return(true); } } if (temp is PayToPubkeyHashTemplate p2pkhT) { var keyId = p2pkhT.ExtractScriptPubKeyParameters(scriptPubKey) !; if (repo.TryGetPubKey(keyId, out var _)) { return(true); } } PubKey[]? pks = null; if (temp is PayToMultiSigTemplate p2multiT) { pks = p2multiT.ExtractScriptPubKeyParameters(scriptPubKey) !.PubKeys; } if (temp is PayToScriptHashTemplate p2shT) { var scriptId = p2shT.ExtractScriptPubKeyParameters(scriptPubKey) !; // This will give us witness script directly in case of p2sh-p2wsh if (repo.TryGetScript(scriptId, out var sc)) { scriptPubKey = sc; pks = sc.GetAllPubKeys(); } } if (temp is PayToWitTemplate) { var witId = PayToWitScriptHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey); if (witId != null) { if (repo.TryGetScript(witId.HashForLookUp, out var sc)) { pks = sc.GetAllPubKeys(); } } var wpkh = PayToWitPubKeyHashTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey); if (wpkh != null) { var witKeyId = wpkh.AsKeyId(); if (repo.TryGetPubKey(witKeyId, out var _)) { return(true); } } } if (pks != null) { foreach (var pk in pks) { if (!repo.TryGetPubKey(pk.Hash, out var _)) { return(false); } } return(true); } return(false); }