public ColoredEntry(uint index, AssetMoney asset) { if(asset == null) throw new ArgumentNullException("asset"); Index = index; Asset = asset; }
private async Task TransferOneDirection(TransactionBuilder builder, TransactionBuildContext context, BitcoinAddress @from, decimal amount, IAsset asset, BitcoinAddress to, bool addDust = true, bool sendDust = false) { var fromStr = from.ToString(); if (OpenAssetsHelper.IsBitcoin(asset.Id)) { var coins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(fromStr)).ToList(); var balance = coins.Cast <Coin>().Select(o => o.Amount).DefaultIfEmpty().Sum(o => o?.ToDecimal(MoneyUnit.BTC) ?? 0); if (sendDust && balance > amount && balance - amount < new TxOut(Money.Zero, from).GetDustThreshold(builder.StandardTransactionPolicy.MinRelayTxFee).ToDecimal(MoneyUnit.BTC)) { amount = balance; } await _transactionBuildHelper.SendWithChange(builder, context, coins, to, new Money(amount, MoneyUnit.BTC), from, addDust); } else { var assetIdObj = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId; var assetAmount = new AssetMoney(assetIdObj, amount, asset.MultiplierPower); var coins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(fromStr, assetIdObj)).ToList(); _transactionBuildHelper.SendAssetWithChange(builder, context, coins, to, assetAmount, @from); } }
public async Task Monitoring() { var currentBlock = await _settingsRepository.Get <int>(Constants.ProcessingBlockSetting); if (currentBlock == 0) { currentBlock = await _rpcBitcoinClient.GetBlockCount() - 1; } var dbCommitments = (await _commitmentRepository.GetMonitoringCommitments()).GroupBy(o => o.LockedAddress).ToDictionary(o => o.Key, o => o); do { var block = await _qBitNinjaApiCaller.GetBlock(currentBlock); if (block == null) { break; } foreach (var transaction in block.Block.Transactions) { var marker = transaction.GetColoredMarker(); foreach (var transactionOutput in transaction.Outputs.AsIndexedOutputs()) { var address = transactionOutput.TxOut.ScriptPubKey.GetDestinationAddress(_connectionParams.Network)?.ToString(); if (address != null && dbCommitments.ContainsKey(address)) { var commitments = dbCommitments[address].OrderByDescending(o => o.CreateDt).ToList(); ICoin coin = new Coin(transaction, transactionOutput.TxOut).ToScriptCoin(commitments[0].LockedScript.ToScript()); decimal amount; if (marker == null) { amount = transactionOutput.TxOut.Value.ToDecimal(MoneyUnit.BTC); } else { var asset = await _assetRepository.GetAssetById(commitments[0].AssetId); var assetMoney = new AssetMoney(new BitcoinAssetId(asset.BlockChainAssetId).AssetId, marker.Quantities[transactionOutput.N - 1]); coin = ((Coin)coin).ToColoredCoin(assetMoney); amount = assetMoney.ToDecimal(asset.MultiplierPower); } var commitment = commitments.FirstOrDefault(o => o.Type == CommitmentType.Hub && o.HubAmount == amount || o.Type == CommitmentType.Client && o.ClientAmount == amount); if (commitment != null) { await ProcessBroadcastedCommitment(commitment, coin); } } } } currentBlock++; await _settingsRepository.Set(Constants.ProcessingBlockSetting, currentBlock); } while (true); }
public void AssetMoneyLessThan() { AssetId assetId = new AssetId("8f316d9a09"); AssetMoney smallAssetMoney = new AssetMoney(assetId, 2); AssetMoney largeAssetMoney = new AssetMoney(assetId, 5); Assert.True(smallAssetMoney < largeAssetMoney); Assert.False(largeAssetMoney < smallAssetMoney); }
public void AssetMoneyToStringTest() { AssetId assetId = new AssetId("8f316d9a09"); AssetMoney assetMoney = new AssetMoney(assetId, 1); String actual = assetMoney.ToString(); Assert.Equal("1-8f316d9a09", actual); }
public void AssetMoneyMultiply() { AssetId assetId = new AssetId("8f316d9a09"); AssetMoney assetMoney = new AssetMoney(assetId, 2); AssetMoney actual = assetMoney * 2; Assert.Equal(4, actual.Quantity); actual = 2 * assetMoney; Assert.Equal(4, actual.Quantity); }
public void CanSplitMoneyBag() { var gold = new AssetId(new Key()); var bag = new MoneyBag(); bag += Money.Coins(12); bag += new AssetMoney(gold, 10); MoneyBag[] splitted = bag.Split(12).ToArray(); Assert.Equal(Money.Coins(1.0m), splitted[0].GetAmount(null)); Assert.Equal(new AssetMoney(gold, 1), splitted[0].GetAmount(gold)); Assert.Equal(new AssetMoney(gold, 0), splitted[11].GetAmount(gold)); }
private void CanSplitAssetMoneyCore(AssetId asset, long amount, int parts) { AssetMoney money = new AssetMoney(asset, amount); var splitted = money.Split(parts).ToArray(); Assert.True(splitted.Length == parts); Assert.True(splitted.Sum(asset) == money); var groups = splitted.Select(s => s.Quantity).GroupBy(o => o); var differentValues = groups.Count(); Assert.True(differentValues == 1 || differentValues == 2); }
public Task <CreateTransactionResponse> GetDestroyTransaction(BitcoinAddress bitcoinAddres, decimal modelAmount, IAsset asset, Guid transactionId) { return(Retry.Try(async() => { var context = new TransactionBuildContext(_connectionParams.Network, _pregeneratedOutputsQueueFactory); return await context.Build(async() => { var builder = new TransactionBuilder(); var assetId = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId; var coins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(bitcoinAddres.ToString(), assetId)).ToList(); builder.SetChange(bitcoinAddres, ChangeType.Colored); builder.AddCoins(coins); var assetMoney = new AssetMoney(assetId, modelAmount, asset.MultiplierPower); var changeAddress = BitcoinAddress.Create(_baseSettings.ChangeAddress, _connectionParams.Network); _transactionBuildHelper.SendAssetWithChange(builder, context, coins, changeAddress, assetMoney, bitcoinAddres); await _transactionBuildHelper.AddFee(builder, context); var tx = builder.BuildTransaction(true); uint markerPosition; var colorMarker = ColorMarker.Get(tx, out markerPosition); for (var i = 0; i < colorMarker.Quantities.Length; i++) { if ((long)colorMarker.Quantities[i] == assetMoney.Quantity && tx.Outputs[i + 1].ScriptPubKey.GetDestinationAddress(_connectionParams.Network) == changeAddress) { colorMarker.Quantities[i] = 0; break; } } tx.Outputs[markerPosition].ScriptPubKey = colorMarker.GetScript(); await SaveSpentOutputs(transactionId, tx); await _signRequestRepository.InsertTransactionId(transactionId); await SaveNewOutputs(transactionId, tx, context); return new CreateTransactionResponse(tx.ToHex(), transactionId); }); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log)); }
public AssetCoin(AssetMoney assetMoney, ICoin innerCoin) { if (assetMoney == null) { throw new ArgumentNullException(nameof(assetMoney)); } if (innerCoin == null) { throw new ArgumentNullException(nameof(innerCoin)); } Money = assetMoney; this.innerCoin = innerCoin; }
private Task GenerateColorOutputs(string assetId) { return(Retry.Try(async() => { var asset = await _assetRepostory.GetItemAsync(assetId); var setting = await GetAssetSetting(assetId); var hotWallet = OpenAssetsHelper.ParseAddress(setting.HotWallet); var assetIdObj = new BitcoinAssetId(asset.BlockChainAssetId).AssetId; var outputs = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.HotWallet, assetIdObj, 0, false); var balance = outputs.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount); var outputSize = new AssetMoney(assetIdObj, setting.OutputSize, asset.MultiplierPower); var changeBalance = new AssetMoney(assetIdObj); if (setting.ChangeWallet != setting.HotWallet && !string.IsNullOrEmpty(setting.ChangeWallet)) { var changeOutputs = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.ChangeWallet, assetIdObj, 0, false); changeBalance = changeOutputs.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount); } if ((balance + changeBalance).ToDecimal(asset.MultiplierPower) < setting.MinBalance) { await SendBalanceNotifications(assetId, setting.HotWallet, setting.MinBalance); } var existingCoinsCount = outputs.Count(o => o.Amount <= outputSize && o.Amount.Quantity > outputSize.Quantity / 2); if (existingCoinsCount > setting.MinOutputsCount) { return; } var generateCnt = setting.MaxOutputsCount - existingCoinsCount; var coins = outputs.Where(o => o.Amount > outputSize * 2).ToList(); balance = coins.Aggregate(new AssetMoney(assetIdObj, 0), (accum, coin) => accum + coin.Amount); generateCnt = Math.Min(generateCnt, (int)(balance.Quantity / outputSize.Quantity)); if (generateCnt == 0) { return; } await GenerateOutputs(generateCnt, coins, hotWallet, outputSize, asset, setting); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _logger)); }
private ICoin FindCoin(Transaction tr, string multisig, string walletRedeemScript, decimal amount, IAsset asset) { if (OpenAssetsHelper.IsBitcoin(asset.Id)) { var money = new Money(amount, MoneyUnit.BTC); return(tr.Outputs.AsCoins().FirstOrDefault(o => o.Amount == money && o.ScriptPubKey.GetDestinationAddress(_connectionParams.Network).ToString() == multisig)); } var assetMoney = new AssetMoney(new BitcoinAssetId(asset.BlockChainAssetId), amount, asset.MultiplierPower); uint markerPosition; var marker = ColorMarker.Get(tr, out markerPosition); var found = tr.Outputs.AsIndexedOutputs() .FirstOrDefault(o => o.TxOut.ScriptPubKey.GetDestinationAddress(_connectionParams.Network)?.ToString() == multisig && o.N > markerPosition && marker.Quantities[o.N - markerPosition - 1] == (ulong)assetMoney.Quantity); return(found?.ToCoin().ToScriptCoin(new Script(walletRedeemScript)).ToColoredCoin(assetMoney)); }
private async Task <decimal> SendToMultisig(BitcoinAddress @from, BitcoinAddress toMultisig, IAsset assetEntity, TransactionBuilder builder, TransactionBuildContext context, decimal amount) { if (OpenAssetsHelper.IsBitcoin(assetEntity.Id)) { Money sendAmount; var unspentOutputs = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(from.ToString())).ToList(); if (amount < 0) { sendAmount = unspentOutputs.OfType <Coin>().DefaultIfEmpty().Sum(o => o.Amount); } else { sendAmount = Money.FromUnit(amount, MoneyUnit.BTC); } if (sendAmount > 0) { _transactionBuildHelper.SendWithChange(builder, context, unspentOutputs, toMultisig, sendAmount, from); } return(sendAmount.ToDecimal(MoneyUnit.BTC)); } else { var asset = new BitcoinAssetId(assetEntity.BlockChainAssetId, _connectionParams.Network).AssetId; long sendAmount; var unspentOutputs = (await _bitcoinOutputsService.GetColoredUnspentOutputs(from.ToString(), asset)).ToList(); if (amount < 0) { sendAmount = unspentOutputs.Sum(o => o.Amount.Quantity); } else { sendAmount = new AssetMoney(asset, amount, assetEntity.MultiplierPower).Quantity; } if (sendAmount > 0) { _transactionBuildHelper.SendAssetWithChange(builder, context, unspentOutputs, toMultisig, new AssetMoney(asset, sendAmount), @from); } return(new AssetMoney(asset, sendAmount).ToDecimal(assetEntity.MultiplierPower)); } }
public void CanSplitAssetMoney() { var gold = new AssetId(new Key()); CanSplitAssetMoneyCore(gold, 1234, 3); CanSplitAssetMoneyCore(gold, 1234, 2); CanSplitAssetMoneyCore(gold, 1234, 10); CanSplitAssetMoneyCore(gold, 1, 3); Assert.Throws <ArgumentOutOfRangeException>(() => CanSplitAssetMoneyCore(gold, 1000, 0)); CanSplitAssetMoneyCore(gold, 0, 10); AssetMoney[] result = new AssetMoney(gold, 20).Split(3).ToArray(); Assert.True(result[0].Quantity == 7); Assert.True(result[1].Quantity == 7); Assert.True(result[2].Quantity == 6); Assert.True(result[0].Id == gold); }
public Task <CreateTransactionResponse> GetTransferAllTransaction(BitcoinAddress @from, BitcoinAddress to, Guid transactionId) { return(Retry.Try(async() => { var context = new TransactionBuildContext(_connectionParams.Network, _pregeneratedOutputsQueueFactory); return await context.Build(async() => { var builder = new TransactionBuilder(); var uncoloredCoins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(from.ToString())).ToList(); var coloredCoins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(from.ToString())).ToList(); if (uncoloredCoins.Count == 0 && coloredCoins.Count == 0) { throw new BackendException("Address has no unspent outputs", ErrorCode.NoCoinsFound); } if (uncoloredCoins.Count > 0) { _transactionBuildHelper.SendWithChange(builder, context, uncoloredCoins, to, uncoloredCoins.Sum(o => o.TxOut.Value), from); } foreach (var assetGroup in coloredCoins.GroupBy(o => o.AssetId)) { var sum = new AssetMoney(assetGroup.Key); foreach (var coloredCoin in assetGroup) { sum += coloredCoin.Amount; } _transactionBuildHelper.SendAssetWithChange(builder, context, assetGroup.ToList(), to, sum, from); } await _transactionBuildHelper.AddFee(builder, context); var buildedTransaction = builder.BuildTransaction(true); await SaveSpentOutputs(transactionId, buildedTransaction); await _signRequestRepository.InsertTransactionId(transactionId); await SaveNewOutputs(transactionId, buildedTransaction, context); return new CreateTransactionResponse(buildedTransaction.ToHex(), transactionId); }); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log)); }
public void SendAssetWithChange(TransactionBuilder builder, TransactionBuildContext context, List <ColoredCoin> coins, IDestination destination, AssetMoney amount, IDestination changeDestination) { if (amount.Quantity <= 0) { throw new BackendException("Amount can't be less or equal to zero", ErrorCode.BadInputParameter); } Action throwError = () => { throw new BackendException($"The sum of total applicable outputs is less than the required: {amount.Quantity} {amount.Id}.", ErrorCode.NotEnoughAssetAvailable); }; var selectedCoins = OpenAssetsHelper.CoinSelect(coins, amount); if (selectedCoins == null) { throwError(); } var orderedCounts = selectedCoins.Cast <ColoredCoin>().OrderBy(o => o.Amount).ToList(); var sendAmount = new AssetMoney(amount.Id); var cnt = 0; while (sendAmount < amount && cnt < orderedCounts.Count) { sendAmount += orderedCounts[cnt].Amount; cnt++; } if (sendAmount < amount) { throwError(); } builder.AddCoins(orderedCounts.Take(cnt)); context.AddCoins(orderedCounts.Take(cnt)); builder.SendAsset(destination, amount); if ((sendAmount - amount).Quantity > 0) { builder.SendAsset(changeDestination, sendAmount - amount); } }
public void ReadWrite(BitcoinStream stream) { stream.ReadWriteAsVarInt(ref _Index); if(stream.Serializing) { byte[] assetId = Asset.Id.ToBytes(); stream.ReadWrite(ref assetId); long quantity = Asset.Quantity; stream.ReadWrite(ref quantity); } else { byte[] assetId = new byte[20]; stream.ReadWrite(ref assetId); long quantity = 0; stream.ReadWrite(ref quantity); Asset = new AssetMoney(new AssetId(assetId), quantity); } }
private async Task TransferOneDirection(TransactionBuilder builder, TransactionBuildContext context, BitcoinAddress @from, decimal amount, IAsset asset, BitcoinAddress to) { var fromStr = from.ToString(); if (OpenAssetsHelper.IsBitcoin(asset.Id)) { var coins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(fromStr)).ToList(); _transactionBuildHelper.SendWithChange(builder, context, coins, to, new Money(amount, MoneyUnit.BTC), from); } else { var assetIdObj = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId; var assetAmount = new AssetMoney(assetIdObj, amount, asset.MultiplierPower); var coins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(fromStr, assetIdObj)).ToList(); _transactionBuildHelper.SendAssetWithChange(builder, context, coins, to, assetAmount, @from); } }
public static void DestroyColorCoin(Transaction tr, AssetMoney money, BitcoinAddress destination, Network network) { if (money == null || money.Quantity <= 0) { return; } uint markerPosition; var colorMarker = ColorMarker.Get(tr, out markerPosition); for (var i = 0; i < colorMarker.Quantities.Length; i++) { if ((long)colorMarker.Quantities[i] == money.Quantity && tr.Outputs[i + 1].ScriptPubKey.GetDestinationAddress(network) == destination) { colorMarker.Quantities[i] = 0; break; } } tr.Outputs[markerPosition].ScriptPubKey = colorMarker.GetScript(); }
public Task <CreateTransactionResponse> GetDestroyTransaction(BitcoinAddress bitcoinAddres, decimal modelAmount, IAsset asset, Guid transactionId) { return(Retry.Try(async() => { var context = _transactionBuildContextFactory.Create(_connectionParams.Network); return await context.Build(async() => { var builder = new TransactionBuilder(); var assetId = new BitcoinAssetId(asset.BlockChainAssetId, _connectionParams.Network).AssetId; var coins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(bitcoinAddres.ToString(), assetId)).ToList(); builder.SetChange(bitcoinAddres, ChangeType.Colored); builder.AddCoins(coins); var assetMoney = new AssetMoney(assetId, modelAmount, asset.MultiplierPower); var changeAddress = BitcoinAddress.Create(_baseSettings.ChangeAddress, _connectionParams.Network); _transactionBuildHelper.SendAssetWithChange(builder, context, coins, changeAddress, assetMoney, bitcoinAddres); await _transactionBuildHelper.AddFee(builder, context); var tx = builder.BuildTransaction(true); OpenAssetsHelper.DestroyColorCoin(tx, assetMoney, changeAddress, _connectionParams.Network); await _spentOutputService.SaveSpentOutputs(transactionId, tx); await SaveNewOutputs(transactionId, tx, context); return new CreateTransactionResponse(tx.ToHex(), transactionId); }); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log)); }
public ColoredCoin(AssetMoney asset, Coin bearer) { this.Amount = asset; this.Bearer = bearer; }
public TransactionBuilder IssueAsset(Script scriptPubKey, AssetMoney asset) { AssertOpReturn("Colored Coin"); if(_IssuedAsset == null) _IssuedAsset = asset.Id; else if(_IssuedAsset != asset.Id) throw new InvalidOperationException("You can issue only one asset type in a transaction"); CurrentGroup.IssuanceBuilders.Add(ctx => { var marker = ctx.GetColorMarker(true); if(ctx.IssuanceCoin == null) { var issuance = ctx.Group.Coins.Values.OfType<IssuanceCoin>().Where(i => i.AssetId == asset.Id).FirstOrDefault(); if(issuance == null) throw new InvalidOperationException("No issuance coin for emitting asset found"); ctx.IssuanceCoin = issuance; ctx.Transaction.Inputs.Insert(0, new TxIn(issuance.Outpoint)); ctx.AdditionalFees -= issuance.Bearer.Amount; if(issuance.DefinitionUrl != null) { marker.SetMetadataUrl(issuance.DefinitionUrl); } } ctx.Transaction.Outputs.Insert(0, new TxOut(GetDust(scriptPubKey), scriptPubKey)); marker.Quantities = new[] { checked((ulong)asset.Quantity) }.Concat(marker.Quantities).ToArray(); ctx.AdditionalFees += ctx.Transaction.Outputs[0].Value; return asset; }); return this; }
public void CanSplitMoneyBag() { var gold = new AssetId(new Key()); MoneyBag bag = new MoneyBag(); bag += Money.Coins(12); bag += new AssetMoney(gold, 10); var splitted = bag.Split(12).ToArray(); Assert.Equal(Money.Coins(1.0m), splitted[0].GetAmount(null)); Assert.Equal(new AssetMoney(gold, 1), splitted[0].GetAmount(gold)); Assert.Equal(new AssetMoney(gold, 0), splitted[11].GetAmount(gold)); }
public Task <CreateTransactionResponse> GetTransferAllTransaction(BitcoinAddress @from, BitcoinAddress to, Guid transactionId) { return(Retry.Try(async() => { var context = _transactionBuildContextFactory.Create(_connectionParams.Network); var channels = await _offchainService.GetCurrentChannels(from.ToString()); var assets = await _assetRepository.Values(); return await context.Build(async() => { var builder = new TransactionBuilder(); var uncoloredCoins = (await _bitcoinOutputsService.GetUncoloredUnspentOutputs(from.ToString())).ToList(); var coloredCoins = (await _bitcoinOutputsService.GetColoredUnspentOutputs(from.ToString())).ToList(); if (uncoloredCoins.Count == 0 && coloredCoins.Count == 0) { throw new BackendException("Address has no unspent outputs", ErrorCode.NoCoinsFound); } async Task <IDestination> GetChangeWallet(string asset) { var assetSetting = await _offchainService.GetAssetSetting(asset); return OpenAssetsHelper.ParseAddress(!string.IsNullOrEmpty(assetSetting.ChangeWallet) ? assetSetting.ChangeWallet : assetSetting.HotWallet); }; if (uncoloredCoins.Count > 0) { var hubAmount = Money.Zero; IDestination hubAmountAddress = null; var channel = channels.FirstOrDefault(o => o.Asset == "BTC"); if (channel != null) { hubAmount = Money.FromUnit(channel.HubAmount, MoneyUnit.BTC); hubAmountAddress = await GetChangeWallet("BTC"); } builder.AddCoins(uncoloredCoins); context.AddCoins(uncoloredCoins); builder.Send(to, uncoloredCoins.Sum(o => o.TxOut.Value) - hubAmount); if (hubAmount > 0) { builder.Send(hubAmountAddress, hubAmount); } } foreach (var assetGroup in coloredCoins.GroupBy(o => o.AssetId)) { var asset = assets.First(o => o.BlockChainAssetId == assetGroup.Key.GetWif(_connectionParams.Network).ToString()); var channel = channels.FirstOrDefault(o => o.Asset == asset.Id); var sum = new AssetMoney(assetGroup.Key); foreach (var coloredCoin in assetGroup) { sum += coloredCoin.Amount; } var hubAmount = new AssetMoney(assetGroup.Key); IDestination hubAmountAddress = null; if (channel != null) { hubAmount = new AssetMoney(assetGroup.Key, channel.HubAmount, asset.MultiplierPower); hubAmountAddress = await GetChangeWallet(asset.Id); } builder.AddCoins(assetGroup.ToList()); context.AddCoins(assetGroup.ToList()); builder.SendAsset(to, sum - hubAmount); if (hubAmount.Quantity > 0) { builder.SendAsset(hubAmountAddress, hubAmount); } } await _transactionBuildHelper.AddFee(builder, context); var buildedTransaction = builder.BuildTransaction(true); await _spentOutputService.SaveSpentOutputs(transactionId, buildedTransaction); await SaveNewOutputs(transactionId, buildedTransaction, context); foreach (var offchainChannel in channels) { await _offchainService.RemoveChannel(offchainChannel); } return new CreateTransactionResponse(buildedTransaction.ToHex(), transactionId); }); }, exception => (exception as BackendException)?.Code == ErrorCode.TransactionConcurrentInputsProblem, 3, _log)); }
public void CanSplitAssetMoney() { var gold = new AssetId(new Key()); CanSplitAssetMoneyCore(gold, 1234, 3); CanSplitAssetMoneyCore(gold, 1234, 2); CanSplitAssetMoneyCore(gold, 1234, 10); CanSplitAssetMoneyCore(gold, 1, 3); Assert.Throws<ArgumentOutOfRangeException>(() => CanSplitAssetMoneyCore(gold, 1000, 0)); CanSplitAssetMoneyCore(gold, 0, 10); var result = new AssetMoney(gold, 20).Split(3).ToArray(); Assert.True(result[0].Quantity == 7); Assert.True(result[1].Quantity == 7); Assert.True(result[2].Quantity == 6); Assert.True(result[0].Id == gold); }
public ColoredCoin ToColoredCoin(AssetMoney asset) { return new ColoredCoin(asset, this); }
public ColoredCoin(AssetMoney asset, Coin bearer) { Amount = asset; Bearer = bearer; }
private async Task GenerateIssueAllowedCoins() { foreach (var asset in await _assetRepostory.Values()) { if (OpenAssetsHelper.IsBitcoin(asset.Id) || OpenAssetsHelper.IsLkk(asset.Id) || !asset.IssueAllowed) { continue; } try { var setting = await GetAssetSetting(asset.Id); if (setting.HotWallet != setting.ChangeWallet) { continue; } var hotWallet = OpenAssetsHelper.ParseAddress(setting.HotWallet); var assetId = new BitcoinAssetId(asset.BlockChainAssetId).AssetId; var coins = await _bitcoinOutputsService.GetColoredUnspentOutputs(setting.HotWallet, assetId); var outputSize = new AssetMoney(assetId, setting.OutputSize, asset.MultiplierPower); await _logger.WriteInfoAsync("GenerateOffchainOutputsFunction", "GenerateIssueAllowedCoins", "AssetId " + asset.Id, "Start process"); var existingCoinsCount = coins.Count(o => o.Amount <= outputSize && o.Amount * 2 > outputSize); if (existingCoinsCount > setting.MinOutputsCount) { continue; } var generateCnt = setting.MaxOutputsCount - existingCoinsCount; var generated = 0; while (generated < generateCnt) { var outputsCount = Math.Min(setting.MaxOutputsCountInTx, generateCnt - generated); var context = _transactionBuildContextFactory.Create(_connectionParams.Network); await context.Build(async() => { var builder = new TransactionBuilder(); var queue = _pregeneratedOutputsQueueFactory.Create(asset.BlockChainAssetId); var coin = await queue.DequeueCoin(); try { var issueCoin = new IssuanceCoin(coin) { DefinitionUrl = new Uri(asset.DefinitionUrl) }; builder.AddCoins(issueCoin); for (var i = 0; i < outputsCount; i++) { builder.IssueAsset(hotWallet, outputSize); } context.IssueAsset(assetId); await _transactionBuildHelper.AddFee(builder, context); var tr = builder.BuildTransaction(true); await SignAndBroadcastTransaction(tr, context); return(""); } catch (Exception) { await queue.EnqueueOutputs(coin); throw; } }); generated += outputsCount; } } catch (Exception ex) { await _logger.WriteWarningAsync("GenerateOffchainOutputsFunction", "GenerateIssueAllowedCoins", "AssetId " + asset.Id, ex); } finally { await _logger.WriteInfoAsync("GenerateOffchainOutputsFunction", "GenerateIssueAllowedCoins", "AssetId " + asset.Id, "End process"); } } }
public TransactionBuilder IssueAsset(IDestination destination, AssetMoney asset) { return IssueAsset(destination.ScriptPubKey, asset); }
public ColoredCoin ToColoredCoin(AssetMoney asset) { return(new ColoredCoin(asset, this)); }
public TransactionBuilder SendAsset(Script scriptPubKey, AssetMoney asset) { if(asset.Quantity < 0) throw new ArgumentOutOfRangeException("asset", "Asset amount can't be negative"); AssertOpReturn("Colored Coin"); var builders = CurrentGroup.BuildersByAsset.TryGet(asset.Id); if(builders == null) { builders = new List<Builder>(); CurrentGroup.BuildersByAsset.Add(asset.Id, builders); builders.Add(SetColoredChange); } builders.Add(ctx => { var marker = ctx.GetColorMarker(false); var txout = ctx.Transaction.AddOutput(new TxOut(GetDust(scriptPubKey), scriptPubKey)); marker.SetQuantity(ctx.Transaction.Outputs.Count - 2, asset.Quantity); ctx.AdditionalFees += txout.Value; return asset; }); return this; }