Пример #1
0
        private Address FindLender(BigInteger amount)
        {
            var count = _lenderList.Count();

            if (count > 0)
            {
                var index         = Runtime.GenerateRandomNumber() % count;
                var originalIndex = index;
                do
                {
                    var address = _lenderList.Get <Address>(index);
                    var lender  = _lenderMap.Get <Address, GasLender>(address);
                    if (lender.balance >= amount)
                    {
                        return(address);
                    }

                    index++;
                    if (index == originalIndex)
                    {
                        break;
                    }

                    if (index >= count)
                    {
                        index = 0;
                    }
                } while (true);
            }

            return(Address.Null);
        }
Пример #2
0
        private void CreateOTC(Address from, string baseSymbol, string quoteSymbol, BigInteger amount, BigInteger price)
        {
            var uid = Runtime.GenerateUID();

            var           count = _otcBook.Count();
            ExchangeOrder lockUpOrder;

            for (int i = 0; i < count; i++)
            {
                lockUpOrder = _otcBook.Get <ExchangeOrder>(i);
                if (lockUpOrder.Creator == from)
                {
                    throw new Exception("Already have an offer created");
                    return;
                }
            }

            var baseBalance = Runtime.GetBalance(baseSymbol, from);

            Runtime.Expect(baseBalance >= amount, "invalid seller amount");
            Runtime.TransferTokens(baseSymbol, from, this.Address, price);

            var order = new ExchangeOrder(uid, Runtime.Time, from, this.Address, amount, baseSymbol, price, quoteSymbol, ExchangeOrderSide.Sell, ExchangeOrderType.OTC);

            _otcBook.Add <ExchangeOrder>(order);
        }
Пример #3
0
        private Address FindLender()
        {
            var count = _lenderList.Count();

            if (count > 0)
            {
                var index = Runtime.GetRandomNumber() % count;
                return(_lenderList.Get <Address>(index));
            }

            return(Address.Null);
        }
Пример #4
0
        private int FindAppIndex(string name)
        {
            var count = _apps.Count();

            for (int i = 0; i < count; i++)
            {
                var app = _apps.Get <AppInfo>(i);
                if (app.id == name)
                {
                    return(i);
                }
            }

            return(-1);
        }
Пример #5
0
        private bool UpdatePendingSettle(StorageList list, int index)
        {
            var swap       = list.Get <PendingSettle>(index);
            var prevStatus = swap.status;

            switch (swap.status)
            {
            case SwapStatus.Settle:
            {
                var diff = Timestamp.Now - swap.time;
                if (diff >= 60)
                {
                    swap.settleHash = SettleTransaction(DomainSettings.PlatformName, DomainSettings.RootChainName, swap.sourceHash);
                    if (swap.settleHash != Hash.Null)
                    {
                        swap.status = SwapStatus.Confirm;
                    }
                }
                break;
            }

            case SwapStatus.Confirm:
            {
                var result = this.NexusAPI.GetTransaction(swap.settleHash.ToString());
                if (result is TransactionResult)
                {
                    var tx = (TransactionResult)result;
                    swap.status = SwapStatus.Finished;
                }
                else
                if (result is ErrorResult)
                {
                    var error = ((ErrorResult)result).error;
                    if (error != "pending")
                    {
                        swap.settleHash = Hash.Null;
                        swap.time       = Timestamp.Now;
                        swap.status     = SwapStatus.Settle;
                    }
                }
                break;
            }

            default: return(false);
            }

            if (swap.status == SwapStatus.Finished)
            {
                var settlements = new StorageMap(SettlementTag, this.Storage);
                settlements.Set <Hash, Hash>(swap.sourceHash, swap.destinationHash);
                return(true);
            }

            if (swap.status != prevStatus)
            {
                list.Replace <PendingSettle>(index, swap);
            }

            return(false);
        }
Пример #6
0
        public void TestStorageListWithNestedMap()
        {
            var context = new MemoryStorageContext();

            var map = new StorageMap("map".AsByteArray(), context);

            Assert.IsTrue(map.Count() == 0);

            map.Set(1, "hello");
            map.Set(3, "world");
            var count = map.Count();

            Assert.IsTrue(count == 2);

            var list = new StorageList("list".AsByteArray(), context);

            Assert.IsTrue(list.Count() == 0);

            list.Add(map);

            count = list.Count();
            Assert.IsTrue(count == 1);

            var another = list.Get <StorageMap>(0);

            count = another.Count();
            Assert.IsTrue(count == 2);
        }
