public override async Task <JObject> ExecuteAsync(IClient client)
        {
            var senderAddress = "0x12890d2cce102216644c59daE5baed380d84830c";
            var privateKey    = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";
            var abi           =
                @"[{""constant"":false,""inputs"":[{""name"":""val"",""type"":""int256""}],""name"":""multiply"",""outputs"":[{""name"":""d"",""type"":""int256""}],""type"":""function""},{""inputs"":[{""name"":""multiplier"",""type"":""int256""}],""type"":""constructor""}]";
            var byteCode =
                "0x60606040526040516020806052833950608060405251600081905550602b8060276000396000f3606060405260e060020a60003504631df4f1448114601a575b005b600054600435026060908152602090f3";

            var multiplier = 7;

            var web3 = new Web3.Web3(new Account(privateKey), client);

            var receipt = await
                          web3.Eth.DeployContract.SendRequestAndWaitForReceiptAsync(abi, byteCode, senderAddress,
                                                                                    new HexBigInteger(900000), null, multiplier);

            var contract = web3.Eth.GetContract(abi, receipt.ContractAddress);

            var function         = contract.GetFunction("multiply");
            var transactionInput = function.CreateTransactionInput(senderAddress, null, null, 7);
            var signer           = new TransactionSigner();
            var nonce            = await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(senderAddress);

            var signedTransaction = signer.SignTransaction(privateKey, transactionInput.To, 0, nonce.Value,
                                                           Transaction.DEFAULT_GAS_PRICE, 900000,
                                                           transactionInput.Data);

            var traceTransaction = new TraceRawTransaction(client);

            return(await traceTransaction.SendRequestAsync(signedTransaction.EnsureHexPrefix(),
                                                           new[] { TraceType.vmTrace }, BlockParameter.CreateLatest()));
        }
Пример #2
0
        public void Test_SignAndRecover()
        {
            var keyPair = new EcdsaKeyPair("0xD95D6DB65F3E2223703C5D8E205D98E3E6B470F067B0F94F6C6BF73D4301CE48"
                                           .HexToBytes().ToPrivateKey());
            var signer = new TransactionSigner();
            var abi    = ContractEncoder.Encode("hello()");
            var tx     = new Transaction
            {
                To         = ContractRegisterer.LatokenContract,
                Invocation = ByteString.CopyFrom(abi),
                From       = keyPair.PublicKey.GetAddress(),
                GasPrice   = 123123,
                /* TODO: "calculate gas limit for input size" */
                GasLimit = GasMetering.DefaultBlockGasLimit,
                Nonce    = 0,
                Value    = new BigInteger(0).ToUInt256()
            };
            // using old chain id
            var receipt = signer.Sign(tx, keyPair, false);

            Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(false).ToHex());

            var publicKey = receipt.RecoverPublicKey(false);

            Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex());
            Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex());

            // using new chain id
            receipt = signer.Sign(tx, keyPair, true);
            Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(true).ToHex());

            publicKey = receipt.RecoverPublicKey(true);
            Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex());
            Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex());
        }
 public IntegrationDependencies(TransactionFetcher fetcher)
 {
     Fetcher   = fetcher;
     Hasher    = new TransactionHasher(Fetcher);
     SignerMap = new SignerMap(new PayToPubKeySigner(Fetcher, Hasher), new PayToPubKeyHashSigner(Fetcher, Hasher));
     Signer    = new TransactionSigner(Fetcher, new ScriptClassifier(), SignerMap);
 }
Пример #4
0
        /// <summary>
        /// Sends a message to an ethereum smart contract with the intent to change a part of the contract on the blockchain.
        /// </summary>
        /// <typeparam name="TFunc"> The type of the function to execute. </typeparam>
        /// <param name="function"> The function to execute. </param>
        /// <param name="privateKey"> The private key of the address executing the contract function. </param>
        /// <param name="contractAddress"> The address of the contract which will process the message. </param>
        /// <param name="gasPrice"> The gas price (in wei) to use to send the transaction. </param>
        /// <param name="gasLimit"> The gas limit (in wei) to use to send the transaction. </param>
        /// <param name="value"> The amount of eth (in wei) to send with the transaction. </param>
        /// <returns> Task which returns the TransactionPoller which will await the transaction result. </returns>
        public static async Task <TransactionPoller> SendContractMessage <TFunc>(
            TFunc function,
            string privateKey,
            string contractAddress,
            BigInteger gasPrice,
            BigInteger gasLimit,
            BigInteger value) where TFunc : FunctionMessage, new()
        {
            EthECKey ethECKey = new EthECKey(privateKey);

            function.SetDefaultFromAddressIfNotSet(ethECKey.GetPublicAddress());
            function.Gas      = gasLimit;
            function.GasPrice = gasPrice;

            InMemoryNonceService nonceService = new InMemoryNonceService(ethECKey.GetPublicAddress(), NetworkProvider.GetWeb3().Client);

            TransactionSigner signer       = new TransactionSigner();
            string            signedTxData = signer.SignTransaction(
                privateKey,
                NetworkProvider.GetActiveNetworkChain(),
                contractAddress,
                value,
                (await nonceService.GetNextNonceAsync()).Value,
                gasPrice,
                gasLimit,
                function.CreateTransactionInput(contractAddress).Data);

            EthSendRawTransaction rawTransaction = new EthSendRawTransaction(NetworkProvider.GetWeb3().Client);

            return(new TransactionPoller(await rawTransaction.SendRequestAsync(signedTxData)));
        }
Пример #5
0
 public AccountSignerTransactionManager(IClient rpcClient, Account account, BigInteger?chainId = null)
 {
     ChainId            = chainId;
     Account            = account ?? throw new ArgumentNullException(nameof(account));
     Client             = rpcClient;
     _transactionSigner = new TransactionSigner();
 }
 public TransactionSignedUnityRequest(string url, string privateKey, string account)
 {
     _url                       = url;
     _account                   = account;
     _privateKey                = privateKey;
     _transactionSigner         = new TransactionSigner();
     _ethSendTransactionRequest = new EthSendRawTransactionUnityRequest(_url);
     _transactionCountRequest   = new EthGetTransactionCountUnityRequest(_url);
 }
 public TransactionSignedUnityRequest(Account account, string url)
 {
     _url                        = url;
     _account                    = account;
     _transactionSigner          = new TransactionSigner();
     _ethSendTransactionRequest  = new EthSendRawTransactionUnityRequest(_url);
     _transactionCountRequest    = new EthGetTransactionCountUnityRequest(_url);
     _ethEstimateGasUnityRequest = new EthEstimateGasUnityRequest(_url);
     _ethGasPriceUnityRequest    = new EthGasPriceUnityRequest(_url);
 }
 public AccountSignerTransactionManager(IClient rpcClient, string privateKey)
 {
     if (privateKey == null)
     {
         throw new ArgumentNullException(nameof(privateKey));
     }
     Client             = rpcClient;
     _account           = EthECKey.GetPublicAddress(privateKey);
     _privateKey        = privateKey;
     _transactionSigner = new TransactionSigner();
 }
Пример #9
0
 public TransactionSignedUnityRequest(string url, string privateKey)
 {
     _url                        = url;
     _account                    = EthECKey.GetPublicAddress(privateKey);
     _privateKey                 = privateKey;
     _transactionSigner          = new TransactionSigner();
     _ethSendTransactionRequest  = new EthSendRawTransactionUnityRequest(_url);
     _transactionCountRequest    = new EthGetTransactionCountUnityRequest(_url);
     _ethEstimateGasUnityRequest = new EthEstimateGasUnityRequest(_url);
     _ethGasPriceUnityRequest    = new EthGasPriceUnityRequest(_url);
 }
