public static async Task Verify([QueueTrigger("verify")] string msg, ILogger log)
        {
            if (String.IsNullOrWhiteSpace(msg))
            {
                log.LogError("Empty request received.");
            }

            var parts = msg.Split(",");

            if (parts.Length != 2)
            {
                log.LogError("Invalid request received.");
            }

            var daemonURL        = ConfigurationProvider.GetSetting("DaemonURL");
            var daemonCredential = ConfigurationProvider.GetSetting("DaemonCredential");
            var client           = new Web3(url: daemonURL,
                                            authenticationHeader: new AuthenticationHeaderValue("basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(daemonCredential))));
            var table       = CloudStorage.GetTable <Transaction>();
            var transaction = await table.RetrieveAsync <Transaction>(parts[0], parts[1]);

            var receipt = await client.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(transaction.RowKey);

            if (receipt != null && receipt.Status.Value == 1)
            {
                if (receipt.Status.Value == 1)
                {
                    log.LogInformation("Transaction {0} has been verified in success state.", transaction.RowKey);
                    transaction.Confirmed = true;
                    await table.ReplaceAsync(new[] { transaction });
                }
                else
                {
                    var errormsg = $"Transaction {transaction.RowKey} has not yet been verified.";
                    log.LogInformation(errormsg);
                    throw new ApplicationException(errormsg);
                }
            }
        }
        public static async Task Distribute([BlobTrigger("airdrop/{name}")] Stream myBlob, string name, ILogger log)
        {
            //reads distribution addresses and amount line by line from the CSV file input
            var distributions = ReadLines(myBlob, Encoding.UTF8);

            var requests = new List <AirdropRequest>();

            foreach (var distribution in distributions)
            {
                //ignores any empty line
                if (String.IsNullOrWhiteSpace(distribution))
                {
                    continue;
                }

                //treats the first parts of lines seperated by comma as distribution addresses, the second as amount
                var parts = distribution.Split(',');
                if (parts.Length != 4 ||
                    !parts[0].Trim().StartsWith("0x") ||
                    !Double.TryParse(parts[1], out var amount) ||
                    !parts[2].Trim().StartsWith("0x") ||
                    parts[3].Trim().StartsWith("0x"))
                {
                    log.LogDebug("Invalid distribution found: {0}", distribution);
                    continue;
                }
                requests.Add(new AirdropRequest
                {
                    Amount    = amount,
                    Contract  = parts[2].Trim(),
                    From      = parts[3].Trim(),
                    To        = parts[0].Trim(),
                    Reference = name
                });
            }


            var daemonURL        = ConfigurationProvider.GetSetting("DaemonURL");
            var daemonCredential = ConfigurationProvider.GetSetting("DaemonCredential");

            var froms  = requests.GroupBy(r => r.From).Select(g => g.Key).Distinct();
            var nonces = new Dictionary <string, long>();

            foreach (var from in froms)
            {
                var account = new Account(from);
                var client  = new Web3(new Account(from),
                                       url: daemonURL,
                                       authenticationHeader: new AuthenticationHeaderValue("basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(daemonCredential))));
                var nonce = await client.Eth.Transactions.GetTransactionCount.SendRequestAsync(account.Address);

                nonces.Add(from, (long)nonce.Value);
            }

            var queue = CloudStorage.GetQueue("airdrop");

            foreach (var request in requests)
            {
                request.Nonce = nonces[request.From];
                var msg = JsonConvert.SerializeObject(request);
                await queue.AddMessageAsync(new CloudQueueMessage(msg));

                nonces[request.From] = request.Nonce + 1;
            }
        }
        public static async Task Airdrop([QueueTrigger("airdrop")] string msg, ILogger log)
        {
            var request = JsonConvert.DeserializeObject <AirdropRequest>(msg);

            var daemonURL        = ConfigurationProvider.GetSetting("DaemonURL");
            var daemonCredential = ConfigurationProvider.GetSetting("DaemonCredential");

            //the real transactional amount needs to be multiplied by the decimals of Relex Token
            var amountInWei = request.Amount * (long)Math.Pow(10, ERC20Decimals);

            //initialize an Ethereum RPC client and build a standard ERC20 contract for use to interact with
            var account = new Account(request.From);

            var client = new Web3(account,
                                  url: daemonURL,
                                  authenticationHeader: new AuthenticationHeaderValue("basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(daemonCredential))));

            //builds and sends token transfering request
            //standard ERC20 tokens can be transfered by calling the 'transfer' method defined in their contract
            var transferHandler = client.Eth.GetContractTransactionHandler <TransferFunction>();
            var transfer        = new TransferFunction()
            {
                To          = request.To,
                TokenAmount = new BigInteger(amountInWei),
                Nonce       = request.Nonce
            };

            log.LogInformation($"Sending {request.Amount} tokens({request.Contract}) to {request.To}... ");

            await transferHandler.SendRequestAsync(request.Contract, transfer);

            var receipt = await transferHandler.SendRequestAndWaitForReceiptAsync(request.Contract, transfer);

            if (receipt == null || (receipt.HasErrors().HasValue&& receipt.HasErrors().Value))
            {
                log.LogError("Failed.");
                throw new ApplicationException("Failed in processing airdrop request.");
            }
            else if (receipt.HasErrors().HasValue&& receipt.HasErrors().Value)
            {
                log.LogError($"Failed with status code: {(int)receipt.Status.Value}");
                var errormsg = receipt.Logs.ToString();
                log.LogError(errormsg);
                throw new ApplicationException(errormsg);
            }
            else
            {
                var transaction = new Transaction
                {
                    Amount       = request.Amount,
                    Confirmed    = false,
                    Contract     = request.Contract,
                    Creation     = DateTimeOffset.UtcNow,
                    From         = request.From,
                    PartitionKey = request.To,
                    RowKey       = receipt.TransactionHash,
                    Reference    = request.Reference,
                    Gas          = (int)receipt.GasUsed.Value
                };
                log.LogInformation($"Done. Transaction hash: {receipt.TransactionHash}.");
                await CloudStorage.GetTable <Transaction>().InsertAsync(new[] { transaction });

                await CloudStorage.GetQueue("verify").AddMessageAsync(new CloudQueueMessage($"{transaction.PartitionKey},{transaction.RowKey}"));
            }
        }