Exemple #1
0
        public TokenSwapper(Spook node, PhantasmaKeys swapKey, NeoAPI neoAPI, EthAPI ethAPI, EthAPI bscAPI, BigInteger minFee)
        {
            this.Node         = node;
            this.SwapKeys     = swapKey;
            this.OracleReader = Nexus.GetOracleReader();
            this.MinimumFee   = minFee;
            this.neoAPI       = neoAPI;
            this.ethAPI       = ethAPI;
            this.bscAPI       = bscAPI;

            this.Storage = new KeyStoreStorage(Nexus.CreateKeyStoreAdapter("swaps"));

            this._interopBlocks = new Dictionary <SwapPlatformChain, BigInteger>();

            foreach (var platform in Settings.Oracle.SwapPlatforms)
            {
                _interopBlocks[platform.Chain] = platform.InteropHeight;
            }

            var inProgressMap = new StorageMap(InProgressTag, this.Storage);

            Console.WriteLine($"inProgress count: {inProgressMap.Count()}");
            inProgressMap.Visit <Hash, string>((key, value) =>
            {
                if (!string.IsNullOrEmpty(value))
                {
                    Console.WriteLine($"inProgress: {key} - {value}");
                }
            });
        }
Exemple #2
0
        public TokenSwapper(Spook node, PhantasmaKeys swapKey, NeoAPI neoAPI, EthAPI ethAPI, BigInteger minFee, string[] supportedPlatforms)
        {
            this.Node         = node;
            this.SwapKeys     = swapKey;
            this.OracleReader = Nexus.GetOracleReader();
            this.MinimumFee   = minFee;
            this.neoAPI       = neoAPI;
            this.ethAPI       = ethAPI;

            this.Storage = new KeyStoreStorage(Nexus.CreateKeyStoreAdapter("swaps"));

            this.interopBlocks = new Dictionary <string, BigInteger>();

            interopBlocks[DomainSettings.PlatformName] = BigInteger.Parse(Settings.Oracle.PhantasmaInteropHeight);
            interopBlocks["neo"]      = BigInteger.Parse(Settings.Oracle.NeoInteropHeight);
            interopBlocks["ethereum"] = BigInteger.Parse(Settings.Oracle.EthInteropHeight);

            _supportedPlatforms.Add(DomainSettings.PlatformName);
            foreach (var entry in supportedPlatforms)
            {
                if (_supportedPlatforms.Contains(entry))
                {
                    throw new SwapException($"Duplicated swap platform {entry}, check config");
                }

                if (!interopBlocks.ContainsKey(entry))
                {
                    throw new SwapException($"Unknown swap platform {entry}, check config");
                }

                _supportedPlatforms.Add(entry);
            }
        }
Exemple #3
0
        public BSCInterop(TokenSwapper swapper, EthAPI ethAPI, PBigInteger interopBlockHeight, string[] contracts, uint confirmations)
            : base(swapper, BSCWallet.BSCPlatform)
        {
            string lastBlockHeight = OracleReader.GetCurrentHeight(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform);

            if (string.IsNullOrEmpty(lastBlockHeight))
            {
                OracleReader.SetCurrentHeight(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, new BigInteger(interopBlockHeight.ToSignedByteArray()).ToString());
            }

            Logger.Message($"interopHeight: {OracleReader.GetCurrentHeight(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform)}");
            Console.WriteLine("encoded bsc: " + BSCWallet.EncodeAddress("0x44E8743A6CAC3E59594C19DD462863A5AA5E06BB"));
            Console.WriteLine("encoded eth: " + EthereumWallet.EncodeAddress("0x44E8743A6CAC3E59594C19DD462863A5AA5E06BB"));

            Console.WriteLine("from encoded bsc: " + BSCWallet.EncodeAddress("0xA89a34c37Da826085E458c17067DA2F38b6e4763"));
            Console.WriteLine("from encoded eth: " + EthereumWallet.EncodeAddress("0xA89a34c37Da826085E458c17067DA2F38b6e4763"));

            this.contracts = contracts.ToList();

            // add local swap address to contracts
            this.contracts.Add(LocalAddress);

            this.confirmations = confirmations;
            this.ethAPI        = ethAPI;
        }
