예제 #1
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;
        }
예제 #2
0
        public string GetAddress(WalletKind kind)
        {
            if (_wallets.ContainsKey(kind))
            {
                return(_wallets[kind].Address);
            }

            CryptoWallet wallet;

            switch (kind)
            {
            case WalletKind.Phantasma: wallet = new PhantasmaWallet(keys); break;

            case WalletKind.Neo: wallet = new NeoWallet(keys); break;

            case WalletKind.Bitcoin: wallet = new BitcoinWallet(keys); break;

            case WalletKind.Ethereum: wallet = new EthereumWallet(keys); break;

            case WalletKind.EOS: wallet = new EOSWallet(keys); break;

            default: throw new Exception("Unsupported wallet kind: " + kind);
            }

            _wallets[kind] = wallet;
            return(wallet.Address);
        }
예제 #3
0
        public void TestEthereumWallet()
        {
            var keys    = new PhantasmaKeys(Base16.Decode("a95bd75a7b3b1c0a2a14595e8065a95cb06417f6aaedcc3bc45fda52900ab9e8"));
            var wallet  = new EthereumWallet(keys);
            var address = wallet.Address;

            Assert.IsTrue(address.Equals("0xe57a6c074d1db5ed7c98228df71ce5fa35b6bc72", StringComparison.OrdinalIgnoreCase));
        }
예제 #4
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
            {
                Func <string, Address> addressEncoder = (address) => { return(EthereumWallet.EncodeAddress(address)); };
                Func <Nethereum.RPC.Eth.DTOs.Transaction, Address> addressExtractor = (tx) => { return(EthereumInterop.ExtractInteropAddress(tx, logger)); };

                var crawler = new EvmBlockCrawler(logger, combinedAddresses.ToArray(), confirmations, api,
                                                  addressEncoder, addressExtractor, EthereumWallet.EthereumPlatform);
                // 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()));
        }
        public void ShouldGenerateFromPrivateKey()
        {
            var privateKey     = "ca5edb4b5db35fc6677d9c6fe223afc3343014653b159ae4291f543a78761c87";
            var ethereumWallet = new EthereumWallet(privateKey);

            var pubKey = ethereumWallet.PublicKey;

            Assert.AreEqual(expected: "02ba33e9bba01836a3c5c8c4aa70abb16ccffc66470d40def867a0d66fa3d40c27", actual: pubKey.ToString());

            var walletAddress = ethereumWallet.Address;

            Assert.AreEqual(expected: "0xA2ae76fb87C154580a034c116115cE39441Add6F", actual: walletAddress);
        }
예제 #6
0
        protected void OnPlatformAddressAdd(string[] args)
        {
            var platform        = args[0];
            var externalAddress = args[1];

            Address localAddress;

            switch (platform)
            {
            case NeoWallet.NeoPlatform:
                localAddress = NeoWallet.EncodeAddress(externalAddress);
                break;

            case EthereumWallet.EthereumPlatform:
                localAddress = EthereumWallet.EncodeAddress(externalAddress);
                break;

            case BSCWallet.BSCPlatform:
                localAddress = BSCWallet.EncodeAddress(externalAddress);
                break;

            default:
                throw new Exception("Unknown platform: " + platform);
            }

            var minimumFee = _cli.Settings.Node.MinimumFee;
            var script     = ScriptUtils.BeginScript()
                             .AllowGas(_cli.NodeKeys.Address, Address.Null, minimumFee, 1500)
                             .CallContract("interop", nameof(InteropContract.RegisterAddress), _cli.NodeKeys.Address, platform, localAddress, externalAddress)
                             .SpendGas(_cli.NodeKeys.Address).EndScript();

            var expire = Timestamp.Now + TimeSpan.FromMinutes(2);
            var tx     = new Phantasma.Blockchain.Transaction(_cli.Nexus.Name, _cli.Nexus.RootChain.Name, script, expire, Spook.TxIdentifier);

            tx.Mine((int)ProofOfWork.Minimal);
            tx.Sign(_cli.NodeKeys);

            if (_cli.Mempool != null)
            {
                _cli.Mempool.Submit(tx);
                Console.WriteLine($"Transaction {tx.Hash} submitted to mempool.");
            }
            else
            {
                Console.WriteLine("No mempool available");
                return;
            }
            Console.WriteLine($"Added address {externalAddress} to {platform}");
            Spook.Logger.Message($"Added address {externalAddress} to {platform}");
        }
예제 #7
0
        // NOTE no locks happen here because this callback is called from within a lock
        internal override Hash SettleSwap(Hash sourceHash, Address destination, IToken token, Numerics.BigInteger amount)
        {
            // check if tx was sent but not minded yet
            string tx = null;

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

            if (inProgressMap.ContainsKey <Hash>(sourceHash))
            {
                tx = inProgressMap.Get <Hash, string>(sourceHash);

                if (!string.IsNullOrEmpty(tx))
                {
                    return(VerifyEthTx(sourceHash, tx));
                }
            }

            var total = Numerics.UnitConversion.ToDecimal(amount, token.Decimals);

            var ethKeys = EthereumKey.FromWIF(this.WIF);

            var destAddress = EthereumWallet.DecodeAddress(destination);

            try
            {
                Logger.Debug($"ETHSWAP: Trying transfer of {total} {token.Symbol} from {ethKeys.Address} to {destAddress}");
                var transferResult = ethAPI.TryTransferAsset(EthereumWallet.EthereumPlatform, token.Symbol, destAddress,
                                                             total, token.Decimals, out tx);

                if (transferResult == EthTransferResult.Success)
                {
                    // persist resulting tx hash as in progress
                    inProgressMap.Set <Hash, string>(sourceHash, tx);
                    Logger.Debug("broadcasted eth tx: " + tx);
                }
                else
                {
                    Logger.Error($"ETHSWAP: Transfer of {total} {token.Symbol} from {ethKeys.Address} to {destAddress} failed, no tx generated");
                }
            }
            catch (Exception e)
            {
                Logger.Error($"Exception during transfer: {e}");
                // we don't know if the transfer happend or not, therefore can't delete from inProgressMap yet.
                return(Hash.Null);
            }

            return(VerifyEthTx(sourceHash, tx));
        }
예제 #8
0
        public static void DecodePlatformAndAddress(Address source, out string platform, out string address)
        {
            byte[] bytes;

            source.DecodeInterop(out platform, out bytes, 0);

            switch (platform)
            {
            case NeoWallet.NeoPlatform:
                address = NeoWallet.DecodeAddress(source);
                break;

            case EthereumWallet.EthereumPlatform:
                address = EthereumWallet.DecodeAddress(source);
                break;

            default:
                throw new NotImplementedException($"cannot decode addresses for {platform} chain");
            }
        }
예제 #9
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);
        }
예제 #10
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);
        }
예제 #11
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);
        }