public async Task <string> CreateHubCommitment(string clientPubKey, IAsset asset, decimal amount, string signedByClientChannel)
        {
            var address = await _multisigService.GetMultisig(clientPubKey);

            if (address == null)
            {
                throw new BackendException($"Client {clientPubKey} is not registered", ErrorCode.BadInputParameter);
            }

            var channel = await _offchainChannelRepository.GetChannel(address.MultisigAddress, asset.Id);

            if (channel == null)
            {
                throw new BackendException("Channel is not found", ErrorCode.ShouldOpenNewChannel);
            }

            if (amount < 0 && channel.ClientAmount < Math.Abs(amount))
            {
                throw new BackendException("Client amount in channel is low than required", ErrorCode.BadChannelAmount);
            }

            if (amount > 0 && channel.HubAmount < amount)
            {
                throw new BackendException("Hub amount in channel is low than required", ErrorCode.BadChannelAmount);
            }

            if (!TransactionComparer.CompareTransactions(channel.InitialTransaction, signedByClientChannel))
            {
                throw new BackendException("Provided signed transaction is not equal initial transaction", ErrorCode.BadTransaction);
            }

            if (!await _signatureVerifier.Verify(signedByClientChannel, clientPubKey))
            {
                throw new BackendException("Provided signed transaction is not signed by client", ErrorCode.BadTransaction);
            }

            var fullSignedChannel = await _signatureApiProvider.SignTransaction(signedByClientChannel);

            if (!_signatureVerifier.VerifyScriptSigs(fullSignedChannel))
            {
                throw new BackendException("Channel transaction is not full signed", ErrorCode.BadFullSignTransaction);
            }

            await _offchainChannelRepository.SetFullSignedTransaction(address.MultisigAddress, asset.Id, fullSignedChannel);

            var hubRevokeKey = new Key();

            var newHubAmount     = channel.HubAmount - amount;
            var newClientAmount  = channel.ClientAmount + amount;
            var commitmentResult = CreateCommitmentTransaction(address, new PubKey(address.ExchangePubKey), new PubKey(clientPubKey), hubRevokeKey.PubKey, new PubKey(clientPubKey), asset,
                                                               newHubAmount, newClientAmount, fullSignedChannel);

            await _commitmentRepository.CreateCommitment(CommitmentType.Hub, channel.ChannelId, address.MultisigAddress, asset.Id,
                                                         new BitcoinSecret(hubRevokeKey, _connectionParams.Network).ToString(), hubRevokeKey.PubKey.ToHex(),
                                                         commitmentResult.Transaction.ToHex(), newClientAmount, newHubAmount, commitmentResult.LockedAddress, commitmentResult.LockedScript);

            return(commitmentResult.Transaction.ToHex());
        }
Example #2
0
        private void ProceedSort()
        {
            var item = _repository.Categories.Item;

            TransactionComparer comparer = new TransactionComparer(_repository.Categories.Item);

            var reports = _repository.Reports.Item.Reports.ToList();

            foreach (var report in reports)
            {
                report.Transactions.Sort(comparer);
            }

            _iOutput.ShowReports(reports);
        }
Example #3
0
        public IEnumerable <Transaction> Order(BlockHeader blockHeader, IEnumerable <Transaction> transactions)
        {
            UInt256 GetPriority(Transaction tx) =>
            _priorities.TryGetValue(blockHeader, tx, out var destination)
                    ? destination.Value
                    : UInt256.Zero;

            ISet <Address>          sendersWhitelist    = _sendersWhitelist.GetItemsFromContractAtBlock(blockHeader).AsSet();
            IComparer <Transaction> transactionComparer = new TransactionComparer(
                t => sendersWhitelist.Contains(t.SenderAddress),
                GetPriority);

            // We group transactions by sender. Each group is sorted by nonce and then by priority desc, then gasprice desc, then gaslimit asc
            // transactions grouped by sender with nonce order then priority:
            // A -> N0_P3, N1_P1, N1_P0, N3_P5...
            // B -> N4_P4, N5_P3, N6_P3...
            IEnumerable <IEnumerable <Transaction> > bySenderOrdered = transactions
                                                                       .Where(tx => tx != null) // for safety
                                                                       .GroupBy(tx => tx.SenderAddress)
                                                                       .Select(g => g.OrderBy(tx => tx.Nonce).ThenBy(t => t, transactionComparer));

            return(Order(bySenderOrdered, transactionComparer));
        }