Пример #10
0
 protected virtual void InitialiseInnerServices()
 {
     Eth         = new EthApiContractService(Client);
     Shh         = new ShhApiService(Client);
     Net         = new NetApiService(Client);
     Personal    = new PersonalApiService(Client);
     Convert     = new UnitConversion();
     sha3Keccack = new Sha3Keccack();
     OfflineTransactionSigner = new TransactionSigner();
     addressUtil = new AddressUtil();
 }
Пример #11
0
        // Creates, Signs and publishes a new transaction
        public static TransactionHash createSignPublishTransaction(string abi, string contractAddress,
                                                                   string signingPrivateKey, string contractFunction, params object [] inputParams)
        {
            // Sign the transaction offline first
            string signedTransaction = new TransactionSigner().SignTransaction(
                signingPrivateKey,                                                                                               // privateKey
                contractAddress,                                                                                                 // to
                0,                                                                                                               // amount in wei to send with transaction
                web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(EthECKey.GetPublicAddress(signingPrivateKey)).Result, // nonce value
                AppModelConfig.defaultGasPrice,                                                                                  // gasPrice
                AppModelConfig.defaultGasLimit,                                                                                  // gasLimit
                web3.Eth.GetContract(abi, contractAddress).GetFunction(contractFunction).GetData(inputParams)                    // data
                );

            // Publish the raw and signed transaction
            try {
                return(new TransactionHash {
                    Hash = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync(signedTransaction).Result
                });
            } catch (Exception exc) {
                // If the transaction was rejected by the blockchain return and throw an HTTP Error
                throw new HttpError(
                          HttpStatusCode.NotAcceptable,
                          AppModelConfig.TransactionProcessingError,
                          AppModelConfig.TransactionProcessingErrorMessage + "   ---   " + exc.Message);
            }

            // ***************************************************************************************
            // Alternative method of publishing transactions by not using offline transaction signing
            //  => Disadvantage of this method is that every transaction creates a new web3 connection
            //  => Advantage of this method is that multiple transactions can be published at the same time (no issues with nonce values)
            // ***************************************************************************************

            // Function contractFunction =
            //     new Web3(new Account(signingPrivateKey), AppModelConfig.WEB3_URL_ENDPOINT).Eth.GetContract(abi, address).GetFunction(function);

            // // Create, Sign and publish transaction
            // try {
            //     return new TransactionHash {
            //         Hash = contractFunction.SendTransactionAsync(
            //             EthECKey.GetPublicAddress(signingPrivateKey),
            //             new HexBigInteger(4712388),
            //             null,
            //             inputParams
            //             ).Result
            //     };
            // } catch {
            //     // If the transaction was rejected by the blockchain return and throw an HTTP Error
            //     throw new HttpError(
            //         HttpStatusCode.NotAcceptable,
            //         AppModelConfig.TransactionProcessingError,
            //         AppModelConfig.TransactionProcessingErrorMessage);
            // }
        }
 public AccountSignerTransactionManager(IClient rpcClient, string privateKey)
 {
     if (privateKey == null)
     {
         throw new ArgumentNullException(nameof(privateKey));
     }
     Client   = rpcClient;
     _account = new Account(privateKey);
     _account.NonceService = new InMemoryNonceService(_account.Address, rpcClient);
     _transactionSigner    = new TransactionSigner();
 }
Пример #13
0
        public void Test_Tx_Pool_Replacement()
        {
            _blockManager.TryBuildGenesisBlock();
            TestTxPoolAdding();

            var privateKey = Crypto.GeneratePrivateKey().ToPrivateKey();
            var keyPair    = new EcdsaKeyPair(privateKey);

            AddRandomTxesToPool(keyPair, out var randomTxes);
            var rnd = new Random();

            randomTxes = randomTxes.OrderBy(item => rnd.Next()).ToList();
            bool useNewChainId = HardforkHeights.IsHardfork_9Active(_blockManager.GetHeight() + 1);
            var  signer        = new TransactionSigner();

            foreach (var tx in randomTxes)
            {
                Console.WriteLine($"nonce: {tx.Transaction.Nonce}");
                var newTx = new Transaction(tx.Transaction);
                // lower price
                newTx.GasPrice = tx.Transaction.GasPrice - 1;
                var randomTx = TestUtils.GetRandomTransaction(useNewChainId).Transaction;
                newTx.To       = randomTx.To;
                newTx.Value    = randomTx.Value;
                newTx.GasLimit = randomTx.GasLimit;
                var newTxReceipt = signer.Sign(newTx, keyPair, useNewChainId);
                var result       = _transactionPool.Add(newTxReceipt);
                Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}");
                Assert.AreEqual(OperatingError.Underpriced, result);
                // equal price
                newTx.GasPrice = tx.Transaction.GasPrice;
                newTxReceipt   = signer.Sign(newTx, keyPair, useNewChainId);
                result         = _transactionPool.Add(newTxReceipt);
                Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}");
                Assert.AreEqual(OperatingError.Underpriced, result);
                // higher price
                newTx.GasPrice = tx.Transaction.GasPrice + 1;
                newTxReceipt   = signer.Sign(newTx, keyPair, useNewChainId);
                result         = _transactionPool.Add(newTxReceipt);
                Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}");
                Assert.AreEqual(OperatingError.DuplicatedTransaction, result);
                // higher price and all fields same
                newTx          = new Transaction(tx.Transaction);
                newTx.GasPrice = tx.Transaction.GasPrice + 1;
                newTxReceipt   = signer.Sign(newTx, keyPair, useNewChainId);
                result         = _transactionPool.Add(newTxReceipt);
                Console.WriteLine($"old gas price: {tx.Transaction.GasPrice}, new gas price: {newTxReceipt.Transaction.GasPrice}");
                Assert.AreEqual(OperatingError.Ok, result);
            }
        }
 public SignedTransactionManager(IClient rpcClient, string privateKey, string account)
 {
     if (privateKey == null)
     {
         throw new ArgumentNullException(nameof(privateKey));
     }
     if (account == null)
     {
         throw new ArgumentNullException(nameof(account));
     }
     _rpcClient         = rpcClient;
     _privateKey        = privateKey;
     _account           = account;
     _transactionSigner = new TransactionSigner();
 }