Exemple #4
0
        private void SetupOracleApis()
        {
            var neoPlatform = Settings.Oracle.SwapPlatforms.FirstOrDefault(x => x.Chain == SwapPlatformChain.Neo);

            if (neoPlatform != null && neoPlatform.Enabled)
            {
                var neoScanURL = Settings.Oracle.NeoscanUrl;

                this._neoAPI = new Neo.Core.RemoteRPCNode(neoScanURL, neoPlatform.RpcNodes);
                this._neoAPI.SetLogger((s) => Logger.Message(s));

                this._neoScanAPI = new NeoScanAPI(neoScanURL, Logger, _nexus, _nodeKeys);
            }

            var bscPlatform = Settings.Oracle.SwapPlatforms.FirstOrDefault(x => x.Chain == SwapPlatformChain.BSC);

            if (bscPlatform != null && bscPlatform.Enabled)
            {
                var bscWIF  = Settings.GetInteropWif(Nexus, _nodeKeys, BSCWallet.BSCPlatform);
                var bscKeys = PhantasmaKeys.FromWIF(bscWIF);

                this._bscAPI = new EthAPI(SwapPlatformChain.BSC, this.Nexus, this.Settings, new EthAccount(bscKeys.PrivateKey.ToHex()), Logger);
            }

            var ethPlatform = Settings.Oracle.SwapPlatforms.FirstOrDefault(x => x.Chain == SwapPlatformChain.Ethereum);

            if (ethPlatform != null && ethPlatform.Enabled)
            {
                var ethWIF  = Settings.GetInteropWif(Nexus, _nodeKeys, EthereumWallet.EthereumPlatform);
                var ethKeys = PhantasmaKeys.FromWIF(ethWIF);

                this._ethAPI = new EthAPI(SwapPlatformChain.Ethereum, this.Nexus, this.Settings, new EthAccount(ethKeys.PrivateKey.ToHex()), Logger);
            }

            this._cryptoCompareAPIKey = Settings.Oracle.CryptoCompareAPIKey;
            if (!string.IsNullOrEmpty(this._cryptoCompareAPIKey))
            {
                Logger.Message($"CryptoCompare API enabled.");
            }
            else
            {
                throw new Exception($"CryptoCompare API key missing, oracles won't work properly and oracles are no longer optional...");
            }
        }
Exemple #5
0
        public EthereumInterop(TokenSwapper swapper, EthAPI ethAPI, PBigInteger interopBlockHeight, string[] contracts, uint confirmations)
            : base(swapper, EthereumWallet.EthereumPlatform)
        {
            string lastBlockHeight = OracleReader.GetCurrentHeight(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform);

            if (string.IsNullOrEmpty(lastBlockHeight))
            {
                OracleReader.SetCurrentHeight(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, new BigInteger(interopBlockHeight.ToSignedByteArray()).ToString());
            }

            Logger.Message($"interopHeight: {OracleReader.GetCurrentHeight(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform)}");

            this.contracts = contracts.ToList();

            // add local swap address to contracts
            this.contracts.Add(LocalAddress);

            this.confirmations = confirmations;
            this.ethAPI        = ethAPI;
        }
Exemple #6
0
 private void Init()
 {
     Hdd       = DEV9Header.HDD_DEF;
     HddSize   = 8 * 1024;
     Eth       = DEV9Header.ETH_DEF;
     EthType   = EthAPI.Winsock;
     EthEnable = true;
     HddEnable = false;
     DirectConnectionSettings = new ConfigDirectIP();
     SocketConnectionSettings = new ConfigSocketIP();
     EnableLogging            = new ConfigLogging();
     Hosts = new HashSet <ConfigHost>();
     Hosts.Add(new ConfigHost()
     {
         Desc    = "Set DNS to 192.0.2.1 to use this host list",
         URL     = "www.example.com",
         IP      = "0.0.0.0",
         Enabled = false
     });
 }