Example #4
0
        public async Task Broadcast([FromBody] BroadcastTransactionRequest model)
        {
            var signRequest = await _transactionSignRequestRepository.GetSignRequest(model.TransactionId);

            if (signRequest == null)
            {
                throw new BackendException("Transaction is not found", ErrorCode.BadTransaction);
            }

            if (signRequest.Invalidated == true)
            {
                throw new BackendException("Transaction was invalidated", ErrorCode.BadTransaction);
            }

            var initialTransaction = await _transactionBlobStorage.GetTransaction(model.TransactionId, TransactionBlobType.Initial);

            if (!TransactionComparer.CompareTransactions(initialTransaction, model.Transaction))
            {
                throw new BackendException("Signed transaction is not equals to initial transaction", ErrorCode.BadTransaction);
            }

            var transaction = new Transaction(model.Transaction);

            if (transaction.Inputs.All(o => o.ScriptSig == null || o.ScriptSig.Length == 0))
            {
                throw new BackendException("Transaction is not signed by client", ErrorCode.BadTransaction);
            }

            var fullSignedHex = signRequest.DoNotSign ? model.Transaction : await _signatureApiProvider.SignTransaction(model.Transaction);

            await _transactionBlobStorage.AddOrReplaceTransaction(model.TransactionId, TransactionBlobType.Signed, fullSignedHex);

            var fullSigned = new Transaction(fullSignedHex);

            await _broadcastService.BroadcastTransaction(model.TransactionId, fullSigned, useHandlers : false, savePaidFees : !signRequest.DoNotSign);
        }
 // Transactions can only be instantiated by type
 public Transactions(Type type)
 {
     this.type = type;
     comparer  = new TransactionComparer(type);
 }
 public async Task <ICommitment> GetCommitment(string multisig, string asset, string transactionHex)
 {
     return((await _table.GetDataAsync(o => o.Multisig == multisig && o.AssetId == asset && o.Actual)).FirstOrDefault(o => TransactionComparer.CompareTransactions(o.InitialTransaction, transactionHex)));
 }
        public async Task <string> Finalize(string clientPubKey, string hotWalletPubKey, IAsset asset, string clientRevokePubKey, string signedByClientHubCommitment)
        {
            var address = await _multisigService.GetMultisig(clientPubKey);

            if (address == null)
            {
                throw new BackendException($"Client {clientPubKey} is not registered", ErrorCode.BadInputParameter);
            }

            var channel = await _offchainChannelRepository.GetChannel(address.MultisigAddress, asset.Id);

            if (channel == null)
            {
                throw new BackendException("Channel is not found", ErrorCode.ShouldOpenNewChannel);
            }

            var hubCommitment = await _commitmentRepository.GetLastCommitment(address.MultisigAddress, asset.Id, CommitmentType.Hub);

            if (hubCommitment == null)
            {
                throw new BackendException("Commitment is not found", ErrorCode.CommitmentNotFound);
            }

            if (!TransactionComparer.CompareTransactions(signedByClientHubCommitment, hubCommitment.InitialTransaction))
            {
                throw new BackendException("Provided signed transaction is not equal initial transaction", ErrorCode.BadTransaction);
            }

            if (!await _signatureVerifier.Verify(signedByClientHubCommitment, clientPubKey, SigHash.Single | SigHash.AnyoneCanPay))
            {
                throw new BackendException("Provided signed transaction is not signed by client", ErrorCode.BadTransaction);
            }

            var fullSignedCommitment = await _signatureApiProvider.SignTransaction(signedByClientHubCommitment, SigHash.Single | SigHash.AnyoneCanPay);

            if (!_signatureVerifier.VerifyScriptSigs(fullSignedCommitment))
            {
                throw new BackendException("Transaction is not full signed", ErrorCode.BadFullSignTransaction);
            }

            await _commitmentRepository.SetFullSignedTransaction(hubCommitment.CommitmentId, address.MultisigAddress, asset.Id, fullSignedCommitment);

            var clientCommitmentResult = CreateCommitmentTransaction(address, new PubKey(clientPubKey),
                                                                     new PubKey(hotWalletPubKey), new PubKey(clientRevokePubKey), new PubKey(address.ExchangePubKey), asset,
                                                                     hubCommitment.ClientAmount, hubCommitment.HubAmount, channel.FullySignedChannel);

            var signedByHubCommitment = await _signatureApiProvider.SignTransaction(clientCommitmentResult.Transaction.ToHex(), SigHash.Single | SigHash.AnyoneCanPay);

            await _commitmentRepository.CreateCommitment(CommitmentType.Client, channel.ChannelId, address.MultisigAddress, asset.Id, null,
                                                         clientRevokePubKey, signedByHubCommitment, hubCommitment.ClientAmount, hubCommitment.HubAmount, clientCommitmentResult.LockedAddress, clientCommitmentResult.LockedScript);

            if (!channel.IsBroadcasted)
            {
                var channelTr = new Transaction(channel.FullySignedChannel);

                await _lykkeTransactionBuilderService.SaveSpentOutputs(channel.ChannelId, channelTr);

                await _rpcBitcoinClient.BroadcastTransaction(channelTr, channel.ChannelId);

                await _offchainChannelRepository.SetChannelBroadcasted(address.MultisigAddress, asset.Id);

                if (channel.PrevChannelTrnasactionId.HasValue)
                {
                    await _commitmentRepository.CloseCommitmentsOfChannel(address.MultisigAddress, asset.Id, channel.PrevChannelTrnasactionId.Value);
                }
            }

            await _offchainChannelRepository.UpdateAmounts(address.MultisigAddress, asset.Id, hubCommitment.ClientAmount, hubCommitment.HubAmount);

            return(signedByHubCommitment);
        }