Пример #15
0
        public void Test_SignIssue()
        {
            var keyPair = new EcdsaKeyPair("0xd95d6db65f3e2223703c5d8e205d98e3e6b470f067b0f94f6c6bf73d4301ce48"
                                           .HexToBytes().ToPrivateKey());
            var signer = new TransactionSigner();
            var data   =
                "0x0061736d01000000011c0660017f006000017f60037f7f7f0060027f7f0060000060017f017f0290010703656e76156765745f7472616e736665727265645f66756e6473000003656e760d6765745f63616c6c5f73697a65000103656e760f636f70795f63616c6c5f76616c7565000203656e760c6c6f61645f73746f72616765000303656e760a7365745f72657475726e000303656e760b73797374656d5f68616c74000003656e760c736176655f73746f72616765000303060504050202040405017001010105030100020608017f01418080040b071202066d656d6f72790200057374617274000b0ab806052e004100410036028080044100410036028480044100410036028c800441003f0041107441f0ff7b6a36028880040ba60101047f418080042101024003400240200128020c0d002001280208220220004f0d020b200128020022010d000b41002101410028020821020b02402002200041076a41787122036b22024118490d00200120036a41106a22002001280200220436020002402004450d00200420003602040b2000200241706a3602082000410036020c2000200136020420012000360200200120033602080b2001410136020c200141106a0b2d002000411f6a21000340200120002d00003a0000200141016a21012000417f6a21002002417f6a22020d000b0b2d002001411f6a21010340200120002d00003a00002001417f6a2101200041016a21002002417f6a22020d000b0b820402047f047e230041a0016b2200240020001000024002400240024002402000290300200041106a29030084200041086a290300200041186a29030084844200520d00100741001001220136020441002001100822023602084100200120021002200141034d0d014100200228020022033602000240200341eea3f68405460d00200341d4c78168470d0220004180016a41186a420037030020004200370390012000420037038801200042003703800120004180016a200041e0006a1003200041206a41186a200041e0006a41186a2903003703002000200041f0006a2903003703302000200041e8006a290300370328200020002903603703204100450d0341004100100441011005000b2001417c6a4120490d03200241046a200041c0006a41201009200041c8006a2903002104200041d0006a2903002105200041c0006a41186a29030021062000290340210720004180016a41186a4200370300200041e0006a41186a200637030020004200370390012000420037038801200042003703800120002005370370200020043703682000200737036020004180016a200041e0006a100641010d0441004100100441011005000b41004100100441011005000b41004100100441011005000b200041206a4120100822004120100a20004120100441001005000b200041a0016a240041030f0b41004100100441001005000b00740970726f647563657273010c70726f6365737365642d62790105636c616e675431302e302e3120286769743a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a65637420623661313733343336373838653638333239636335653965653066363531623630336136333765332900ad01046e616d6501a5010c00156765745f7472616e736665727265645f66756e6473010d6765745f63616c6c5f73697a65020f636f70795f63616c6c5f76616c7565030c6c6f61645f73746f72616765040a7365745f72657475726e050b73797374656d5f68616c74060c736176655f73746f72616765070b5f5f696e69745f6865617008085f5f6d616c6c6f63090b5f5f62653332746f6c654e0a0b5f5f6c654e746f626533320b057374617274"
                .HexToBytes();
            var tx = new Transaction
            {
                To         = UInt160Utils.Empty,
                Invocation = ByteString.CopyFrom(data),
                From       = "0x6Bc32575ACb8754886dC283c2c8ac54B1Bd93195".HexToBytes().ToUInt160(),
                GasPrice   = 1,
                GasLimit   = 5369560,
                Nonce      = 0,
                Value      = new BigInteger(0).ToUInt256()
            };
            // using old chain id
            var receipt = signer.Sign(tx, keyPair, false);

            Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(false).ToHex());
            var txHashFromWeb3Py = "0x0bd482bdd02f75f4897658f39c6ddf0a4ef0c58b2f4c3acdf0474ba497a0a6d5";

            Assert.AreEqual(receipt.Hash.ToHex(), txHashFromWeb3Py);

            var publicKey = receipt.RecoverPublicKey(false);

            Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex());
            Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex());


            // using new chain id
            receipt = signer.Sign(tx, keyPair, true);
            Assert.AreEqual(receipt.Hash.ToHex(), receipt.FullHash(true).ToHex());
            txHashFromWeb3Py = "0x45361b6213f2f7115feb7044ab9f52e03f2c7e49bb1866b5d094a0e39f0fa2f6";
            Assert.AreEqual(receipt.Hash.ToHex(), txHashFromWeb3Py);

            publicKey = receipt.RecoverPublicKey(true);
            Assert.AreEqual(keyPair.PublicKey.ToHex(), publicKey.ToHex());
            Assert.AreEqual(keyPair.PublicKey.GetAddress().ToHex(), publicKey.GetAddress().ToHex());
        }
Пример #16
0
        public static TransactionReceipt GetRandomTransactionFromAddress(EcdsaKeyPair keyPair, ulong nonce, bool useNewChainId)
        {
            var signer = new TransactionSigner();

            byte[] random = new byte[32];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            rng.GetBytes(random);
            var randomValue = new Random().Next(1, 100);
            var tx          = new Transaction
            {
                To       = random.Slice(0, 20).ToUInt160(),
                From     = keyPair.PublicKey.GetAddress(),
                GasPrice = (ulong)Money.Parse("0.0000001").ToWei(),
                GasLimit = 100000000,
                Nonce    = nonce,
                Value    = Money.Parse($"{randomValue}.0").ToUInt256()
            };

            return(signer.Sign(tx, keyPair, useNewChainId));
        }
Пример #17
0
        static void Main(string[] args)
        {
            KeyVaultClient kvc       = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
            var            signer    = new AzureKeyVaultExternalSigner(kvc, URI);
            var            publicKey = signer.GetPublicKeyAsync().Result;

            System.Console.WriteLine(publicKey.ToHex());

            var msgHash           = new Util.Sha3Keccack().CalculateHash("Hello").HexToByteArray();
            var ethExternalSigner = new EthECKeyExternalSigner(signer);

            var signature          = ethExternalSigner.SignAndCalculateVAsync(msgHash).Result;
            var publicKeyRecovered = EthECKey.RecoverFromSignature(signature, msgHash);

            System.Console.WriteLine(publicKeyRecovered.GetPubKey().ToHex());

            var transfer = new TransferFunction();

            transfer.To          = "0x1996a57077877D38e18A1BE44A55100D77b8fA1D";
            transfer.FromAddress = publicKeyRecovered.GetPublicAddress();
            transfer.Value       = 1;
            transfer.Nonce       = 1;
            transfer.GasPrice    = 100;
            transfer.Gas         = 1000;

            var rpcClient        = new RpcClient(new Uri("http://localhost:8545"));
            var transactionInput = transfer.CreateTransactionInput("0x12890d2cce102216644c59daE5baed380d84830c");

            var externalAccount = new ExternalAccount(ethExternalSigner, 1);

            externalAccount.InitialiseAsync().Wait();
            externalAccount.InitialiseDefaultTransactionManager(rpcClient);
            var signature2          = externalAccount.TransactionManager.SignTransactionAsync(transactionInput).Result;
            var transactionSigner   = new TransactionSigner();
            var publicKeyRecovered2 = transactionSigner.GetPublicKey(signature2, 1);

            System.Console.WriteLine(publicKeyRecovered2.ToHex());
            System.Console.ReadLine();
        }
Пример #18
0
        public static TransactionReceipt GetCustomTransaction(string value, string gasPrice, bool useNewChainId)
        {
            var signer = new TransactionSigner();

            byte[] random = new byte[32];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            rng.GetBytes(random);
            var keyPair = new EcdsaKeyPair(random.ToPrivateKey());

            var tx = new Transaction
            {
                To       = random.Slice(0, 20).ToUInt160(),
                From     = keyPair.PublicKey.GetAddress(),
                GasPrice = (ulong)Money.Parse(gasPrice).ToWei(),
                GasLimit = 100000000,
                Nonce    = 0,
                Value    = Money.Parse(value).ToUInt256()
            };

            return(signer.Sign(tx, keyPair, useNewChainId));
        }
    public IEnumerator SendRawTransaction()
    {
        //unpack first
        string json = File.ReadAllText(@"ks");

        KeyStoreService keystore = new KeyStoreService();

        byte[] privateKey;
        try
        {
            privateKey = keystore.DecryptKeyStoreFromJson("", json);  //live
        }
        catch (DecryptionException exc)
        {
            Debug.Log("password invalid");
            throw exc;
        }


        int nonce = 1; // GetPending transaction count + 1;

        TransactionSigner signer = new TransactionSigner();
        string            signedTransactionData = signer.SignTransaction(privateKey, m_addr,
                                                                         new BigInteger(0.002f * m_ether),
                                                                         new BigInteger(nonce),
                                                                         new BigInteger(20L * m_gwei),
                                                                         new BigInteger(21000));

        Assert.IsTrue(signer.VerifyTransaction(signedTransactionData));

        Debug.Log(signer.GetSenderAddress(signedTransactionData));

        EthSendRawTransactionUnityRequest req = new EthSendRawTransactionUnityRequest(m_endpoint);

        yield return(req.SendRequest(signedTransactionData));

        Debug.Log(req.Result);
    }
