<?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>0x77</title>
        <link>https://paragraph.com/@0x77-2</link>
        <description>Do more</description>
        <lastBuildDate>Sat, 01 Aug 2026 12:13:44 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>0x77</title>
            <url>https://storage.googleapis.com/papyrus_images/51f528e3641eaad022f0a083779c28e62f183030632cf5ee030851b61bb96752.jpg</url>
            <link>https://paragraph.com/@0x77-2</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[WTF Vyper教程: 3. Function]]></title>
            <link>https://paragraph.com/@0x77-2/wtf-vyper-3-function</link>
            <guid>lzPtZWyJZbI6HkYrQ2aj</guid>
            <pubDate>Mon, 19 Feb 2024 15:14:04 GMT</pubDate>
            <description><![CDATA[Vyper 中的函数是合约内可执行的代码单元，只能在合约的模块范围内声明。所有的合约方法必须要声明函数是外部函数(external)还是内部函数(internal)，如果不声明编译会失败.函数类型参考函数的类型是通过添加装饰器的方式来完成，Vyper 中总共有 6 种装饰器，我们将它分为 3 类：可见性、可变性和重入锁。可见性external: 用于标识外部函数，这类函数是合约接口的一部分，只能通过交易或从其他合约调用 ​internal: 用于标识内部函数，内部函数只由同一合约内的其他函数中可访问，通常通过 self.f() 对象调用, f()为方法名 ​可变性view: 表示函数是一个只读函数，可以读取但不修改合约状态pure: 表示函数是一个pure函数，既不会读取也不修改合约状态payable: 表示函数可以接收 ETH，可以读写合约状态. 只有标记为 @payable 的函数才能接收 ETH 转账重入锁nonreentrant("key"): 用于防止函数的重入，当尝试从外部合约再次调用加锁的函数时，交易会回滚函数基本结构一个基本的函数定义包括函数名、参数列表（可选）和...]]></description>
            <content:encoded><![CDATA[<p>Vyper 中的函数是合约内可执行的代码单元，只能在合约的模块范围内声明。所有的合约方法必须要声明函数是外部函数(external)还是内部函数(internal)，如果不声明编译会失败.</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">函数类型参考</h2><p>函数的类型是通过添加装饰器的方式来完成，Vyper 中总共有 6 种装饰器，我们将它分为 3 类：可见性、可变性和重入锁。</p><ol><li><p>可见性</p><ul><li><p><code>external</code>: 用于标识外部函数，这类函数是合约接口的一部分，只能通过交易或从其他合约调用 ​</p></li><li><p><code>internal</code>: 用于标识内部函数，内部函数只由同一合约内的其他函数中可访问，通常通过 <code>self.f()</code> 对象调用, <code>f()</code>为方法名 ​</p></li></ul></li><li><p>可变性</p><ul><li><p><code>view</code>: 表示函数是一个只读函数，可以读取但不修改合约状态</p></li><li><p><code>pure</code>: 表示函数是一个<code>pure</code>函数，既不会读取也不修改合约状态</p></li><li><p><code>payable</code>: 表示函数可以接收 ETH，可以读写合约状态. 只有标记为 <code>@payable</code> 的函数才能接收 ETH 转账</p></li></ul></li><li><p>重入锁</p><ul><li><p>nonreentrant(&quot;key&quot;): 用于防止函数的重入，当尝试从外部合约再次调用加锁的函数时，交易会回滚</p></li></ul></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">函数基本结构</h2><p>一个基本的函数定义包括函数名、参数列表（可选）和返回值（可选）</p><p>代码示例：</p><pre data-type="codeBlock" text="@external
def my_function(param: uint256) -&gt; bool:
    ...
"><code>@<span class="hljs-keyword">external</span>
def my_function(param: <span class="hljs-keyword">uint256</span>) <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">bool</span>:
    ...
</code></pre><ul><li><p><code>@external</code>: 外部函数修饰符</p></li><li><p><code>def</code>: 声明函数时的固定用法，与 Python 类似</p></li><li><p><code>my_function</code>: 函数名，代码风格遵循 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://curve.readthedocs.io/guide-code-style.html">Curve.fi</a> 标准</p></li><li><p><code>param</code>: 函数的参数，可选的</p></li><li><p><code>bool</code>: 函数返回值，可选的</p></li></ul><h3 id="h-1-external-and-internal" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. external &amp; internal</h3><p>代码示例：</p><pre data-type="codeBlock" text="num2: public(uint256)

@internal
def _internal_function(_new_num: uint256):
    self.num2 = _new_num

@external
def call_internal_function(_new_num: uint256):
    self._internal_function(_new_num)
"><code>num2: <span class="hljs-keyword">public</span>(<span class="hljs-keyword">uint256</span>)

@<span class="hljs-keyword">internal</span>
def _internal_function(_new_num: <span class="hljs-keyword">uint256</span>):
    <span class="hljs-built_in">self</span>.num2 <span class="hljs-operator">=</span> _new_num

@<span class="hljs-keyword">external</span>
def call_internal_function(_new_num: <span class="hljs-keyword">uint256</span>):
    <span class="hljs-built_in">self</span>._internal_function(_new_num)
</code></pre><p>示例中，我们定义了一个内部函数 <code>_internal_function</code>, 每次调用都更新 <code>num2</code> 的值，它只能由合约内部调用。然后我们再定义了一个外部函数 <code>call_internal_function</code>，用来调用内部函数 <code>_internal_function</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fa6c8ae6e3000ca20359dea4557dc224d8a352820d638a61f800417619ca04ad.png" alt="call_function" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">call_function</figcaption></figure><h3 id="h-2-view-and-pure" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. view &amp; pure</h3><ul><li><p><code>view</code> 表示函数是一个视图函数，可以读取但不修改合约的状态。常用于获取合约的当前状态或计算结果，而不产生任何区块链上的状态变化</p></li><li><p><code>pure</code> 表示函数既不会读取也不会修改合约的状态。通常用于执行纯粹的计算或返回常量值 ​</p></li><li><p><code>view</code> 和 <code>pure</code> 都可以成为为内部函数和外部函数</p></li></ul><p>代码示例：</p><pre data-type="codeBlock" text="num1: public(uint256)
num2: public(uint256)

@view
@external
def external_view_function() -&gt; uint256:
    return self.num1

@view
@internal
def _internal_view_function() -&gt; uint256:
    return 99

@view
@external
def view_internal_function() -&gt; uint256:
    return self._internal_view_function()

@external
def call_internal_view_function():
    self.num2 = self._internal_view_function()

@pure
@external
def external_pure_function() -&gt; uint256:
    return 100
"><code>num1: <span class="hljs-keyword">public</span>(<span class="hljs-keyword">uint256</span>)
num2: <span class="hljs-keyword">public</span>(<span class="hljs-keyword">uint256</span>)

@<span class="hljs-keyword">view</span>
@<span class="hljs-keyword">external</span>
def external_view_function() <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>:
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>.num1

@<span class="hljs-keyword">view</span>
@<span class="hljs-keyword">internal</span>
def _internal_view_function() <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>:
    <span class="hljs-keyword">return</span> <span class="hljs-number">99</span>

@<span class="hljs-keyword">view</span>
@<span class="hljs-keyword">external</span>
def view_internal_function() <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>:
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span>._internal_view_function()

@<span class="hljs-keyword">external</span>
def call_internal_view_function():
    <span class="hljs-built_in">self</span>.num2 <span class="hljs-operator">=</span> <span class="hljs-built_in">self</span>._internal_view_function()

@<span class="hljs-keyword">pure</span>
@<span class="hljs-keyword">external</span>
def external_pure_function() <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>:
    <span class="hljs-keyword">return</span> <span class="hljs-number">100</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b945223809d70430b33dc4b52f690ce29fbf506c8fe72a80937a90ceb96286c0.png" alt="view" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">view</figcaption></figure><h3 id="h-3-payable" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. payable</h3><p>只有标记为 <code>@payable</code> 的构造函数或者功能函数才能接收 ETH 转账。特殊情况下不想要指定函数接收 ETH，那么可以使用 Vyper 的内置函数 <code>__default__</code>，使用 default 函数表示允许合约接收 ETH，用户可以直接往合约地址里转入 ETH</p><p>代码示例：</p><pre data-type="codeBlock" text="@payable
@external
def __init__():
    pass

@payable
@external
def receipt_eth():
    pass

@payable
@external
def __default__():
    pass
"><code><span class="hljs-variable">@payable</span>
<span class="hljs-variable">@external</span>
def <span class="hljs-built_in">__init__</span>():
    pass

<span class="hljs-variable">@payable</span>
<span class="hljs-variable">@external</span>
def <span class="hljs-built_in">receipt_eth</span>():
    pass

<span class="hljs-variable">@payable</span>
<span class="hljs-variable">@external</span>
def <span class="hljs-built_in">__default__</span>():
    pass
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1ca020d4592694cf062d461a8d7a2df5db83fdbed8f6c7ba98869ed3c04b3b21.png" alt="构造函数" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">构造函数</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ba56bcbe9f179614d984dd30a9d5a36a1112cde4e95563bc29ac3f52865ab3a8.png" alt="调用函数" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">调用函数</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0652c59b25a4bba68571c51a41ff93913fefeb70adad6475d719d8aa3a0c6cac.png" alt="直接转ETH" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">直接转ETH</figcaption></figure><h1 id="h-4-nonreentrant" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4. nonreentrant</h1><p><code>nonreentrant</code> 修饰符用于防止函数的重入，确保函数在同一交易中不会被重复调用, 非常重要的安全特性，尤其在处理资金交易时。</p><p>可重入锁可以分为两种状态: 激活和非激活。当调用标记 <code>nonreentrant</code> 的函数时，状态为：</p><ul><li><p>确保不处于活动状态</p></li><li><p>函数设置为激活状态</p></li></ul><p>一旦函数调用结束，状态为：</p><ul><li><p>函数设置为非激活状态</p></li></ul><p>通过这种机制，用户可以确保该函数只能在调用结束后才能重新调用，这意味着无论执行什么外部调用都不会发生重入。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">代码示例</h4><pre data-type="codeBlock" text="@nonreentrant(&quot;lock&quot;)
@external
def sensitive_function():
    pass
"><code><span class="hljs-variable">@nonreentrant</span>(<span class="hljs-string">"lock"</span>)
<span class="hljs-variable">@external</span>
def <span class="hljs-built_in">sensitive_function</span>():
    pass
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">总结</h2><p>在本节中，我们介绍了 Vyper 的函数类型。在开发合约过程中需要根据函数的用途和需要的安全级别来选择合适的类型。</p>]]></content:encoded>
            <author>0x77-2@newsletter.paragraph.com (0x77)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/244da3375e46563581c711e7d4cc1f7d9d56d24e8103ae3fe7d585785ec5acba.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[WTF Vyper教程: 2. ValueTypes]]></title>
            <link>https://paragraph.com/@0x77-2/wtf-vyper-2-valuetypes</link>
            <guid>rW4BoEvT0JzRRg9kS9iV</guid>
            <pubDate>Mon, 19 Feb 2024 15:06:52 GMT</pubDate>
            <description><![CDATA[WTF Vyper 教程: 2. 值类型我最近在重新学Vyper，巩固一下细节，也写一个“Vyper极简入门”，供小白们使用（编程大佬可以另找教程），每周更新1-3讲。 推特: @0x77 所有代码和教程开源在github: github.com/WTFAcademy/WTF-VyperVyper 提供对两类变量类型的访问：值（Value）: 合约中变量的任何使用都将直接传递其值。引用（Reference）: 合约中变量的任何使用都将传递对内存中地址的引用，而不是值存储在那里。本节中我们只介绍值类型，引用类型将在第 4 节中详细介绍。值类型布尔型bool: true 或 false数字 - 整型int128: 有符号 128 位整数int256: 有符号 256 位整数uint8: 无符号 8 位整数uint256: 无符号 256 位整数数字 - 浮点数decimal: 带符号的浮点数，精度为 10 位小数地址address: 20 字节的十六进制数，带有 0x 前缀。字节数组bytes32: 32 字节数组，通常用于储存 256 位 keccak 哈希值Bytes[N]: 可...]]></description>
            <content:encoded><![CDATA[<h1 id="h-wtf-vyper-2" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">WTF Vyper 教程: 2. 值类型</h1><p>我最近在重新学Vyper，巩固一下细节，也写一个“Vyper极简入门”，供小白们使用（编程大佬可以另找教程），每周更新1-3讲。</p><p>推特: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/0x00077">@0x77</a></p><p>所有代码和教程开源在github: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WTFAcademy/WTF-Vyper">github.com/WTFAcademy/WTF-Vyper</a></p><h2 id="h-vyper" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Vyper 提供对两类变量类型的访问：</h2><ol><li><p>值（Value）: 合约中变量的任何使用都将直接传递其值。</p></li><li><p>引用（Reference）: 合约中变量的任何使用都将传递对内存中地址的引用，而不是值存储在那里。</p></li></ol><p>本节中我们只介绍值类型，引用类型将在第 4 节中详细介绍。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">值类型</h2><ol><li><p>布尔型</p><ul><li><p>bool: true 或 false</p></li></ul></li><li><p>数字 - 整型</p><ul><li><p>int128: 有符号 128 位整数</p></li><li><p>int256: 有符号 256 位整数</p></li><li><p>uint8: 无符号 8 位整数</p></li><li><p>uint256: 无符号 256 位整数</p></li></ul></li><li><p>数字 - 浮点数</p><ul><li><p>decimal: 带符号的浮点数，精度为 10 位小数</p></li></ul></li><li><p>地址</p><ul><li><p>address: 20 字节的十六进制数，带有 0x 前缀。</p></li></ul></li><li><p>字节数组</p><ul><li><p>bytes32: 32 字节数组，通常用于储存 256 位 keccak 哈希值</p></li><li><p>Bytes[N]: 可变长字节数组，N 是存储的最大字节数组的长度。</p></li></ul></li><li><p>字符串</p><ul><li><p>String[N]: 保存字母数字字符串的可变长度字符串字节数组，其中 N 是存储的最大字符串的长度</p></li></ul></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">常用的值类型</h2><h3 id="h-1" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. 布尔型</h3><p>布尔值分为 <code>True</code> 和 <code>False</code>, 布尔值的运算和 Python 一致。在 Vyper 中使用 <code>bool</code> 对变量进行声明时值默认为 <code>False</code>。</p><pre data-type="codeBlock" text="is_bool: public(bool)

@payable
@external
def __init__():
    self.is_bool = True
"><code>is_bool: <span class="hljs-keyword">public</span>(<span class="hljs-keyword">bool</span>)

@<span class="hljs-keyword">payable</span>
@<span class="hljs-keyword">external</span>
def __init__():
    <span class="hljs-built_in">self</span>.is_bool <span class="hljs-operator">=</span> True
</code></pre><p>布尔值的运算包括</p><ul><li><p>not x: 逻辑非</p></li><li><p>x and y: 逻辑与</p></li><li><p>x or y: 逻辑或</p></li><li><p>x == y: 等于</p></li><li><p>x != y: 不等于</p></li></ul><p>代码示例：</p><pre data-type="codeBlock" text="bool1: bool = True
bool2: bool = not bool1

bool1 and bool2 -&gt; False
bool1 or bool2 -&gt; True
bool1 == bool2 -&gt; False
bool1 != bool2 -&gt; True
"><code>bool1: <span class="hljs-keyword">bool</span> <span class="hljs-operator">=</span> True
bool2: <span class="hljs-keyword">bool</span> <span class="hljs-operator">=</span> not bool1

bool1 and bool2 <span class="hljs-operator">-</span><span class="hljs-operator">></span> False
bool1 or bool2 <span class="hljs-operator">-</span><span class="hljs-operator">></span> True
bool1 <span class="hljs-operator">=</span><span class="hljs-operator">=</span> bool2 <span class="hljs-operator">-</span><span class="hljs-operator">></span> False
bool1 <span class="hljs-operator">!</span><span class="hljs-operator">=</span> bool2 <span class="hljs-operator">-</span><span class="hljs-operator">></span> True
</code></pre><h3 id="h-2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 整型</h3><p>常用的整型包括</p><pre data-type="codeBlock" text="# 有符号的256位整数，包括负数
number: int256 = -1

# 无符号的256位正整数
number: uint256 = 123456
"><code><span class="hljs-comment"># 有符号的256位整数，包括负数</span>
number: <span class="hljs-attr">int256</span> = -<span class="hljs-number">1</span>

<span class="hljs-comment"># 无符号的256位正整数</span>
number: <span class="hljs-attr">uint256</span> = <span class="hljs-number">123456</span>
</code></pre><p>整型运算包括</p><ul><li><p>比较运算符（返回布尔值）： <code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></p></li><li><p>算术运算符: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>**</code>, <code>%</code></p></li><li><p>按位运算符：<code>&amp;</code>, <code>|</code>, <code>^</code>, <code>~</code></p></li><li><p>移位运算符: <code>&lt;&lt;</code>, <code>&gt;&gt;</code></p></li></ul><p>Vyper 中，只有相同类型的变量才能进行运算，代码示例：</p><pre data-type="codeBlock" text="x: uint256 = 100
y: uint256 = 200

is_bool: bool = x &lt; y
number: uint256 = x + y
number2: uint256 = x &amp; y
"><code>x: <span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span> <span class="hljs-number">100</span>
y: <span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span> <span class="hljs-number">200</span>

is_bool: <span class="hljs-keyword">bool</span> <span class="hljs-operator">=</span> x <span class="hljs-operator">&#x3C;</span> y
number: <span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span> x <span class="hljs-operator">+</span> y
number2: <span class="hljs-keyword">uint256</span> <span class="hljs-operator">=</span> x <span class="hljs-operator">&#x26;</span> y
</code></pre><h3 id="h-3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. 地址</h3><p>Vyper 中的地址类型是一种基本的数据类型，用于存储一个 20 字节的以太坊地址，这些地址通常包括外部账户和合约账户。在 Vyper 中直接使用 <code>address</code> 关键字声明地址变量。</p><pre data-type="codeBlock" text="owner: public(address)

self.owner = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
"><code>owner: <span class="hljs-keyword">public</span>(<span class="hljs-keyword">address</span>)

<span class="hljs-built_in">self</span>.owner <span class="hljs-operator">=</span> <span class="hljs-number">0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE</span>
</code></pre><h3 id="h-4" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4. 字节数组</h3><p>在 Vyper 中，字节数组是用于存储和处理字节序列的数据类型，具体分为定长字节数组(bytesN)和可变字节数组(Bytes[N])。</p><p><code>bytesN</code> 这是一个 <code>N</code> 字节宽的字节数组, 比如 <code>bytes32</code> 是一个固定长度的 32 字节的字节数组。它通常用于存储 256 位的 keccak 哈希值、密钥和其他固定长度的加密数据。<code>bytes4</code>常用于存储函数选择器</p><p>代码示例</p><pre data-type="codeBlock" text="# 0x4f8b61438cf1d5e6f4f684d62bf496fc8975999b940392b49a2b70e209a69c12
bytes_value: bytes32 = keccak256(&quot;Vyper&quot;)

method: bytes4 = 0x01abcdef
"><code><span class="hljs-comment"># 0x4f8b61438cf1d5e6f4f684d62bf496fc8975999b940392b49a2b70e209a69c12</span>
bytes_value: <span class="hljs-attr">bytes32</span> = keccak256(<span class="hljs-string">"Vyper"</span>)

method: <span class="hljs-attr">bytes4</span> = <span class="hljs-number">0</span>x01abcdef
</code></pre><p><code>Bytes[N]</code> 是一个可变长度的字节数组，其中 <code>N</code> 定义了字节数组的最大长度。代码示例:</p><pre data-type="codeBlock" text="bytes_string: Bytes[100] = b&quot;\x01&quot;
"><code><span class="hljs-symbol">bytes_string:</span> Bytes[<span class="hljs-number">100</span>] = b<span class="hljs-string">"\x01"</span>
</code></pre><h3 id="h-5" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5. 字符串</h3><p><code>String[N]</code> 是一个可变长度的字符串字节数组，其中 <code>N</code> 定义了字符串的最大长度。它是专门用于存储文本数据的类型，与 Bytes[N]类似，但更适合处理纯文本。</p><p>代码示例:</p><pre data-type="codeBlock" text="example_str: String[100] = &quot;Hello Vyper!&quot;
"><code><span class="hljs-symbol">example_str:</span> <span class="hljs-type">String</span>[<span class="hljs-number">100</span>] = <span class="hljs-string">"Hello Vyper!"</span>
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">总结</h2><p>在本节中，我们介绍了 <code>Vyper</code> 中的 5 种常用的值变量类型，如果想要了解更加详细的类型内容，可以在<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.vyperlang.org/en/latest/types.html">官方文档</a>中查看。</p>]]></content:encoded>
            <author>0x77-2@newsletter.paragraph.com (0x77)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/244da3375e46563581c711e7d4cc1f7d9d56d24e8103ae3fe7d585785ec5acba.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[WTF Vyper 入门教程: 1. Hello Vyper]]></title>
            <link>https://paragraph.com/@0x77-2/wtf-vyper-1-hello-vyper</link>
            <guid>gJ2nTuq0Kal8nZmZ9d9S</guid>
            <pubDate>Thu, 25 Jan 2024 02:50:09 GMT</pubDate>
            <description><![CDATA[WTF Vyper教程: 1. Hello Vyper 我最近在重新学Vyper，巩固一下细节，也写一个“Vyper极简入门”，供小白们使用（编程大佬可以另找教程），每周更新1-3讲。 推特: @0x77 所有代码和教程开源在github: github.com/WTFAcademy/WTF-VyperVyper简述Vyper 是一种面向合约的类似于 Python 的编程语言，专为EVM设计。与Solidity不同，Vyper强调简单性和安全性，而Solidity则提供更多灵活性和复杂特性。开发环境与Solidity不同，Remix只支持Vyper 0.2.16 以下的版本，而最新版是Vyper 0.3.10，因此我们不得不转向其他开发环境。 这里，我们主要介绍两个开发环境本地开发（推荐），需要在本地安装Vyper和ApeWorx。浏览器IDE：链接本地开发1. 安装Vyper使用 Docker 和 PIP 可安装Vyper。此处使用 PIP，其他安装方法见Vyper官方文档。pip3 install vyper # 或 pip3 install vyper==0.3.9 安装的...]]></description>
            <content:encoded><![CDATA[<p><strong>WTF Vyper教程: 1. Hello Vyper</strong></p><p>我最近在重新学Vyper，巩固一下细节，也写一个“Vyper极简入门”，供小白们使用（编程大佬可以另找教程），每周更新1-3讲。</p><p>推特: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/0x00077">@0x77</a></p><p>所有代码和教程开源在github: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/WTFAcademy/WTF-Vyper">github.com/WTFAcademy/WTF-Vyper</a></p><h2 id="h-vyper" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Vyper简述</h2><p>Vyper 是一种面向合约的类似于 Python 的编程语言，专为<code>EVM</code>设计。与Solidity不同，Vyper强调简单性和安全性，而Solidity则提供更多灵活性和复杂特性。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">开发环境</h2><p>与Solidity不同，<code>Remix</code>只支持Vyper <code>0.2.16</code> 以下的版本，而最新版是Vyper <code>0.3.10</code>，因此我们不得不转向其他开发环境。</p><p>这里，我们主要介绍两个开发环境</p><ol><li><p>本地开发（<strong>推荐</strong>），需要在本地安装<code>Vyper</code>和<code>ApeWorx</code>。</p></li><li><p>浏览器IDE：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://try.vyperlang.org/">链接</a></p></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">本地开发</h2><h3 id="h-1-vyper" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. 安装Vyper</h3><p>使用 <code>Docker</code> 和 <code>PIP</code> 可安装Vyper。此处使用 <code>PIP</code>，其他安装方法见<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.vyperlang.org/en/latest/installing-vyper.html">Vyper官方文档</a>。</p><pre data-type="codeBlock" text="pip3 install vyper
# 或
pip3 install vyper==0.3.9
"><code>pip3 install vyper
<span class="hljs-comment"># 或</span>
pip3 install <span class="hljs-attr">vyper</span>==<span class="hljs-number">0.3</span>.<span class="hljs-number">9</span>
</code></pre><p>安装的Vyper版本取决于当前Python版本。</p><h3 id="h-2-apeworx" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 安装ApeWorX</h3><p>ApeWorX是一个与Vyper完全兼容的智能合约开发框架。另一框架<code>brownie</code>已停止更新。ApeWorX官网: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://apeworx.io">ApeWorX</a>。</p><pre data-type="codeBlock" text="pip3 install eth-ape
"><code>pip3 install eth<span class="hljs-operator">-</span>ape
</code></pre><h3 id="h-3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. 安装插件</h3><p>开发常用插件包括 <code>hardhat</code> 和 <code>alchemy</code>。使用<code>alchemy</code>需要本地设置<code>key</code>，详情见<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://academy.apeworx.io/articles/account-tutorial">这里</a>。</p><pre data-type="codeBlock" text="ape plugins install hardhat, alchemy
"><code></code></pre><h3 id="h-4" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4. 初始化项目</h3><pre data-type="codeBlock" text="ape init
"><code>ape <span class="hljs-keyword">init</span>
</code></pre><p><strong>ape-config.yaml 文件示例配置</strong> 以 <code>ethereum-fork</code> 为例的配置信息：</p><pre data-type="codeBlock" text="name: HelloVyper

plugins:
  - name: alchemy
  - name: etherscan
  - name: hardhat

default_ecosystem: ethereum

ethereum:
  default_network: mainnet-fork
  mainnet_fork:
    default_provider: hardhat
    transaction_acceptance_timeout: 99999999
  mainnet:
    transaction_acceptance_timeout: 99999999

hardhat:
  port: auto
  fork:
    ethereum:
      mainnet:
        upstream_provider: alchemy
        enable_hardhat_deployments: true

test:
  mnemonic: test test test test test test test test test test test junk
  number_of_accounts: 5
"><code><span class="hljs-attr">name:</span> <span class="hljs-string">HelloVyper</span>

<span class="hljs-attr">plugins:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">alchemy</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">etherscan</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">hardhat</span>

<span class="hljs-attr">default_ecosystem:</span> <span class="hljs-string">ethereum</span>

<span class="hljs-attr">ethereum:</span>
  <span class="hljs-attr">default_network:</span> <span class="hljs-string">mainnet-fork</span>
  <span class="hljs-attr">mainnet_fork:</span>
    <span class="hljs-attr">default_provider:</span> <span class="hljs-string">hardhat</span>
    <span class="hljs-attr">transaction_acceptance_timeout:</span> <span class="hljs-number">99999999</span>
  <span class="hljs-attr">mainnet:</span>
    <span class="hljs-attr">transaction_acceptance_timeout:</span> <span class="hljs-number">99999999</span>

<span class="hljs-attr">hardhat:</span>
  <span class="hljs-attr">port:</span> <span class="hljs-string">auto</span>
  <span class="hljs-attr">fork:</span>
    <span class="hljs-attr">ethereum:</span>
      <span class="hljs-attr">mainnet:</span>
        <span class="hljs-attr">upstream_provider:</span> <span class="hljs-string">alchemy</span>
        <span class="hljs-attr">enable_hardhat_deployments:</span> <span class="hljs-literal">true</span>

<span class="hljs-attr">test:</span>
  <span class="hljs-attr">mnemonic:</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">test</span> <span class="hljs-string">junk</span>
  <span class="hljs-attr">number_of_accounts:</span> <span class="hljs-number">5</span>
</code></pre><p>遇 <code>PUSH0</code> 错误时，在 <code>ape-config</code> 文件中添加：</p><pre data-type="codeBlock" text="vyper:
  evm_version: paris
"><code><span class="hljs-attr">vyper:</span>
  <span class="hljs-attr">evm_version:</span> <span class="hljs-string">paris</span>
</code></pre><h2 id="h-vyper" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">编写第一个Vyper合约</h2><p>我们的第一个Vyper合约非常简单，仅包含几行代码：</p><pre data-type="codeBlock" text="# @version 0.3.9

greet: public(String[12])

@payable
@external
def __init__():
    self.greet = &quot;Hello Vyper!&quot;
"><code><span class="hljs-comment"># <span class="hljs-doctag">@version</span> 0.3.9</span>

<span class="hljs-symbol">greet:</span> <span class="hljs-keyword">public</span>(<span class="hljs-title class_">String</span>[<span class="hljs-number">12</span>])

<span class="hljs-variable">@payable</span>
<span class="hljs-variable">@external</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>():
    <span class="hljs-variable language_">self</span>.greet = <span class="hljs-string">"Hello Vyper!"</span>
</code></pre><p>代码逐行分析：</p><ol><li><p>指定Vyper编译器版本 <code>0.3.9</code> 或 <code>&gt;=0.3.9</code>。</p></li><li><p>声明<code>public</code>变量<code>greet</code>：<code>public(String[12])</code>。</p></li><li><p><code>@payable</code> 和 <code>@external</code> 装饰器。</p></li><li><p><code>__init__</code>：合约的构造函数。</p></li><li><p>设置 <code>greet</code> 变量的初始值。</p></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">编译并部署代码</h2><p>在合约文件夹下输入命令进行编译：</p><pre data-type="codeBlock" text="ape compile
"><code>ape <span class="hljs-built_in">compile</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/201cf65ddf66ca84e2d24523c0880f67ef5be03a422593b521ba9bbc53746f9a.png" alt="compile" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">compile</figcaption></figure><ol><li><p>进入 <code>ape</code> 控制台，部署到 <code>ethereum-fork</code>。</p></li><li><p><code>ape</code> 分配测试账户并添加ETH：</p></li></ol><pre data-type="codeBlock" text="from ape import accounts

accounts[0].balance += int(1e18)
"><code><span class="hljs-keyword">from</span> ape <span class="hljs-keyword">import</span> <span class="hljs-title">accounts</span>

<span class="hljs-title">accounts</span>[0].<span class="hljs-title">balance</span> <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">int</span></span>(1<span class="hljs-title">e18</span>)
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e125b61d35b5bf3730d12c4a930a5a6d1fc9ed1fb1300391b0412911325fa9de.png" alt="addBalance" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">addBalance</figcaption></figure><pre data-type="codeBlock" text="contract = accounts[0].deploy(project.HelloVyper)
"><code><span class="hljs-attr">contract</span> = accounts[<span class="hljs-number">0</span>].deploy(project.HelloVyper)
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c44b46d0460909b5da24a45baeadf0ac78d14f7e285a75e3a7e65a8594bc2f4b.png" alt="deploy" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">deploy</figcaption></figure><h2 id="h-ide" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">使用浏览器IDE开发</h2><p>对于简单的合约，你可以在<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://try.vyperlang.org/">https://try.vyperlang.org/</a>网站托管的jupyter notebook上进行开发。</p><p>首先，你需要导入<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/vyperlang/titanoboa">boa</a>包，它是一个Vyper解释器，支持在jupyter notebook中运行Vyper合约。</p><pre data-type="codeBlock" text="# 导入需要的包
import boa; from boa.network import NetworkEnv
%load_ext boa.ipython
from boa.integrations.jupyter import BrowserSigner
"><code># 导入需要的包
<span class="hljs-keyword">import</span> <span class="hljs-title">boa</span>; <span class="hljs-keyword">from</span> boa.network <span class="hljs-keyword">import</span> <span class="hljs-title">NetworkEnv</span>
<span class="hljs-operator">%</span><span class="hljs-title">load_ext</span> <span class="hljs-title">boa</span>.<span class="hljs-title">ipython</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">boa</span>.<span class="hljs-title">integrations</span>.<span class="hljs-title">jupyter</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">BrowserSigner</span>
</code></pre><p>第二步，复制粘贴我们的Vyper合约。</p><pre data-type="codeBlock" text="%%vyper MyContract

greet: public(String[12])

@payable
@external
def __init__():
    self.greet = &quot;Hello Vyper!&quot;
"><code><span class="hljs-operator">%</span><span class="hljs-operator">%</span>vyper MyContract

greet: <span class="hljs-keyword">public</span>(String[<span class="hljs-number">12</span>])

@<span class="hljs-keyword">payable</span>
@<span class="hljs-keyword">external</span>
def __init__():
    <span class="hljs-built_in">self</span>.greet <span class="hljs-operator">=</span> <span class="hljs-string">"Hello Vyper!"</span>
</code></pre><p>第三步，部署Vyper合约，并赋值给合约变量<code>c</code>：</p><pre data-type="codeBlock" text="# 部署合约
c = MyContract.deploy()
"><code><span class="hljs-comment"># 部署合约</span>
<span class="hljs-attr">c</span> = MyContract.deploy()
</code></pre><p>最后一步，与部署好的合约<code>c</code>交互，读取<code>greet</code>变量的值，将输出<code>&apos;Hello Vyper!&apos;</code>。</p><pre data-type="codeBlock" text="# 对于public变量，可以通过合约实例直接访问
c.greet()
"><code># 对于<span class="hljs-keyword">public</span>变量，可以通过合约实例直接访问
c.greet()
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"></h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/81b6499ab98f81da643b9aad232c99eaf15a536eee652248073ff9977ee90b01.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><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">总结</h2><p>这一讲，我们介绍了Vyper语言，它的开发环境，并编写和部署第一个合约 <code>HelloVyper</code>。后续我们将更深入的学习Vyper！</p>]]></content:encoded>
            <author>0x77-2@newsletter.paragraph.com (0x77)</author>
        </item>
    </channel>
</rss>