Beispiel #1
0
        protected override InteropTransaction PullPlatformTransaction(string platformName, string chainName, Hash hash)
        {
            logger.Debug($"{platformName} pull tx: {hash}");
            InteropTransaction tx = Read <InteropTransaction>(platformName, chainName, hash, StorageConst.Transaction);

            if (tx != null && tx.Hash != null)
            {
                logger.Debug($"Found tx {hash} in oracle storage");
                return(tx);
            }

            switch (platformName)
            {
            case NeoWallet.NeoPlatform:
                NeoTx   neoTx;
                UInt256 uHash = new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes());
                neoTx = _cli.NeoAPI.GetTransaction(uHash);
                var coldStorage = _cli.Settings.Oracle.SwapColdStorageNeo;
                tx = NeoInterop.MakeInteropTx(logger, neoTx, _cli.NeoAPI,
                                              _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Neo], coldStorage);
                break;

            case EthereumWallet.EthereumPlatform:
            {
                var txRcpt = _cli.EthAPI.GetTransactionReceipt(hash.ToString());
                tx = EthereumInterop.MakeInteropTx(_cli.Nexus, logger, txRcpt, _cli.EthAPI,
                                                   _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Ethereum]);
                break;
            }

            case BSCWallet.BSCPlatform:
            {
                var txRcpt = _cli.BscAPI.GetTransactionReceipt(hash.ToString());
                tx = BSCInterop.MakeInteropTx(_cli.Nexus, logger, txRcpt, _cli.BscAPI,
                                              _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.BSC]);
                break;
            }

            default:
                throw new OracleException("Uknown oracle platform: " + platformName);
            }

            if (!Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx))
            {
                logger.Error($"Oracle transaction { hash } on platform { platformName } updated!");
            }

            return(tx);
        }
Beispiel #2
0
        protected override Phantasma.Numerics.BigInteger PullFee(Timestamp time, string platform)
        {
            platform = platform.ToLower();

            switch (platform)
            {
            case NeoWallet.NeoPlatform:
                return(Phantasma.Numerics.UnitConversion.ToBigInteger(0.1m, DomainSettings.FiatTokenDecimals));

            case EthereumWallet.EthereumPlatform:

                CachedFee fee;
                if (_feeCache.TryGetValue(platform, out fee))
                {
                    if ((Timestamp.Now - fee.Time) < 60)
                    {
                        var logMessage = $"PullFee({platform}): Cached fee pulled: {fee.Value}, GAS limit: {_cli.Settings.Oracle.EthGasLimit}, calculated fee: {fee.Value * _cli.Settings.Oracle.EthGasLimit}";
                        logger.Debug(logMessage);

                        return(fee.Value * _cli.Settings.Oracle.EthGasLimit);
                    }
                }

                var newFee = EthereumInterop.GetNormalizedFee(_cli.Settings.Oracle.EthFeeURLs.ToArray());
                fee = new CachedFee(Timestamp.Now, UnitConversion.ToBigInteger(newFee, 9));     // 9 for GWEI
                _feeCache[platform] = fee;

                var logMessage2 = $"PullFee({platform}): New fee pulled: {fee.Value}, GAS limit: {_cli.Settings.Oracle.EthGasLimit}, calculated fee: {fee.Value * _cli.Settings.Oracle.EthGasLimit}";
                logger.Debug(logMessage2);

                return(fee.Value * _cli.Settings.Oracle.EthGasLimit);

            default:
                throw new OracleException($"Support for {platform} fee not implemented in this node");
            }
        }
