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; }
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())); }
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}"); }
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); }
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); }
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); }