ENJIN Development: Getting started with the Enjin C#SDK

ENJIN Development:  Getting started with the Enjin C#SDK

Ok.  So your wallet is up and now you wanna get some minting done.

First order of business is to git/download the SDK: https://github.com/enjin/platform-csharp-sdk

Next you see that the SDK is really a GraphQL wrapper around the enjin.io/platform graphiql interface…with a number of helper functions.   This means you don’t necessariy need the full SDK just the juicy bits.   Minimum are the models/schemas etc in the Enjin.Platform.SDK folder and if you need FuelTanks or Beam then also the content of those folders.    We have decided not to implement the PusherClient and instead go for a solution where we poll for transactions whenever we have pending transactions…so that means you could also leave out the PusherClient if you want.

Another thing to note is that things are moving really fast on the enjin side which means SDKs and especially the SDK nugets are not always updated.   In case you use nugets you might need to pull the latest project and then deploy with your own local nuget.   Alternatively just directly import the relevant projects direclty into your .NEt solution and clean up the overlaps.   

We also use one main Collection and one FuelTank.   If you plan to have only a few Collections and FuelTanks it is easier just to create them directly on your Enjin Account page or via Graphiql.

Below is some pseudo code based on the code we use on the Psiens.io server.    

This code is meant for INSPIRATION only. 

            
   public void Initialize()
   {

       main_collection_id = 1234;
       StartService();
   }

   public async void StartService()
   {
       pending_transactions = new Dictionary<int, EnjinTransaction>();
       pending_create_player = new Dictionary<int, DateTime>();

       _timer = new Timer(PollEnjin, null, 0, poll_interval);

       client = PlatformClient.Builder().SetBaseAddress("https://platform.enjin.io/").Build();
       client.Auth(PsiensServerGlobals.secrets.ENJIN_APP_KEY);

       // Wallet? w = await GetProjectWallet();

       float pwb = await GetProjectWalletBalance();
       float ftb = await GetFuelTankBalance();

       processing = false;

       Output.Info("Enjin Service Started Project Wallet Balance= " + pwb.ToString() + " And Fuel Tank Balance " + ftb.ToString());

   }

   public async void StopService()
   {
       PollEnjin(null);
       _timer.Dispose();

       client.Dispose();
       Output.Info("Enjiin Service Stopped...");
   }


   public void PollEnjin(object? state)
   {
       Output.Debug("tick.." + pending_transactions.Count + ":" + processing + " pending players " + pending_create_player.Count);

       if (pending_create_player.Count > 0) ProcessPendingCreatePlayers();

       if (processing || pending_transactions.Count == 0) return;

       ProcessPendingTransactions();

   }



   public async Task<bool> InitiateMintOrb(Orb orb, PsiensPlayer player)
   {
       Output.Debug("Initiate Minting of orb " + orb.ID);

       //Create the meta and upload to IPFS..url is returned.
       string uri = await _metaService.CreateAndUploadOrbMeta(orb);

       //string uri = "https://bafkreifsgzfalygl325drmt5p5ay6monoei7ytbahsd4qktde7ws7s2vb4.ipfs.nftstorage.link/";

       Output.Debug("InitiateMint Got Meta url " + uri);

       AttributeInput[] inputparams = new AttributeInput[8];
       //Required
       inputparams[0] = new AttributeInput().SetKey("uri").SetValue(uri);
       //Optional
       inputparams[1] = new AttributeInput().SetKey("id").SetValue(orb.ID.ToString());
       inputparams[2] = new AttributeInput().SetKey("type").SetValue(PsiensFunctions.GetTypeDescription(orb.Type) + " (" + (orb.Type + 1).ToString() + ")");
       inputparams[3] = new AttributeInput().SetKey("level").SetValue(PsiensFunctions.GetLevelDescription(orb.Level) + " (" + (orb.Level + 1).ToString() + ")");
       inputparams[4] = new AttributeInput().SetKey("family").SetValue(PsiensFunctions.GetFamily(orb.Family).Name + " (" + (orb.Family + 1).ToString() + ")");
       inputparams[5] = new AttributeInput().SetKey("stats").SetValue(orb.Stat_1.ToString() + "," + orb.Stat_2.ToString() + "," + orb.Stat_3.ToString() + "," + orb.Stat_4.ToString() + "," + orb.Stat_5.ToString());
       inputparams[6] = new AttributeInput().SetKey("gen").SetValue(orb.Generation.ToString());
       inputparams[7] = new AttributeInput().SetKey("alias").SetValue(orb.Alias.ToString());

       (EncodableTokenIdInput ecinput, BigInteger tokenid) = ERC1155EncodeOrb(orb);

       CreateTokenParams ctps = new CreateTokenParams()
           .SetAttributes(inputparams)
           .SetUnitPrice(ConvertTokenValueToGweiBigInt(0.01f))  //= 0.01ENJ
           .SetTokenId(ecinput)
           .SetCap(new TokenMintCap().SetType(TokenMintCapType.SingleMint));

       TransactionFragment transactionFragment = new TransactionFragment().WithId();

       CreateToken req = new CreateToken().SetCollectionId(main_collection_id).SetParams(ctps).SetRecipient(player.ENJIN_Wallet).Fragment(transactionFragment);

       Output.Debug("Sending CreateToken Request For Orb " + orb.ID);
       try
       {
           Task<IPlatformResponse<GraphQlResponse<Transaction>>> task = client.SendCreateToken(req);
           IPlatformResponse<GraphQlResponse<Transaction>> platformRes = task.Result;
           GraphQlResponse<Transaction> gqlRes = platformRes.Result;
           if (platformRes.IsSuccessStatusCode)
           {
               Output.Debug("platform success " + JsonSerializer.Serialize(gqlRes, PsiensServerGlobals.json_options));


               if (gqlRes.Data != null)
               {
                   Output.Debug("Got Data " + JsonSerializer.Serialize(gqlRes.Data, PsiensServerGlobals.json_options));

                   if (gqlRes.Data.Result != null)
                   {
                       Output.Debug("Got Data Result " + JsonSerializer.Serialize(gqlRes.Data.Result, PsiensServerGlobals.json_options));
                   }
                   else
                   {
                       Output.Error("No Data.Result returned from CreateToken call"); return false;
                   }
               }
               else
               {
                   Output.Error("No Data returned from CreateToken call"); return false;
               }


               Output.Debug("Sending CreateToken Response Success " + gqlRes.Data.Result.Id.ToString());

               orb.Uri = uri;
               orb.Updated = DateTime.UtcNow;
               orb.Collection_id = main_collection_id;
               orb.Pending_transaction_id = (int)gqlRes.Data.Result.Id;
               //We get the TokenID based on our own input...this is not really confirmed before Token is finally created.
               orb.Token_id = tokenid.ToString();

               //orb.Token_id (string of BigInteger)...we will not have this before the Token has been created on the blockchain
               orb.State = (int)ORBSTATES.MintPending;

               Output.Debug("Orb Token Created on Enjin : " + JsonSerializer.Serialize(orb, PsiensServerGlobals.json_options));

               AddEnjinTransaction(player, orb.ID, (int)gqlRes.Data.Result.Id, ENJINTRANSACTIONSTATE.MintPending, JsonSerializer.Serialize(orb, PsiensServerGlobals.json_options));
           }
           else
           {
               Output.Error("Error on ENJIN Mint Orb " + orb.ID);
               return false;
           }
       }
       catch (Exception e)
       {
           Output.Error("CREATE TOKEN ERROR" + e.Message);
           return false;
       }

       return true;
   }

   /// <summary>
   /// Convert Orb stats into an ERC1155 encoded tokenid
   /// Returns both the EncodableTokenIdInput and the resulting BigInteger TokenId.
   /// </summary>
   /// <param name="orb"></param>
   /// <returns></returns>
   public (EncodableTokenIdInput, BigInteger) ERC1155EncodeOrb(Orb orb)
   {
       Byte[] bytes = new Byte[8];
       bytes[0] = (byte)(orb.Type + 1);
       bytes[1] = (byte)(orb.Level + 1);
       bytes[2] = (byte)(orb.Family + 1);
       bytes[3] = orb.Stat_1;
       bytes[4] = orb.Stat_2;
       bytes[5] = orb.Stat_3;
       bytes[6] = orb.Stat_4;
       bytes[7] = orb.Stat_5;
       string hex = Convert.ToHexString(bytes);

       byte[] idbytes = BitConverter.GetBytes(orb.ID);

       bytes = new Byte[8];
       bytes[0] = orb.Generation;
       bytes[1] = 0;
       bytes[2] = 0;
       bytes[3] = 0;
       bytes[4] = idbytes[3];
       bytes[5] = idbytes[2];
       bytes[6] = idbytes[1];
       bytes[7] = idbytes[0];

       string idhex = Convert.ToHexString(bytes);
       BigInteger bg = BigInteger.Parse(hex + idhex, NumberStyles.AllowHexSpecifier);
       Erc1155EncoderInput erc1155EncoderInput = new Erc1155EncoderInput().SetTokenId("0x" + hex).SetIndex((BigInteger)orb.ID);

       return (new EncodableTokenIdInput().SetErc1155(erc1155EncoderInput), bg);

   }

   /// <summary>
   /// Extract the 12 first bytes in the tokenid.  
   /// 
   /// </summary>
   /// <param name="tokenid"></param>
   /// <returns></returns>
   public byte[]? ExtractDataFromFromERC1155(BigInteger tokenid)
   {
       if (tokenid == null) return null;

       //see https://docs.enjin.io/enjin-platform/getting-started/tokenid-structure-best-practices
       string hex = BigIntegerHelper.ToHexString(tokenid);
       byte[] bytes = tokenid.ToByteArray(true, true);

       return bytes.Take(12).ToArray();

   }

   /// <summary>
   /// Extract OrbID from a tokenid
   /// </summary>
   /// <param name="tokenid"></param>
   /// <returns></returns>
   public int ExtractOrbIDFromERC1155(BigInteger tokenid)
   {
       if (tokenid == null) return -1;

       //see https://docs.enjin.io/enjin-platform/getting-started/tokenid-structure-best-practices
       //
       string hex = BigIntegerHelper.ToHexString(tokenid);
       byte[] bytes = tokenid.ToByteArray(true, true);

       //last 4 byte = orb id integer
       byte[] last4 = bytes.Skip(bytes.Length - 4).ToArray();
       Array.Reverse(last4);
       int bi = BitConverter.ToInt32(last4, 0);

       return bi;

   }


   /// <summary>
   /// Create a new Player Wallet and adds it to the main FuelTank
   /// 
   /// Note that while the CreateWallet returns immediately and GetWallet returns awaited wallet object
   /// ....AddPlayerToFuelTank returns a transaction.  
   /// </summary>
   /// <param name="player"></param>
   /// <returns></returns>

   public bool CreateEnjinPlayer(PsiensPlayer player)
   {

       //see https://docs.enjin.io/enjin-platform/getting-started/recipes-and-snippets/using-managed-wallets
       CreateWallet req = new CreateWallet().SetExternalId(enjinplayer_prefix + player.Player_Id.ToString());

       Task<IPlatformResponse<GraphQlResponse<bool?>>> task = client.SendCreateWallet(req);
       IPlatformResponse<GraphQlResponse<bool?>> platformRes = task.Result;
       //GraphQlResponse<bool?> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           Output.Debug("Initiate ENJIN CreatePlayer");
           pending_create_player.Add(player.Player_Id, DateTime.UtcNow);
           return true;
       }
       else
       {
           Output.Error("Error");
           return false;
       }

       return true;
   }

   /// <summary>
   /// Process pending create players
   /// Check is valid Wallet exits for player and if so add fueltank transaction.
   /// </summary>
   /// <returns></returns>
   public async Task ProcessPendingCreatePlayers()
   {

       List<int> pendplayers = pending_create_player.Keys.ToList();
       foreach (int pid in pendplayers)
       {
           Wallet? w = await GetPlayerWallet(pid);
           if (w == null || w.Account == null || w.Account.Address == null) continue;

           Output.Debug("ENJIN Wallet for " + enjinplayer_prefix + pid + " created with adr = " + w.Account.Address);

           PsiensPlayer? player = await _playerService.GetPlayerAsync(pid);
           if (player == null)
           {
               Output.Warning("Could not process CreateEnjinPlayer");
               pending_create_player.Remove(pid);
               continue;
           }

           player.ENJIN_Wallet = w.Account.Address;
           player.ENJIN_Account_id = w.Account.PublicKey;
           player.Updated = DateTime.UtcNow;
           player.ENJIN_Managed = false;  //this is only set true then FuelTank has been added.
           Output.Debug("ENJIN Player Managed Wallet = " + w.Account.Address + " public key= " + w.Account.PublicKey);

           //Add Fuel Tank
           await AddPlayerToProjectFuelTank(player);

           pending_create_player.Remove(pid);

       }


   }

   /// <summary>
   /// We connect a Player Managed Account/Wallet to the Project's FuelTank using the AddAccount call
   /// 
   /// NOTE: The FuelTank is tightly connected to the Project Wallet and will receive funds from there so no need to transfer funds there manually
   /// (which is also impossible because the FuelTank address is an internal address ex....)
   /// The FuelTank rules can be set/altered in the Project Account Page.
   /// </summary>
   /// <param name="player"></param>
   /// <returns></returns>
   public async Task<bool> AddPlayerToProjectFuelTank(PsiensPlayer player)
   {
       Output.Debug("Attempt to Add Player to FuelTank " + PsiensServerGlobals.configuration.GetValue<string>("Project_FuelTank_Address") + " with player managed wallet " + player.ENJIN_Wallet);

       TransactionFragment tfrag = new TransactionFragment().WithId().WithTransactionId().WithMethod();
       AddAccount addAccount = new AddAccount()
           .SetTankId(PsiensServerGlobals.configuration.GetValue<string>("Project_FuelTank_Address"))
           .SetUserId(player.ENJIN_Wallet)
           .Fragment(tfrag);

       Task<IPlatformResponse<GraphQlResponse<Transaction?>>> task = client.SendAddAccount(addAccount);
       IPlatformResponse<GraphQlResponse<Transaction?>> platformRes = task.Result;
       GraphQlResponse<Transaction?> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           Output.Debug("Attempt to Add Player to FuelTank Success with " + JsonSerializer.Serialize(gqlRes.Data.Result));
           if (gqlRes.Data != null && gqlRes.Data.Result != null)
               AddEnjinTransaction(player, 0, (int)gqlRes.Data.Result.Id, ENJINTRANSACTIONSTATE.PlayerFuelTankPending);
       }
       else
       {
           Output.Error("Error Adding Player to FuelTank " + player.Player_Id.ToString());
           return false;
       }
       return true;
   }


   /// <summary>
   /// Get all the Orbs (ids) present in a players managed wallet
   /// </summary>
   /// <param name="playerid"></param>
   /// <returns></returns>

   public async Task<List<Token>> GetPlayerWalletOrbTokens(int playerid)
   {
       List<Token> ids = new List<Token>();
       AttributeFragment attributeFragment = new AttributeFragment().WithKey().WithValue();
       TokenFragment tokenFragment = new TokenFragment().WithTokenId().WithAttributes(attributeFragment);
       TokenAccountFragment tafragment = new TokenAccountFragment().WithToken(tokenFragment);
       EdgeFragment<TokenAccountFragment> tedgefragment = new EdgeFragment<TokenAccountFragment>().WithNode(tafragment);
       ConnectionFragment<TokenAccountFragment> tconnectionFragment = new ConnectionFragment<TokenAccountFragment>().WithEdges(tedgefragment);
       WalletFragment frag = new WalletFragment().WithTokenAccounts(tconnectionFragment);
       GetWallet req = new GetWallet().SetExternalId(enjinplayer_prefix + playerid.ToString()).Fragment(frag);
       // Send the request and get the Task containing the response
       Task<IPlatformResponse<GraphQlResponse<Wallet>>> task = client.SendGetWallet(req);
       // Get the platform response holding the HTTP data
       IPlatformResponse<GraphQlResponse<Wallet>> platformRes = task.Result;
       GraphQlResponse<Wallet> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null)
               {
                   foreach (var cnode in gqlRes.Data.Result.TokenAccounts.Edges)
                       if (cnode.Node.Token != null) ids.Add(cnode.Node.Token);

                   return ids;
               }

           Output.Error("Could not Get Enjin Wallet");
           return ids;
       }
       else
       {
           Output.Error("Could not Get Enjin Wallet");
       }
       return ids;
   }


   public async Task<List<int>> GetPlayerWalletOrbIDs(int playerid)
   {
       List<int> ids = new List<int>();

       TokenFragment tokenFragment = new TokenFragment().WithTokenId();
       TokenAccountFragment tafragment = new TokenAccountFragment().WithToken(tokenFragment);
       EdgeFragment<TokenAccountFragment> tedgefragment = new EdgeFragment<TokenAccountFragment>().WithNode(tafragment);
       ConnectionFragment<TokenAccountFragment> tconnectionFragment = new ConnectionFragment<TokenAccountFragment>().WithEdges(tedgefragment);
       WalletFragment frag = new WalletFragment().WithTokenAccounts(tconnectionFragment);
       GetWallet req = new GetWallet().SetExternalId(enjinplayer_prefix + playerid.ToString()).Fragment(frag);
       // Send the request and get the Task containing the response
       Task<IPlatformResponse<GraphQlResponse<Wallet>>> task = client.SendGetWallet(req);
       // Get the platform response holding the HTTP data
       IPlatformResponse<GraphQlResponse<Wallet>> platformRes = task.Result;
       GraphQlResponse<Wallet> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null)
               {
                   foreach (var cnode in gqlRes.Data.Result.TokenAccounts.Edges)
                       if (cnode.Node.Token != null)
                           ids.Add(ExtractOrbIDFromERC1155((BigInteger)cnode.Node.Token.TokenId));
                   return ids;
               }
           Output.Error("Could not Get Enjin Wallet");
           return ids;
       }
       else
       {
           Output.Error("Could not Get Enjin Wallet");
       }
       return ids;
   }



   /// <summary>
   /// Get the players wallet
   /// </summary>
   /// <param name="playerid"></param>
   /// <returns></returns>
   public async Task<Wallet?> GetPlayerWallet(int playerid)
   {
       AccountFragment accountFragment = new AccountFragment().WithAddress().WithPublicKey();
       WalletFragment frag = new WalletFragment().WithId().WithAccount(accountFragment).WithManaged();
       GetWallet req = new GetWallet().SetExternalId(enjinplayer_prefix + playerid.ToString()).Fragment(frag);
       // Send the request and get the Task containing the response
       Task<IPlatformResponse<GraphQlResponse<Wallet>>> task = client.SendGetWallet(req);
       // Get the platform response holding the HTTP data
       IPlatformResponse<GraphQlResponse<Wallet>> platformRes = task.Result;
       GraphQlResponse<Wallet> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null)
                   return gqlRes.Data.Result;

           Output.Error("Could not Get Enjin Wallet");
           return null;
       }
       else
       {
           Output.Error("Could not Get Enjin Wallet");
       }
       return null;
   }


   /// <summary>
   /// Get the main Project Wallet associated with the Main Collection
   /// </summary>
   /// <returns></returns>
   public async Task<Wallet?> GetProjectWallet()
   {
       BalancesFragment balancesFragment = new BalancesFragment().WithFree().WithReserved().WithFeeFrozen().WithMiscFrozen();
       AccountFragment accountFragment = new AccountFragment().WithAddress().WithPublicKey();
       WalletFragment frag = new WalletFragment().WithId().WithAccount(accountFragment).WithBalances(balancesFragment);

       GetWallet req = new GetWallet().SetId(12345).Fragment(frag);

       // Send the request and get the Task containing the response
       Task<IPlatformResponse<GraphQlResponse<Wallet>>> task = client.SendGetWallet(req);

       // Get the platform response holding the HTTP data
       IPlatformResponse<GraphQlResponse<Wallet>> platformRes = task.Result;

       GraphQlResponse<Wallet> gqlRes = platformRes.Result;

       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null)
                   return gqlRes.Data.Result;

           Output.Error("Could not Retreive Enjin Project Wallet");
           return null;
       }
       else
       {
           Output.Error("Could not Get Enjin Wallet");
       }


       return null;

   }

   /// <summary>
   /// Return the number ENJ in the main Project Wallet
   /// </summary>
   /// <returns></returns>
   public async Task<float> GetProjectWalletBalance()
   {
       BalancesFragment balancesFragment = new BalancesFragment().WithFree();
       AccountFragment accountFragment = new AccountFragment().WithAddress();
       WalletFragment frag = new WalletFragment().WithId().WithAccount(accountFragment).WithBalances(balancesFragment);
       GetWallet req = new GetWallet().SetId(12345).Fragment(frag);
       // Send the request and get the Task containing the response
       Task<IPlatformResponse<GraphQlResponse<Wallet>>> task = client.SendGetWallet(req);
       // Get the platform response holding the HTTP data
       IPlatformResponse<GraphQlResponse<Wallet>> platformRes = task.Result;
       GraphQlResponse<Wallet> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null && gqlRes.Data.Result.Balances != null)
                   return ConvertGWEIToFloat((BigInteger)gqlRes.Data.Result.Balances.Free);

           Output.Error("Could not Retreive Enjin Project Wallet");
           return 0;
       }
       else
       {
           Output.Error("Could not Get Enjin Wallet");
       }


       return 0;

   }


   /// <summary>
   /// Return the amount of ENJ in the Main Fuel Tank
   /// </summary>
   /// <returns></returns>

   public async Task<float> GetFuelTankBalance()
   {
       BalancesFragment balancesFragment = new BalancesFragment().WithFree();
       AccountFragment accountFragment = new AccountFragment().WithAddress();
       WalletFragment frag = new WalletFragment().WithId().WithAccount(accountFragment).WithBalances(balancesFragment);
       GetWallet req = new GetWallet().SetAccount("Project_FuelTank_Address").Fragment(frag);
       // Send the request and get the Task containing the response
       Task<IPlatformResponse<GraphQlResponse<Wallet>>> task = client.SendGetWallet(req);
       // Get the platform response holding the HTTP data
       IPlatformResponse<GraphQlResponse<Wallet>> platformRes = task.Result;
       GraphQlResponse<Wallet> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null && gqlRes.Data.Result.Balances != null)
                   return ConvertGWEIToFloat((BigInteger)gqlRes.Data.Result.Balances.Free);

           Output.Error("Could not Retreive Enjin Fule Tank Wallet");
           return 0;
       }
       else
       {
           Output.Error("Could not Get Fuel Tank Wallet");
       }
       return 0;
   }



   ///***********************  TRANSACTIONS


   /// <summary>
   /// Add a new EnjinTransaction to pending queue
   /// </summary>
   /// <param name="playerid"></param>
   /// <param name="orbid"></param>
   /// <param name="trans_id"></param>
   /// <param name="state"></param>
   public void AddEnjinTransaction(PsiensPlayer player, int orbid, int trans_id, ENJINTRANSACTIONSTATE state, string data = "")
   {
       player.ENJIN_pending_transaction = trans_id.ToString();
       EnjinTransaction et = new EnjinTransaction() { Orb_id = orbid, Player_id = player.Player_Id, Date_time = DateTime.UtcNow, ID = trans_id, State = state, Data = data };
       pending_transactions.Add(trans_id, et);
       Output.Debug("Adding enjin transaction " + JsonSerializer.Serialize(et, PsiensServerGlobals.json_options));
   }


   /// <summary>
   /// Process any pending enjin transactions.
   /// </summary>
   /// <returns></returns>
   public async Task<bool> ProcessPendingTransactions()
   {
       processing = true;

       List<BigInteger> transids = new List<BigInteger>();
       foreach (BigInteger i in pending_transactions.Keys) transids.Add(i);

       TransactionFragment tfrag = new TransactionFragment().WithId().WithMethod(true).WithResult(true).WithState(true).WithTransactionId();
       EdgeFragment<TransactionFragment> efrag = new EdgeFragment<TransactionFragment>().WithNode(tfrag);
       ConnectionFragment<TransactionFragment> connectionFragment = new ConnectionFragment<TransactionFragment>().WithEdges(efrag);
       GetTransactions req = new GetTransactions().SetVariable("ids", CoreTypes.BigIntArray, transids.ToArray()).Fragment(connectionFragment);
       Task<IPlatformResponse<GraphQlResponse<Connection<Transaction>>>> task = client.SendGetTransactions(req);
       IPlatformResponse<GraphQlResponse<Connection<Transaction>>> platformRes = task.Result;
       GraphQlResponse<Connection<Transaction>> gqlRes = platformRes.Result;
       if (platformRes.IsSuccessStatusCode)
       {
           if (gqlRes != null)
               if (gqlRes.Data != null)
               {
                   Output.Debug("Processing " + gqlRes.Data.Result.TotalCount + " transactions");
                   foreach (var node in gqlRes.Data.Result.Edges)
                       if (node.Node != null) ProcessTransaction(node.Node);

                   processing = false;
                   return true;
               }
           Output.Error("Error Processing transactions");
           processing = false;
           return false;
       }
       else
       {
           Output.Error("Error Processing transactions");
           processing = false;
           return false;
       }
       processing = false;
   }



   public void ProcessTransaction(Transaction t)
   {
       Output.Debug("Processing Transaction " + JsonSerializer.Serialize(t, PsiensServerGlobals.json_options));
       //Check if finalize...if not the return
       if (t.State != TransactionState.Finalized) return;

       //IsSuccess
       if (t.Result == TransactionResult.ExtrinsicSuccess)
       {
           if (!pending_transactions.ContainsKey((int)t.Id))
           {
               Output.Error("Unknown Enjin Transaction " + t.TransactionId);
               return;
           }

           //we have sent a CreateWallet+AddAccount request and have now received transaction success
           if (pending_transactions[(int)t.Id].State == ENJINTRANSACTIONSTATE.PlayerFuelTankPending)
           {
               PsiensPlayer? p = _playerService.GetPlayer(pending_transactions[(int)t.Id].Player_id);
               if (p == null)
               {
                   Output.Error("PsiensPlayer not found for processed Transaction " + t.Id.ToString());
                   pending_transactions.Remove((int)t.Id);
                   p.ENJIN_pending_transaction = "error";
                   p.ENJIN_Managed = false;
                   p.Updated = DateTime.UtcNow;
                   return;
               }

               p.ENJIN_pending_transaction = "";
               p.ENJIN_Managed = true;
               p.Updated = DateTime.UtcNow;
               pending_transactions.Remove((int)t.Id);

               _transactionService.RecordPlayerOrbTransaction(p.Player_Id, pending_transactions[(int)t.Id].Orb_id, p.ENJIN_Wallet, 0, 0, (int)Transactions.TransactionType.EnjinPlayerCreated); //.GetAwaiter().GetResult();

           }

           //we have sent a Mint Token request and have now received transaction success
           if (pending_transactions[(int)t.Id].State == ENJINTRANSACTIONSTATE.MintPending)
           {
               //_playerService.MintCompleted(pending_transactions[(int)t.Id].Orb_id);
               Output.Debug("MINT COMPLETED FOR ORB " + pending_transactions[(int)t.Id].Orb_id + " : " + pending_transactions[(int)t.Id].Data);
               pending_transactions.Remove((int)t.Id);
           }
       }
       //Is error
       if (t.Result == TransactionResult.ExtrinsicFailed)
       {
           Output.Error("Enjin Transaction error " + t.TransactionId);
           pending_transactions.Remove((int)t.Id);
       }
   }


   //************************ HELPERS



   /// ENJIN Values are often given in GWEI where 1 ENJ = 1 x 10^18 gwei.  Returns GWEI in string format.
   /// </summary>
   /// <param name=""></param>
   /// <returns></returns>
   public string ConvertTokenValueToGwei(float amount)
   {

       //System.Numerics.BigInteger val = (int)(value * 1000000000000000000f);
       //Cant find a good way to deal with uint256 in C#!!!

       int val = (int)MathF.Round(amount * 10000f);
       return val.ToString("D") + "00000000000000";


   }

   /// <summary>
   /// ENJIN Values are often given in GWEI where 1 ENJ = 1 x 10^18 gwei.  Returns GWEI in BigInt format.
   /// </summary>
   /// <param name=""></param>
   /// <returns></returns>
   public BigInteger ConvertTokenValueToGweiBigInt(float amount)
   {
       return BigInteger.Parse(ConvertTokenValueToGwei(amount));

   }



   public float ConvertGWEIToFloat(BigInteger gweival)
   {
       return (float)gweival / 1000000000000000000f;
   }
        

As you can see from the above code then we are have 3X coverage for our NFT stats (the Orb), since the main stats are 1. Encoded in the TokenID, 2. Set as Attributes on the Token and 3. Available in the meta.json for the Token.    Maybe overkill but we do it because we can 😉

Happy Coding.

 

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x