Пример #20
0
        /// <summary>
        /// Sends a given amount of ether to an address.
        /// </summary>
        /// <param name="privateKey"> The private key of the address which is sending the ether. </param>
        /// <param name="addressTo"> The address the ether is being sent to. </param>
        /// <param name="amount"> The amount of ether being sent, in eth. (not wei) </param>
        /// <param name="gasPrice"> The gas price (in wei) to use to send the transaction. </param>
        /// <param name="gasLimit"> The gas limit (in wei) to use to send the transaction. </param>
        /// <returns> Task which returns the TransactionPoller which will await the transaction result. </returns>
        public static async Task <TransactionPoller> SendEther(string privateKey, string addressTo, decimal amount, BigInteger gasPrice, BigInteger gasLimit)
        {
            BigInteger value = SolidityUtils.ConvertToUInt(amount, 18);

            EthECKey ethECKey = new EthECKey(privateKey);

            InMemoryNonceService nonceService = new InMemoryNonceService(ethECKey.GetPublicAddress(), NetworkProvider.GetWeb3().Client);

            TransactionSigner signer       = new TransactionSigner();
            string            signedTxData = signer.SignTransaction(
                privateKey,
                NetworkProvider.GetActiveNetworkChain(),
                addressTo,
                value,
                (await nonceService.GetNextNonceAsync()).Value,
                gasPrice,
                gasLimit,
                string.Empty);

            EthSendRawTransaction rawTransaction = new EthSendRawTransaction(NetworkProvider.GetWeb3().Client);

            return(new TransactionPoller(await rawTransaction.SendRequestAsync(signedTxData)));
        }
Пример #21
0
        public bool Run(bool txid, IConfiguration cfg, HttpClient httpClient, ITxBuilder txBuilder, Dictionary <string, string> settings, string progressId, string pluginsFolder, string url, string[] command, out bool inProgress, out string msg)
        {
            Debug.Assert(command != null);
            if (command.Length < 2)
            {
                inProgress = false;
                msg        = "invalid parameter count";
                return(false);
            }

            bool erc20 = command[0].Equals("collectCoins", StringComparison.OrdinalIgnoreCase);

            if (erc20 || command[0].Equals("registerTransfer", StringComparison.OrdinalIgnoreCase))
            {
                // ethereum RegisterTransfer gain orderId
                // ethereum CollectCoins amount

                string progress = Path.Combine(pluginsFolder, $"{name}_progress{progressId}.txt");

                inProgress = false;

                if (erc20 && command.Length != 2 || !erc20 && command.Length != 3)
                {
                    msg = "invalid parameter count";
                    return(false);
                }

                string gainString   = "0";
                string orderId      = null;
                string amountString = null;
                if (erc20)
                {
                    amountString = command[1];
                }
                else
                {
                    gainString = command[1];
                    orderId    = command[2];
                }

                string secret = cfg["secret"];
                if (string.IsNullOrWhiteSpace(secret))
                {
                    msg = "ethereum.secret is not set";
                    return(false);
                }
                var ethereumPrivateKey = secret;

#if DEBUG
                string confirmationsCount = cfg["confirmationsCount"];
                if (int.TryParse(confirmationsCount, out int parsedCount))
                {
                    mConfirmationsExpected = parsedCount;
                }
#endif

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";
                    return(false);
                }

                string ethSrcAddress = EthECKey.GetPublicAddress(ethereumPrivateKey);
                var    web3          = new Nethereum.Web3.Web3(rpcUrl);

                string srcAddressId = null;
                string dstAddressId = null;
                if (!erc20)
                {
                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{orderId}", out msg);
                    if (protobuf == null)
                    {
                        msg = "failed to extract address data through RPC";
                        return(false);
                    }
                    if (orderId.StartsWith(RpcHelper.creditCoinNamespace + RpcHelper.dealOrderPrefix))
                    {
                        var dealOrder = DealOrder.Parser.ParseFrom(protobuf);
                        if (gainString.Equals("0"))
                        {
                            srcAddressId = dealOrder.SrcAddress;
                            dstAddressId = dealOrder.DstAddress;
                        }
                        else
                        {
                            dstAddressId = dealOrder.SrcAddress;
                            srcAddressId = dealOrder.DstAddress;
                        }
                        amountString = dealOrder.Amount;
                    }
                    else if (orderId.StartsWith(RpcHelper.creditCoinNamespace + RpcHelper.repaymentOrderPrefix))
                    {
                        var repaymentOrder = RepaymentOrder.Parser.ParseFrom(protobuf);
                        if (gainString.Equals("0"))
                        {
                            srcAddressId = repaymentOrder.SrcAddress;
                            dstAddressId = repaymentOrder.DstAddress;
                        }
                        else
                        {
                            dstAddressId = repaymentOrder.SrcAddress;
                            srcAddressId = repaymentOrder.DstAddress;
                        }
                        amountString = repaymentOrder.Amount;
                    }
                    else
                    {
                        msg = "unexpected referred order";
                        return(false);
                    }
                }

                string payTxId;
                if (File.Exists(progress))
                {
                    Console.WriteLine("Found unfinished action, retrying...");
                    payTxId = File.ReadAllText(progress);
                }
                else
                {
                    string ethDstAddress = null;
                    if (!erc20)
                    {
                        var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{srcAddressId}", out msg);
                        if (protobuf == null)
                        {
                            msg = "failed to extract address data through RPC";
                            return(false);
                        }
                        var srcAddress = Address.Parser.ParseFrom(protobuf);

                        protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{dstAddressId}", out msg);
                        if (protobuf == null)
                        {
                            msg = "failed to extract address data through RPC";
                            return(false);
                        }
                        Address dstAddress = Address.Parser.ParseFrom(protobuf);

                        if (!srcAddress.Blockchain.Equals(name) || !dstAddress.Blockchain.Equals(name))
                        {
                            msg = $"ethereum RegisterTransfer can only transfer ether.\nThis source is registered for {srcAddress.Blockchain} and destination for {dstAddress.Blockchain}";
                            return(false);
                        }
                        ethDstAddress = dstAddress.Value;

                        if (!ethSrcAddress.Equals(srcAddress.Value, StringComparison.OrdinalIgnoreCase))
                        {
                            msg = "The deal is for a different client";
                            return(false);
                        }
                    }

                    BigInteger transferAmount;
                    if (!BigInteger.TryParse(amountString, out transferAmount) || transferAmount <= 0)
                    {
                        msg = "Invalid amount";
                        return(false);
                    }
                    BigInteger gain;
                    if (!BigInteger.TryParse(gainString, out gain))
                    {
                        msg = "Invalid amount";
                        return(false);
                    }
                    transferAmount = transferAmount + gain;
                    if (transferAmount < 0)
                    {
                        msg = "Invalid amount";
                        return(false);
                    }

                    var txCount = web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(ethSrcAddress).Result;
                    TransactionSigner signer = new TransactionSigner();

                    HexBigInteger gasPrice;

                    string gasPriceInGweiString = cfg["gasPriceInGwei"];
                    if (int.TryParse(gasPriceInGweiString, out int gasPriceOverride))
                    {
                        gasPrice = new HexBigInteger(Nethereum.Util.UnitConversion.Convert.ToWei(gasPriceOverride, Nethereum.Util.UnitConversion.EthUnit.Gwei));
                    }
                    else
                    {
                        gasPrice = web3.Eth.GasPrice.SendRequestAsync().Result;
                    }
                    Console.WriteLine("gasPrice: " + gasPrice.Value.ToString());

                    string        to;
                    string        data;
                    BigInteger    amount;
                    HexBigInteger gasLimit;
                    if (erc20)
                    {
                        string creditcoinContract    = cfg["creditcoinContract"];
                        string creditcoinContractAbi = cfg["creditcoinContractAbi"];

                        to = creditcoinContract;

                        var contract      = web3.Eth.GetContract(creditcoinContractAbi, creditcoinContract);
                        var burn          = contract.GetFunction("exchange");
                        var functionInput = new object[] { transferAmount, txBuilder.getSighash() };
                        data     = burn.GetData(functionInput);
                        gasLimit = burn.EstimateGasAsync(functionInput).Result;
                        amount   = 0;
                    }
                    else
                    {
                        gasLimit = web3.Eth.Transactions.EstimateGas.SendRequestAsync(new Nethereum.RPC.Eth.DTOs.CallInput(orderId, ethDstAddress, new Nethereum.Hex.HexTypes.HexBigInteger(transferAmount))).Result;
                        Console.WriteLine("gasLimit: " + gasLimit.Value.ToString());

                        to     = ethDstAddress;
                        data   = orderId;
                        amount = transferAmount;
                    }

                    string txRaw = signer.SignTransaction(ethereumPrivateKey, to, amount, txCount, gasPrice, gasLimit, data);
                    payTxId = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + txRaw).Result;
                    Console.WriteLine("Ethereum Transaction ID: " + payTxId);

                    File.WriteAllText(progress, $"{payTxId}");
                }

                inProgress = true;
                while (true)
                {
                    var receipt = web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(payTxId).Result;
                    if (receipt.BlockNumber != null)
                    {
                        var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                        if (blockNumber.Value - receipt.BlockNumber.Value >= mConfirmationsExpected)
                        {
                            break;
                        }
                    }
                    Thread.Sleep(1000);
                }
                File.Delete(progress);
                inProgress = false;

                if (erc20)
                {
                    command = new string[] { command[0], ethSrcAddress, amountString, payTxId };
                }
                else
                {
                    command = new string[] { command[0], gainString, orderId, payTxId };
                }
                var tx = txBuilder.BuildTx(command, out msg);
                if (tx == null)
                {
                    return(false);
                }

                Debug.Assert(msg == null);

                var content = new ByteArrayContent(tx);
                content.Headers.Add("Content-Type", "application/octet-stream");

                msg = RpcHelper.CompleteBatch(httpClient, url, "batches", content, txid);

                return(true);
            }
            else
            {
                inProgress = false;
                msg        = "Unknown command: " + command[0];
                return(false);
            }
        }