Beispiel #3
0
        public InteropTransfers ExtractInteropTransfers(Blockchain.Nexus nexus, Logger logger, string swapAddress)
        {
            var interopTransfers = new InteropTransfers();

            lock (transactions)
            {
                foreach (var txVo in transactions)
                {
                    var block = txVo.Block;
                    var txr   = txVo.TransactionReceipt;
                    var tx    = txVo.Transaction;

                    var interopAddress = EthereumInterop.ExtractInteropAddress(tx);
                    var transferEvents = txr.DecodeAllEvents <TransferEventDTO>();
                    //var swapEvents = txr.DecodeAllEvents<SwapEventDTO>();
                    var nodeSwapAddress = EthereumWallet.EncodeAddress(swapAddress);

                    if (transferEvents.Count > 0 || tx.Value != null && tx.Value.Value > 0)
                    {
                        if (!interopTransfers.ContainsKey(block.BlockHash))
                        {
                            interopTransfers.Add(block.BlockHash, new Dictionary <string, List <InteropTransfer> >());
                        }
                    }

                    if (transferEvents.Count > 0)
                    {
                        var blockId = block.Number.ToString();
                        var hash    = txr.TransactionHash;

                        foreach (var evt in transferEvents)
                        {
                            var targetAddress = EthereumWallet.EncodeAddress(evt.Event.To);

                            // If it's not our address, skip immediatly, don't log it
                            if (targetAddress != nodeSwapAddress)
                            {
                                continue;
                            }

                            logger.Message($"Found ERC20 swap: {blockId} hash: {hash} to: {evt.Event.To} from: {evt.Event.From} value: {evt.Event.Value}");
                            var asset = EthUtils.FindSymbolFromAsset(nexus, evt.Log.Address);
                            logger.Message("asset: " + asset);
                            if (asset == null)
                            {
                                logger.Message($"Asset [{evt.Log.Address}] not supported");
                                continue;
                            }


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

                            logger.Message("nodeSwapAddress: " + nodeSwapAddress);
                            logger.Message("sourceAddress: " + sourceAddress);
                            logger.Message("targetAddress: " + targetAddress);
                            logger.Message("amount: " + amount);

                            if (!interopTransfers[block.BlockHash].ContainsKey(evt.Log.TransactionHash))
                            {
                                interopTransfers[block.BlockHash].Add(evt.Log.TransactionHash, new List <InteropTransfer>());
                            }

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

                    if (tx.Value != null && tx.Value.Value > 0)
                    {
                        logger.Message("ETH:");
                        logger.Message(block.Number.ToString());
                        logger.Message(tx.TransactionHash);
                        logger.Message(tx.To);
                        logger.Message(tx.From);
                        logger.Message(tx.Value.ToString());

                        var targetAddress = EthereumWallet.EncodeAddress(tx.To);

                        if (targetAddress != nodeSwapAddress)
                        {
                            continue;
                        }

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

                        var sourceAddress = EthereumWallet.EncodeAddress(tx.From);
                        var amount        = PBigInteger.Parse(tx.Value.ToString());

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

                transactions.Clear();
            }

            // clear transactions after extraction was done
            return(interopTransfers);
        }
Beispiel #4
0
        protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height = new NativeBigInt())
        {
            if (hash == null && height == null)
            {
                throw new OracleException($"Fetching block not possible without hash or height");
            }

            InteropBlock block = Read <InteropBlock>(platformName, chainName, hash, StorageConst.Block);

            if (height == null && block.Hash != null && block.Hash != Hash.Null)
            {
                return(block);
            }

            Tuple <InteropBlock, InteropTransaction[]> interopTuple;

            switch (platformName)
            {
            case NeoWallet.NeoPlatform:

                NeoBlock neoBlock;

                if (height == 0)
                {
                    neoBlock = _cli.NeoAPI.GetBlock(new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes()));
                }
                else
                {
                    neoBlock = _cli.NeoAPI.GetBlock(height);
                }

                if (neoBlock == null)
                {
                    throw new OracleException($"Neo block is null");
                }

                var coldStorage = _cli.Settings.Oracle.SwapColdStorageNeo;
                interopTuple = NeoInterop.MakeInteropBlock(logger, neoBlock, _cli.NeoAPI,
                                                           _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Neo], coldStorage);
                break;

            case EthereumWallet.EthereumPlatform:

            {
                var hashes = _cli.Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform, _cli.Nexus.RootStorage)
                             .Select(x => x.ToString().Substring(0, 40)).ToArray();

                interopTuple = EthereumInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.EthAPI, height,
                                                                hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.Ethereum]);
                break;
            }

            case BSCWallet.BSCPlatform:
            {
                var hashes = _cli.Nexus.GetPlatformTokenHashes(BSCWallet.BSCPlatform, _cli.Nexus.RootStorage)
                             .Select(x => x.ToString().Substring(0, 40)).ToArray();

                interopTuple = BSCInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.BscAPI, height,
                                                           hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[SwapPlatformChain.BSC]);
                break;
            }


            default:
                throw new OracleException("Uknown oracle platform: " + platformName);
            }

            if (interopTuple.Item1.Hash != Hash.Null)
            {
                var initialStore = Persist <InteropBlock>(platformName, chainName, interopTuple.Item1.Hash, StorageConst.Block,
                                                          interopTuple.Item1);
                var transactions = interopTuple.Item2;

                if (!initialStore)
                {
                    logger.Debug($"Oracle block { interopTuple.Item1.Hash } on platform { platformName } updated!");
                }

                foreach (var tx in transactions)
                {
                    var txInitialStore = Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx);
                    if (!txInitialStore)
                    {
                        logger.Debug($"Oracle block { interopTuple.Item1.Hash } on platform { platformName } updated!");
                    }
                }
            }

            return(interopTuple.Item1);
        }
