// NFT version internal bool BurnToken(string symbol, StorageContext storage, Address target, BigInteger tokenID) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } var chain = RootChain; var supply = new SupplySheet(symbol, chain, this); if (!supply.Burn(storage, 1)) { return(false); } var ownerships = new OwnershipSheet(symbol); if (!ownerships.Take(storage, target, tokenID)) { return(false); } return(true); }
private void SynchronizeSupplies(Dictionary <string, BigInteger> synchMap) { foreach (var entry in synchMap) { var symbol = entry.Key; var balance = entry.Value; if (balance == 0) // usually will happen due to token receive and send in same transaction { continue; } var parentName = Nexus.GetParentChainByName(this.Name); var parentChain = Nexus.FindChainByName(parentName); if (parentChain != null) { var parentSupplies = new SupplySheet(symbol, parentChain, Nexus); parentSupplies.Synch(parentChain.Storage, this.Name, balance); } var childrenNames = this.Nexus.GetChildChainsByName(this.Name); foreach (var childName in childrenNames) { var childChain = Nexus.FindChainByName(childName); var childSupplies = new SupplySheet(symbol, childChain, Nexus); childSupplies.Synch(childChain.Storage, this.Name, balance); } } }
// NFT version internal bool MintToken(string symbol, StorageContext storage, Chain chain, Address target, BigInteger tokenID) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } var supply = new SupplySheet(symbol, chain, this); if (!supply.Mint(storage, 1, tokenInfo.MaxSupply)) { return(false); } var ownerships = new OwnershipSheet(symbol); if (!ownerships.Give(storage, target, tokenID)) { return(false); } EditNFTLocation(symbol, tokenID, chain.Address, target); return(true); }
internal bool BurnTokens(string symbol, StorageContext storage, Chain chain, Address target, BigInteger amount) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (!tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } if (amount <= 0) { return(false); } var supply = new SupplySheet(symbol, chain, this); if (tokenInfo.IsCapped && !supply.Burn(storage, amount)) { return(false); } var balances = new BalanceSheet(symbol); if (!balances.Subtract(storage, target, amount)) { return(false); } return(true); }
internal void InitSupplySheet(Token token, BigInteger maxSupply) { Throw.If(!token.IsCapped, "should be capped"); Throw.If(_tokenSupplies.ContainsKey(token), "supply sheet already created"); var sheet = new SupplySheet(0, 0, maxSupply); _tokenSupplies[token] = sheet; }
public BigInteger GetTokenSupply(StorageContext storage, string symbol) { if (!TokenExists(symbol)) { throw new ChainException($"Token does not exist ({symbol})"); } var supplies = new SupplySheet(symbol, RootChain, this); return(supplies.GetTotal(storage)); }
// TODO investigate the necessity of having this method internal void InitSupplySheet(string tokenSymbol, BigInteger maxSupply) { var tokenInfo = Nexus.GetTokenInfo(tokenSymbol); Throw.If(!tokenInfo.IsCapped, "should be capped"); Throw.If(_tokenSupplies.ContainsKey(tokenSymbol), "supply sheet already created"); var sheet = new SupplySheet(0, 0, maxSupply); _tokenSupplies[tokenSymbol] = sheet; }
internal bool BurnTokens(RuntimeVM runtimeVM, string symbol, Address target, BigInteger amount) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (!tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } if (amount <= 0) { return(false); } var supply = new SupplySheet(symbol, runtimeVM.Chain, this); if (tokenInfo.IsCapped && !supply.Burn(runtimeVM.ChangeSet, amount)) { return(false); } var balances = new BalanceSheet(symbol); if (!balances.Subtract(runtimeVM.ChangeSet, target, amount)) { return(false); } var tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerBurn, target, amount); if (!tokenTriggerResult) { return(false); } var accountScript = this.LookUpAddressScript(target); var accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerBurn, target, amount); if (!accountTriggerResult) { return(false); } return(true); }
// NFT version internal bool MintToken(RuntimeVM runtimeVM, string symbol, Address target, BigInteger tokenID) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } var supply = new SupplySheet(symbol, runtimeVM.Chain, this); if (!supply.Mint(runtimeVM.ChangeSet, 1, tokenInfo.MaxSupply)) { return(false); } var ownerships = new OwnershipSheet(symbol); if (!ownerships.Give(runtimeVM.ChangeSet, target, tokenID)) { return(false); } var tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerMint, target, tokenID); if (!tokenTriggerResult) { return(false); } var accountScript = this.LookUpAddressScript(target); var accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerMint, target, tokenID); if (!accountTriggerResult) { return(false); } EditNFTLocation(symbol, tokenID, runtimeVM.Chain.Address, target); return(true); }
// NFT version internal bool BurnToken(RuntimeVM runtimeVM, string symbol, Address target, BigInteger tokenID) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } var chain = RootChain; var supply = new SupplySheet(symbol, chain, this); if (!supply.Burn(runtimeVM.ChangeSet, 1)) { return(false); } var ownerships = new OwnershipSheet(symbol); if (!ownerships.Take(runtimeVM.ChangeSet, target, tokenID)) { return(false); } var tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerBurn, target, tokenID); if (!tokenTriggerResult) { return(false); } var accountScript = this.LookUpAddressScript(target); var accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerBurn, target, tokenID); if (!accountTriggerResult) { return(false); } return(true); }
internal SupplySheet GetTokenSupplies(Token token) { Throw.If(!token.IsCapped, "should be capped"); if (_tokenSupplies.ContainsKey(token)) { return(_tokenSupplies[token]); } Throw.If(this.ParentChain == null, "supply sheet not created"); var parentSupplies = this.ParentChain.GetTokenSupplies(token); var sheet = new SupplySheet(parentSupplies.LocalBalance, 0, token.MaxSupply); _tokenSupplies[token] = sheet; return(sheet); }
public void SendToken(Address targetChainAddress, Address from, Address to, string symbol, BigInteger tokenID) { Runtime.Expect(IsWitness(from), "invalid witness"); Runtime.Expect(IsAddressOfParentChain(targetChainAddress) || IsAddressOfChildChain(targetChainAddress), "source must be parent or child chain"); Runtime.Expect(!to.IsInterop, "destination cannot be interop address"); var targetChain = this.Runtime.Nexus.FindChainByAddress(targetChainAddress); Runtime.Expect(this.Runtime.Nexus.TokenExists(symbol), "invalid token"); var tokenInfo = this.Runtime.Nexus.GetTokenInfo(symbol); Runtime.Expect(!tokenInfo.Flags.HasFlag(TokenFlags.Fungible), "must be non-fungible token"); if (tokenInfo.IsCapped()) { var supplies = new SupplySheet(symbol, this.Runtime.Chain, Runtime.Nexus); BigInteger amount = 1; if (IsAddressOfParentChain(targetChainAddress)) { Runtime.Expect(supplies.MoveToParent(this.Storage, amount), "source supply check failed"); } else // child chain { Runtime.Expect(supplies.MoveToChild(this.Storage, this.Runtime.Chain.Name, amount), "source supply check failed"); } } Runtime.Expect(Runtime.Nexus.TransferToken(Runtime, symbol, from, targetChainAddress, tokenID), "take token failed"); Runtime.Notify(EventKind.TokenBurn, from, new TokenEventData() { symbol = symbol, value = tokenID, chainAddress = Runtime.Chain.Address }); Runtime.Notify(EventKind.TokenEscrow, to, new TokenEventData() { symbol = symbol, value = tokenID, chainAddress = targetChainAddress }); }
private void DoSettlement(Chain sourceChain, Address targetAddress, TokenEventData data) { var symbol = data.symbol; var value = data.value; Runtime.Expect(value > 0, "value must be greater than zero"); Runtime.Expect(targetAddress != Address.Null, "target must not be null"); Runtime.Expect(this.Runtime.Nexus.TokenExists(symbol), "invalid token"); var tokenInfo = this.Runtime.Nexus.GetTokenInfo(symbol); if (tokenInfo.IsCapped) { var sourceSupplies = new SupplySheet(symbol, sourceChain, Runtime.Nexus); var targetSupplies = new SupplySheet(symbol, this.Runtime.Chain, Runtime.Nexus); if (IsAddressOfParentChain(sourceChain.Address)) { Runtime.Expect(targetSupplies.MoveFromParent(this.Storage, value), "target supply check failed"); } else // child chain { Runtime.Expect(targetSupplies.MoveFromChild(this.Storage, this.Runtime.Chain.Name, value), "target supply check failed"); } } if (tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { Runtime.Expect(Runtime.Nexus.MintTokens(symbol, this.Storage, Runtime.Chain, targetAddress, value), "mint failed"); } else { Runtime.Expect(Runtime.Nexus.MintToken(symbol, this.Storage, Runtime.Chain, targetAddress, value), "mint failed"); } Runtime.Notify(EventKind.TokenReceive, targetAddress, new TokenEventData() { symbol = symbol, value = value, chainAddress = sourceChain.Address }); }
public void SendTokens(Address targetChainAddress, Address from, Address to, string symbol, BigInteger amount) { Runtime.Expect(IsWitness(from), "invalid witness"); Runtime.Expect(IsAddressOfParentChain(targetChainAddress) || IsAddressOfChildChain(targetChainAddress), "target must be parent or child chain"); var targetChain = this.Runtime.Nexus.FindChainByAddress(targetChainAddress); Runtime.Expect(this.Runtime.Nexus.TokenExists(symbol), "invalid token"); var tokenInfo = this.Runtime.Nexus.GetTokenInfo(symbol); Runtime.Expect(tokenInfo.Flags.HasFlag(TokenFlags.Fungible), "must be fungible token"); if (tokenInfo.IsCapped) { var sourceSupplies = new SupplySheet(symbol, this.Runtime.Chain, Runtime.Nexus); var targetSupplies = new SupplySheet(symbol, targetChain, Runtime.Nexus); if (IsAddressOfParentChain(targetChainAddress)) { Runtime.Expect(sourceSupplies.MoveToParent(this.Storage, amount), "source supply check failed"); } else // child chain { Runtime.Expect(sourceSupplies.MoveToChild(this.Storage, this.Runtime.Chain.Name, amount), "source supply check failed"); } } Runtime.Expect(Runtime.Nexus.BurnTokens(symbol, this.Storage, this.Runtime.Chain, from, amount), "burn failed"); Runtime.Notify(EventKind.TokenBurn, from, new TokenEventData() { symbol = symbol, value = amount, chainAddress = Runtime.Chain.Address }); Runtime.Notify(EventKind.TokenEscrow, to, new TokenEventData() { symbol = symbol, value = amount, chainAddress = targetChainAddress }); }
internal SupplySheet GetTokenSupplies(string tokenSymbol) { var tokenInfo = Nexus.GetTokenInfo(tokenSymbol); Throw.If(!tokenInfo.IsCapped, "should be capped"); if (_tokenSupplies.ContainsKey(tokenSymbol)) { return(_tokenSupplies[tokenSymbol]); } var parentChainName = Nexus.GetParentChainByName(this.Name); var parentChain = Nexus.FindChainByName(parentChainName); Throw.If(parentChain == null, "supply sheet not created"); var parentSupplies = parentChain.GetTokenSupplies(tokenSymbol); var sheet = new SupplySheet(parentSupplies.LocalBalance, 0, tokenInfo.MaxSupply); _tokenSupplies[tokenSymbol] = sheet; return(sheet); }
internal Chain CreateChain(StorageContext storage, Address owner, string name, Chain parentChain, Block parentBlock, IEnumerable <string> contractNames) { if (name != RootChainName) { if (parentChain == null || parentBlock == null) { return(null); } } if (!Chain.ValidateName(name)) { return(null); } // check if already exists something with that name if (ChainExists(name)) { return(null); } if (contractNames == null) { return(null); } var chain = new Chain(this, name, _logger); var contractSet = new HashSet <string>(contractNames); contractSet.Add(GasContractName); contractSet.Add(TokenContractName); chain.DeployContracts(contractSet); // add to persistent list of chains var chainList = this.Chains.ToList(); chainList.Add(name); this.Chains = chainList; // add address and name mapping this._vars.Set(ChainNameMapKey + chain.Name, chain.Address.PublicKey); this._vars.Set(ChainAddressMapKey + chain.Address.Text, Encoding.UTF8.GetBytes(chain.Name)); if (parentChain != null) { this._vars.Set(ChainParentNameKey + chain.Name, Encoding.UTF8.GetBytes(parentChain.Name)); this._vars.Set(ChainParentBlockKey + chain.Name, parentBlock.Hash.ToByteArray()); var childrenList = GetChildrenListOfChain(parentChain.Name); childrenList.Add <string>(chain.Name); var tokenList = this.Tokens; // copy each token current supply relative to parent to the chain new foreach (var tokenSymbol in tokenList) { var parentSupply = new SupplySheet(tokenSymbol, parentChain, this); var localSupply = new SupplySheet(tokenSymbol, chain, this); localSupply.Init(chain.Storage, storage, parentSupply); } } else { this.RootChainAddress = chain.Address; } _chainCache[chain.Name] = chain; return(chain); }
public BigInteger GetTokenSupply(StorageContext storage, string symbol) { var supplies = new SupplySheet(symbol, this, Nexus); return(supplies.GetTotal(storage)); }
internal bool BurnTokens(string symbol, StorageContext storage, BalanceSheet balances, SupplySheet supply, Address target, BigInteger amount) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (!tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { return(false); } if (amount <= 0) { return(false); } if (tokenInfo.IsCapped && !supply.Burn(amount)) { return(false); } if (!balances.Subtract(storage, target, amount)) { return(false); } EditTokenSupply(symbol, -amount); return(true); }
public void SideChainTransferMultipleSteps() { var owner = KeyPair.Generate(); var simulator = new ChainSimulator(owner, 1234); var nexus = simulator.Nexus; var sourceChain = nexus.RootChain; var sideChain = nexus.FindChainByName("bank"); var symbol = Nexus.FuelTokenSymbol; var token = nexus.GetTokenInfo(symbol); var sender = KeyPair.Generate(); var receiver = KeyPair.Generate(); var originalAmount = UnitConversion.ToBigInteger(10, token.Decimals); var sideAmount = originalAmount / 2; Assert.IsTrue(sideAmount > 0); var newChainName = "testing"; // Send from Genesis address to "sender" user simulator.BeginBlock(); simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, symbol, originalAmount); simulator.GenerateChain(owner, sideChain, newChainName); simulator.EndBlock(); var targetChain = nexus.FindChainByName(newChainName); // verify test user balance var balance = nexus.RootChain.GetTokenBalance(symbol, sender.Address); Assert.IsTrue(balance == originalAmount); // do a side chain send using test user balance from root to apps chain simulator.BeginBlock(); var txA = simulator.GenerateSideChainSend(sender, symbol, sourceChain, sender.Address, sideChain, sideAmount, 0); var blockA = simulator.EndBlock().FirstOrDefault(); var evtsA = blockA.GetEventsForTransaction(txA.Hash); // finish the chain transfer simulator.BeginBlock(); var txB = simulator.GenerateSideChainSettlement(sender, nexus.RootChain, sideChain, blockA.Hash); Assert.IsTrue(simulator.EndBlock().Any()); // we cant transfer the full side amount due to fees // TODO calculate the proper fee values instead of this var txCostA = simulator.Nexus.RootChain.GetTransactionFee(txA); var txCostB = sideChain.GetTransactionFee(txB); sideAmount = sideAmount - txCostB; balance = sideChain.GetTokenBalance(symbol, sender.Address); Assert.IsTrue(balance == sideAmount); var extraFree = UnitConversion.ToBigInteger(0.01m, token.Decimals); sideAmount -= extraFree * 10; // do another side chain send using test user balance from apps to target chain simulator.BeginBlock(); var txC = simulator.GenerateSideChainSend(sender, symbol, sideChain, receiver.Address, targetChain, sideAmount, extraFree); var blockC = simulator.EndBlock().FirstOrDefault(); var evtsC = blockC.GetEventsForTransaction(txC.Hash); var appSupplies = new SupplySheet(symbol, sideChain, nexus); var childBalance = appSupplies.GetChildBalance(sideChain.Storage, targetChain.Name); var expectedChildBalance = sideAmount + extraFree; // finish the chain transfer simulator.BeginBlock(); var txD = simulator.GenerateSideChainSettlement(receiver, sideChain, targetChain, blockC.Hash); Assert.IsTrue(simulator.EndBlock().Any()); // TODO verify balances }