Пример #7
0
        // should only be called from inside lock block
        private Hash GetSettleHash(string sourcePlatform, Hash sourceHash)
        {
            var settlements = new StorageMap(SettlementTag, this.Storage);

            if (settlements.ContainsKey <Hash>(sourceHash))
            {
                return(settlements.Get <Hash, Hash>(sourceHash));
            }

            var pendingList = new StorageList(PendingTag, this.Storage);
            var count       = pendingList.Count();

            for (int i = 0; i < count; i++)
            {
                var settlement = pendingList.Get <PendingFee>(i);
                if (settlement.sourceHash == sourceHash)
                {
                    return(settlement.destinationHash);
                }
            }

            var hash = (Hash)Nexus.RootChain.InvokeContract(Nexus.RootStorage, "interop", nameof(InteropContract.GetSettlement), sourcePlatform, sourceHash).ToObject();

            if (hash != Hash.Null && !settlements.ContainsKey <Hash>(sourceHash))
            {
                // This modification should be locked when GetSettleHash() is called from SettleSwap(),
                // so we lock it in SettleSwap().
                settlements.Set <Hash, Hash>(sourceHash, hash);
            }
            return(hash);
        }
Пример #8
0
        public Hash GetSettleHash(string sourcePlatform, Hash sourceHash)
        {
            var settlements = new StorageMap(SettlementTag, this.Storage);

            if (settlements.ContainsKey <Hash>(sourceHash))
            {
                return(settlements.Get <Hash, Hash>(sourceHash));
            }

            var pendingList = new StorageList(PendingTag, this.Storage);
            var count       = pendingList.Count();

            for (int i = 0; i < count; i++)
            {
                var settlement = pendingList.Get <PendingSettle>(i);
                if (settlement.sourceHash == sourceHash)
                {
                    return(settlement.destinationHash);
                }
            }

            var hash = (Hash)Nexus.RootChain.InvokeContract(Nexus.RootStorage, "interop", nameof(InteropContract.GetSettlement), sourcePlatform, sourceHash).ToObject();

            if (hash != Hash.Null && !settlements.ContainsKey <Hash>(sourceHash))
            {
                settlements.Set <Hash, Hash>(sourceHash, hash);
            }
            return(hash);
        }
        public EnergyMaster GetMaster(Address address)
        {
            var count = _mastersList.Count();

            for (int i = 0; i < count; i++)
            {
                var master = _mastersList.Get <EnergyMaster>(i);
                if (master.address == address)
                {
                    return(master);
                }
            }

            return(new EnergyMaster {
                address = Address.Null
            });
        }
Пример #10
0
        public Address GetValidatorByIndex(BigInteger index)
        {
            Runtime.Expect(index >= 0, "invalid validator index");

            var count = _validatorList.Count();

            Runtime.Expect(index < count, "invalid validator index");

            var address = _validatorList.Get <Address>(index);

            return(address);
        }
Пример #11
0
        public Hash GetLatestSaleHash()
        {
            var count = (int)_saleList.Count();

            if (count <= 0)
            {
                return(Hash.Null);
            }

            var index     = count - 1;
            var firstHash = _saleList.Get <Hash>(index);

            return(firstHash);
        }
Пример #12
0
        public void TestStorageList()
        {
            var context = new MemoryStorageContext();
            var list    = new StorageList("test".AsByteArray(), context);

            Assert.IsTrue(list.Count() == 0);

            list.Add("hello");
            list.Add("world");
            Assert.IsTrue(list.Count() == 2);

            list.RemoveAt(0);
            Assert.IsTrue(list.Count() == 1);

            var temp = list.Get <string>(0);

            Assert.IsTrue(temp == "world");

            list.Replace <string>(0, "hello");

            temp = list.Get <string>(0);
            Assert.IsTrue(temp == "hello");
        }