Beispiel #5
0
        protected override InteropBlock PullPlatformBlock(string platformName, string chainName, Hash hash, NativeBigInt height = new NativeBigInt())
        {
            if (hash == null && height == null)
            {
                throw new OracleException($"Fetching block not possible without hash or height");
            }

            InteropBlock block = Read <InteropBlock>(platformName, chainName, hash, StorageConst.Block);

            if (height == null && block.Hash != null && block.Hash != Hash.Null)
            {
                return(block);
            }

            Tuple <InteropBlock, InteropTransaction[]> interopTuple;

            switch (platformName)
            {
            case NeoWallet.NeoPlatform:

                NeoBlock neoBlock;

                if (height == 0)
                {
                    neoBlock = _cli.NeoAPI.GetBlock(new UInt256(LuxUtils.ReverseHex(hash.ToString()).HexToBytes()));
                }
                else
                {
                    neoBlock = _cli.NeoAPI.GetBlock(height);
                }

                if (neoBlock == null)
                {
                    throw new OracleException($"Neo block is null");
                }

                interopTuple = NeoInterop.MakeInteropBlock(logger, neoBlock, _cli.NeoAPI, _cli.TokenSwapper.SwapAddresses[platformName]);
                break;

            case EthereumWallet.EthereumPlatform:

                //BlockWithTransactions ethBlock;
                //if (height == 0)
                //{
                //    //TODO MakeInteropBlock for a full block not done yet
                //    //ethBlock = _cli.EthAPI.GetBlock(hash.ToString());
                //    //interopTuple = EthereumInterop.MakeInteropBlock(logger, ethBlock, _cli.EthAPI, _cli.TokenSwapper.swapAddress);
                //}
                //else
                //{
                //}

                var hashes = _cli.Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform, _cli.Nexus.RootStorage)
                             .Select(x => x.ToString().Substring(0, 40)).ToArray();

                interopTuple = EthereumInterop.MakeInteropBlock(_cli.Nexus, logger, _cli.EthAPI, height,
                                                                hashes, _cli.Settings.Oracle.EthConfirmations, _cli.TokenSwapper.SwapAddresses[platformName]);
                break;

            default:
                throw new OracleException("Uknown oracle platform: " + platformName);
            }

            if (interopTuple.Item1.Hash != Hash.Null)
            {
                var persisted = Persist <InteropBlock>(platformName, chainName, interopTuple.Item1.Hash, StorageConst.Block,
                                                       interopTuple.Item1);

                if (persisted)
                {
                    var transactions = interopTuple.Item2;

                    foreach (var tx in transactions)
                    {
                        var txPersisted = Persist <InteropTransaction>(platformName, chainName, tx.Hash, StorageConst.Transaction, tx);
                    }
                }
                else
                {
                    logger.Error($"Persisting oracle block { interopTuple.Item1.Hash } on platform { platformName } failed!");
                }
            }

            return(interopTuple.Item1);
        }
