internal Ledger(ContractService contractService, WalletContract contract, OperationCode operation, BitcoinPubKeyAddress utxoReceiver, BitcoinPubKeyAddress tokenReceiver = null, decimal?amount = null, string referenceCode = null) { _contract = contract; Operation = operation; TokenReceiver = tokenReceiver; TokenReceiverHash = tokenReceiver.ExtractWitnessProgram(); ReferenceCode = referenceCode; UtxoReceiver = utxoReceiver; if (operation == OperationCode.Issue && tokenReceiver == null) { TokenReceiverHash = new BitcoinPubKeyAddress(contract.OwnerPublicAddress, contractService.MainNetwork).ExtractWitnessProgram(); } if (amount < 0) { throw new InvalidOperationException("The amount cannot be negative."); } if (amount.HasValue) { Amount = amount.Value; } else if (operation != OperationCode.Issue) { throw new ArgumentNullException("Amount cannot be null if the operation is not issuance of the owner address."); } else { Amount = contract.TotalSupply; } }
public static Ledger ToLedger(this ApiTransaction transaction, WalletContract contract, ContractService service) { var ledger = new Ledger() { TxId = transaction.txid, Blockheight = transaction.blockheight, Time = new DateTime(1970, 1, 1).AddSeconds(transaction.blocktime) }; var domain = BitConverter.ToString(Encoding.Default.GetBytes("RMUTSB.AC.TH")).Replace("-", "").ToLower(); //var domain = "54534357414c4c4554"; var data = transaction.GetOP_RETURN(); try { if (data.StartsWith(domain)) { return(null); } var contractNameHex = data.Substring(0, 16); if (contract.NameHex == contractNameHex) { ledger.Operation = (OperationCode)(ushort.Parse(data.Substring(16, 4), System.Globalization.NumberStyles.HexNumber)); var publicAddress = transaction.vin.First(v => !string.IsNullOrEmpty(v.addr)).addr; var publicKey = new BitcoinPubKeyAddress(publicAddress, service.MainNetwork); ledger.TokenSenderHash = publicKey.ExtractWitnessProgram(); ledger.TokenReceiverHashHex = data.Substring(20, 40); ledger.Amount = BitConverterExtension.ToDecimal(data.Substring(60, 32).StringToByteArray()); if (data.Length > 92) { ledger.ReferenceCode = Encoding.Default.GetString(data.Substring(92).StringToByteArray()); } return(ledger); } else { return(null); } } catch (Exception e) { Debug.WriteLine(e.Message); return(null); } }
/// <summary> /// Obtain the account according to the public key. /// </summary> /// <param name="pubKeyAddress">A Bitcoin-compatible public key</param> /// <returns>An account according to the given key.</returns> public Account GetAccount(BitcoinPubKeyAddress pubKeyAddress) { var witnessProgram = pubKeyAddress.ExtractWitnessProgram(); return(GetAccount(witnessProgram)); }
/// <summary> /// A private method to process the account balance from the ledgers in local data store. /// </summary> /// <param name="reset">If true, the existing balance will be removed and process again (Optional, default is false)</param> /// <returns>None.</returns> private void UpdateBalance(bool reset = false) { var ledgers = ledger.Find(l => l.Status == ProcessStatus.NotProcessed); if (reset) { db.DropCollection($"Account-{contract.NameHex}"); ledgers = ledger.FindAll(); } foreach (var entry in ledgers) { switch (entry.Operation) { case OperationCode.Transfer: var fromAccount = account.FindOne(a => a.WitnessProgram == entry.TokenSenderHash); if (fromAccount == null) { fromAccount = new Account() { WitnessProgram = entry.TokenSenderHash }; } else if (entry.Amount < (decimal)Math.Round(Math.Pow(0.1, contract.NoOfDecimal), contract.NoOfDecimal)) { entry.Status = ProcessStatus.DustAmount; ledger.Upsert(entry); } else if (fromAccount.Balance >= entry.Amount + TransferFee) { fromAccount.Balance -= entry.Amount + TransferFee; var toAccount = account.FindOne(a => a.WitnessProgram == entry.TokenReceiverHash); if (toAccount == null) { toAccount = new Account() { WitnessProgram = entry.TokenReceiverHash }; } toAccount.Balance += entry.Amount; fromAccount.Blockheight = entry.Blockheight; toAccount.Blockheight = entry.Blockheight; account.Upsert(fromAccount); account.Upsert(toAccount); var ownerAccount = account.FindOne(a => a.WitnessProgram == ownerAddress.ExtractWitnessProgram()); if (ownerAccount == null) { ownerAccount = new Account() { WitnessProgram = entry.TokenReceiverHash }; } ownerAccount.Balance += TransferFee; ownerAccount.Blockheight = entry.Blockheight; account.Upsert(ownerAccount); account.EnsureIndex(a => a.WitnessProgram); entry.Status = ProcessStatus.Processed; ledger.Upsert(entry); } else { entry.Status = ProcessStatus.FailedIgnore; ledger.Upsert(entry); } break; case OperationCode.Burn: entry.Status = ProcessStatus.FeatureNotAvailable; ledger.Upsert(entry); break; case OperationCode.Interest: entry.Status = ProcessStatus.FeatureNotAvailable; ledger.Upsert(entry); break; case OperationCode.Issue: if (entry.TokenSenderHash.QuickCompare(ownerAddress.ExtractWitnessProgram())) { var ownerAccount = account.FindOne(a => a.WitnessProgram == ownerAddress.ExtractWitnessProgram()); if (ownerAccount == null) { ownerAccount = new Account() { WitnessProgram = entry.TokenReceiverHash }; } ownerAccount.Balance += entry.Amount; ownerAccount.Blockheight = entry.Blockheight; account.Upsert(ownerAccount); account.EnsureIndex(a => a.WitnessProgram); entry.Status = ProcessStatus.Processed; } else { entry.Status = ProcessStatus.FailedIgnore; } ledger.Upsert(entry); break; default: entry.Status = ProcessStatus.NotDefined; ledger.Upsert(entry); break; } } account.EnsureIndex(a => a.WitnessProgram); }