Пример #13
0
        public bool IsExchange(Address address)
        {
            var count = _exchanges.Count();

            for (int i = 0; i < count; i++)
            {
                var exchange = _exchanges.Get <ExchangeProvider>(i);
                if (exchange.address == address)
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #14
0
        public Hash GetBlockHashAtHeight(BigInteger height)
        {
            if (height <= 0)
            {
                throw new ChainException("invalid block height");
            }

            if (height > this.Height)
            {
                return(Hash.Null);
            }

            var hashList = new StorageList(BlockHeightListTag, this.Storage);
            // NOTE chain heights start at 1, but list index start at 0
            var hash = hashList.Get <Hash>(height - 1);

            return(hash);
        }
Пример #15
0
        private IEnumerable <Transaction> ProcessPendingTasks(Block block, OracleReader oracle, BigInteger minimumFee, StorageChangeSetContext changeSet, bool allowModify)
        {
            var taskList  = new StorageList(TaskListTag, changeSet);
            var taskCount = taskList.Count();

            List <Transaction> transactions = null;

            int i = 0;

            while (i < taskCount)
            {
                var taskID = taskList.Get <BigInteger>(i);
                var task   = GetTask(changeSet, taskID);

                Transaction tx;

                var taskResult = ProcessPendingTask(block, oracle, minimumFee, changeSet, allowModify, task, out tx);
                if (taskResult == TaskResult.Running)
                {
                    i++;
                }
                else
                {
                    taskList.RemoveAt <BigInteger>(i);
                }

                if (tx != null)
                {
                    if (transactions == null)
                    {
                        transactions = new List <Transaction>();
                    }

                    transactions.Add(tx);
                }
            }

            if (transactions != null)
            {
                return(transactions);
            }

            return(Enumerable.Empty <Transaction>());
        }
Пример #16
0
        public void TakeOrder(Address from, BigInteger uid)
        {
            Runtime.Expect(Runtime.IsWitness(from), "invalid witness");

            var count = _otcBook.Count();

            for (int i = 0; i < count; i++)
            {
                var order = _otcBook.Get <ExchangeOrder>(i);
                if (order.Uid == uid)
                {
                    throw new NotImplementedException();

                    return;
                }
            }

            Runtime.Expect(false, "order not found");
        }
Пример #17
0
        public void CancelOrder(BigInteger uid)
        {
            Runtime.Expect(_orderMap.ContainsKey <BigInteger>(uid), "order not found");
            var         key       = _orderMap.Get <BigInteger, string>(uid);
            StorageList orderList = _orders.Get <string, StorageList>(key);

            var count = orderList.Count();

            for (int i = 0; i < count; i++)
            {
                var order = orderList.Get <ExchangeOrder>(i);
                if (order.Uid == uid)
                {
                    Runtime.Expect(IsWitness(order.Creator), "invalid witness");

                    orderList.RemoveAt <ExchangeOrder>(i);
                    _orderMap.Remove <BigInteger>(uid);
                    _fills.Remove <BigInteger>(uid);

                    if (_escrows.ContainsKey <BigInteger>(uid))
                    {
                        var leftoverEscrow = _escrows.Get <BigInteger, BigInteger>(uid);
                        if (leftoverEscrow > 0)
                        {
                            var escrowSymbol = order.Side == ExchangeOrderSide.Sell ? order.QuoteSymbol : order.BaseSymbol;
                            Runtime.Nexus.TransferTokens(Runtime, escrowSymbol, this.Address, order.Creator, leftoverEscrow);
                            Runtime.Notify(EventKind.TokenReceive, order.Creator, new TokenEventData()
                            {
                                chainAddress = this.Address, symbol = escrowSymbol, value = leftoverEscrow
                            });
                        }
                    }

                    return;
                }
            }

            // if it reaches here, it means it not found nothing in previous part
            throw new Exception("order not found");
        }
Пример #18
0
        public ExchangeOrder GetExchangeOrder(BigInteger uid)
        {
            Runtime.Expect(_orderMap.ContainsKey <BigInteger>(uid), "order not found");

            var         key       = _orderMap.Get <BigInteger, string>(uid);
            StorageList orderList = _orders.Get <string, StorageList>(key);

            var count = orderList.Count();
            var order = new ExchangeOrder();

            for (int i = 0; i < count; i++)
            {
                order = orderList.Get <ExchangeOrder>(i);
                if (order.Uid == uid)
                {
                    //Runtime.Expect(Runtime.IsWitness(order.Creator), "invalid witness");
                    break;
                }
            }

            return(order);
        }
Пример #19
0
        private PrivacyQueue FetchQueue(string symbol)
        {
            StorageList list = _queues.Get <string, StorageList>(symbol);

            PrivacyQueue queue;

            var count = list.Count();

            if (count > 0)
            {
                var last = list.Get <PrivacyQueue>(count - 1);
                if (last.addresses.Count() < last.size)
                {
                    return(last);
                }
            }

            var id      = (uint)(count + 1);
            var baseKey = $"{symbol}.{id}";

            var addrKey     = $"{baseKey}.addr".AsByteArray();
            var addressList = new StorageList(addrKey, Runtime.ChangeSet);

            addressList.Clear();

            var ringKey  = $"{baseKey}.ring".AsByteArray();
            var ringList = new StorageList(addrKey, Runtime.ChangeSet);

            ringList.Clear();

            queue = new PrivacyQueue()
            {
                addresses = addressList, signatures = ringList, ID = id, size = 3
            };
            list.Add(queue);
            return(queue);
        }
Пример #20
0
        public void SettleTransaction(Address from, string platform, string chain, Hash hash)
        {
            PlatformSwapAddress[] swapAddresses;

            if (platform != DomainSettings.PlatformName)
            {
                Runtime.Expect(Runtime.PlatformExists(platform), "unsupported platform");
                var platformInfo = Runtime.GetPlatformByName(platform);
                swapAddresses = platformInfo.InteropAddresses;
            }
            else
            {
                swapAddresses = null;
            }

            Runtime.Expect(Runtime.IsWitness(from), "invalid witness");
            Runtime.Expect(from.IsUser, "must be user address");

            var chainHashes = _hashes.Get <string, StorageMap>(platform);

            Runtime.Expect(!chainHashes.ContainsKey <Hash>(hash), "hash already seen");

            var interopTx = Runtime.ReadTransactionFromOracle(platform, chain, hash);

            Runtime.Expect(interopTx.Hash == hash, "unxpected hash");

            int swapCount = 0;

            foreach (var transfer in interopTx.Transfers)
            {
                var count = _withdraws.Count();
                var index = -1;
                for (int i = 0; i < count; i++)
                {
                    var entry = _withdraws.Get <InteropWithdraw>(i);
                    if (entry.destination == transfer.destinationAddress && entry.transferAmount == transfer.Value && entry.transferSymbol == transfer.Symbol)
                    {
                        index = i;
                        break;
                    }
                }

                if (index >= 0)
                {
                    Runtime.Expect(transfer.Value > 0, "amount must be positive and greater than zero");

                    Runtime.Expect(Runtime.TokenExists(transfer.Symbol), "invalid token");
                    var token = this.Runtime.GetToken(transfer.Symbol);
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.External), "token must be external");

                    var withdraw = _withdraws.Get <InteropWithdraw>(index);
                    _withdraws.RemoveAt <InteropWithdraw>(index);

                    Runtime.TransferTokens(withdraw.feeSymbol, this.Address, transfer.sourceAddress, withdraw.feeAmount);

                    swapCount++;
                }
                else
                if (swapAddresses != null)
                {
                    foreach (var entry in swapAddresses)
                    {
                        if (transfer.destinationAddress == entry.LocalAddress)
                        {
                            Runtime.Expect(!transfer.sourceAddress.IsNull, "invalid source address");

                            Runtime.Expect(transfer.Value > 0, "amount must be positive and greater than zero");

                            Runtime.Expect(Runtime.TokenExists(transfer.Symbol), "invalid token");
                            var token = this.Runtime.GetToken(transfer.Symbol);

                            Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
                            Runtime.Expect(token.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");
                            Runtime.Expect(token.Flags.HasFlag(TokenFlags.External), "token must be external");

                            Runtime.Expect(transfer.interopAddress.IsUser, "invalid destination address");

                            // TODO support NFT
                            Runtime.SwapTokens(platform, transfer.sourceAddress, Runtime.Chain.Name, transfer.interopAddress, transfer.Symbol, transfer.Value, null, null);
                            //Runtime.Notify(EventKind.TokenSwap, destination, new TokenEventData(token.Symbol, amount, Runtime.Chain.Name));

                            swapCount++;
                            break;
                        }
                    }
                }
            }

            Runtime.Expect(swapCount > 0, "nothing to settle");
            chainHashes.Set <Hash, Hash>(hash, Runtime.Transaction.Hash);
            Runtime.Notify(EventKind.ChainSwap, from, new TransactionSettleEventData(hash, platform, chain));
        }
Пример #21
0
        public void SettleTransaction(Address from, string platform, Hash hash)
        {
            Runtime.Expect(platform != DomainSettings.PlatformName, "must be external platform");
            Runtime.Expect(Runtime.PlatformExists(platform), "unsupported platform");
            var platformInfo = Runtime.GetPlatform(platform);

            Runtime.Expect(Runtime.IsWitness(from), "invalid witness");
            Runtime.Expect(from.IsUser, "must be user address");

            var chainHashes = _hashes.Get <string, StorageSet>(platform);

            Runtime.Expect(!chainHashes.Contains <Hash>(hash), "hash already seen");

            var interopTx = Runtime.ReadTransactionFromOracle(platform, DomainSettings.RootChainName, hash);

            Runtime.Expect(interopTx.Platform == platform, "unxpected platform name");
            Runtime.Expect(interopTx.Hash == hash, "unxpected hash");

            int swapCount = 0;

            foreach (var evt in interopTx.Events)
            {
                if (evt.Kind == EventKind.TokenReceive && evt.Address == platformInfo.Address)
                {
                    Runtime.Expect(!evt.Address.IsNull, "invalid source address");

                    var transfer = evt.GetContent <TokenEventData>();
                    Runtime.Expect(transfer.value > 0, "amount must be positive and greater than zero");

                    Runtime.Expect(Runtime.TokenExists(transfer.symbol), "invalid token");
                    var token = this.Runtime.GetToken(transfer.symbol);

                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.External), "token must be external");

                    Address destination = Address.Null;
                    foreach (var otherEvt in interopTx.Events)
                    {
                        if (otherEvt.Kind == EventKind.TokenSend)
                        {
                            var otherTransfer = otherEvt.GetContent <TokenEventData>();
                            if (otherTransfer.chainAddress == transfer.chainAddress && otherTransfer.symbol == transfer.symbol)
                            {
                                destination = otherEvt.Address;
                                break;
                            }
                        }
                    }

                    if (destination.IsInterop)
                    {
                        destination = GetLink(destination, DomainSettings.PlatformName);
                    }
                    else
                    {
                        Runtime.Expect(destination.IsUser, "invalid destination address");
                    }

                    Runtime.Expect(Runtime.TransferTokens(transfer.symbol, platformInfo.Address, destination, transfer.value), "mint failed");
                    Runtime.Notify(EventKind.TokenReceive, destination, new TokenEventData()
                    {
                        chainAddress = platformInfo.Address, value = transfer.value, symbol = transfer.symbol
                    });

                    swapCount++;
                    break;
                }

                if (evt.Kind == EventKind.TokenClaim)
                {
                    var destination = evt.Address;
                    Runtime.Expect(!destination.IsNull, "invalid destination");

                    var transfer = evt.GetContent <TokenEventData>();
                    Runtime.Expect(transfer.value > 0, "amount must be positive and greater than zero");

                    Runtime.Expect(Runtime.TokenExists(transfer.symbol), "invalid token");
                    var token = this.Runtime.GetToken(transfer.symbol);
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");
                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.External), "token must be external");

                    var count = _withdraws.Count();
                    var index = -1;
                    for (int i = 0; i < count; i++)
                    {
                        var entry = _withdraws.Get <InteropWithdraw>(i);
                        if (entry.destination == destination && entry.transferAmount == transfer.value && entry.transferSymbol == transfer.symbol)
                        {
                            index = i;
                            break;
                        }
                    }

                    Runtime.Expect(index >= 0, "invalid withdraw, possible leak found");

                    var withdraw = _withdraws.Get <InteropWithdraw>(index);
                    Runtime.Expect(withdraw.broker == from, "invalid broker");

                    _withdraws.RemoveAt <InteropWithdraw>(index);

                    Runtime.Expect(Runtime.TransferTokens(withdraw.feeSymbol, this.Address, from, withdraw.feeAmount), "fee payment failed");

                    Runtime.Notify(EventKind.TokenReceive, from, new TokenEventData()
                    {
                        chainAddress = this.Runtime.Chain.Address, value = withdraw.feeAmount, symbol = withdraw.feeSymbol
                    });
                    Runtime.Notify(EventKind.TokenReceive, destination, new TokenEventData()
                    {
                        chainAddress = platformInfo.Address, value = withdraw.transferAmount, symbol = withdraw.transferSymbol
                    });

                    swapCount++;
                    break;
                }
            }

            Runtime.Expect(swapCount > 0, "nothing to settle");
            chainHashes.Add <Hash>(hash);
        }
