<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Bin</title>
        <link>https://paragraph.com/@bin-6</link>
        <description>@bloom_cry
</description>
        <lastBuildDate>Mon, 25 May 2026 12:48:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Bin</title>
            <url>https://storage.googleapis.com/papyrus_images/3d08beac67139cb5fbcb3b32953e3cf8a8ec5438536adea4b6a28b8719e7b5cb.jpg</url>
            <link>https://paragraph.com/@bin-6</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[ Best Way to Deploy Contract on Multi Chains]]></title>
            <link>https://paragraph.com/@bin-6/best-way-to-deploy-contract-on-multi-chains</link>
            <guid>FUAc9tAeXcF1X4zG1mdn</guid>
            <pubDate>Sun, 10 Nov 2024 12:02:55 GMT</pubDate>
            <description><![CDATA[How does you contract address comes from? What is the best way to deploy same address on different EVM chains? Here is the answer: Keyless + FactoryTL, DRWhen the goal is to deploy your contracts to the same addresses on multiple blockchains, fewer factors affecting deployment addresses make it easier to achieveCreate is related to wallet address and nocne. Create2 is influenced by address of factory, salt, and bytecode. Create3 is affected by salt and factory address, not influenced by bytec...]]></description>
            <content:encoded><![CDATA[<p>How does you contract address comes from? What is the best way to deploy same address on different EVM chains?</p><p>Here is the answer:</p><p>Keyless + Factory</p><h1 id="h-tl-dr" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">TL, DR</h1><ul><li><p>When the goal is to deploy your contracts to the same addresses on multiple blockchains, fewer factors affecting deployment addresses make it easier to achieve</p></li><li><p>Create is related to wallet address and nocne. Create2 is influenced by address of factory, salt, and bytecode. Create3 is affected by salt and factory address, not influenced by bytecode</p></li><li><p>Keyless does not need to maintain the wallet address of the deployment factory</p></li></ul><h1 id="h-contract-creation" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Contract Creation</h1><p>We have three ways to deploy contract, create and create2 are EVM codes and create3 is not.</p><h2 id="h-create" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Create</h2><pre data-type="codeBlock" text="address = keccak256(rlp([sender_address,sender_nonce]))[12:]
"><code><span class="hljs-selector-tag">address</span> = keccak256(rlp(<span class="hljs-selector-attr">[sender_address,sender_nonce]</span>))<span class="hljs-selector-attr">[12:]</span>
</code></pre><p>address is determined by the sender and sender nonce.</p><p>And here is the opcode:</p><pre data-type="codeBlock" text="create(vaule,offset,size);
"><code><span class="hljs-built_in">create</span>(vaule,offset,size);
</code></pre><p><strong>If want to keep addresses are same on different EVM chains, addresses should not be associated with nonce.</strong></p><h2 id="h-create2" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Create2</h2><p>By create2, contract can be calculated:</p><pre data-type="codeBlock" text="address = keccak256(0xff + sender_address + salt + keccak256(initialisation_code))[12:]
"><code><span class="hljs-keyword">address</span> <span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-number">0xff</span> <span class="hljs-operator">+</span> sender_address <span class="hljs-operator">+</span> salt <span class="hljs-operator">+</span> <span class="hljs-built_in">keccak256</span>(initialisation_code))[<span class="hljs-number">12</span>:]
</code></pre><p>sender_address is usually contract factory address.</p><p>So the contract is influenced by: <strong>address of factory</strong>, <strong>salt</strong>, and <strong>contract bytecode.</strong> It&apos;s possible to know the contract&apos;s address on blockchain before it&apos;s deployed.</p><p>opcode:</p><pre data-type="codeBlock" text="create2(vaule,offset,size,salt) =&gt; address //return address 0 if failed 
"><code>create2(vaule,offset,size,salt) <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">address</span> <span class="hljs-comment">//return address 0 if failed </span>
</code></pre><p><strong>In order to keep the addresses consistent, the fewer influencing factors, the better. So we want to get rid of the influence of bytecode.</strong></p><h2 id="h-create3" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Create3</h2><p>CREATE3 is a way to use CREATE and CREATE2 in combination such that bytecode no longer affects the deployment address.  Is not an EVM opcode.</p><p>Contract calculation depends on <strong>address of factory</strong> and <strong>salt.</strong></p><p>How to achieve it?</p><pre data-type="codeBlock" text="address proxy;
/// @solidity memory-safe-assembly
assembly {
    // Deploy a new contract with our pre-made bytecode via CREATE2.
    // We start 32 bytes into the code to avoid copying the byte length.
    proxy := create2(0, add(proxyChildBytecode, 32), mload(proxyChildBytecode), salt)
}
require(proxy != address(0), &quot;DEPLOYMENT_FAILED&quot;);

deployed = getDeployed(salt);
(bool success, ) = proxy.call{value: value}(creationCode);
"><code><span class="hljs-keyword">address</span> proxy;
<span class="hljs-comment">/// @solidity memory-safe-assembly</span>
<span class="hljs-keyword">assembly</span> {
    <span class="hljs-comment">// Deploy a new contract with our pre-made bytecode via CREATE2.</span>
    <span class="hljs-comment">// We start 32 bytes into the code to avoid copying the byte length.</span>
    proxy <span class="hljs-operator">:=</span> <span class="hljs-built_in">create2</span>(<span class="hljs-number">0</span>, <span class="hljs-built_in">add</span>(proxyChildBytecode, <span class="hljs-number">32</span>), <span class="hljs-built_in">mload</span>(proxyChildBytecode), salt)
}
<span class="hljs-built_in">require</span>(proxy <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), <span class="hljs-string">"DEPLOYMENT_FAILED"</span>);

