public void SignTx() { var tx = new SignTx(); tx.InputsCount = 2; tx.OutputsCount = 2; Utils.Write(tx, MessageType.MessageTypeSignTx); Read(); }
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 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()}"); }