Пример #22
0
        public bool Run(IConfiguration cfg, HttpClient httpClient, ITxBuilder txBuilder, Dictionary <string, string> settings, string pluginsFolder, string url, string[] command, out bool inProgress, out string msg)
        {
            Debug.Assert(command != null);
            Debug.Assert(command.Length > 1);
            if (command[0].Equals("registerTransfer", StringComparison.OrdinalIgnoreCase))
            {
                // ethereum RegisterTransfer registeredSourceId amount

                string progress = Path.Combine(pluginsFolder, $"{name}_progress.txt");

                inProgress = false;

                Debug.Assert(command.Length == 3 || command.Length == 4);
                string registeredSourceId = command[1];
                string amountString       = command[2];
                bool   erc20 = command.Length == 4;

                string secret = cfg["secret"];
                if (string.IsNullOrWhiteSpace(secret))
                {
                    msg = "ethereum.secret is not set";

                    return(false);
                }
                var ethereumPrivateKey = secret;

                // TODO disable confirmation count config for release build
                string confirmationsCount = cfg["confirmationsCount"];
                if (string.IsNullOrWhiteSpace(confirmationsCount))
                {
                    msg = "ethereum.confirmationsCount is not set";

                    return(false);
                }
                if (!int.TryParse(confirmationsCount, out int confirmationsExpected))
                {
                    msg = "ethereum.confirmationsCount is not an int";

                    return(false);
                }

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";

                    return(false);
                }

                var web3 = new Nethereum.Web3.Web3(rpcUrl);

                string     payTxId;
                BigInteger fee;
                if (File.Exists(progress))
                {
                    Console.WriteLine("Found unfinished action, retrying...");
                    var data = File.ReadAllText(progress).Split(':');
                    if (data.Length != 2)
                    {
                        msg = "Invalid progress data";
                        return(false);
                    }
                    payTxId = data[0];
                    if (!BigInteger.TryParse(data[1], out fee))
                    {
                        msg = "Invalid progress data";
                        return(false);
                    }
                }
                else
                {
                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{url}/state/{registeredSourceId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var address = Address.Parser.ParseFrom(protobuf);

                    string destinationAddress;
                    if (!settings.TryGetValue("sawtooth.escrow." + name, out destinationAddress))
                    {
                        msg = "Escrow not found for " + name;
                        return(false);
                    }

                    BigInteger transferAmount;
                    if (!BigInteger.TryParse(amountString, out transferAmount) || transferAmount <= 0)
                    {
                        msg = "Invalid amount";
                        return(false);
                    }

                    if (!address.Blockchain.Equals(name))
                    {
                        msg = $"ethereum RegisterTransfer can only transfer ether.\nThis source is registered for {address.Blockchain}";
                        return(false);
                    }

                    string sourceAddress = EthECKey.GetPublicAddress(ethereumPrivateKey);

                    if (!sourceAddress.Equals(address.Address_, StringComparison.OrdinalIgnoreCase))
                    {
                        msg = "The deal is for a different client";
                        return(false);
                    }

                    var txCount = web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(sourceAddress).Result;
                    TransactionSigner signer = new TransactionSigner();

                    // TODO maybe add a y/n choice for user to decline or configurable gas price override
                    var gasPrice = web3.Eth.GasPrice.SendRequestAsync().Result;
                    Console.WriteLine("gasPrice: " + gasPrice.Value.ToString());

                    string        to;
                    string        data;
                    BigInteger    amount;
                    HexBigInteger gasLimit;
                    if (erc20)
                    {
                        string creditcoinContract    = cfg["creditcoinContract"];
                        string creditcoinContractAbi = cfg["creditcoinContractAbi"];

                        to = creditcoinContract;

                        var contract      = web3.Eth.GetContract(creditcoinContractAbi, creditcoinContract);
                        var burn          = contract.GetFunction("exchange");
                        var functionInput = new object[] { transferAmount, address.Sighash };
                        data     = burn.GetData(functionInput);
                        gasLimit = burn.EstimateGasAsync(functionInput).Result;
                        fee      = gasLimit.Value * gasPrice.Value;
                        amount   = 0;
                    }
                    else
                    {
                        gasLimit = web3.Eth.Transactions.EstimateGas.SendRequestAsync(new Nethereum.RPC.Eth.DTOs.CallInput(registeredSourceId, destinationAddress, new Nethereum.Hex.HexTypes.HexBigInteger(transferAmount))).Result;
                        Console.WriteLine("gasLimit: " + gasLimit.Value.ToString());

                        fee    = gasLimit.Value * gasPrice.Value;
                        to     = destinationAddress;
                        data   = address.Sighash;
                        amount = transferAmount + fee;
                    }

                    string txRaw = signer.SignTransaction(ethereumPrivateKey, to, amount, txCount, gasPrice, gasLimit, data);
                    payTxId = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + txRaw).Result;
                    Console.WriteLine("Ethereum Transaction ID: " + payTxId);

                    File.WriteAllText(progress, $"{payTxId}:{fee.ToString()}");
                }

                inProgress = true;
                while (true)
                {
                    var receipt = web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(payTxId).Result;
                    if (receipt.BlockNumber != null)
                    {
                        var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                        if (blockNumber.Value - receipt.BlockNumber.Value >= confirmationsExpected)
                        {
                            break;
                        }
                    }
                    Thread.Sleep(1000);
                }
                File.Delete(progress);
                inProgress = false;

                command = new string[] { command[0], registeredSourceId, amountString, erc20 ? "0" : fee.ToString(), payTxId, erc20 ? "creditcoin" : "1" };
                var tx = txBuilder.BuildTx(command, out msg);
                if (tx == null)
                {
                    return(false);
                }

                Debug.Assert(msg == null);

                var content = new ByteArrayContent(tx);
                content.Headers.Add("Content-Type", "application/octet-stream");

                msg = RpcHelper.CompleteBatch(httpClient, $"{url}/batches", content);

                return(true);
            }
            else
            {
                inProgress = false;
                msg        = "Unknown command: " + command[0];
                return(false);
            }
        }
