<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: jonyx</title>
    <description>The latest articles on Forem by jonyx (@jonyx).</description>
    <link>https://forem.com/jonyx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F267709%2F2b7eff79-b169-48b3-8947-f51b8039abfc.png</url>
      <title>Forem: jonyx</title>
      <link>https://forem.com/jonyx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jonyx"/>
    <language>en</language>
    <item>
      <title>First P2E game on Tableland (2)</title>
      <dc:creator>jonyx</dc:creator>
      <pubDate>Sun, 12 Feb 2023 13:34:51 +0000</pubDate>
      <link>https://forem.com/jonyx/first-p2e-game-on-tableland-2-5g31</link>
      <guid>https://forem.com/jonyx/first-p2e-game-on-tableland-2-5g31</guid>
      <description>&lt;p&gt;It's been a while since I posted a blog about the first P2E game on Tableland, in order to give you an idea about how to manipulate metadata on-chain, just like normal relational database manipulation.&lt;/p&gt;

&lt;p&gt;Previously, I talked about the databases on Tableland for Kart and Asset collections, how to create tables on the Tableland, and how to return URI based on that.&lt;br&gt;
If you missed the previous one, please check it before you move forward.&lt;br&gt;
&lt;a href="https://dev.to/ponyjackal/first-p2e-game-on-tableland-1-2p8p"&gt;https://dev.to/ponyjackal/first-p2e-game-on-tableland-1-2p8p&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, I will deep dive into AutobodyShop contract, where you will eventually apply many assets to the kart, which leads to metadata updates on the Kart collection.&lt;/p&gt;

&lt;p&gt;So we have the applyAssets function which will take assets data for the kart, and update the metadata table on Tableland for the kart.&lt;/p&gt;

&lt;p&gt;It will be easy since we will just fetch assets metadata, and update the kart table.&lt;/p&gt;

&lt;p&gt;But here is the thing, we are not able to get results from tableland on-chain, we can only do that off-chain.&lt;br&gt;
Furthermore, our assets have multiple attributes, do you remember?&lt;br&gt;
This means, we have to do some sub-queries, which is also not possible in the current tableland.&lt;/p&gt;

&lt;p&gt;So I ended up using the hybrid method, we will fetch the results from the assets table and do some sub-queries to finalize the attributes we will apply to the kart off-chain, which is node js api.&lt;br&gt;
Once user hits apply assets button on UI, it will hit this api, not the smart contract function directly, and from that api, we make some voucher which contains (BE signature, query strings to run on tableland tables), call the smart contract on UI.&lt;/p&gt;