Пример #22
0
        public void Queue(Address from, string symbol, BigInteger tableID)
        {
            Runtime.Expect(IsWitness(from), "invalid witness");
            Runtime.Expect(tableID == 0, "invalid table");

            var token = Runtime.Nexus.GetTokenInfo(Nexus.StakingTokenSymbol);

            Runtime.Expect(symbol == token.Symbol, "invalid symbol");

            Runtime.Expect(!_matchMap.ContainsKey <Address>(from), "already in match");

            var fee = GetTableFee(tableID);

            Runtime.Expect(Runtime.Nexus.TransferTokens(token.Symbol, this.Storage, Runtime.Chain, from, Runtime.Chain.Address, fee), "fee transfer failed");

            int queueIndex = -1;
            var count      = _queue.Count();

            for (var i = 0; i < count; i++)
            {
                var temp = _queue.Get <CasinoQueue>(i);
                if (temp.table == tableID)
                {
                    queueIndex = i;
                    break;
                }
            }

            if (queueIndex >= 0)
            {
                var other = _queue.Get <CasinoQueue>(queueIndex);

                _matchCount++;

                _matchMap.Set <Address, BigInteger>(from, _matchCount);
                _matchMap.Set <Address, BigInteger>(other.player, _matchCount);

                Runtime.Notify(EventKind.CasinoTableStart, from, other.player);
                Runtime.Notify(EventKind.CasinoTableStart, other.player, from);

                var match = new CasinoMatch()
                {
                    amount       = fee * 2,
                    host         = other.player,
                    opponent     = from,
                    matchTurn    = 0,
                    hostTurn     = 0,
                    opponentTurn = 0,
                    timestamp    = Runtime.Time,
                    cards        = new byte[52],
                };

                for (int j = 0; j < 2; j++)
                {
                    for (int i = 0; i < 2; i++)
                    {
                        var card = DrawCard(match.cards, (byte)(i + 1));
                        Runtime.Expect(card >= 0, "card draw failed");
                        Runtime.Notify(EventKind.CasinoTableCard, i == 0 ? match.host : match.opponent, i);
                    }
                }

                _matchData.Set <BigInteger, CasinoMatch>(_matchCount, match);
            }
            else
            {
                var entry = new CasinoQueue()
                {
                    player = from, amount = fee, symbol = symbol, table = tableID
                };
                _queue.Add <CasinoQueue>(entry);
                Runtime.Notify(EventKind.CasinoTableQueued, from, tableID);
            }
        }