Exemple #7
0
        private void SetupOracleApis()
        {
            var neoScanURL = Settings.Oracle.NeoscanUrl;

            var neoRpcList = Settings.Oracle.NeoRpcNodes;

            this._neoAPI = new Neo.Core.RemoteRPCNode(neoScanURL, neoRpcList.ToArray());
            this._neoAPI.SetLogger((s) => Logger.Message(s));

            var ethRpcList = Settings.Oracle.EthRpcNodes;

            var ethWIF  = Settings.GetInteropWif(Nexus, _nodeKeys, EthereumWallet.EthereumPlatform);
            var ethKeys = PhantasmaKeys.FromWIF(ethWIF);

            this._ethAPI = new EthAPI(this.Nexus, this.Settings, new EthAccount(ethKeys.PrivateKey.ToHex()), Logger);

            this._neoScanAPI = new NeoScanAPI(neoScanURL, Logger, _nexus, _nodeKeys);

            this._cryptoCompareAPIKey = Settings.Oracle.CryptoCompareAPIKey;
            if (!string.IsNullOrEmpty(this._cryptoCompareAPIKey))
            {
                Logger.Message($"CryptoCompare API enabled...");
            }
        }
Exemple #8
0
        public static InteropTransaction MakeInteropTx(Nexus nexus, Logger logger, TransactionReceipt txr, EthAPI api, string[] swapAddresses)
        {
            logger.Debug("checking tx: " + txr.TransactionHash);

            IList <InteropTransfer> interopTransfers = new List <InteropTransfer>();

            interopTransfers = GetInteropTransfers(nexus, logger, txr, api, swapAddresses).SelectMany(x => x.Value).ToList();
            logger.Debug($"Found {interopTransfers.Count} interop transfers!");

            return((interopTransfers.Count() > 0)
                ? new InteropTransaction(Hash.Parse(txr.TransactionHash), interopTransfers.ToArray())
                : new InteropTransaction(Hash.Null, interopTransfers.ToArray()));
        }
