public async Task <APIResultCodes> SendAsync(decimal Amount, string destAccount, string ticker = LyraGlobal.OFFICIALTICKERCODE) { if (Amount <= 0) { throw new Exception("Amount must > 0"); } TransactionBlock previousBlock = await GetLatestBlockAsync(); if (previousBlock == null) { throw new Exception("No balance"); } var blockresult = await _node.GetLastServiceBlockAsync(); if (blockresult.ResultCode != APIResultCodes.Success) { return(blockresult.ResultCode); } ServiceBlock lastServiceBlock = blockresult.GetBlock() as ServiceBlock; //long atomicamount = (long)(Amount * (decimal)Math.Pow(10, precision)); var balance_change = Amount; //var transaction = new TransactionInfo() { TokenCode = ticker, Amount = atomicamount }; var fee = lastServiceBlock.TransferFee; if (ticker == LyraGlobal.OFFICIALTICKERCODE) { balance_change += fee; } // see if we have enough tokens if (previousBlock.Balances[ticker] < balance_change.ToBalanceLong()) { return(APIResultCodes.InsufficientFunds); //throw new Exception("Insufficient funds"); } // see if we have enough LYR to pay the transfer fee if (ticker != LyraGlobal.OFFICIALTICKERCODE) { if (!previousBlock.Balances.ContainsKey(LyraGlobal.OFFICIALTICKERCODE) || previousBlock.Balances[LyraGlobal.OFFICIALTICKERCODE] < fee.ToBalanceLong()) { //throw new Exception("Insufficient funds to pay transfer fee"); return(APIResultCodes.InsufficientFunds); } } SendTransferBlock sendBlock; sendBlock = new SendTransferBlock() { AccountID = _accountId, VoteFor = previousBlock.VoteFor, ServiceHash = lastServiceBlock.Hash, DestinationAccountId = destAccount, Balances = new Dictionary <string, long>(), //PaymentID = string.Empty, Fee = fee, FeeCode = LyraGlobal.OFFICIALTICKERCODE, FeeType = fee == 0m ? AuthorizationFeeTypes.NoFee : AuthorizationFeeTypes.Regular }; sendBlock.Balances.Add(ticker, previousBlock.Balances[ticker] - balance_change.ToBalanceLong()); //sendBlock.Transaction = transaction; // for customer tokens, we pay fee in LYR (unless they are accepted by authorizers as a fee - TO DO) if (ticker != LyraGlobal.OFFICIALTICKERCODE) { sendBlock.Balances.Add(LyraGlobal.OFFICIALTICKERCODE, previousBlock.Balances[LyraGlobal.OFFICIALTICKERCODE] - fee.ToBalanceLong()); } // transfer unchanged token balances from the previous block foreach (var balance in previousBlock.Balances) { if (!(sendBlock.Balances.ContainsKey(balance.Key))) { sendBlock.Balances.Add(balance.Key, balance.Value); } } await sendBlock.InitializeBlockAsync(previousBlock, _signer); if (!sendBlock.ValidateTransaction(previousBlock)) { return(APIResultCodes.SendTransactionValidationFailed); //throw new Exception("ValidateTransaction failed"); } //sendBlock.Signature = Signatures.GetSignature(PrivateKey, sendBlock.Hash); AuthorizationAPIResult result; //var stopwatch = Stopwatch.StartNew(); result = await _trans.SendTransferAsync(sendBlock); //stopwatch.Stop(); //PrintConLine($"_node.SendTransfer: {stopwatch.ElapsedMilliseconds} ms."); if (result.ResultCode == APIResultCodes.Success) { LastBlock = sendBlock; } else { LastBlock = null; } return(result.ResultCode); }
public async Task <BlockAPIResult> GetLastServiceBlockAsync() { // always response to query. node bootstrap need this api. //if (! await CheckServiceStatusAsync()) return null; return(await _node.GetLastServiceBlockAsync()); }