Пример #23
0
        public void Update()
        {
            try
            {
                if (this.platforms == null)
                {
                    if (!Nexus.HasGenesis)
                    {
                        return;
                    }

                    var platforms = Nexus.GetPlatforms(Nexus.RootStorage);
                    this.platforms = platforms.Select(x => Nexus.GetPlatformInfo(Nexus.RootStorage, x)).ToArray();

                    if (this.platforms.Length == 0)
                    {
                        Logger.Warning("No interop platforms found. Make sure that the Nexus was created correctly.");
                        return;
                    }

                    if (IsPlatformSupported(SwapPlatformChain.Neo))
                    {
                        InitSwapper(SwapPlatformChain.Neo, new NeoInterop(this, neoAPI,
                                                                          _interopBlocks[SwapPlatformChain.Neo], Settings.Oracle.NeoQuickSync));
                    }

                    if (IsPlatformSupported(SwapPlatformChain.Ethereum))
                    {
                        InitSwapper(SwapPlatformChain.Ethereum, new EthereumInterop(this, ethAPI,
                                                                                    _interopBlocks[SwapPlatformChain.Ethereum], Nexus.GetPlatformTokenHashes(EthereumWallet.EthereumPlatform,
                                                                                                                                                             Nexus.RootStorage).Select(x => x.ToString().Substring(0, 40)).ToArray(), Settings.Oracle.EthConfirmations));
                    }

                    if (IsPlatformSupported(SwapPlatformChain.BSC) && Nexus.PlatformExists(Nexus.RootStorage, BSCWallet.BSCPlatform))
                    {
                        InitSwapper(SwapPlatformChain.BSC, new BSCInterop(this, bscAPI, _interopBlocks[SwapPlatformChain.BSC],
                                                                          Nexus.GetPlatformTokenHashes(BSCWallet.BSCPlatform, Nexus.RootStorage).Select(x =>
                                                                                                                                                        x.ToString().Substring(0, 40)).ToArray(), Settings.Oracle.EthConfirmations));
                    }

                    Logger.Message("Available swap addresses:");
                    foreach (var x in SwapAddresses)
                    {
                        Logger.Message("platform: " + x.Key + " address: " + string.Join(", ", x.Value));
                    }
                }

                if (this.platforms.Length == 0)
                {
                    return;
                }
                else
                {
                    if (_taskMap.Count == 0)
                    {
                        foreach (var platform in Settings.Oracle.SwapPlatforms)
                        {
                            if (platform.Chain != SwapPlatformChain.Phantasma) // TODO is this IF necessary?
                            {
                                _taskMap.Add(platform.Chain, null);
                            }
                        }
                    }
                }

                lock (StateModificationLock)
                {
                    var pendingList = new StorageList(PendingTag, this.Storage);

                    int i     = 0;
                    var count = pendingList.Count();

                    while (i < count)
                    {
                        var settlement = pendingList.Get <PendingFee>(i);
                        if (UpdatePendingSettle(pendingList, i))
                        {
                            pendingList.RemoveAt(i);
                            count--;
                        }
                        else
                        {
                            i++;
                        }
                    }
                }

                ProcessCompletedTasks();

                for (var j = 0; j < _taskMap.Count; j++)
                {
                    var platform = _taskMap.Keys.ElementAt(j);

                    var task = _taskMap[platform];
                    if (task == null)
                    {
                        if (_swappers.TryGetValue(platform, out ChainSwapper finder))
                        {
                            _taskMap[platform] = new Task <IEnumerable <PendingSwap> >(() =>
                            {
                                return(finder.Update());
                            });
                        }
                    }
                }

                // start new tasks
                foreach (var entry in _taskMap)
                {
                    var task = entry.Value;
                    if (task != null && task.Status.Equals(TaskStatus.Created))
                    {
                        task.ContinueWith(t => { Console.WriteLine($"===> task {task.ToString()} failed"); }, TaskContinuationOptions.OnlyOnFaulted);
                        task.Start();
                    }
                }
            }
            catch (Exception e)
            {
                var logMessage = "TokenSwapper.Update() exception caught:\n" + e.Message;
                var inner      = e.InnerException;
                while (inner != null)
                {
                    logMessage += "\n---> " + inner.Message + "\n\n" + inner.StackTrace;
                    inner       = inner.InnerException;
                }
                logMessage += "\n\n" + e.StackTrace;

                Logger.Error(logMessage);
            }
        }