Exemple #9
0
        private static Dictionary <string, List <InteropTransfer> > GetInteropTransfers(Nexus nexus, Logger logger,
                                                                                        TransactionReceipt txr, EthAPI api, string[] swapAddresses)
        {
            logger.Debug($"get interop transfers for tx {txr.TransactionHash}");
            var interopTransfers = new Dictionary <string, List <InteropTransfer> >();

            Nethereum.RPC.Eth.DTOs.Transaction tx = null;
            try
            {
                // tx to get the eth transfer if any
                tx = api.GetTransaction(txr.TransactionHash);
            }
            catch (Exception e)
            {
                logger.Error("Getting eth tx failed: " + e.Message);
            }

            Console.WriteLine("txr: " + txr.Status);
            logger.Debug("Transaction status: " + txr.Status.Value);
            // check if tx has failed
            if (txr.Status.Value == 0)
            {
                logger.Error($"tx {txr.TransactionHash} failed");
                return(interopTransfers);
            }

            foreach (var a in swapAddresses)
            {
                Console.WriteLine("swap address: " + a);
            }
            var nodeSwapAddresses = swapAddresses.Select(x => BSCWallet.EncodeAddress(x));
            var interopAddress    = ExtractInteropAddress(tx);

            Console.WriteLine("interop address: " + interopAddress);

            // ERC721 (NFT)
            // TODO currently this code block is mostly copypaste from BEP20 block, later make a single method for both...
            //var erc721_events = txr.DecodeAllEvents<Nethereum.StandardNonFungibleTokenERC721.ContractDefinition.TransferEventDTOBase>();
            //foreach (var evt in erc721_events)
            //{
            //    var asset = EthUtils.FindSymbolFromAsset(nexus, evt.Log.Address);
            //    if (asset == null)
            //    {
            //        logger.Warning($"Asset [{evt.Log.Address}] not supported");
            //        continue;
            //    }

            //    var targetAddress = BSCWallet.EncodeAddress(evt.Event.To);
            //    var sourceAddress = BSCWallet.EncodeAddress(evt.Event.From);
            //    var tokenID = PBigInteger.Parse(evt.Event.TokenId.ToString());

            //    if (nodeSwapAddresses.Contains(targetAddress))
            //    {
            //        if (!interopTransfers.ContainsKey(evt.Log.TransactionHash))
            //        {
            //            interopTransfers.Add(evt.Log.TransactionHash, new List<InteropTransfer>());
            //        }

            //        string tokenURI = FetchTokenURI(evt.Log.Address, evt.Event.TokenId);

            //        interopTransfers[evt.Log.TransactionHash].Add
            //        (
            //            new InteropTransfer
            //            (
            //                BSCWallet.BSCPlatform,
            //                sourceAddress,
            //                DomainSettings.PlatformName,
            //                targetAddress,
            //                interopAddress,
            //                asset,
            //                tokenID,
            //                System.Text.Encoding.UTF8.GetBytes(tokenURI)
            //            )
            //        );
            //    }
            //}

            // BEP20
            var bep20_events = txr.DecodeAllEvents <TransferEventDTO>();

            foreach (var evt in bep20_events)
            {
                var asset = EthUtils.FindSymbolFromAsset(BSCWallet.BSCPlatform, nexus, evt.Log.Address);
                if (asset == null)
                {
                    logger.Warning($"Asset [{evt.Log.Address}] not supported");
                    continue;
                }

                var targetAddress = BSCWallet.EncodeAddress(evt.Event.To);
                var sourceAddress = BSCWallet.EncodeAddress(evt.Event.From);
                var amount        = PBigInteger.Parse(evt.Event.Value.ToString());

                if (nodeSwapAddresses.Contains(targetAddress))
                {
                    if (!interopTransfers.ContainsKey(evt.Log.TransactionHash))
                    {
                        interopTransfers.Add(evt.Log.TransactionHash, new List <InteropTransfer>());
                    }

                    interopTransfers[evt.Log.TransactionHash].Add
                    (
                        new InteropTransfer
                        (
                            BSCWallet.BSCPlatform,
                            sourceAddress,
                            DomainSettings.PlatformName,
                            targetAddress,
                            interopAddress,
                            asset,
                            amount
                        )
                    );
                }
            }

            Console.WriteLine("value: " + tx.Value);
            Console.WriteLine("value: " + tx.Value.Value);
            if (tx.Value != null && tx.Value.Value > 0)
            {
                var targetAddress = BSCWallet.EncodeAddress(tx.To);
                var sourceAddress = BSCWallet.EncodeAddress(tx.From);

                foreach (var a in nodeSwapAddresses)
                {
                    Console.WriteLine("node swap address: " + a);
                }
                Console.WriteLine("target address: " + targetAddress);

                if (nodeSwapAddresses.Contains(targetAddress))
                {
                    var amount = PBigInteger.Parse(tx.Value.ToString());

                    if (!interopTransfers.ContainsKey(tx.TransactionHash))
                    {
                        interopTransfers.Add(tx.TransactionHash, new List <InteropTransfer>());
                    }

                    interopTransfers[tx.TransactionHash].Add
                    (
                        new InteropTransfer
                        (
                            BSCWallet.BSCPlatform,
                            sourceAddress,
                            DomainSettings.PlatformName,
                            targetAddress,
                            interopAddress,
                            "BSC", // TODO use const
                            amount
                        )
                    );
                }
            }


            return(interopTransfers);
        }
Exemple #10
0
        public static Tuple <InteropBlock, InteropTransaction[]> MakeInteropBlock(Nexus nexus, Logger logger, EthAPI api
                                                                                  , BigInteger height, string[] contracts, uint confirmations, string[] swapAddress)
        {
            Hash blockHash           = Hash.Null;
            var  interopTransactions = new List <InteropTransaction>();

            //TODO HACK
            var combinedAddresses = contracts.ToList();

            combinedAddresses.AddRange(swapAddress);

            Dictionary <string, Dictionary <string, List <InteropTransfer> > > transfers = new Dictionary <string, Dictionary <string, List <InteropTransfer> > >();

            try
            {
                // TODO pass from outside to not instantiate for each call to MakeInteropBlock
                Func <string, Address> addressEncoder = (address) => { return(BSCWallet.EncodeAddress(address)); };
                Func <Nethereum.RPC.Eth.DTOs.Transaction, Address> addressExtractor = (tx) => { return(BSCInterop.ExtractInteropAddress(tx)); };

                var crawler = new EvmBlockCrawler(logger, combinedAddresses.ToArray(), confirmations, api,
                                                  addressEncoder, addressExtractor, BSCWallet.BSCPlatform);
                // fetch blocks
                crawler.Fetch(height);
                transfers = crawler.ExtractInteropTransfers(nexus, logger, swapAddress);
            }
            catch (Exception e)
            {
                logger.Error("Failed to fetch eth blocks: " + e);
            }

            if (transfers.Count == 0)
            {
                var emptyBlock = new InteropBlock(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, Hash.Null, new Hash[] {});
                return(Tuple.Create(emptyBlock, interopTransactions.ToArray()));
            }

            blockHash = Hash.Parse(transfers.FirstOrDefault().Key);

            foreach (var block in transfers)
            {
                var txTransferDict = block.Value;
                foreach (var tx in txTransferDict)
                {
                    var interopTx = MakeInteropTx(logger, tx.Key, tx.Value);
                    if (interopTx.Hash != Hash.Null)
                    {
                        interopTransactions.Add(interopTx);
                    }
                }
            }

            var hashes = interopTransactions.Select(x => x.Hash).ToArray();

            InteropBlock interopBlock = (interopTransactions.Count() > 0)
                ? new InteropBlock(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, blockHash, hashes)
                : new InteropBlock(BSCWallet.BSCPlatform, BSCWallet.BSCPlatform, Hash.Null, hashes);

            return(Tuple.Create(interopBlock, interopTransactions.ToArray()));
        }
