public void SwapToken(Address buyer, Address seller, string baseSymbol, string quoteSymbol, BigInteger tokenID, BigInteger price, byte[] signature) { Runtime.Expect(IsWitness(buyer), "invalid witness"); Runtime.Expect(seller != buyer, "invalid seller"); Runtime.Expect(Runtime.Nexus.TokenExists(baseSymbol), "invalid base token"); var baseToken = Runtime.Nexus.GetTokenInfo(baseSymbol); Runtime.Expect(!baseToken.Flags.HasFlag(TokenFlags.Fungible), "token must be non-fungible"); var ownerships = new OwnershipSheet(baseSymbol); var owner = ownerships.GetOwner(this.Storage, tokenID); Runtime.Expect(owner == seller, "invalid owner"); var swap = new TokenSwap() { baseSymbol = baseSymbol, quoteSymbol = quoteSymbol, buyer = buyer, seller = seller, price = price, value = tokenID, }; var msg = Serialization.Serialize(swap); Runtime.Expect(Ed25519.Verify(signature, msg, seller.PublicKey), "invalid signature"); Runtime.Expect(Runtime.Nexus.TokenExists(quoteSymbol), "invalid quote token"); var quoteToken = Runtime.Nexus.GetTokenInfo(quoteSymbol); Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible"); var balances = new BalanceSheet(quoteSymbol); var balance = balances.Get(this.Storage, buyer); Runtime.Expect(balance >= price, "invalid balance"); Runtime.Expect(Runtime.Nexus.TransferTokens(quoteSymbol, this.Storage, Runtime.Chain, buyer, owner, price), "payment failed"); Runtime.Expect(Runtime.Nexus.TransferToken(baseSymbol, this.Storage, Runtime.Chain, owner, buyer, tokenID), "transfer failed"); Runtime.Notify(EventKind.TokenSend, seller, new TokenEventData() { chainAddress = Runtime.Chain.Address, symbol = baseSymbol, value = tokenID }); Runtime.Notify(EventKind.TokenSend, buyer, new TokenEventData() { chainAddress = Runtime.Chain.Address, symbol = quoteSymbol, value = price }); Runtime.Notify(EventKind.TokenReceive, seller, new TokenEventData() { chainAddress = Runtime.Chain.Address, symbol = quoteSymbol, value = price }); Runtime.Notify(EventKind.TokenReceive, buyer, new TokenEventData() { chainAddress = Runtime.Chain.Address, symbol = baseSymbol, value = tokenID }); }
// NOTE this only works if the token is curently on this chain public Address GetTokenOwner(string tokenSymbol, BigInteger tokenID) { var tokenInfo = Nexus.GetTokenInfo(tokenSymbol); Throw.If(tokenInfo.IsFungible, "non fungible required"); var ownerships = new OwnershipSheet(tokenSymbol); return(ownerships.GetOwner(this.Storage, tokenID)); }
public void BuyToken(Address from, string symbol, BigInteger tokenID) { Runtime.Expect(IsWitness(from), "invalid witness"); var auctionID = symbol + "." + tokenID; Runtime.Expect(_auctionMap.ContainsKey <string>(auctionID), "invalid auction"); var auction = _auctionMap.Get <string, MarketAuction>(auctionID); Runtime.Expect(Runtime.Nexus.TokenExists(auction.BaseSymbol), "invalid base token"); var baseToken = Runtime.Nexus.GetTokenInfo(auction.BaseSymbol); Runtime.Expect(!baseToken.Flags.HasFlag(TokenFlags.Fungible), "token must be non-fungible"); var ownerships = new OwnershipSheet(baseToken.Symbol); var owner = ownerships.GetOwner(this.Storage, auction.TokenID); Runtime.Expect(owner == Runtime.Chain.Address, "invalid owner"); if (auction.Creator != from) { Runtime.Expect(Runtime.Nexus.TokenExists(auction.QuoteSymbol), "invalid quote token"); var quoteToken = Runtime.Nexus.GetTokenInfo(auction.QuoteSymbol); Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "quote token must be fungible"); var balances = new BalanceSheet(quoteToken.Symbol); var balance = balances.Get(this.Storage, from); Runtime.Expect(balance >= auction.Price, "not enough balance"); Runtime.Expect(Runtime.Nexus.TransferTokens(quoteToken.Symbol, this.Storage, Runtime.Chain, from, auction.Creator, auction.Price), "payment failed"); } Runtime.Expect(Runtime.Nexus.TransferToken(baseToken.Symbol, this.Storage, Runtime.Chain, Runtime.Chain.Address, from, auction.TokenID), "transfer failed"); _auctionMap.Remove <string>(auctionID); _auctionIDs.Remove(auctionID); if (auction.Creator == from) { Runtime.Notify(EventKind.AuctionCancelled, from, new MarketEventData() { ID = auction.TokenID, BaseSymbol = auction.BaseSymbol, QuoteSymbol = auction.QuoteSymbol, Price = 0 }); } else { Runtime.Notify(EventKind.AuctionFilled, from, new MarketEventData() { ID = auction.TokenID, BaseSymbol = auction.BaseSymbol, QuoteSymbol = auction.QuoteSymbol, Price = auction.Price }); } }
public void SellToken(Address from, string baseSymbol, string quoteSymbol, BigInteger tokenID, BigInteger price, Timestamp endDate) { Runtime.Expect(IsWitness(from), "invalid witness"); Runtime.Expect(endDate > Runtime.Time, "invalid end date"); var maxAllowedDate = Runtime.Time + TimeSpan.FromDays(30); Runtime.Expect(endDate <= maxAllowedDate, "end date is too distant"); Runtime.Expect(Runtime.Nexus.TokenExists(quoteSymbol), "invalid quote token"); var quoteToken = Runtime.Nexus.GetTokenInfo(quoteSymbol); Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "quote token must be fungible"); Runtime.Expect(Runtime.Nexus.TokenExists(baseSymbol), "invalid base token"); var baseToken = Runtime.Nexus.GetTokenInfo(baseSymbol); Runtime.Expect(!baseToken.Flags.HasFlag(TokenFlags.Fungible), "base token must be non-fungible"); var ownerships = new OwnershipSheet(baseSymbol); var owner = ownerships.GetOwner(this.Storage, tokenID); Runtime.Expect(owner == from, "invalid owner"); Runtime.Expect(Runtime.Nexus.TransferToken(Runtime, baseToken.Symbol, from, Runtime.Chain.Address, tokenID), "transfer failed"); var auction = new MarketAuction(from, Runtime.Time, endDate, baseSymbol, quoteSymbol, tokenID, price); var auctionID = baseSymbol + "." + tokenID; _auctionMap.Set(auctionID, auction); _auctionIDs.Add(auctionID); Runtime.Notify(EventKind.OrderCreated, from, new MarketEventData() { ID = tokenID, BaseSymbol = baseSymbol, QuoteSymbol = quoteSymbol, Price = price }); Runtime.Notify(EventKind.TokenSend, from, new TokenEventData() { chainAddress = this.Runtime.Chain.Address, symbol = auction.BaseSymbol, value = tokenID }); }
public void NftBurn() { var owner = KeyPair.Generate(); var simulator = new ChainSimulator(owner, 1234); var nexus = simulator.Nexus; var chain = nexus.RootChain; var symbol = "COOL"; var testUser = KeyPair.Generate(); // Create the token CoolToken as an NFT simulator.BeginBlock(); simulator.GenerateToken(owner, symbol, "CoolToken", 0, 0, Blockchain.Tokens.TokenFlags.None); simulator.EndBlock(); // Send some SOUL to the test user (required for gas used in "burn" transaction) simulator.BeginBlock(); simulator.GenerateTransfer(owner, testUser.Address, chain, Nexus.FuelTokenSymbol, UnitConversion.ToBigInteger(1, Nexus.FuelTokenDecimals)); simulator.EndBlock(); var token = simulator.Nexus.GetTokenInfo(symbol); var tokenData = new byte[] { 0x1, 0x3, 0x3, 0x7 }; Assert.IsTrue(nexus.TokenExists(symbol), "Can't find the token symbol"); // verify nft presence on the user pre-mint var ownerships = new OwnershipSheet(symbol); var ownedTokenList = ownerships.Get(chain.Storage, testUser.Address); Assert.IsTrue(!ownedTokenList.Any(), "How does the user already have a CoolToken?"); // Mint a new CoolToken directly on the user simulator.BeginBlock(); simulator.GenerateNft(owner, testUser.Address, symbol, tokenData, new byte[0]); simulator.EndBlock(); // verify nft presence on the user post-mint ownedTokenList = ownerships.Get(chain.Storage, testUser.Address); Assert.IsTrue(ownedTokenList.Count() == 1, "How does the user not have one now?"); var ownerAddress = ownerships.GetOwner(chain.Storage, 1); Assert.IsTrue(ownerAddress == testUser.Address); //verify that the present nft is the same we actually tried to create var tokenId = ownedTokenList.ElementAt(0); var nft = nexus.GetNFT(symbol, tokenId); Assert.IsTrue(nft.ROM.SequenceEqual(tokenData) || nft.RAM.SequenceEqual(tokenData), "And why is this NFT different than expected? Not the same data"); // burn the token simulator.BeginBlock(); simulator.GenerateNftBurn(testUser, chain, symbol, tokenId); simulator.EndBlock(); //verify the user no longer has the token ownedTokenList = ownerships.Get(chain.Storage, testUser.Address); Assert.IsTrue(!ownedTokenList.Any(), "How does the user still have it post-burn?"); }