deployed <span class="hljs-operator">=</span> getDeployed(salt);
(<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> proxy.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: value}(creationCode);
</code></pre><ol><li><p>Deploy a new contract with our pre-made bytecode via CREATE2, so we can ensure the factory contract</p></li><li><p>Deploy actually contract by the factory contract deployed via CREATE2, and the nonce is always 1.</p><p>(Notice: Factory nonce is 1 rather than 0 of EOA)</p></li></ol><p>At this point, we can deploy the same contract address on different EVM chains, and the address is only affected by salt</p><blockquote><p><strong>Notice</strong>: The creation code is contract bytecode that you want to deploy. If you want to deploy an upgradable contract, the bytecode is ERC1967 Contract bytecode with its constructor:</p><p><code>abi.encodePacked(ERC1967bytecode + abi.encode(&lt;impl address, initData&gt;))</code></p><p>Here initData is ERC1967 data. And if the contract is UUPS type, you have to call <code>initialize()</code> when deploying the contract. So the <code>initData</code> will be encoded by <code>initialize()</code></p></blockquote><p>Now here is another question: we still have to preserve the private key that controls the address safely. the EOA that deploys the factory. Is there a way that don&apos;t need to regardless of this?</p><h1 id="h-keyless" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Keyless</h1><p>What is keyless address?</p><p>Keyless means no one owns the private key of the address.</p><h2 id="h-understanding-transaction-in-ethereum" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Understanding transaction in Ethereum</h2><p>We need to understand ethereum tx again. A simple ethereum tx format:</p><pre data-type="codeBlock" text="{
  nonce: &quot;0x00&quot;,
  chainID:&quot;1&quot;,
  gasPrice: &quot;0x09184e72a000&quot;,
  gasLimit: &quot;0x27100&quot;,
  to: &quot;0x0000000000000000000000000000000000000000&quot;,
  value: &quot;0x01&quot;,
  data: &quot;0x7f7465737432000000000000000000000000000000000000000000000000000000600057&quot;,
  sig:{r,s,v}
}
"><code>{
  nonce: <span class="hljs-string">"0x00"</span>,
  chainID:<span class="hljs-string">"1"</span>,
  gasPrice: <span class="hljs-string">"0x09184e72a000"</span>,
  gasLimit: <span class="hljs-string">"0x27100"</span>,
  to: <span class="hljs-string">"0x0000000000000000000000000000000000000000"</span>,
  value: <span class="hljs-string">"0x01"</span>,
  data: <span class="hljs-string">"0x7f7465737432000000000000000000000000000000000000000000000000000000600057"</span>,
  sig:{r,s,v}
}
</code></pre><p>Network using <code>ecrecover</code> function to get signer address and get gasFee</p><pre data-type="codeBlock" text="addressRecovered = ecrecover(Transaction, v, r, s);
"><code><span class="hljs-attr">addressRecovered</span> = ecrecover(Transaction, v, r, s)<span class="hljs-comment">;</span>
</code></pre><p>Here is the point that it doesn&apos;t matter who forwards the transaction to network because the address executing the transaction is the one recovered from the transaction</p><h2 id="h-usage-of-keyless" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Usage of Keyless</h2><p>Even with the alteration of v, r, and s values to randomly generated values, the transaction will not be considered as “invalid”. It will still be executed successfully from the recovered address. The entire process of deploying a contract is:</p><ol><li><p>Generate the tx by field with random value for r,s and data (bytecode of the factory cotract)</p></li><li><p>Recover the address by &quot;ecrecover&quot; and fund that address</p></li><li><p>Serialize and broadcast the transaction to the network. And can also get the address of contract that will be created</p></li><li><p>Deploy business contract by factory that deployed by keyless</p></li></ol><p>By using this method, there is no need to safeguard a private key or need to be concerned about nonce. The nonce of keyless is always zero</p><p>Seaport contract (opensea contract) is deployed in this way.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md">https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md</a></p><p><strong>End.</strong> we can deploy the same contract address on different EVM chains, and the address is only affected by salt, and we don’t need to manage the private key of EOA that deploy the factory contract.</p><p>Just need to keep factory bytecode and salt is enough.</p><p>And here is the code example of factory deployment:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://x.com/bloom_cry/status/1861602210964218131">https://x.com/bloom_cry/status/1861602210964218131</a></p><p>Send me message to get the full code example of factory + keyless deployment!</p>]]></content:encoded>
            <author>bin-6@newsletter.paragraph.com (Bin)</author>
        </item>
        <item>
            <title><![CDATA[Inflation Attack and Defense in ERC4626]]></title>
            <link>https://paragraph.com/@bin-6/inflation-attack-and-defense-in-erc4626</link>
            <guid>cmJKssQimMgoeQz7BzsH</guid>
            <pubDate>Sun, 03 Nov 2024 06:48:54 GMT</pubDate>
            <description><![CDATA[BackgroundWhat is ERC4626? ERC4626 is an extension of ERC20 that proposes a standard interface for token vaults, offering functionality for depositing, withdrawing tokens and reading balance.contract ERC4626 is ERC20, IERC4626 {} The main functions implemented areDeposit assets(e.g. USDC) get shares tokenfunction deposit(uint256 assets, address receiver) external returns (uint256 shares); function mint(uint256 shares, address receiver) external returns (uint256 assets); Redeem share token, ge...]]></description>
            <content:encoded><![CDATA[<h1 id="h-background" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Background</h1><p><strong>What is ERC4626?</strong></p><p>ERC4626 is an extension of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/5.x/erc20">ERC20</a> that proposes a standard interface for token vaults, offering functionality for depositing, withdrawing tokens and reading balance.</p><pre data-type="codeBlock" text="contract ERC4626 is ERC20, IERC4626 {}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ERC4626</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span>, <span class="hljs-title">IERC4626</span> </span>{}
</code></pre><p>The main functions implemented are</p><ul><li><p>Deposit assets(e.g. USDC) get shares token</p><pre data-type="codeBlock" text="function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function mint(uint256 shares, address receiver) external returns (uint256 assets);
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets, <span class="hljs-keyword">address</span> receiver</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> shares</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> shares, <span class="hljs-keyword">address</span> receiver</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets</span>)</span>;
</code></pre></li><li><p>Redeem share token, get assets</p><pre data-type="codeBlock" text="function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets, <span class="hljs-keyword">address</span> receiver, <span class="hljs-keyword">address</span> owner</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> shares</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">redeem</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> shares, <span class="hljs-keyword">address</span> receiver, <span class="hljs-keyword">address</span> owner</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets</span>)</span>;
</code></pre></li><li><p>Share and amount conversion ratio</p><pre data-type="codeBlock" text="function convertToShares(uint256 assets) external view returns (uint256 shares);
function convertToAssets(uint256 shares) external view returns (uint256 assets);
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">convertToShares</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> shares</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">convertToAssets</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> shares</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets</span>)</span>;
</code></pre></li></ul><p>There is a formula between share and amount:</p><p>$$\frac{share}{totalShare} = \frac{asset}{totalAsset}$$</p><p>Here share is user should get share amount, asset is the asset amount that user deposit or withdraw to the vault. <strong>Determine the ratio between asset and share</strong>.</p><h1 id="h-inflation-attack" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Inflation Attack</h1><p>Let&apos;s consider a scenario</p><ol><li><p>Initially, totalAssets and totalShares are 0</p></li><li><p>The attacker deposits 1 token, gets the shareReceived = 1 (totalShares = 1 )</p></li><li><p>User plan to deposit 1000 tokens</p></li><li><p>The Attacker transfer 1000 tokens before user, changes the totalAssets to 1001</p></li><li><p>User deposit 1000 tokens, get the shareReceived = 1 * 1000 / 1001 = 0.999001 = 0 , vault state: totalAssets = 1001 + 1000 = 2001, totalShares = 1</p></li><li><p>The attack redeem 1 share to get 2001 tokens</p></li></ol><p>How does this happen? Attacker can manipulate the denominator by increasing it, causing users to receive less share than expected since rounding down.</p><p>Let&apos;s analyze it according <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/5.x/erc4626">Inflation attack</a> , Assuming</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/388c26ad6342dc98e298351cdc7bab6636c4e1ef86fdb3ed6710f7f901dc73c6.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b492355558734bde50961a5e3b4d48b9c1c74a02020ea5174b6640f1c5dd0d0a.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>After donation of attack, that rate of this vault is</p><p>$$\frac{a_0}{a_0+a_1}$$</p><p>to dilute that deposit to 0 share, just need to ensure that</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ed0c0302c659256f01508d418c2379e9f6abb014180b3cdaf90fa81d9b05feee.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Using $$a_0$$is 1 and $$a_1$$is u is enough. So attacker only needs u+1 to perform attack</p><h1 id="h-defense-method" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Defense Method</h1><h2 id="h-ensure-that-the-initial-state-is-by-owner" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Ensure that the initial state is by owner</h2><p>If the initial assets in the vault are not zero, the cost of attacker is expensive. Even without other defense methods, assume the owner deposits 1000 assets into the vault.</p><p>userShare = totalyShare(1000) * assetAmount(1000) / totalAsset(1000 + x)</p><p>attacker needs to make (x + 1000) greater than 10^6, so x = 10^-1000</p><h2 id="h-control-totalasset-internal-instead-of-balanceof" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Control totalAsset internal instead of balanceof()</h2><p>Another reason for the success of the attack is that the attacker can transfer assets（donation） into the contract, thus diluting the share.</p><p>Keep track of assets held by the vault internally, rather than rely on the balanceOf function. This way, the donated assets cannot influence the vault&apos;s internal accounting.</p><h2 id="h-decimals-offset-approach-used-in-yieldbox" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Decimals offset approach used in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/boringcrypto/YieldBox/blob/master/contracts/YieldBoxRebase.sol#L32">YieldBox</a></h2><p>YieldBox add a decimal offset in totalShare, means that 1 asset is not according to 1 share.</p><pre data-type="codeBlock" text="function _toShares(
    uint256 amount,
    uint256 totalShares_,
    uint256 totalAmount,
    bool roundUp
) internal pure returns (uint256 share) {
    // To prevent reseting the ratio due to withdrawal of all shares, we start with
    // 1 amount/1e8 shares already burned. This also starts with a 1 : 1e8 ratio which
    // functions like 8 decimal fixed point math. This prevents ratio attacks or inaccuracy
    // due to &apos;gifting&apos; or rebasing tokens. (Up to a certain degree)
    totalAmount++;
    totalShares_ += 1e8;

    // Calculte the shares using te current amount to share ratio
    share = (amount * totalShares_) / totalAmount;

    // Default is to round down (Solidity), round up if required
    if (roundUp &amp;&amp; (share * totalAmount) / totalShares_ &lt; amount) {
        share++;
    }
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_toShares</span>(<span class="hljs-params">
    <span class="hljs-keyword">uint256</span> amount,
    <span class="hljs-keyword">uint256</span> totalShares_,
    <span class="hljs-keyword">uint256</span> totalAmount,
    <span class="hljs-keyword">bool</span> roundUp
</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> share</span>) </span>{
    <span class="hljs-comment">// To prevent reseting the ratio due to withdrawal of all shares, we start with</span>
    <span class="hljs-comment">// 1 amount/1e8 shares already burned. This also starts with a 1 : 1e8 ratio which</span>
    <span class="hljs-comment">// functions like 8 decimal fixed point math. This prevents ratio attacks or inaccuracy</span>
    <span class="hljs-comment">// due to 'gifting' or rebasing tokens. (Up to a certain degree)</span>
    totalAmount<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
    totalShares_ <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1e8</span>;

    <span class="hljs-comment">// Calculte the shares using te current amount to share ratio</span>
    share <span class="hljs-operator">=</span> (amount <span class="hljs-operator">*</span> totalShares_) <span class="hljs-operator">/</span> totalAmount;

    <span class="hljs-comment">// Default is to round down (Solidity), round up if required</span>
    <span class="hljs-keyword">if</span> (roundUp <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> (share <span class="hljs-operator">*</span> totalAmount) <span class="hljs-operator">/</span> totalShares_ <span class="hljs-operator">&#x3C;</span> amount) {
        share<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
    }
}
</code></pre><h2 id="h-openzeppelin" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Openzeppelin</h2><p>Oz proposes defense based on YieldBox, It consists of two parts: virtual shares and decimals offset</p><p>The formula above becomes:</p><p>$$\frac{share}{totalShare + 10^{decimal}} = \frac{assetAmount}{totalAsset + 1}$$</p><ul><li><p>Decimal means we can use more decimal places to represent the shares. e.g. Decimal is 3, 1 assets 对应1000 share</p></li><li><p>totalAsset + 1 instead of totalAsset means we give a virtual asset to the vault</p></li></ul><p>And here is the implementation of openzeppelin after v4.9 according to the formula above</p><pre data-type="codeBlock" text="function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) {
    return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_convertToShares</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> assets, Math.Rounding rounding</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">virtual</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
    <span class="hljs-keyword">return</span> assets.mulDiv(totalSupply() <span class="hljs-operator">+</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> _decimalsOffset(), totalAssets() <span class="hljs-operator">+</span> <span class="hljs-number">1</span>, rounding);
}
</code></pre><p>Let&apos;s see if we don&apos;t have decimal, if the above attack can succeed. Now we have：</p><p>$$\frac{share}{totalShare + 1} = \frac{assetAmount}{totalAsset + 1}$$</p><ol><li><p>Initially, totalAssets and totalShares are 0</p></li><li><p>The attacker deposits 1 token, gets the shareReceived = 1 * 1 / 1 = 1 (totalShares = 1 )</p></li><li><p>User plan to deposit 1000 assets</p></li><li><p>For making user receive 0 share, attacker need to transfer x assets before user $$share &lt; 1$$ =&gt; $$\frac{2000}{1 + totalAssets} &lt; 1$$ =&gt; $$totalAssets &gt;1999$$ Thus, the minimum x should be 1999. The total assets of the vault is 2000</p></li><li><p>User deposit 1000 assets, get the shareReceived = 1000 * (1 + 1) / 2001 = 0， vault state: totalAssets = 3000, totalShares = 1</p></li><li><p>Attack redeem 1 share, receive token amount = 1 * (3001) / (1 + 1 ) = 1500</p></li></ol><p>We can see that even though without decimal, attacker still loses 500 assets. If user doesn&apos;t deposit, the loss is at least equal to the user’s deposit（1000）. So the virtual shares and assets make this attack non-profitable for the attacker.</p><p>Actually, the donation of attack has to suffer more loss , to ensure that user can not get share if decimal is not zero.</p><p>Here is a program that I wrote to test:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0ef07d05956706848c8e9027e64026044f46104c763c8a74598fcbc4dd18b3c8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/397078ad7ea4182bcd2146a1e00a259614735d6b1eb0b02d4b32729e179958c0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/397078ad7ea4182bcd2146a1e00a259614735d6b1eb0b02d4b32729e179958c0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h1 id="h-reference" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Reference</h1><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/5.x/erc4626">https://docs.openzeppelin.com/contracts/5.x/erc4626</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks">https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://x.com/bloom_cry/status/1852965843988365736">https://x.com/bloom_cry/status/1852965843988365736</a></p>]]></content:encoded>
            <author>bin-6@newsletter.paragraph.com (Bin)</author>
        </item>
        <item>
            <title><![CDATA[OPYN]]></title>
            <link>https://paragraph.com/@bin-6/opyn</link>
            <guid>oVip8bMswWtX4xtDYzYF</guid>
            <pubDate>Sat, 28 May 2022 09:51:14 GMT</pubDate>
            <description><![CDATA[都在说OPYN可能会有空投，但基本是一脸蒙进去，一脸蒙出来，真是想花钱都不知道怎么花。今天简单讲解一下OPYN期权交易的操作。 不同于期货，OPYN是一个期权交易，期货买卖的是货，期权买卖的是一个权利，而这个权利可以选择执行也可以选择不执行。 首先进去OPYN官网： Trade Options on Ethereum 界面基本如下所示： 先名词解释： call：看涨 put:看跌 bid：买单，是有人要买这个权利 ask：卖单 strike：到期行权价 不明白没关系，我来举个栗子： 假设现价eth是5000u，买方花了500u买了一个权利，该权利内容是：十天以后以5000u买入eth。 此时有两种情况：eth涨到6000u， 买方行使权力，花5000+500u购买了以太坊，盈利500u；eth跌到4500u，买方放弃行使权力，因为可以在市场上用更低价买入。卖方赚500u。该例子中，行权价就是5500u，只要十天以后ETH的价格高于5500，买方就盈利，反之卖方盈利。买方和卖方一定是相反的，买方看涨必定是卖方看跌。 此时我单机CALLS（看涨）下的Bid，右侧红色高亮，代表我要以8...]]></description>
            <content:encoded><![CDATA[<p>都在说OPYN可能会有空投，但基本是一脸蒙进去，一脸蒙出来，真是想花钱都不知道怎么花。今天简单讲解一下OPYN期权交易的操作。</p><p>不同于期货，OPYN是一个期权交易，期货买卖的是货，期权买卖的是一个权利，而这个权利可以选择执行也可以选择不执行。</p><p>首先进去OPYN官网： <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://link.zhihu.com/?target=https%3A//v2.opyn.co/%23/">Trade Options on Ethereum</a></p><p>界面基本如下所示：</p><p><strong>先名词解释：</strong> call：看涨 put:看跌 bid：买单，是有人要买这个权利 ask：卖单 strike：到期行权价</p><p>不明白没关系，我来举个栗子：</p><p>假设现价eth是5000u，买方花了500u买了一个权利，该权利内容是：十天以后以5000u买入eth。 此时有两种情况：</p><ol><li><p>eth涨到6000u， 买方行使权力，花5000+500u购买了以太坊，盈利500u；</p></li><li><p>eth跌到4500u，买方放弃行使权力，因为可以在市场上用更低价买入。卖方赚500u。</p></li></ol><p>该例子中，行权价就是5500u，只要十天以后ETH的价格高于5500，买方就盈利，反之卖方盈利。买方和卖方一定是相反的，买方看涨必定是卖方看跌。</p><p>此时我单机CALLS（看涨）下的Bid，右侧红色高亮，代表我要以8.94刀的价格卖一个权利，买方到期后可以以3700+8.94 刀的价格购买以太坊。 到期后如果ETH价格高于3708.94，买方赚，反之卖方赚。</p><p>当然如果你要卖的话，可以选择抵押一定资产，因为买方如果赚的话，卖方需要承担差额。</p><p>这就是OPYN期权的基本原理，如果只是简单操作而不是专业玩期权，按照这个可以简单交互一下。</p>]]></content:encoded>
            <author>bin-6@newsletter.paragraph.com (Bin)</author>
        </item>
    </channel>
</rss>