Beispiel #6
0
        public InteropTransfers ExtractInteropTransfers(Blockchain.Nexus nexus, Logger logger, string[] swapAddresses)
        {
            var interopTransfers = new InteropTransfers();

            lock (transactions)
            {
                foreach (var txVo in transactions)
                {
                    var block = txVo.Block;
                    var txr   = txVo.TransactionReceipt;
                    var tx    = txVo.Transaction;

                    Address interopAddress;
                    try
                    {
                        interopAddress = EthereumInterop.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);
                            continue;
                        }
                        else
                        {
                            throw;
                        }
                    }
                    var transferEvents = txr.DecodeAllEvents <TransferEventDTO>();
                    //var swapEvents = txr.DecodeAllEvents<SwapEventDTO>();
                    var nodeSwapAddresses = swapAddresses.Select(x => encodeHandler(x)).ToList();
                    //var nodeSwapAddresses = encodeHandler(swapAddress);

                    if (transferEvents.Count > 0 || tx.Value != null && tx.Value.Value > 0)
                    {
                        if (!interopTransfers.ContainsKey(block.BlockHash))
                        {
                            interopTransfers.Add(block.BlockHash, new Dictionary <string, List <InteropTransfer> >());
                        }
                    }

                    if (transferEvents.Count > 0)
                    {
                        var blockId = block.Number.ToString();
                        var hash    = txr.TransactionHash;

                        foreach (var evt in transferEvents)
                        {
                            var targetAddress = encodeHandler(evt.Event.To);

                            // If it's not our address, skip immediatly, don't log it
                            if (!nodeSwapAddresses.Contains(targetAddress))
                            {
                                continue;
                            }

                            var asset = EthUtils.FindSymbolFromAsset(this.platform, nexus, evt.Log.Address);
                            logger.Debug($@"Found {this.platform} swap: {blockId} hash: {hash} to: {evt.Event.To}
                                from: {evt.Event.From} value: {evt.Event.Value} asset: {asset}");
                            if (asset == null)
                            {
                                logger.Debug($"Asset [{evt.Log.Address}] not supported");
                                continue;
                            }


                            var sourceAddress = encodeHandler(evt.Event.From);
                            var amount        = PBigInteger.Parse(evt.Event.Value.ToString());

                            //logger.Message("nodeSwapAddress: " + nodeSwapAddress);
                            //logger.Message("sourceAddress: " + sourceAddress);
                            //logger.Message("targetAddress: " + targetAddress);
                            //logger.Message("amount: " + amount);

                            if (!interopTransfers[block.BlockHash].ContainsKey(evt.Log.TransactionHash))
                            {
                                interopTransfers[block.BlockHash].Add(evt.Log.TransactionHash, new List <InteropTransfer>());
                            }

                            interopTransfers[block.BlockHash][evt.Log.TransactionHash].Add
                            (
                                new InteropTransfer
                                (
                                    this.platform,
                                    sourceAddress,
                                    DomainSettings.PlatformName,
                                    targetAddress,
                                    interopAddress, // interop address
                                    asset,
                                    amount
                                )
                            );
                        }
                    }

                    if (tx.Value != null && tx.Value.Value > 0)
                    {
                        //logger.Message("ETH:");
                        //logger.Message(block.Number.ToString());
                        //logger.Message(tx.TransactionHash);
                        //logger.Message(tx.To);
                        //logger.Message(tx.From);
                        //logger.Message(tx.Value.ToString());

                        var targetAddress = encodeHandler(tx.To);
                        Console.WriteLine("target eth: " + targetAddress);

                        if (!nodeSwapAddresses.Contains(targetAddress))
                        {
                            continue;
                        }

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

                        var sourceAddress = encodeHandler(tx.From);
                        var amount        = PBigInteger.Parse(tx.Value.ToString());

                        var nativeSymbol = (this.platform == "ethereum") ? "ETH" : "BNB";

                        interopTransfers[block.BlockHash][tx.TransactionHash].Add
                        (
                            new InteropTransfer
                            (
                                this.platform,
                                sourceAddress,
                                DomainSettings.PlatformName,
                                targetAddress,
                                interopAddress, // interop address
                                nativeSymbol,
                                amount
                            )
                        );
                    }
                }

                transactions.Clear();
            }

            // clear transactions after extraction was done
            return(interopTransfers);
        }