internal Token(Address owner, string symbol, string name, BigInteger maxSupply, int decimals, TokenFlags flags) { Throw.If(maxSupply < 0, "negative supply"); Throw.If(maxSupply == 0 && flags.HasFlag(TokenFlags.Finite), "finite requires a supply"); Throw.If(maxSupply > 0 && !flags.HasFlag(TokenFlags.Finite), "infinite requires no supply"); if (!flags.HasFlag(TokenFlags.Fungible)) { Throw.If(flags.HasFlag(TokenFlags.Divisible), "non-fungible token must be indivisible"); } if (flags.HasFlag(TokenFlags.Divisible)) { Throw.If(decimals <= 0, "divisible token must have decimals"); } else { Throw.If(decimals > 0, "indivisible token can't have decimals"); } this.Owner = owner; this.Symbol = symbol; this.Name = name; this.MaxSupply = maxSupply; this.Decimals = decimals; this.Flags = flags; _supply = 0; }
public TokenInfo(string symbol, string name, Address owner, BigInteger maxSupply, int decimals, TokenFlags flags, byte[] script, ContractInterface ABI) { Throw.IfNullOrEmpty(symbol, nameof(symbol)); Throw.IfNullOrEmpty(name, nameof(name)); Throw.If(decimals < 0, "decimals can't be negative"); Throw.If(flags == TokenFlags.None, "token must have flags set"); Throw.If(script == null || script.Length == 0, "token script can't be empty"); Throw.If(maxSupply < 0, "negative supply"); Throw.If(maxSupply == 0 && flags.HasFlag(TokenFlags.Finite), "finite requires a supply"); Throw.If(maxSupply > 0 && !flags.HasFlag(TokenFlags.Finite), "infinite requires no supply"); if (!flags.HasFlag(TokenFlags.Fungible)) { Throw.If(flags.HasFlag(TokenFlags.Divisible), "non-fungible token must be indivisible"); } if (flags.HasFlag(TokenFlags.Divisible)) { Throw.If(decimals <= 0, "divisible token must have decimals"); } else { Throw.If(decimals > 0, "indivisible token can't have decimals"); } this.Symbol = symbol; this.Name = name; this.Owner = owner; this.Flags = flags; this.Decimals = decimals; this.MaxSupply = maxSupply; this.Script = script; this.ABI = ABI; }
public void CreateToken(Address from, string symbol, string name, string platform, Hash hash, BigInteger maxSupply, BigInteger decimals, TokenFlags flags, byte[] script) { var pow = Runtime.Transaction.Hash.GetDifficulty(); Runtime.Expect(pow >= (int)ProofOfWork.Minimal, "expected proof of work"); Runtime.Expect(!string.IsNullOrEmpty(symbol), "token symbol required"); Runtime.Expect(!string.IsNullOrEmpty(name), "token name required"); Runtime.Expect(maxSupply >= 0, "token supply cant be negative"); Runtime.Expect(decimals >= 0, "token decimals cant be negative"); Runtime.Expect(decimals <= MAX_TOKEN_DECIMALS, $"token decimals cant exceed {MAX_TOKEN_DECIMALS}"); Runtime.Expect(!Runtime.TokenExists(symbol), "token already exists"); if (symbol == DomainSettings.FuelTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Fuel), "token should be native"); } else { Runtime.Expect(!flags.HasFlag(TokenFlags.Fuel), "token can't be native"); } if (symbol == DomainSettings.StakingTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Stakable), "token should be stakable"); } if (symbol == DomainSettings.FiatTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Fiat), "token should be fiat"); } Runtime.Expect(!string.IsNullOrEmpty(platform), "chain name required"); if (flags.HasFlag(TokenFlags.External)) { Runtime.Expect(from == Runtime.Nexus.GenesisAddress, "genesis address only"); Runtime.Expect(platform != DomainSettings.PlatformName, "external token chain required"); Runtime.Expect(Runtime.PlatformExists(platform), "platform not found"); } else { Runtime.Expect(platform == DomainSettings.PlatformName, "chain name is invalid"); } Runtime.Expect(from.IsUser, "owner address must be user address"); Runtime.Expect(Runtime.IsStakeMaster(from), "needs to be master"); Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(this.Runtime.CreateToken(symbol, name, platform, hash, maxSupply, (int)decimals, flags, script), "token creation failed"); Runtime.Notify(EventKind.TokenCreate, from, symbol); }
public override void AddToken(IPEndPoint endPoint, uint token, TokenFlags tokenFlags) { if (token == TokenHelper.TokenNone) { return; } for (var i = 0; i < ConnlessPacketList.Count; i++) { var info = ConnlessPacketList[i]; if (info.EndPoint.Compare(endPoint, true)) { info.SendCallback?.Invoke(info.TrackID, info.CallbackContext); NetworkHelper.SendPacketConnless(Client, info.EndPoint, token, TokenManager.GenerateToken(info.EndPoint), info.Data, info.DataSize); ConnlessPacketList.RemoveAt(i--); } } if (!tokenFlags.HasFlag(TokenFlags.ResponseOnly)) { TokenCache.Add(new AddressInfo() { EndPoint = endPoint, Token = token, Expiry = Time.Get() + Time.Freq() * TokenHelper.TokenCacheAddressExpiry }); } }
public void CreateToken(Address owner, string symbol, string name, BigInteger maxSupply, BigInteger decimals, TokenFlags flags) { Runtime.Expect(!string.IsNullOrEmpty(symbol), "token symbol required"); Runtime.Expect(!string.IsNullOrEmpty(name), "token name required"); Runtime.Expect(maxSupply >= 0, "token supply cant be negative"); Runtime.Expect(decimals >= 0, "token decimals cant be negative"); Runtime.Expect(decimals <= MAX_TOKEN_DECIMALS, $"token decimals cant exceed {MAX_TOKEN_DECIMALS}"); if (symbol == Nexus.FuelTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Fuel), "token should be native"); } else { Runtime.Expect(!flags.HasFlag(TokenFlags.Fuel), "token can't be native"); } if (symbol == Nexus.StakingTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Stakable), "token should be stakable"); } if (symbol == Nexus.StableTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Stable), "token should be stable"); } if (flags.HasFlag(TokenFlags.External)) { Runtime.Expect(owner == Runtime.Nexus.GenesisAddress, "external token not permitted"); } Runtime.Expect(IsWitness(owner), "invalid witness"); symbol = symbol.ToUpperInvariant(); var token = this.Runtime.Nexus.CreateToken(owner, symbol, name, maxSupply, (int)decimals, flags); Runtime.Expect(token != null, "invalid token"); if (token.IsCapped) { Runtime.Chain.InitSupplySheet(token, maxSupply); } Runtime.Notify(EventKind.TokenCreate, owner, symbol); }
public void CreateToken(Address from, string symbol, string name, BigInteger maxSupply, int decimals, TokenFlags flags, byte[] script) { var Runtime = this; Runtime.Expect(Runtime.IsRootChain(), "must be root chain"); var pow = Runtime.Transaction.Hash.GetDifficulty(); Runtime.Expect(pow >= (int)ProofOfWork.Minimal, "expected proof of work"); Runtime.Expect(!string.IsNullOrEmpty(symbol), "token symbol required"); Runtime.Expect(!string.IsNullOrEmpty(name), "token name required"); Runtime.Expect(ValidationUtils.IsValidTicker(symbol), "invalid symbol"); Runtime.Expect(!Runtime.TokenExists(symbol), "token already exists"); Runtime.Expect(maxSupply >= 0, "token supply cant be negative"); Runtime.Expect(decimals >= 0, "token decimals cant be negative"); Runtime.Expect(decimals <= DomainSettings.MAX_TOKEN_DECIMALS, $"token decimals cant exceed {DomainSettings.MAX_TOKEN_DECIMALS}"); if (symbol == DomainSettings.FuelTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Fuel), "token should be native"); } else { Runtime.Expect(!flags.HasFlag(TokenFlags.Fuel), "token can't be native"); } if (symbol == DomainSettings.StakingTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Stakable), "token should be stakable"); } if (symbol == DomainSettings.FiatTokenSymbol) { Runtime.Expect(flags.HasFlag(TokenFlags.Fiat), "token should be fiat"); } if (!flags.HasFlag(TokenFlags.Fungible)) { Runtime.Expect(!flags.HasFlag(TokenFlags.Divisible), "non-fungible token must be indivisible"); } if (flags.HasFlag(TokenFlags.Divisible)) { Runtime.Expect(decimals > 0, "divisible token must have decimals"); } else { Runtime.Expect(decimals == 0, "indivisible token can't have decimals"); } Runtime.Expect(from.IsUser, "owner address must be user address"); Runtime.Expect(Runtime.IsStakeMaster(from), "needs to be master"); Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Nexus.CreateToken(RootStorage, symbol, name, maxSupply, decimals, flags, script); Runtime.Notify(EventKind.TokenCreate, from, symbol); }
internal bool CreateToken(Address owner, string symbol, string name, BigInteger maxSupply, int decimals, TokenFlags flags, byte[] script) { if (symbol == null || name == null || maxSupply < 0) { return(false); } symbol = symbol.ToUpper(); // check if already exists something with that name if (TokenExists(symbol)) { return(false); } Throw.If(maxSupply < 0, "negative supply"); Throw.If(maxSupply == 0 && flags.HasFlag(TokenFlags.Finite), "finite requires a supply"); Throw.If(maxSupply > 0 && !flags.HasFlag(TokenFlags.Finite), "infinite requires no supply"); if (!flags.HasFlag(TokenFlags.Fungible)) { Throw.If(flags.HasFlag(TokenFlags.Divisible), "non-fungible token must be indivisible"); } if (flags.HasFlag(TokenFlags.Divisible)) { Throw.If(decimals <= 0, "divisible token must have decimals"); } else { Throw.If(decimals > 0, "indivisible token can't have decimals"); } var tokenInfo = new TokenInfo(owner, symbol, name, maxSupply, decimals, flags, script); EditToken(symbol, tokenInfo); // add to persistent list of tokens var tokenList = this.Tokens.ToList(); tokenList.Add(symbol); this.Tokens = tokenList; return(true); }
public Transaction GenerateToken(PhantasmaKeys owner, string symbol, string name, BigInteger totalSupply, int decimals, TokenFlags flags, byte[] tokenScript = null, Dictionary <string, int> labels = null, IEnumerable <ContractMethod> customMethods = null) { var version = Nexus.GetGovernanceValue(Nexus.RootStorage, Nexus.NexusProtocolVersionTag); if (labels == null) { labels = new Dictionary <string, int>(); } if (tokenScript == null) { // small script that restricts minting of tokens to transactions where the owner is a witness var addressStr = Base16.Encode(owner.Address.ToByteArray()); string[] scriptString; if (version >= 4) { scriptString = new string[] { $"alias r3, $result", $"alias r4, $owner", $"@{AccountTrigger.OnMint}: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; } else { scriptString = new string[] { $"alias r1, $triggerMint", $"alias r2, $currentTrigger", $"alias r3, $result", $"alias r4, $owner", $@"load $triggerMint, ""{AccountTrigger.OnMint}""", $"pop $currentTrigger", $"equal $triggerMint, $currentTrigger, $result", $"jmpif $result, @mintHandler", $"jmp @end", $"@mintHandler: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; } DebugInfo debugInfo; tokenScript = AssemblerUtils.BuildScript(scriptString, "GenerateToken", out debugInfo, out labels); } var sb = ScriptUtils. BeginScript(). AllowGas(owner.Address, Address.Null, MinimumFee, 9999); if (version >= 4) { var triggerMap = new Dictionary <AccountTrigger, int>(); var onMintLabel = AccountTrigger.OnMint.ToString(); if (labels.ContainsKey(onMintLabel)) { triggerMap[AccountTrigger.OnMint] = labels[onMintLabel]; } var methods = AccountContract.GetTriggersForABI(triggerMap); if (customMethods != null) { methods = methods.Concat(customMethods); } var abi = new ContractInterface(methods, Enumerable.Empty <ContractEvent>()); var abiBytes = abi.ToByteArray(); sb.CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript, abiBytes); } else { sb.CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript); } if (!flags.HasFlag(TokenFlags.Fungible)) { ContractInterface nftABI; byte[] nftScript; NFTUtils.GenerateNFTDummyScript(symbol, name, name, "http://simulator/nft/*", "http://simulator/img/*", out nftScript, out nftABI); sb.CallInterop("Nexus.CreateTokenSeries", owner.Address, symbol, new BigInteger(0), totalSupply, TokenSeriesMode.Unique, nftScript, nftABI.ToByteArray()); } sb.SpendGas(owner.Address); var script = sb.EndScript(); var tx = MakeTransaction(owner, ProofOfWork.Minimal, Nexus.RootChain, script); return(tx); }
static byte[] GenCreateToken() { Console.Write("Token symbol? "); string symbol = Console.ReadLine(); if (!ValidationUtils.IsValidTicker(symbol)) { Console.Write("Invalid token symbol"); return(null); } Console.Write("Token name? "); string name = Console.ReadLine(); TokenFlags flags = TokenFlags.Transferable; var possibleValues = new[] { TokenFlags.Burnable, TokenFlags.Divisible, TokenFlags.Finite, TokenFlags.Fungible }; foreach (var val in possibleValues) { if (FetchAnswer($"Is {symbol} {val}?")) { flags |= val; } } int decimals; if (flags.HasFlag(TokenFlags.Divisible)) { Console.Write($"How many decimals {symbol} has?: "); if (!int.TryParse(Console.ReadLine(), out decimals) || decimals < 0 || decimals > 18) { Console.Write("Invalid decimals"); return(null); } } else { decimals = 0; } BigInteger maxSupply; if (flags.HasFlag(TokenFlags.Finite)) { Console.Write($"What is the max supply of {symbol}?: "); decimal val; if (!decimal.TryParse(Console.ReadLine(), out val) || val <= 0) { Console.Write("Invalid decimals"); return(null); } maxSupply = UnitConversion.ToBigInteger(val, decimals); } else { maxSupply = 0; } var labels = new Dictionary <string, int>(); var addressStr = Base16.Encode(signerKeys.Address.ToByteArray()); string[] scriptString; scriptString = new string[] { $"alias r3, $result", $"alias r4, $owner", $"@{AccountTrigger.OnMint}: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; DebugInfo debugInfo; var tokenScript = AssemblerUtils.BuildScript(scriptString, "GenerateToken", out debugInfo, out labels); var sb = ScriptUtils. BeginScript(). AllowGas(signerKeys.Address, Address.Null, MinimumFee, 9999); var triggerMap = new Dictionary <AccountTrigger, int>(); var onMintLabel = AccountTrigger.OnMint.ToString(); if (labels.ContainsKey(onMintLabel)) { triggerMap[AccountTrigger.OnMint] = labels[onMintLabel]; } var methods = AccountContract.GetTriggersForABI(triggerMap); var abi = new ContractInterface(methods, Enumerable.Empty <ContractEvent>()); var abiBytes = abi.ToByteArray(); sb.CallInterop("Nexus.CreateToken", signerKeys.Address, symbol, name, maxSupply, decimals, flags, tokenScript, abiBytes); if (!flags.HasFlag(TokenFlags.Fungible)) { Console.Write("NFT deployment not supported yet"); return(null); } sb.SpendGas(signerKeys.Address); var script = sb.EndScript(); return(script); }