Exemple #11
0
 public static Tuple <InteropBlock, InteropTransaction[]> MakeInteropBlock(Logger logger, BlockWithTransactions block, EthAPI api
                                                                           , string[] swapAddress)
 {
     //TODO
     return(null);
 }
Exemple #12
0
        private static Dictionary <string, List <InteropTransfer> > GetInteropTransfers(Nexus nexus, Logger logger,
                                                                                        TransactionReceipt txr, EthAPI api, string swapAddress)
        {
            logger.Debug($"get interop transfers for tx {txr.TransactionHash}");
            var interopTransfers = new Dictionary <string, List <InteropTransfer> >();

            Nethereum.RPC.Eth.DTOs.Transaction tx = null;
            try
            {
                // tx to get the eth transfer if any
                tx = api.GetTransaction(txr.TransactionHash);
            }
            catch (Exception e)
            {
                logger.Error("Getting eth tx failed: " + e.Message);
            }

            logger.Debug("Transaction status: " + txr.Status.Value);
            // check if tx has failed
            if (txr.Status.Value == 0)
            {
                logger.Error($"tx {txr.TransactionHash} failed");
                return(interopTransfers);
            }

            var nodeSwapAddress = EthereumWallet.EncodeAddress(swapAddress);
            var events          = txr.DecodeAllEvents <TransferEventDTO>();
            var interopAddress  = ExtractInteropAddress(tx);

            // ERC20
            foreach (var evt in events)
            {
                var asset = EthUtils.FindSymbolFromAsset(nexus, evt.Log.Address);
                if (asset == null)
                {
                    logger.Warning($"Asset [{evt.Log.Address}] not supported");
                    continue;
                }

                var targetAddress = EthereumWallet.EncodeAddress(evt.Event.To);
                var sourceAddress = EthereumWallet.EncodeAddress(evt.Event.From);
                var amount        = PBigInteger.Parse(evt.Event.Value.ToString());

                if (targetAddress.Equals(nodeSwapAddress))
                {
                    if (!interopTransfers.ContainsKey(evt.Log.TransactionHash))
                    {
                        interopTransfers.Add(evt.Log.TransactionHash, new List <InteropTransfer>());
                    }

                    interopTransfers[evt.Log.TransactionHash].Add
                    (
                        new InteropTransfer
                        (
                            EthereumWallet.EthereumPlatform,
                            sourceAddress,
                            DomainSettings.PlatformName,
                            targetAddress,
                            interopAddress,
                            asset,
                            amount
                        )
                    );
                }
            }

            if (tx.Value != null && tx.Value.Value > 0)
            {
                var targetAddress = EthereumWallet.EncodeAddress(tx.To);
                var sourceAddress = EthereumWallet.EncodeAddress(tx.From);

                if (targetAddress.Equals(nodeSwapAddress))
                {
                    var amount = PBigInteger.Parse(tx.Value.ToString());

                    if (!interopTransfers.ContainsKey(tx.TransactionHash))
                    {
                        interopTransfers.Add(tx.TransactionHash, new List <InteropTransfer>());
                    }

                    interopTransfers[tx.TransactionHash].Add
                    (
                        new InteropTransfer
                        (
                            EthereumWallet.EthereumPlatform,
                            sourceAddress,
                            DomainSettings.PlatformName,
                            targetAddress,
                            interopAddress,
                            "ETH", // TODO use const
                            amount
                        )
                    );
                }
            }


            return(interopTransfers);
        }