Пример #24
0
        public void Update()
        {
            if (this.platforms == null)
            {
                if (!Nexus.HasGenesis)
                {
                    return;
                }

                var platforms = Nexus.GetPlatforms(Nexus.RootStorage);
                this.platforms = platforms.Select(x => Nexus.GetPlatformInfo(Nexus.RootStorage, x)).ToArray();

                if (this.platforms.Length == 0)
                {
                    logger.Warning("No interop platforms found. Make sure that the Nexus was created correctly.");
                    return;
                }

                _finders["neo"] = new NeoInterop(this, wifs["neo"], interopBlocks["neo"], neoscanAPI, logger);
            }

            if (this.platforms.Length == 0)
            {
                return;
            }

            var pendingList = new StorageList(PendingTag, this.Storage);
            int i           = 0;
            var count       = pendingList.Count();

            while (i < count)
            {
                var settlement = pendingList.Get <PendingSettle>(i);
                if (UpdatePendingSettle(pendingList, i))
                {
                    pendingList.RemoveAt <PendingSettle>(i);
                    count--;
                }
                else
                {
                    i++;
                }
            }

            foreach (var finder in _finders.Values)
            {
                var swaps = finder.Update();

                foreach (var swap in swaps)
                {
                    if (_pendingSwaps.ContainsKey(swap.hash))
                    {
                        logger.Message($"Already known swap, ignore {finder.PlatformName} swap: {swap.source} => {swap.destination}");
                        continue;
                    }

                    logger.Message($"Detected {finder.PlatformName} swap: {swap.source} => {swap.destination} hash: {swap.hash}");
                    _pendingSwaps[swap.hash] = swap;
                    MapSwap(swap.source, swap.hash);
                    MapSwap(swap.destination, swap.hash);
                }
            }
        }