Пример #23
0
 public AccountOfflineTransactionSigner()
 {
     _transactionSigner = new TransactionSigner();
 }
 public AccountSignerTransactionManager(IClient rpcClient, Account account)
 {
     _account           = account ?? throw new ArgumentNullException(nameof(account));
     Client             = rpcClient;
     _transactionSigner = new TransactionSigner();
 }
Пример #25
0
        /// <summary>
        /// TODO: This should be made in to a unit test but it's annoying to add the UI for a unit test as the Trezor requires human intervention for the pin
        /// </summary>
        /// <returns></returns>
        private async static Task Go()
        {
            try
            {
                using (var trezorHid = await Connect())
                {
                    using (var trezorManager = new TrezorManager(GetPin, trezorHid))
                    {
                        await trezorManager.InitializeAsync();

                        var tasks = new List <Task>();

                        for (var i = 0; i < 50; i++)
                        {
                            tasks.Add(DoGetAddress(trezorManager, i));
                        }

                        await Task.WhenAll(tasks);

                        for (var i = 0; i < 50; i++)
                        {
                            var address = await GetAddress(trezorManager, i);

                            Console.WriteLine($"Index: {i} (No change) - Address: {address}");

                            if (address != _Addresses[i])
                            {
                                throw new Exception("The ordering got messed up");
                            }
                        }

                        var ethAddress = await trezorManager.GetAddressAsync("ETH", 60, false, 0, false, AddressType.Ethereum);

                        Console.WriteLine($"First ETH address: {ethAddress}");

                        //This fails with 'Safety check failed'
                        //See https://github.com/trezor/trezor-mcu/issues/143
                        //https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c
                        //Which values here need leading zeros? Is Unicode the correct encoding?



                        var message = new EthereumSignMessage
                        {
                            AddressNs = KeyPath.Parse("m/44'/60'/0'/0/0").Indexes,
                            Message   = Encoding.UTF8.GetBytes("Hello").ToHex().ToHexBytes()
                        };

                        var messageSignature = await trezorManager.SendMessageAsync <EthereumMessageSignature, EthereumSignMessage>(message);

                        //Same as first address
                        Console.WriteLine(ToHex(messageSignature.Address));

                        var signer            = new Nethereum.Signer.EthereumMessageSigner();
                        var messageSignature2 = signer.EncodeUTF8AndSign("Hello2", new EthECKey(
                                                                             "0x2e14c29aaecd1b7c681154d41f50c4bb8b6e4299a431960ed9e860e39cae6d29"));
                        // var recoveredAddress = signer.EncodeUTF8AndEcRecover("Hello", messageSignature.Signature.ToHex());
                        //Same as recovered address
                        //Console.WriteLine(recoveredAddress);

                        //var txMessage = new EthereumSignTx
                        //{
                        //    Nonce = 1.ToHexBytes(),
                        //    GasPrice = 1000000000.ToHexBytes(),
                        //    GasLimit = 21000.ToHexBytes(),
                        //    To = "689c56aef474df92d44a1b70850f808488f9769c".ToHexBytes(),
                        //    Value = 1000000000000000.ToHexBytes(),
                        //    //Value = "de0b6b3a7640000".ToHexBytes(),
                        //    AddressNs = KeyPath.Parse("m/44'/60'/0'/0/0").Indexes,
                        //    ChainId = 1
                        //};



                        var txMessage = new EthereumSignTx
                        {
                            Nonce    = 10.ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            GasPrice = 10.ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            GasLimit = 21000.ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            To       = "689c56aef474df92d44a1b70850f808488f9769c".ToHexBytes(),
                            Value    = BigInteger.Parse("10000000000000000000").ToBytesForRLPEncoding().ToHex().ToHexBytes(),
                            //Value = "de0b6b3a7640000".ToHexBytes(),
                            AddressNs = KeyPath.Parse("m/44'/60'/0'/0/0").Indexes,
                            //ChainId = 1
                        };
                        var transaction = await trezorManager.SendMessageAsync <EthereumTxRequest, EthereumSignTx>(txMessage);

                        var transactionSigner = new TransactionSigner();
                        var sigature2         = transactionSigner.SignTransaction("0x2e14c29aaecd1b7c681154d41f50c4bb8b6e4299a431960ed9e860e39cae6d29",
                                                                                  "0x689c56aef474df92d44a1b70850f808488f9769c", 10, 10, 10, 21000);
                        var transactionRecovered = new Transaction(sigature2.HexToByteArray());
                        //var transactionChainId = new TransactionChainId(sigature2.HexToByteArray(), 1);


                        Console.WriteLine("All good");

                        Console.ReadLine();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Console.ReadLine();
            }
        }
Пример #26
0
 public AccountOfflineTransactionSigner(TransactionSigner transactionSigner)
 {
     _transactionSigner = transactionSigner;
 }
Пример #27
0
        public bool Run(IConfiguration cfg, string signerHexStr, string[] command, out string msg)
        {
            Debug.Assert(command != null);
            Debug.Assert(command.Length > 0);
            if (command[0].Equals("verify"))
            {
                Debug.Assert(command.Length == 7);
                string txId = command[1];
                string destinationAddressString = command[2];
                string destinationAmount        = command[3];
                string sighash             = command[4];
                string sourceAddressString = command[5];
                string networkId           = command[6];

                // TODO disable confirmation count config for release build
                string confirmationsCount = cfg["confirmationsCount"];
                if (string.IsNullOrWhiteSpace(confirmationsCount))
                {
                    msg = "ethereum.confirmationsCount is not set";

                    return(false);
                }
                if (!int.TryParse(confirmationsCount, out int confirmationsExpected))
                {
                    msg = "ethereum.confirmationsCount is not an int";

                    return(false);
                }

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";

                    return(false);
                }

                var web3 = new Nethereum.Web3.Web3(rpcUrl);

                var tx            = web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(txId).Result;
                int confirmations = 0;
                if (tx.BlockNumber != null)
                {
                    var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                    confirmations = (int)(blockNumber.Value - tx.BlockNumber.Value);
                }

                if (confirmations < confirmationsExpected)
                {
                    msg = "Invalid transaction: not enough confirmations";
                    return(false);
                }

                if (!sourceAddressString.Equals(tx.From, System.StringComparison.OrdinalIgnoreCase))
                {
                    msg = "Invalid transaction: wrong sourceAddressString";
                    return(false);
                }

                if (networkId.Equals("creditcoin"))
                {
                    string creditcoinContract = cfg["creditcoinContract"];

                    if (string.IsNullOrWhiteSpace(creditcoinContract))
                    {
                        msg = "ethereum.creditcoinContract is not set";

                        return(false);
                    }

                    string creditcoinContractAbi = cfg["creditcoinContractAbi"];
                    if (string.IsNullOrWhiteSpace(creditcoinContractAbi))
                    {
                        msg = "ethereum.creditcoinContractAbi is not set";

                        return(false);
                    }

                    var contract = web3.Eth.GetContract(creditcoinContractAbi, creditcoinContract);
                    var burn     = contract.GetFunction("exchange");
                    var inputs   = burn.DecodeInput(tx.Input);
                    Debug.Assert(inputs.Count == 2);
                    var value = inputs[0].Result.ToString();
                    if (destinationAmount != value)
                    {
                        msg = "Invalid transaction: wrong amount";
                        return(false);
                    }

                    var tag = inputs[1].Result.ToString();
                    if (!tag.Equals(sighash))
                    {
                        msg = "Invalid transaction: wrong sighash";
                        return(false);
                    }
                }
                else
                {
                    if (destinationAmount != tx.Value.Value.ToString())
                    {
                        msg = "Invalid transaction: wrong amount";
                        return(false);
                    }

                    if (tx.Input == null)
                    {
                        msg = "Invalid transaction: expecting data";
                        return(false);
                    }

                    if (!sighash.StartsWith("0x"))
                    {
                        sighash = "0x" + sighash;
                    }
                    if (!tx.Input.Equals(sighash, System.StringComparison.OrdinalIgnoreCase))
                    {
                        msg = "Invalid transaction: wrong sighash";
                        return(false);
                    }

                    if (!tx.To.Equals(destinationAddressString, System.StringComparison.OrdinalIgnoreCase))
                    {
                        msg = "Invalid transaction: wrong destinationAddressString";
                        return(false);
                    }
                }

                msg = null;
                return(true);
            }
            else if (command[0].Equals("unlock"))
            {
                var ccSigner  = new Signer(RpcHelper.HexToBytes(signerHexStr));
                var txBuilder = new TxBuilder(ccSigner);

                Debug.Assert(command.Length == 5);
                string kind = command[1];
                string addressFromString = command[2];

                HttpClient httpClient = new HttpClient();

                string txFrom;
                string amountString;
                string feeString;
                string addressToString;
                string networkId;

                string ccCommand;

                if (kind.Equals("funds"))
                {
                    string dealOrderId            = command[3];
                    string addressToUnlockFundsTo = command[4];

                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{dealOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var dealOrder = DealOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{dealOrder.AskOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var askOrder = AskOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{askOrder.TransferId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var transfer = Transfer.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{addressToUnlockFundsTo}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var address = Address.Parser.ParseFrom(protobuf);
                    if (!askOrder.Sighash.Equals(address.Sighash))
                    {
                        msg = "The address doesn't match the ask order";
                        return(false);
                    }
                    txFrom          = transfer.Txid;
                    amountString    = transfer.Amount;
                    feeString       = transfer.Fee;
                    addressToString = address.Address_;
                    networkId       = transfer.Network;
                    ccCommand       = "UnlockFunds";
                }
                else if (kind.Equals("collateral"))
                {
                    string repaymentOrderId             = command[3];
                    string addressToUnlockCollateralsTo = command[4];

                    var protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{repaymentOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var repaymentOrder = RepaymentOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{repaymentOrder.DealId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var dealOrder = DealOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{dealOrder.AskOrderId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var askOrder = AskOrder.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{askOrder.TransferId}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var transfer = Transfer.Parser.ParseFrom(protobuf);
                    protobuf = RpcHelper.ReadProtobuf(httpClient, $"{creditcoinUrl}/state/{addressToUnlockCollateralsTo}", out msg);
                    if (protobuf == null)
                    {
                        return(false);
                    }
                    var address = Address.Parser.ParseFrom(protobuf);
                    if (!askOrder.Sighash.Equals(address.Sighash))
                    {
                        msg = "The address doesn't match the ask order";
                        return(false);
                    }
                    txFrom          = transfer.Txid;
                    amountString    = transfer.Amount;
                    feeString       = transfer.Fee;
                    addressToString = address.Address_;
                    networkId       = transfer.Network;
                    ccCommand       = "UnlockCollateral";
                }
                else
                {
                    msg = "unknown unlock kind";
                    return(false);
                }

                string secret = cfg["secret"];
                if (string.IsNullOrWhiteSpace(secret))
                {
                    msg = "ethereum.secret is not set";
                    return(false);
                }
                var ethereumPrivateKey = secret;

                // TODO disable confirmation count config for release build
                string confirmationsCount = cfg["confirmationsCount"];
                if (string.IsNullOrWhiteSpace(confirmationsCount))
                {
                    msg = "ethereum.confirmationsCount is not set";
                    return(false);
                }
                if (!int.TryParse(confirmationsCount, out int confirmationsExpected))
                {
                    msg = "ethereum.confirmationsCount is not an int";
                    return(false);
                }

                string rpcUrl = cfg["rpc"];
                if (string.IsNullOrWhiteSpace(rpcUrl))
                {
                    msg = "ethereum.rpc is not set";
                    return(false);
                }

                BigInteger fee;
                if (!BigInteger.TryParse(feeString, out fee))
                {
                    msg = "Invalid progress data";
                    return(false);
                }

                var web3 = new Nethereum.Web3.Web3(rpcUrl);

                BigInteger transferAmount;
                if (!BigInteger.TryParse(amountString, out transferAmount) || transferAmount <= 0)
                {
                    msg = "Invalid amount";
                    return(false);
                }

                string sourceAddress = EthECKey.GetPublicAddress(ethereumPrivateKey);

                if (!sourceAddress.Equals(addressFromString, StringComparison.OrdinalIgnoreCase))
                {
                    msg = "The deal is for a different client";
                    return(false);
                }

                var txCount = web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(sourceAddress).Result;
                TransactionSigner signer = new TransactionSigner();
                var    gasLimit          = web3.Eth.Transactions.EstimateGas.SendRequestAsync(new Nethereum.RPC.Eth.DTOs.CallInput(string.Empty, addressToString, new Nethereum.Hex.HexTypes.HexBigInteger(transferAmount))).Result;
                var    gasPrice          = web3.Eth.GasPrice.SendRequestAsync().Result;
                string txRaw             = signer.SignTransaction(ethereumPrivateKey, addressToString, transferAmount + fee, txCount, gasPrice, gasLimit, string.Empty);
                string payTxId           = web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + txRaw).Result;

                while (true)
                {
                    var receipt = web3.Eth.TransactionManager.TransactionReceiptService.PollForReceiptAsync(payTxId).Result;
                    if (receipt.BlockNumber != null)
                    {
                        var blockNumber = web3.Eth.Blocks.GetBlockNumber.SendRequestAsync().Result;
                        if (blockNumber.Value - receipt.BlockNumber.Value >= confirmationsExpected)
                        {
                            break;
                        }
                    }
                    Thread.Sleep(1000);
                }

                command = new string[] { ccCommand, command[3], command[4] };
                var tx = txBuilder.BuildTx(command, out msg);
                Debug.Assert(tx != null);
                Debug.Assert(msg == null);
                var content = new ByteArrayContent(tx);
                content.Headers.Add("Content-Type", "application/octet-stream");
                msg = RpcHelper.CompleteBatch(httpClient, $"{creditcoinUrl}/batches", content);
            }

            msg = "Unknown command: " + command[0];
            return(false);
        }
Пример #28
0
        public async Task <IActionResult> Post(JsonRpcClientReq req, int chainid = 0)
        {
            if (chainid == 0)
            {
                return(BadRequest("chainid error"));
            }

            switch (req.Method)
            {
            case "eth_sendRawTransaction": {
                var signer = new TransactionSigner();

                var addr = signer.GetSenderAddress(req.Params[0].ToString());
                var rpc  = NodeChoose.ChooseServer(chainid, addr);

                if (string.IsNullOrEmpty(rpc))
                {
                    return(BadRequest("not find suitable rpc server"));
                }

                var sendResult = await SendRequest(req, rpc);

                if (sendResult.result)
                {
                    return(new ContentResult()
                        {
                            Content = sendResult.response,
                            ContentType = "application/json",
                            StatusCode = 200
                        });
                }
                return(BadRequest(sendResult.response));
            }

            default: {
                var cache = EthRpcCache.Instance.CheckCache(chainid, req);
                if (cache.hasCache)
                {
                    Logger.Debug($"{req} in cache");

                    //update resp id
                    var respObj = JObject.Parse(cache.result);
                    respObj["id"]    = req.Id;
                    respObj["cache"] = cache.strategy.ToString();

                    return(new ContentResult()
                        {
                            Content = respObj.ToString(Formatting.None),
                            ContentType = "application/json",
                            StatusCode = 200
                        });
                }

                var rpc = NodeChoose.ChooseServer(chainid);
                if (string.IsNullOrEmpty(rpc))
                {
                    return(BadRequest("not find suitable rpc server"));
                }

                var sendResult = await SendRequest(req, rpc);

                if (sendResult.result)
                {
                    var respObj = JObject.Parse(sendResult.response);

                    switch (cache.strategy)
                    {
                    case RpcCacheStrategy.NotCache:
                        break;

                    case RpcCacheStrategy.CacheInMemory:
                    case RpcCacheStrategy.CacheInDb:
                        var cacheResult = EthRpcCache.Instance.AddCache(chainid, req, sendResult.response);
                        respObj["cacheOption"] = cache.strategy.ToString();
                        respObj["cacheResult"] = cacheResult;
                        break;
                    }
                    return(new ContentResult()
                        {
                            Content = respObj.ToString(Formatting.None),
                            ContentType = "application/json",
                            StatusCode = 200
                        });
                }

                return(BadRequest(sendResult.response));
            }
            }
        }
Пример #29
0
        private async Task SendRawTransaction(TimestampDao timestamp, IWeb3 web3, string secretKey, double estimateGasPrice, EthSettings ethSettings)
        {
            if (!Enum.TryParse(ethSettings.Network, true, out Chain networkChain))
            {
                networkChain = Chain.MainNet;
                _logger.Warning($"Unable to parse '{ethSettings.Network}' to type '{typeof(Chain)}', so setting default to '{networkChain}'.");
            }

            bool proofVerified = _ethHelper.VerifyStamp(timestamp);

            if (!proofVerified)
            {
                var message = $"Unable to verify the signature '{timestamp.Signature}'.";
                _logger.Warning(message);
                throw new TimestampException(message);
            }

            string proofStr = JsonConvert.SerializeObject(
                new
            {
                file      = timestamp.FileName,
                hash      = timestamp.FileHash,
                publicKey = timestamp.PublicKey,
                signature = timestamp.Signature
            });

            var txData = HexStringUTF8ConvertorExtensions.ToHexUTF8(proofStr);

            var fromAddress = web3.TransactionManager.Account.Address;
            var futureNonce = await web3.TransactionManager.Account.NonceService.GetNextNonceAsync();

            _logger.Information($"Signed transaction on chain: {networkChain}, To: {ethSettings.ToAddress}, Nonce: {futureNonce}, GasPrice: {estimateGasPrice}, From Address :{fromAddress}");

            var offlineTransactionSigner = new TransactionSigner();
            var encoded = offlineTransactionSigner.SignTransaction(
                secretKey,
                networkChain,
                ethSettings.ToAddress,
                Web3.Convert.ToWei(0, UnitConversion.EthUnit.Gwei),
                futureNonce,
                Web3.Convert.ToWei(estimateGasPrice, UnitConversion.EthUnit.Gwei),
                new BigInteger(100000),
                txData);

            var verified = offlineTransactionSigner.VerifyTransaction(encoded);

            if (!verified)
            {
                var message = $"Unable to verify the transaction for data '{txData}'.";
                _logger.Error(message);
                throw new TimestampException(message);
            }

            try
            {
                var txId = await web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + encoded);

                timestamp.Address       = fromAddress;
                timestamp.Nonce         = (long)futureNonce.Value;
                timestamp.TransactionId = txId;
                timestamp.Network       = networkChain.ToString();
                timestamp.BlockNumber   = -1;

                if (string.IsNullOrWhiteSpace(txId))
                {
                    timestamp.Status = TimestampState.Failed;
                    var message = $"Transaction failed for an user '{timestamp.UserId}' with file name '{timestamp.FileName}'.";
                    _logger.Error(message);
                }
            }
            catch (RpcResponseException ex)
            {
                await web3.TransactionManager.Account.NonceService.ResetNonce();

                if (ex.Message.Contains("nonce too low", StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new RpcClientNonceException(ex.Message);
                }
                else if (ex.Message.Contains("transaction underpriced", StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new RpcClientUnderpricedException(ex.Message);
                }

                throw;
            }
        }
Пример #30
0
        public void Test_Tx_Building()
        {
            var signer  = new TransactionSigner();
            var keyPair = new EcdsaKeyPair("0xD95D6DB65F3E2223703C5D8E205D98E3E6B470F067B0F94F6C6BF73D4301CE48"
                                           .HexToBytes().ToPrivateKey());

            var tx = new Transaction
            {
                To       = "0xB8CD3195faf7da8a87A2816B9b4bBA2A19D25dAb".HexToUInt160(),
                From     = keyPair.PublicKey.GetAddress(),
                GasPrice = (ulong)Money.Parse("0.0000001").ToWei(),
                GasLimit = 100000000,
                Nonce    = 0,
                Value    = Money.Parse("20.0").ToUInt256()
            };

            Console.WriteLine($"Tx: from: {tx.From.ToHex()}, to: {tx.To.ToHex()}");

            // using old chain id
            // this is correct RLP of unsigned ethereum tx with chain id 25, check at https://toolkit.abdk.consulting/ethereum#transaction
            var expectedRawHash =
                "0xef8085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d0000080198080"
                .HexToBytes()
                .Keccak();

            Assert.AreEqual(expectedRawHash, tx.RawHash(false));

            // this is correct RLP of signed ethereum tx with chain id 25, check at https://toolkit.abdk.consulting/ethereum#transaction
            // signature is deterministic in compliance with https://tools.ietf.org/html/rfc6979
            var expectedFullHash =
                "0xf86f8085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d000008055a0c763aabd0587adb01786db24eac39c76a22bfcf97d19ad07f3b64ddd2294bdeba04710bc793cd49e4a957cc4babec18c27eabd8c873267b1fdb4943f16de22321f"
                .HexToBytes()
                .Keccak();
            var receipt = signer.Sign(tx, keyPair, false);

            Assert.AreEqual(
                expectedFullHash,
                receipt.Hash
                );
            var pubKey = receipt.RecoverPublicKey(false);

            Assert.AreEqual(receipt.Transaction.From.ToHex(), pubKey.GetAddress().ToHex());

            // using new chain id
            // this is correct RLP of unsigned ethereum tx with chain id 225, check at https://toolkit.abdk.consulting/ethereum#transaction
            expectedRawHash =
                "0xf08085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d000008081e18080"
                .HexToBytes()
                .Keccak();
            Assert.AreEqual(expectedRawHash, tx.RawHash(true));

            // this is correct RLP of signed ethereum tx with chain id 225, check at https://toolkit.abdk.consulting/ethereum#transaction
            // signature is deterministic in compliance with https://tools.ietf.org/html/rfc6979
            expectedFullHash =
                "0xf8718085174876e8008405f5e10094b8cd3195faf7da8a87a2816b9b4bba2a19d25dab8901158e460913d00000808201e5a07daf59f5e3223da3732ff0f0ffc464c533a881245fe00d09573c792f8a5f055aa067da9775fd1253f05215f961a019b619cc4d2aa8e2ae6c29c8232152f6692c24"
                .HexToBytes()
                .Keccak();
            receipt = signer.Sign(tx, keyPair, true);
            Assert.AreEqual(
                expectedFullHash,
                receipt.Hash
                );
            pubKey = receipt.RecoverPublicKey(true);
            Assert.AreEqual(receipt.Transaction.From.ToHex(), pubKey.GetAddress().ToHex());
        }