Exemple #13
0
        public static Tuple <InteropBlock, InteropTransaction[]> MakeInteropBlock(Nexus nexus, Logger logger, EthAPI api
                                                                                  , BigInteger height, string[] contracts, uint confirmations, string swapAddress)
        {
            Hash blockHash           = Hash.Null;
            var  interopTransactions = new List <InteropTransaction>();

            //TODO HACK
            var combinedAddresses = contracts.ToList();

            combinedAddresses.Add(swapAddress);

            Dictionary <string, Dictionary <string, List <InteropTransfer> > > transfers = new Dictionary <string, Dictionary <string, List <InteropTransfer> > >();

            try
            {
                var crawler = new EthBlockCrawler(logger, combinedAddresses.ToArray(), confirmations, api);
                // fetch blocks
                crawler.Fetch(height);
                transfers = crawler.ExtractInteropTransfers(nexus, logger, swapAddress);
            }
            catch (Exception e)
            {
                logger.Error("Failed to fetch eth blocks: " + e);
            }

            if (transfers.Count == 0)
            {
                var emptyBlock = new InteropBlock(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, Hash.Null, new Hash[] {});
                return(Tuple.Create(emptyBlock, interopTransactions.ToArray()));
            }

            blockHash = Hash.Parse(transfers.FirstOrDefault().Key);

            foreach (var block in transfers)
            {
                var txTransferDict = block.Value;
                foreach (var tx in txTransferDict)
                {
                    var interopTx = MakeInteropTx(logger, tx.Key, tx.Value);
                    if (interopTx.Hash != Hash.Null)
                    {
                        interopTransactions.Add(interopTx);
                    }
                }
            }

            var hashes = interopTransactions.Select(x => x.Hash).ToArray();

            InteropBlock interopBlock = (interopTransactions.Count() > 0)
                ? new InteropBlock(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, blockHash, hashes)
                : new InteropBlock(EthereumWallet.EthereumPlatform, EthereumWallet.EthereumPlatform, Hash.Null, hashes);

            return(Tuple.Create(interopBlock, interopTransactions.ToArray()));
        }
Exemple #14
0
        private void Init()
        {
            Hdd = DEV9Header.HDD_DEF;
            HddSize = 8 * 1024;
            Eth = DEV9Header.ETH_DEF;
            EthType = EthAPI.Winsock;
            EthEnable = true;
            HddEnable = false;

            DirectConnectionSettings = new ConfigDirectIP();
            SocketConnectionSettings = new ConfigSocketIP();
        }
