public async Task ExtractNormalConversionDeposits_ReturnDeposits_AboveFasterThresholdAsync()
        {
            Block block = this.network.Consensus.ConsensusFactory.CreateBlock();

            BitcoinPubKeyAddress targetAddress = this.addressHelper.GetNewTargetChainPubKeyAddress();

            byte[] opReturnBytes = Encoding.UTF8.GetBytes(targetAddress.ToString());

            // Set amount to be less than the small threshold amount.
            CreateDepositTransaction(targetAddress, block, this.federationSettings.SmallDepositThresholdAmount - 1, opReturnBytes);

            byte[] ethOpReturnBytes = Encoding.UTF8.GetBytes(InterFluxOpReturnEncoder.Encode(DestinationChain.ETH, TargetETHAddress));

            // Set amount to be exactly the small threshold amount.
            CreateConversionTransaction(block, DepositValidationHelper.ConversionTransactionMinimum - 1, ethOpReturnBytes);

            // Set amount to be greater than the small threshold amount.
            CreateConversionTransaction(block, DepositValidationHelper.ConversionTransactionMinimum + 1, ethOpReturnBytes);

            int blockHeight = 12345;
            IReadOnlyList <IDeposit> extractedDeposits = await this.depositExtractor.ExtractDepositsFromBlock(block, blockHeight, this.retrievalTypeConfirmations);

            // Should only be 1, with the value just over the withdrawal fee.
            IEnumerable <IDeposit> applicable = extractedDeposits.Where(d => d.Amount > DepositValidationHelper.ConversionTransactionMinimum && d.RetrievalType == DepositRetrievalType.ConversionLarge);

            applicable.Count().Should().Be(1);
            foreach (IDeposit extractedDeposit in applicable)
            {
                Assert.True(extractedDeposit.Amount >= this.federationSettings.SmallDepositThresholdAmount);
            }
        }
        public void EncodeAndDecodeETHAddress()
        {
            string address = "0xd2390da742872294BE05dc7359D7249d7C79460E";
            string encoded = InterFluxOpReturnEncoder.Encode(DestinationChain.ETH, address);
            bool   success = InterFluxOpReturnEncoder.TryDecode(encoded, out int resultChain, out string resultAddress);

            Assert.True(success);
            Assert.Equal(DestinationChain.ETH, (DestinationChain)resultChain);
            Assert.Equal(address, resultAddress);
        }
        public MaturedBlocksProviderTests()
        {
            this.loggerFactory = Substitute.For <ILoggerFactory>();
            this.logger        = Substitute.For <ILogger>();
            this.loggerFactory.CreateLogger(null).ReturnsForAnyArgs(this.logger);
            this.conversionRequestRepository = Substitute.For <IConversionRequestRepository>();
            this.consensusManager            = Substitute.For <IConsensusManager>();
            this.network          = new CirrusRegTest();
            this.mainChainNetwork = new StraxRegTest();

            this.opReturnDataReader = Substitute.For <IOpReturnDataReader>();
            this.opReturnDataReader.TryGetTargetAddress(null, out string address).Returns(callInfo => { callInfo[1] = null; return(false); });

            this.transactionBuilder = new TestTransactionBuilder();

            this.addressHelper = new MultisigAddressHelper(this.network, this.mainChainNetwork);
            this.targetAddress = this.addressHelper.GetNewTargetChainPubKeyAddress();
            this.opReturnBytes = Encoding.UTF8.GetBytes(InterFluxOpReturnEncoder.Encode(DestinationChain.STRAX, this.targetAddress.ToString()));

            this.federatedPegSettings = Substitute.For <IFederatedPegSettings>();
            this.federatedPegSettings.MultiSigRedeemScript.Returns(this.addressHelper.PayToMultiSig);

            this.federatedPegSettings.MinimumConfirmationsSmallDeposits.Returns(5);
            this.federatedPegSettings.MinimumConfirmationsNormalDeposits.Returns(10);
            this.federatedPegSettings.MinimumConfirmationsLargeDeposits.Returns(20);

            this.federatedPegSettings.SmallDepositThresholdAmount.Returns(Money.Coins(10));
            this.federatedPegSettings.NormalDepositThresholdAmount.Returns(Money.Coins(100));

            this.consensusManager.GetBlocksAfterBlock(Arg.Any <ChainedHeader>(), MaturedBlocksProvider.MaturedBlocksBatchSize, Arg.Any <CancellationTokenSource>()).Returns(delegate(CallInfo info)
            {
                var chainedHeader = (ChainedHeader)info[0];
                if (chainedHeader == null)
                {
                    return(this.blocks.Where(x => x.ChainedHeader.Height <= this.consensusManager.Tip.Height).ToArray());
                }

                return(this.blocks.SkipWhile(x => x.ChainedHeader.Height <= chainedHeader.Height).Where(x => x.ChainedHeader.Height <= this.consensusManager.Tip.Height).ToArray());
            });

            this.retrievalTypeConfirmations = new Dictionary <DepositRetrievalType, int>
            {
                [DepositRetrievalType.Small]  = this.federatedPegSettings.MinimumConfirmationsSmallDeposits,
                [DepositRetrievalType.Normal] = this.federatedPegSettings.MinimumConfirmationsNormalDeposits,
                [DepositRetrievalType.Large]  = this.federatedPegSettings.MinimumConfirmationsLargeDeposits,
            };

            this.retrievalTypeConfirmations[DepositRetrievalType.Distribution]     = this.federatedPegSettings.MinimumConfirmationsDistributionDeposits;
            this.retrievalTypeConfirmations[DepositRetrievalType.ConversionSmall]  = this.federatedPegSettings.MinimumConfirmationsSmallDeposits;
            this.retrievalTypeConfirmations[DepositRetrievalType.ConversionNormal] = this.federatedPegSettings.MinimumConfirmationsNormalDeposits;
            this.retrievalTypeConfirmations[DepositRetrievalType.ConversionLarge]  = this.federatedPegSettings.MinimumConfirmationsLargeDeposits;
        }
        public async Task ExtractConversionDeposits_BelowAndAboveThresholdAsync()
        {
            Block block = this.network.Consensus.ConsensusFactory.CreateBlock();

            byte[] ethOpReturnBytes = Encoding.UTF8.GetBytes(InterFluxOpReturnEncoder.Encode(DestinationChain.ETH, TargetETHAddress));

            CreateConversionTransaction(block, DepositValidationHelper.ConversionTransactionMinimum - 1, ethOpReturnBytes);

            CreateConversionTransaction(block, DepositValidationHelper.ConversionTransactionMinimum + 1, ethOpReturnBytes);

            int blockHeight = 12345;
            IReadOnlyList <IDeposit> extractedDeposits = await this.depositExtractor.ExtractDepositsFromBlock(block, blockHeight, this.retrievalTypeConfirmations);

            // Should only be two, with the value just over the withdrawal fee.
            extractedDeposits.Count.Should().Be(1);
            foreach (IDeposit extractedDeposit in extractedDeposits)
            {
                Assert.True(extractedDeposit.Amount == DepositValidationHelper.ConversionTransactionMinimum + 1);
            }
        }
        public void CanEncodeAndDecode()
        {
            int    chain   = 3;
            string address = "0x51EC92A3aB8cfcA412Ea43766A9259523fC81501";

            string encoded = InterFluxOpReturnEncoder.Encode(chain, address);

            bool success = InterFluxOpReturnEncoder.TryDecode(encoded, out int resultChain, out string resultAddress);

            Assert.True(success);
            Assert.Equal(chain, resultChain);
            Assert.Equal(address, resultAddress);


            byte[] encodedBytes = Encoding.UTF8.GetBytes(encoded);
            bool   success2     = InterFluxOpReturnEncoder.TryDecode(encodedBytes, out int resultChain2, out string resultAddress2);

            Assert.True(success2);
            Assert.Equal(chain, resultChain2);
            Assert.Equal(address, resultAddress2);
        }
        public void ExtractLargeConversionDeposits_ReturnDeposits_AboveNormalThreshold()
        {
            Block block = this.network.Consensus.ConsensusFactory.CreateBlock();

            // Create the target address.
            BitcoinPubKeyAddress targetAddress = this.addressHelper.GetNewTargetChainPubKeyAddress();

            byte[] opReturnBytes = Encoding.UTF8.GetBytes(targetAddress.ToString());

            // Set amount to be less than deposit minimum
            CreateDepositTransaction(targetAddress, block, FederatedPegSettings.CrossChainTransferMinimum - 1, opReturnBytes);

            // Set amount to be less than the small threshold amount.
            CreateDepositTransaction(targetAddress, block, this.federationSettings.SmallDepositThresholdAmount - 1, opReturnBytes);

            // Set amount to be exactly the normal threshold amount.
            CreateDepositTransaction(targetAddress, block, this.federationSettings.NormalDepositThresholdAmount, opReturnBytes);

            byte[] ethOpReturnBytes = Encoding.UTF8.GetBytes(InterFluxOpReturnEncoder.Encode(DestinationChain.ETH, TargetETHAddress));

            // Set amount to be equal to the normal threshold amount.
            CreateConversionTransaction(block, this.federationSettings.NormalDepositThresholdAmount, ethOpReturnBytes);

            // Set amount to be greater than the conversion deposit minimum amount.
            CreateConversionTransaction(block, Money.Coins(DepositExtractor.ConversionTransactionMinimum + 1), ethOpReturnBytes);

            int blockHeight = 12345;
            IReadOnlyList <IDeposit> extractedDeposits = this.depositExtractor.ExtractDepositsFromBlock(block, blockHeight, new[] { DepositRetrievalType.ConversionLarge });

            // Should only be 1, with the value just over the withdrawal fee.
            extractedDeposits.Count.Should().Be(1);
            foreach (IDeposit extractedDeposit in extractedDeposits)
            {
                Assert.True(extractedDeposit.Amount > this.federationSettings.NormalDepositThresholdAmount);
                Assert.Equal(TargetETHAddress, extractedDeposit.TargetAddress);
            }
        }