<?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>DEV Community: Ayden</title>
    <description>The latest articles on DEV Community by Ayden (@coffiasd).</description>
    <link>https://dev.to/coffiasd</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%2F915214%2Fb10a88f5-58a0-4e1e-8b40-af1947d6fb62.png</url>
      <title>DEV Community: Ayden</title>
      <link>https://dev.to/coffiasd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coffiasd"/>
    <language>en</language>
    <item>
      <title>Audit H/M report Summary from Ondo code4rena</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Fri, 13 Oct 2023 06:07:27 +0000</pubDate>
      <link>https://dev.to/coffiasd/audit-hm-report-summary-from-ondo-code4rena-4dii</link>
      <guid>https://dev.to/coffiasd/audit-hm-report-summary-from-ondo-code4rena-4dii</guid>
      <description>&lt;h2&gt;
  
  
  1.Chain support chain cannot be removed or cleared in bridge contracts.
&lt;/h2&gt;

&lt;p&gt;Contracts provide a way to add support for a chain; however, they do not provide a way to delete it.&lt;br&gt;
When a contract offers an addition method, it's important to consider whether it should also provide a deletion method&lt;/p&gt;

&lt;h2&gt;
  
  
  2.Contract use msg.sender as remote chain receiver when bridge token.
&lt;/h2&gt;

&lt;p&gt;AA wallet like safe has different wallet address on different chains.&lt;br&gt;
This vulnerability requires us to be familiar with some commonly used third-party tools in order to discover it&lt;/p&gt;

&lt;h2&gt;
  
  
  3.Two different transactions can result in the same txnHash value, thus breaking the approval process of transaction minting
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="n"&gt;txnHashToTransaction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;txnHash&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srcSender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider whether the keys in similar mappings are always unique?&lt;/p&gt;

&lt;h2&gt;
  
  
  4.Admin can’t burn tokens from blocklisted addresses because of a check in _beforeTokenTransfer
&lt;/h2&gt;

&lt;p&gt;The burn operation prematurely calls the beforeTransfer function, but beforeTransfer needs to check if the address is blocked, which hinders the successful execution of the burn&lt;/p&gt;

&lt;h2&gt;
  
  
  origin
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://blog.coffiasd.cn/23-10-13.html"&gt;https://blog.coffiasd.cn/23-10-13.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  contact me for SC private review
&lt;/h2&gt;

&lt;p&gt;Twitter:&lt;a href="https://twitter.com/coffiasse"&gt;https://twitter.com/coffiasse&lt;/a&gt;&lt;br&gt;
Github:&lt;a href="https://github.com/coffiasd"&gt;https://github.com/coffiasd&lt;/a&gt;&lt;br&gt;
TG:&lt;a class="mentioned-user" href="https://dev.to/coffiasd"&gt;@coffiasd&lt;/a&gt;&lt;/p&gt;

</description>
      <category>solidity</category>
    </item>
    <item>
      <title>All you need to know about openzeppelin access control</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Thu, 27 Jul 2023 04:57:34 +0000</pubDate>
      <link>https://dev.to/coffiasd/all-you-need-to-know-about-openzeppelin-access-control-18h8</link>
      <guid>https://dev.to/coffiasd/all-you-need-to-know-about-openzeppelin-access-control-18h8</guid>
      <description>&lt;h2&gt;
  
  
  what is access control
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NF6fU7_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/coffiasd/images/blob/6b8faa901198b07cf99a106518dc14842cc4fe1f/030726.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NF6fU7_i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/coffiasd/images/blob/6b8faa901198b07cf99a106518dc14842cc4fe1f/030726.png%3Fraw%3Dtrue" alt="Alt access control" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basiclly,access control means "who is allowed to do this thing".It's quite important for smart contract to specify a particular address who can totally control the whole system.Therefor it's critical to fully understand how to use access control before using it in your project or just copy some example code from somewhere.&lt;br&gt;
In openzeppelin there are mainly two  ways to implementing access control.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single onlyOwner role&lt;/li&gt;
&lt;li&gt;Role-Based Access Control (RBAC)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive into how to master this 2 ways.&lt;/p&gt;
&lt;h2&gt;
  
  
  master how to use it by practice
&lt;/h2&gt;
&lt;h3&gt;
  
  
  OnlyOwner
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;pragma&lt;/span&gt; &lt;span class="n"&gt;solidity&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/access/Ownable.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;MyContract&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Ownable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;normalThing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// anyone can call this normalThing()
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;specialThing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;onlyOwner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// only the owner can call specialThing()!
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;let's create two user for our test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;owner address&lt;/li&gt;
&lt;li&gt;arbitrary address
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;arbitrary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x101&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and the we use owner address to create the smart contract,it's quite simple you don't even need to pass any parameters.openzeppelin &lt;code&gt;Ownable&lt;/code&gt; would set msg.sender as it's owner as default.we use foundry for testing,if you're not familiar  with  foundry,go and learn it first before proceeding further.&lt;/p&gt;

&lt;p&gt;Firstly,we use owner address create our smart contract above in foundry test contract setUp function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;//let's set address owner to msg.sender.
&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//create the contract.
&lt;/span&gt;&lt;span class="n"&gt;myContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyContract&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we use the arbitrary address to invoke the &lt;code&gt;specialThing&lt;/code&gt; function which is protected by onlyOwner modifier.As expect the invoke revert because of access control.Here goes the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;//use arbitrary address invoke specialThing() function.
&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectRevert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ownable: caller is not the owner"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;specialThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally,we use our owner who master the contract invoke the &lt;code&gt;specialThing&lt;/code&gt; function.As you see the owne succeed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;//switch to owner.
&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;specialThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want the whole example codes go for:&lt;a href="https://gist.github.com/coffiasd/84552b5a33845fa567bfc3aa5204d460"&gt;https://gist.github.com/coffiasd/84552b5a33845fa567bfc3aa5204d460&lt;/a&gt;&lt;br&gt;
If you have any questions, you can also reach me through the contact information below.&lt;/p&gt;
&lt;h3&gt;
  
  
  Role-Based Access Control
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;pragma&lt;/span&gt; &lt;span class="n"&gt;solidity&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/access/AccessControl.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"@openzeppelin/contracts/token/ERC20/ERC20.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;MyToken2&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ERC20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AccessControl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create a new role identifier for the minter role
&lt;/span&gt;    &lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;constant&lt;/span&gt; &lt;span class="n"&gt;MINTER_ROLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MINTER_ROLE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;minter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ERC20&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"TKN"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_grantRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEFAULT_ADMIN_ROLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Grant the minter role to a specified account
&lt;/span&gt;        &lt;span class="n"&gt;_grantRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MINTER_ROLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Check that the calling account has the minter role
&lt;/span&gt;        &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MINTER_ROLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"Caller is not a minter"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can create whatever role we want in Role-Based Access Control (RBAC) contract.Let's say we want create a minter role who can mint some ERC20 token.We can use a special constant &lt;code&gt;bytes32&lt;/code&gt; as the name of the role like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create a new role identifier for the minter role
&lt;/span&gt;&lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;constant&lt;/span&gt; &lt;span class="n"&gt;MINTER_ROLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MINTER_ROLE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firstly,we use &lt;code&gt;owner&lt;/code&gt; address as our minter to create our access control contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt; &lt;span class="n"&gt;myToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyToken2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we use the arbitrary user to mint some ERC20 token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;//use arbitrary address invoke mint() function.
&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectRevert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Caller is not a minter"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the above invoke would be revert because of arbitrary don't hold the minter role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;//switch to owner.
&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we switch msg.sender to owner the call would successed.&lt;/p&gt;