Exemple #15
0
        private static Dictionary <string, List <InteropTransfer> > GetInteropTransfers(Nexus nexus, Logger logger,
                                                                                        TransactionReceipt txr, EthAPI api, string[] swapAddresses)
        {
            logger.Debug($"get interop transfers for tx {txr.TransactionHash}");
            var interopTransfers = new Dictionary <string, List <InteropTransfer> >();

            Nethereum.RPC.Eth.DTOs.Transaction tx = null;
            try
            {
                // tx to get the eth transfer if any
                tx = api.GetTransaction(txr.TransactionHash);
            }
            catch (Exception e)
            {
                logger.Error("Getting eth tx failed: " + e.Message);
            }

            logger.Debug("Transaction status: " + txr.Status.Value);
            // check if tx has failed
            if (txr.Status.Value == 0)
            {
                logger.Error($"tx {txr.TransactionHash} failed");
                return(interopTransfers);
            }

            var     nodeSwapAddresses = swapAddresses.Select(x => EthereumWallet.EncodeAddress(x));
            Address interopAddress;

            try
            {
                interopAddress = ExtractInteropAddress(tx, logger);
            }
            catch (Exception e)
            {
                if (e.ToString().Contains("Header byte out of range"))
                {
                    // Ignoring this exception and skipping this tx.
                    // RecoverFromSignature() crashed and we cannot avoid it atm.
                    // Related to EIP-1559, example of probematic tx: https://etherscan.io/tx/0xb022c146d8d1e684de0c1faae43e7ce36afb6969719adfdcafcc5bb7d5913185
                    // TODO Fix by updating to new Nethereum and dealing with EIP-1559 better.
                    logger.Debug("Warning: Skipping 'Header byte out of range' tx: " + tx.TransactionHash);
                    return(interopTransfers);
                }
                else
                {
                    throw;
                }
            }

            // ERC721 (NFT)
            // TODO currently this code block is mostly copypaste from ERC20 block, later make a single method for both...
            //var erc721_events = txr.DecodeAllEvents<Nethereum.StandardNonFungibleTokenERC721.ContractDefinition.TransferEventDTOBase>();
            //foreach (var evt in erc721_events)
            //{
            //    var asset = EthUtils.FindSymbolFromAsset(nexus, evt.Log.Address);
            //    if (asset == null)
            //    {
            //        logger.Warning($"Asset [{evt.Log.Address}] not supported");
            //        continue;
            //    }

            //    var targetAddress = EthereumWallet.EncodeAddress(evt.Event.To);
            //    var sourceAddress = EthereumWallet.EncodeAddress(evt.Event.From);
            //    var tokenID = PBigInteger.Parse(evt.Event.TokenId.ToString());

            //    if (nodeSwapAddresses.Contains(targetAddress))
            //    {
            //        if (!interopTransfers.ContainsKey(evt.Log.TransactionHash))
            //        {
            //            interopTransfers.Add(evt.Log.TransactionHash, new List<InteropTransfer>());
            //        }

            //        string tokenURI = FetchTokenURI(evt.Log.Address, evt.Event.TokenId);

            //        interopTransfers[evt.Log.TransactionHash].Add
            //        (
            //            new InteropTransfer
            //            (
            //                EthereumWallet.EthereumPlatform,
            //                sourceAddress,
            //                DomainSettings.PlatformName,
            //                targetAddress,
            //                interopAddress,
            //                asset,
            //                tokenID,
            //                System.Text.Encoding.UTF8.GetBytes(tokenURI)
            //            )
            //        );
            //    }
            //}

            // ERC20
            var erc20_events = txr.DecodeAllEvents <TransferEventDTO>();

            foreach (var evt in erc20_events)
            {
                var asset = EthUtils.FindSymbolFromAsset(EthereumWallet.EthereumPlatform, nexus, evt.Log.Address);
                if (asset == null)
                {
                    logger.Warning($"Asset [{evt.Log.Address}] not supported");
                    continue;
                }

                var targetAddress = EthereumWallet.EncodeAddress(evt.Event.To);
                var sourceAddress = EthereumWallet.EncodeAddress(evt.Event.From);
                var amount        = PBigInteger.Parse(evt.Event.Value.ToString());

                if (nodeSwapAddresses.Contains(targetAddress))
                {
                    if (!interopTransfers.ContainsKey(evt.Log.TransactionHash))
                    {
                        interopTransfers.Add(evt.Log.TransactionHash, new List <InteropTransfer>());
                    }

                    interopTransfers[evt.Log.TransactionHash].Add
                    (
                        new InteropTransfer
                        (
                            EthereumWallet.EthereumPlatform,
                            sourceAddress,
                            DomainSettings.PlatformName,
                            targetAddress,
                            interopAddress,
                            asset,
                            amount
                        )
                    );
                }
            }

            if (tx.Value != null && tx.Value.Value > 0)
            {
                var targetAddress = EthereumWallet.EncodeAddress(tx.To);
                var sourceAddress = EthereumWallet.EncodeAddress(tx.From);

                if (nodeSwapAddresses.Contains(targetAddress))
                {
                    var amount = PBigInteger.Parse(tx.Value.ToString());

                    if (!interopTransfers.ContainsKey(tx.TransactionHash))
                    {
                        interopTransfers.Add(tx.TransactionHash, new List <InteropTransfer>());
                    }

                    interopTransfers[tx.TransactionHash].Add
                    (
                        new InteropTransfer
                        (
                            EthereumWallet.EthereumPlatform,
                            sourceAddress,
                            DomainSettings.PlatformName,
                            targetAddress,
                            interopAddress,
                            "ETH", // TODO use const
                            amount
                        )
                    );
                }
            }


            return(interopTransfers);
        }