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) { var baseBalance = Runtime.GetBalance(order.BaseSymbol, this.Address); Runtime.Expect(baseBalance >= order.Price, "invalid seller amount"); var quoteBalance = Runtime.GetBalance(order.QuoteSymbol, from); Runtime.Expect(quoteBalance >= order.Amount, "invalid buyer amount"); Runtime.TransferTokens(order.BaseSymbol, this.Address, from, order.Price); Runtime.TransferTokens(order.QuoteSymbol, from, order.Creator, order.Amount); _otcBook.RemoveAt(i); return; } } Runtime.Expect(false, "order not found"); }
// migrates the full stake from one address to other public void Migrate(Address from, Address to) { Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(to.IsUser, "destination must be user address"); var targetStake = _stakes.Get <Address, EnergyAction>(to); Runtime.Expect(targetStake.totalAmount == 0, "Tried to migrate to an account that's already staking"); //migrate stake var sourceStake = _stakes.Get <Address, EnergyAction>(from); _stakes.Set(to, sourceStake); _stakes.Remove(from); //migrate master claim var masterAccountThreshold = GetMasterThreshold(); if (sourceStake.totalAmount >= masterAccountThreshold) { var count = _mastersList.Count(); var index = -1; Timestamp claimDate = Runtime.Time; for (int i = 0; i < count; i++) { var master = _mastersList.Get <EnergyMaster>(i); if (master.address == from) { index = i; claimDate = master.claimDate; break; } } Runtime.Expect(index >= 0, "Expected this address to be a master"); _mastersList.RemoveAt <EnergyMaster>(index); _mastersList.Add(new EnergyMaster() { address = to, claimDate = claimDate }); } //migrate voting power var votingLogbook = _voteHistory.Get <Address, StorageList>(from); votingLogbook.Add(to); votingLogbook.Remove(from); }
public void StopLend(Address from) { Runtime.Expect(IsWitness(from), "invalid witness"); Runtime.Expect(IsLender(from), "not a lender"); int index = -1; var count = _lenderList.Count(); for (int i = 0; i < count; i++) { var entry = _lenderList.Get <Address>(i); if (entry == from) { index = i; break; } } Runtime.Expect(index >= 0, "not lending"); _lenderList.RemoveAt <Address>(index); _lenderMap.Remove <Address>(from); Runtime.Notify(EventKind.AddressUnlink, from, Runtime.Chain.Address); }
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>()); }
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"); }
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"); }
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); } } }
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); } }
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)); }
public BigInteger Unstake(Address from, BigInteger amount) { Runtime.Expect(IsWitness(from), "witness failed"); if (!_stakes.ContainsKey <Address>(from)) { return(0); } var stake = _stakes.Get <Address, EnergyAction>(from); if (stake.timestamp.Value == 0) // failsafe, should never happen { return(0); } var diff = Runtime.Time - stake.timestamp; var days = diff / 86400; // convert seconds to days Runtime.Expect(days >= 1, "waiting period required"); var token = Runtime.Nexus.GetTokenInfo(Nexus.StakingTokenSymbol); var balances = Runtime.Chain.GetTokenBalances(token.Symbol); var balance = balances.Get(this.Storage, Runtime.Chain.Address); Runtime.Expect(balance >= amount, "not enough balance"); Runtime.Expect(stake.totalAmount >= amount, "tried to unstake more than what was staked"); Runtime.Expect(balances.Subtract(this.Storage, Runtime.Chain.Address, amount), "balance subtract failed"); Runtime.Expect(balances.Add(this.Storage, from, amount), "balance add failed"); stake.totalAmount -= amount; var unclaimedPartials = GetLastAction(from).unclaimedPartials; if (stake.totalAmount == 0 && unclaimedPartials == 0) { _stakes.Remove(from); _voteHistory.Remove(from); } else { var entry = new EnergyAction() { unclaimedPartials = unclaimedPartials, totalAmount = stake.totalAmount, timestamp = this.Runtime.Time, }; _stakes.Set(from, entry); RemoveVotingPower(from, amount); } if (stake.totalAmount < MasterAccountThreshold) { var count = _mastersList.Count(); var index = -1; for (int i = 0; i < count; i++) { var master = _mastersList.Get <EnergyMaster>(i); if (master.address == from) { index = i; break; } } if (index >= 0) { var penalizationDate = GetMasterClaimDateFromReference(1, _mastersList.Get <EnergyMaster>(index).claimDate); _mastersList.RemoveAt <EnergyMaster>(index); Runtime.Notify(EventKind.MasterDemote, from, penalizationDate); } } Runtime.Notify(EventKind.TokenUnstake, from, new TokenEventData() { chainAddress = Runtime.Chain.Address, symbol = token.Symbol, value = amount }); return(amount); }
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); } }
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); }
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)); }
public override void Fill(float contentPos) { float psDiff = contentPos + headOffset; float peDiff = psDiff + currentContentSize - paddedSize; float psEntryOffset = entry[0].info.size; float peEntryOffset = entry[entry.Count - 1].info.size; int totalCount = indexOffset + currentCount; bool sizeChanged = false; Entry <T> e = null; //Debug.Log($"posOffset {contentPosOffset} psDiff {psDiff} ps {psEntryOffset}"); if (totalCount == targetCount && contentPos < 0) { //nothing } else if (psDiff < 0 && -psDiff >= psEntryOffset + recyclePadding) { //Debug.Log($"recycle head psDiff {psDiff} ps {psEntryOffset}"); //recycle head indexOffset += elementPerLine; currentCount -= elementPerLine; for (int r = 0; r < elementPerLine; ++r) { SwitchT(entry[r].item, false); } entry.RemoveAt(0, elementPerLine); headOffset += psEntryOffset; currentContentSize -= psEntryOffset; } else if (psDiff > 0 && indexOffset > 0) { //Debug.Log($"add head psDiff {psDiff} ps {psEntryOffset}"); //add head indexOffset -= elementPerLine; currentCount += elementPerLine; entry.AddTo(0, elementPerLine); for (int r = 0; r < elementPerLine; ++r) { e = ActivateEntry(entry[r]); e.info = FillT(indexOffset + r, e.item); e.transform.anchoredPosition = Repos(r, -e.info.size - currentContentSize); e.transform.name = (indexOffset + r).ToString(); } headOffset -= e.info.size; currentContentSize += e.info.size; } if (indexOffset == 0 && contentPos > 0) { //nothing } else if (peDiff > 0 && peDiff >= peEntryOffset + recyclePadding) { //Debug.Log($"recycle tail peDiff {peDiff} pe {peEntryOffset}"); sizeChanged = true; //recycle tail for (int r = 0; r < tailCount; ++r) { SwitchT((e = entry.RemoveAt(entry.Count - 1)).item, false); } //Debug.Log($"recycled {tailCount}"); currentCount -= tailCount; tailCount = elementPerLine; currentContentSize -= peEntryOffset; } else if (peDiff < 0 && totalCount < targetCount) { //Debug.Log($"add tail peDiff {peDiff} pe {peEntryOffset}"); sizeChanged = true; //add tail tailCount = Mathf.Min(targetCount - totalCount, elementPerLine); for (int r = 0; r < tailCount; ++r) { e = ActivateEntry(entry.Add()); e.info = FillT(totalCount + r, e.item); e.transform.anchoredPosition = Repos(r, 0); e.transform.name = (totalCount + r).ToString(); } //Debug.Log($"added {tailCount} {totalCount} {targetCount} {e.offset}"); currentCount += tailCount; currentContentSize += e.info.size; } if (sizeChanged) { RefreshContentSize(); } }