Exemplo n.º 1
0
        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}");
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 4
0
        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));
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        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 })}");
        }
Exemplo n.º 7
0
        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);
        }
Exemplo n.º 9
0
        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));
        }
Exemplo n.º 10
0
        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()}");
        }