&lt;p&gt;Hope you will find it easy to understand, or this blog will help you.&lt;br&gt;
&lt;a href="https://dev.to/ponyjackal/signature-verification-on-hybrid-method-2349"&gt;https://dev.to/ponyjackal/signature-verification-on-hybrid-method-2349&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the voucher for applyAssets function on Autobodyshop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct AutoBodyShopVoucher {
    address owner;
    uint256 kartId;
    uint256[] assetIds;
    string resetQuery;
    string applyQuery;
    string updateImageQuery;
    uint256 nonce;
    uint256 expiry;
    bytes signature;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that I'd love to share applyAssets function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  /**
   * @dev Apply assets attributes to a kart
   * @param _voucher The AutoBodyShopVoucher
   */
  function applyAssets(AutoBodyShopVoucher calldata _voucher) external nonContract nonReentrant {
    address signer = _verify(_voucher);
    require(signer == gameServer &amp;amp;&amp;amp; msg.sender == _voucher.owner, "AutoBodyShop: invalid call");
    require(_voucher.nonce == nonces[_voucher.owner], "AutoBodyShop: invalid nonce");
    require(_voucher.expiry == 0 || block.timestamp &amp;lt;= _voucher.expiry, "AutoBodyShop: signature is expired");
    require(kittyKartGoKart.ownerOf(_voucher.kartId) == msg.sender, "AutoBodyShop: not a kart owner");

    nonces[_voucher.owner]++;
    for (uint256 i = 0; i &amp;lt; _voucher.assetIds.length; i++) {
      require(kittyKartAsset.ownerOf(_voucher.assetIds[i]) == msg.sender, "AutoBodyShop: not an asset owner");
      kittyKartAsset.safeTransferFrom(msg.sender, address(this), _voucher.assetIds[i]);
    }

    // update in_use for previously applied asset
    tableland.runSQL(address(this), kittyKartAssetAttributeTableId, _voucher.resetQuery);
    // set kart_id in asset attribute table
    tableland.runSQL(address(this), kittyKartAssetAttributeTableId, _voucher.applyQuery);
    // update image url for kart
    tableland.runSQL(address(this), kittyKartGoKartTableId, _voucher.updateImageQuery);

    emit ApplyAssets(_voucher.kartId, _voucher.assetIds);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks pretty much straight forward, doesn't it?&lt;/p&gt;

&lt;p&gt;First there are some validation checks including ownership and voucher.&lt;br&gt;
And then transfer assets to Autobodyshop contract, &lt;/p&gt;

&lt;p&gt;Finally, update tableland tables,&lt;/p&gt;

&lt;p&gt;Note that we need 3 things to update.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update in_use column in asset table&lt;/li&gt;
&lt;li&gt;update kart_id column in asset table&lt;/li&gt;
&lt;li&gt;update image_url column in kart table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oh, did I tell you about tableland write permissions?&lt;/p&gt;

&lt;p&gt;Okay, no worries, let me explain now.&lt;/p&gt;

&lt;p&gt;Each tableland table has privileges so that onlyowners can write into the table, though it's public to read.&lt;br&gt;
And table owner here is the table creator obivously, in our case, for assets table, owner is Asset contract, for kart table, owner is Kart contract.&lt;br&gt;
For more details, &lt;a href="https://docs.tableland.xyz/table-writes-updates" rel="noopener noreferrer"&gt;https://docs.tableland.xyz/table-writes-updates&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you notice, we are going to update assets and kart tables on Autobodyshop contract, which is not the owner.&lt;br&gt;
In order to make this work, we have to grant write permission to Autobodyshop contract, and only owner of the table can do this.&lt;/p&gt;

&lt;p&gt;That's why we have grantAccess and revokeAccess functions in Kart and Asset contracts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; /**
   * @dev Grant access of table to EOA
   * @param _to The address to grant access
   */
  function grantAccess(address _to) external onlyOwner {
    require(metadataTableId != 0, "KittyKartGoKart: table is not created yet");
    tableland.runSQL(
      address(this),
      metadataTableId,
      string.concat(
        "GRANT INSERT, UPDATE, DELETE ON ",
        metadataTable,
        " TO ",
        "'",
        StringsUpgradeable.toHexString(_to),
        "'",
        ";"
      )
    );
    emit AccessGranted(_to);
  }

  /**
   * @dev Revoke access of table to EOA
   * @param _to The address to grant access
   */
  function revokeAccess(address _to) external onlyOwner {
    require(metadataTableId != 0, "KittyKartGoKart: table is not created yet");
    tableland.runSQL(
      address(this),
      metadataTableId,
      string.concat(
        "REVOKE INSERT, UPDATE, DELETE ON ",
        metadataTable,
        " FROM ",
        "'",
        StringsUpgradeable.toHexString(_to),
        "'",
        ";"
      )
    );
    emit AccessRevoked(_to);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the write permission is granted to the Autobodyshop contract, we are able to run SQL queries to update assets and the kart table on Autobodyshop contract.&lt;/p&gt;

&lt;p&gt;Damn, I think I went through all the things you need to get familiar with the app.&lt;/p&gt;

&lt;p&gt;Here are 2 things I want to emphasize, that shaped our current design.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no way to get query results on-chain&lt;/li&gt;
&lt;li&gt;For now, it's not possible to run sub-queries in the tableland&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you know, it will give a sense of building on-chain metadata in NFT space with tableland.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed this,&lt;br&gt;
Thanks&lt;/p&gt;

</description>
      <category>openai</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>First P2E game on Tableland (1)</title>
      <dc:creator>jonyx</dc:creator>
      <pubDate>Sun, 27 Nov 2022 14:04:39 +0000</pubDate>
      <link>https://forem.com/jonyx/first-p2e-game-on-tableland-1-2p8p</link>
      <guid>https://forem.com/jonyx/first-p2e-game-on-tableland-1-2p8p</guid>
      <description>&lt;p&gt;We say that blockchain is a distributed ledger as we think of it as a decentralized database.&lt;br&gt;
And there are many decentralized apps on top of it.&lt;/p&gt;

&lt;p&gt;And we all know that it is not always easy to query data from the blockchain and that's where many database layer services like The Graph come into play.&lt;/p&gt;

&lt;p&gt;But there are still inefficiencies in terms of performance and latency.&lt;br&gt;
And that's why we sometimes in the need of own indexer for nft collections.&lt;/p&gt;

&lt;p&gt;Today, I'd like to introudce Tableland Network, a decentralized web3 protocol for structured relational data, starting with Ethereum (EVM) and EVM-compatible L2s.&lt;br&gt;
&lt;a href="https://docs.tableland.xyz/what-is-tableland" rel="noopener noreferrer"&gt;https://docs.tableland.xyz/what-is-tableland&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first time, I checked their doc, I was so excited about this one since it will just make developers' lives way easier.&lt;/p&gt;

&lt;p&gt;Simply they have their own relational database and then mint NFTs representing privileges to the tables.&lt;br&gt;
And again its accessible from both on-chain and off-chain.&lt;/p&gt;

&lt;p&gt;You can check the first nft collection storing metadata on tableland tables.&lt;br&gt;
&lt;a href="https://opensea.io/collection/tableland-rigs" rel="noopener noreferrer"&gt;https://opensea.io/collection/tableland-rigs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of all the advantages Tableland will bring, I think the fact that it lets us build dynamic metadata would be the one we have to consider first.&lt;/p&gt;

&lt;p&gt;Okay, I know that you can walk through all the technical details and some approaches yourself from the doc above.&lt;br&gt;
So I will remain lots of things on you and skip to the P2E game I built on top of the tableland, pretty assume that this will attract you since it's the very first approach yet.&lt;/p&gt;

&lt;p&gt;What I was trying to build for KittyKart &lt;br&gt;
(&lt;a href="https://kittyinu.com/" rel="noopener noreferrer"&gt;https://kittyinu.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/KittyKartRacing?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor" rel="noopener noreferrer"&gt;https://twitter.com/KittyKartRacing?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://playtoearn.net/blockchaingame/kittykart" rel="noopener noreferrer"&gt;https://playtoearn.net/blockchaingame/kittykart&lt;/a&gt;)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;NFT collections (Kart, Assets)
There are 2 NFT collections, Kart and Asset.
Kart is the automotive in the game which you will use to race others, and assets are the part of Kart. 
You can replace any assets you want in your kart for the better performance of the kart.
FYI, assets can hold several traits, for example, you can think of an asset
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "engine": "v8",
    "color": "violet"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Autobody shop
It's the place where users can apply various assets to the Kart,
Technically once one asset is applied to the kart, the metadata of the kart will be updated accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First and foremost, we have to design the tables for nft collections, and create tables on smart contracts. (FYI, table creator will have admin privilege of that table, in our case smart contracts)&lt;/p&gt;

&lt;p&gt;Here are the code piece for creating tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
   * @dev create table in TableLand
   * @param _registry The registry address
   */
  function createMetadataTable(address _registry) external payable onlyOwner returns (uint256) {
    /*
     * registry if the address of the Tableland registry. You can always find those
     * here https://github.com/tablelandnetwork/evm-tableland#currently-supported-chains
     */
    tableland = ITablelandTables(_registry);

    metadataTableId = tableland.createTable(
      address(this),
      /*
       *  CREATE TABLE prefix_chainId (
       *    int id,
       *    string name,
       *    string description,
       *    string image,
       *    string background_color,
       *    string external_url,
       *    string animation_url,
       *    string owner,
       *  );
       */
      string.concat(
        "CREATE TABLE ",
        tablePrefix,
        "_",
        StringsUpgradeable.toString(block.chainid),
        " (id int, name text, description text, image text, background_color text, external_url text, animation_url text, owner text);"
      )
    );

    metadataTable = string.concat(
      tablePrefix,
      "_",
      StringsUpgradeable.toString(block.chainid),
      "_",
      StringsUpgradeable.toString(metadataTableId)
    );

    emit CreateMetadataTable(metadataTable, metadataTableId);

    return metadataTableId;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to build tokenURI for public access to metadata. (again tableland tables are accessible by public off-chain)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
   * @dev tokenURI is an example of how to turn a row in your table back into
   * erc721 compliant metadata JSON. Here, we do a simple SELECT statement
   * with function that converts the result into json.
   */
  function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {
    require(_exists(_tokenId), "KittyKartGoKart: URI query for nonexistent token");
    string memory base = _baseURI();

    return
      string.concat(
        base,
        "SELECT%20json_object(%27id%27,id,%27name%27,name,%27description%27,description",
        ",%27image%27,image,%27background_color%27,background_color,%27external_url%27,external_url,%27animation_url%27,animation_url",
        ",%27attributes%27,json_group_array(json_object(%27display_type%27,display_type",
        ",%27trait_type%27,trait_type,%27value%27,value)))",
        "%20FROM%20",
        metadataTable,
        "%20LEFT%20JOIN%20",
        assetAttributeTable,
        "%20ON%20(",
        metadataTable,
        ".id=",
        assetAttributeTable,
        ".kart_id%20AND%20",
        assetAttributeTable,
        ".in_use=1)",
        "%20WHERE%20id=",
        StringsUpgradeable.toString(_tokenId),
        "%20GROUP%20BY%20id",
        "&amp;amp;mode=list"
      );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the basic example of token URI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://testnet.tableland.network/query?s=SELECT%20json_object(%27id%27,id,%27name%27,name,%27description%27,description,%27image%27,image,%27external_url%27,external_url,%27animation_url%27,animation_url,%27attributes%27,json_group_array(json_object(%27display_type%27,display_type,%27trait_type%27,trait_type,%27value%27,value)))%20FROM%20kitty_kart_test_5_700%20LEFT%20JOIN%20kitty_asset_test_attribute_5_702%20ON%20(kitty_kart_test_5_700.id=kitty_asset_test_attribute_5_702.kart_id%20AND%20kitty_asset_test_attribute_5_702.in_use=1)%20WHERE%20id=1%20GROUP%20BY%20id&amp;amp;mode=list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will ask how to mint NFT and insert metadata into the tableland tables.&lt;br&gt;
No worries, I have this to show you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  /**
   * @dev Its free mint for test
   * @param _quantity The quantity value to mint
   */
  function publicMint(uint256 _quantity) external nonContract nonReentrant {
    uint256 tokenId = _nextTokenId();
    for (uint256 i = 0; i &amp;lt; _quantity; i++) {
      tableland.runSQL(
        address(this),
        metadataTableId,
        string.concat(
          "INSERT INTO ",
          metadataTable,
          " (id, name, description, image, external_url, animation_url) VALUES (",
          StringsUpgradeable.toString(tokenId + i),
          ", '#",
          StringsUpgradeable.toString(tokenId + i),
          "', '",
          description,
          "', '",
          defaultImage,
          "', '",
          externalURL,
          "', '",
          defaultAnimationURL,
          "');"
        )
      );
    }
    _mint(msg.sender, _quantity);

    emit Mint(msg.sender, _quantity);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you will be clear about how to play with tableland tables, and yes it is almost the same as normal interaction with relational databases with SQL queries.&lt;br&gt;
One exception here is tableland can't accept sub queries, which is a barrier of tabeland adaption in cases, but this shouldn't be a blocker.&lt;/p&gt;

&lt;p&gt;time to move on to autobody shop?&lt;/p&gt;

&lt;p&gt;You will have a basic idea of it, since you are very familiar with database manipulations,&lt;br&gt;
and you are right, it is all about updating existing kart metadata on the tableland.&lt;/p&gt;

&lt;p&gt;but how?&lt;/p&gt;

&lt;p&gt;Am going to leave you alone to think about this. (heading to Khalifa International Stadium for Canada vs Croatia match)&lt;/p&gt;

&lt;p&gt;See you next time.&lt;/p&gt;

</description>
      <category>tableland</category>
      <category>nft</category>
      <category>metadata</category>
      <category>dynamic</category>
    </item>
    <item>
      <title>Signature verification on hybrid method</title>
      <dc:creator>jonyx</dc:creator>
      <pubDate>Sun, 30 Oct 2022 13:52:34 +0000</pubDate>
      <link>https://forem.com/jonyx/signature-verification-on-hybrid-method-2349</link>
      <guid>https://forem.com/jonyx/signature-verification-on-hybrid-method-2349</guid>
      <description>&lt;p&gt;It's true that hybrid approach in the design of web3 applications can not be ignored.&lt;br&gt;
While on chain smart contracts are great to verify things as a single source of truth, it is not so great for data manipulation.&lt;/p&gt;

&lt;p&gt;That's where hybrid comes into play.&lt;/p&gt;

&lt;p&gt;We normally make some calculations off chain on top of synced database with on chain storages, and then reflect the result onto smart contracts as soon as we make sure that it's valid.&lt;/p&gt;

&lt;p&gt;And yet, this validation is not that easy and this is the most vulnerable point in whole application, cause malicious actors can always try to pretend to be a valid user.&lt;/p&gt;

&lt;p&gt;Of course there is a number of approaches for this, as you know, the most well-knowns are Merkle proof and signature verification.&lt;/p&gt;

&lt;p&gt;Today, I am going to deep dive into signature verification in hybrid applications.&lt;br&gt;
I will more focus on the overall architecture rather that how we use signature verification.&lt;/p&gt;

&lt;p&gt;If you are not familiar with signature and EIP712, you'd better first go through it,&lt;br&gt;
&lt;a href="https://nftschool.dev/tutorial/lazy-minting/" rel="noopener noreferrer"&gt;https://nftschool.dev/tutorial/lazy-minting/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the basic diagram below about the flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy4a095rtv15cyh0wjsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy4a095rtv15cyh0wjsp.png" alt=" " width="632" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see there are 3 steps to go in terms of frontend application, I think it will make you more sense to overview this in frontend's perspective since it is actually the entry point for the users to the application.&lt;/p&gt;

&lt;p&gt;Step1, once user triggers actions on the frontend, it will require to sign a message.&lt;br&gt;
And then it will make an API request to backend in order to get signature singed by private wallet.&lt;/p&gt;

&lt;p&gt;Example requests body would be like this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    ...
    userAddress: string,
    userSignature: string,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When it comes to request body, it will vary depends on the actions user made and the application you are building.&lt;br&gt;
For instance, it would include collection address, token id, price in case user is trying to list his NFT on the marketplace.&lt;/p&gt;

&lt;p&gt;Step 2, Once frontend gets signature from the backend side, now it's time to make a transaction, here just for your note, user is actually making a transaction through UI.&lt;/p&gt;

&lt;p&gt;The very basic voucher struct would be something like this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    user: address;
    ...
    nonce: uint256;
    expiry: uint256
    signature: bytes;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In smart contract, there must be some validations about signature, like if the signature is signed by the private wallet, user is matched to transaction sender, nonce is correct, and finally voucher is not expired by checking expiry.&lt;br&gt;
You are free to add more validations for your specific needs.&lt;/p&gt;

&lt;p&gt;FYI, it's obvious to make an update on signatures mapping and nonce once signature is valid and you are about to proceed your update on states.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mapping(address =&amp;gt; uint256) public nonces;
mapping(bytes =&amp;gt; bool) public signatures;

nonces[_voucher.user]++;
signatures[_voucher.signature] = true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Step3. There must be a result from the transaction, right? whether it's succeed or reverted.&lt;br&gt;
Only if transaction is succeed and state variables are updated on chain, we are now ready to update a database in order to sync with on chain.&lt;/p&gt;

&lt;p&gt;You will call the API for this with request body includes&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    ...
    userSignature: string, // signature by user
    txSignature: string, // signature by private wallet
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For this, you have to validate if transaction is succeed and states are updated, it might be a good way to check signature mapping if txSingature is valid or not.&lt;/p&gt;

&lt;p&gt;and you might want to do some updates on your DB and then return the result to the user.&lt;/p&gt;

&lt;p&gt;Finally the user will get the result of his action on UI.&lt;/p&gt;

&lt;p&gt;Thanks for your attention, I tried to make this as short as possible but at the same time, I tried to give you more sense.))&lt;/p&gt;

&lt;p&gt;I am going to walk through tableland implementation for dynamic metadata which is the must-solve thing in P2E games.&lt;br&gt;
&lt;a href="https://docs.tableland.xyz/" rel="noopener noreferrer"&gt;https://docs.tableland.xyz/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So stay tuned.&lt;/p&gt;

</description>
      <category>nft</category>
      <category>signature</category>
      <category>hybrid</category>
      <category>p2e</category>
    </item>
    <item>
      <title>What would be the best choice later on?</title>
      <dc:creator>jonyx</dc:creator>
      <pubDate>Sun, 05 Apr 2020 00:34:34 +0000</pubDate>
      <link>https://forem.com/jonyx/what-would-be-the-best-choice-later-on-e78</link>
      <guid>https://forem.com/jonyx/what-would-be-the-best-choice-later-on-e78</guid>
      <description>&lt;p&gt;Hello guys.&lt;br&gt;
Since COVID has affected our original lives, I am in the need to get remote jobs.&lt;br&gt;
I know that there are lots of frameworks and developers on the job sites.&lt;br&gt;
So it would be important to learn the right skills.&lt;/p&gt;

&lt;p&gt;I am going to choose the best framework for web development to learn later on.&lt;br&gt;
I am now considering Node js/Express js, PHP/Laravel/Symfony, Python/Django/Flask, Ruby on Rails as well as ASP.NET CORE for the backend.&lt;br&gt;
And React js, Vue js, Angular, Svelte for the frontend.&lt;/p&gt;

&lt;p&gt;Not sure which is the best one to learn to get more jobs in the freelancing market place.&lt;/p&gt;

&lt;p&gt;When it comes to the backend, I've heard that it goes without saying that ASP.NET CORE and Laravel have the largest amount of jobs in market places like Upwork.com, linkedin.com and so on.&lt;br&gt;
However, it is true that it would be hard to get this kind of job since there are tons of PHP, ASP.NET developers.&lt;br&gt;
Meanwhile, the cost would be quite low.&lt;/p&gt;

&lt;p&gt;Regarding the frontend, it is obviously true that React has tons of jobs and developers on the Job sites.&lt;/p&gt;

&lt;p&gt;What I am considering are two things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More chances to get jobs means low competition - (more jobs, fewer developers on market place)&lt;/li&gt;
&lt;li&gt;The cost&lt;/li&gt;
&lt;li&gt;consistency - (should keep its value at least a few more years from now)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking forward to your valuable comments.&lt;br&gt;
Thanks in advance,&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Voice conference and Video Room in Twilio API</title>
      <dc:creator>jonyx</dc:creator>
      <pubDate>Sun, 08 Dec 2019 04:33:37 +0000</pubDate>
      <link>https://forem.com/jonyx/voice-conference-and-video-room-in-twilio-api-3p7m</link>
      <guid>https://forem.com/jonyx/voice-conference-and-video-room-in-twilio-api-3p7m</guid>
      <description>&lt;p&gt;I'd like to build video conference platform using Twilio api in PHP for the  backend.&lt;br&gt;
And I want to know how to create voice conference and video room in twilio using PHP.&lt;br&gt;
There are PHP code for this  in twilio doc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$response = new TwiML;

// Start with a &amp;lt;Dial&amp;gt; verb
$dial = $response-&amp;gt;dial();

dial-&amp;gt;conference('My conference', array(
                'startConferenceOnEnter' =&amp;gt; True,
                'endConferenceOnExit' =&amp;gt; True
                ));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have some questions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do I need to return $reponse to the client side?&lt;/li&gt;
&lt;li&gt;How can I connect this voice conference?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please help me with this&lt;br&gt;
Thanks&lt;/p&gt;

</description>
      <category>php</category>
      <category>twilio</category>
      <category>voice</category>
      <category>videoroom</category>
    </item>
  </channel>
</rss>