Пример #25
0
        public void SettleTransaction(Address from, string platform, string chain, Hash hash)
        {
            PlatformSwapAddress[] swapAddresses;

            if (platform != DomainSettings.PlatformName)
            {
                Runtime.Expect(Runtime.PlatformExists(platform), "unsupported platform");
                var platformInfo = Runtime.GetPlatformByName(platform);
                swapAddresses = platformInfo.InteropAddresses;
            }
            else
            {
                swapAddresses = null;
            }

            Runtime.Expect(Runtime.IsWitness(from), "invalid witness");
            Runtime.Expect(from.IsUser, "must be user address");

            var chainHashes = _hashes.Get <string, StorageMap>(platform);

            Runtime.Expect(!chainHashes.ContainsKey <Hash>(hash), "hash already seen");

            var interopTx = Runtime.ReadTransactionFromOracle(platform, chain, hash);

            Runtime.Expect(interopTx.Hash == hash, "unxpected hash");

            int swapCount = 0;

            foreach (var transfer in interopTx.Transfers)
            {
                var count = _withdraws.Count();
                var index = -1;
                for (int i = 0; i < count; i++)
                {
                    var entry = _withdraws.Get <InteropWithdraw>(i);
                    if (entry.destination == transfer.destinationAddress && entry.transferAmount == transfer.Value && entry.transferSymbol == transfer.Symbol)
                    {
                        index = i;
                        break;
                    }
                }

                if (index >= 0)
                {
                    Runtime.Expect(Runtime.TokenExists(transfer.Symbol), "invalid token");
                    var token = this.Runtime.GetToken(transfer.Symbol);

                    if (Runtime.ProtocolVersion >= 4)
                    {
                        if (token.Flags.HasFlag(TokenFlags.Fungible))
                        {
                            Runtime.Expect(transfer.Value > 0, "amount must be positive and greater than zero");
                        }
                        else
                        {
                            Runtime.Expect(Runtime.NFTExists(transfer.Symbol, transfer.Value), $"nft {transfer.Value} must exist");
                        }
                    }
                    else
                    {
                        Runtime.Expect(transfer.Value > 0, "amount must be positive and greater than zero");
                        Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
                    }

                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");

                    var withdraw = _withdraws.Get <InteropWithdraw>(index);
                    _withdraws.RemoveAt <InteropWithdraw>(index);

                    if (Runtime.ProtocolVersion >= 3)
                    {
                        var org = Runtime.GetOrganization(DomainSettings.ValidatorsOrganizationName);
                        Runtime.Expect(org.IsMember(from), $"{from.Text} is not a validator node");
                        Runtime.TransferTokens(withdraw.feeSymbol, this.Address, from, withdraw.feeAmount);
                    }
                    else
                    {
                        Runtime.TransferTokens(withdraw.feeSymbol, this.Address, transfer.sourceAddress, withdraw.feeAmount);
                    }

                    swapCount++;
                }
                else
                if (swapAddresses != null)
                {
                    foreach (var entry in swapAddresses)
                    {
                        if (transfer.destinationAddress == entry.LocalAddress)
                        {
                            Runtime.Expect(!transfer.sourceAddress.IsNull, "invalid source address");

                            // Here we detect if this transfer occurs between two swap addresses
                            var isInternalTransfer = Runtime.IsPlatformAddress(transfer.sourceAddress);

                            if (!isInternalTransfer)
                            {
                                Runtime.Expect(Runtime.TokenExists(transfer.Symbol), "invalid token");
                                var token = this.Runtime.GetToken(transfer.Symbol);

                                if (Runtime.ProtocolVersion >= 4)
                                {
                                    if (token.Flags.HasFlag(TokenFlags.Fungible))
                                    {
                                        Runtime.Expect(transfer.Value > 0, "amount must be positive and greater than zero");
                                    }
                                    else
                                    {
                                        Runtime.Expect(Runtime.NFTExists(transfer.Symbol, transfer.Value), $"nft {transfer.Value} must exist");
                                    }
                                }
                                else
                                {
                                    Runtime.Expect(transfer.Value > 0, "amount must be positive and greater than zero");
                                    Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");
                                }


                                Runtime.Expect(token.Flags.HasFlag(TokenFlags.Transferable), "token must be transferable");

                                Runtime.Expect(transfer.interopAddress.IsUser, "invalid destination address");

                                Runtime.SwapTokens(platform, transfer.sourceAddress, Runtime.Chain.Name, transfer.interopAddress, transfer.Symbol, transfer.Value);


                                if (Runtime.ProtocolVersion >= 4 && !token.Flags.HasFlag(TokenFlags.Fungible))
                                {
                                    var externalNft = Runtime.ReadNFTFromOracle(platform, transfer.Symbol, transfer.Value);
                                    var ram         = Serialization.Serialize(externalNft);

                                    var localNft = Runtime.ReadToken(transfer.Symbol, transfer.Value);
                                    Runtime.WriteToken(transfer.Symbol, transfer.Value, ram);
                                }

                                swapCount++;
                            }

                            break;
                        }
                    }
                }
            }

            Runtime.Expect(swapCount > 0, "nothing to settle");
            chainHashes.Set <Hash, Hash>(hash, Runtime.Transaction.Hash);
            Runtime.Notify(EventKind.ChainSwap, from, new TransactionSettleEventData(hash, platform, chain));
        }