&lt;p&gt;What's more? we can use owner address to grant a &lt;code&gt;minter&lt;/code&gt; role whoever we want.Let's say we grant the &lt;code&gt;minter&lt;/code&gt; role to the arbitrary address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grantRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MINTER_ROLE"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After invoke the grantRole function the arbitrary has the right to mint token.&lt;/p&gt;

&lt;p&gt;At the same time,arbitrary address don't has the right to grant role to another address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectRevert&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grantRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MINTER_ROLE"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1001&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the owner we also have the right to revoke role we grant before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;revokeRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MINTER_ROLE"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arbitrary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectRevert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Caller is not a minter"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;myToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we invoke role of  arbitrary,he can't mint ERC20 token anymore.&lt;/p&gt;

&lt;p&gt;If you want the whole example codes go for:&lt;a href="https://gist.github.com/coffiasd/340241d63980dc9d423e4ece2f9b20db"&gt;https://gist.github.com/coffiasd/340241d63980dc9d423e4ece2f9b20db&lt;/a&gt;&lt;br&gt;
If you have any questions, you can also reach me through the contact information below.&lt;/p&gt;

&lt;p&gt;Origin:&lt;a href="https://blog.coffiasd.cn/03-07-26.html"&gt;https://blog.coffiasd.cn/03-07-26.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  let's connect
&lt;/h2&gt;

&lt;p&gt;Twitter:&lt;a href="https://twitter.com/coffiasse"&gt;https://twitter.com/coffiasse&lt;/a&gt;&lt;br&gt;
Github:&lt;a href="https://github.com/coffiasd"&gt;https://github.com/coffiasd&lt;/a&gt;&lt;br&gt;
TG:&lt;a class="mentioned-user" href="https://dev.to/coffiasd"&gt;@coffiasd&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to use solidity CREATE and CREATE2</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Thu, 27 Jul 2023 04:55:33 +0000</pubDate>
      <link>https://dev.to/coffiasd/how-to-use-solidity-create-and-create2-25hb</link>
      <guid>https://dev.to/coffiasd/how-to-use-solidity-create-and-create2-25hb</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fG9W-NMS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i04z0gzhvaekjmlcr8vd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fG9W-NMS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i04z0gzhvaekjmlcr8vd.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are 2 major ways to deploy smart contract &lt;code&gt;CREATE&lt;/code&gt; and &lt;code&gt;CREATE2&lt;/code&gt;. They look quite similar, but there are still some differences.CREATE2 and CREATE are one of solidity opcode which give us the ability to predict the address where a contract will be deployed before we deploy a smart contract.You might be curious about what opcode is.Opcodes are the fundamental building blocks of EVM bytecode, and each opcode represents a specific operation that the EVM can perform. For example, there are opcodes for arithmetic operations, logical operations, storage access, memory manipulation, conditional branching, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CREATE
&lt;/h2&gt;

