private async Task SignTronTransaction(string transactionRaw, string path, int?expectedDataLength = null) { await GetLedger(); _LedgerManager.SetCoinNumber(195); var transactionData = new List <byte>(); for (var i = 0; i < transactionRaw.Length; i += 2) { var byteInHex = transactionRaw.Substring(i, 2); transactionData.Add(Convert.ToByte(byteInHex, 16)); } var derivationData = Helpers.GetDerivationPathData(AddressPathBase.Parse <BIP44AddressPath>(path)); var firstRequest = new TronAppSignatureRequest(derivationData.Concat(transactionData).ToArray()); var response = await _LedgerManager.SendRequestAsync <TronAppSignatureResponse, TronAppSignatureRequest>(firstRequest); var hexData = new StringBuilder(); for (var i = 0; i < response.Data.Length; i++) { hexData.Append(response.Data[i].ToString("X2")); } Console.WriteLine(hexData); Assert.IsTrue(response.IsSuccess, $"The response failed with a status of: {response.StatusMessage} ({response.ReturnCode})"); Assert.IsTrue(!expectedDataLength.HasValue || hexData.Length == expectedDataLength, $"Expected legnth {expectedDataLength}. Actual: {hexData.Length}"); }
private async Task <string> GetAddressAsync(string addressPath, bool display = false, string coinName = null, bool isPublicKey = false) { var bip44AddressPath = AddressPathBase.Parse <BIP44AddressPath>(addressPath); //TODO: Duplicate code here var address = await TrezorManager.GetAddressAsync(bip44AddressPath, isPublicKey, display); Assert.IsTrue(!string.IsNullOrEmpty(address), $"The address was null or empty. Path: {addressPath}"); Console.WriteLine(address); return(address); }
public async Task TestEthereumGetAddressParsed() { _LedgerManager.SetCoinNumber(60); //Modern Path var path = AddressPathBase.Parse <CustomAddressPath>("m/44'/60'/0'/0/0"); var address = await _LedgerManager.GetAddressAsync(path, false, false); Assert.IsTrue(!string.IsNullOrEmpty(address)); //Legacy Path path = AddressPathBase.Parse <CustomAddressPath>("m/44'/60'/0'/0"); address = await _LedgerManager.GetAddressAsync(path, false, false); Assert.IsTrue(!string.IsNullOrEmpty(address)); }
public async Task TestTronDisplayAddress() { uint coinNumber = 195; var isSegwit = false; var isChange = false; var index = 0; LedgerManager.SetCoinNumber(coinNumber); //This address seems to match the default address in the Tron app var path = $"m/{(isSegwit ? 49 : 44)}'/{coinNumber}'/{(isChange ? 1 : 0)}'/{0}/{index}"; var addressPath = AddressPathBase.Parse <BIP44AddressPath>(path); var address = await LedgerManager.GetAddressAsync(addressPath, false, true); Assert.IsTrue(!string.IsNullOrEmpty(address)); }
public async Task SignEthereumTransaction2() { var txMessage = new EthereumSignTx { Nonce = 10.ToBytesForRLPEncoding().ToHex().ToHexBytes(), GasPrice = 1000000000.ToBytesForRLPEncoding().ToHex().ToHexBytes(), GasLimit = 21000.ToBytesForRLPEncoding().ToHex().ToHexBytes(), To = "689c56aef474df92d44a1b70850f808488f9769c", Value = BigInteger.Parse("10000000000000000000").ToBytesForRLPEncoding().ToHex().ToHexBytes(), AddressNs = AddressPathBase.Parse <BIP44AddressPath>("m/44'/60'/0'/0/0").ToArray(), ChainId = 1 }; var transaction = await TrezorManager.SendMessageAsync <EthereumTxRequest, EthereumSignTx>(txMessage); Assert.AreEqual(transaction.SignatureR.Length, 32); Assert.AreEqual(transaction.SignatureS.Length, 32); }
static async Task SignBitcoinTransactionAsync() { //get address path for address in Trezor var addressPath = AddressPathBase.Parse <BIP44AddressPath>("m/49'/0'/0'/0/0").ToArray(); // previous unspent input of Transaction var txInput = new TxInputType() { AddressNs = addressPath, Amount = 100837, ScriptType = InputScriptType.Spendp2shwitness, PrevHash = "3becf448ae38cf08c0db3c6de2acb8e47acf6953331a466fca76165fdef1ccb7".ToBytes(), // transaction ID PrevIndex = 0, Sequence = 4294967293 // Sequence number represent Replace By Fee 4294967293 or leave empty for default }; // TX we want to make a payment var txOut = new TxOutputType() { AddressNs = new uint[0], Amount = 100837, Address = "18UxSJMw7D4UEiRqWkArN1Lq7VSGX6qH3H", ScriptType = OutputScriptType.Paytoaddress // if is segwit use Spendp2shwitness }; // Must be filled with basic data like below var signTx = new SignTx() { Expiry = 0, LockTime = 0, CoinName = "Bitcoin", Version = 2, OutputsCount = 1, InputsCount = 1 }; Log.Information($"TxSignature: {await _soterDevice.SignTransactionAsync(signTx, new List<TxInputType> { txInput }, new List<TxOutputType> { txOut })}"); }
public async Task SignBitcoinTransactionAsync() { //get address path for address in Trezor var addressPath = AddressPathBase.Parse <BIP44AddressPath>("m/49'/0'/0'/0/0").ToArray(); // previous unspent input of Transaction var txInput = new TxAck.TransactionType.TxInputType() { AddressNs = addressPath, Amount = 100837, ScriptType = InputScriptType.Spendp2shwitness, PrevHash = "797ad8727ee672123acfc7bcece06bf648d3833580b1b50246363f3293d9fe20".ToHexBytes(), // transaction ID PrevIndex = 0, Sequence = 4294967293 // Sequence number represent Replace By Fee 4294967293 or leave empty for default }; // TX we want to make a payment var txOut = new TxAck.TransactionType.TxOutputType() { AddressNs = new uint[0], Amount = 100837, Address = "34i58jxXbcjHbHmo1Pdzx8UjqLphZuG8c1", ScriptType = TxAck.TransactionType.TxOutputType.OutputScriptType.Paytoaddress // if is segwit use Spendp2shwitness }; // Must be filled with basic data like below var signTx = new SignTx() { Expiry = 0, LockTime = 0, CoinName = "Bitcoin", Version = 2, OutputsCount = 1, InputsCount = 1 }; // For every TX request from Trezor to us, we response with TxAck like below var txAck = new TxAck() { Tx = new TxAck.TransactionType() { Inputs = { txInput }, // Tx Inputs Outputs = { txOut }, // Tx Outputs Expiry = 0, InputsCnt = 1, // must be exact number of Inputs count OutputsCnt = 1, // must be exact number of Outputs count Version = 2 } }; // If the field serialized.serialized_tx from Trezor is set, // it contains a chunk of the signed transaction in serialized format. // The chunks are returned in the right order and just concatenating all returned chunks will result in the signed transaction. // So we need to add chunks to the list var serializedTx = new List <byte>(); // We send SignTx() to the Trezor and we wait him to send us Request var request = await TrezorManager.SendMessageAsync <TxRequest, SignTx>(signTx); // We do loop here since we need to send over and over the same transactions to trezor because his 64 kilobytes memory // and he will sign chunks and return part of signed chunk in serialized manner, until we receive finall type of Txrequest TxFinished while (request.request_type != TxRequest.RequestType.Txfinished) { switch (request.request_type) { case TxRequest.RequestType.Txinput: { //We send TxAck() with TxInputs request = await TrezorManager.SendMessageAsync <TxRequest, TxAck>(txAck); // Now we have to check every response is there any SerializedTx chunk if (request.Serialized != null) { // if there is any we add to our list bytes serializedTx.AddRange(request.Serialized.SerializedTx); } break; } case TxRequest.RequestType.Txoutput: { //We send TxAck() with TxOutputs request = await TrezorManager.SendMessageAsync <TxRequest, object>(txAck); // Now we have to check every response is there any SerializedTx chunk if (request.Serialized != null) { // if there is any we add to our list bytes serializedTx.AddRange(request.Serialized.SerializedTx); } break; } case TxRequest.RequestType.Txextradata: { // for now he didn't ask me for extra data :) break; } case TxRequest.RequestType.Txmeta: { // for now he didn't ask me for extra Tx meta data :) break; } } } Debug.WriteLine($"TxSignature: {serializedTx.ToArray().ToHexCompact()}"); }
public void TestParser() { var pathAsString = "m/45/5/3/5'/0'"; var customAddressPath = AddressPathBase.Parse <CustomAddressPath>(pathAsString); Assert.Equal(pathAsString, customAddressPath.ToString()); Assert.True(5 == customAddressPath.AddressPathElements.Count); Assert.True(45 == customAddressPath.AddressPathElements[0].Value); Assert.False(customAddressPath.AddressPathElements[0].Harden); Assert.True(5 == customAddressPath.AddressPathElements[1].Value); Assert.False(customAddressPath.AddressPathElements[1].Harden); Assert.True(3 == customAddressPath.AddressPathElements[2].Value); Assert.False(customAddressPath.AddressPathElements[2].Harden); Assert.True(5 == customAddressPath.AddressPathElements[3].Value); Assert.True(customAddressPath.AddressPathElements[3].Harden); Assert.True(2147483653 == customAddressPath.ToArray()[3]); pathAsString = "m/45/5/3/5'"; customAddressPath = AddressPathBase.Parse <CustomAddressPath>(pathAsString); Assert.Equal(pathAsString, customAddressPath.ToString()); Assert.True(2147483653 == customAddressPath.ToArray()[3]); Assert.True(5 == customAddressPath.AddressPathElements[3].Value); customAddressPath = AddressPathBase.Parse <CustomAddressPath>("0/1/2"); Assert.True(0 == customAddressPath.AddressPathElements[0].Value); Assert.True(1 == customAddressPath.AddressPathElements[1].Value); Assert.True(2 == customAddressPath.AddressPathElements[2].Value); var bip44AddressPath = AddressPathBase.Parse <BIP44AddressPath>("44'/0'/0'/0/0"); Assert.True(44 == bip44AddressPath.Purpose); Assert.True(0 == bip44AddressPath.CoinType); Assert.True(0 == bip44AddressPath.Account); Assert.True(0 == bip44AddressPath.Change); Assert.True(0 == bip44AddressPath.AddressIndex); Assert.True(bip44AddressPath.ToArray()[0] == 2147483692); var sb = new StringBuilder(); sb.Append("m"); for (var i = 0; i < 100; i++) { sb.Append($"/{i}{(i % 2 == 0 ? "'" : string.Empty)}"); } customAddressPath = AddressPathBase.Parse <CustomAddressPath>(sb.ToString()); for (var i = 0; i < 100; i++) { Assert.True(customAddressPath.AddressPathElements[i].Harden == (i % 2 == 0)); } Assert.Equal(sb.ToString(), customAddressPath.ToString()); Exception validationException = null; try { bip44AddressPath = AddressPathBase.Parse <BIP44AddressPath>("44'/0'/0/0/0"); bip44AddressPath.Validate(); } catch (Exception ex) { validationException = ex; } Assert.NotNull(validationException); validationException = null; try { bip44AddressPath = AddressPathBase.Parse <BIP44AddressPath>("50'/0'/0'/0/0"); bip44AddressPath.Validate(); } catch (Exception ex) { validationException = ex; } Assert.NotNull(validationException); }
private Task <string> GetAddressAsync(string addressPath, bool display = false, string coinName = null, bool isPublicKey = false) { var bip44AddressPath = AddressPathBase.Parse <BIP44AddressPath>(addressPath); return(TrezorManager.GetAddressAsync(bip44AddressPath, isPublicKey, display)); }
public async Task SignBitcoinTransactionAsync() { //get address path for address in Trezor var addressPath = AddressPathBase.Parse <BIP44AddressPath>("m/49'/0'/0'/0/0").ToArray(); // previous unspent inputs of Transaction var txInputs = new List <TxAck.TransactionType.TxInputType>() { new TxAck.TransactionType.TxInputType() { AddressNs = addressPath, Amount = 1790890, ScriptType = InputScriptType.Spendp2shwitness, PrevHash = "797ad8727ee672123acfc7bcece06bf648d3833580b1b50246363f3293d9fe20".ToHexBytes(), // transaction ID PrevIndex = 0, Sequence = 4294967293 // Sequence number represent Replace By Fee 4294967293 or leave empty for default } }; // TX we want to make a payment var txOutputs = new List <TxAck.TransactionType.TxOutputType>() { new TxAck.TransactionType.TxOutputType() { Amount = 50000, Address = "34i58jxXbcjHbHmo1Pdzx8UjqLphZuG8c1", ScriptType = TxAck.TransactionType.TxOutputType.OutputScriptType.Paytoaddress // always use Paytoaddress if Address is set }, new TxAck.TransactionType.TxOutputType() { Amount = 1790890 - 50000 - 1000, // change output does not specify Address but uses AddressNs AddressNs = AddressPathBase.Parse <BIP44AddressPath>("m/49'/0'/0'/1/0").ToArray(), ScriptType = TxAck.TransactionType.TxOutputType.OutputScriptType.Paytop2shwitness // must match all inputs }, }; // Must be filled with basic data like below var signTx = new SignTx() { LockTime = 0, CoinName = "Bitcoin", Version = 2, InputsCount = (uint)txInputs.Count, OutputsCount = (uint)txOutputs.Count, }; // Cache of previous transactions. This dictionary must contain an entry for every PrevHash used in the transaction inputs above. var prevTxes = new Dictionary <string, TxAck.TransactionType> { // Information taken from https://btc1.trezor.io/tx/797ad8727ee672123acfc7bcece06bf648d3833580b1b50246363f3293d9fe20 // All the shown fields must be correctly filled out. For Bitcoin, others can be omitted. ["797ad8727ee672123acfc7bcece06bf648d3833580b1b50246363f3293d9fe20".ToUpper()] = new TxAck.TransactionType() { Version = 1, LockTime = 0, Inputs = { new TxAck.TransactionType.TxInputType() { // address_n, script_type and amonout is unused in previous tx PrevHash = "0757c4c6247bbd46f718e6944735d3c5047c5e6f8bf0150506b5347b680b5812".ToHexBytes(), PrevIndex = 0, ScriptSig = "16001438865742de45fc9617e754fe0e413d2c6ef30124".ToHexBytes(), Sequence = 4294967295, }, }, // For previous tx, BinOutputs are used instead of Outputs. They only have amount and script_pubkey. BinOutputs = { new TxAck.TransactionType.TxOutputBinType() { Amount = 1790890, ScriptPubkey = "00146d4100c05c93a8f2bd7c1342df587ec90cb0ec43".ToHexBytes(), }, new TxAck.TransactionType.TxOutputBinType() { Amount = 1998443, ScriptPubkey = "a914211b791fc53bad19ef17b3ddeeeb24e610a5ffd087".ToHexBytes(), }, }, } }; // If the field serialized.serialized_tx from Trezor is set, // it contains a chunk of the signed transaction in serialized format. // The chunks are returned in the right order and just concatenating all returned chunks will result in the signed transaction. // So we need to add chunks to the list var serializedTx = new List <byte>(); // We send SignTx() to the Trezor and we wait him to send us Request var request = await TrezorManager.SendMessageAsync <TxRequest, SignTx>(signTx).ConfigureAwait(false); // We do loop here since we need to send over and over the same transactions to trezor because his 64 kilobytes memory // and he will sign chunks and return part of signed chunk in serialized manner, until we receive finall type of Txrequest TxFinished var running = true; while (running) { if (request.Serialized != null) { // if there is any we add to our list bytes serializedTx.AddRange(request.Serialized.SerializedTx); } // for clarity, use a new txAck object each time var txAck = new TxAck() { Tx = new TxAck.TransactionType() }; switch (request.request_type) { case TxRequest.RequestType.Txinput: { var prevHash = request.Details.TxHash; var prevIndex = (int)request.Details.RequestIndex; if (prevHash != null) { // retrieve input from specified previous tx var prevtx = prevTxes[prevHash.ToHexString()]; txAck.Tx.Inputs.Add(prevtx.Inputs[prevIndex]); } else { // take one of the current transaction inputs txAck.Tx.Inputs.Add(txInputs[prevIndex]); } request = await TrezorManager.SendMessageAsync <TxRequest, TxAck>(txAck).ConfigureAwait(false); break; } case TxRequest.RequestType.Txoutput: { var prevHash = request.Details.TxHash; var prevIndex = (int)request.Details.RequestIndex; if (prevHash != null) { // retrieve **bin** output from specified previous tx var prevtx = prevTxes[prevHash.ToHexString()]; txAck.Tx.BinOutputs.Add(prevtx.BinOutputs[prevIndex]); } else { // take one of the current transaction normal outputs txAck.Tx.Outputs.Add(txOutputs[prevIndex]); } request = await TrezorManager.SendMessageAsync <TxRequest, object>(txAck).ConfigureAwait(false); break; } case TxRequest.RequestType.Txextradata: { // This will never happen for Bitcoin. // For Zcash, you need to pre-fill ExtraData and ExtraDataLen in the previous tx. // This is somewhat complicated: basically, parse the raw transaction bytes up to Expiry field, // and take all raw bytes beyond that. // request.Details will contain offset and length, pick that chunk and put it into TransactionType.ExtraData that you send. throw new NotImplementedException(); } case TxRequest.RequestType.Txmeta: { // This will only happen when txHash is set. var prevtx = prevTxes[request.Details.TxHash.ToHexString()]; txAck.Tx = new TxAck.TransactionType() { Version = prevtx.Version, LockTime = prevtx.LockTime, InputsCnt = (uint)prevtx.Inputs.Count, OutputsCnt = (uint)prevtx.BinOutputs.Count, }; request = await TrezorManager.SendMessageAsync <TxRequest, object>(txAck).ConfigureAwait(false); break; } case TxRequest.RequestType.Txfinished: { // stop the loop running = false; break; } } } Debug.WriteLine($"TxSignature: {serializedTx.ToArray().ToHexCompact()}"); }