Пример #26
0
        public void Update()
        {
            try
            {
                if (this.platforms == null)
                {
                    if (!Nexus.HasGenesis)
                    {
                        return;
                    }

                    var platforms = Nexus.GetPlatforms(Nexus.RootStorage);
                    this.platforms = platforms.Select(x => Nexus.GetPlatformInfo(Nexus.RootStorage, x)).ToArray();

                    if (this.platforms.Length == 0)
                    {
                        Logger.Warning("No interop platforms found. Make sure that the Nexus was created correctly.");
                        return;
                    }

                    _swappers["neo"]     = new NeoInterop(this, neoAPI, interopBlocks["neo"], Settings.Oracle.NeoQuickSync);
                    SwapAddresses["neo"] = _swappers["neo"].LocalAddress;

                    _swappers["ethereum"]     = new EthereumInterop(this, ethAPI, interopBlocks["ethereum"], Nexus.GetPlatformTokenHashes("ethereum", Nexus.RootStorage).Select(x => x.ToString().Substring(0, 40)).ToArray(), Settings.Oracle.EthConfirmations);
                    SwapAddresses["ethereum"] = _swappers["ethereum"].LocalAddress;

                    Logger.Message("Available swap addresses:");
                    foreach (var x in SwapAddresses)
                    {
                        Logger.Message("platform: " + x.Key + " address: " + x.Value);
                    }
                }

                if (this.platforms.Length == 0)
                {
                    return;
                }
                else
                {
                    if (taskDict.Count == 0)
                    {
                        foreach (var platform in this.platforms)
                        {
                            taskDict.Add(platform.Name, null);
                        }
                    }
                }

                lock (StateModificationLock)
                {
                    var pendingList = new StorageList(PendingTag, this.Storage);

                    int i     = 0;
                    var count = pendingList.Count();

                    while (i < count)
                    {
                        var settlement = pendingList.Get <PendingFee>(i);
                        if (UpdatePendingSettle(pendingList, i))
                        {
                            pendingList.RemoveAt(i);
                            count--;
                        }
                        else
                        {
                            i++;
                        }
                    }
                }

                ProcessCompletedTasks();

                for (var j = 0; j < taskDict.Count; j++)
                {
                    var platform = taskDict.Keys.ElementAt(j);
                    var task     = taskDict[platform];
                    if (task == null)
                    {
                        if (_swappers.TryGetValue(platform, out ChainSwapper finder))
                        {
                            taskDict[platform] = new Task <IEnumerable <PendingSwap> >(() =>
                            {
                                return(finder.Update());
                            });
                        }
                    }
                }

                // start new tasks
                foreach (var entry in taskDict)
                {
                    var task = entry.Value;
                    if (task != null && task.Status.Equals(TaskStatus.Created))
                    {
                        task.ContinueWith(t => { Console.WriteLine($"===> task {task.ToString()} failed"); }, TaskContinuationOptions.OnlyOnFaulted);
                        task.Start();
                    }
                }
            }
            catch (Exception e)
            {
                var logMessage = "TokenSwapper.Update() exception caught:\n" + e.Message;
                var inner      = e.InnerException;
                while (inner != null)
                {
                    logMessage += "\n---> " + inner.Message + "\n\n" + inner.StackTrace;
                    inner       = inner.InnerException;
                }
                logMessage += "\n\n" + e.StackTrace;

                Logger.Error(logMessage);
            }
        }