&lt;p&gt;Smart contracts can be created both by other contracts and regular EOA.They both compute the new address the same way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;new_address &lt;span class="o"&gt;=&lt;/span&gt; keccak256&lt;span class="o"&gt;(&lt;/span&gt;sender, nonce&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So each created address is associated with a nonce value.Nonce increased on every transaction.It is related to the number of transactions we make and is unpredictable. That's why we need CREATE2.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CREATE2 ?
&lt;/h2&gt;

&lt;p&gt;The whole idea behind this opcode is to make the resulting address independent of future events. Regardless of what may happen on the blockchain, it will always be possible to deploy the contract at the precomputed address.There are four parameters in CREATE2 function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0xFF&lt;/li&gt;
&lt;li&gt;the address of sender&lt;/li&gt;
&lt;li&gt;A salt (random value from sender)&lt;/li&gt;
&lt;li&gt;bytecode (the code of the new contract)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;new_address &lt;span class="o"&gt;=&lt;/span&gt; keccak256&lt;span class="o"&gt;(&lt;/span&gt;0xFF, sender, salt, bytecode&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why we need CREATE2 ?
&lt;/h2&gt;

&lt;p&gt;Imagine a scenario where you need to deploy a contract to multiple networks, and precisely at that moment, you need to store the addresses of the yet-to-be-deployed contracts as storage parameters within the currently deployed contract. In such cases, you would require knowing the future addresses of the contracts to be deployed in advance.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use hash function to calculate address.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="kt"&gt;bytes1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xff&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;_salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TokenTemplate&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;creationCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use deploy to get the deployed address.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;bytes&lt;/span&gt; &lt;span class="k"&gt;memory&lt;/span&gt; &lt;span class="n"&gt;bytecode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;_salt&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;payable&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;assembly&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;create2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;callvalue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// wei sent with current call
&lt;/span&gt;                &lt;span class="c1"&gt;// Actual code starts after skipping the first 32 bytes
&lt;/span&gt;                &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytecode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;mload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytecode&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Load the size of code contained in the first 32 bytes
&lt;/span&gt;                &lt;span class="n"&gt;_salt&lt;/span&gt; &lt;span class="c1"&gt;// Salt from function arguments
&lt;/span&gt;            &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;iszero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extcodesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;revert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can find the whole code on github:&lt;br&gt;
&lt;a href="https://gist.github.com/coffiasd/c2ff1a2d718d286b9064873be2fe079a"&gt;https://gist.github.com/coffiasd/c2ff1a2d718d286b9064873be2fe079a&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Origin: &lt;a href="https://blog.coffiasd.cn/03-07-24.html"&gt;https://blog.coffiasd.cn/03-07-24.html&lt;/a&gt;&lt;br&gt;
Follow my twitter:&lt;a href="https://twitter.com/coffiasse"&gt;https://twitter.com/coffiasse&lt;/a&gt;&lt;br&gt;
TG:&lt;a class="mentioned-user" href="https://dev.to/coffiasd"&gt;@coffiasd&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Merkle树的逻辑和证明</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Mon, 17 Jul 2023 05:29:43 +0000</pubDate>
      <link>https://dev.to/coffiasd/merkleshu-de-luo-ji-he-zheng-ming-4an</link>
      <guid>https://dev.to/coffiasd/merkleshu-de-luo-ji-he-zheng-ming-4an</guid>
      <description>&lt;h2&gt;
  
  
  什么是Merkle树
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EPc3zPZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9onfwb5psfxgpgvmki52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EPc3zPZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9onfwb5psfxgpgvmki52.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  定义
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Merkle Tree&lt;/code&gt;，也叫默克尔树或哈希树，是区块链的底层加密技术，被比特币和以太坊区块链广泛采用。Merkle Tree是一种自下而上构建的加密树，每个叶子是对应数据的哈希，而每个非叶子为它的2个子节点的哈希。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vk1cCy5S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b3h5d2gsr82lqbj9qbs9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vk1cCy5S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b3h5d2gsr82lqbj9qbs9.png" alt="Image description" width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  如何生成Merkle树的数据
&lt;/h3&gt;

&lt;p&gt;在solidity中我们通过keccak256算法计算hash值:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toHashValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="err"&gt;前&lt;/span&gt;
&lt;span class="mh"&gt;0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2&lt;/span&gt;

&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="err"&gt;后&lt;/span&gt;
&lt;span class="mh"&gt;0x999bf57501565dbd2fdcea36efa2b9aef8340a8901e3459f4a4c926275d36cdb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在对叶子节点的值进行hash运算之后，再把相邻的节点再进行hash运算，直到只剩下一个根节点。&lt;br&gt;
假设存在两个相邻的节点A和B,那么在进行hash运算的时候到地址是hash(A+B)呢？还是hash(B+A)呢？其实这是由A和B的大小决定的，在openzeppelin对应的merkle代码中我们可以找到这么一段代码:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;_hashPair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;pure&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bytes32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_efficientHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_efficientHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;总结来说就是把相对小的数值放到前面去这么来排序计算hash值。这个地方在自己动手实际运算的时候可能会有些许困惑。&lt;br&gt;
在实际的项目中一般只需要把计算的最后结果的根hash值存储到合约中，如果大量的地址都需要存到合约中的话会消耗大量的gas费。经过merkle树计算之后，大大的减少了需要存储的数据。&lt;br&gt;
通过一段foundry的setUp演示下如何计算和存储root hash值:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;
    &lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;bytes32&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;bytes32&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;memory&lt;/span&gt; &lt;span class="n"&gt;addrss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x2d886570A0dA04885bfD6eb48eD8b8ff01A0eb7e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xed857ac80A9cc7ca07a1C213e79683A1883df07B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;//通过地址列表计算叶子节点的hash值
&lt;/span&gt;        &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;
        &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;
        &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;
        &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addrss&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;

        &lt;span class="c1"&gt;//计算第二层的hash值
&lt;/span&gt;        &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;
        &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;

        &lt;span class="c1"&gt;//计算根的hash值
&lt;/span&gt;        &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;为了演示方便我们值写了4个地址，实际项目中可能地址数量非常大。&lt;/p&gt;

&lt;h2&gt;
  
  
  如何来验证Merkle树
&lt;/h2&gt;

&lt;p&gt;在合约中存储到root hash值之后我们如何去验证由客户端发过来的地址是否是有效地址或者说在白名单中的地址呢？&lt;br&gt;
首先我们需要将地址进行hash运算，作为第三个参数，然后将地址相邻的hash值作为proof传到验证函数中。&lt;br&gt;
proof列表对应下面图片中的红色标记区域&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gTcWvoy---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ie841nie2fo1qt4e8ana.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gTcWvoy---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ie841nie2fo1qt4e8ana.png" alt="Image description" width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;测试的验证方法:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testVerify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;address&lt;/span&gt; &lt;span class="n"&gt;proofAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;bytes32&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;memory&lt;/span&gt; &lt;span class="n"&gt;proof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;bytes32&lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;leafs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;MerkleProof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodePacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proofAddress&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;完整的foundry测试代码:&lt;a href="https://gist.github.com/coffiasd/96022abd7f9a8a2189bda14bf9e755dc"&gt;https://gist.github.com/coffiasd/96022abd7f9a8a2189bda14bf9e755dc&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  在实际项目中的应用场景
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;发放空投&lt;/li&gt;
&lt;li&gt;NFT的白名单&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  在合约审计中的常见漏洞
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;parentHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bytes32&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;pure&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bytes32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;abi.encode(address, uint)将会输出64字节。由于abi.encode(bytes32, bytes32)也是64字节，因此在叶子节点和父节点之间可能会发生哈希碰撞。&lt;/p&gt;

&lt;p&gt;Follow我的推进行交流学习:&lt;a href="https://twitter.com/nifty12111"&gt;https://twitter.com/nifty12111&lt;/a&gt;&lt;br&gt;
TG:&lt;a class="mentioned-user" href="https://dev.to/coffiasd"&gt;@coffiasd&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Solidity Assembly的基础用法</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Sat, 15 Jul 2023 02:23:06 +0000</pubDate>
      <link>https://dev.to/coffiasd/solidity-assemblyde-ji-chu-yong-fa-499k</link>
      <guid>https://dev.to/coffiasd/solidity-assemblyde-ji-chu-yong-fa-499k</guid>
      <description>&lt;h2&gt;
  
  
  什么是Assembly
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VD7-NbM_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h97shde4euu7d9nrpbaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VD7-NbM_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h97shde4euu7d9nrpbaj.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
在编写Solidity代码时，我们可以使用&lt;code&gt;assembly{}&lt;/code&gt;关键字开始编写Yul代码，它是一种简化且扩展了的汇编语言。通过使用assembly，我们可以直接访问堆栈，并优化代码以提高内存效率，从而减少执行交易所需的燃气量。这最终降低了用户的交易成本。&lt;/p&gt;

&lt;p&gt;然而，在可读性方面存在一些妥协。许多前端开发人员可以阅读Solidity智能合约并理解正在执行的功能以及如何将其应用到他们的web3查询中。相比之下，汇编可能会让人感到有些困惑，如果你不熟悉低级编程，可能很难理解其逻辑和流程。&lt;/p&gt;
&lt;h2&gt;
  
  
  操作码列表
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;操作码&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;add(x, y)&lt;/td&gt;
&lt;td&gt;将栈中的前两个值相加，并用结果替换它们&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sub(x, y)&lt;/td&gt;
&lt;td&gt;减法操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mul(x, y)&lt;/td&gt;
&lt;td&gt;乘法操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;div(x, y)&lt;/td&gt;
&lt;td&gt;除法操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mod(x, y)&lt;/td&gt;
&lt;td&gt;取模操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lt(x, y)&lt;/td&gt;
&lt;td&gt;小于。如果 x 小于 y，则返回 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gt(x, y)&lt;/td&gt;
&lt;td&gt;大于&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;eq(x, y)&lt;/td&gt;
&lt;td&gt;等于。如果 x 等于 y，则返回 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;not(x)&lt;/td&gt;
&lt;td&gt;按位取反 (1010 &amp;gt; 0101)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;and(x, y)&lt;/td&gt;
&lt;td&gt;按位与 (1000 AND 1100 &amp;gt; 1000)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;or(x, y)&lt;/td&gt;
&lt;td&gt;按位或 (1000 AND 1100 &amp;gt; 1100)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;xor(x, y)&lt;/td&gt;
&lt;td&gt;按位异或 (1000 XOR 1100 &amp;gt; 0100)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;byte(n, x)&lt;/td&gt;
&lt;td&gt;X 的第 N 个字节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;keccak256(pos, n)&lt;/td&gt;
&lt;td&gt;本地哈希算法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pop(x)&lt;/td&gt;
&lt;td&gt;从栈中弹出 X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mload(pos)&lt;/td&gt;
&lt;td&gt;加载存储在位置 pos 的内存数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mstore(pos, value)&lt;/td&gt;
&lt;td&gt;在位置 pos 的memory中存储值 value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sload(pos)&lt;/td&gt;
&lt;td&gt;加载存储在位置 pos 的存储数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sstore(pos, value)&lt;/td&gt;
&lt;td&gt;在位置 pos 的storage中存储值 value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;balance(address)&lt;/td&gt;
&lt;td&gt;以 wei 为单位返回地址的以太币余额&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;call(gas, address, value, in, insize, out, outsize)&lt;/td&gt;
&lt;td&gt;调用外部合约，也可用于发送资金，成功时返回 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delegatecall(gas, address, value, in, insize, out, outsize)&lt;/td&gt;
&lt;td&gt;与上述相同，但由用户而不是合约进行调用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;revert(p, s)&lt;/td&gt;
&lt;td&gt;撤销事务和任何状态更改&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;return(p, s)&lt;/td&gt;
&lt;td&gt;结束执行并返回数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;这里需要注意的是&lt;code&gt;mstore&lt;/code&gt;和&lt;code&gt;sstore&lt;/code&gt;的区别，主要存储的位置的不一致，一种是存储在memory中，另一种是存储在storage中。&lt;/p&gt;
&lt;h2&gt;
  
  
  使用案例
&lt;/h2&gt;
&lt;h3&gt;
  
  
  读写
&lt;/h3&gt;

&lt;p&gt;下面我们通过一个例子展示下如何使用&lt;code&gt;Assembly&lt;/code&gt;把数据存储到storage中，然后通过函数读取的方式读出来。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testAssembly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//定义一个存储的值方便测试.
&lt;/span&gt;        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;//将x存储到storage中。
&lt;/span&gt;        &lt;span class="k"&gt;assembly&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;sstore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;//在storage中读取x的值,其中0是pos
&lt;/span&gt;        &lt;span class="k"&gt;assembly&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;readX&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;//将readX的值存储到memory,pos == 0x80的位置。
&lt;/span&gt;            &lt;span class="n"&gt;mstore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;readX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;//将0x80中的值取出来.
&lt;/span&gt;        &lt;span class="k"&gt;assembly&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;//判断最终取出来的v == x?
&lt;/span&gt;        &lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;上诉的例子在实际项目中不太可能出现，只是为了展示读写的过程。&lt;/p&gt;

&lt;h3&gt;
  
  
  基础运算
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testAssembly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//定义一个存储的值方便测试.
&lt;/span&gt;        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;//将x存储到storage中。
&lt;/span&gt;        &lt;span class="k"&gt;assembly&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;//判断最终取出来的r == x?
&lt;/span&gt;        &lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow我的推进行交流学习:&lt;a href="https://twitter.com/nifty12111"&gt;https://twitter.com/nifty12111&lt;/a&gt;&lt;br&gt;
TG:&lt;a class="mentioned-user" href="https://dev.to/coffiasd"&gt;@coffiasd&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>手摸手教你如何使用foundry进行测试脚本编写</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Fri, 14 Jul 2023 01:53:47 +0000</pubDate>
      <link>https://dev.to/coffiasd/shou-mo-shou-jiao-ni-ru-he-shi-yong-foundryjin-xing-ce-shi-jiao-ben-bian-xie-1c4j</link>
      <guid>https://dev.to/coffiasd/shou-mo-shou-jiao-ni-ru-he-shi-yong-foundryjin-xing-ce-shi-jiao-ben-bian-xie-1c4j</guid>
      <description>&lt;h2&gt;
  
  
  什么是foundry?
&lt;/h2&gt;

&lt;p&gt;foundry是一个solidity智能合约开发工具。可以帮你管理依赖包，编译项目，运行测试脚本，还可以让你通过命令行工具或者script脚本和链上合约进行交互。和hardhat不同的地方是，hardhat我们还是主要用来开发大型的合约项目，但是foundry用来进行编写测试脚本我认为是非常方便的。主要的特点是可以直接使用solidity编写合约测试脚本，无需在JavaScript和solidity之间进行切换。虽然在hardhat也可以编写测试脚本，但是有时候需要切换语言或者对类型进行转换相对会比较麻烦。&lt;/p&gt;

&lt;h2&gt;
  
  
  安装和配置
&lt;/h2&gt;

&lt;p&gt;Foundryup是foundry的安装器。我们可以直接通过终端命令行进行安装:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://foundry.paradigm.xyz | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;或者要是你喜欢也可以通过源码的方式进行编译安装&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# clone the repository&lt;/span&gt;
git clone https://github.com/foundry-rs/foundry.git
&lt;span class="nb"&gt;cd &lt;/span&gt;foundry
&lt;span class="c"&gt;# install Forge + Cast&lt;/span&gt;
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; ./cli &lt;span class="nt"&gt;--profile&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;--bins&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;span class="c"&gt;# install Anvil&lt;/span&gt;
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; ./anvil &lt;span class="nt"&gt;--profile&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;span class="c"&gt;# install Chisel&lt;/span&gt;
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; ./chisel &lt;span class="nt"&gt;--profile&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  初始化
&lt;/h2&gt;

&lt;p&gt;我们可以通过forge命令行直接初始化新项目&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge init helle_foundry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;初始化之后的大概是这么个目录结构:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;hello_foundry
&lt;span class="nv"&gt;$ &lt;/span&gt;tree &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; 1
&lt;span class="nb"&gt;.&lt;/span&gt;
├── lib     依赖的包文件目录
├── script  自定义的脚本目录
├── src     合约源码目录
└── &lt;span class="nb"&gt;test    &lt;/span&gt;测试脚本目录

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  特性和使用
&lt;/h2&gt;

&lt;h3&gt;
  
  
  编写测试脚本
&lt;/h3&gt;

&lt;p&gt;测试脚本的基本代码结构：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;pragma&lt;/span&gt; &lt;span class="n"&gt;solidity&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"forge-std/Test.sol"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;ContractBTest&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;testNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;testNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_NumberIs42&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;assertEq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testFail_Subtract43&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;testNumber&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在上面的例子中每个test函数都是相互独立的，setUp函数类似于我们的构造函数，会首先进行调用setUp函数进行初始化。在我们实际的操作中，可以直接导入需要测试的合约，然后在setUp中对合约进行初始化。我们只需要一个变量就能调用目标合约中的函数进行测试。&lt;/p&gt;

&lt;p&gt;运行测试脚本的命令:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--match-contract&lt;/span&gt; &lt;span class="s2"&gt;"ContractBTest(合约名称)"&lt;/span&gt; &lt;span class="nt"&gt;-vvv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  debug
&lt;/h3&gt;

&lt;p&gt;我们可以通过&lt;code&gt;-vvv&lt;/code&gt; 和 &lt;code&gt;-vvvv&lt;/code&gt;进行数据跟踪。在打印出来的日志中，我们通过颜色来区分不同的错误类型(如果你的终端支持颜色显示的话)：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;绿色 : 正常的调用&lt;/li&gt;
&lt;li&gt;红色 : 回滚的调用&lt;/li&gt;
&lt;li&gt;蓝色 : 作弊码的调用&lt;/li&gt;
&lt;li&gt;青色 : 日志&lt;/li&gt;
&lt;li&gt;黄色 : 合约部署
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="o"&gt;[&lt;/span&gt;24661] OwnerUpOnlyTest::testIncrementAsOwner&lt;span class="o"&gt;()&lt;/span&gt;
    ├─ &lt;span class="o"&gt;[&lt;/span&gt;2262] OwnerUpOnly::count&lt;span class="o"&gt;()&lt;/span&gt;
    │   └─ ← 0
    ├─ &lt;span class="o"&gt;[&lt;/span&gt;20398] OwnerUpOnly::increment&lt;span class="o"&gt;()&lt;/span&gt;
    │   └─ ← &lt;span class="o"&gt;()&lt;/span&gt;
    ├─ &lt;span class="o"&gt;[&lt;/span&gt;262] OwnerUpOnly::count&lt;span class="o"&gt;()&lt;/span&gt;
    │   └─ ← 1
    └─ ← &lt;span class="o"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  fuzz测试
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;SafeTest&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testFuzz_Withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;payable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nb"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;preBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nb"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;postBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nb"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;assertEq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preBalance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;postBalance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;比如上面的提款测试，普通的test测试函数需要自定义一个固定的amount金额，但是这个指定的amount不能覆盖到所有的情景，另一个选择就是使用testFuzz.fuzz测试的函数名和普通测试对比只是多了fuzz，需要注意的是所有的测试函数需要用&lt;code&gt;test&lt;/code&gt;或者&lt;code&gt;testFuzz&lt;/code&gt;开头否则是不会被认为是一个测试函数的。&lt;/p&gt;

&lt;h3&gt;
  
  
  console.log日志打印
&lt;/h3&gt;

&lt;p&gt;在solidity中打印日志需要提前对日志内容的类型进行定义。foundry支持下面的一些数据类型进行日志打印，可以帮助我们进行debug:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;console.logInt(int i)&lt;/li&gt;
&lt;li&gt;console.logUint(uint i)&lt;/li&gt;
&lt;li&gt;console.logString(string memory s)&lt;/li&gt;
&lt;li&gt;console.logBool(bool b)&lt;/li&gt;
&lt;li&gt;console.logAddress(address a)&lt;/li&gt;
&lt;li&gt;console.logBytes(bytes memory b)&lt;/li&gt;
&lt;li&gt;console.logBytes1(bytes1 b)&lt;/li&gt;
&lt;li&gt;console.logBytes2(bytes2 b)&lt;/li&gt;
&lt;li&gt;console.logBytes32(bytes32 b)
对于一些更加复杂的数据结构，比如我们的目标合约中返回了一个struct类型的数据。我们可以直接使用targetContract.StructName对数据进行定义。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  assert
&lt;/h3&gt;

&lt;p&gt;foundry中主要有3种类型的assert&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assert(conditon) 判断一个bool值&lt;/li&gt;
&lt;li&gt;assertEq(a,b)    判断a，b两个值是否相等&lt;/li&gt;
&lt;li&gt;assertTrue(condition,"reason")
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testGetTotalShares&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;assertEq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prizePool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTotalShares&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  时间和区块进行改变
&lt;/h3&gt;

&lt;p&gt;某些合约中可能有时间间隔，比如一个stake asset操作之后，可能需要一个月的时间间隔之后才能进行下一次操作，这个时候我们可以直接去修改evm中的时间&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vm.warp&lt;span class="o"&gt;(&lt;/span&gt;block.timstamp + 30 days&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;或者我们也可以对区块进行增加&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vm.roll&lt;span class="o"&gt;(&lt;/span&gt;block.number + 1&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  vm.expectRevert
&lt;/h3&gt;

&lt;p&gt;在某些测试中，对于条件不满足的情况下，合约逻辑中可能会存在一些revert的情况，我们需要对这些revert进行捕捉的时候可以用到&lt;code&gt;vm.expertRevert&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expectRevert() &lt;/li&gt;
&lt;li&gt;expectRevert(bytes4 message)&lt;/li&gt;
&lt;li&gt;expectRevert(bytes calldata message)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testLowLevelCallRevert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectRevert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error message"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;revertsAsExpected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myContract&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nb"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myCalldata&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;revertsAsExpected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"expectRevert: call did not revert"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;有些合约对一些多次出现的错误可能把它定义为一个error类型，这个时候我们可以通过&lt;code&gt;CustomError.selector&lt;/code&gt;对错误进行捕捉。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vm.expectRevert&lt;span class="o"&gt;(&lt;/span&gt;CustomError.selector&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vm.expectRevert&lt;span class="o"&gt;(&lt;/span&gt;
    abi.encodeWithSelector&lt;span class="o"&gt;(&lt;/span&gt;CustomError.selector, 1, 2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;对于那些直接revert并没有定义错误的情况下:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; vm.expectRevert&lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;follow我的推进行交流学习:&lt;a href="https://twitter.com/nifty12111"&gt;https://twitter.com/nifty12111&lt;/a&gt;&lt;br&gt;
TG:&lt;a class="mentioned-user" href="https://dev.to/coffiasd"&gt;@coffiasd&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How do i win 3 hackathon in one month</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Sat, 25 Feb 2023 12:39:11 +0000</pubDate>
      <link>https://dev.to/coffiasd/how-do-i-win-3-hackathon-in-one-month-36j5</link>
      <guid>https://dev.to/coffiasd/how-do-i-win-3-hackathon-in-one-month-36j5</guid>
      <description>&lt;h1&gt;
  
  
  overview
&lt;/h1&gt;

&lt;p&gt;If you are interested in competing in a Web3 hackathon, it is important to understand that a hackathon is a challenging event that requires a lot of work, dedication, and creativity. However, with the right mindset and approach, you can increase your chances of winning. Here are some tips to help you win a Web3 hackathon:&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the Theme and Criteria
&lt;/h2&gt;

&lt;p&gt;The first step to winning a Web3 hackathon is to understand the theme and criteria of the hackathon. Make sure you read the rules and guidelines carefully, so that you can create a project that meets the requirements and stands out from the competition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Research and Brainstorm
&lt;/h2&gt;

&lt;p&gt;Once you know the theme and criteria of the hackathon, start researching and brainstorming ideas for your project. Consider what problems you can solve using Web3 technologies and how your project can add value to the Web3 ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Focus on User Experience
&lt;/h2&gt;

&lt;p&gt;User experience is an important factor in creating a successful Web3 project. Consider how your project can make the user's experience smoother, more efficient, and more enjoyable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a Minimum Viable Product (MVP)
&lt;/h2&gt;

&lt;p&gt;A minimum viable product (MVP) is a basic version of your project that has enough features to demonstrate its value. Building an MVP is important because it allows you to get feedback from users and judges, and make improvements before the final presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Web3 Technologies
&lt;/h2&gt;

&lt;p&gt;Web3 technologies are the backbone of the Web3 ecosystem. To win a Web3 hackathon, it is important to implement Web3 technologies in your project. Some examples of Web3 technologies include blockchain, decentralized storage, and smart contracts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Clear and Concise Pitch
&lt;/h2&gt;

&lt;p&gt;Your pitch is the key to winning a Web3 hackathon. Make sure your pitch is clear, concise, and compelling. Focus on the most important features of your project and explain how your project solves a real-world problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice and Refine Your Presentation
&lt;/h2&gt;

&lt;p&gt;Practice makes perfect. Before the final presentation, practice your pitch and make sure it is well-rehearsed. Also, consider getting feedback from others to refine your presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network and Collaborate with Others
&lt;/h2&gt;

&lt;p&gt;Networking and collaboration are important in a Web3 hackathon. Attend workshops, meetups, and other events to meet other participants and potential collaborators. Collaborating with others can help you create a stronger project and increase your chances of winning.&lt;br&gt;
In conclusion, winning a Web3 hackathon requires hard work, dedication, and creativity. By following these tips, you can increase your chances of winning and make your mark on the Web3 ecosystem. Good luck!&lt;/p&gt;

&lt;p&gt;contact me in social media:&lt;br&gt;
&lt;a href="https://twitter.com/coffiasse"&gt;twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>gitcoin</category>
      <category>solidity</category>
      <category>hackatho</category>
    </item>
    <item>
      <title>How to quick start web3.storage</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Tue, 01 Nov 2022 02:45:43 +0000</pubDate>
      <link>https://dev.to/coffiasd/how-to-quick-start-web3storage-274</link>
      <guid>https://dev.to/coffiasd/how-to-quick-start-web3storage-274</guid>
      <description>&lt;h2&gt;
  
  
  register an account
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;li&gt;Github (recommand)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  install the client
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javascript
npm install web3.storage
golang
go get github.com/web3-storage/go-w3s-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  create a client instance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//get the access token
function getAccessToken(){
    return process.env.TOKEN
}
//creata an instance
function makeStorageClient(){
    return new Web3storage({token:getAccessToken()})
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  preparing files for uploading
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getFiles(){
    const fileInput = document.querySelector('input[type="file"]')
    return fileInput.files
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  upload files to web3.storage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//async upload process
async function storageFiles(files){
    const client = makeStorageClient()
    const cid = await client.put(files)
    return cid
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  directory wrapping
&lt;/h2&gt;

&lt;p&gt;after uploading you'll get a cid of the directory and then the entire link gonna be ipfs:///&lt;br&gt;
to make a gateway link :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://&amp;lt;cid&amp;gt;.ipfs.&amp;lt;gateway-host&amp;gt;/&amp;lt;filename&amp;gt;
https://&amp;lt;gateway-host&amp;gt;/ipfs/&amp;lt;cid&amp;gt;/&amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  storing ipfs content archives?
&lt;/h2&gt;

&lt;p&gt;if you already have some files you can use putCar client function.I don't want to jump into this here.&lt;/p&gt;

&lt;h2&gt;
  
  
  how to access data we uploaded above ?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;using an IPFS http gateway&lt;/li&gt;
&lt;li&gt;using client library&lt;/li&gt;
&lt;li&gt;ipfs command line&lt;/li&gt;
&lt;li&gt;system command line&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  how to query web3.storage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function checkStatus(cid){
    const client = xxxx
    const status = await client.status(cid)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;return data structure&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cid&lt;/li&gt;
&lt;li&gt;created&lt;/li&gt;
&lt;li&gt;dagSize&lt;/li&gt;
&lt;li&gt;pins&lt;/li&gt;
&lt;li&gt;deals&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  how to list files uploaded to web3.storage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = xxxx
for await (const upload of client.list(){
    console.log(upload.name,upload.cid,upload.dagSize)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  listing the content of an IPFS directory
&lt;/h2&gt;

</description>
    </item>
    <item>
      <title>All you need to know for writing a reserve protocol collateral plugins quick start</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Sun, 30 Oct 2022 15:21:34 +0000</pubDate>
      <link>https://dev.to/coffiasd/all-you-need-to-know-for-writing-a-reserve-protocol-collateral-plugins-quick-start-16pj</link>
      <guid>https://dev.to/coffiasd/all-you-need-to-know-for-writing-a-reserve-protocol-collateral-plugins-quick-start-16pj</guid>
      <description>&lt;p&gt;core plugin depends on two plugin types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assets / Collateral (contracts/plugins/assets)&lt;/li&gt;
&lt;li&gt;Trading (contract/plugins/trading) not discussed here&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collateral is erc20 token + below:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;if ERC20 back ?&lt;/li&gt;
&lt;li&gt;refresh()&lt;/li&gt;
&lt;li&gt;status() SOUND/IFFY/DISABLED&lt;/li&gt;
&lt;li&gt;rate exchange&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monetary units
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Unit of Account&lt;/li&gt;
&lt;li&gt;Target unit
RToken maintaining stability or appreciation against its target unit&lt;/li&gt;
&lt;li&gt;Reference unit&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  e.g. of 3 different tokens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Collateral : cUSDC&lt;/li&gt;
&lt;li&gt;Refence : USDC&lt;/li&gt;
&lt;li&gt;Target : USD&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Units definition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;{UoA} unit of account recommand USD here&lt;/li&gt;
&lt;li&gt;{tok} whole token&lt;/li&gt;
&lt;li&gt;{ref} whole reference token&lt;/li&gt;
&lt;li&gt;{target} whole target unit&lt;/li&gt;
&lt;li&gt;{ref/tok} refPerTok()&lt;/li&gt;
&lt;li&gt;{target/ref} targetPerRef()&lt;/li&gt;
&lt;li&gt;{UoA/target} pricePerTarget()&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Basket definition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prime basket
this is set by governance , on changes through successful governance proposals. it consists of an array of triples

e.g. : &lt;/li&gt;
&lt;li&gt;Reference basket

e.g. : &lt;/li&gt;
&lt;li&gt;Collateral bascket

e.g.: &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IAsset interface
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1K9-5wgb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ue1xotlv5s5z36ue1na.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1K9-5wgb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ue1xotlv5s5z36ue1na.jpg" alt="Image description" width="880" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accounting units
&lt;/h3&gt;

&lt;p&gt;before we create a collateral plugin we have to choose 3 accounting units&lt;/p&gt;

&lt;h3&gt;
  
  
  Collateral unit
&lt;/h3&gt;

&lt;p&gt;its just erc20 token&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference unit
&lt;/h3&gt;

&lt;p&gt;to be ask , what's a unit that this collateral token will always be worth the same value or more of .&lt;/p&gt;

&lt;h3&gt;
  
  
  Target unit
&lt;/h3&gt;

&lt;p&gt;target unit has to do with a concept called the target basket. what's prime basket ?&lt;br&gt;
A example of linear combination of target units:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 USD&lt;/li&gt;
&lt;li&gt;0.5 USD + 0.55 EURO&lt;/li&gt;
&lt;li&gt;0.5 USD + 0.35 EURO + 0.00001BTC&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Unit of account
&lt;/h3&gt;

&lt;p&gt;we can assume UoA == USD , because for now USD price are king.&lt;/p&gt;

&lt;h3&gt;
  
  
  Important properties for collateral plugins
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Collateral plugins should be permisionless and should be able to used by any number if RTokens&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Token balance can't be rebasing&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  refresh() should never be revert
&lt;/h3&gt;

&lt;p&gt;refresh is been called before any transactions , it return exchange rates.&lt;br&gt;
if occur an important error , refresh should change the state to &lt;strong&gt;DISABLED&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  strictPrice() price(bool) status()
&lt;/h3&gt;

&lt;h3&gt;
  
  
  the IFFY status should be temporary
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Collateral must default if refPerTok() falls
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Defaulted Collateral must stay defaulted
&lt;/h3&gt;

&lt;p&gt;if status() ever returns disabled , then it must always return disabled in the nearly future&lt;/p&gt;

&lt;h3&gt;
  
  
  Token rewards should be claimable
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;rewardERC20()&lt;/li&gt;
&lt;li&gt;getClaimCalldata()&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Smaller Constraints
&lt;/h3&gt;

&lt;p&gt;The value of the following methods should never change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;isColleteral()&lt;/li&gt;
&lt;li&gt;targetName()&lt;/li&gt;
&lt;li&gt;erc20()&lt;/li&gt;
&lt;li&gt;rewardERC20()&lt;/li&gt;
&lt;li&gt;erc20Deciamls()&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Function-by-function walkthrough
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;strictPrice() {UoA/tok}&lt;/li&gt;
&lt;li&gt;price(bool) {UoA/tok}
if revert depends on the bool value true or false&lt;/li&gt;
&lt;li&gt;refPerTok() {ref/tok}&lt;/li&gt;
&lt;li&gt;targetPerRef() {target/ref}&lt;/li&gt;
&lt;li&gt;pricePerTarget(){UoA/tartget}&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Analyze stolen NFTs that been marked by opensea</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Fri, 07 Oct 2022 12:31:38 +0000</pubDate>
      <link>https://dev.to/coffiasd/analyze-stolen-nfts-that-been-marked-by-opensea-4j0e</link>
      <guid>https://dev.to/coffiasd/analyze-stolen-nfts-that-been-marked-by-opensea-4j0e</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;This is a hackathon data analytics project. I analyze the top 2300 nfts sort by volume。 You can find the detail list from my GitHub repo. Or you can click here。&lt;br&gt;
&lt;a href="https://github.com/coffiasd/hackathon-data-analytics/blob/main/data/RankNFTS.csv"&gt;https://github.com/coffiasd/hackathon-data-analytics/blob/main/data/RankNFTS.csv&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CSV Data
&lt;/h2&gt;

&lt;p&gt;Below is all csv file that i collect.RankNFTs.csv is the top 2300 NFTs list. tokenIds/{contract}.csv is stolen NFTs tokenID list.lastSalePrice/{contract}.csv is the last sale price of each tokenId.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RankNFTs.csv&lt;/li&gt;
&lt;li&gt;tokenIds/{contract}.csv&lt;/li&gt;
&lt;li&gt;lastSalePrice/{contract}.csv&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Python script
&lt;/h2&gt;

&lt;p&gt;You can get the all scripts my github repo above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;getNFTsRankTopVolume.py(get top volume NFTs &amp;amp;&amp;amp; stolen NFTs list)&lt;/li&gt;
&lt;li&gt;getNFTsDetail.py(get NFT’s last sale price)&lt;/li&gt;
&lt;li&gt;caculateStolen.py(caculate Result)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getNftsRankTopVolume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.traitsniper.com/v1/collections?page="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; \
        &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;"&amp;amp;limit=100&amp;amp;sort_total_volume=desc"&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"x-ts-api-key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TraitsniperApiKey&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;caculateContractItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# get collection detail
&lt;/span&gt;    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getCollectionDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# read stolen nfts list
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../data/stolen/lastSalePrice/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                       &lt;span class="n"&gt;contractAddress&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;".csv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# caculate items
&lt;/span&gt;    &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iterrows&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"floor_price"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"floor_price"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"nft_name"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"total_volume"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                       &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"total_volume"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fetch Collections
&lt;/h2&gt;

&lt;p&gt;First and foremost we need to get the list of each collection and then get the list of stolen nfts.&lt;/p&gt;

&lt;p&gt;How to calculate the price of each stolen nft?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If this item has a history price &amp;amp;&amp;amp; the latest_price&amp;gt;floor_price take the latest_price as worth.&lt;/li&gt;
&lt;li&gt;If latest_price&amp;lt;floor_price take the floor_price as worth.&lt;/li&gt;
&lt;li&gt;If this item does’t has a history price then take the current floor price as worth.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# worth
# latest_history_price
# floor_price
&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt; &lt;span class="n"&gt;worth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"latest_history_price"&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;latest_history_price&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;floor_price&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;worth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;latest_history_price&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;worth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floor_price&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;worth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floor_price&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calculate
&lt;/h2&gt;

&lt;p&gt;I analyze each marked as stolen contract to find out the stolen volume and the numbers of stolen NFTs.Below is the output after i run caculateStolen.py you can get source code from my github repo above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tO0a4ZW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48uwa7uk7a9n45sck07i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tO0a4ZW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48uwa7uk7a9n45sck07i.png" alt="Image description" width="880" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create a cool discord bot for your chat group</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Fri, 30 Sep 2022 02:56:31 +0000</pubDate>
      <link>https://dev.to/coffiasd/create-a-cool-discord-bot-for-your-chat-group-2f03</link>
      <guid>https://dev.to/coffiasd/create-a-cool-discord-bot-for-your-chat-group-2f03</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;It's very common to see that some discord groups add a discord bot. What does discord bot can do for us？ It can reply to user depends on what they send。 Let's say when our users send some sad words the bot can encourage she/he by sending some words. Furthermore, when a new member joined our group, the bot can welcome the newcomers because the owner maybe not always online. The bot is scalable you can use it to create something awesome.&lt;/p&gt;

&lt;h2&gt;
  
  
  library
&lt;/h2&gt;

&lt;p&gt;After searching GitHub i found out several discord Api libraries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cog-Creators/Red-DiscordBot(python)&lt;/li&gt;
&lt;li&gt;discordjs/discord.js(javascript)&lt;/li&gt;
&lt;li&gt;Rapptz/discord.py(python)&lt;/li&gt;
&lt;li&gt;bwmarrin/discordgo(golang)
I choose Rapptz/discord.py in this piece, because i damn love python。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install env
&lt;/h2&gt;

&lt;p&gt;First and foremost, we need to install our python env. We need to install python 3.8 or higher version. If you don't wanna to install any local env, that'sthat's ok you can use some cloud env like replit.com or pythonanywhere whatever you want. But for me i installed env using anaconda software. It provides UI and it's quite easy to use。&lt;/p&gt;

&lt;h2&gt;
  
  
  get a bot token
&lt;/h2&gt;

&lt;p&gt;For sure we need a token。 Then how do we get it? Just click "&lt;a href="https://discord.com/developers/applications"&gt;https://discord.com/developers/applications&lt;/a&gt;" and then login your discord account. You will see the new application button near your avatar. After creating an application go to bot page and copy your token. You should be very careful not to leak it。&lt;/p&gt;

&lt;h2&gt;
  
  
  invent bot to our chat group
&lt;/h2&gt;

&lt;p&gt;I hope you have a free discord chat group already。 If not, you can create one for free。Go to our application page again, you will see  Oauth2/URL Generator。 Generate an invite link for your application by picking the scopes and permissions it needs to function。 Get the URL and open it in our browser。That's all。&lt;/p&gt;

&lt;h2&gt;
  
  
  Some awesome python code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;discord&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Logged on as'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# don't respond to ourselves
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'ping'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pong'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;intents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;discord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;intents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;intents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'YOUR TOKEN HERE'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need a proxy you can attach some code like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;intents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://127.0.0.1:10809"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This proxy address is my local proxy address. You should replace it with your own address if you wanna use a proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  result
&lt;/h2&gt;

&lt;p&gt;After you run python demo.py you will see&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2022-09-30 10:15:48 INFO     discord.client logging &lt;span class="k"&gt;in &lt;/span&gt;using static token
2022-09-30 10:15:50 INFO     discord.gateway Shard ID None has connected to Gateway &lt;span class="o"&gt;(&lt;/span&gt;Session ID: xxxxxxx&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Logged on as xxxx-demo#4518
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After all of above is done you will see your bot is online。&lt;br&gt;
If you get any question about discord bot or discord application please feel free to connect me.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to use dune.com to collect some NFTs data</title>
      <dc:creator>Ayden</dc:creator>
      <pubDate>Wed, 14 Sep 2022 13:30:29 +0000</pubDate>
      <link>https://dev.to/coffiasd/how-to-use-dunecom-to-collect-some-nfts-data-478m</link>
      <guid>https://dev.to/coffiasd/how-to-use-dunecom-to-collect-some-nfts-data-478m</guid>
      <description>&lt;h2&gt;
  
  
  What is dune ?
&lt;/h2&gt;

&lt;p&gt;Dune is a powerful tool for blockchain research, complete with all the tools you need to discover,explore,and visualize vast amounts of blockchain data. We can get data via a sql query and then present data as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bar charts&lt;/li&gt;
&lt;li&gt;Area Charts&lt;/li&gt;
&lt;li&gt;Scatter Charts&lt;/li&gt;
&lt;li&gt;Line Charts&lt;/li&gt;
&lt;li&gt;Pie Charts&lt;/li&gt;
&lt;li&gt;Counters&lt;/li&gt;
&lt;li&gt;Tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XRYvAJVs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dune.com/docs/images/dashboard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XRYvAJVs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dune.com/docs/images/dashboard.png" alt="alt image" width="880" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sql guides
&lt;/h2&gt;

&lt;p&gt;Before we get into sql. In case you have no background on relational databases like mysql, let's break down what are relational databases.Relational databases contain a set of data tables so that a user can query some combination of tables to get only the subset of data (rows) they need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jEdk0Du_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/626/0%2AG2IHSoKltVQryGJM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jEdk0Du_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/626/0%2AG2IHSoKltVQryGJM.png" alt="alt image" width="501" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above is an example of a relational database.&lt;br&gt;
With sql query we can get the data we need fast and efficiently.&lt;/p&gt;
&lt;h2&gt;
  
  
  Data sets
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ethereum&lt;/li&gt;
&lt;li&gt;Gnosis chain&lt;/li&gt;
&lt;li&gt;Polygon&lt;/li&gt;
&lt;li&gt;Optimsm&lt;/li&gt;
&lt;li&gt;BNB smart chain&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Create an dashboards via sql
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vObt9w4I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dune.com/docs/features/queries/images/query-editor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vObt9w4I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dune.com/docs/features/queries/images/query-editor.png" alt="alt image" width="880" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH token_names as (
select * from
nft."tokens"
)

select name, symbol, count(*) as number_of_nfts
from erc721."ERC721_evt_Transfer" as scam_transfers
join token_names on token_names.contract_address = scam_transfers.contract_address
where scam_transfers."to" = '\x3E0DeFb880cd8e163baD68ABe66437f99A7A8A74'
AND scam_transfers."from" != '\x0000000000000000000000000000000000000000'
group by name, symbol
order by 3 desc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
