<?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>Yaakov</title>
        <link>https://paragraph.com/@yaakov</link>
        <description>undefined</description>
        <lastBuildDate>Sat, 04 Jul 2026 15:47:10 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Yaakov</title>
            <url>https://storage.googleapis.com/papyrus_images/e420272dddd68eb09cd7b9e96dbe069f94c6f03f95f6898655fc155bcb74dda1.png</url>
            <link>https://paragraph.com/@yaakov</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Leo 语言开发规范总结]]></title>
            <link>https://paragraph.com/@yaakov/leo-5</link>
            <guid>jT1sKSafBLzX9u8b0tOv</guid>
            <pubDate>Wed, 30 Oct 2024 11:27:19 GMT</pubDate>
            <description><![CDATA[一、代码布局规范1. 缩进要求每级缩进使用 4 个空格。不推荐使用制表符（Tab）。2. 空行使用规则顶层声明之间（如 transition、function、struct、record 和 mapping）需要用单个空行分隔。import 语句之间可以选择性地使用单个空行分隔。文件顶部的最后一个 import 语句后应该跟一个空行。3. 文件结构顺序按照以下顺序组织文件内容：导入语句（Imports）程序声明（Program declaration）映射（Mappings）记录和结构体（Records + Structs）函数和转换（Functions + Transitions）二、命名规范各类型命名方式如下：包名：使用 snake_case（推荐使用单个词）。结构体和记录：使用 CamelCase。结构体和记录成员：使用 snake_case。函数名：使用 snake_case。函数参数：使用 snake_case。变量名：使用 snake_case。输入参数：使用 snake_case。三、语法规范1. 大括号使用开括号总是与声明在同一行，不要将开括号放在新行。2. 分号...]]></description>
            <content:encoded><![CDATA[<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><ul><li><p>每级缩进使用 4 个空格。</p></li><li><p>不推荐使用制表符（Tab）。</p></li></ul><h3 id="h-2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 空行使用规则</h3><ul><li><p>顶层声明之间（如 <code>transition</code>、<code>function</code>、<code>struct</code>、<code>record</code> 和 <code>mapping</code>）需要用单个空行分隔。</p></li><li><p><code>import</code> 语句之间可以选择性地使用单个空行分隔。</p></li><li><p>文件顶部的最后一个 <code>import</code> 语句后应该跟一个空行。</p></li></ul><h3 id="h-3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. 文件结构顺序</h3><p>按照以下顺序组织文件内容：</p><ol><li><p>导入语句（Imports）</p></li><li><p>程序声明（Program declaration）</p></li><li><p>映射（Mappings）</p></li><li><p>记录和结构体（Records + Structs）</p></li><li><p>函数和转换（Functions + Transitions）</p></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">二、命名规范</h2><p>各类型命名方式如下：</p><ul><li><p><strong>包名</strong>：使用 <code>snake_case</code>（推荐使用单个词）。</p></li><li><p><strong>结构体和记录</strong>：使用 <code>CamelCase</code>。</p></li><li><p><strong>结构体和记录成员</strong>：使用 <code>snake_case</code>。</p></li><li><p><strong>函数名</strong>：使用 <code>snake_case</code>。</p></li><li><p><strong>函数参数</strong>：使用 <code>snake_case</code>。</p></li><li><p><strong>变量名</strong>：使用 <code>snake_case</code>。</p></li><li><p><strong>输入参数</strong>：使用 <code>snake_case</code>。</p></li></ul><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><ul><li><p>开括号总是与声明在同一行，不要将开括号放在新行。</p></li></ul><h3 id="h-2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 分号使用</h3><ul><li><p>每个语句（包括 <code>return</code> 语句）都必须以分号结束，保持语句结束的一致性。</p></li></ul><h3 id="h-3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. 逗号使用</h3><ul><li><p>当结束定界符出现在单独一行时，应包含尾随逗号，以提高代码的可维护性和可读性。</p></li></ul><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">四、条件分支处理</h2><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">推荐做法</h3><ul><li><p>使用三元表达式而不是 <code>if-else</code> 语句，可以更好地控制电路大小和效率。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">原因解释</h3><ul><li><p>Leo 编译器会将 <code>transitions</code> 中的 <code>if-else</code> 语句重写为三元表达式序列，因为底层电路构造不支持分支操作。</p></li><li><p>三元表达式是最经济的条件形式，可以在评估条件之前解析第一个和第二个表达式的值。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">性能影响</h3><ul><li><p>使用 <code>if-else</code> 会导致电路创建分支，每个分支都需要完整评估，条件内的每个计算成本都会翻倍。这会显著增加约束数量并降低电路效率。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">代码示例</h3><ul><li><p><strong>不推荐</strong>：</p><pre data-type="codeBlock" text="if (condition) {
    return a;
} else {
    return b;
}
"><code><span class="hljs-keyword">if</span> (condition) {
    <span class="hljs-keyword">return</span> a;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> b;
}
</code></pre></li><li><p><strong>推荐</strong>：</p><pre data-type="codeBlock" text="return condition ? a : b;
"><code>return condition ? <span class="hljs-selector-tag">a</span> : b;
</code></pre></li></ul><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><ul><li><p>保持代码结构清晰，遵循文件元素的标准顺序，使用一致的命名约定。</p></li></ul><h3 id="h-2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 性能优化</h3><ul><li><p>优先使用三元表达式，避免不必要的条件分支，注意控制电路大小。</p></li></ul><h3 id="h-3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. 可维护性</h3><ul><li><p>保持代码格式的一致性，适当使用空行增加可读性，遵循标准的命名规范。</p></li></ul><hr><p>这些规范和最佳实践可以帮助开发者编写更高效、更易维护的 Leo 代码，同时确保生成的电路具有最佳性能。</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[使用 Spruce DID Kit 颁发 Aleo 的可验证凭证]]></title>
            <link>https://paragraph.com/@yaakov/spruce-did-kit-aleo</link>
            <guid>mCUuF6Skiy3jFfbtir67</guid>
            <pubDate>Fri, 16 Aug 2024 12:39:17 GMT</pubDate>
            <description><![CDATA[使用 Spruce DID Kit 颁发 Aleo 的可验证凭证介绍Spruce DID Kit 是一个功能强大的工具包，旨在帮助开发者构建和管理去中心化身份（Decentralized Identity）。它是 SpruceKit 生态系统的一部分，专注于实现和管理符合 W3C 标准的可验证凭证（Verifiable Credentials，VC）和去中心化标识符（Decentralized Identifiers，DID）。通过使用 Spruce DID Kit，开发者可以轻松地创建、签署、验证和管理数字身份和凭证，确保身份数据的安全性和隐私性。主要功能和组件DIDKit: 这是 Spruce DID Kit 的核心库之一，提供了处理 W3C 可验证凭证和去中心化标识符的工具。DIDKit 支持各种数据模型和协议，帮助开发者实现标准化的身份管理解决方案。TreeLDR: 一种模式定义语言，用于描述模式的结构和语义。它连接了 RDF（资源描述框架）与结构化模式框架（如 JSON Schema），提供了更丰富的数据描述能力。Rebase: 这个库用于处理加密可验证的声明，并基于这...]]></description>
            <content:encoded><![CDATA[<h1 id="h-spruce-did-kit-aleo" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">使用 Spruce DID Kit 颁发 Aleo 的可验证凭证</h1><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">介绍</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.sprucekit.dev/">Spruce DID Kit</a> 是一个功能强大的工具包，旨在帮助开发者构建和管理去中心化身份（Decentralized Identity）。它是 SpruceKit 生态系统的一部分，专注于实现和管理符合 W3C 标准的可验证凭证（Verifiable Credentials，VC）和去中心化标识符（Decentralized Identifiers，DID）。通过使用 Spruce DID Kit，开发者可以轻松地创建、签署、验证和管理数字身份和凭证，确保身份数据的安全性和隐私性。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">主要功能和组件</h4><ol><li><p><strong>DIDKit</strong>: 这是 Spruce DID Kit 的核心库之一，提供了处理 W3C 可验证凭证和去中心化标识符的工具。DIDKit 支持各种数据模型和协议，帮助开发者实现标准化的身份管理解决方案。</p></li><li><p><strong>TreeLDR</strong>: 一种模式定义语言，用于描述模式的结构和语义。它连接了 RDF（资源描述框架）与结构化模式框架（如 JSON Schema），提供了更丰富的数据描述能力。</p></li><li><p><strong>Rebase</strong>: 这个库用于处理加密可验证的声明，并基于这些声明发行可验证凭证（VC）。它确保了声明的真实性和可信性，是身份验证流程的关键部分。</p></li><li><p><strong>以太坊登录</strong>: 这一功能允许用户使用其以太坊账户和 ENS（以太坊名称服务）配置文件来控制他们的数字身份。它提供了一种新的身份验证方法，增强了用户对其数字身份的控制。</p></li></ol><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">使用场景</h4><p>Spruce DID Kit 可用于多个场景，包括但不限于：</p><ul><li><p><strong>数字身份验证</strong>：创建和验证用户的数字身份，确保用户数据的真实性和隐私性。</p></li><li><p><strong>身份钱包构建</strong>：开发支持可验证凭证的数字钱包，用户可以在这些钱包中存储和管理其身份数据。</p></li><li><p><strong>现有系统增强</strong>：将可验证凭证功能集成到现有的身份管理系统或钱包中，提升系统的安全性和功能性。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">快速入门指南</h3><p>本教程将带你了解如何使用 SpruceID 工具，重点讲解使用 DIDKit CLI 程序进行凭证发行和验证的基础知识。</p><h4 id="h-0-didkit" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">第0步：安装 DIDKit</h4><p>要在GNU/Linux、MacOS或Windows+WSL上安装DIDKit命令行程序，首先需要安装Cargo。</p><pre data-type="codeBlock" text="cargo install didkit-cli
"><code>cargo install didkit<span class="hljs-operator">-</span>cli
</code></pre><p>这将会把 <code>didkit</code> 二进制文件添加到你的 Cargo 安装路径中，通常位于 <code>~/.cargo/bin</code>，你可以将其添加到系统的PATH中以方便使用。</p><h4 id="h-1-did-vc" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">第1步：使用 DID 发行和验证你的第一个可验证凭证（VC）</h4><p><strong>生成 did-key DID</strong>要发行你的第一个凭证，你需要一个签名密钥。使用DIDKit生成一个Ed25519私钥，并使用did-key DID方法创建一个DID：</p><pre data-type="codeBlock" text="didkit generate-ed25519-key &gt; issuer_key.jwk
issuer_did=$(didkit key-to-did key -k issuer_key.jwk)
echo $issuer_did
"><code>didkit generate<span class="hljs-operator">-</span>ed25519<span class="hljs-operator">-</span>key <span class="hljs-operator">></span> issuer_key.jwk
issuer_did<span class="hljs-operator">=</span>$(didkit key<span class="hljs-operator">-</span>to<span class="hljs-operator">-</span>did key <span class="hljs-operator">-</span>k issuer_key.jwk)
echo $issuer_did
</code></pre><p>在准备好签名密钥及其DID后，指定要签名的可验证凭证（VC）的JSON格式：</p><pre data-type="codeBlock" text="cat &gt; unsigned-vc.json &lt;&lt; EOF
{
    &quot;@context&quot;: &quot;https://www.w3.org/2018/credentials/v1&quot;,
    &quot;id&quot;: &quot;urn:uuid:$(uuidgen)&quot;,
    &quot;type&quot;: [&quot;VerifiableCredential&quot;],
    &quot;issuer&quot;: &quot;${issuer_did}&quot;,
    &quot;issuanceDate&quot;: &quot;$(date -u +%FT%TZ)&quot;,
    &quot;credentialSubject&quot;: {
        &quot;id&quot;: &quot;did:example:my-data-subject-identifier&quot;
    }
}
EOF
"><code>cat <span class="hljs-operator">></span> unsigned<span class="hljs-operator">-</span>vc.json <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span> EOF
{
    <span class="hljs-string">"@context"</span>: <span class="hljs-string">"https://www.w3.org/2018/credentials/v1"</span>,
    <span class="hljs-string">"id"</span>: <span class="hljs-string">"urn:uuid:$(uuidgen)"</span>,
    <span class="hljs-string">"type"</span>: [<span class="hljs-string">"VerifiableCredential"</span>],
    <span class="hljs-string">"issuer"</span>: <span class="hljs-string">"${issuer_did}"</span>,
    <span class="hljs-string">"issuanceDate"</span>: <span class="hljs-string">"$(date -u +%FT%TZ)"</span>,
    <span class="hljs-string">"credentialSubject"</span>: {
        <span class="hljs-string">"id"</span>: <span class="hljs-string">"did:example:my-data-subject-identifier"</span>
    }
}
EOF
</code></pre><p><code>@context</code> 属性表明这个JSON对象是一个W3C可验证凭证。<code>id</code> 属性是这个VC的标识符。<code>type</code> 属性识别这个VC为一个基本数据模型。<code>issuer</code> 属性包含发行者的URI（即之前生成的did-key），<code>issuanceDate</code> 表示发行时间（当前UTC时间）。<code>credentialSubject</code> 包含实际的声明。</p><p><strong>签署VC</strong>要使用DIDKit CLI签署VC，指定签名密钥的路径、验证方法（<code>-v</code>）、证明目的（<code>-p</code>）和未签名的凭证：</p><pre data-type="codeBlock" text="vm=$(didkit key-to-verification-method key --key-path issuer_key.jwk)
didkit vc-issue-credential --key-path issuer_key.jwk \
                           -v &quot;${vm}&quot; -p assertionMethod \
                           &lt; unsigned-vc.json &gt; signed-vc.json
cat signed-vc.json
"><code>vm<span class="hljs-operator">=</span>$(didkit key<span class="hljs-operator">-</span>to<span class="hljs-operator">-</span>verification<span class="hljs-operator">-</span>method key <span class="hljs-operator">-</span><span class="hljs-operator">-</span>key<span class="hljs-operator">-</span>path issuer_key.jwk)
didkit vc<span class="hljs-operator">-</span>issue<span class="hljs-operator">-</span>credential <span class="hljs-operator">-</span><span class="hljs-operator">-</span>key<span class="hljs-operator">-</span>path issuer_key.jwk \
                           <span class="hljs-operator">-</span>v <span class="hljs-string">"${vm}"</span> <span class="hljs-operator">-</span>p assertionMethod \
                           <span class="hljs-operator">&#x3C;</span> unsigned<span class="hljs-operator">-</span>vc.json <span class="hljs-operator">></span> signed<span class="hljs-operator">-</span>vc.json
cat signed<span class="hljs-operator">-</span>vc.json
</code></pre><p>这将生成一个已签名的VC。验证已签名的VC：</p><pre data-type="codeBlock" text="didkit vc-verify-credential &lt; signed-vc.json
"><code>didkit vc<span class="hljs-operator">-</span>verify<span class="hljs-operator">-</span>credential <span class="hljs-operator">&#x3C;</span> signed<span class="hljs-operator">-</span>vc.json
</code></pre><p>确保没有出现任何检查失败、警告或错误。为了验证，修改 <code>signed-vc.json</code> 的内容，然后再次验证它以查看验证失败的情况。</p><h4 id="h-2did-webvc" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">第2步：验证由did-web发行的VC</h4><p>要验证来自Spruce演示服务器的VC：</p><pre data-type="codeBlock" text="curl https://demo.spruceid.com/get-example-vc &gt; example-vc.json
"><code>curl https:<span class="hljs-comment">//demo.spruceid.com/get-example-vc > example-vc.json</span>
</code></pre><p><code>example-vc.json</code> 应该类似于：</p><pre data-type="codeBlock" text="{
  &quot;@context&quot;: [&quot;https://www.w3.org/2018/credentials/v1&quot;],
  &quot;type&quot;: &quot;VerifiableCredential&quot;,
  &quot;credentialSubject&quot;: {},
  &quot;issuer&quot;: &quot;did:web:demo.spruceid.com&quot;,
  &quot;issuanceDate&quot;: &quot;2021-09-13T18:23:56Z&quot;,
  &quot;proof&quot;: {
    &quot;type&quot;: &quot;Ed25519Signature2018&quot;,
    &quot;proofPurpose&quot;: &quot;assertionMethod&quot;,
    &quot;verificationMethod&quot;: &quot;did:web:demo.spruceid.com#_t-v-Ep7AtkELhhvAzCCDzy1O5Bn_z1CVFv9yiRXdHY&quot;,
    &quot;created&quot;: &quot;2021-09-13T18:23:56.483Z&quot;,
    &quot;jws&quot;: &quot;eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..X5J2jI5j3TPqFO_g6XOlB730WlXJ8mDsfoyLQ4u60MelVosi1Et6V_pB7-zELDggdqZTsKQjSqDodv0m7ui1Bg&quot;
  },
  &quot;expirationDate&quot;: &quot;2021-10-13T18:23:56Z&quot;
}
"><code>{
  "<span class="hljs-keyword">@context</span><span class="hljs-string">": ["</span><span class="hljs-attribute">https</span>://www.w3.org/<span class="hljs-number">2018</span>/credentials/v1<span class="hljs-string">"],
  "</span>type<span class="hljs-string">": "</span>VerifiableCredential<span class="hljs-string">",
  "</span>credentialSubject<span class="hljs-string">": {},
  "</span>issuer<span class="hljs-string">": "</span><span class="hljs-attribute">did</span>:<span class="hljs-attribute">web</span>:demo.spruceid.com<span class="hljs-string">",
  "</span>issuanceDate<span class="hljs-string">": "</span><span class="hljs-number">2021</span>-<span class="hljs-number">09</span>-<span class="hljs-number">13</span>T18:<span class="hljs-number">23</span>:<span class="hljs-number">56</span>Z<span class="hljs-string">",
  "</span>proof<span class="hljs-string">": {
    "</span>type<span class="hljs-string">": "</span>Ed25519Signature2018<span class="hljs-string">",
    "</span>proofPurpose<span class="hljs-string">": "</span>assertionMethod<span class="hljs-string">",
    "</span>verificationMethod<span class="hljs-string">": "</span><span class="hljs-attribute">did</span>:<span class="hljs-attribute">web</span>:demo.spruceid.com#_t-v-Ep7AtkELhhvAzCCDzy1O5Bn_z1CVFv9yiRXdHY<span class="hljs-string">",
    "</span>created<span class="hljs-string">": "</span><span class="hljs-number">2021</span>-<span class="hljs-number">09</span>-<span class="hljs-number">13</span>T18:<span class="hljs-number">23</span>:<span class="hljs-number">56.483</span>Z<span class="hljs-string">",
    "</span>jws<span class="hljs-string">": "</span>eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..X5J2jI5j3TPqFO_g6XOlB730WlXJ8mDsfoyLQ4u60MelVosi1Et6V_pB7-zELDggdqZTsKQjSqDodv0m7ui1Bg<span class="hljs-string">"
  },
  "</span>expirationDate<span class="hljs-string">": "</span><span class="hljs-number">2021</span>-<span class="hljs-number">10</span>-<span class="hljs-number">13</span>T18:<span class="hljs-number">23</span>:<span class="hljs-number">56</span>Z<span class="hljs-string">"
}
</span></code></pre><p>验证VC：</p><pre data-type="codeBlock" text="didkit vc-verify-credential -p assertionMethod &lt; example-vc.json
"><code>didkit vc<span class="hljs-operator">-</span>verify<span class="hljs-operator">-</span>credential <span class="hljs-operator">-</span>p assertionMethod <span class="hljs-operator">&#x3C;</span> example<span class="hljs-operator">-</span>vc.json
</code></pre><p>确保没有出现任何检查失败、警告或错误。修改 <code>example-vc.json</code> 的内容，然后再次验证它以查看验证失败的情况。要直接解析did-web DID：</p><pre data-type="codeBlock" text="didkit did-resolve did:web:demo.spruceid.com
"><code>didkit did<span class="hljs-operator">-</span>resolve did:web:demo.spruceid.com
</code></pre><p>更多信息请访问：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.sprucekit.dev">https://www.sprucekit.dev</a></p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">总结</h3><p>通过前面的简单学习，你已经学习了使用did-key DID发行可验证凭证（VC），并验证它以及通过did-web DID发行的VC的整个过程。通过SpruceKit和DIDKit，你拥有了构建和验证去中心化身份解决方案的强大工具。这只是一个开始，在SpruceID生态系统中还有许多功能和能力等待你探索。一起加油！</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo 多签钱包的实现过程分析]]></title>
            <link>https://paragraph.com/@yaakov/aleo-2</link>
            <guid>brzJufDLNTC8PumjEi1W</guid>
            <pubDate>Fri, 16 Aug 2024 12:38:19 GMT</pubDate>
            <description><![CDATA[Aleo 多签钱包的实现过程分析背景在现代区块链应用中，资产管理和交易安全性成为了关键问题，尤其是在需要多人共同管理或决策的情况下。传统的单签名（Single-Signature）模式，虽然简单易用，但存在单点故障的风险。为了增强安全性和分散控制权，区块链引入了多签名合约（Multi-signature contract）机制。多签合约允许一个钱包或账户的资产由多个参与者共同管理，只有在达到预设的签名阈值时，交易才能被执行。 这里我们要学习的一个 Aleo 的多签合约 Coffer multisig wallet 正是一个实现了多签名功能的智能合约。这种合约设计适合那些需要多方共同参与决策的场景，例如企业财务管理、去中心化自治组织（DAO）或需要高安全性的个人账户管理。作用Coffer multisig wallet 多签合约在以下方面具有自己的优势：安全性提升：合约定义了多个持有者（最多可以有9个），这些持有者共同管理同一个钱包（WalletInfo结构体表示）。只有在达到预设的签名数量（阈值）时，交易才会被执行。这有效防止了单点失误或恶意操作导致的资金丢失。灵活的资产管理：该...]]></description>
            <content:encoded><![CDATA[<h1 id="h-aleo" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Aleo 多签钱包的实现过程分析</h1><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">背景</h3><p>在现代区块链应用中，资产管理和交易安全性成为了关键问题，尤其是在需要多人共同管理或决策的情况下。传统的单签名（Single-Signature）模式，虽然简单易用，但存在单点故障的风险。为了增强安全性和分散控制权，区块链引入了多签名合约（Multi-signature contract）机制。多签合约允许一个钱包或账户的资产由多个参与者共同管理，只有在达到预设的签名阈值时，交易才能被执行。</p><p>这里我们要学习的一个 Aleo 的多签合约 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/coffer-aleo/coffer-wallet/tree/main">Coffer multisig wallet</a> 正是一个实现了多签名功能的智能合约。这种合约设计适合那些需要多方共同参与决策的场景，例如企业财务管理、去中心化自治组织（DAO）或需要高安全性的个人账户管理。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">作用</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/coffer-aleo/coffer-wallet/tree/main">Coffer multisig wallet</a> 多签合约在以下方面具有自己的优势：</p><ol><li><p><strong>安全性提升</strong>：</p><ul><li><p>合约定义了多个持有者（最多可以有9个），这些持有者共同管理同一个钱包（<code>WalletInfo</code>结构体表示）。只有在达到预设的签名数量（阈值）时，交易才会被执行。这有效防止了单点失误或恶意操作导致的资金丢失。</p></li></ul></li><li><p><strong>灵活的资产管理</strong>：</p><ul><li><p>该合约允许在多名持有者之间创建并管理钱包账户，支持复杂的资金管理操作。每个钱包可以持有多种代币，并且支持代币的存入、转出和转移操作。通过<code>create_wallet3</code>、<code>create_transfer3</code>、<code>confirm_transfer</code>、<code>reject_transfer</code>等多个操作函数，合约实现了完整的资产管理流程。</p></li></ul></li><li><p><strong>透明的交易流程</strong>：</p><ul><li><p>合约中的每一步操作都被记录在链上，确保了所有持有者都能透明地看到每一笔交易的状态。例如，<code>create_transfer3</code>创建一笔待确认的转账，之后的<code>confirm_transfer</code>和<code>reject_transfer</code>函数让持有者们对这笔交易进行确认或拒绝，只有当确认数达到阈值时，交易才会通过<code>execute_confirmed_transfer</code>执行。</p></li></ul></li><li><p><strong>去中心化控制</strong>：</p><ul><li><p>多签合约分散了资产的控制权，使得单一持有者无法单独进行敏感操作，必须通过集体决策。这种去中心化的控制方式，特别适合于需要多人共同参与决策的组织或项目，确保了管理的公平性和公正性。</p></li></ul></li></ol><p>综上， <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/coffer-aleo/coffer-wallet/tree/main">Coffer multisig wallet</a> 合约在多签的实现上提供了强大的安全性和管理功能，适用于需要多人共同管理的场景，有效地解决了传统单签名模式中的风险问题。</p><p>现在我们开始一起学习 Aleo 伤的这个多签合约（大部分关键代码已给出注释）。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">实现</h3><p><strong>钱包相关结构体与记录定义</strong></p><pre data-type="codeBlock" text="    struct WalletInfo {
        wallet_id: field,   // 钱包ID，唯一标识钱包

        holder1: address,   // 持有者1的地址
        holder2: address,   // 持有者2的地址
        holder3: address,   // 持有者3的地址
        holder4: address,   // 持有者4的地址（可选）
        holder5: address,   // 持有者5的地址（可选）
        holder6: address,   // 持有者6的地址（可选）
        holder7: address,   // 持有者7的地址（可选）
        holder8: address,   // 持有者8的地址（可选）
        holder9: address,   // 持有者9的地址（可选）

        holder_count: u8,   // 持有者数量
        threshold: u8       // 批准转账所需的最少确认数
    }

    record WalletHolder {
        owner: address,     // 钱包持有者的地址
        owner_id: u8,       // 持有者ID
        wallet: WalletInfo, // 钱包的基本信息
    }

    record PendingTransfer {
        owner: address,     // 转账请求的持有者
        transfer_id: field, // 转账ID
        creator: address,   // 转账创建者
        wallet: WalletInfo, // 与转账相关的钱包信息
        token_id: u64,      // 代币ID
        amount: u128,       // 转账金额
        to_address: address, // 接收方地址
        to_wallet_id: field, // 接收方钱包ID
    }

    record SignedTransfer {
        owner: address,     // 签名转账的持有者
        transfer_id: field, // 转账ID
        creator: address,   // 转账创建者
        wallet: WalletInfo, // 与转账相关的钱包信息
        token_id: u64,      // 代币ID
        amount: u128,       // 转账金额
        to_address: address, // 接收方地址
        to_wallet_id: field, // 接收方钱包ID
        confirmed: bool,    // 是否确认（true为确认，false为拒绝）
    }

    struct WalletBalanceKey {
        wallet_id: field,   // 钱包ID
        token_id: u64       // 代币ID
    }

    struct TransferStatus {
        confirmation_count: u8, // 已确认的次数
        rejection_count: u8,    // 已拒绝的次数
        status: u8,             // 转账状态（0-创建，1-执行，2-拒绝）
    }
"><code>    <span class="hljs-keyword">struct</span> <span class="hljs-title class_">WalletInfo</span> {
        wallet_id: field,   <span class="hljs-comment">// 钱包ID，唯一标识钱包</span>

        holder1: address,   <span class="hljs-comment">// 持有者1的地址</span>
        holder2: address,   <span class="hljs-comment">// 持有者2的地址</span>
        holder3: address,   <span class="hljs-comment">// 持有者3的地址</span>
        holder4: address,   <span class="hljs-comment">// 持有者4的地址（可选）</span>
        holder5: address,   <span class="hljs-comment">// 持有者5的地址（可选）</span>
        holder6: address,   <span class="hljs-comment">// 持有者6的地址（可选）</span>
        holder7: address,   <span class="hljs-comment">// 持有者7的地址（可选）</span>
        holder8: address,   <span class="hljs-comment">// 持有者8的地址（可选）</span>
        holder9: address,   <span class="hljs-comment">// 持有者9的地址（可选）</span>

        holder_count: <span class="hljs-type">u8</span>,   <span class="hljs-comment">// 持有者数量</span>
        threshold: <span class="hljs-type">u8</span>       <span class="hljs-comment">// 批准转账所需的最少确认数</span>
    }

    record WalletHolder {
        owner: address,     <span class="hljs-comment">// 钱包持有者的地址</span>
        owner_id: <span class="hljs-type">u8</span>,       <span class="hljs-comment">// 持有者ID</span>
        wallet: WalletInfo, <span class="hljs-comment">// 钱包的基本信息</span>
    }

    record PendingTransfer {
        owner: address,     <span class="hljs-comment">// 转账请求的持有者</span>
        transfer_id: field, <span class="hljs-comment">// 转账ID</span>
        creator: address,   <span class="hljs-comment">// 转账创建者</span>
        wallet: WalletInfo, <span class="hljs-comment">// 与转账相关的钱包信息</span>
        token_id: <span class="hljs-type">u64</span>,      <span class="hljs-comment">// 代币ID</span>
        amount: <span class="hljs-type">u128</span>,       <span class="hljs-comment">// 转账金额</span>
        to_address: address, <span class="hljs-comment">// 接收方地址</span>
        to_wallet_id: field, <span class="hljs-comment">// 接收方钱包ID</span>
    }

    record SignedTransfer {
        owner: address,     <span class="hljs-comment">// 签名转账的持有者</span>
        transfer_id: field, <span class="hljs-comment">// 转账ID</span>
        creator: address,   <span class="hljs-comment">// 转账创建者</span>
        wallet: WalletInfo, <span class="hljs-comment">// 与转账相关的钱包信息</span>
        token_id: <span class="hljs-type">u64</span>,      <span class="hljs-comment">// 代币ID</span>
        amount: <span class="hljs-type">u128</span>,       <span class="hljs-comment">// 转账金额</span>
        to_address: address, <span class="hljs-comment">// 接收方地址</span>
        to_wallet_id: field, <span class="hljs-comment">// 接收方钱包ID</span>
        confirmed: <span class="hljs-type">bool</span>,    <span class="hljs-comment">// 是否确认（true为确认，false为拒绝）</span>
    }

    <span class="hljs-keyword">struct</span> <span class="hljs-title class_">WalletBalanceKey</span> {
        wallet_id: field,   <span class="hljs-comment">// 钱包ID</span>
        token_id: <span class="hljs-type">u64</span>       <span class="hljs-comment">// 代币ID</span>
    }

    <span class="hljs-keyword">struct</span> <span class="hljs-title class_">TransferStatus</span> {
        confirmation_count: <span class="hljs-type">u8</span>, <span class="hljs-comment">// 已确认的次数</span>
        rejection_count: <span class="hljs-type">u8</span>,    <span class="hljs-comment">// 已拒绝的次数</span>
        status: <span class="hljs-type">u8</span>,             <span class="hljs-comment">// 转账状态（0-创建，1-执行，2-拒绝）</span>
    }
</code></pre><p><strong>映射 (Mappings)</strong></p><pre data-type="codeBlock" text="    mapping wallet_exists: field =&gt; bool; // 用于检查钱包是否存在

    mapping wallet_balances: field =&gt; u128; // 用于存储钱包的代币余额

    mapping transfers: field =&gt; TransferStatus; // 用于存储转账状态
"><code>    <span class="hljs-keyword">mapping</span> wallet_exists: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">bool</span>; <span class="hljs-comment">// 用于检查钱包是否存在</span>

    <span class="hljs-keyword">mapping</span> wallet_balances: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> u128; <span class="hljs-comment">// 用于存储钱包的代币余额</span>

    <span class="hljs-keyword">mapping</span> transfers: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> TransferStatus; <span class="hljs-comment">// 用于存储转账状态</span>
</code></pre><p><strong>Transition Functions (过渡函数)</strong></p><pre data-type="codeBlock" text="    transition create_wallet3(owner1: address, owner2: address, owner3: address, threshold: u8, wallet_id: field) -&gt; (WalletHolder, WalletHolder, WalletHolder) {
        let holder_count: u8 = 3u8; // 定义持有者数量为3
        let zero_address: address = aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc; // 定义占位符地址

        assert (threshold &gt; 0u8 &amp;&amp; threshold &lt;= holder_count); // 确保阈值在有效范围内
        assert (owner1 != owner2); // 确保持有者1和持有者2地址不相同

        let wallet_info: WalletInfo = WalletInfo {
            wallet_id: wallet_id,
            holder1: owner1,
            holder2: owner2,
            holder3: owner3,
            holder4: zero_address,
            holder5: zero_address,
            holder6: zero_address,
            holder7: zero_address,
            holder8: zero_address,
            holder9: zero_address,
            holder_count: holder_count,
            threshold: threshold
        }; // 创建一个包含三个持有者的钱包信息

        let wallet_holder1: WalletHolder = WalletHolder {
            owner: owner1,
            owner_id: 1u8,
            wallet: wallet_info
        }; // 创建第一个钱包持有者

        let wallet_holder2: WalletHolder = WalletHolder {
            owner: owner2,
            owner_id: 2u8,
            wallet: wallet_info
        }; // 创建第二个钱包持有者

        let wallet_holder3: WalletHolder = WalletHolder {
            owner: owner3,
            owner_id: 3u8,
            wallet: wallet_info
        }; // 创建第三个钱包持有者

        return (wallet_holder1, wallet_holder2, wallet_holder3) then finalize(wallet_id); // 返回钱包持有者记录并调用 finalize 函数
    }

    finalize create_wallet3(wallet_id: field) {
        assert(!Mapping::get_or_use(wallet_exists, wallet_id, false)); // 确保钱包ID唯一
        Mapping::set(wallet_exists, wallet_id, true); // 标记钱包为已存在
    }

    transition create_transfer3(wallet_holder: WalletHolder, token_id: u64, amount: u128, to_address: address, to_wallet_id: field, transfer_id: field) -&gt; (WalletHolder, PendingTransfer, PendingTransfer, PendingTransfer) {
        let holder_count: u8 = 3u8;
        let zero_address: address = aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc;

        assert(wallet_holder.wallet.holder_count == holder_count); // 确保持有者数量为3
        assert(to_address == zero_address || to_wallet_id == 0field); // 确保转账目标仅为地址或钱包ID之一

        let pending1: PendingTransfer = PendingTransfer {
            owner: wallet_holder.wallet.holder1,
            transfer_id: transfer_id,
            creator: wallet_holder.owner,
            wallet: wallet_holder.wallet,
            token_id: token_id,
            amount: amount,
            to_address: to_address,
            to_wallet_id: to_wallet_id
        }; // 为持有者1创建待处理转账

        let pending2: PendingTransfer = PendingTransfer {
            owner: wallet_holder.wallet.holder2,
            transfer_id: transfer_id,
            creator: wallet_holder.owner,
            wallet: wallet_holder.wallet,
            token_id: token_id,
            amount: amount,
            to_address: to_address,
            to_wallet_id: to_wallet_id
        }; // 为持有者2创建待处理转账

        let pending3: PendingTransfer = PendingTransfer {
            owner: wallet_holder.wallet.holder3,
            transfer_id: transfer_id,
            creator: wallet_holder.owner,
            wallet: wallet_holder.wallet,
            token_id: token_id,
            amount: amount,
            to_address: to_address,
            to_wallet_id: to_wallet_id
        }; // 为持有者3创建待处理转账

        let new_wallet_holder: WalletHolder = WalletHolder {
            owner: wallet_holder.owner,
            owner_id: wallet_holder.owner_id,
            wallet: wallet_holder.wallet
        }; // 创建更新后的钱包持有者

        return (new_wallet_holder, pending1, pending2, pending3) then finalize(transfer_id); // 返回更新后的钱包持有者和待处理转账记录并调用 finalize
    }

    finalize create_transfer3(transfer_id: field) {
        assert(!Mapping::contains(transfers, transfer_id)); // 确保转账ID唯一
        Mapping::set(transfers, transfer_id, TransferStatus {
            confirmation_count: 1u8,
            rejection_count: 0u8,
            status: 0u8,
        }); // 初始化转账状态
    }

    transition confirm_transfer(pending_transfer: PendingTransfer) -&gt; SignedTransfer {
        let signed: SignedTransfer = SignedTransfer {
            owner: pending_transfer.owner,
            transfer_id: pending_transfer.transfer_id,
            creator: pending_transfer.creator,
            wallet: pending_transfer.wallet,
            token_id: pending_transfer.token_id,
            amount: pending_transfer.amount,
            to_address: pending_transfer.to_address,
            to_wallet_id: pending_transfer.to_wallet_id,
            confirmed: true
        }; // 创建一个签名的转账记录

        return (signed) then finalize(pending_transfer.transfer_id); // 返回签名记录并调用 finalize
    }

    finalize confirm_transfer(transfer_id: field) {
        let transfer_status: TransferStatus = Mapping::get(transfers, transfer_id);

        Mapping::set(transfers, transfer_id, TransferStatus {
                        confirmation_count: transfer_status.confirmation_count + 1u8, // 增加确认次数
            rejection_count: transfer_status.rejection_count, // 保持拒绝次数不变
            status: transfer_status.status // 保持当前转账状态不变
        });
    }

    transition reject_transfer(pending_transfer: PendingTransfer) -&gt; SignedTransfer {
        let signed: SignedTransfer = SignedTransfer {
            owner: pending_transfer.owner,
            transfer_id: pending_transfer.transfer_id,
            creator: pending_transfer.creator,
            wallet: pending_transfer.wallet,
            token_id: pending_transfer.token_id,
            amount: pending_transfer.amount,
            to_address: pending_transfer.to_address,
            to_wallet_id: pending_transfer.to_wallet_id,
            confirmed: false // 将转账标记为拒绝
        };

        return (signed) then finalize(pending_transfer.transfer_id); // 返回已拒绝的签名记录并调用 finalize
    }

    finalize reject_transfer(transfer_id: field) {
        let transfer_status: TransferStatus = Mapping::get(transfers, transfer_id);
        Mapping::set(transfers, transfer_id, TransferStatus {
            confirmation_count: transfer_status.confirmation_count, // 保持确认次数不变
            rejection_count: transfer_status.rejection_count + 1u8, // 增加拒绝次数
            status: transfer_status.status // 保持当前转账状态不变
        });
    }

    transition execute_confirmed_transfer(signed_transfer: SignedTransfer) -&gt; (SignedTransfer, Token) {
        let zero_address: address = aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc;
        assert(signed_transfer.to_wallet_id == 0field || signed_transfer.to_address == zero_address); // 确保目标为有效的地址或钱包

        let token: Token = Token {
            owner: signed_transfer.to_address, // 生成新的 Token 对象
            amount: signed_transfer.to_wallet_id == 0field ? signed_transfer.amount : 0u128, // 如果目标是地址，设置金额
            token_id: signed_transfer.token_id
        };
        let to_wallet_balance_key: field = signed_transfer.to_wallet_id == 0field ? 0field : get_wallet_balance_key(token.token_id, signed_transfer.to_wallet_id); // 生成目标钱包的余额密钥

        let new_signed: SignedTransfer = SignedTransfer {
            owner: signed_transfer.owner,
            transfer_id: signed_transfer.transfer_id,
            creator: signed_transfer.creator,
            wallet: signed_transfer.wallet,
            token_id: signed_transfer.token_id,
            amount: signed_transfer.amount,
            to_address: signed_transfer.to_address,
            to_wallet_id: signed_transfer.to_wallet_id,
            confirmed: signed_transfer.confirmed
        };
        return (new_signed, token) then finalize(signed_transfer.transfer_id, signed_transfer.wallet.threshold, get_wallet_balance_key(token.token_id, signed_transfer.wallet.wallet_id), signed_transfer.amount, to_wallet_balance_key); // 返回更新后的签名记录和 Token 对象，并调用 finalize
    }

    finalize execute_confirmed_transfer(transfer_id: field, wallet_threshold: u8, wallet_balance_key: field, amount: u128, to_wallet_balance_key: field) {
        let transfer_status: TransferStatus = Mapping::get(transfers, transfer_id);
        assert(transfer_status.status == 0u8); // 确保转账尚未执行
        assert(transfer_status.confirmation_count &gt;= wallet_threshold); // 确保达到确认阈值

        let balance: u128 = Mapping::get(wallet_balances, wallet_balance_key);
        Mapping::set(wallet_balances, wallet_balance_key, balance - amount); // 从钱包余额中扣除转账金额

        if (to_wallet_balance_key == 0field) {
            // 如果目标是地址，代币已经在 transition 中生成，无需进一步处理
        } else {
            let to_balance: u128 = Mapping::get_or_use(wallet_balances, to_wallet_balance_key, 0u128);
            Mapping::set(wallet_balances, to_wallet_balance_key, to_balance + amount); // 如果目标是钱包，增加目标钱包的余额
        }

        Mapping::set(transfers, transfer_id, TransferStatus { 
            confirmation_count: transfer_status.confirmation_count,
            rejection_count: transfer_status.rejection_count,
            status: 1u8 // 更新转账状态为已执行
        });
    }

    transition deposit(token: Token, amount: u128, wallet_id: field) -&gt; (Token) {
        let change: Token = Token {
            owner: token.owner,
            amount: token.amount - amount, // 计算剩余代币
            token_id: token.token_id,
        };

        return (change) then finalize(wallet_id, get_wallet_balance_key(token.token_id, wallet_id), amount); // 返回剩余代币并调用 finalize
    }

    finalize deposit(wallet_id: field, wallet_balance_key: field, amount: u128) {
        assert (Mapping::contains(wallet_exists, wallet_id)); // 确保钱包存在

        let balance: u128 = Mapping::get_or_use(wallet_balances, wallet_balance_key, 0u128);
        Mapping::set(wallet_balances, wallet_balance_key, balance + amount); // 增加钱包的余额
    }

    inline get_wallet_balance_key(token_id: u64, wallet_id: field) -&gt; field {
        return BHP256::hash_to_field(WalletBalanceKey {token_id: token_id, wallet_id: wallet_id}); // 生成钱包余额的哈希密钥
    }
"><code>    transition create_wallet3(owner1: <span class="hljs-keyword">address</span>, owner2: <span class="hljs-keyword">address</span>, owner3: <span class="hljs-keyword">address</span>, threshold: u8, wallet_id: field) <span class="hljs-operator">-</span><span class="hljs-operator">></span> (WalletHolder, WalletHolder, WalletHolder) {
        let holder_count: u8 <span class="hljs-operator">=</span> 3u8; <span class="hljs-comment">// 定义持有者数量为3</span>
        let zero_address: <span class="hljs-keyword">address</span> <span class="hljs-operator">=</span> aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc; <span class="hljs-comment">// 定义占位符地址</span>

        <span class="hljs-built_in">assert</span> (threshold <span class="hljs-operator">></span> 0u8 <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> threshold <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> holder_count); <span class="hljs-comment">// 确保阈值在有效范围内</span>
        <span class="hljs-built_in">assert</span> (owner1 <span class="hljs-operator">!</span><span class="hljs-operator">=</span> owner2); <span class="hljs-comment">// 确保持有者1和持有者2地址不相同</span>

        let wallet_info: WalletInfo <span class="hljs-operator">=</span> WalletInfo {
            wallet_id: wallet_id,
            holder1: owner1,
            holder2: owner2,
            holder3: owner3,
            holder4: zero_address,
            holder5: zero_address,
            holder6: zero_address,
            holder7: zero_address,
            holder8: zero_address,
            holder9: zero_address,
            holder_count: holder_count,
            threshold: threshold
        }; <span class="hljs-comment">// 创建一个包含三个持有者的钱包信息</span>

        let wallet_holder1: WalletHolder <span class="hljs-operator">=</span> WalletHolder {
            owner: owner1,
            owner_id: 1u8,
            wallet: wallet_info
        }; <span class="hljs-comment">// 创建第一个钱包持有者</span>

        let wallet_holder2: WalletHolder <span class="hljs-operator">=</span> WalletHolder {
            owner: owner2,
            owner_id: 2u8,
            wallet: wallet_info
        }; <span class="hljs-comment">// 创建第二个钱包持有者</span>

        let wallet_holder3: WalletHolder <span class="hljs-operator">=</span> WalletHolder {
            owner: owner3,
            owner_id: 3u8,
            wallet: wallet_info
        }; <span class="hljs-comment">// 创建第三个钱包持有者</span>

        <span class="hljs-keyword">return</span> (wallet_holder1, wallet_holder2, wallet_holder3) then finalize(wallet_id); <span class="hljs-comment">// 返回钱包持有者记录并调用 finalize 函数</span>
    }

    finalize create_wallet3(wallet_id: field) {
        <span class="hljs-built_in">assert</span>(<span class="hljs-operator">!</span>Mapping::get_or_use(wallet_exists, wallet_id, <span class="hljs-literal">false</span>)); <span class="hljs-comment">// 确保钱包ID唯一</span>
        Mapping::set(wallet_exists, wallet_id, <span class="hljs-literal">true</span>); <span class="hljs-comment">// 标记钱包为已存在</span>
    }

    transition create_transfer3(wallet_holder: WalletHolder, token_id: u64, amount: u128, to_address: <span class="hljs-keyword">address</span>, to_wallet_id: field, transfer_id: field) <span class="hljs-operator">-</span><span class="hljs-operator">></span> (WalletHolder, PendingTransfer, PendingTransfer, PendingTransfer) {
        let holder_count: u8 <span class="hljs-operator">=</span> 3u8;
        let zero_address: <span class="hljs-keyword">address</span> <span class="hljs-operator">=</span> aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc;

        <span class="hljs-built_in">assert</span>(wallet_holder.wallet.holder_count <span class="hljs-operator">=</span><span class="hljs-operator">=</span> holder_count); <span class="hljs-comment">// 确保持有者数量为3</span>
        <span class="hljs-built_in">assert</span>(to_address <span class="hljs-operator">=</span><span class="hljs-operator">=</span> zero_address <span class="hljs-operator">|</span><span class="hljs-operator">|</span> to_wallet_id <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0field); <span class="hljs-comment">// 确保转账目标仅为地址或钱包ID之一</span>

        let pending1: PendingTransfer <span class="hljs-operator">=</span> PendingTransfer {
            owner: wallet_holder.wallet.holder1,
            transfer_id: transfer_id,
            creator: wallet_holder.owner,
            wallet: wallet_holder.wallet,
            token_id: token_id,
            amount: amount,
            to_address: to_address,
            to_wallet_id: to_wallet_id
        }; <span class="hljs-comment">// 为持有者1创建待处理转账</span>

        let pending2: PendingTransfer <span class="hljs-operator">=</span> PendingTransfer {
            owner: wallet_holder.wallet.holder2,
            transfer_id: transfer_id,
            creator: wallet_holder.owner,
            wallet: wallet_holder.wallet,
            token_id: token_id,
            amount: amount,
            to_address: to_address,
            to_wallet_id: to_wallet_id
        }; <span class="hljs-comment">// 为持有者2创建待处理转账</span>

        let pending3: PendingTransfer <span class="hljs-operator">=</span> PendingTransfer {
            owner: wallet_holder.wallet.holder3,
            transfer_id: transfer_id,
            creator: wallet_holder.owner,
            wallet: wallet_holder.wallet,
            token_id: token_id,
            amount: amount,
            to_address: to_address,
            to_wallet_id: to_wallet_id
        }; <span class="hljs-comment">// 为持有者3创建待处理转账</span>

        let new_wallet_holder: WalletHolder <span class="hljs-operator">=</span> WalletHolder {
            owner: wallet_holder.owner,
            owner_id: wallet_holder.owner_id,
            wallet: wallet_holder.wallet
        }; <span class="hljs-comment">// 创建更新后的钱包持有者</span>

        <span class="hljs-keyword">return</span> (new_wallet_holder, pending1, pending2, pending3) then finalize(transfer_id); <span class="hljs-comment">// 返回更新后的钱包持有者和待处理转账记录并调用 finalize</span>
    }

    finalize create_transfer3(transfer_id: field) {
        <span class="hljs-built_in">assert</span>(<span class="hljs-operator">!</span>Mapping::contains(transfers, transfer_id)); <span class="hljs-comment">// 确保转账ID唯一</span>
        Mapping::set(transfers, transfer_id, TransferStatus {
            confirmation_count: 1u8,
            rejection_count: 0u8,
            status: 0u8,
        }); <span class="hljs-comment">// 初始化转账状态</span>
    }

    transition confirm_transfer(pending_transfer: PendingTransfer) <span class="hljs-operator">-</span><span class="hljs-operator">></span> SignedTransfer {
        let signed: SignedTransfer <span class="hljs-operator">=</span> SignedTransfer {
            owner: pending_transfer.owner,
            transfer_id: pending_transfer.transfer_id,
            creator: pending_transfer.creator,
            wallet: pending_transfer.wallet,
            token_id: pending_transfer.token_id,
            amount: pending_transfer.amount,
            to_address: pending_transfer.to_address,
            to_wallet_id: pending_transfer.to_wallet_id,
            confirmed: <span class="hljs-literal">true</span>
        }; <span class="hljs-comment">// 创建一个签名的转账记录</span>

        <span class="hljs-keyword">return</span> (signed) then finalize(pending_transfer.transfer_id); <span class="hljs-comment">// 返回签名记录并调用 finalize</span>
    }

    finalize confirm_transfer(transfer_id: field) {
        let transfer_status: TransferStatus <span class="hljs-operator">=</span> Mapping::get(transfers, transfer_id);

        Mapping::set(transfers, transfer_id, TransferStatus {
                        confirmation_count: transfer_status.confirmation_count <span class="hljs-operator">+</span> 1u8, <span class="hljs-comment">// 增加确认次数</span>
            rejection_count: transfer_status.rejection_count, <span class="hljs-comment">// 保持拒绝次数不变</span>
            status: transfer_status.status <span class="hljs-comment">// 保持当前转账状态不变</span>
        });
    }

    transition reject_transfer(pending_transfer: PendingTransfer) <span class="hljs-operator">-</span><span class="hljs-operator">></span> SignedTransfer {
        let signed: SignedTransfer <span class="hljs-operator">=</span> SignedTransfer {
            owner: pending_transfer.owner,
            transfer_id: pending_transfer.transfer_id,
            creator: pending_transfer.creator,
            wallet: pending_transfer.wallet,
            token_id: pending_transfer.token_id,
            amount: pending_transfer.amount,
            to_address: pending_transfer.to_address,
            to_wallet_id: pending_transfer.to_wallet_id,
            confirmed: <span class="hljs-literal">false</span> <span class="hljs-comment">// 将转账标记为拒绝</span>
        };

        <span class="hljs-keyword">return</span> (signed) then finalize(pending_transfer.transfer_id); <span class="hljs-comment">// 返回已拒绝的签名记录并调用 finalize</span>
    }

    finalize reject_transfer(transfer_id: field) {
        let transfer_status: TransferStatus <span class="hljs-operator">=</span> Mapping::get(transfers, transfer_id);
        Mapping::set(transfers, transfer_id, TransferStatus {
            confirmation_count: transfer_status.confirmation_count, <span class="hljs-comment">// 保持确认次数不变</span>
            rejection_count: transfer_status.rejection_count <span class="hljs-operator">+</span> 1u8, <span class="hljs-comment">// 增加拒绝次数</span>
            status: transfer_status.status <span class="hljs-comment">// 保持当前转账状态不变</span>
        });
    }

    transition execute_confirmed_transfer(signed_transfer: SignedTransfer) <span class="hljs-operator">-</span><span class="hljs-operator">></span> (SignedTransfer, Token) {
        let zero_address: <span class="hljs-keyword">address</span> <span class="hljs-operator">=</span> aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc;
        <span class="hljs-built_in">assert</span>(signed_transfer.to_wallet_id <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0field <span class="hljs-operator">|</span><span class="hljs-operator">|</span> signed_transfer.to_address <span class="hljs-operator">=</span><span class="hljs-operator">=</span> zero_address); <span class="hljs-comment">// 确保目标为有效的地址或钱包</span>

        let token: Token <span class="hljs-operator">=</span> Token {
            owner: signed_transfer.to_address, <span class="hljs-comment">// 生成新的 Token 对象</span>
            amount: signed_transfer.to_wallet_id <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0field ? signed_transfer.amount : 0u128, <span class="hljs-comment">// 如果目标是地址，设置金额</span>
            token_id: signed_transfer.token_id
        };
        let to_wallet_balance_key: field <span class="hljs-operator">=</span> signed_transfer.to_wallet_id <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0field ? 0field : get_wallet_balance_key(token.token_id, signed_transfer.to_wallet_id); <span class="hljs-comment">// 生成目标钱包的余额密钥</span>

        let new_signed: SignedTransfer <span class="hljs-operator">=</span> SignedTransfer {
            owner: signed_transfer.owner,
            transfer_id: signed_transfer.transfer_id,
            creator: signed_transfer.creator,
            wallet: signed_transfer.wallet,
            token_id: signed_transfer.token_id,
            amount: signed_transfer.amount,
            to_address: signed_transfer.to_address,
            to_wallet_id: signed_transfer.to_wallet_id,
            confirmed: signed_transfer.confirmed
        };
        <span class="hljs-keyword">return</span> (new_signed, token) then finalize(signed_transfer.transfer_id, signed_transfer.wallet.threshold, get_wallet_balance_key(token.token_id, signed_transfer.wallet.wallet_id), signed_transfer.amount, to_wallet_balance_key); <span class="hljs-comment">// 返回更新后的签名记录和 Token 对象，并调用 finalize</span>
    }

    finalize execute_confirmed_transfer(transfer_id: field, wallet_threshold: u8, wallet_balance_key: field, amount: u128, to_wallet_balance_key: field) {
        let transfer_status: TransferStatus <span class="hljs-operator">=</span> Mapping::get(transfers, transfer_id);
        <span class="hljs-built_in">assert</span>(transfer_status.status <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0u8); <span class="hljs-comment">// 确保转账尚未执行</span>
        <span class="hljs-built_in">assert</span>(transfer_status.confirmation_count <span class="hljs-operator">></span><span class="hljs-operator">=</span> wallet_threshold); <span class="hljs-comment">// 确保达到确认阈值</span>

        let balance: u128 <span class="hljs-operator">=</span> Mapping::get(wallet_balances, wallet_balance_key);
        Mapping::set(wallet_balances, wallet_balance_key, balance <span class="hljs-operator">-</span> amount); <span class="hljs-comment">// 从钱包余额中扣除转账金额</span>

        <span class="hljs-keyword">if</span> (to_wallet_balance_key <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0field) {
            <span class="hljs-comment">// 如果目标是地址，代币已经在 transition 中生成，无需进一步处理</span>
        } <span class="hljs-keyword">else</span> {
            let to_balance: u128 <span class="hljs-operator">=</span> Mapping::get_or_use(wallet_balances, to_wallet_balance_key, 0u128);
            Mapping::set(wallet_balances, to_wallet_balance_key, to_balance <span class="hljs-operator">+</span> amount); <span class="hljs-comment">// 如果目标是钱包，增加目标钱包的余额</span>
        }

        Mapping::set(transfers, transfer_id, TransferStatus { 
            confirmation_count: transfer_status.confirmation_count,
            rejection_count: transfer_status.rejection_count,
            status: 1u8 <span class="hljs-comment">// 更新转账状态为已执行</span>
        });
    }

    transition deposit(token: Token, amount: u128, wallet_id: field) <span class="hljs-operator">-</span><span class="hljs-operator">></span> (Token) {
        let change: Token <span class="hljs-operator">=</span> Token {
            owner: token.owner,
            amount: token.amount <span class="hljs-operator">-</span> amount, <span class="hljs-comment">// 计算剩余代币</span>
            token_id: token.token_id,
        };

        <span class="hljs-keyword">return</span> (change) then finalize(wallet_id, get_wallet_balance_key(token.token_id, wallet_id), amount); <span class="hljs-comment">// 返回剩余代币并调用 finalize</span>
    }

    finalize deposit(wallet_id: field, wallet_balance_key: field, amount: u128) {
        <span class="hljs-built_in">assert</span> (Mapping::contains(wallet_exists, wallet_id)); <span class="hljs-comment">// 确保钱包存在</span>

        let balance: u128 <span class="hljs-operator">=</span> Mapping::get_or_use(wallet_balances, wallet_balance_key, 0u128);
        Mapping::set(wallet_balances, wallet_balance_key, balance <span class="hljs-operator">+</span> amount); <span class="hljs-comment">// 增加钱包的余额</span>
    }

    inline get_wallet_balance_key(token_id: u64, wallet_id: field) <span class="hljs-operator">-</span><span class="hljs-operator">></span> field {
        <span class="hljs-keyword">return</span> BHP256::hash_to_field(WalletBalanceKey {token_id: token_id, wallet_id: wallet_id}); <span class="hljs-comment">// 生成钱包余额的哈希密钥</span>
    }
</code></pre><p><strong>代币相关结构体与记录定义</strong></p><pre data-type="codeBlock" text="    // ██████████████████████████████████████████████████████████████████████
    //                                 Tokens
    // ██████████████████████████████████████████████████████████████████████

    record Token {
        owner: address,  // 代币的持有者地址
        amount: u128,    // 代币的数量
        token_id: u64,   // 代币的ID
    }

    struct TokenInfo {
        token_id: u64,   // 代币的ID
        max_supply: u128, // 代币的最大供应量
        decimals: u8,    // 代币的小数位数
    }

    mapping registered_tokens: u64 =&gt; TokenInfo; // 存储已注册的代币信息

    transition create_token(token_id: u64, decimals: u8, max_supply: u128) {
        let new_token: TokenInfo = TokenInfo{
            token_id,
            decimals,
            max_supply,
        }; // 创建新的代币信息

        return then finalize(new_token); // 返回代币信息并调用 finalize
    }

    finalize create_token(new_token: TokenInfo) {
        assert(!Mapping::contains(registered_tokens, new_token.token_id)); // 确保代币ID唯一
        Mapping::set(registered_tokens, new_token.token_id, new_token);    // 将新代币信息存储到映射中
    }

    transition mint_private(
        receiver: address, 
        token_id: u64, 
        amount: u128,
    ) -&gt; Token {
        assert(amount &lt;= 1000u128 * (10u128 ** 6u8)); // 确保铸造的代币数量不超过限制
        return Token {
            owner: receiver,
            amount: amount,
            token_id,
        } then finalize(token_id);  // 返回铸造的代币并调用 finalize
    }

    finalize mint_private(token_id: u64) {
        let token_info: TokenInfo = Mapping::get(registered_tokens, token_id); // 获取代币信息（此处没有具体操作，可根据需求扩展）
    }

}
"><code>    <span class="hljs-comment">// ██████████████████████████████████████████████████████████████████████</span>
    <span class="hljs-comment">//                                 Tokens</span>
    <span class="hljs-comment">// ██████████████████████████████████████████████████████████████████████</span>

    record Token {
        owner: <span class="hljs-keyword">address</span>,  <span class="hljs-comment">// 代币的持有者地址</span>
        amount: u128,    <span class="hljs-comment">// 代币的数量</span>
        token_id: u64,   <span class="hljs-comment">// 代币的ID</span>
    }

    <span class="hljs-keyword">struct</span> <span class="hljs-title">TokenInfo</span> {
        token_id: u64,   <span class="hljs-comment">// 代币的ID</span>
        max_supply: u128, <span class="hljs-comment">// 代币的最大供应量</span>
        decimals: u8,    <span class="hljs-comment">// 代币的小数位数</span>
    }

    <span class="hljs-keyword">mapping</span> registered_tokens: u64 <span class="hljs-operator">=</span><span class="hljs-operator">></span> TokenInfo; <span class="hljs-comment">// 存储已注册的代币信息</span>

    transition create_token(token_id: u64, decimals: u8, max_supply: u128) {
        let new_token: TokenInfo <span class="hljs-operator">=</span> TokenInfo{
            token_id,
            decimals,
            max_supply,
        }; <span class="hljs-comment">// 创建新的代币信息</span>

        <span class="hljs-keyword">return</span> then finalize(new_token); <span class="hljs-comment">// 返回代币信息并调用 finalize</span>
    }

    finalize create_token(new_token: TokenInfo) {
        <span class="hljs-built_in">assert</span>(<span class="hljs-operator">!</span>Mapping::contains(registered_tokens, new_token.token_id)); <span class="hljs-comment">// 确保代币ID唯一</span>
        Mapping::set(registered_tokens, new_token.token_id, new_token);    <span class="hljs-comment">// 将新代币信息存储到映射中</span>
    }

    transition mint_private(
        receiver: <span class="hljs-keyword">address</span>, 
        token_id: u64, 
        amount: u128,
    ) <span class="hljs-operator">-</span><span class="hljs-operator">></span> Token {
        <span class="hljs-built_in">assert</span>(amount <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> 1000u128 <span class="hljs-operator">*</span> (10u128 <span class="hljs-operator">*</span><span class="hljs-operator">*</span> 6u8)); <span class="hljs-comment">// 确保铸造的代币数量不超过限制</span>
        <span class="hljs-keyword">return</span> Token {
            owner: receiver,
            amount: amount,
            token_id,
        } then finalize(token_id);  <span class="hljs-comment">// 返回铸造的代币并调用 finalize</span>
    }

    finalize mint_private(token_id: u64) {
        let token_info: TokenInfo <span class="hljs-operator">=</span> Mapping::get(registered_tokens, token_id); <span class="hljs-comment">// 获取代币信息（此处没有具体操作，可根据需求扩展）</span>
    }

}
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">代码总结</h3><ul><li><p>该智能合约用于管理钱包和代币的创建、转账、存储及相关操作。</p></li><li><p><code>WalletInfo</code> 和 <code>WalletHolder</code> 定义了钱包的基本信息和持有者的结构。</p></li><li><p><code>PendingTransfer</code> 和 <code>SignedTransfer</code> 用于表示和管理转账的不同状态。</p></li><li><p>映射（<code>Mappings</code>）用于存储钱包是否存在、钱包的余额及转账的状态等。</p></li><li><p>过渡函数（<code>Transition Functions</code>）实现了钱包的创建、转账的确认与拒绝、代币的创建与铸造等核心功能。</p></li><li><p>最后，<code>finalize</code> 用于确保每个操作的状态正确更新。</p></li></ul><p>通过这些结构和功能，该智能合约能够实现一个多签名钱包系统，其中持有者们可以通过共同投票决定是否执行某笔转账。这些功能可以扩展到更复杂的金融应用场景中。我们从中也可以学习如何编写一个多签合约的思路，并且理解和掌握 Leo 这门编程语言。</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[ZK Gaming Toolkit 使用指南]]></title>
            <link>https://paragraph.com/@yaakov/zk-gaming-toolkit</link>
            <guid>q5OPpwXjnbpf8yDCtNz8</guid>
            <pubDate>Fri, 16 Aug 2024 12:37:30 GMT</pubDate>
            <description><![CDATA[ZK Gaming Toolkit 使用指南简介ZK Gaming SDK 是一个用于与 Aleo 零知识平台交互的游戏开发 API。它为开发者提供了丰富的工具和接口，使得在 Aleo 区块链上构建去中心化游戏变得更加容易。 你可以查看 Boloney，这是第一个使用 ZK Gaming Toolkit 构建的游戏。开始使用运行 API 主要有两种方式：本地运行或在隔离的 Minikube 容器中运行。本地运行在本地运行 API 之前，请确保已安装以下软件：Node.js 版本 18.16.0 LTSYarnAleoLeoSnarkOSAleo 开发服务器 - 运行 cargo install aleo-development-server首先启动本地 SnarkOS 信标节点：snarkos start --nodisplay --dev 0 --beacon "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH" ⚠️ 请不要更改私钥，因为应用程序在开发过程中是配置为使用此私钥的。然后，在另一个终端窗口中启动...]]></description>
            <content:encoded><![CDATA[<h1 id="h-zk-gaming-toolkit" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">ZK Gaming Toolkit 使用指南</h1><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">简介</h2><p>ZK Gaming SDK 是一个用于与 Aleo 零知识平台交互的游戏开发 API。它为开发者提供了丰富的工具和接口，使得在 Aleo 区块链上构建去中心化游戏变得更加容易。</p><p>你可以查看 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Kryha/boloney">Boloney</a>，这是第一个使用 ZK Gaming Toolkit 构建的游戏。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">开始使用</h2><p>运行 API 主要有两种方式：本地运行或在隔离的 Minikube 容器中运行。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">本地运行</h3><p>在本地运行 API 之前，请确保已安装以下软件：</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nodejs.org/en">Node.js</a> 版本 18.16.0 LTS</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://yarnpkg.com/getting-started/install">Yarn</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/AleoHQ/aleo#2-build-guide">Aleo</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/AleoHQ/leo#2-build-guide">Leo</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/AleoHQ/snarkOS#22-installation">SnarkOS</a></p></li><li><p>Aleo 开发服务器 - 运行 <code>cargo install aleo-development-server</code></p></li></ul><p>首先启动本地 SnarkOS 信标节点：</p><pre data-type="codeBlock" text="snarkos start --nodisplay --dev 0 --beacon &quot;APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH&quot;
"><code>snarkos start <span class="hljs-operator">-</span><span class="hljs-operator">-</span>nodisplay <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-number">0</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>beacon <span class="hljs-string">"APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH"</span>
</code></pre><blockquote><p>⚠️ 请不要更改私钥，因为应用程序在开发过程中是配置为使用此私钥的。</p></blockquote><p>然后，在另一个终端窗口中启动 Aleo 开发服务器：</p><pre data-type="codeBlock" text="aleo-develop start -p http://127.0.0.1:3030
"><code>aleo<span class="hljs-operator">-</span>develop start <span class="hljs-operator">-</span>p http:<span class="hljs-comment">//127.0.0.1:3030</span>
</code></pre><blockquote><p>⚠️ 请确保指定该本地地址。如果未指定地址，开发服务器将连接到公共测试网，而在开发过程中通常不希望这样做。</p></blockquote><p>接着，本地构建所有程序：</p><pre data-type="codeBlock" text="./build_local_programs.sh
"><code>./build_local_programs.sh
</code></pre><p>首次运行 API 时，请确保同时部署这些程序：</p><pre data-type="codeBlock" text="DEPLOY_PROGRAMS=true DEPLOY_PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH yarn start
"><code><span class="hljs-attr">DEPLOY_PROGRAMS</span>=<span class="hljs-literal">true</span> DEPLOY_PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH yarn start
</code></pre><p>注意查看应用程序和开发服务器的日志。</p><p>所有程序成功部署到网络后，API 应可在 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://localhost:5001">http://localhost:5001</a> 访问。</p><p>如果没有重置网络，以后本地运行 API 时，只需运行：</p><pre data-type="codeBlock" text="yarn start
"><code>yarn <span class="hljs-keyword">start</span>
</code></pre><p>如果你希望重置网络，可以先停止信标进程，然后运行：</p><pre data-type="codeBlock" text="snarkos clean --dev 0
"><code>snarkos clean <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-number">0</span>
</code></pre><blockquote><p>⚠️ 重置本地网络后，你将需要重新部署程序。</p></blockquote><h3 id="h-minikube" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">使用 Minikube 运行</h3><blockquote><p>⚠️ 除非你在进行部署或确实了解自己在做什么，否则强烈建议不要使用此方法。通过 Minikube 运行 API 时，应用程序将连接到公共测试网，这对于开发来说并不理想。</p></blockquote><p>在使用 Minikube 运行 API 之前，请确保已安装以下软件：</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.docker.com/engine/install/">Docker</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://kubernetes.io/docs/tasks/tools/#kubectl">kubectl</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://minikube.sigs.k8s.io/docs/start/">Minikube</a> - 仅执行“安装”部分的第一步</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://skaffold.dev/docs/install/">Skaffold</a></p></li></ul><p>在运行 Minikube 之前，确保 Docker 正在运行。如果你使用 MacOS，请确保给 Docker 分配至少 8GB 的内存和至少 50GB 的虚拟磁盘空间。可以通过打开 Docker Desktop -&gt; 设置（右上角）-&gt; 资源进行配置。</p><p>启动 Minikube：</p><pre data-type="codeBlock" text="minikube start --cpus=max --memory=max
"><code>minikube start <span class="hljs-operator">-</span><span class="hljs-operator">-</span>cpus<span class="hljs-operator">=</span>max <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">memory</span><span class="hljs-operator">=</span>max
</code></pre><p>启用 Ingress 插件：</p><pre data-type="codeBlock" text="minikube addons enable ingress
"><code>minikube addons <span class="hljs-built_in">enable</span> ingress
</code></pre><p>在新的终端标签中运行：</p><pre data-type="codeBlock" text="sudo minikube tunnel
"><code></code></pre><p>这将允许你在后台运行时访问部署的应用程序。</p><p>回到第一个终端标签并运行：</p><pre data-type="codeBlock" text="skaffold run
"><code>skaffold run
</code></pre><p>这将构建 API 并将其部署到 Minikube 集群中。</p><p>要检查 Pod 的状态，运行：</p><pre data-type="codeBlock" text="kubectl -n zk-gaming-tk-local get pods
"><code>kubectl <span class="hljs-operator">-</span>n zk<span class="hljs-operator">-</span>gaming<span class="hljs-operator">-</span>tk<span class="hljs-operator">-</span>local get pods
</code></pre><p>要查看日志，运行：</p><pre data-type="codeBlock" text="# pod_name 可从上一步命令的输出中获取
kubectl -n zk-gaming-tk-local logs &lt;pod_name&gt; -f
"><code># pod_name 可从上一步命令的输出中获取
kubectl <span class="hljs-operator">-</span>n zk<span class="hljs-operator">-</span>gaming<span class="hljs-operator">-</span>tk<span class="hljs-operator">-</span>local logs <span class="hljs-operator">&#x3C;</span>pod_name<span class="hljs-operator">></span> <span class="hljs-operator">-</span>f
</code></pre><p>如果 Pod 正常运行，API 应可在 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://zk-gaming-tk.localhost">http://zk-gaming-tk.localhost</a> 访问。</p><blockquote><p>⚠️ 在 MacOS 上，可能需要配置 <code>dnsmasq</code> 以访问自定义域名。可以参考 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.stevenrombauts.be/2018/01/use-dnsmasq-instead-of-etc-hosts/#2-only-send-test-and-box-queries-to-dnsmasq">此指南</a>，并使用 <code>.localhost</code> 替代 <code>.test</code> 和 <code>.box</code>。</p></blockquote><h2 id="h-pr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">提交 PR</h2><blockquote><p>⚠️ 这些步骤只能由有钱包访问权限的维护人员完成。</p></blockquote><p>如果 PR 包含对 Leo 程序的任何更改，请在合并之前确保执行以下操作，以便正确地将程序部署到测试网：</p><ol><li><p>前往 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://demo.leo.app/faucet">此处</a> 并给 Kryha Aleo 账户添加一些积分。</p></li><li><p>等待交易完成。请勿关闭浏览器标签页！</p></li><li><p>完成 PR，流水线应会自动将新程序部署到测试网上。请耐心等待……部署时间约为每个程序 8 分钟。</p></li></ol><h2 id="h-leo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">添加新 Leo 程序</h2><p>创建新 Leo 程序时，需要更新流水线，以便程序正确部署到测试网。</p><p>假设程序名称为 <code>cool_program</code>，要正确部署，打开 <code>azure-pipelines.yaml</code> 并在 <code>run_check_script</code> 作业中添加以下内容：</p><pre data-type="codeBlock" text="files=$(git diff HEAD HEAD~ --name-only)

while IFS= read -r name; do
    # 之前的 case 省略
    ...
    elif [[ $name =~ ^contracts/cool_program/* ]]; then
        echo &quot;##vso[task.setvariable variable=coolProgramUpdated;isoutput=true]True&quot;
    fi
done &lt;&lt;&lt;&quot;$files&quot;
"><code>files<span class="hljs-operator">=</span>$(git diff HEAD HEAD<span class="hljs-operator">~</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>name<span class="hljs-operator">-</span>only)

<span class="hljs-keyword">while</span> IFS<span class="hljs-operator">=</span> read <span class="hljs-operator">-</span>r name; do
    # 之前的 case 省略
    ...
    elif [[ $name <span class="hljs-operator">=</span><span class="hljs-operator">~</span> <span class="hljs-operator">^</span>contracts<span class="hljs-operator">/</span>cool_program<span class="hljs-comment">/* ]]; then
        echo "##vso[task.setvariable variable=coolProgramUpdated;isoutput=true]True"
    fi
done &#x3C;&#x3C;&#x3C;"$files"
</span></code></pre><p>接着，在 <code>build_and_deploy_leo_programs_stage</code> 中定义新变量：</p><pre data-type="codeBlock" text="variables:
    # 之前的变量省略
    ...
    coolProgramUpdated: $[stageDependencies.check_updated_programs.run_check_script.outputs[&apos;UpdatedPrograms.coolProgramUpdated&apos;]]
"><code>variables:
    # 之前的变量省略
    ...
    coolProgramUpdated: $[stageDependencies.check_updated_programs.run_check_script.outputs[<span class="hljs-string">'UpdatedPrograms.coolProgramUpdated'</span>]]
</code></pre><p>在 <code>build_and_deploy_leo_programs_job</code> 作业中，所有之前定义的步骤之后，添加以下新步骤：</p><pre data-type="codeBlock" text="- script: |
    docker build -f Dockerfile.program . \
      --build-arg APP_NAME=cool_program \
      --build-arg PRIVATE_KEY=$(privateKey) \
      --build-arg BUILD_ID=$(buildId) \
      --build-arg FEE=600000 \
      --build-arg ZK_GAMING_ALEO=&quot;eu.gcr.io/web3-335312/aleo/zk-gaming-snarkos:latest&quot;
  displayName: Cool Program Docker build
  condition: and(succeeded(), eq(variables[&apos;coolProgramUpdated&apos;], &apos;True&apos;))
  retryCountOnTaskFailure: 3
- script: echo &quot;##vso[task.setvariable variable=coolProgramVersion;isoutput=true]$(buildId)&quot;
  displayName: Update Cool Program version locally
  condition: and(succeeded(), eq(variables[&apos;coolProgramUpdated&apos;], &apos;True&apos;))
- script: |
    az pipelines variable-group variable update \
      --group-id $(aleoProgramIdsGroupId) \
      --name coolProgramVersion \
      --org $(devOpsOrg) \
      --project $(devOpsProject) \
      --value $(buildId)
  displayName: Update Cool Program version in variable group
  condition: and(succeeded(), eq(variables[&apos;coolProgramUpdated&apos;], &apos;True&apos;))
  env:
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)
"><code><span class="hljs-operator">-</span> script: <span class="hljs-operator">|</span>
    docker build <span class="hljs-operator">-</span>f Dockerfile.program . \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>build<span class="hljs-operator">-</span>arg APP_NAME<span class="hljs-operator">=</span>cool_program \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>build<span class="hljs-operator">-</span>arg PRIVATE_KEY<span class="hljs-operator">=</span>$(privateKey) \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>build<span class="hljs-operator">-</span>arg BUILD_ID<span class="hljs-operator">=</span>$(buildId) \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>build<span class="hljs-operator">-</span>arg FEE<span class="hljs-operator">=</span><span class="hljs-number">600000</span> \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>build<span class="hljs-operator">-</span>arg ZK_GAMING_ALEO<span class="hljs-operator">=</span><span class="hljs-string">"eu.gcr.io/web3-335312/aleo/zk-gaming-snarkos:latest"</span>
  displayName: Cool Program Docker build
  condition: and(succeeded(), eq(variables[<span class="hljs-string">'coolProgramUpdated'</span>], <span class="hljs-string">'True'</span>))
  retryCountOnTaskFailure: <span class="hljs-number">3</span>
<span class="hljs-operator">-</span> script: echo <span class="hljs-string">"##vso[task.setvariable variable=coolProgramVersion;isoutput=true]$(buildId)"</span>
  displayName: Update Cool Program version locally
  condition: and(succeeded(), eq(variables[<span class="hljs-string">'coolProgramUpdated'</span>], <span class="hljs-string">'True'</span>))
<span class="hljs-operator">-</span> script: <span class="hljs-operator">|</span>
    az pipelines variable<span class="hljs-operator">-</span>group variable update \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>group<span class="hljs-operator">-</span>id $(aleoProgramIdsGroupId) \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>name coolProgramVersion \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>org $(devOpsOrg) \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>project $(devOpsProject) \
      <span class="hljs-operator">-</span><span class="hljs-operator">-</span>value $(buildId)
  displayName: Update Cool Program version in variable group
  condition: and(succeeded(), eq(variables[<span class="hljs-string">'coolProgramUpdated'</span>], <span class="hljs-string">'True'</span>))
  env:
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)
</code></pre><p>变量版本需要添加到流水线变量组。为此，请联系 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="mailto:marius@kryha.io">marius@kryha.io</a>。</p><h2 id="h-leo-snarkos" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">更新 Leo 和 SnarkOS 版本</h2><p>由于 Leo 和 SnarkOS 目前处于活跃开发中，有些更改可能会破坏构建，因此我们在 <code>Dockerfile.snarkos</code> 中手动设置了与工具包正确配合使用的最新版本的提交哈希。如果你希望更新到新版本，应执行以下步骤：</p><ol><li><p><code>git pull</code> 最新的 Leo 或 SnarkOS 代码，并运行 <code>cargo install --path .</code> 在本地安装新版本。</p></li><li><p>确保程序使用更新后的 CLI 工具正确构建和运行。</p></li><li><p>使用 <code>yarn start</code> 在本地运行工具包，并确保端点按预期工作。</p></li><li><p>在 Leo 或 SnarkOS 仓库中运行 <code>git log</code> 并复制 <code>HEAD</code> 提交哈希。</p></li><li><p>打开 <code>Dockerfile.snarkos</code> 并将提交哈希设置为复制的值。</p></li><li><p>通过 <code>skaffold run</code> 运行工具包，并确保其正常工作。</p></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">总结</h2><p>通过这篇教程，我们已经了解了如何在本地和 Minikube 环境中运行 ZK Gaming Toolkit，如何设置开发环境，以及如何添加和部署新的 Leo 程序。ZK Gaming Toolkit 为开发者提供了强大的工具，使得在 Aleo 区块链上构建去中心化应用和游戏变得更加简便和高效。</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[AleoJS 的简单使用教程]]></title>
            <link>https://paragraph.com/@yaakov/aleojs</link>
            <guid>fazVM5nSETRXcwcyvVCH</guid>
            <pubDate>Fri, 16 Aug 2024 07:50:16 GMT</pubDate>
            <description><![CDATA[AleoJS 的简单使用指南简介AleoJS 是一个为 Aleo 区块链开发的轻量级库，旨在简化开发者与 Aleo 生态系统的交互。它通过提供一系列工具和接口，让开发者可以更方便地在 Aleo 区块链上构建、测试和部署去中心化应用（dApps）。AleoJS 借鉴了 zk-gaming-toolkit 的灵感，同时为开发者提供了更加友好的编程体验。 主要特点包括：简化开发流程：通过提供命令行工具和自动化的项目结构，开发者可以快速启动和管理 Aleo 项目。支持多种网络：AleoJS 支持测试网和主网等多种网络，方便开发者在不同环境中测试和部署应用。自动生成类型：在编译过程中，AleoJS 会自动生成 Leo 和 JavaScript 类型，简化了智能合约与前端应用之间的数据交互。强大的测试支持：AleoJS 提供了丰富的测试框架，帮助开发者验证智能合约的正确性和稳定性。安装在开始之前，请确保您已经设置了以下环境：Rust：安装指南SnarkOS：安装指南Leo语言：安装指南通过 NPM 安装您可以通过 npm 全局安装 Aleo.js：npm install -g @aleojs...]]></description>
            <content:encoded><![CDATA[<h1 id="h-aleojs" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">AleoJS 的简单使用指南</h1><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">简介</h2><p>AleoJS 是一个为 Aleo 区块链开发的轻量级库，旨在简化开发者与 Aleo 生态系统的交互。它通过提供一系列工具和接口，让开发者可以更方便地在 Aleo 区块链上构建、测试和部署去中心化应用（dApps）。AleoJS 借鉴了 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/kryha/zk-gaming-toolkit">zk-gaming-toolkit</a> 的灵感，同时为开发者提供了更加友好的编程体验。</p><p>主要特点包括：</p><ol><li><p><strong>简化开发流程</strong>：通过提供命令行工具和自动化的项目结构，开发者可以快速启动和管理 Aleo 项目。</p></li><li><p><strong>支持多种网络</strong>：AleoJS 支持测试网和主网等多种网络，方便开发者在不同环境中测试和部署应用。</p></li><li><p><strong>自动生成类型</strong>：在编译过程中，AleoJS 会自动生成 Leo 和 JavaScript 类型，简化了智能合约与前端应用之间的数据交互。</p></li><li><p><strong>强大的测试支持</strong>：AleoJS 提供了丰富的测试框架，帮助开发者验证智能合约的正确性和稳定性。</p></li></ol><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">安装</h2><p>在开始之前，请确保您已经设置了以下环境：</p><ol><li><p><strong>Rust</strong>：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.rust-lang.org/tools/install">安装指南</a></p></li><li><p><strong>SnarkOS</strong>：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/aleoHQ/snarkos">安装指南</a></p></li><li><p><strong>Leo语言</strong>：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/aleoHQ/leo">安装指南</a></p></li></ol><h3 id="h-npm" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">通过 NPM 安装</h3><p>您可以通过 npm 全局安装 Aleo.js：</p><pre data-type="codeBlock" text="npm install -g @aleojs/cli@latest
"><code>npm install -g <span class="hljs-keyword">@aleojs</span>/cli<span class="hljs-keyword">@latest</span>
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">从源码安装</h3><blockquote><p>如果尚未设置 pnpm，请参考 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pnpm.io/installation">pnpm 安装指南</a>。</p></blockquote><pre data-type="codeBlock" text="# 下载源码
git clone https://github.com/venture23-zkp/aleojs

cd aleojs

# 安装依赖项
pnpm install

# 构建项目
npm run build

# 安装 aleojs
npm run install:cli
"><code><span class="hljs-comment"># 下载源码</span>
git <span class="hljs-built_in">clone</span> https://github.com/venture23-zkp/aleojs

<span class="hljs-built_in">cd</span> aleojs

<span class="hljs-comment"># 安装依赖项</span>
pnpm install

<span class="hljs-comment"># 构建项目</span>
npm run build

<span class="hljs-comment"># 安装 aleojs</span>
npm run install:cli
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">使用方法</h2><p>安装完成后，您可以通过以下命令使用 AleoJS：</p><pre data-type="codeBlock" text="aleojs-cli-dev
"><code>aleojs<span class="hljs-operator">-</span>cli<span class="hljs-operator">-</span>dev
</code></pre><p>安装成功的输出如下：</p><pre data-type="codeBlock" text="_    _                _ ____
/ \  | | ___  ___     | / ___|
/ _ \ | |/ _ \/ _ \ _  | \___ \
/ ___ \| |  __/ (_) | |_| |___) |
/_/   \_\_|\___|\___/ \___/|____/
Usage: aleojs-cli-dev [options] [command]

AleoJS CLI

Options:
  -h, --help                       显示帮助信息
  -V, --version                    输出版本号

Commands:
  init [options] &lt;project-name&gt;    初始化您的 AleoJS 项目
  add &lt;program-name&gt;               添加新组件或资源
  compile                          编译您的 AleoJS 项目
  unflatten                        为程序生成leo构建文件
  autogen                          为合约生成ts类型（仅在生成构建后使用）
  start [options] &lt;node&gt;           运行您的 AleoJS 项目
  run [options] &lt;file&gt;             运行文件
  deploy [options] &lt;program-name&gt;  部署程序
  execute &lt;file-path&gt;              执行脚本
  help [command]                   显示帮助信息
"><code><span class="hljs-keyword">_</span>    <span class="hljs-keyword">_</span>                <span class="hljs-keyword">_</span> ____
<span class="hljs-operator">/</span> \  <span class="hljs-operator">|</span> <span class="hljs-operator">|</span> ___  ___     <span class="hljs-operator">|</span> <span class="hljs-operator">/</span> ___<span class="hljs-operator">|</span>
<span class="hljs-operator">/</span> <span class="hljs-keyword">_</span> \ <span class="hljs-operator">|</span> <span class="hljs-operator">|</span><span class="hljs-operator">/</span> <span class="hljs-keyword">_</span> \<span class="hljs-operator">/</span> <span class="hljs-keyword">_</span> \ <span class="hljs-keyword">_</span>  <span class="hljs-operator">|</span> \___ \
<span class="hljs-operator">/</span> ___ \<span class="hljs-operator">|</span> <span class="hljs-operator">|</span>  __<span class="hljs-operator">/</span> (<span class="hljs-keyword">_</span>) <span class="hljs-operator">|</span> <span class="hljs-operator">|</span><span class="hljs-keyword">_</span><span class="hljs-operator">|</span> <span class="hljs-operator">|</span>___) <span class="hljs-operator">|</span>
<span class="hljs-operator">/</span><span class="hljs-keyword">_</span><span class="hljs-operator">/</span>   \<span class="hljs-keyword">_</span>\<span class="hljs-keyword">_</span><span class="hljs-operator">|</span>\___<span class="hljs-operator">|</span>\___<span class="hljs-operator">/</span> \___<span class="hljs-operator">/</span><span class="hljs-operator">|</span>____<span class="hljs-operator">/</span>
Usage: aleojs<span class="hljs-operator">-</span>cli<span class="hljs-operator">-</span>dev [options] [command]

AleoJS CLI

Options:
  <span class="hljs-operator">-</span>h, <span class="hljs-operator">-</span><span class="hljs-operator">-</span>help                       显示帮助信息
  <span class="hljs-operator">-</span>V, <span class="hljs-operator">-</span><span class="hljs-operator">-</span>version                    输出版本号

Commands:
  init [options] <span class="hljs-operator">&#x3C;</span>project<span class="hljs-operator">-</span>name<span class="hljs-operator">></span>    初始化您的 AleoJS 项目
  add <span class="hljs-operator">&#x3C;</span>program<span class="hljs-operator">-</span>name<span class="hljs-operator">></span>               添加新组件或资源
  compile                          编译您的 AleoJS 项目
  unflatten                        为程序生成leo构建文件
  autogen                          为合约生成ts类型（仅在生成构建后使用）
  start [options] <span class="hljs-operator">&#x3C;</span>node<span class="hljs-operator">></span>           运行您的 AleoJS 项目
  run [options] <span class="hljs-operator">&#x3C;</span>file<span class="hljs-operator">></span>             运行文件
  deploy [options] <span class="hljs-operator">&#x3C;</span>program<span class="hljs-operator">-</span>name<span class="hljs-operator">></span>  部署程序
  execute <span class="hljs-operator">&#x3C;</span>file<span class="hljs-operator">-</span>path<span class="hljs-operator">></span>              执行脚本
  help [command]                   显示帮助信息
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">初始化新项目</h3><p>通过指定项目名称来初始化一个新项目：</p><pre data-type="codeBlock" text="aleojs-cli-dev init &lt;PROJECT_NAME&gt;
"><code>aleojs<span class="hljs-operator">-</span>cli<span class="hljs-operator">-</span>dev init <span class="hljs-operator">&#x3C;</span>PROJECT_NAME<span class="hljs-operator">></span>
</code></pre><p>例如，我们可以创建一个名为 <code>token</code> 的新项目。</p><blockquote><p>这将自动为项目安装依赖项。</p></blockquote><p>在项目初始化完成后，AleoJS 将生成以下目录结构：</p><pre data-type="codeBlock" text="├── contract
│   └── base-contract.ts
├── node_modules/
├── programs
│   ├── sample_program.leo
│   └── token.leo
├── scripts
│   └── deploy.ts
├── test
│   ├── sample_program.test.ts
│   └── token.test.ts
├── .env
├── .gitignore
├── aleo-config.js
├── babel.config.json
├── jest.config.json
├── package-lock.json
├── package.json
├── README.md
├── node_modules/
└── tsconfig.json
"><code>├── contract
│   └── base-contract.ts
├── node_modules/
├── programs
│   ├── sample_program.leo
│   └── token.leo
├── scripts
│   └── deploy.ts
├── test
│   ├── sample_program.test.ts
│   └── token.test.ts
├── .env
├── .gitignore
├── aleo-<span class="hljs-built_in">config</span>.js
├── babel.<span class="hljs-built_in">config</span>.json
├── jest.<span class="hljs-built_in">config</span>.json
├── <span class="hljs-built_in">package</span>-lock.json
├── <span class="hljs-built_in">package</span>.json
├── README.md
├── node_modules/
└── tsconfig.json
</code></pre><p>在初始化项目后，会生成以下几个重要目录：</p><ul><li><p><strong>contract</strong>：包含一个名为 <code>base-contract.ts</code> 的文件，这是一个包含常用方法和Aleo程序在JavaScript中的配置的类。</p></li><li><p><strong>programs</strong>：用于存放所有 Leo 程序的目录。初始化时会自动生成 <code>token.leo</code> 和 <code>sample_program.leo</code> 文件。</p></li><li><p><strong>scripts</strong>：用于存放特定任务和用户脚本的目录。</p></li><li><p><strong>test</strong>：用于存放所有测试文件的目录。</p></li><li><p><code>aleo-config.js</code>：配置文件，包含私钥、执行链上或模拟运行的模式以及不同网络的配置。</p></li></ul><h3 id="h-aleo-configjs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>aleo-config.js</code> 配置文件详解</h3><pre data-type="codeBlock" text="import dotenv from &apos;dotenv&apos;;
dotenv.config();

export default {
  accounts: [process.env.ALEO_PRIVATE_KEY],
  mode: &apos;execute&apos;,
  mainnet: {},
  networks: {
    testnet3: {
      endpoint: &apos;http://localhost:3030&apos;,
      accounts: [process.env.ALEO_PRIVATE_KEY_TESTNET3, 
                 process.env.ALEO_DEVNET_PRIVATE_KEY2],
      priorityFee: 0.01
    },
    mainnet: {
      endpoint: &apos;https://api.explorer.aleo.org/v1&apos;,
      accounts: [process.env.ALEO_PRIVATE_KEY_MAINNET],
      priorityFee: 0.001
    }
  },
  defaultNetwork: &apos;testnet3&apos;
};
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">dotenv</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'dotenv'</span>;
dotenv.config();

export default {
  accounts: [process.env.ALEO_PRIVATE_KEY],
  mode: <span class="hljs-string">'execute'</span>,
  mainnet: {},
  networks: {
    testnet3: {
      endpoint: <span class="hljs-string">'http://localhost:3030'</span>,
      accounts: [process.env.ALEO_PRIVATE_KEY_TESTNET3, 
                 process.env.ALEO_DEVNET_PRIVATE_KEY2],
      priorityFee: <span class="hljs-number">0</span><span class="hljs-number">.01</span>
    },
    mainnet: {
      endpoint: <span class="hljs-string">'https://api.explorer.aleo.org/v1'</span>,
      accounts: [process.env.ALEO_PRIVATE_KEY_MAINNET],
      priorityFee: <span class="hljs-number">0</span><span class="hljs-number">.001</span>
    }
  },
  defaultNetwork: <span class="hljs-string">'testnet3'</span>
};
</code></pre><p>该配置文件支持两种执行模式：</p><ol><li><p><code>execute</code> 模式：在该模式下，会生成并在链上广播证明。内部调用 <code>snarkos developer execute</code> 命令。</p></li><li><p><code>evaluate</code> 模式：在该模式下，不会生成和广播证明。内部调用 <code>leo run</code> 命令。</p></li></ol><blockquote><p><code>aleo-config</code> 作为整个项目的默认配置，也可以根据每个程序进行覆盖。</p></blockquote><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">添加或修改程序</h3><p>要添加一个新程序，可以在 <code>programs/</code> 目录中创建一个新文件。要修改现有文件，可以直接修改文件或运行以下命令：</p><pre data-type="codeBlock" text="aleojs-cli-dev add [PROGRAM_NAME]
"><code>aleojs<span class="hljs-operator">-</span>cli<span class="hljs-operator">-</span>dev add [PROGRAM_NAME]
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">编译项目</h3><p>要编译项目，运行以下命令：</p><pre data-type="codeBlock" text="aleojs-cli-dev compile
"><code>aleojs<span class="hljs-operator">-</span>cli<span class="hljs-operator">-</span>dev compile
</code></pre><p>这将创建 <code>artifacts</code> 文件夹，其中包含两个主要目录：</p><ul><li><p><strong>leo</strong>：包含所有的 Leo 包。对于 <code>programs</code> 目录中的每个程序，将生成相应的 Leo 包。程序代码会被复制到 <code>src/main.leo</code> 文件中，并进行编译。如果所有程序都编译成功，则生成的 <code>.aleo</code> 文件会被解析为 Leo 和 JS 类型文件，存放在 js 目录中。</p></li><li><p><strong>js</strong>：包含 Leo 类型文件、JS 类型文件、<code>js2leo</code>（Leo 类型到 JS 类型的转换）、<code>leo2js</code>（JS 类型到 Leo 类型的转换）。对于每个程序，还会创建 <code>&lt;PROGRAM-NAME&gt;.ts</code> 文件，包含程序的所有转换和映射。</p></li></ul><p>目录结构如下：</p><pre data-type="codeBlock" text="├── js
│   ├── js2leo
│   │   ├── index.ts
│   │   └── token.ts
│   ├── leo2js
│   │   ├── index.ts
│   │   └── token.ts
│   └── types
│       ├── index.ts
│       └── token.ts
│   ├── sample_program.ts
│   ├── token.ts
└── leo
    ├── sample_program
    │   ├── README.md
    │   ├── build
    │   ├── inputs
    │   ├── leo.lock
    │   ├── outputs
    │   ├── program.json
    │   └── src
    └── token
        ├── README.md
        ├── build
        ├── inputs
        ├── leo.lock
        ├── outputs
        ├── program.json
        └── src
"><code>├── js
│   ├── js2leo
│   │   ├── index.ts
│   │   └── token.ts
│   ├── leo2js
│   │   ├── index.ts
│   │   └── token.ts
│   └── types
│       ├── index.ts
│       └── token.ts
│   ├── sample_program.ts
│   ├── token.ts
└── leo
    ├── sample_program
    │   ├── README.md
    │   ├── build
    │   ├── inputs
    │   ├── leo.lock
    │   ├── outputs
    │   ├── program.json
    │   └── src
    └── token
        ├── README.md
        ├── build
        ├── inputs
        ├── leo.lock
        ├── outputs
        ├── program.json
        └── src
</code></pre><blockquote><p>注意：由于 <code>sample_program</code> 没有类型文件，因此不需要生成 <code>js2leo</code>、<code>leo2js</code> 或 <code>type</code> 文件。</p></blockquote><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">运行测试</h3><p>在编译成功后，您可以基于生成的文件编写测试用例。</p><p>一个用于 <code>sample_program</code> 和 <code>token</code> 程序的示例测试文件已创建。运行所有测试的命令如下：</p><pre data-type="codeBlock" text="npm run test
"><code>npm run test
</code></pre><p>如果您只想测试某个特定的文件，可以使用以下命令：</p><pre data-type="codeBlock" text="npm run test -- sample_program.test.ts
"><code>npm run test <span class="hljs-operator">-</span><span class="hljs-operator">-</span> sample_program.test.ts
</code></pre><blockquote><p>小提示：您不需要输入完整的测试文件名称。您可以使用文件名的一部分，系统将自动运行与输入名称匹配的测试。 例如：<code>npm run test -- sample</code></p></blockquote><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">高级测试</h2><p>在 <code>test</code> 目录下创建一个测试文件（文件名例如 <code>token.test.ts</code>），以下是一个示例测试文件：</p><pre data-type="codeBlock" text="import { parseRecordString } from &apos;@aleojs/core&apos;;
import { PrivateKey } from &apos;@aleohq/sdk&apos;;

import { TokenContract } from &apos;../artifacts/js/token&apos;;
import { token, tokenLeo } from &apos;../artifacts/js/types/token&apos;;
import { gettoken } from &apos;../artifacts/js/leo2js/token&apos;;

const TIMEOUT = 200_000;
const amount = BigInt(2);

// 初始化合约类
const mode = &apos;execute&apos;;
const contract = new TokenContract({ mode });

// 该方法会映射 `aleo-config.js` 中定义的网络，并返回相应私钥地址的数组
const [admin, user] = contract.getAccounts();

// 此方法返回与指定 Aleo 地址关联的私钥
const adminPrivateKey = contract.getPrivateKey(admin);

// 自定义函数，用于解析 token 记录数据
function parseRecordtoToken(
  recordString: string,
  mode?: &apos;execute&apos; | &apos;evaluate&apos;,
  privateKey?: string
): token {
  // 如果是 `execute` 模式下记录是加密的，因此我们需要解密它们
  if (mode &amp;&amp; mode === &apos;execute&apos;) {
    if (!privateKey)
      throw new Error(&apos;需要私钥来进行解密&apos;);
    const record = gettoken(
      parseRecordString(
        PrivateKey.from_string(privateKey).to_view_key().decrypt(recordString)
      ) as tokenLeo
    );
    return record;
  }
  const record = gettoken(
    parseRecordString(JSON.stringify(recordString)) as tokenLeo
  );
  return record;
}

// 在测试开始之前执行
beforeAll(async () =&gt; {
  // 在 `execute` 模式下运行测试之前需要先部署合约
  if (contract.config.mode === &apos;execute&apos;) {
    // 该方法检查链上是否已经部署了程序
    const deployed = await contract.isDeployed();

    // 如果合约已经部署，则跳过部署步骤
    if (deployed) return;

    const tx = await contract.deploy();
    await contract.wait(tx);
  }
}, TIMEOUT);

test(
  &apos;铸造私人 token&apos;,
  async () =&gt; {
    const [result, tx] = await contract.mint_private(admin, amount);

    // 在 `evaluate` 模式下，tx 是 undefined，因此不需要等待它
    if (tx) await contract.wait(tx);

    const senderRecord: token = parseRecordtoToken(
      result,
      mode,
      adminPrivateKey
    );
    expect(senderRecord.owner).toBe(admin);
    expect(senderRecord.amount.toString()).toBe(amount.toString());
  },
  TIMEOUT
);

test(
  &apos;转移私人 token&apos;,
  async () =&gt; {
    const [token, tx] = await contract.mint_private(admin, amount);
    if (tx) await contract.wait(tx);
    const record: token = parseRecordtoToken(token, mode, adminPrivateKey);

    // `transfer_private` 返回两个记录，因此 result1 和 result2 保存这些记录，tx1 保存交易执行数据
    const [result1, result2, tx1] = await contract.transfer_private(
      record,
      user,
      amount
    );

    if (tx1) await contract.wait(tx1);

    const privateKey = contract.getPrivateKey(user);
    const record1 = parseRecordtoToken(result1, mode, adminPrivateKey);
    const record2 = parseRecordtoToken(result2, mode, privateKey);

    expect(record1.amount).toBe(BigInt(0));
    expect(record2.amount).toBe(amount);
  },
  TIMEOUT
);
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">parseRecordString</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@aleojs/core'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">PrivateKey</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@aleohq/sdk'</span>;

<span class="hljs-keyword">import</span> { <span class="hljs-title">TokenContract</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../artifacts/js/token'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">token</span>, <span class="hljs-title">tokenLeo</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../artifacts/js/types/token'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">gettoken</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'../artifacts/js/leo2js/token'</span>;

const TIMEOUT <span class="hljs-operator">=</span> <span class="hljs-number">200_000</span>;
const amount <span class="hljs-operator">=</span> BigInt(<span class="hljs-number">2</span>);

<span class="hljs-comment">// 初始化合约类</span>
const mode <span class="hljs-operator">=</span> <span class="hljs-string">'execute'</span>;
const <span class="hljs-class"><span class="hljs-keyword">contract</span> = <span class="hljs-title"><span class="hljs-keyword">new</span></span> <span class="hljs-title">TokenContract</span>(<span class="hljs-params">{ mode }</span>);

<span class="hljs-comment">// 该方法会映射 `aleo-config.js` 中定义的网络，并返回相应私钥地址的数组</span>
<span class="hljs-title">const</span> [<span class="hljs-title">admin</span>, <span class="hljs-title">user</span>] = <span class="hljs-title"><span class="hljs-keyword">contract</span></span>.<span class="hljs-title">getAccounts</span>(<span class="hljs-params"></span>);

<span class="hljs-comment">// 此方法返回与指定 Aleo 地址关联的私钥</span>
<span class="hljs-title">const</span> <span class="hljs-title">adminPrivateKey</span> = <span class="hljs-title"><span class="hljs-keyword">contract</span></span>.<span class="hljs-title">getPrivateKey</span>(<span class="hljs-params">admin</span>);

<span class="hljs-comment">// 自定义函数，用于解析 token 记录数据</span>
<span class="hljs-title"><span class="hljs-keyword">function</span></span> <span class="hljs-title">parseRecordtoToken</span>(<span class="hljs-params">
  recordString: <span class="hljs-keyword">string</span>,
  mode?: <span class="hljs-string">'execute'</span> | <span class="hljs-string">'evaluate'</span>,
  privateKey?: <span class="hljs-keyword">string</span>
</span>): <span class="hljs-title">token</span> </span>{
  <span class="hljs-comment">// 如果是 `execute` 模式下记录是加密的，因此我们需要解密它们</span>
  <span class="hljs-keyword">if</span> (mode <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> mode <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'execute'</span>) {
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>privateKey)
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'需要私钥来进行解密'</span>);
    const record <span class="hljs-operator">=</span> gettoken(
      parseRecordString(
        PrivateKey.from_string(privateKey).to_view_key().decrypt(recordString)
      ) <span class="hljs-keyword">as</span> tokenLeo
    );
    <span class="hljs-keyword">return</span> record;
  }
  const record <span class="hljs-operator">=</span> gettoken(
    parseRecordString(JSON.stringify(recordString)) <span class="hljs-keyword">as</span> tokenLeo
  );
  <span class="hljs-keyword">return</span> record;
}

<span class="hljs-comment">// 在测试开始之前执行</span>
beforeAll(async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  <span class="hljs-comment">// 在 `execute` 模式下运行测试之前需要先部署合约</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">contract</span>.config.mode <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'execute'</span>) {
    <span class="hljs-comment">// 该方法检查链上是否已经部署了程序</span>
    const deployed <span class="hljs-operator">=</span> await <span class="hljs-keyword">contract</span>.isDeployed();

    <span class="hljs-comment">// 如果合约已经部署，则跳过部署步骤</span>
    <span class="hljs-keyword">if</span> (deployed) <span class="hljs-keyword">return</span>;

    const <span class="hljs-built_in">tx</span> <span class="hljs-operator">=</span> await <span class="hljs-keyword">contract</span>.deploy();
    await <span class="hljs-keyword">contract</span>.wait(<span class="hljs-built_in">tx</span>);
  }
}, TIMEOUT);

test(
  <span class="hljs-string">'铸造私人 token'</span>,
  async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    const [result, <span class="hljs-built_in">tx</span>] <span class="hljs-operator">=</span> await <span class="hljs-keyword">contract</span>.mint_private(admin, amount);

    <span class="hljs-comment">// 在 `evaluate` 模式下，tx 是 undefined，因此不需要等待它</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">tx</span>) await <span class="hljs-keyword">contract</span>.wait(<span class="hljs-built_in">tx</span>);

    const senderRecord: token <span class="hljs-operator">=</span> parseRecordtoToken(
      result,
      mode,
      adminPrivateKey
    );
    expect(senderRecord.owner).toBe(admin);
    expect(senderRecord.amount.toString()).toBe(amount.toString());
  },
  TIMEOUT
);

test(
  <span class="hljs-string">'转移私人 token'</span>,
  async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    const [token, <span class="hljs-built_in">tx</span>] <span class="hljs-operator">=</span> await <span class="hljs-keyword">contract</span>.mint_private(admin, amount);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">tx</span>) await <span class="hljs-keyword">contract</span>.wait(<span class="hljs-built_in">tx</span>);
    const record: token <span class="hljs-operator">=</span> parseRecordtoToken(token, mode, adminPrivateKey);

    <span class="hljs-comment">// `transfer_private` 返回两个记录，因此 result1 和 result2 保存这些记录，tx1 保存交易执行数据</span>
    const [result1, result2, tx1] <span class="hljs-operator">=</span> await <span class="hljs-keyword">contract</span>.transfer_private(
      record,
      user,
      amount
    );

    <span class="hljs-keyword">if</span> (tx1) await <span class="hljs-keyword">contract</span>.wait(tx1);

    const privateKey <span class="hljs-operator">=</span> <span class="hljs-keyword">contract</span>.getPrivateKey(user);
    const record1 <span class="hljs-operator">=</span> parseRecordtoToken(result1, mode, adminPrivateKey);
    const record2 <span class="hljs-operator">=</span> parseRecordtoToken(result2, mode, privateKey);

    expect(record1.amount).toBe(BigInt(<span class="hljs-number">0</span>));
    expect(record2.amount).toBe(amount);
  },
  TIMEOUT
);
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">执行测试文件</h3><p>要执行测试文件，可以使用以下命令：</p><pre data-type="codeBlock" text="npm test -- --runInBand token.test.ts
"><code>npm test <span class="hljs-operator">-</span><span class="hljs-operator">-</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>runInBand token.test.ts
</code></pre><p>这将会运行 <code>token.test.ts</code> 文件中的所有测试用例，确保您的智能合约逻辑在实际操作中正常工作。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">总结</h2><p>本教程提供了关于Aleo.js的安装、项目启动、程序添加、编译、测试和部署的完整示例。希望通过这个教程能帮助你顺利地在Aleo区块链上进行开发。</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo Apps 钱包适配器的简单使用介绍]]></title>
            <link>https://paragraph.com/@yaakov/aleo-apps</link>
            <guid>OFEc7FzDtLoRkf9ptEJr</guid>
            <pubDate>Fri, 16 Aug 2024 07:20:50 GMT</pubDate>
            <description><![CDATA[Aleo Apps 钱包适配器的简单使用介绍Demox Labs 提供了一套模块化的 TypeScript 钱包适配器和组件，专为 Aleo 应用程序设计。这篇文章将为您介绍如何将 Wallet Adapter 集成到基于 React 的Aleo应用中，并提供详细的代码示例，帮助您快速上手。快速设置（使用React UI）1. 📲 安装依赖首先，安装以下必要的依赖项：npm install --save \ @demox-labs/aleo-wallet-adapter-base \ @demox-labs/aleo-wallet-adapter-react \ @demox-labs/aleo-wallet-adapter-reactui \ @demox-labs/aleo-wallet-adapter-leo \ react 2. 🛠️ 集成设置在React应用中，使用以下代码来集成Wallet Adapter：import React, { FC, useMemo } from "react"; import { WalletProvider } from "@dem...]]></description>
            <content:encoded><![CDATA[<h1 id="h-aleo-apps" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Aleo Apps 钱包适配器的简单使用介绍</h1><p>Demox Labs 提供了一套模块化的 TypeScript 钱包适配器和组件，专为 Aleo 应用程序设计。这篇文章将为您介绍如何将 Wallet Adapter 集成到基于 React 的Aleo应用中，并提供详细的代码示例，帮助您快速上手。</p><h2 id="h-react-ui" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">快速设置（使用React UI）</h2><h3 id="h-1" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. 📲 安装依赖</h3><p>首先，安装以下必要的依赖项：</p><pre data-type="codeBlock" text="npm install --save \
    @demox-labs/aleo-wallet-adapter-base \
    @demox-labs/aleo-wallet-adapter-react \
    @demox-labs/aleo-wallet-adapter-reactui \
    @demox-labs/aleo-wallet-adapter-leo \
    react
"><code>npm install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>save \
    @demox<span class="hljs-operator">-</span>labs<span class="hljs-operator">/</span>aleo<span class="hljs-operator">-</span>wallet<span class="hljs-operator">-</span>adapter<span class="hljs-operator">-</span>base \
    @demox<span class="hljs-operator">-</span>labs<span class="hljs-operator">/</span>aleo<span class="hljs-operator">-</span>wallet<span class="hljs-operator">-</span>adapter<span class="hljs-operator">-</span>react \
    @demox<span class="hljs-operator">-</span>labs<span class="hljs-operator">/</span>aleo<span class="hljs-operator">-</span>wallet<span class="hljs-operator">-</span>adapter<span class="hljs-operator">-</span>reactui \
    @demox<span class="hljs-operator">-</span>labs<span class="hljs-operator">/</span>aleo<span class="hljs-operator">-</span>wallet<span class="hljs-operator">-</span>adapter<span class="hljs-operator">-</span>leo \
    react
</code></pre><h3 id="h-2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 🛠️ 集成设置</h3><p>在React应用中，使用以下代码来集成Wallet Adapter：</p><pre data-type="codeBlock" text="import React, { FC, useMemo } from &quot;react&quot;;
import { WalletProvider } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import { WalletModalProvider } from &quot;@demox-labs/aleo-wallet-adapter-reactui&quot;;
import { LeoWalletAdapter } from &quot;@demox-labs/aleo-wallet-adapter-leo&quot;;
import { DecryptPermission, WalletAdapterNetwork } from &quot;@demox-labs/aleo-wallet-adapter-base&quot;;

// 导入默认样式，可以根据需求覆盖
require(&quot;@demox-labs/aleo-wallet-adapter-reactui/styles.css&quot;);

export const Wallet: FC = () =&gt; {
  const wallets = useMemo(
    () =&gt; [new LeoWalletAdapter({ appName: &quot;Leo Demo App&quot; })],
    []
  );

  return (
    &lt;WalletProvider
      wallets={wallets}
      decryptPermission={DecryptPermission.UponRequest}
      network={WalletAdapterNetwork.Localnet}
      autoConnect
    &gt;
      &lt;WalletModalProvider&gt;
        {/* 你的应用组件在这里 */}
      &lt;/WalletModalProvider&gt;
    &lt;/WalletProvider&gt;
  );
};
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useMemo</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">WalletProvider</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">WalletModalProvider</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-reactui"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">LeoWalletAdapter</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-leo"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">DecryptPermission</span>, <span class="hljs-title">WalletAdapterNetwork</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-base"</span>;

<span class="hljs-comment">// 导入默认样式，可以根据需求覆盖</span>
<span class="hljs-built_in">require</span>(<span class="hljs-string">"@demox-labs/aleo-wallet-adapter-reactui/styles.css"</span>);

export const Wallet: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const wallets <span class="hljs-operator">=</span> useMemo(
    () <span class="hljs-operator">=</span><span class="hljs-operator">></span> [<span class="hljs-keyword">new</span> LeoWalletAdapter({ appName: <span class="hljs-string">"Leo Demo App"</span> })],
    []
  );

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>WalletProvider
      wallets<span class="hljs-operator">=</span>{wallets}
      decryptPermission<span class="hljs-operator">=</span>{DecryptPermission.UponRequest}
      network<span class="hljs-operator">=</span>{WalletAdapterNetwork.Localnet}
      autoConnect
    <span class="hljs-operator">></span>
      <span class="hljs-operator">&#x3C;</span>WalletModalProvider<span class="hljs-operator">></span>
        {<span class="hljs-comment">/* 你的应用组件在这里 */</span>}
      <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>WalletModalProvider<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>WalletProvider<span class="hljs-operator">></span>
  );
};
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">功能实现示例</h2><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">✍🏻 实现消息签名功能</h3><p>使用以下代码片段可以为您的应用添加消息签名功能：</p><pre data-type="codeBlock" text="import { WalletNotConnectedError } from &quot;@demox-labs/aleo-wallet-adapter-base&quot;;
import { useWallet } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import { LeoWalletAdapter } from &quot;@demox-labs/aleo-wallet-adapter-leo&quot;;
import React, { FC, useCallback } from &quot;react&quot;;

export const SignMessage: FC = () =&gt; {
  const { wallet, publicKey } = useWallet();

  const onClick = useCallback(async () =&gt; {
    if (!publicKey) throw new WalletNotConnectedError();

    const message = &quot;需要签名的消息&quot;;
    const bytes = new TextEncoder().encode(message);
    const signatureBytes = await (
      wallet?.adapter as LeoWalletAdapter
    ).signMessage(bytes);
    const signature = new TextDecoder().decode(signatureBytes);
    alert(&quot;签名消息: &quot; + signature);
  }, [wallet, publicKey]);

  return (
    &lt;button onClick={onClick} disabled={!publicKey}&gt;
      签名消息
    &lt;/button&gt;
  );
};
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">WalletNotConnectedError</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-base"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useWallet</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">LeoWalletAdapter</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-leo"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useCallback</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export const SignMessage: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const { wallet, publicKey } <span class="hljs-operator">=</span> useWallet();

  const onClick <span class="hljs-operator">=</span> useCallback(async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>publicKey) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WalletNotConnectedError();

    const message <span class="hljs-operator">=</span> <span class="hljs-string">"需要签名的消息"</span>;
    const <span class="hljs-keyword">bytes</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> TextEncoder().encode(message);
    const signatureBytes <span class="hljs-operator">=</span> await (
      wallet?.adapter <span class="hljs-keyword">as</span> LeoWalletAdapter
    ).signMessage(<span class="hljs-keyword">bytes</span>);
    const signature <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> TextDecoder().decode(signatureBytes);
    alert(<span class="hljs-string">"签名消息: "</span> <span class="hljs-operator">+</span> signature);
  }, [wallet, publicKey]);

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{onClick} disabled<span class="hljs-operator">=</span>{<span class="hljs-operator">!</span>publicKey}<span class="hljs-operator">></span>
      签名消息
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
  );
};
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🔓 实现解密功能</h3><p>以下代码片段展示了如何实现消息解密：</p><pre data-type="codeBlock" text="import { WalletNotConnectedError } from &quot;@demox-labs/aleo-wallet-adapter-base&quot;;
import { useWallet } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import React, { FC, useCallback } from &quot;react&quot;;

export const DecryptMessage: FC = () =&gt; {
  const { publicKey, decrypt } = useWallet();

  const onClick = async () =&gt; {
    const cipherText = &quot;需要解密的记录....&quot;;
    if (!publicKey) throw new WalletNotConnectedError();
    if (decrypt) {
      const decryptedPayload = await decrypt(cipherText);
      alert(&quot;解密结果: &quot; + decryptedPayload);
    }
  };

  return (
    &lt;button onClick={onClick} disabled={!publicKey}&gt;
      解密消息
    &lt;/button&gt;
  );
};
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">WalletNotConnectedError</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-base"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useWallet</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useCallback</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export const DecryptMessage: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const { publicKey, decrypt } <span class="hljs-operator">=</span> useWallet();

  const onClick <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    const cipherText <span class="hljs-operator">=</span> <span class="hljs-string">"需要解密的记录...."</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>publicKey) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WalletNotConnectedError();
    <span class="hljs-keyword">if</span> (decrypt) {
      const decryptedPayload <span class="hljs-operator">=</span> await decrypt(cipherText);
      alert(<span class="hljs-string">"解密结果: "</span> <span class="hljs-operator">+</span> decryptedPayload);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{onClick} disabled<span class="hljs-operator">=</span>{<span class="hljs-operator">!</span>publicKey}<span class="hljs-operator">></span>
      解密消息
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
  );
};
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🗂️ 请求记录</h3><p>您可以使用以下代码片段请求指定程序的记录：</p><pre data-type="codeBlock" text="import { WalletNotConnectedError } from &quot;@demox-labs/aleo-wallet-adapter-base&quot;;
import { useWallet } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import React, { FC, useCallback } from &quot;react&quot;;

export const RequestRecords: FC = () =&gt; {
  const { publicKey, requestRecords } = useWallet();

  const onClick = async () =&gt; {
    const program = &quot;credits.aleo&quot;;
    if (!publicKey) throw new WalletNotConnectedError();
    if (requestRecords) {
      const records = await requestRecords(program);
      console.log(&quot;记录: &quot; + records);
    }
  };

  return (
    &lt;button onClick={onClick} disabled={!publicKey}&gt;
      请求记录
    &lt;/button&gt;
  );
};
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">WalletNotConnectedError</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-base"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useWallet</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useCallback</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export const RequestRecords: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const { publicKey, requestRecords } <span class="hljs-operator">=</span> useWallet();

  const onClick <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    const program <span class="hljs-operator">=</span> <span class="hljs-string">"credits.aleo"</span>;
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>publicKey) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WalletNotConnectedError();
    <span class="hljs-keyword">if</span> (requestRecords) {
      const records <span class="hljs-operator">=</span> await requestRecords(program);
      console.log(<span class="hljs-string">"记录: "</span> <span class="hljs-operator">+</span> records);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{onClick} disabled<span class="hljs-operator">=</span>{<span class="hljs-operator">!</span>publicKey}<span class="hljs-operator">></span>
      请求记录
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
  );
};
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">📡 请求交易</h3><p>通过以下代码片段，您可以请求交易：</p><pre data-type="codeBlock" text="import {
  Transaction,
  WalletAdapterNetwork,
  WalletNotConnectedError
} from &quot;@demox-labs/aleo-wallet-adapter-base&quot;;
import { useWallet } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import React, { FC, useCallback } from &quot;react&quot;;

export const RequestTransaction: FC = () =&gt; {
  const { publicKey, requestTransaction } = useWallet();

  const onClick = async () =&gt; {
    if (!publicKey) throw new WalletNotConnectedError();

    const record = `&apos;{&quot;id&quot;:&quot;0f27d86a-1026-4980-9816-bcdce7569aa4&quot;,&quot;program_id&quot;:&quot;credits.aleo&quot;,&quot;microcredits&quot;:&quot;200000&quot;,&quot;spent&quot;:false,&quot;data&quot;:{}}&apos;`;
    const inputs = [JSON.parse(record), &quot;aleo1kf3dgrz9...&quot;, &quot;100u64&quot;];
    const fee = 35_000;

    const aleoTransaction = Transaction.createTransaction(
      publicKey,
      WalletAdapterNetwork.Testnet,
      &apos;credits.aleo&apos;,
      &apos;transfer&apos;,
      inputs,
      fee
    );

    if (requestTransaction) {
      await requestTransaction(aleoTransaction);
    }
  };

  return (
    &lt;button onClick={onClick} disabled={!publicKey}&gt;
      请求交易
    &lt;/button&gt;
  );
};
"><code><span class="hljs-keyword">import</span> {
  <span class="hljs-title">Transaction</span>,
  <span class="hljs-title">WalletAdapterNetwork</span>,
  <span class="hljs-title">WalletNotConnectedError</span>
} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-base"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useWallet</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useCallback</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export const RequestTransaction: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const { publicKey, requestTransaction } <span class="hljs-operator">=</span> useWallet();

  const onClick <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>publicKey) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WalletNotConnectedError();

    const record <span class="hljs-operator">=</span> `<span class="hljs-string">'{"id":"0f27d86a-1026-4980-9816-bcdce7569aa4","program_id":"credits.aleo","microcredits":"200000","spent":false,"data":{}}'</span>`;
    const inputs <span class="hljs-operator">=</span> [JSON.parse(record), <span class="hljs-string">"aleo1kf3dgrz9..."</span>, <span class="hljs-string">"100u64"</span>];
    const fee <span class="hljs-operator">=</span> <span class="hljs-number">35_000</span>;

    const aleoTransaction <span class="hljs-operator">=</span> Transaction.createTransaction(
      publicKey,
      WalletAdapterNetwork.Testnet,
      <span class="hljs-string">'credits.aleo'</span>,
      <span class="hljs-string">'transfer'</span>,
      inputs,
      fee
    );

    <span class="hljs-keyword">if</span> (requestTransaction) {
      await requestTransaction(aleoTransaction);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{onClick} disabled<span class="hljs-operator">=</span>{<span class="hljs-operator">!</span>publicKey}<span class="hljs-operator">></span>
      请求交易
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
  );
};
</code></pre><h3 id="h-aleo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">💻 部署Aleo程序</h3><p>以下是如何部署Aleo程序的代码示例：</p><pre data-type="codeBlock" text="import {
  Deployment,
  WalletAdapterNetwork,
  WalletNotConnectedError
} from &quot;@demox-labs/aleo-wallet-adapter-base&quot;;
import { useWallet } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import React, { FC, useCallback } from &quot;react&quot;;

export const DeployProgram: FC = () =&gt; {
  const { publicKey, requestDeploy } = useWallet();

  const onClick = async () =&gt; {
    if (!publicKey) throw new WalletNotConnectedError();

    const program = `
      program hello.aleo;
      function main:
        input r0 as u32.public;
        input r1 as u32.private;
        add r0 r1 into r2;
        output r2 as u32.private;
    `;
    const fee = 4_835_000;

    const aleoDeployment = new Deployment(
      publicKey,
      WalletAdapterNetwork.Testnet,
      program,
      fee
    );

    if (requestDeploy) {
      await requestDeploy(aleoDeployment);
    }
  };

  return (
    &lt;button onClick={onClick} disabled={!publicKey}&gt;
      部署程序
    &lt;/button&gt;
  );
};
"><code><span class="hljs-keyword">import</span> {
  <span class="hljs-title">Deployment</span>,
  <span class="hljs-title">WalletAdapterNetwork</span>,
  <span class="hljs-title">WalletNotConnectedError</span>
} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-base"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">useWallet</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useCallback</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export const DeployProgram: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const { publicKey, requestDeploy } <span class="hljs-operator">=</span> useWallet();

  const onClick <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>publicKey) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> WalletNotConnectedError();

    const program <span class="hljs-operator">=</span> `
      program hello.aleo;
      <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>:
        <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">u32</span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span></span>;
        input r1 <span class="hljs-keyword">as</span> u32.private;
        add r0 r1 into r2;
        output r2 <span class="hljs-keyword">as</span> u32.private;
    `;
    const fee <span class="hljs-operator">=</span> <span class="hljs-number">4_835_000</span>;

    const aleoDeployment <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Deployment(
      publicKey,
      WalletAdapterNetwork.Testnet,
      program,
      fee
    );

    <span class="hljs-keyword">if</span> (requestDeploy) {
      await requestDeploy(aleoDeployment);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="hljs-operator">&#x3C;</span>button onClick<span class="hljs-operator">=</span>{onClick} disabled<span class="hljs-operator">=</span>{<span class="hljs-operator">!</span>publicKey}<span class="hljs-operator">></span>
      部署程序
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>button<span class="hljs-operator">></span>
  );
};
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">订阅事件</h3><p>您可以使用以下代码订阅钱包事件，例如账户更改：</p><pre data-type="codeBlock" text="import { useWallet } from &quot;@demox-labs/aleo-wallet-adapter-react&quot;;
import { LeoWalletAdapter } from &quot;@demox-labs/aleo-wallet-adapter-leo&quot;;
import React, { FC, useEffect, useCallback } from &quot;react&quot;;

export const SubscribeToEvent: FC = () =&gt; {
  const { wallet } = useWallet();

  const handleAccountChange = useCallback(() =&gt; {
    // 处理账户变化，重新连接
  }, [wallet]);

  useEffect(() =&gt; {
    (wallet?.adapter as LeoWalletAdapter).on(&apos;accountChange&apos;, handleAccountChange);
    return () =&gt; {
      (wallet?.adapter as LeoWalletAdapter).off(&apos;accountChange&apos;, handleAccountChange);
    }
  }, [wallet]);

  return (
    // 组件内容
  );
};
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">useWallet</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-react"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">LeoWalletAdapter</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@demox-labs/aleo-wallet-adapter-leo"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">React</span>, { <span class="hljs-title">FC</span>, <span class="hljs-title">useEffect</span>, <span class="hljs-title">useCallback</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"react"</span>;

export const SubscribeToEvent: FC <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
  const { wallet } <span class="hljs-operator">=</span> useWallet();

  const handleAccountChange <span class="hljs-operator">=</span> useCallback(() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-comment">// 处理账户变化，重新连接</span>
  }, [wallet]);

  useEffect(() <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    (wallet?.adapter <span class="hljs-keyword">as</span> LeoWalletAdapter).on(<span class="hljs-string">'accountChange'</span>, handleAccountChange);
    <span class="hljs-keyword">return</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
      (wallet?.adapter <span class="hljs-keyword">as</span> LeoWalletAdapter).off(<span class="hljs-string">'accountChange'</span>, handleAccountChange);
    }
  }, [wallet]);

  <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">// 组件内容</span>
  );
};
</code></pre><p>通过以上步骤和代码片段，您可以成功地在Aleo应用中集成Demox Labs的Wallet Adapter，为用户提供更加无缝和安全的体验。如果有更多问题或需要深入了解，建议查阅Demox Labs的官方文档或加入开发者社区获取更多支持。</p><hr><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[通过 Puzzle SDK 和 WalletConnect 在 Aleo 上构建隐私 dApps]]></title>
            <link>https://paragraph.com/@yaakov/puzzle-sdk-walletconnect-aleo-dapps</link>
            <guid>XgRXDvuPXM7fqBkrwZOz</guid>
            <pubDate>Fri, 16 Aug 2024 06:50:06 GMT</pubDate>
            <description><![CDATA[通过 Puzzle SDK 和 WalletConnect 在 Aleo 上构建隐私 dApps在本教程中，我们将一步步了解如何使用 Puzzle SDK和WalletConnect 构建隐私的 dApps。除了构建隐私 dApp，还将学习如何集成 Puzzle Wallet 到我们自己的项目中，本教程都将提供必要的实现步骤和代码演示，让你快速上手。Puzzle SDK概述Puzzle SDK提供了React钩子，用于在隐私 dApp 和 Puzzle Wallet 之间进行交互。对于不使用React的人来说，也可以使用纯JavaScript 实现的 SDK。下载钱包你可以从Chrome商店或iOS的App Store下载Puzzle Wallet。Puzzle | Aleo Wallet - Chrome Web StorePuzzle | Aleo Wallet - App Store下载 Puzzle SDK要下载React SDK，请使用以下命令：npm i @puzzlehq/sdk 对于JavaScript SDK，使用以下命令：npm i @puzzlehq/sdk...]]></description>
            <content:encoded><![CDATA[<h1 id="h-puzzle-sdk-walletconnect-aleo-dapps" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">通过 Puzzle SDK 和 WalletConnect 在 Aleo 上构建隐私 dApps</h1><p>在本教程中，我们将一步步了解如何使用 Puzzle SDK和WalletConnect 构建隐私的 dApps。除了构建隐私 dApp，还将学习如何集成 Puzzle Wallet 到我们自己的项目中，本教程都将提供必要的实现步骤和代码演示，让你快速上手。</p><h3 id="h-puzzle-sdk" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Puzzle SDK概述</h3><p>Puzzle SDK提供了React钩子，用于在隐私 dApp 和 Puzzle Wallet 之间进行交互。对于不使用React的人来说，也可以使用纯JavaScript 实现的 SDK。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">下载钱包</h3><p>你可以从Chrome商店或iOS的App Store下载Puzzle Wallet。</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://chromewebstore.google.com/detail/puzzle-aleo-wallet/fdchdcpieegfofnofhgdombfckhbcokj">Puzzle | Aleo Wallet - Chrome Web Store</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://apps.apple.com/us/app/puzzle-aleo-wallet/id6450268321">Puzzle | Aleo Wallet - App Store</a></p></li></ul><h3 id="h-puzzle-sdk" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">下载 Puzzle SDK</h3><p>要下载React SDK，请使用以下命令：</p><pre data-type="codeBlock" text="npm i @puzzlehq/sdk
"><code>npm <span class="hljs-selector-tag">i</span> <span class="hljs-keyword">@puzzlehq</span>/sdk
</code></pre><p>对于JavaScript SDK，使用以下命令：</p><pre data-type="codeBlock" text="npm i @puzzlehq/sdk-core
"><code>npm <span class="hljs-selector-tag">i</span> <span class="hljs-keyword">@puzzlehq</span>/sdk-core
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">克隆示例代码库</h3><p>我们提供了一些示例代码库供你入门。例如，要克隆 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/puzzlehq/build-a-token">build a token</a> 代码库，使用以下命令：</p><pre data-type="codeBlock" text="git clone https://github.com/puzzlehq/build-a-token.git
"><code>git <span class="hljs-built_in">clone</span> https://github.com/puzzlehq/build-a-token.git
</code></pre><h3 id="h-dapp" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">运行示例dApp应用程序</h3><p>要运行示例dApp应用程序，请按以下步骤操作：</p><pre data-type="codeBlock" text="# 进入项目目录
cd build-a-token

# 运行开发服务器
npm run dev
"><code><span class="hljs-comment"># 进入项目目录</span>
<span class="hljs-built_in">cd</span> build-a-token

<span class="hljs-comment"># 运行开发服务器</span>
npm run dev
</code></pre><h3 id="h-sdk" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">SDK概述</h3><p><code>@puzzlehq/sdk</code>暴露了多个JavaScript函数和React钩子用于dApp开发。所有来自<code>@puzzlehq/sdk-core</code>的函数也由<code>@puzzlehq/sdk</code>导出。</p><h3 id="h-puzzlewalletprovider" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">PuzzleWalletProvider</h3><p>要使用React SDK，请将你的应用包裹在<code>PuzzleWalletProvider</code>中。</p><pre data-type="codeBlock" text="import ReactDOM from &apos;react-dom/client&apos;;
import YourApp from &apos;./YourApp.js&apos;;
import { PuzzleWalletProvider } from &apos;@puzzlehq/sdk&apos;;

ReactDOM.createRoot(document.getElementById(&apos;root&apos;)!).render(
  &lt;PuzzleWalletProvider
    dAppName=&quot;&lt;YOUR DAPP NAME&gt;&quot;
    dAppDescription=&quot;&lt;YOUR DAPP DESCRIPTION&gt;&quot;
    dAppUrl=&quot;&lt;YOUR DAPP URL&gt;&quot;
    dAppIconURL=&quot;&lt;YOUR DAPP ICON URL&gt;&quot;
    projectId=&quot;&lt;YOUR WALLETCONNECT PROJECT ID&gt;&quot; // 可选
  &gt;
    &lt;YourApp /&gt;
  &lt;/PuzzleWalletProvider&gt;
);
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">ReactDOM</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-title">YourApp</span> <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'./YourApp.js'</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">PuzzleWalletProvider</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'@puzzlehq/sdk'</span>;

ReactDOM.createRoot(document.getElementById(<span class="hljs-string">'root'</span>)<span class="hljs-operator">!</span>).render(
  <span class="hljs-operator">&#x3C;</span>PuzzleWalletProvider
    dAppName<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;YOUR DAPP NAME>"</span>
    dAppDescription<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;YOUR DAPP DESCRIPTION>"</span>
    dAppUrl<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;YOUR DAPP URL>"</span>
    dAppIconURL<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;YOUR DAPP ICON URL>"</span>
    projectId<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;YOUR WALLETCONNECT PROJECT ID>"</span> <span class="hljs-comment">// 可选</span>
  <span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span>YourApp <span class="hljs-operator">/</span><span class="hljs-operator">></span>
  <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>PuzzleWalletProvider<span class="hljs-operator">></span>
);
</code></pre><h3 id="h-walletconnect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect 概述</h3><p>如果你不想使用我们的SDK，你可以直接通过任何WalletConnect V2包使用Puzzle Wallet功能。</p><h3 id="h-walletconnect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect方法</h3><p>方法是由dApp发起的函数。</p><pre data-type="codeBlock" text="export const wc_aleo_methods = [
  &apos;decrypt&apos;,
  &apos;disconnect&apos;,
  &apos;getSelectedAccount&apos;,
  &apos;getBalance&apos;,
  &apos;getRecords&apos;,
  &apos;requestCreateEvent&apos;,
  &apos;getEvent&apos;,
  &apos;getEvents&apos;,
  &apos;createSharedState&apos;,
  &apos;importSharedState&apos;,
  &apos;requestSignature&apos;,
];
"><code>export const <span class="hljs-attr">wc_aleo_methods</span> = [
  <span class="hljs-string">'decrypt'</span>,
  <span class="hljs-string">'disconnect'</span>,
  <span class="hljs-string">'getSelectedAccount'</span>,
  <span class="hljs-string">'getBalance'</span>,
  <span class="hljs-string">'getRecords'</span>,
  <span class="hljs-string">'requestCreateEvent'</span>,
  <span class="hljs-string">'getEvent'</span>,
  <span class="hljs-string">'getEvents'</span>,
  <span class="hljs-string">'createSharedState'</span>,
  <span class="hljs-string">'importSharedState'</span>,
  <span class="hljs-string">'requestSignature'</span>,
]<span class="hljs-comment">;</span>
</code></pre><h3 id="h-walletconnect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect 事件</h3><p>事件是由钱包发起的函数。</p><pre data-type="codeBlock" text="export const wc_events = [
  &apos;chainChanged&apos;,
  &apos;accountSelected&apos;,
  &apos;selectedAccountSynced&apos;,
  &apos;sharedAccountSynced&apos;,
];
"><code>export const <span class="hljs-attr">wc_events</span> = [
  <span class="hljs-string">'chainChanged'</span>,
  <span class="hljs-string">'accountSelected'</span>,
  <span class="hljs-string">'selectedAccountSynced'</span>,
  <span class="hljs-string">'sharedAccountSynced'</span>,
]<span class="hljs-comment">;</span>
</code></pre><h3 id="h-walletconnect-id" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect 链 ID</h3><p>目前，Puzzle只支持一个链ID，但随着Aleo获得官方WalletConnect支持，这可能会改变。</p><pre data-type="codeBlock" text="export const wc_aleo_chains = [&apos;aleo:1&apos;]; // 可能会更改
"><code><span class="hljs-keyword">export</span> <span class="hljs-type">const</span> wc_aleo_chains = [<span class="hljs-string">'aleo:1'</span>]; <span class="hljs-comment">// 可能会更改</span>
</code></pre><h3 id="h-walletconnect-id" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect 项目 ID</h3><pre data-type="codeBlock" text="const projectId = &apos;f0aaeffe71b636da453fce042d79d723&apos;;
"><code>const <span class="hljs-attr">projectId</span> = <span class="hljs-string">'f0aaeffe71b636da453fce042d79d723'</span><span class="hljs-comment">;</span>
</code></pre><h3 id="h-walletconnect-web3modal" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect Web3Modal 属性</h3><pre data-type="codeBlock" text="export const web3modal_puzzle_props = {
  standaloneChains: wc_aleo_chains,
  enableExplorer: false,
  enableAccountView: true,
  enableNetworkView: true,
  enableStandaloneMode: true,
  mobileWallets: [
    {
      id: &apos;puzzle&apos;,
      name: &apos;Puzzle Wallet&apos;,
      links: {
        native: &apos;puzzleapp://&apos;,
        universal: &apos;&apos;,
      },
    },
  ],
  desktopWallets: [
    {
      id: &apos;puzzle&apos;,
      name: &apos;Puzzle Wallet&apos;,
      links: {
        native: &apos;&apos;,
        universal: &apos;https://walletconnect.puzzle.online/&apos;,
      },
    },
  ],
  walletImages: {
    puzzle: &apos;https://i.imgur.com/p9tHaFC.png&apos;,
  },
};
"><code><span class="hljs-string">export</span> <span class="hljs-string">const</span> <span class="hljs-string">web3modal_puzzle_props</span> <span class="hljs-string">=</span> {
  <span class="hljs-attr">standaloneChains:</span> <span class="hljs-string">wc_aleo_chains</span>,
  <span class="hljs-attr">enableExplorer:</span> <span class="hljs-literal">false</span>,
  <span class="hljs-attr">enableAccountView:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">enableNetworkView:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">enableStandaloneMode:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">mobileWallets:</span> [
    {
      <span class="hljs-attr">id:</span> <span class="hljs-string">'puzzle'</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">'Puzzle Wallet'</span>,
      <span class="hljs-attr">links:</span> {
        <span class="hljs-attr">native:</span> <span class="hljs-string">'puzzleapp://'</span>,
        <span class="hljs-attr">universal:</span> <span class="hljs-string">''</span>,
      },
    },
  ],
  <span class="hljs-attr">desktopWallets:</span> [
    {
      <span class="hljs-attr">id:</span> <span class="hljs-string">'puzzle'</span>,
      <span class="hljs-attr">name:</span> <span class="hljs-string">'Puzzle Wallet'</span>,
      <span class="hljs-attr">links:</span> {
        <span class="hljs-attr">native:</span> <span class="hljs-string">''</span>,
        <span class="hljs-attr">universal:</span> <span class="hljs-string">'https://walletconnect.puzzle.online/'</span>,
      },
    },
  ],
  <span class="hljs-attr">walletImages:</span> {
    <span class="hljs-attr">puzzle:</span> <span class="hljs-string">'https://i.imgur.com/p9tHaFC.png'</span>,
  },
}<span class="hljs-string">;</span>
</code></pre><h3 id="h-walletconnect-sign-client" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">WalletConnect Sign Client 属性</h3><pre data-type="codeBlock" text="export const signClient_puzzleProps = {
  requiredNamespaces: {
    aleo: {
      methods: wc_aleo_methods,
      chains: wc_aleo_chains,
      events: wc_events,
    },
  },
};
"><code><span class="hljs-string">export</span> <span class="hljs-string">const</span> <span class="hljs-string">signClient_puzzleProps</span> <span class="hljs-string">=</span> {
  <span class="hljs-attr">requiredNamespaces:</span> {
    <span class="hljs-attr">aleo:</span> {
      <span class="hljs-attr">methods:</span> <span class="hljs-string">wc_aleo_methods</span>,
      <span class="hljs-attr">chains:</span> <span class="hljs-string">wc_aleo_chains</span>,
      <span class="hljs-attr">events:</span> <span class="hljs-string">wc_events</span>,
    },
  },
}<span class="hljs-string">;</span>
</code></pre><p>更多信息你可以在这里找到：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/puzzlehq">Puzzle GitHub</a></p><p>通过上面的代码学习，你将学会如何将 Puzzle SDK 和 WalletConnect 集成到你的 Aleo dApp 中，这将是 dApp 开发的关键一步。</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[通过 Puzzle Wallet 和 Puzzle SDK 在 Aleo 上构建你的第一个 zkGame]]></title>
            <link>https://paragraph.com/@yaakov/puzzle-wallet-puzzle-sdk-aleo-zkgame</link>
            <guid>Pu4HLh2z70XXKvkQgD3M</guid>
            <pubDate>Thu, 15 Aug 2024 15:39:04 GMT</pubDate>
            <description><![CDATA[在这篇指南中，我们将使用 Puzzle Wallet 和 Puzzle SDK 一步步构建一个基于 Aleo 的 ZK 游戏。我们将创建一个名为 "Where’s Alex" 的简化版战舰游戏，在这个游戏中，Alex 隐藏了自己的位置，玩家需要猜测 Alex 的位置。这篇文章将展示 Aleo 的隐私功能和 Puzzle SDK 的多方隐私特性。游戏、部署、赚取奖励！1. 游戏创建 Aleo 账户并使用 Puzzle Wallet：下载 Puzzle Wallet，并按照扩展程序中的说明创建账户。然后需要几分钟等待 Aleo 积分和 Puzzle Pieces 到账。进入 Where’s Alex 游戏 链接，连接你的钱包，并验证你拥有的 Puzzle Prudens。然后使用 Puzzle 的开发工具铸造一些 Puzzle Prudens。铸造 Puzzle Prudens:打开 Puzzle 的开发工具 并连接你的钱包。在 "Create Event" 部分输入以下信息：Program ID: puzzle_pieces_v015.aleoFunction ID: mint_p...]]></description>
            <content:encoded><![CDATA[<p>在这篇指南中，我们将使用 Puzzle Wallet 和 Puzzle SDK 一步步构建一个基于 Aleo 的 ZK 游戏。我们将创建一个名为 &quot;Where’s Alex&quot; 的简化版战舰游戏，在这个游戏中，Alex 隐藏了自己的位置，玩家需要猜测 Alex 的位置。这篇文章将展示 Aleo 的隐私功能和 Puzzle SDK 的多方隐私特性。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">游戏、部署、赚取奖励！</h3><h3 id="h-1" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1. 游戏</h3><p><strong>创建 Aleo 账户并使用 Puzzle Wallet：</strong></p><ul><li><p>下载 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://chromewebstore.google.com/detail/puzzle-aleo-wallet/fdchdcpieegfofnofhgdombfckhbcokj">Puzzle Wallet</a>，并按照扩展程序中的说明创建账户。然后需要几分钟等待 Aleo 积分和 Puzzle Pieces 到账。</p></li><li><p>进入 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wheresalex.puzzle.online/">Where’s Alex 游戏</a> 链接，连接你的钱包，并验证你拥有的 Puzzle Prudens。然后使用 Puzzle 的开发工具铸造一些 Puzzle Prudens。</p></li></ul><p><strong>铸造 Puzzle Prudens:</strong></p><ul><li><p>打开 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dev.puzzle.online/">Puzzle 的开发工具</a> 并连接你的钱包。</p></li><li><p>在 &quot;Create Event&quot; 部分输入以下信息：</p><ul><li><p><strong>Program ID</strong>: puzzle_pieces_v015.aleo</p></li><li><p><strong>Function ID</strong>: mint_private</p></li><li><p><strong>Function Inputs</strong>: 500u64 你的 ALEO 账户地址</p></li></ul><p>示例：</p><pre data-type="codeBlock" text="500u64 aleo1v2ny2f64fsa97xc6s9medy68cf69szqxms03tyevgz8v9jlfzgzslxt6ka
"><code>500u64 aleo1v2ny2<span class="hljs-type">f64</span>fsa97xc6s9medy68cf69szqxms03tyevgz8v9jlfzgzslxt6ka
</code></pre></li><li><p>点击 &quot;Create Event&quot; 并等待交易完成。</p></li><li><p>一旦交易完成，你可以回到 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wheresalex.puzzle.online/">Where’s Alex </a>并开始游戏！向以下属于 Puzzle 团队的 Aleo 地址发起挑战，获取 Earn 的资格：</p><ul><li><p><strong>地址</strong>：aleo1u66muyfx8kp9zw957m4tkkpmrpjdnem4q4zpddh6zd2dejds3y9qa6p32u</p></li></ul></li></ul><h3 id="h-2" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 部署</h3><p>让我们来 Fork 这个游戏，并创建你自己的 zkGame！这个过程分为三个步骤：</p><p><strong>A. 设置你的 Where’s Alex :</strong></p><div data-type="youtube" videoId="qxjle4Rv9-Y">
      <div class="youtube-player" data-id="qxjle4Rv9-Y" style="background-image: url('https://i.ytimg.com/vi/qxjle4Rv9-Y/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=qxjle4Rv9-Y">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><ol><li><p>Fork 这个游戏的前端代码和 Aleo 智能合约代码。访问 Where’s Alex 的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="">GitHub </a>仓库，Fork 前端代码和 Aleo 智能合约代码。</p></li><li><p>阅读 Aleo 智能合约代码部分的 readme 文件，了解 Aleo 智能合约代码，以及了解 Where’s Alex 和 Puzzle 如何处理多方隐私。</p></li></ol><p><strong>B. 将你的 zkGame Aleo 程序部署到 Aleo</strong></p><p>主要包括三个步骤：</p><p><strong>步骤 1：获取 Aleo 程序部署工具</strong></p><p>如果你还没有安装 Rust、snarkVM、snarkOS 和 Leo，现在需要安装它们。建议使用 VS Code 的用户添加 Leo 扩展。</p><div data-type="youtube" videoId="WtdntQ-KhUI">
      <div class="youtube-player" data-id="WtdntQ-KhUI" style="background-image: url('https://i.ytimg.com/vi/WtdntQ-KhUI/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=WtdntQ-KhUI">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><p><strong>步骤 2-6：制作你自己的 “zkGame Pieces” 程序和 “zkGame” 程序</strong></p><ol><li><p>在 VS Code 中打开你新 Fork 的仓库，并进入 programs 文件夹。</p></li><li><p>更新 <code>puzzle_pieces_v015.leo</code> 程序，使用你独特的标题/版本。</p></li><li><p>更新 <code>puzzle_pieces</code> 的 <code>program.json</code> 文件，并使用 <code>test.sh</code> 脚本确保一切正常。</p></li><li><p>更新 <code>wheres_alex_v018.leo</code> 程序以导入你自己的代币，并使用你独特的标题/版本。</p></li><li><p>更新 <code>program.json</code> 文件和 <code>test.sh</code> 脚本，确保一切正常。</p></li></ol><p><strong>步骤 7-9：将你的 zkGame 程序部署到 Aleo</strong></p><ol><li><p>为你的 Aleo 账户充值。你需要 70 Aleo Credits 来部署合约。创建新的账户，并将信用转移到你的主账户。</p></li><li><p>部署 zkGame Pieces 程序：</p></li></ol><pre data-type="codeBlock" text="snarkos developer deploy &quot;INSERT_YOUR_PIECES_FORK_PROGRAM_NAME_HERE.aleo&quot; --private-key &quot;INSERT_YOUR_ALEO_PRIVATE_KEY_HERE&quot; --query &quot;https://api.explorer.aleo.org/v1&quot; --broadcast &quot;https://api.explorer.aleo.org/v1/testnet3/transaction/broadcast&quot; --priority-fee 16000000
"><code>snarkos developer deploy <span class="hljs-string">"INSERT_YOUR_PIECES_FORK_PROGRAM_NAME_HERE.aleo"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key <span class="hljs-string">"INSERT_YOUR_ALEO_PRIVATE_KEY_HERE"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>query <span class="hljs-string">"https://api.explorer.aleo.org/v1"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-string">"https://api.explorer.aleo.org/v1/testnet3/transaction/broadcast"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>priority<span class="hljs-operator">-</span>fee <span class="hljs-number">16000000</span>
</code></pre><ol><li><p>部署 zkGame 程序：</p></li></ol><pre data-type="codeBlock" text="snarkos developer deploy &quot;INSERT_YOUR_WHERES_ALEX_FORK_PROGRAM_NAME_HERE.aleo&quot; --private-key &quot;INSERT_YOUR_ALEO_PRIVATE_KEY_HERE&quot; --query &quot;https://api.explorer.aleo.org/v1&quot; --broadcast &quot;https://api.explorer.aleo.org/v1/testnet3/transaction/broadcast&quot; --priority-fee 17000000
"><code>snarkos developer deploy <span class="hljs-string">"INSERT_YOUR_WHERES_ALEX_FORK_PROGRAM_NAME_HERE.aleo"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key <span class="hljs-string">"INSERT_YOUR_ALEO_PRIVATE_KEY_HERE"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>query <span class="hljs-string">"https://api.explorer.aleo.org/v1"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-string">"https://api.explorer.aleo.org/v1/testnet3/transaction/broadcast"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>priority<span class="hljs-operator">-</span>fee <span class="hljs-number">17000000</span>
</code></pre><p><strong>C. 将你的 zkGame 前端部署到 Vercel</strong></p><div data-type="youtube" videoId="hiIpCPq15V4">
      <div class="youtube-player" data-id="hiIpCPq15V4" style="background-image: url('https://i.ytimg.com/vi/hiIpCPq15V4/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=hiIpCPq15V4">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><ol><li><p>更新前端引用的 Aleo 程序：</p><ul><li><p>打开 VS Code，在你 Fork 的仓库中。</p></li><li><p>使用 “Control F” 在 <code>src</code> 文件夹中搜索 <code>puzzle_pieces_v015.aleo</code> 并替换为你部署的版本。</p></li><li><p>使用 “Control F” 在 <code>src</code> 文件夹中搜索 <code>wheres_alex_v018.aleo</code> 并替换为你部署的版本。</p></li><li><p>使用 “Control F” 在 <code>src</code> 文件夹中搜索 “fees” 并调整值以确保费用足够高。</p></li></ul></li><li><p>测试新程序的前端应用：</p><ul><li><p>使用以下命令在本地编译并测试：</p></li></ul><pre data-type="codeBlock" text="pnpm i &amp;&amp; pnpm run dev
"><code>pnpm i <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> pnpm run dev
</code></pre><ul><li><p>连接钱包到你的本地版本 zkGame，并验证它是否工作正常。铸造一些 zkGame pieces 并验证你的余额。</p></li></ul></li><li><p>添加你个人风格的元素并部署到 Vercel：</p><ul><li><p>根据你的喜好，通过更新代币名称、游戏标题、背景图片、选择和图片等内容，来为你的 zkGame 增加一些个性化元素。</p></li><li><p>然后通过 Vercel 部署你的游戏。</p></li></ul></li></ol><h3 id="h-3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3. 赚取奖励</h3><p>挑战 Puzzle 官方账户，在你新部署的程序的网站上与他们对战，地址如下：</p><ul><li><p><strong>地址</strong>：aleo1u66muyfx8kp9zw957m4tkkpmrpjdnem4q4zpddh6zd2dejds3y9qa6p32u</p></li></ul><p>更多信息请参考：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.puzzle.online">https://docs.puzzle.online</a></p><p>通过这个教程开发部署的更多 zkGame 示例：</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://leo-wheres-luna.vercel.app/">Where’s Luna</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wheres-adam.vercel.app/">Where’s Adam</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wheres-joe.vercel.app/">Where’s Joe</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wheres-dominion.vercel.app/">Where’s Dominion</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wheres-daniel.vercel.app/">Where’s Daniel</a></p></li></ul><p>恭喜你构建并部署了你的第一个 Aleo zkGame！</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[在 Staking.xyz 上质押 Aleo 的简单教程]]></title>
            <link>https://paragraph.com/@yaakov/staking-xyz-aleo</link>
            <guid>Xp8iS4zkWGAjt2ydJ7FN</guid>
            <pubDate>Thu, 15 Aug 2024 14:53:14 GMT</pubDate>
            <description><![CDATA[在 Staking.xyz 上质押 Aleo 的简单教程在这篇文章中将一步步的演示在 Staking.xyz 上质押 Aleo，验证者需要质押 ALEO 才能激活，如果你不想运行自己的验证者，可以将你的 ALEO 委托给其他验证者。委托是非托管的，这意味着你仍然完全控制你的资金。什么是质押？Aleo 是一个使用 zk 证明来支持隐私应用的 Layer 1 区块链。这些证明需要称为 provers 的特殊参与者，他们在不泄露内容的情况下创建交易的加密证明。验证者则是另一个关键参与者，他们对新区块和区块历史达成共识。为了防止 sybil 攻击，验证者需要质押 Aleo Credits。要成为活跃的验证者，必须自我质押 1000 万 Aleo Credits。验证者也可以通过接受其他代币持有者的委托来增加质押。如何开始质押？你可以通过两种方式参与 Aleo 质押：成为验证者：运行一个 Aleo 节点，与其他验证者通信以形成共识。成为委托者：选择验证者并将你的 Aleo Credits 质押给他们，同时保留对你资产的完全控制权。在 Staking.xyz 上质押的步骤指南：访问 stak...]]></description>
            <content:encoded><![CDATA[<h1 id="h-stakingxyz-aleo" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">在 Staking.xyz 上质押 Aleo 的简单教程</h1><p>在这篇文章中将一步步的演示在 Staking.xyz 上质押 Aleo，验证者需要质押 ALEO 才能激活，如果你不想运行自己的验证者，可以将你的 ALEO 委托给其他验证者。委托是非托管的，这意味着你仍然完全控制你的资金。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">什么是质押？</h3><p>Aleo 是一个使用 zk 证明来支持隐私应用的 Layer 1 区块链。这些证明需要称为 provers 的特殊参与者，他们在不泄露内容的情况下创建交易的加密证明。验证者则是另一个关键参与者，他们对新区块和区块历史达成共识。为了防止 sybil 攻击，验证者需要质押 Aleo Credits。要成为活跃的验证者，必须自我质押 1000 万 Aleo Credits。验证者也可以通过接受其他代币持有者的委托来增加质押。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">如何开始质押？</h3><p>你可以通过两种方式参与 Aleo 质押：</p><ol><li><p>成为验证者：运行一个 Aleo 节点，与其他验证者通信以形成共识。</p></li><li><p>成为委托者：选择验证者并将你的 Aleo Credits 质押给他们，同时保留对你资产的完全控制权。</p></li></ol><h3 id="h-stakingxyz" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">在 Staking.xyz 上质押的步骤指南：</h3><ol><li><p>访问 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.staking.xyz/stake?network=aleo¤cy=ALEO&amp;stakingType=native">staking.xyz</a>。在 staking.xyz 开始管理你的质押。</p></li><li><p>选择质押数量。输入你想要质押的 ALEO 数量，这里质押数量不能低于1000 积分。</p></li><li><p>获得质押奖励。质押奖励在每个区块中赚取，并直接添加到你的质押余额中，复投你的奖励。</p></li><li><p>解除质押过程。你可以随时解质押。解质押后，你需要等待 1 小时才能转移你的 ALEO。</p></li></ol><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">质押的重要注意事项：</h3><p><strong>委托者：</strong></p><ul><li><p>需要至少 10,000 Aleo Credits 才能开始赚取奖励。</p></li><li><p>奖励在 1-2 个区块后赚取，并自动复合。</p></li></ul><p><strong>验证者：</strong></p><ul><li><p>必须至少质押 10,000,000 Aleo Credits 才能成为活跃验证者。</p></li><li><p>如果他们有任何活跃的委托者，则无法退出活跃集。</p></li></ul><p><strong>选择验证者时的考虑：</strong></p><ul><li><p><strong>性能</strong>：高在线时间和可靠的性能至关重要。</p></li><li><p><strong>贡献</strong>：通过工具、社区或公共 RPC 端点为生态系统做出贡献的验证者。</p></li><li><p><strong>佣金</strong>：合理的佣金率以确保可持续运营。</p></li><li><p><strong>去中心化</strong>：避免委托过于集中的验证者，以维护网络弹性。</p></li><li><p><strong>声誉</strong>：在其他生态系统中的表现可以预示在 Aleo 上的未来表现。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">质押奖励和协议：</h3><p><strong>奖励：</strong></p><ul><li><p>协议发放初始总供应量的 5% 作为质押奖励。</p></li><li><p>Coinbase 奖励分配给 Aleo 质押者，其中三分之一用于 Aleo provers 提供的解决方案。</p></li></ul><p><strong>ARC 提案：</strong></p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/AleoNet/ARCs/discussions/51"><strong>ARC-0037</strong></a>：区分工作和提款地址。</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/AleoNet/ARCs/discussions/52"><strong>ARC-0038</strong></a>：验证者可以从委托者那里收取佣金。</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://aleo.org/post/arc-0041-contest-sherlock/"><strong>ARC-0041</strong></a>：允许验证者在没有直接拥有 1000 万 Aleo Credits 的情况下激活。</p></li></ul><p>在 Aleo 上质押需要认真的选择一个靠谱的验证者。在委托你的 ALEO 之前，始终要研究验证者并理解质押机制。随着 Aleo 向主网推出迈进，对最新进展保持关注非常重要。</p><p>通过遵循本指南，你可以简单地了解 Staking.xyz 上的质押过程，为网络安全做出贡献并在此过程中赚取奖励。</p><blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq">Aleo Twitter</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo">Aleo Discord</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/">Aleo 官网</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo Rust SDK 的简单使用教程]]></title>
            <link>https://paragraph.com/@yaakov/aleo-rust-sdk</link>
            <guid>syToveiQggLd3IkU3xpD</guid>
            <pubDate>Wed, 24 Jul 2024 08:30:03 GMT</pubDate>
            <description><![CDATA[前面我们介绍过 Aleo 的 Javascript 和 Python SDK 的使用教程，但是 Rust 作为区块链开发的最常用的语言之一还没有合适的 SDK 可以使用，最近发现了一个用 Rust 写的 SDK，虽然功能还不够完善，但是作者正在慢慢迭代，满足基本需求问题不大。 项目地址： https://github.com/C-B-Elite/aleo-agent安装首先确保已经成功安装 Rust，在你的项目目录下运行以下 Cargo 命令：cargo add aleo-agent 或者在你的 Cargo.toml 文件中添加以下行：aleo-agent = "1.0.1" 使用发起转账 先看一段简单的 demouse aleo_agent::account::Account; use aleo_agent::agent::{Agent, TransferArgs, TransferType}; use aleo_agent::{CiphertextRecord, PlaintextRecord, MICROCREDITS}; use anyhow::Result; use s...]]></description>
            <content:encoded><![CDATA[<p>前面我们介绍过 Aleo 的 Javascript 和 Python SDK 的使用教程，但是 Rust 作为区块链开发的最常用的语言之一还没有合适的 SDK 可以使用，最近发现了一个用 Rust 写的 SDK，虽然功能还不够完善，但是作者正在慢慢迭代，满足基本需求问题不大。</p><p>项目地址：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/C-B-Elite/aleo-agent">https://github.com/C-B-Elite/aleo-agent</a></p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">安装</h3><p>首先确保已经成功安装 Rust，在你的项目目录下运行以下 Cargo 命令：</p><pre data-type="codeBlock" text="cargo add aleo-agent
"><code>cargo <span class="hljs-keyword">add</span> aleo-agent
</code></pre><p>或者在你的 <code>Cargo.toml</code> 文件中添加以下行：</p><pre data-type="codeBlock" text="aleo-agent = &quot;1.0.1&quot;
"><code><span class="hljs-attr">aleo-agent</span> = <span class="hljs-string">"1.0.1"</span>
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">使用</h3><p><strong><em>发起转账</em></strong></p><p>先看一段简单的 demo</p><pre data-type="codeBlock" text="use aleo_agent::account::Account;
use aleo_agent::agent::{Agent, TransferArgs, TransferType};
use aleo_agent::{CiphertextRecord, PlaintextRecord, MICROCREDITS};
use anyhow::Result;
use std::str::FromStr;

fn main() -&gt; Result&lt;()&gt; {
    
    // 私钥格式: APrivateKey1zkp...
    let alice_key = &quot;Alice PRIVATE KEY&quot;;
    let alice_account = Account::from_private_key(alice_key)?;
    let alice_agent = Agent::builder().with_account(alice_account).build();

    let bob_key = &quot;Bob PRIVATE KEY&quot;;
    let bob_account = Account::from_private_key(bob_key)?;
    let bob_address = bob_account.address();
    
    // 获取 Alice 的公共余额
    let public_balance = alice_agent.get_public_balance()?;
    println!(&quot;Alice Public Balance : {}&quot;, public_balance);
    
    // 公共转账到公共账户
    let transfer_args = TransferArgs::from(
        MICROCREDITS, // 1 微信用
        bob_address.to_owned(),
        1,
        None,
        TransferType::Public,
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);

    // 公共转账到私有账户
    let transfer_args = TransferArgs::from(
        MICROCREDITS, // 1 微信用
        bob_address.to_owned(),
        1,
        None,
        TransferType::PublicToPrivate,
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);

    // 私有转账到公共账户
    // 明文记录格式: &quot;{owner: aleo1xxxxx.private,microcredits: 1u64.private,_nonce: xxxxxgroup.public}&quot;
    let record = PlaintextRecord::from_str(&quot;PLAINTEXT RECORD&quot;)?;

    // 从密文记录解密明文记录
    // 格式: record1xxxxxxxxxx
    let ciphertext_record = CiphertextRecord::from_str(&quot;CIPHERTEXT RECORD&quot;)?;
    let fee_record = alice_agent.decrypt_ciphertext_record(&amp;ciphertext_record)?;

    let transfer_args = TransferArgs::from(
        MICROCREDITS, // 1 微信用
        bob_address.to_owned(),
        10,
        Some(fee_record),
        TransferType::PrivateToPublic(record),
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);

    // 私有转账到私有账户
    let encrypted_fee_record = CiphertextRecord::from_str(&quot;record1xxxxxxx&quot;)?;
    let record = alice_agent.decrypt_ciphertext_record(&amp;encrypted_fee_record)?;

    let transfer_args = TransferArgs::from(
        MICROCREDITS,
        bob_address.to_owned(),
        1,
        None,
        TransferType::Private(record),
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);

    Ok(())
}
"><code>use aleo_agent::account::Account;
use aleo_agent::agent::{Agent, TransferArgs, TransferType};
use aleo_agent::{CiphertextRecord, PlaintextRecord, MICROCREDITS};
use anyhow::Result;
use std::str::FromStr;

fn main() <span class="hljs-operator">-</span><span class="hljs-operator">></span> Result<span class="hljs-operator">&#x3C;</span>()<span class="hljs-operator">></span> {
    
    <span class="hljs-comment">// 私钥格式: APrivateKey1zkp...</span>
    let alice_key <span class="hljs-operator">=</span> <span class="hljs-string">"Alice PRIVATE KEY"</span>;
    let alice_account <span class="hljs-operator">=</span> Account::from_private_key(alice_key)?;
    let alice_agent <span class="hljs-operator">=</span> Agent::builder().with_account(alice_account).build();

    let bob_key <span class="hljs-operator">=</span> <span class="hljs-string">"Bob PRIVATE KEY"</span>;
    let bob_account <span class="hljs-operator">=</span> Account::from_private_key(bob_key)?;
    let bob_address <span class="hljs-operator">=</span> bob_account.<span class="hljs-built_in">address</span>();
    
    <span class="hljs-comment">// 获取 Alice 的公共余额</span>
    let public_balance <span class="hljs-operator">=</span> alice_agent.get_public_balance()?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"Alice Public Balance : {}"</span>, public_balance);
    
    <span class="hljs-comment">// 公共转账到公共账户</span>
    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS, <span class="hljs-comment">// 1 微信用</span>
        bob_address.to_owned(),
        <span class="hljs-number">1</span>,
        None,
        TransferType::Public,
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);

    <span class="hljs-comment">// 公共转账到私有账户</span>
    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS, <span class="hljs-comment">// 1 微信用</span>
        bob_address.to_owned(),
        <span class="hljs-number">1</span>,
        None,
        TransferType::PublicToPrivate,
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);

    <span class="hljs-comment">// 私有转账到公共账户</span>
    <span class="hljs-comment">// 明文记录格式: "{owner: aleo1xxxxx.private,microcredits: 1u64.private,_nonce: xxxxxgroup.public}"</span>
    let record <span class="hljs-operator">=</span> PlaintextRecord::from_str(<span class="hljs-string">"PLAINTEXT RECORD"</span>)?;

    <span class="hljs-comment">// 从密文记录解密明文记录</span>
    <span class="hljs-comment">// 格式: record1xxxxxxxxxx</span>
    let ciphertext_record <span class="hljs-operator">=</span> CiphertextRecord::from_str(<span class="hljs-string">"CIPHERTEXT RECORD"</span>)?;
    let fee_record <span class="hljs-operator">=</span> alice_agent.decrypt_ciphertext_record(<span class="hljs-operator">&#x26;</span>ciphertext_record)?;

    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS, <span class="hljs-comment">// 1 微信用</span>
        bob_address.to_owned(),
        <span class="hljs-number">10</span>,
        Some(fee_record),
        TransferType::PrivateToPublic(record),
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);

    <span class="hljs-comment">// 私有转账到私有账户</span>
    let encrypted_fee_record <span class="hljs-operator">=</span> CiphertextRecord::from_str(<span class="hljs-string">"record1xxxxxxx"</span>)?;
    let record <span class="hljs-operator">=</span> alice_agent.decrypt_ciphertext_record(<span class="hljs-operator">&#x26;</span>encrypted_fee_record)?;

    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS,
        bob_address.to_owned(),
        <span class="hljs-number">1</span>,
        None,
        TransferType::Private(record),
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);

    Ok(())
}
</code></pre><p>这段代码展示了如何使用 <code>aleo_agent</code> 库进行不同类型的资产转移操作。具体步骤如下：</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">主要流程</h4><ol><li><p><strong>账户初始化</strong>：使用私钥创建账户对象。</p></li><li><p><strong>账户代理初始化</strong>：使用账户对象创建代理对象，用于执行转移操作。</p></li><li><p><strong>获取公共余额</strong>：查询账户的公共余额。</p></li><li><p><strong>公共转账到公共账户</strong>：从Alice账户向Bob账户进行公共转账。</p></li><li><p><strong>公共转账到私有账户</strong>：从Alice账户向Bob账户进行公共到私有的转账。</p></li><li><p><strong>私有转账到公共账户</strong>：从Alice账户向Bob账户进行私有到公共的转账。</p></li><li><p><strong>私有转账到私有账户</strong>：从Alice账户向Bob账户进行私有到私有的转账。</p></li></ol><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">代码详细介绍</h4><pre data-type="codeBlock" text="use aleo_agent::account::Account;
use aleo_agent::agent::{Agent, TransferArgs, TransferType};
use aleo_agent::{CiphertextRecord, PlaintextRecord, MICROCREDITS};
use anyhow::Result;
use std::str::FromStr;

fn main() -&gt; Result&lt;()&gt; {
"><code><span class="hljs-keyword">use</span> aleo_agent::account::Account;
<span class="hljs-keyword">use</span> aleo_agent::agent::{Agent, TransferArgs, TransferType};
<span class="hljs-keyword">use</span> aleo_agent::{CiphertextRecord, PlaintextRecord, MICROCREDITS};
<span class="hljs-keyword">use</span> anyhow::<span class="hljs-type">Result</span>;
<span class="hljs-keyword">use</span> std::<span class="hljs-type">str</span>::FromStr;

<span class="hljs-keyword">fn</span> <span class="hljs-title function_">main</span>() <span class="hljs-punctuation">-></span> <span class="hljs-type">Result</span>&#x3C;()> {
</code></pre><ul><li><p><strong>导入依赖库</strong>：导入<code>aleo_agent</code>库中所需的模块和类型，以及<code>anyhow</code>库用于错误处理。</p></li><li><p><strong>定义主函数</strong>：<code>main</code>函数用于执行代码逻辑。</p></li></ul><pre data-type="codeBlock" text="    // private key format: APrivateKey1zkp...
    let alice_key = &quot;Alice PRIVATE KEY&quot;;
    let alice_account = Account::from_private_key(alice_key)?;
    let alice_agent = Agent::builder().with_account(alice_account).build();

    let bob_key = &quot;Bob PRIVATE KEY&quot;;
    let bob_account = Account::from_private_key(bob_key)?;
    let bob_address = bob_account.address();
"><code>    // private key format: APrivateKey1zkp...
    let <span class="hljs-attr">alice_key</span> = <span class="hljs-string">"Alice PRIVATE KEY"</span><span class="hljs-comment">;</span>
    let <span class="hljs-attr">alice_account</span> = Account::from_private_key(alice_key)?<span class="hljs-comment">;</span>
    let <span class="hljs-attr">alice_agent</span> = Agent::builder().with_account(alice_account).build()<span class="hljs-comment">;</span>

    let <span class="hljs-attr">bob_key</span> = <span class="hljs-string">"Bob PRIVATE KEY"</span><span class="hljs-comment">;</span>
    let <span class="hljs-attr">bob_account</span> = Account::from_private_key(bob_key)?<span class="hljs-comment">;</span>
    let <span class="hljs-attr">bob_address</span> = bob_account.address()<span class="hljs-comment">;</span>
</code></pre><ul><li><p><strong>创建Alice账户</strong>：从私钥创建Alice的账户对象，并使用该账户对象创建代理对象。</p></li><li><p><strong>创建Bob账户</strong>：从私钥创建Bob的账户对象，并获取其地址。</p></li></ul><pre data-type="codeBlock" text="    // get alice public balance
    let public_balance = alice_agent.get_public_balance()?;
    println!(&quot;Alice Public Balance : {}&quot;, public_balance);
"><code>    <span class="hljs-comment">// get alice public balance</span>
    let public_balance <span class="hljs-operator">=</span> alice_agent.get_public_balance()?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"Alice Public Balance : {}"</span>, public_balance);
</code></pre><ul><li><p><strong>获取Alice的公共余额</strong>：查询并打印Alice账户的公共余额。</p></li></ul><pre data-type="codeBlock" text="    // public transfer to public account
    let transfer_args = TransferArgs::from(
        MICROCREDITS, // 1 credit
        bob_address.to_owned(),
        1,
        None,
        TransferType::Public,
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);
"><code>    <span class="hljs-comment">// public transfer to public account</span>
    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS, <span class="hljs-comment">// 1 credit</span>
        bob_address.to_owned(),
        <span class="hljs-number">1</span>,
        None,
        TransferType::Public,
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);
</code></pre><ul><li><p><strong>公共转账到公共账户</strong>：创建转账参数，从Alice账户向Bob账户进行公共转账，并打印交易哈希。</p></li></ul><pre data-type="codeBlock" text="    // public transfer to private
    let transfer_args = TransferArgs::from(
        MICROCREDITS, // 1 credit
        bob_address.to_owned(),
        1,
        None,
        TransferType::PublicToPrivate,
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);
"><code>    <span class="hljs-comment">// public transfer to private</span>
    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS, <span class="hljs-comment">// 1 credit</span>
        bob_address.to_owned(),
        <span class="hljs-number">1</span>,
        None,
        TransferType::PublicToPrivate,
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);
</code></pre><ul><li><p><strong>公共转账到私有账户</strong>：创建转账参数，从Alice账户向Bob账户进行公共到私有的转账，并打印交易哈希。</p></li></ul><pre data-type="codeBlock" text="    // private transfer to public
    // plaintext record format : &quot;{owner: aleo1xxxxx.private,microcredits: 1u64.private,_nonce: xxxxxgroup.public}&quot;
    let record = PlaintextRecord::from_str(&quot;PLAINTEXT RECORD&quot;)?;

    //  decrypt plaintext record from ciphertext record
    //  format: record1xxxxxxxxxx
    let ciphertext_record = CiphertextRecord::from_str(&quot;CIPHERTEXT RECORD&quot;)?;
    let fee_record = alice_agent.decrypt_ciphertext_record(&amp;ciphertext_record)?;

    let transfer_args = TransferArgs::from(
        MICROCREDITS, // 1 credit
        bob_address.to_owned(),
        10,
        Some(fee_record),
        TransferType::PrivateToPublic(record),
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);
"><code>    <span class="hljs-comment">// private transfer to public</span>
    <span class="hljs-comment">// plaintext record format : "{owner: aleo1xxxxx.private,microcredits: 1u64.private,_nonce: xxxxxgroup.public}"</span>
    let record <span class="hljs-operator">=</span> PlaintextRecord::from_str(<span class="hljs-string">"PLAINTEXT RECORD"</span>)?;

    <span class="hljs-comment">//  decrypt plaintext record from ciphertext record</span>
    <span class="hljs-comment">//  format: record1xxxxxxxxxx</span>
    let ciphertext_record <span class="hljs-operator">=</span> CiphertextRecord::from_str(<span class="hljs-string">"CIPHERTEXT RECORD"</span>)?;
    let fee_record <span class="hljs-operator">=</span> alice_agent.decrypt_ciphertext_record(<span class="hljs-operator">&#x26;</span>ciphertext_record)?;

    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS, <span class="hljs-comment">// 1 credit</span>
        bob_address.to_owned(),
        <span class="hljs-number">10</span>,
        Some(fee_record),
        TransferType::PrivateToPublic(record),
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);
</code></pre><ul><li><p><strong>私有转账到公共账户</strong>：从字符串解析出明文记录和密文记录，解密密文记录，创建转账参数，并执行转账操作，打印交易哈希。</p></li></ul><pre data-type="codeBlock" text="    // private transfer to private
    let encrypted_fee_record = CiphertextRecord::from_str(&quot;record1xxxxxxx&quot;)?;
    let record = alice_agent.decrypt_ciphertext_record(&amp;encrypted_fee_record)?;

    let transfer_args = TransferArgs::from(
        MICROCREDITS,
        bob_address.to_owned(),
        1,
        None,
        TransferType::Private(record),
    );
    let tx_hash = alice_agent.transfer(transfer_args)?;
    println!(&quot;tx_hash: {tx_hash}&quot;);

    Ok(())
}
"><code>    <span class="hljs-comment">// private transfer to private</span>
    let encrypted_fee_record <span class="hljs-operator">=</span> CiphertextRecord::from_str(<span class="hljs-string">"record1xxxxxxx"</span>)?;
    let record <span class="hljs-operator">=</span> alice_agent.decrypt_ciphertext_record(<span class="hljs-operator">&#x26;</span>encrypted_fee_record)?;

    let transfer_args <span class="hljs-operator">=</span> TransferArgs::<span class="hljs-keyword">from</span>(
        MICROCREDITS,
        bob_address.to_owned(),
        <span class="hljs-number">1</span>,
        None,
        TransferType::Private(record),
    );
    let tx_hash <span class="hljs-operator">=</span> alice_agent.<span class="hljs-built_in">transfer</span>(transfer_args)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"tx_hash: {tx_hash}"</span>);

    Ok(())
}
</code></pre><ul><li><p><strong>私有转账到私有账户</strong>：从字符串解析出密文记录，解密密文记录，创建转账参数，并执行转账操作，打印交易哈希。</p></li></ul><p><strong><em>部署和执行程序</em></strong></p><pre data-type="codeBlock" text="use aleo_agent::account::Account;
use aleo_agent::agent::Agent;
use aleo_agent::program::ProgramManager;
use anyhow::Result;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;

fn main() -&gt; Result&lt;()&gt; {
    // 使用私钥构建代理
    let private_key = &quot;YOUR PRIVATE KEY&quot;; // APrivateKey1zkp...
    let account = Account::from_private_key(private_key)?;
    let agent = Agent::builder().with_account(account).build();

    // 使用 Leo 项目中的 leo build 命令生成的 build 文件夹
    let path = Path::new(&quot;/contract/build&quot;); // 必须是绝对路径
    let local_program = ProgramManager::load_program_from_path(path)?;
    
    // 部署程序
    let deploy_tx_id = agent.deploy_program(&amp;local_program, 1, None)?;
    println!(&quot;已部署程序，交易ID: {}&quot;, deploy_tx_id);

    // 等待广播和确认
    sleep(Duration::from_secs(60));

    // 获取交易状态
    let status = agent.get_confirmed_transaction(&amp;deploy_tx_id)?;
    println!(&quot;部署交易状态: \n {status:?}&quot;);

    // 获取程序ID
    let program_id = local_program.id();
    let pm = agent.program(program_id.to_string().as_ref())?;

    // 执行程序
    let inputs = vec![&quot;1u32&quot;, &quot;2u32&quot;];
    let exec_tx_id = pm.execute_program(&quot;main&quot;, inputs.into_iter(), 1, None)?;
    println!(&quot;执行程序，交易ID: {exec_tx_id}&quot;);

    // 等待广播和确认
    sleep(Duration::from_secs(60));
    
    // 获取交易状态
    let status = agent.get_confirmed_transaction(&amp;exec_tx_id)?;
    println!(&quot;执行交易状态: \n{:#?}&quot;, status);

    Ok(())
}
"><code><span class="hljs-keyword">use</span> aleo_agent::account::Account;
<span class="hljs-keyword">use</span> aleo_agent::agent::Agent;
<span class="hljs-keyword">use</span> aleo_agent::program::ProgramManager;
<span class="hljs-keyword">use</span> anyhow::<span class="hljs-type">Result</span>;
<span class="hljs-keyword">use</span> std::path::Path;
<span class="hljs-keyword">use</span> std::thread::sleep;
<span class="hljs-keyword">use</span> std::time::Duration;

<span class="hljs-keyword">fn</span> <span class="hljs-title function_">main</span>() <span class="hljs-punctuation">-></span> <span class="hljs-type">Result</span>&#x3C;()> {
    <span class="hljs-comment">// 使用私钥构建代理</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">private_key</span> = <span class="hljs-string">"YOUR PRIVATE KEY"</span>; <span class="hljs-comment">// APrivateKey1zkp...</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">account</span> = Account::<span class="hljs-title function_ invoke__">from_private_key</span>(private_key)?;
    <span class="hljs-keyword">let</span> <span class="hljs-variable">agent</span> = Agent::<span class="hljs-title function_ invoke__">builder</span>().<span class="hljs-title function_ invoke__">with_account</span>(account).<span class="hljs-title function_ invoke__">build</span>();

    <span class="hljs-comment">// 使用 Leo 项目中的 leo build 命令生成的 build 文件夹</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">path</span> = Path::<span class="hljs-title function_ invoke__">new</span>(<span class="hljs-string">"/contract/build"</span>); <span class="hljs-comment">// 必须是绝对路径</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">local_program</span> = ProgramManager::<span class="hljs-title function_ invoke__">load_program_from_path</span>(path)?;
    
    <span class="hljs-comment">// 部署程序</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">deploy_tx_id</span> = agent.<span class="hljs-title function_ invoke__">deploy_program</span>(&#x26;local_program, <span class="hljs-number">1</span>, <span class="hljs-literal">None</span>)?;
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"已部署程序，交易ID: {}"</span>, deploy_tx_id);

    <span class="hljs-comment">// 等待广播和确认</span>
    <span class="hljs-title function_ invoke__">sleep</span>(Duration::<span class="hljs-title function_ invoke__">from_secs</span>(<span class="hljs-number">60</span>));

    <span class="hljs-comment">// 获取交易状态</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">status</span> = agent.<span class="hljs-title function_ invoke__">get_confirmed_transaction</span>(&#x26;deploy_tx_id)?;
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"部署交易状态: \n {status:?}"</span>);

    <span class="hljs-comment">// 获取程序ID</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">program_id</span> = local_program.<span class="hljs-title function_ invoke__">id</span>();
    <span class="hljs-keyword">let</span> <span class="hljs-variable">pm</span> = agent.<span class="hljs-title function_ invoke__">program</span>(program_id.<span class="hljs-title function_ invoke__">to_string</span>().<span class="hljs-title function_ invoke__">as_ref</span>())?;

    <span class="hljs-comment">// 执行程序</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">inputs</span> = <span class="hljs-built_in">vec!</span>[<span class="hljs-string">"1u32"</span>, <span class="hljs-string">"2u32"</span>];
    <span class="hljs-keyword">let</span> <span class="hljs-variable">exec_tx_id</span> = pm.<span class="hljs-title function_ invoke__">execute_program</span>(<span class="hljs-string">"main"</span>, inputs.<span class="hljs-title function_ invoke__">into_iter</span>(), <span class="hljs-number">1</span>, <span class="hljs-literal">None</span>)?;
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"执行程序，交易ID: {exec_tx_id}"</span>);

    <span class="hljs-comment">// 等待广播和确认</span>
    <span class="hljs-title function_ invoke__">sleep</span>(Duration::<span class="hljs-title function_ invoke__">from_secs</span>(<span class="hljs-number">60</span>));
    
    <span class="hljs-comment">// 获取交易状态</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">status</span> = agent.<span class="hljs-title function_ invoke__">get_confirmed_transaction</span>(&#x26;exec_tx_id)?;
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"执行交易状态: \n{:#?}"</span>, status);

    <span class="hljs-title function_ invoke__">Ok</span>(())
}
</code></pre><p>这段代码展示了如何使用 <code>aleo_agent</code> 库构建一个代理(agent)，并通过该代理来部署和执行一个程序。以下是代码的详细介绍：</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">导入必要的库和模块</h3><pre data-type="codeBlock" text="use aleo_agent::account::Account;
use aleo_agent::agent::Agent;
use aleo_agent::program::ProgramManager;
use anyhow::Result;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;
"><code><span class="hljs-keyword">use</span> aleo_agent::account::Account;
<span class="hljs-keyword">use</span> aleo_agent::agent::Agent;
<span class="hljs-keyword">use</span> aleo_agent::program::ProgramManager;
<span class="hljs-keyword">use</span> anyhow::<span class="hljs-type">Result</span>;
<span class="hljs-keyword">use</span> std::path::Path;
<span class="hljs-keyword">use</span> std::thread::sleep;
<span class="hljs-keyword">use</span> std::time::Duration;
</code></pre><ul><li><p><strong>aleo_agent::account::Account</strong>: 用于管理账户信息。</p></li><li><p><strong>aleo_agent::agent::Agent</strong>: 代理对象，用于与区块链交互。</p></li><li><p><strong>aleo_agent::program::ProgramManager</strong>: 用于管理程序的部署和执行。</p></li><li><p><strong>anyhow::Result</strong>: 用于处理可能出现的错误。</p></li><li><p><strong>std::path::Path</strong>: 处理文件路径。</p></li><li><p><strong>std::thread::sleep</strong> 和 <strong>std::time::Duration</strong>: 用于设置程序暂停的时间。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">主函数</h3><pre data-type="codeBlock" text="fn main() -&gt; Result&lt;()&gt; {
    // build an agent with private key
    let private_key = &quot;YOUR PRIVATE KEY&quot;; // APrivateKey1zkp...
    let account = Account::from_private_key(private_key)?;
    let agent = Agent::builder().with_account(account).build();
"><code>fn main() <span class="hljs-operator">-</span><span class="hljs-operator">></span> Result<span class="hljs-operator">&#x3C;</span>()<span class="hljs-operator">></span> {
    <span class="hljs-comment">// build an agent with private key</span>
    let private_key <span class="hljs-operator">=</span> <span class="hljs-string">"YOUR PRIVATE KEY"</span>; <span class="hljs-comment">// APrivateKey1zkp...</span>
    let account <span class="hljs-operator">=</span> Account::from_private_key(private_key)?;
    let agent <span class="hljs-operator">=</span> Agent::builder().with_account(account).build();
</code></pre><ul><li><p><strong>创建账户</strong>: 使用私钥创建账户对象 <code>Account</code>。</p></li><li><p><strong>创建代理</strong>: 使用账户对象创建代理对象 <code>Agent</code>，用于后续的区块链操作。</p></li></ul><pre data-type="codeBlock" text="    // The build folder is generated by using leo build in the Leo project.
    let path = Path::new(&quot;/contract/build&quot;); // must be an absolute path
    let local_program = ProgramManager::load_program_from_path(path)?;
"><code>    <span class="hljs-comment">// The build folder is generated by using leo build in the Leo project.</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">path</span> = Path::<span class="hljs-title function_ invoke__">new</span>(<span class="hljs-string">"/contract/build"</span>); <span class="hljs-comment">// must be an absolute path</span>
    <span class="hljs-keyword">let</span> <span class="hljs-variable">local_program</span> = ProgramManager::<span class="hljs-title function_ invoke__">load_program_from_path</span>(path)?;
</code></pre><ul><li><p><strong>加载程序</strong>: 使用 <code>ProgramManager</code> 从指定路径加载已经编译好的 Leo 程序。路径必须是绝对路径。</p></li></ul><pre data-type="codeBlock" text="    // deploy program
    let deploy_tx_id = agent.deploy_program(&amp;local_program, 1, None)?;
    println!(&quot;Deployed program with tx id: {}&quot;, deploy_tx_id);
"><code>    <span class="hljs-comment">// deploy program</span>
    let deploy_tx_id <span class="hljs-operator">=</span> agent.deploy_program(<span class="hljs-operator">&#x26;</span>local_program, <span class="hljs-number">1</span>, None)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"Deployed program with tx id: {}"</span>, deploy_tx_id);
</code></pre><ul><li><p><strong>部署程序</strong>: 使用代理对象 <code>agent</code> 部署程序 <code>local_program</code>，并获取部署交易的ID。</p></li></ul><pre data-type="codeBlock" text="    // waiting for broadcast and confirmation
    sleep(Duration::from_secs(60));
"><code>    <span class="hljs-comment">// waiting for broadcast and confirmation</span>
    <span class="hljs-selector-tag">sleep</span>(<span class="hljs-attribute">Duration</span>::<span class="hljs-built_in">from_secs</span>(<span class="hljs-number">60</span>));
</code></pre><ul><li><p><strong>等待交易确认</strong>: 暂停程序60秒，以等待交易的广播和确认。</p></li></ul><pre data-type="codeBlock" text="    // get transaction status
    let status = agent.get_confirmed_transaction(&amp;deploy_tx_id)?;
    println!(&quot;Deployment tx status: \n {status:?}&quot;);
"><code>    <span class="hljs-comment">// get transaction status</span>
    let status <span class="hljs-operator">=</span> agent.get_confirmed_transaction(<span class="hljs-operator">&#x26;</span>deploy_tx_id)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"Deployment tx status: \n {status:?}"</span>);
</code></pre><ul><li><p><strong>获取交易状态</strong>: 使用代理对象 <code>agent</code> 获取部署交易的确认状态，并打印出来。</p></li></ul><pre data-type="codeBlock" text="    // get program id
    let program_id = local_program.id();
    let pm = agent.program(program_id.to_string().as_ref())?;
"><code>    <span class="hljs-comment">// get program id</span>
    let program_id <span class="hljs-operator">=</span> local_program.id();
    let pm <span class="hljs-operator">=</span> agent.program(program_id.to_string().as_ref())?;
</code></pre><ul><li><p><strong>获取程序ID</strong>: 从已加载的程序 <code>local_program</code> 获取程序ID。</p></li><li><p><strong>创建程序管理对象</strong>: 使用代理对象 <code>agent</code> 创建程序管理对象 <code>pm</code>。</p></li></ul><pre data-type="codeBlock" text="    // execute program
    let inputs = vec![&quot;1u32&quot;, &quot;2u32&quot;];
    let exec_tx_id = pm.execute_program(&quot;main&quot;, inputs.into_iter(), 1, None)?;
    println!(&quot;Execute program with tx id : {exec_tx_id}&quot;);
"><code>    <span class="hljs-comment">// execute program</span>
    let inputs <span class="hljs-operator">=</span> vec<span class="hljs-operator">!</span>[<span class="hljs-string">"1u32"</span>, <span class="hljs-string">"2u32"</span>];
    let exec_tx_id <span class="hljs-operator">=</span> pm.execute_program(<span class="hljs-string">"main"</span>, inputs.into_iter(), <span class="hljs-number">1</span>, None)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"Execute program with tx id : {exec_tx_id}"</span>);
</code></pre><ul><li><p><strong>执行程序</strong>: 使用程序管理对象 <code>pm</code> 执行程序的 <code>main</code> 函数，传入输入参数 <code>1u32</code> 和 <code>2u32</code>，并获取执行交易的ID。</p></li></ul><pre data-type="codeBlock" text="    // waiting for broadcast and confirmation
    sleep(Duration::from_secs(60));
"><code>    <span class="hljs-comment">// waiting for broadcast and confirmation</span>
    <span class="hljs-selector-tag">sleep</span>(<span class="hljs-attribute">Duration</span>::<span class="hljs-built_in">from_secs</span>(<span class="hljs-number">60</span>));
</code></pre><ul><li><p><strong>等待交易确认</strong>: 暂停程序60秒，以等待交易的广播和确认。</p></li></ul><pre data-type="codeBlock" text="    // get transaction status
    let status = agent.get_confirmed_transaction(&amp;exec_tx_id)?;
    println!(&quot;Execution tx status: \n{:#?}&quot;, status);
"><code>    <span class="hljs-comment">// get transaction status</span>
    let status <span class="hljs-operator">=</span> agent.get_confirmed_transaction(<span class="hljs-operator">&#x26;</span>exec_tx_id)?;
    println<span class="hljs-operator">!</span>(<span class="hljs-string">"Execution tx status: \n{:#?}"</span>, status);
</code></pre><ul><li><p><strong>获取交易状态</strong>: 使用代理对象 <code>agent</code> 获取执行交易的确认状态，并打印出来。</p></li></ul><pre data-type="codeBlock" text="    Ok(())
}
"><code>    <span class="hljs-built_in">Ok</span>(())
}
</code></pre><ul><li><p><strong>结束程序</strong>: 如果所有操作成功，程序返回 <code>Ok(())</code>。</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">总结</h3><p>通过以上的使用方式学习，我门可以学会在区块链上发起转账和部署执行自定义的 Leo 程序，实现去中心化的应用。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo Oracle JavaScript SDK 的简单使用]]></title>
            <link>https://paragraph.com/@yaakov/aleo-oracle-javascript-sdk</link>
            <guid>mnjZB1SStuUEWSi9vyK1</guid>
            <pubDate>Wed, 24 Jul 2024 07:34:03 GMT</pubDate>
            <description><![CDATA[Aleo Oracle SDK for JavaScript 是一个 Node.js 包。 https://github.com/zkportal/aleo-oracle-sdk-js 这个 SDK 不使用默认导出。 在内部，这个 API 使用 Fetch API。只要你提供 Fetch API 的实现，它可能在任何 JS 环境中使用。 由于客户端允许配置自定义的公证和验证后端，它还允许提供 Fetch 选项的覆盖，用于与这些后端通信 - 详见 OracleClient 构造函数。目录安装常量:DEFAULT_FETCH_OPTIONSDEFAULT_NOTARIZATION_BACKENDSDEFAULT_NOTARIZATION_HEADERSDEFAULT_NOTARIZATION_OPTIONSDEFAULT_VERIFICATION_BACKEND类型:class AttestationErrorclass AttestationIntegrityErrorclass DebugAttestationErrorclass OracleClientconstructorn...]]></description>
            <content:encoded><![CDATA[<p>Aleo Oracle SDK for JavaScript 是一个 Node.js 包。</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/zkportal/aleo-oracle-sdk-js">https://github.com/zkportal/aleo-oracle-sdk-js</a></p><p>这个 SDK 不使用默认导出。</p><p>在内部，这个 API 使用 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>。只要你提供 Fetch API 的实现，它可能在任何 JS 环境中使用。</p><p>由于客户端允许配置自定义的公证和验证后端，它还允许提供 Fetch 选项的覆盖，用于与这些后端通信 - 详见 <code>OracleClient</code> 构造函数。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">目录</h2><ul><li><p>安装</p></li><li><p>常量:</p><ul><li><p><code>DEFAULT_FETCH_OPTIONS</code></p></li><li><p><code>DEFAULT_NOTARIZATION_BACKENDS</code></p></li><li><p><code>DEFAULT_NOTARIZATION_HEADERS</code></p></li><li><p><code>DEFAULT_NOTARIZATION_OPTIONS</code></p></li><li><p><code>DEFAULT_VERIFICATION_BACKEND</code></p></li></ul></li><li><p>类型:</p><ul><li><p>class <code>AttestationError</code></p></li><li><p>class <code>AttestationIntegrityError</code></p></li><li><p>class <code>DebugAttestationError</code></p></li><li><p>class <code>OracleClient</code></p><ul><li><p><em>constructor</em></p></li><li><p><code>notarize</code></p></li><li><p><code>testSelector</code></p></li><li><p><code>enclavesInfo</code></p></li></ul></li><li><p>类型 <code>AttestationRequest</code></p></li><li><p>类型 <code>AttestationResponse</code></p></li><li><p>类型 <code>ClientConfig</code></p></li><li><p>类型 <code>CustomBackendAllowedFetchOptions</code></p></li><li><p>类型 <code>CustomBackendConfig</code></p></li><li><p>类型 <code>DebugRequestResponse</code></p></li><li><p>类型 <code>EnclaveInfo</code></p></li><li><p>类型 <code>EncodingOptions</code></p></li><li><p>类型 <code>InfoOptions</code></p></li><li><p>类型 <code>NotarizationOptions</code></p></li><li><p>类型 <code>OracleData</code></p></li><li><p>类型 <code>PositionInfo</code></p></li><li><p>类型 <code>ProofPositionalInfo</code></p></li><li><p>类型 <code>SgxInfo</code></p></li></ul></li></ul><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">安装</h2><p>通过运行 <code>npm install @zkportal/aleo-oracle-sdk</code> 安装 SDK。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">常量</h2><h3 id="h-defaultfetchoptions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>DEFAULT_FETCH_OPTIONS</code></h3><p>默认的 Fetch API 选项，应用于所有发往公证和验证后端的请求。</p><pre data-type="codeBlock" text="{
  cache: &apos;no-store&apos;,
  mode: &apos;cors&apos;,
  redirect: &apos;follow&apos;,
  referrer: &apos;&apos;,
  keepalive: false,
}
"><code>{
  <span class="hljs-attr">cache:</span> <span class="hljs-string">'no-store'</span>,
  <span class="hljs-attr">mode:</span> <span class="hljs-string">'cors'</span>,
  <span class="hljs-attr">redirect:</span> <span class="hljs-string">'follow'</span>,
  <span class="hljs-attr">referrer:</span> <span class="hljs-string">''</span>,
  <span class="hljs-attr">keepalive:</span> <span class="hljs-literal">false</span>,
}
</code></pre><h3 id="h-defaultnotarizationbackends" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>DEFAULT_NOTARIZATION_BACKENDS</code></h3><p>如果没有向客户端提供 <code>notarizer</code> 配置，将使用的公证后端配置列表。</p><p>类型：[<code>CustomBackendConfig[]</code>](#类型 custombackendconfig)。</p><pre data-type="codeBlock" text="[
  {
    address: &apos;sgx.aleooracle.xyz&apos;,
    port: 443,
    https: true,
    apiPrefix: &apos;&apos;,
    resolve: true,
    init: DEFAULT_FETCH_OPTIONS,
  },
]
"><code>[
  {
    <span class="hljs-attr">address:</span> <span class="hljs-string">'sgx.aleooracle.xyz'</span>,
    <span class="hljs-attr">port:</span> <span class="hljs-number">443</span>,
    <span class="hljs-attr">https:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">apiPrefix:</span> <span class="hljs-string">''</span>,
    <span class="hljs-attr">resolve:</span> <span class="hljs-literal">true</span>,
    <span class="hljs-attr">init:</span> <span class="hljs-string">DEFAULT_FETCH_OPTIONS</span>,
  },
]
</code></pre><h3 id="h-defaultnotarizationheaders" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>DEFAULT_NOTARIZATION_HEADERS</code></h3><p>添加到所有发往证明目标的请求的默认 HTTP 请求头。</p><pre data-type="codeBlock" text="{
  &apos;Accept&apos;: &apos;*/*&apos;,
  &apos;User-Agent&apos;: &apos;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36&apos;,
  &apos;Upgrade-Insecure-Requests&apos;: &apos;1&apos;,
  &apos;DNT&apos;: &apos;1&apos;,
}
"><code>{
  <span class="hljs-string">'Accept'</span>: <span class="hljs-string">'*/*'</span>,
  <span class="hljs-string">'User-Agent'</span>: <span class="hljs-string">'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'</span>,
  <span class="hljs-string">'Upgrade-Insecure-Requests'</span>: <span class="hljs-string">'1'</span>,
  <span class="hljs-string">'DNT'</span>: <span class="hljs-string">'1'</span>,
}
</code></pre><h3 id="h-defaultnotarizationoptions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>DEFAULT_NOTARIZATION_OPTIONS</code></h3><p>类型：`NotarizationOptions`\</p><pre data-type="codeBlock" text="{
  dataShouldMatch: true,
  timeout: 5000,
  maxTimeDeviation: undefined,
}
"><code>{
  <span class="hljs-attr">dataShouldMatch:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">timeout:</span> <span class="hljs-number">5000</span>,
  <span class="hljs-attr">maxTimeDeviation:</span> <span class="hljs-string">undefined</span>,
}
</code></pre><h3 id="h-defaultverificationbackend" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><code>DEFAULT_VERIFICATION_BACKEND</code></h3><p>如果没有向客户端提供 <code>verifier</code> 配置，将使用的公证后端配置列表。</p><p>类型：`CustomBackendConfig`\。</p><pre data-type="codeBlock" text="{
  address: &apos;verifier.aleooracle.xyz&apos;,
  port: 443,
  https: true,
  apiPrefix: &apos;&apos;,
  resolve: true,
  init: DEFAULT_FETCH_OPTIONS,
}
"><code>{
  <span class="hljs-attr">address:</span> <span class="hljs-string">'verifier.aleooracle.xyz'</span>,
  <span class="hljs-attr">port:</span> <span class="hljs-number">443</span>,
  <span class="hljs-attr">https:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">apiPrefix:</span> <span class="hljs-string">''</span>,
  <span class="hljs-attr">resolve:</span> <span class="hljs-literal">true</span>,
  <span class="hljs-attr">init:</span> <span class="hljs-string">DEFAULT_FETCH_OPTIONS</span>,
}
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">类型</h2><h3 id="h-class-attestationerror" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">class <code>AttestationError</code></h3><p>扩展自：<code>Error</code></p><h3 id="h-class-attestationintegrityerror" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">class <code>AttestationIntegrityError</code></h3><p>扩展自：<code>Error</code></p><h3 id="h-class-debugattestationerror" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">class <code>DebugAttestationError</code></h3><p>扩展自：<code>Error</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-class-oracleclient" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">class <code>OracleClient</code></h3><h4 id="h-constructor" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><em>constructor</em></h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h4 id="h-notarize" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><code>notarize</code></h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h4 id="h-testselector" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><code>testSelector</code></h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h4 id="h-enclavesinfo" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><code>enclavesInfo</code></h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-attestationrequest" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>AttestationRequest</code></h3><p>对 HTTPS 资源的公证和证明请求，并使用数据选择器从响应中提取证明数据。还描述了预期的响应格式，以及如何为 Aleo 程序编码提取的证明数据。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-attestationresponse" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>AttestationResponse</code></h3><p>公证后端对证明请求的响应。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-clientconfig" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>ClientConfig</code></h3><p>Oracle 客户端配置对象。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-custombackendallowedfetchoptions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>CustomBackendAllowedFetchOptions</code></h3><pre data-type="codeBlock" text="Omit&lt;RequestInit, &apos;body&apos; | &apos;integrity&apos; | &apos;method&apos;&gt;
"><code>Omit<span class="hljs-operator">&#x3C;</span>RequestInit, <span class="hljs-string">'body'</span> <span class="hljs-operator">|</span> <span class="hljs-string">'integrity'</span> <span class="hljs-operator">|</span> <span class="hljs-string">'method'</span><span class="hljs-operator">></span>
</code></pre><h3 id="h-custombackendconfig" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>CustomBackendConfig</code></h3><p>Oracle 客户端将用于公证/验证的后端配置。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-debugrequestresponse" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>DebugRequestResponse</code></h3><p>用于调试选择器的公证响应。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-enclaveinfo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>EnclaveInfo</code></h3><p>关于公证后端运行的 TEE 的信息。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-encodingoptions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>EncodingOptions</code></h3><p>描述解释提取的证明数据以编码为 Aleo 程序兼容格式的方法。</p><p>参见 Aleo 编码指南。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-infooptions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>InfoOptions</code></h3><p>获取安全区信息请求的选项。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-notarizationoptions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>NotarizationOptions</code></h3><p>公证客户端选项。参见 公证和证明指南。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-oracledata" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>OracleData</code></h3><p>直接用于 Aleo 程序中的证明相关信息。参见 Aleo 编码指南 和 编码文档 以了解这些值的创建方式。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-positioninfo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>PositionInfo</code></h3><p>描述编码为 Aleo 程序格式的属性的位置和长度。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-proofpositionalinfo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>ProofPositionalInfo</code></h3><p>关于 Aleo 编码的证明响应中不同属性位置的信息。计数在 Aleo 的 <code>u128</code> 属性上进行，计数从 0 开始。</p><p>位置不考虑嵌套结构，并且可能会超出 Aleo 允许的类型属性数量限制。</p><p>请参阅编码文档。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><h3 id="h-sgxinfo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">类型 <code>SgxInfo</code></h3><p>关于运行公证后端的 Intel SGX 安全区的信息。包括一些为了方便在 Aleo 程序中使用而编码的额外属性。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">Alt Text</figcaption></figure><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo 中预言机(Oracle)的简单使用]]></title>
            <link>https://paragraph.com/@yaakov/aleo-oracle-2</link>
            <guid>AIEhWo3MnqzTZdVGBwy1</guid>
            <pubDate>Tue, 23 Jul 2024 15:18:10 GMT</pubDate>
            <description><![CDATA[要开始，请按照 SDK 概览 安装 SDK 并创建一个客户端。第一步：识别数据首先，您需要识别要在 Aleo 程序中使用的数据。通常，Oracle SDK 支持任何可以公开访问的静态 HTTPS 网站，或通过提供正确的头部、cookies 和/或请求体来访问。 关于认证动态渲染的内容您想使用的数据必须是“静态渲染”的，这意味着它必须存在于原始 HTTP 响应中。 这意味着您不能使用在网站加载后渲染的数据，例如通过 XHR 或 WebSocket 获取的数据。 但是，您可能可以直接使用网站用来获取数据的 API。一些您可能想在程序中使用的数据示例：法币/加密货币的价格数据银行对账单发票、收据与身份相关的信息，例如年龄或国籍媒体资源在本示例中，我们将使用阿姆斯特丹的天气数据，并将降水量放入 Aleo 程序中。 https://archive-api.open-meteo.com/v1/archive?latitude=42.93869&longitude=-74.18819&start_date=2024-02-28&end_date=2024-02-28&daily=rain_su...]]></description>
            <content:encoded><![CDATA[<p>要开始，请按照 SDK 概览 安装 SDK 并创建一个客户端。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">第一步：识别数据</h2><p>首先，您需要识别要在 Aleo 程序中使用的数据。通常，Oracle SDK 支持任何可以公开访问的静态 HTTPS 网站，或通过提供正确的头部、cookies 和/或请求体来访问。</p><p><strong>关于认证动态渲染的内容</strong></p><blockquote><p>您想使用的数据必须是“静态渲染”的，这意味着它必须存在于原始 HTTP 响应中。</p><p>这意味着您不能使用在网站加载后渲染的数据，例如通过 XHR 或 WebSocket 获取的数据。</p><p>但是，您可能可以直接使用网站用来获取数据的 API。</p></blockquote><p>一些您可能想在程序中使用的数据示例：</p><ul><li><p>法币/加密货币的价格数据</p></li><li><p>银行对账单</p></li><li><p>发票、收据</p></li><li><p>与身份相关的信息，例如年龄或国籍</p></li><li><p>媒体资源</p></li></ul><p>在本示例中，我们将使用阿姆斯特丹的天气数据，并将降水量放入 Aleo 程序中。</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://archive-api.open-meteo.com/v1/archive?latitude=42.93869&amp;longitude=-74.18819&amp;start_date=2024-02-28&amp;end_date=2024-02-28&amp;daily=rain_sum">https://archive-api.open-meteo.com/v1/archive?latitude=42.93869&amp;longitude=-74.18819&amp;start_date=2024-02-28&amp;end_date=2024-02-28&amp;daily=rain_sum</a></p><blockquote><p>强烈建议使用对时间不敏感的历史数据。如果使用实时数据，其他人可能会在使用相同参数请求相同 URL 时看到不同的结果。</p></blockquote><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">白名单</h3><p>公证员维护一个允许认证的主机列表。您可以在 <code>https://sgx.aleooracle.xyz/whitelist</code> 查询该列表。如果您希望将某个主机列入白名单，请联系我们。</p><p>当前白名单（该列表可能已过时，请始终从 URL 查询列表）:</p><pre data-type="codeBlock" text="[
    &quot;google.com&quot;,
    &quot;api-testnet.bybit.com&quot;,
    &quot;verifier.aleooracle.xyz&quot;,
    &quot;api.bitfinex.com&quot;,
    &quot;api.coinbasecloud.net&quot;,
    &quot;api-pub.bitfinex.com&quot;,
    &quot;sgx.aleooracle.xyz&quot;,
    &quot;api.international.coinbase.com&quot;,
    &quot;api.bybit.com&quot;,
    &quot;www.kraken.com&quot;,
    &quot;pro-api.coinmarketcap.com&quot;,
    &quot;docs.aleooracle.xyz&quot;,
    &quot;api.exchange.coinbase.com&quot;,
    &quot;www.okx.com&quot;,
    &quot;data-api.binance.vision&quot;,
    &quot;testnet.binance.vision&quot;,
    &quot;www.coinbase.com&quot;,
    &quot;api.kraken.com&quot;,
    &quot;archive-api.open-meteo.com&quot;,
    &quot;public.bybit.com&quot;,
    &quot;api.prime.coinbase.com&quot;,
    &quot;www.bitstamp.net&quot;,
    &quot;www.bitfinex.com&quot;,
    &quot;api.kucoin.com&quot;,
    &quot;www.kucoin.com&quot;,
    &quot;api.binance.com&quot;,
    &quot;api-futures.kucoin.com&quot;,
    &quot;iapi.kraken.com&quot;,
    &quot;www.bybit.com&quot;
]
"><code><span class="hljs-selector-attr">[    <span class="hljs-string">"google.com"</span>,    <span class="hljs-string">"api-testnet.bybit.com"</span>,    <span class="hljs-string">"verifier.aleooracle.xyz"</span>,    <span class="hljs-string">"api.bitfinex.com"</span>,    <span class="hljs-string">"api.coinbasecloud.net"</span>,    <span class="hljs-string">"api-pub.bitfinex.com"</span>,    <span class="hljs-string">"sgx.aleooracle.xyz"</span>,    <span class="hljs-string">"api.international.coinbase.com"</span>,    <span class="hljs-string">"api.bybit.com"</span>,    <span class="hljs-string">"www.kraken.com"</span>,    <span class="hljs-string">"pro-api.coinmarketcap.com"</span>,    <span class="hljs-string">"docs.aleooracle.xyz"</span>,    <span class="hljs-string">"api.exchange.coinbase.com"</span>,    <span class="hljs-string">"www.okx.com"</span>,    <span class="hljs-string">"data-api.binance.vision"</span>,    <span class="hljs-string">"testnet.binance.vision"</span>,    <span class="hljs-string">"www.coinbase.com"</span>,    <span class="hljs-string">"api.kraken.com"</span>,    <span class="hljs-string">"archive-api.open-meteo.com"</span>,    <span class="hljs-string">"public.bybit.com"</span>,    <span class="hljs-string">"api.prime.coinbase.com"</span>,    <span class="hljs-string">"www.bitstamp.net"</span>,    <span class="hljs-string">"www.bitfinex.com"</span>,    <span class="hljs-string">"api.kucoin.com"</span>,    <span class="hljs-string">"www.kucoin.com"</span>,    <span class="hljs-string">"api.binance.com"</span>,    <span class="hljs-string">"api-futures.kucoin.com"</span>,    <span class="hljs-string">"iapi.kraken.com"</span>,    <span class="hljs-string">"www.bybit.com"</span>]</span>
</code></pre><h2 id="h-http" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">第二步：创建 HTTP 请求获取数据</h2><p>现在您需要创建一个 HTTP 请求，以获取包含您所需数据的返回。</p><p>在我们的示例中，请求非常简单。我们执行一个 GET 请求并期望得到一个 JSON 返回数据。</p><pre data-type="codeBlock" text="$ curl &quot;https://archive-api.open-meteo.com/v1/archive?latitude=42.93869&amp;longitude=-74.18819&amp;start_date=2024-02-28&amp;end_date=2024-02-28&amp;daily=rain_sum&quot;
"><code><span class="hljs-variable">$ </span>curl <span class="hljs-string">"https://archive-api.open-meteo.com/v1/archive?latitude=42.93869&#x26;longitude=-74.18819&#x26;start_date=2024-02-28&#x26;end_date=2024-02-28&#x26;daily=rain_sum"</span>
</code></pre><p>响应：</p><pre data-type="codeBlock" text="{
  &quot;latitude&quot;: 42.917397,
  &quot;longitude&quot;: -74.37686,
  &quot;generationtime_ms&quot;: 3.921985626220703,
  &quot;utc_offset_seconds&quot;: 0,
  &quot;timezone&quot;: &quot;GMT&quot;,
  &quot;timezone_abbreviation&quot;: &quot;GMT&quot;,
  &quot;elevation&quot;: 117.0,
  &quot;daily_units&quot;: {
    &quot;time&quot;: &quot;iso8601&quot;,
    &quot;rain_sum&quot;: &quot;mm&quot;
  },
  &quot;daily&quot;: {
    &quot;time&quot;: [
      &quot;2024-02-28&quot;
    ],
    &quot;rain_sum&quot;: [
      9.90
    ]
  }
}
"><code>{
  "latitude": <span class="hljs-number">42.917397</span>,
  <span class="hljs-string">"longitude"</span>: -<span class="hljs-number">74.37686</span>,
  <span class="hljs-string">"generationtime_ms"</span>: <span class="hljs-number">3.921985626220703</span>,
  <span class="hljs-string">"utc_offset_seconds"</span>: <span class="hljs-number">0</span>,
  <span class="hljs-string">"timezone"</span>: <span class="hljs-string">"GMT"</span>,
  <span class="hljs-string">"timezone_abbreviation"</span>: <span class="hljs-string">"GMT"</span>,
  <span class="hljs-string">"elevation"</span>: <span class="hljs-number">117.0</span>,
  <span class="hljs-string">"daily_units"</span>: {
    "<span class="hljs-selector-tag">time</span>": <span class="hljs-string">"iso8601"</span>,
    <span class="hljs-string">"rain_sum"</span>: <span class="hljs-string">"mm"</span>
  },
  "daily": {
    "<span class="hljs-selector-tag">time</span>": [
      <span class="hljs-string">"2024-02-28"</span>
    ],
    <span class="hljs-string">"rain_sum"</span>: [
      <span class="hljs-number">9.90</span>
    ]
  }
}
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">第三步：从返回数据中选择数据</h2><p>现在我们已经得到了返回数据，并且知道它的样子，是时候从中提取我们在合约中需要的数据，或称为认证数据。</p><p>该 SDK 使用选择器来应用于响应。</p><p>对于 HTML 响应，它使用 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/XPath">XPath</a>。</p><p>对于 JSON，它使用类似于 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://jqlang.github.io/jq/">JQ</a> 查询语法的 JSON 键路径。</p><p>有关示例，请参见 选择器部分。</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">第四步：构建认证请求</h2><p>现在您可以将我们到目前为止所做的一切放入源代码中。</p><p>认证请求描述了对认证目标的公证请求，认证目标应如何响应以及如何解析其响应以提取目标数据。</p><p>认证请求中的所有属性并非都是必需的。</p><p>下面我们将描述每个属性并给出示例。</p><p>您也可以跳转到 认证请求示例 查看我们的天气示例。</p><h3 id="h-url" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">URL</h3><p>待认证资源的 URL - 认证目标。URL 应不包含方案，假定为 HTTPS。</p><p>例子</p><pre data-type="codeBlock" text="archive-api.open-meteo.com/v1/archive?latitude=42.93869&amp;longitude=-74.18819&amp;start_date=2024-02-28&amp;end_date=2024-02-28&amp;daily=rain_sum
"><code>archive<span class="hljs-operator">-</span>api.open-meteo.com/v1<span class="hljs-operator">/</span>archive?latitude<span class="hljs-operator">=</span><span class="hljs-number">42.93869</span><span class="hljs-operator">&#x26;</span>longitude<span class="hljs-operator">=</span><span class="hljs-number">-74.18819</span><span class="hljs-operator">&#x26;</span>start_date<span class="hljs-operator">=</span><span class="hljs-number">2024</span><span class="hljs-operator">-</span>02<span class="hljs-number">-28</span><span class="hljs-operator">&#x26;</span>end_date<span class="hljs-operator">=</span><span class="hljs-number">2024</span><span class="hljs-operator">-</span>02<span class="hljs-number">-28</span><span class="hljs-operator">&#x26;</span>daily<span class="hljs-operator">=</span>rain_sum
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">请求方法</h3><p>用于向认证目标发送请求的 HTTP 方法。</p><p>支持以下方法：</p><ul><li><p><code>GET</code></p></li><li><p><code>POST</code></p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">选择器</h3><p>可选的元素选择器，用于从认证资源中提取数据 - HTML 的 XPath，JSON 的 JSON 键路径。 如果未提供或为空，oracle 将对整个响应进行认证，除非响应大小超过 <code>{{ variables.constants.attestation_text_size_limit }}</code> 的限制。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">响应格式</h3><p>预期的认证目标响应格式。</p><p>支持的值：</p><ul><li><p><code>JSON</code></p></li><li><p><code>HTML</code></p></li></ul><p>在我们的示例中，响应格式是 <code>JSON</code>。</p><h3 id="h-html" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">HTML 结果类型</h3><p>当响应格式为 <code>HTML</code> 时，您还需要指明应用选择器后响应的提取类型。</p><p>支持的值：</p><ul><li><p><code>element</code></p></li><li><p><code>value</code></p></li></ul><p>如果应用选择器后的数据是 <code>&lt;a href=&quot;/test&quot;&gt;Nice link&lt;/a&gt;</code></p><ul><li><p>使用 <code>element</code> 将使 <code>&lt;a href=&quot;/test&quot;&gt;Nice link&lt;/a&gt;</code> 成为认证数据</p></li><li><p>使用 <code>value</code> 将使 <code>Nice link</code> 成为认证数据</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">请求体</h3><p>可用于提供认证目标请求的 POST 请求体。最大允许大小为 <code>{{ variables.constants.attestation_text_size_limit }}</code>。仅当请求方法为 <code>POST</code> 时生效。</p><p>例子</p><pre data-type="codeBlock" text="任何 HTTP 请求体

{&quot;userName&quot;: &quot;user&quot;,&quot;firstName&quot;: &quot;first&quot;,&quot;lastName&quot;: &quot;last&quot;}
"><code>任何 HTTP 请求体

<span class="hljs-punctuation">{</span><span class="hljs-attr">"userName"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"user"</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"firstName"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"first"</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"lastName"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"last"</span><span class="hljs-punctuation">}</span>
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">请求内容类型</h3><p>可用于为认证目标请求提供 Content-Type 请求头。 仅当请求方法为 <code>POST</code> 时生效。</p><p>例子</p><pre data-type="codeBlock" text="application/json
"><code>application/json
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">请求头</h3><p>可选的 HTTP 请求头字典，用于添加到认证目标请求中。 可能包含敏感信息（如 <code>Authorization</code>、<code>X-Auth-Token</code> 或 <code>Cookie</code>）的头部值以及认证目标使用的任何非标准头部值将在认证报告中被替换为 <code>*****</code>。注意，这些头部将按原样用于认证请求。</p><p>SDK 将使用一些默认头部，可以被覆盖。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">编码选项</h3><p>编码选项包含公证后端应如何解释证明数据并将其编码为 Aleo 格式的信息。数据将被编码为 Aleo <code>u128</code>，以便在 Aleo 程序内部使用。</p><p>有关编码的更多信息，请参阅 理解证明响应的指南。</p><p>编码选项包含两个属性：</p><ul><li><p>值类型</p></li><li><p>精度</p></li></ul><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">值类型</h4><p>定义公证后端如何解释证明数据并将其编码为与 Aleo 兼容的格式。</p><p>支持的值类型：</p><ul><li><p><code>string</code> - 提取的值是一个字符串</p></li><li><p><code>int</code> - 提取的值是一个无符号十进制整数，最大为 64 位</p></li><li><p><code>float</code> - 提取的值是一个无符号浮点数，最大为 64 位</p></li></ul><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">精度</h4><p>此属性仅在值类型为 <code>float</code> 时有效。</p><p>由于 Aleo 不支持浮点数，因此需要将其表示为整数。</p><p>定义提取的证明数据的小数部分应有多少位数字。支持的最大精度为 <code>{{ variables.constants.attestation_precision_limit }}</code>。当值类型为 <code>float</code> 时为必填项。</p><p>精度应始终大于或等于提取数字的小数部分的位数。如果数字的小数部分位数多于提供的精度，则将按提供的精度进行切片。</p><p>例子</p><pre data-type="codeBlock" text="精度：3

- 123.45 -&gt; 123.45
- 123.456 -&gt; 123.456
- 123.4567 -&gt; 123.456

精度：0

- 123.4 -&gt; 123
- 123.456 -&gt; 123
"><code>精度：<span class="hljs-number">3</span>

<span class="hljs-operator">-</span> <span class="hljs-number">123.45</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-number">123.45</span>
<span class="hljs-operator">-</span> <span class="hljs-number">123.456</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-number">123.456</span>
<span class="hljs-operator">-</span> <span class="hljs-number">123.4567</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-number">123.456</span>

精度：<span class="hljs-number">0</span>

<span class="hljs-operator">-</span> <span class="hljs-number">123.4</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-number">123</span>
<span class="hljs-operator">-</span> <span class="hljs-number">123.456</span> <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-number">123</span>
</code></pre><p>要了解其对 Aleo 编码的证明数据的影响，请参阅《理解证明响应指南》中的“将证明数据作为浮点数”部分。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">证明请求示例</h3><p>现在我们已经涵盖了所有属性，可以看到天气示例的请求是什么样的。</p><p>例子</p><pre data-type="codeBlock" text="const req = {
    url: &apos;archive-api.open-meteo.com/v1/archive?latitude=42.93869&amp;longitude=-74.18819&amp;start_date=2024-02-28&amp;end_date=2024-02-28&amp;daily=rain_sum&apos;,
    requestMethod: &apos;GET&apos;,
    selector: &apos;daily.rain_sum.[0]&apos;,
    responseFormat: &apos;json&apos;,
    encodingOptions: {
        value: &apos;float&apos;,
        precision: 2
    },
}
"><code>const req = {
    url: <span class="hljs-string">'archive-api.open-meteo.com/v1/archive?latitude=42.93869&#x26;longitude=-74.18819&#x26;start_date=2024-02-28&#x26;end_date=2024-02-28&#x26;daily=rain_sum'</span>,
    requestMethod: <span class="hljs-string">'GET'</span>,
    selector: <span class="hljs-string">'daily.rain_sum.[0]'</span>,
    responseFormat: <span class="hljs-string">'json'</span>,
    encodingOptions: {
        value: <span class="hljs-string">'float'</span>,
        precision: <span class="hljs-number">2</span>
    },
}
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">第五步：请求证明</h2><p>一旦我们有了证明请求，我们就可以在客户端上调用 Notarize。</p><p>它接受请求和公证选项。</p><blockquote><p>您可以使用所选 SDK 中的测试选择器方法来执行无需证明的公证。</p><p>公证后端将尝试请求证明目标并使用提供的选择器提取数据。您可以使用与公证方法相同的请求来查看公证后端是否能够获取您的数据并正确提取数据。您将能够看到完整的响应主体、提取的数据、响应状态代码和错误（如果有）。</p><p>Test Selector 和 Notarize 的区别是，如果提取失败，Notarize 将不会返回响应主体。</p></blockquote><p>公证后端将向证明目标发送请求，使用选择器提取数据，然后创建证明报告。</p><p>结果将返回到 SDK。然后它将结果发送到验证后端，这将确保公证后端正在运行所需的源代码修订，并且信任链没有被破坏。只有这样，SDK 才会返回来自公证调用的证明结果。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">公证选项</h3><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">数据应匹配</h4><p>如果使用多个证明者，客户端将检查所有证明响应中的证明数据是否完全相同。</p><p>如果所有公证后端的证明都成功但结果不匹配，SDK 将返回错误。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">超时</h4><p>证明请求超时（以毫秒为单位）。如果未设置，将使用默认值（取决于环境）。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">最大时间偏差</h4><p>如果使用多个证明者，此选项可控制证明时间戳之间的最大偏差（以毫秒为单位）。</p><ul><li><p>如果设置为 0，则要求所有证明同时完成（不推荐）。请注意，证明时间戳由证明服务器使用服务器时间设置。</p></li><li><p>如果未设置，则不执行时间偏差检查。</p></li><li><p>如果将时间偏差设置为小于一秒，由于 Oracle SDK、公证后端和证明目标之间自然发生的网络延迟，证明可能会失败。</p></li><li><p>如果偏差设置为超过 10 秒（10 * 1000 毫秒），如果其中一个请求花费的时间太长，并且请求的信息已发生更改或不再可用，则证明目标响应可能会彼此不同。</p></li></ul><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo 中预言机(Oracle)的简单介绍]]></title>
            <link>https://paragraph.com/@yaakov/aleo-oracle</link>
            <guid>DxR84M1kbL4q9kLjXKmO</guid>
            <pubDate>Tue, 23 Jul 2024 14:35:13 GMT</pubDate>
            <description><![CDATA[什么是 Oracle？区块链中的 Oracle 是什么？"区块链 Oracle 是将区块链与外部系统连接的实体，从而使智能合约能够根据现实世界的输入和输出执行。" Chainlink: 什么是区块链 Oracle?在区块链领域，信任具有极大的重要性。由于区块链的问题在于达成共识，外部信息不能与交易数据一起提供，因为其他节点会检测到来自“不可信”来源的信息。因此，来自现实世界的信息应该来自一个单一的第三方来源，其可靠性是所有节点都无可争议的：这就是 Oracle。不幸的是，使用 Oracle 引入了一个被称为区块链 Oracle 问题的问题。 区块链 Oracle 问题"区块链 Oracle 问题指的是：无法确认 Oracle 收集的数据的真实性。此外，根据类型的不同，发生故障和故意篡改的可能性也存在。" "由于 Oracle 不是分布式的，它们重新引入了单点故障。此外，由于它们处理的是非确定性数据，其可靠性需要被信任，这取消了信任最小化的点对点交互。通过智能合约将其实现到区块链中，也可能损害用户对区块链的信任，他们认为区块链比传统系统更可靠。" "即使数据是可信和经过验证的，Or...]]></description>
            <content:encoded><![CDATA[<h2 id="h-oracle" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">什么是 Oracle？</h2><p><strong>区块链中的 Oracle 是什么？</strong></p><blockquote><p>&quot;区块链 Oracle 是将区块链与外部系统连接的实体，从而使智能合约能够根据现实世界的输入和输出执行。&quot;</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://chain.link/education/blockchain-oracles">Chainlink: 什么是区块链 Oracle?</a></p></blockquote><p>在区块链领域，信任具有极大的重要性。由于区块链的问题在于达成共识，外部信息不能与交易数据一起提供，因为其他节点会检测到来自“不可信”来源的信息。因此，来自现实世界的信息应该来自一个单一的第三方来源，其可靠性是所有节点都无可争议的：这就是 Oracle。不幸的是，使用 Oracle 引入了一个被称为区块链 Oracle 问题的问题。</p><p><strong>区块链 Oracle 问题</strong></p><blockquote><p>&quot;区块链 Oracle 问题指的是：无法确认 Oracle 收集的数据的真实性。此外，根据类型的不同，发生故障和故意篡改的可能性也存在。&quot;</p><p>&quot;由于 Oracle 不是分布式的，它们重新引入了单点故障。此外，由于它们处理的是非确定性数据，其可靠性需要被信任，这取消了信任最小化的点对点交互。通过智能合约将其实现到区块链中，也可能损害用户对区块链的信任，他们认为区块链比传统系统更可靠。&quot;</p><p>&quot;即使数据是可信和经过验证的，Oracle 也可能由于故障或故意篡改而在智能合约上操作不正确。&quot;</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://encyclopedia.pub/entry/2959">学术社区百科全书: 区块链 Oracle 问题</a></p></blockquote><h2 id="h-aleo-oracle" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Aleo Oracle 解决方案</h2><p>Aleo Oracle 通过使用以下组件组合来尽量减少上述问题：</p><ul><li><p>完全透明；</p></li><li><p>使用 TEE 进行 TLS 响应公证；</p></li><li><p>Aleo 零知识证明；</p></li></ul><p><strong>环境</strong></p><blockquote><p>&quot;可信执行环境（TEE）是主处理器的一个安全区域。它有助于保护加载其中的代码和数据的机密性和完整性。数据完整性防止未经授权的实体从 TEE 外部篡改数据，而代码完整性防止 TEE 内的代码被未经授权的实体替换或修改...&quot;</p><p>&quot;... 允许用户级代码分配私有内存区域，称为飞地，这些区域被设计为受到在更高特权级别运行的进程的保护。作为一个隔离的执行环境，TEE 提供了安全功能，如隔离执行、在 TEE 内执行的应用程序的完整性以及它们资产的机密性。&quot;</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Trusted_execution_environment">维基百科: 可信执行环境</a></p></blockquote><blockquote><p>为了透明，使用 TEE 仍然涉及一定程度的信任，特别是在 TEE 提供者实现隔离计算环境的过程中。 历史上，TEE，如 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/overview.html">Intel 的 SGX</a>，曾面临挑战和漏洞，但它们已被随后解决。</p></blockquote><p>使用 TEE 解决了许多已知的区块链 Oracle 问题。</p><p>通过拥有开源代码、可重现的构建和源代码签名，用户可以验证数据的真实性，并确保 Oracle 正常运行并执行其预期功能。</p><p>Oracle 客户端支持在不同 TEE 中的多个公证后端，从而消除了单点故障。</p><h2 id="h-aleo-oracle" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Aleo Oracle 架构</h2><p>在高层次上，Oracle 架构由以下部分组成：</p><ul><li><p>Oracle 客户端</p></li><li><p>一个或多个运行在 TEE 内的 Oracle 公证后端</p></li><li><p>Oracle 验证后端</p></li><li><p>Oracle Aleo 程序</p></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">架构图</h3><p>以下图表展示了当应用程序使用 Oracle 客户端获取和验证数据时发生的事情，然后展示了应用程序如何在 Aleo 区块链中使用这些数据。</p><p><strong>获取和验证数据的 Oracle 客户端序列图</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">获取和验证数据的 Oracle 客户端序列图</figcaption></figure><p><strong>客户端获取数据后的 Aleo 程序序列图</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="">客户端获取数据后的 Aleo 程序序列图</figcaption></figure><h3 id="h-oracle" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Oracle 客户端</h3><p>Oracle 客户端是一个需要以安全方式从 web2.0 获取数据的 dApp。这很可能是你——开发者！</p><p>通过使用 Oracle SDK，你可以集成请求 web2.0 资源并在 Aleo 区块链和你的 dApp 中使用它们的功能。</p><p>根据具体的使用案例，你可以使用已部署的特定应用程序的 Oracle 程序，也可以开发自己的程序。</p><p>如果你只需要消费已提交到现有 Oracle 程序的数据，则不需要客户端。</p><p>请参阅使用 Oracle获取关于使用 Oracle SDK 和示例的教程。</p><h3 id="h-oracle" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Oracle 后端</h3><p>Oracle 后端接收来自客户端的公证请求。请求包含有关需要公证的 web2.0 资源的信息、如何访问它、如何从资源中提取相关数据并对其进行编码以供后续使用。</p><p>后端执行对指定资源的 HTTPS 请求，接收响应，然后将选择器应用于响应正文，从资源中生成相关信息。</p><p>结果由 TEE 飞地签名和验证。</p><h3 id="h-oracle" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Oracle 验证后端</h3><p>Oracle 验证后端接收公证响应并验证公证报告。步骤之一是验证公证飞地的唯一 ID 是否与预期的匹配。这是通过 Oracle 公证后端的可重现构建完成的。</p><p>该后端还能够解码 Aleo 编码的报告数据，解码和验证 Aleo 编码的公证报告，例如，如果你想验证他人的报告/数据。</p><p>你可以按照本指南自行托管此后端。</p><h3 id="h-oracle" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Oracle 程序</h3><p>一个能够接受 Oracle 公证报告和公证数据的 Aleo 程序。有关其工作原理的更多信息，请参阅关于 Oracle 程序的指南。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo Testnet Beta Prover 节点运行教程]]></title>
            <link>https://paragraph.com/@yaakov/aleo-testnet-beta-prover</link>
            <guid>0B5F7r9LxG7lIganiAF5</guid>
            <pubDate>Tue, 23 Jul 2024 13:21:14 GMT</pubDate>
            <description><![CDATA[Aleo Testnet Beta Prover 节点运行教程证明者在 Aleo 网络中扮演关键角色，他们通过解决 coinbase 谜题并生成 zkProofs 来获得奖励。 本教程适用于在 7 月 1 日至 15 日进行 Testnet Beta 的测试激励活动，但是该激励活动到目前已经截止，但是这个教程和后面主网的挖矿教程类似，不会有太大变化，可以作为后期主网证明者节点部署的参考。 snarkOS 是 zk 应用程序的去中心化操作系统。它构成了 Aleo 网络的基础，验证交易并以可公开验证的方式存储应用程序的加密状态。构建 snarkOS 的指南：要求：操作系统：仅 64 位架构，更新到最新版本以确保安全CPU：32 核（证明者和验证者首选 64 核）内存：客户端 32GB，验证者 64GB（首选 128GB）存储：客户端 300GB，验证者 2TB（首选 4TB）网络：理论上越快越好GPU：支持 CUDA（证明者可选）安装步骤：确保已安装 Rust v1.79+。安装说明可以在 这里 找到。 克隆 GitHub 仓库：git clone --branch mainnet ...]]></description>
            <content:encoded><![CDATA[<h1 id="h-aleo-testnet-beta-prover" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Aleo Testnet Beta Prover 节点运行教程</h1><p>证明者在 Aleo 网络中扮演关键角色，他们通过解决 coinbase 谜题并生成 zkProofs 来获得奖励。</p><p>本教程适用于在 7 月 1 日至 15 日进行 Testnet Beta 的测试激励活动，但是该激励活动到目前已经截止，但是这个教程和后面主网的挖矿教程类似，不会有太大变化，可以作为后期主网证明者节点部署的参考。</p><p>snarkOS 是 zk 应用程序的去中心化操作系统。它构成了 Aleo 网络的基础，验证交易并以可公开验证的方式存储应用程序的加密状态。</p><h3 id="h-snarkos" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">构建 snarkOS 的指南：</h3><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">要求：</h4><ul><li><p>操作系统：仅 64 位架构，更新到最新版本以确保安全</p></li><li><p>CPU：32 核（证明者和验证者首选 64 核）</p></li><li><p>内存：客户端 32GB，验证者 64GB（首选 128GB）</p></li><li><p>存储：客户端 300GB，验证者 2TB（首选 4TB）</p></li><li><p>网络：理论上越快越好</p></li><li><p>GPU：支持 CUDA（证明者可选）</p></li></ul><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">安装步骤：</h4><p>确保已安装 Rust v1.79+。安装说明可以在 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.rust-lang.org/learn/get-started">这里</a> 找到。</p><p>克隆 GitHub 仓库：</p><pre data-type="codeBlock" text="git clone --branch mainnet --single-branch https://github.com/AleoNet/snarkOS.git
"><code>git clone <span class="hljs-operator">-</span><span class="hljs-operator">-</span>branch mainnet <span class="hljs-operator">-</span><span class="hljs-operator">-</span>single<span class="hljs-operator">-</span>branch https:<span class="hljs-comment">//github.com/AleoNet/snarkOS.git</span>
</code></pre><p>进入 snarkOS 目录：</p><pre data-type="codeBlock" text="cd snarkOS
git checkout tags/testnet-beta
"><code><span class="hljs-built_in">cd</span> snarkOS
git checkout tags/testnet-beta
</code></pre><p>[对于 Ubuntu 用户] 运行帮助脚本：</p><pre data-type="codeBlock" text="./build_ubuntu.sh
"><code>./build_ubuntu.sh
</code></pre><p>安装 snarkOS：</p><pre data-type="codeBlock" text="cargo install --locked --path .
"><code>cargo install <span class="hljs-operator">-</span><span class="hljs-operator">-</span>locked <span class="hljs-operator">-</span><span class="hljs-operator">-</span>path .
</code></pre><p>确保路由器和操作系统防火墙上打开端口 4130/tcp 和 3030/tcp。</p><h3 id="h-aleo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">运行 Aleo 节点：</h3><h4 id="h-aleo" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">运行 Aleo 客户端：</h4><p>按照安装说明进行操作。</p><p>启动客户端节点：</p><pre data-type="codeBlock" text="./run-client.sh
"><code>./run<span class="hljs-operator">-</span>client.sh
</code></pre><h4 id="h-aleo" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">运行 Aleo 证明者：</h4><p>按照安装说明进行操作。</p><p>生成 Aleo 账户地址：</p><pre data-type="codeBlock" text="snarkos account new
"><code>snarkos account <span class="hljs-keyword">new</span>
</code></pre><p>保存私钥、查看密钥和地址。</p><p>启动证明节点：</p><pre data-type="codeBlock" text="./run-prover.sh
"><code>./run<span class="hljs-operator">-</span>prover.sh
</code></pre><p>在提示时输入您的 Aleo 私钥。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">命令行界面：</h3><p>要使用自定义设置运行节点，请参考 snarkOS CLI 中可用的选项和标志。</p><p>使用 snarkos --help 查看完整的 CLI 标志和选项列表：</p><pre data-type="codeBlock" text="snarkOS
The Aleo Team &lt;hello@aleo.org&gt;

USAGE:
    snarkos [OPTIONS] &lt;SUBCOMMAND&gt;

OPTIONS:
    -h, --help                     打印帮助信息
    -v, --verbosity &lt;VERBOSITY&gt;    指定详细程度 [选项: 0, 1, 2, 3] [默认: 2]

SUBCOMMANDS:
    account    管理 Aleo 账户的命令
    clean      清理 snarkOS 节点存储
    help       打印此消息或给定子命令的帮助信息
    start      启动 snarkOS 节点
    update     更新 snarkOS
"><code>snarkOS
The Aleo Team <span class="hljs-operator">&#x3C;</span>hello@aleo.org>

USAGE:
    snarkos [OPTIONS] <span class="hljs-operator">&#x3C;</span>SUBCOMMAND<span class="hljs-operator">></span>

OPTIONS:
    <span class="hljs-operator">-</span>h, <span class="hljs-operator">-</span><span class="hljs-operator">-</span>help                     打印帮助信息
    <span class="hljs-operator">-</span>v, <span class="hljs-operator">-</span><span class="hljs-operator">-</span>verbosity <span class="hljs-operator">&#x3C;</span>VERBOSITY<span class="hljs-operator">></span>    指定详细程度 [选项: <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] [默认: <span class="hljs-number">2</span>]

SUBCOMMANDS:
    account    管理 Aleo 账户的命令
    clean      清理 snarkOS 节点存储
    help       打印此消息或给定子命令的帮助信息
    start      启动 snarkOS 节点
    update     更新 snarkOS
</code></pre><p>以下是 snarkos start 命令的选项：</p><pre data-type="codeBlock" text="USAGE:
    snarkos start [OPTIONS]

OPTIONS:
        --network &lt;NETWORK_ID&gt;                  指定此节点的网络 ID [默认: 3]
        
        --validator                             指定此节点为验证者
        --prover                                指定此节点为证明者
        --client                                指定此节点为客户端
        
        --private-key &lt;PRIVATE_KEY&gt;             指定节点账户的私钥
        --private-key-file &lt;PRIVATE_KEY_FILE&gt;   指定包含节点账户私钥的文件路径
        
        --node &lt;IP:PORT&gt;                        指定节点服务器的 IP 地址和端口 [默认: 0.0.0.0:4130]
        --connect &lt;IP:PORT&gt;                     指定要连接的对等节点的 IP 地址和端口
 
        --rest &lt;REST&gt;                           指定 REST 服务器的 IP 地址和端口 [默认: 0.0.0.0:3030]
        --norest                                如果设置此标志，节点将不会初始化 REST 服务器
        
        --nodisplay                             如果设置此标志，节点将不会渲染显示
        --verbosity &lt;VERBOSITY_LEVEL&gt;           指定节点的详细程度 [选项: 0, 1, 2, 3] [默认: 2]
        --logfile &lt;PATH&gt;                        指定日志存储的文件路径 [默认: /tmp/snarkos.log]
        
        --dev &lt;NODE_ID&gt;                         启用开发模式，指定此节点的唯一 ID
"><code>USAGE:
    snarkos start [OPTIONS]

OPTIONS:
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>network <span class="hljs-operator">&#x3C;</span>NETWORK_ID<span class="hljs-operator">></span>                  指定此节点的网络 ID [默认: <span class="hljs-number">3</span>]
        
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>validator                             指定此节点为验证者
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>prover                                指定此节点为证明者
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>client                                指定此节点为客户端
        
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key <span class="hljs-operator">&#x3C;</span>PRIVATE_KEY<span class="hljs-operator">></span>             指定节点账户的私钥
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">-</span>file <span class="hljs-operator">&#x3C;</span>PRIVATE_KEY_FILE<span class="hljs-operator">></span>   指定包含节点账户私钥的文件路径
        
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>node <span class="hljs-operator">&#x3C;</span>IP:PORT<span class="hljs-operator">></span>                        指定节点服务器的 IP 地址和端口 [默认: <span class="hljs-number">0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>:<span class="hljs-number">4130</span>]
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>connect <span class="hljs-operator">&#x3C;</span>IP:PORT<span class="hljs-operator">></span>                     指定要连接的对等节点的 IP 地址和端口
 
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rest <span class="hljs-operator">&#x3C;</span>REST<span class="hljs-operator">></span>                           指定 REST 服务器的 IP 地址和端口 [默认: <span class="hljs-number">0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>:<span class="hljs-number">3030</span>]
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>norest                                如果设置此标志，节点将不会初始化 REST 服务器
        
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>nodisplay                             如果设置此标志，节点将不会渲染显示
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>verbosity <span class="hljs-operator">&#x3C;</span>VERBOSITY_LEVEL<span class="hljs-operator">></span>           指定节点的详细程度 [选项: <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] [默认: <span class="hljs-number">2</span>]
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>logfile <span class="hljs-operator">&#x3C;</span>PATH<span class="hljs-operator">></span>                        指定日志存储的文件路径 [默认: <span class="hljs-operator">/</span>tmp<span class="hljs-operator">/</span>snarkos.log]
        
        <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-operator">&#x3C;</span>NODE_ID<span class="hljs-operator">></span>                         启用开发模式，指定此节点的唯一 ID
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">开发指南：</h3><p>快速开始。 在第一个终端中，运行以下命令启动第一个验证者：</p><pre data-type="codeBlock" text="cargo run --release -- start --nodisplay --dev 0 --validator
"><code>cargo run <span class="hljs-operator">-</span><span class="hljs-operator">-</span>release <span class="hljs-operator">-</span><span class="hljs-operator">-</span> start <span class="hljs-operator">-</span><span class="hljs-operator">-</span>nodisplay <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-number">0</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>validator
</code></pre><p>在第二个终端中，运行以下命令启动第二个验证者：</p><pre data-type="codeBlock" text="cargo run --release -- start --nodisplay --dev 1 --validator
"><code>cargo run <span class="hljs-operator">-</span><span class="hljs-operator">-</span>release <span class="hljs-operator">-</span><span class="hljs-operator">-</span> start <span class="hljs-operator">-</span><span class="hljs-operator">-</span>nodisplay <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-number">1</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>validator
</code></pre><p>在第三个终端中，运行以下命令启动第三个验证者：</p><pre data-type="codeBlock" text="cargo run --release -- start --nodisplay --dev 2 --validator
"><code>cargo run <span class="hljs-operator">-</span><span class="hljs-operator">-</span>release <span class="hljs-operator">-</span><span class="hljs-operator">-</span> start <span class="hljs-operator">-</span><span class="hljs-operator">-</span>nodisplay <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-number">2</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>validator
</code></pre><p>在第四个终端中，运行以下命令启动第四个验证者：</p><pre data-type="codeBlock" text="cargo run --release -- start --nodisplay --dev 3 --validator
"><code>cargo run <span class="hljs-operator">-</span><span class="hljs-operator">-</span>release <span class="hljs-operator">-</span><span class="hljs-operator">-</span> start <span class="hljs-operator">-</span><span class="hljs-operator">-</span>nodisplay <span class="hljs-operator">-</span><span class="hljs-operator">-</span>dev <span class="hljs-number">3</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>validator
</code></pre><p>从这里开始，可以使用此过程进一步启动证明者和客户端。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">操作：</h3><p>从 0 开始初始化节点，并为每个新节点递增 1 是很重要的。 以下是初始化节点的选项列表（将 替换为从 0 开始的数字）： cargo run --release -- start --nodisplay --dev &lt;NODE_ID&gt; --validator
cargo run --release -- start --nodisplay --dev &lt;NODE_ID&gt; --prover
cargo run --release -- start --nodisplay --dev &lt;NODE_ID&gt; --client
cargo run --release -- start --nodisplay --dev &lt;NODE_ID&gt;
当未指定节点类型时，节点将默认为 --client。 本地开发网络： 安装 tmux。要使用脚本运行本地开发网络，请先安装 tmux。 启动本地开发网络。要启动本地开发网络，请运行： ./devnet.sh
按照终端中的说明启动开发网络。 查看本地开发网络。切换节点（前进）。要切换到本地开发网络中的下一个节点，请运行： Ctrl+b n
切换节点（向后）。要切换到本地开发网络中的上一个节点，请运行： Ctrl+b p
选择节点（选择树）。要在本地开发网络中选择一个节点，请运行： Ctrl+b w
手动选择节点。要在本地开发网络中手动选择节点，请运行： Ctrl+b :select-window -t {NODE_ID}
停止本地开发网络。要停止本地开发网络，请运行： Ctrl+b :kill-session
然后，按 Enter。 清理。要清理节点存储，请运行： cargo run --release -- clean --dev &lt;NODE_ID&gt;
本指南涵盖了安装和使用 snarkOS 以参与 Aleo 测试网 Beta 证明者激励计划的基本步骤。按照提供的详细说明，您可以设置并运行 Aleo 节点，无论是作为客户端还是证明者，并为验证 coinbase 奖励机制做出贡献。 注意：以上的方式是作为 Solo 模式参与的证明者，从目前的测试网运行结果来看，参与的挖矿难度特别高，如果不是持有大量机器，可以考虑加入矿池确保能够获得奖励。 <strong>Aleo 官方链接：</strong> <em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a> <em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a> <em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a> Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Leo 中 Finalize 语法的重大更新]]></title>
            <link>https://paragraph.com/@yaakov/leo-finalize</link>
            <guid>ByxDNKlmjzRYwZJP4cOq</guid>
            <pubDate>Tue, 23 Jul 2024 08:12:33 GMT</pubDate>
            <description><![CDATA[Leo 中 Finalize 语法的重大更新在 Leo 编程语言中，Finalize 是一种机制，用于在智能合约执行结束时对合约状态进行最终的处理和清理。这种方法确保合约在完成所有操作后，能够正确地更新和持久化状态，并执行任何必要的清理工作。 但是在最新的 Leo 代码中 Finalize 语法已经废弃了，这里在最新的 Testbeta 网络中得到了验证。Async/Await 机制用于替代传统的 Finalize 方法，以简化和优化智能合约的状态更新和清理过程。这种方式通过异步编程模型，使代码更易读、更高效，并且避免了传统 Finalize 方法中的一些局限性。Leo 中的 Async/Await概念介绍Async：定义一个异步函数，该函数可以包含异步操作。异步函数不会立即执行，而是返回一个 Future 对象，当需要结果时，可以等待该 Future 完成。Await：用于等待异步函数的执行，直到异步操作完成，并返回结果。主要优点简化代码结构：Async/Await 使异步代码看起来像同步代码一样，减少了回调地狱和复杂的状态管理。提高性能：通过异步编程模型，可以在等待异步操作完...]]></description>
            <content:encoded><![CDATA[<h1 id="h-leo-finalize" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Leo 中 Finalize 语法的重大更新</h1><p>在 Leo 编程语言中，<code>Finalize</code> 是一种机制，用于在智能合约执行结束时对合约状态进行最终的处理和清理。这种方法确保合约在完成所有操作后，能够正确地更新和持久化状态，并执行任何必要的清理工作。</p><p>但是在最新的 Leo 代码中 <code>Finalize</code> 语法已经废弃了，这里在最新的 <code>Testbeta</code> 网络中得到了验证。<code>Async/Await</code> 机制用于替代传统的 <code>Finalize</code> 方法，以简化和优化智能合约的状态更新和清理过程。这种方式通过异步编程模型，使代码更易读、更高效，并且避免了传统 <code>Finalize</code> 方法中的一些局限性。</p><h3 id="h-leo-asyncawait" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Leo 中的 Async/Await</h3><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">概念介绍</h4><ul><li><p><strong>Async</strong>：定义一个异步函数，该函数可以包含异步操作。异步函数不会立即执行，而是返回一个 <code>Future</code> 对象，当需要结果时，可以等待该 <code>Future</code> 完成。</p></li><li><p><strong>Await</strong>：用于等待异步函数的执行，直到异步操作完成，并返回结果。</p></li></ul><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">主要优点</h4><ol><li><p><strong>简化代码结构</strong>：<code>Async/Await</code> 使异步代码看起来像同步代码一样，减少了回调地狱和复杂的状态管理。</p></li><li><p><strong>提高性能</strong>：通过异步编程模型，可以在等待异步操作完成时，执行其他任务，提高合约的执行效率。</p></li><li><p><strong>避免 Finalize 局限</strong>：直接在合约执行过程中处理状态更新和清理，避免了 <code>Finalize</code> 方法的额外复杂性。</p></li></ol><h3 id="h-finalize-asyncawait" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Finalize 和 Async/Await 在实际使用中的区别</h3><ul><li><p>旧版本的 Finalize 语法</p></li></ul><pre data-type="codeBlock" text="program test1.aleo {

    // 示例映射数据以存储全局状态
    mapping data: u32 =&gt; u32; 

    // 执行链上逻辑的异步过渡
    transition main(public x: u32) -&gt; u32 {
    
        // 链下逻辑：根据输入 x 计算一个值
        let off_chain_result: u32 = compute_off_chain(x);

        // 链上逻辑：使用链下结果更新全局状态
        return off_chain_result then finalize (off_chain_result));
        
    }

    // 异步函数以 finalize 更新链上的全局状态
    finalize main (off_chain_result: u32) {
    
        // 将 off_chain_result 值加到 x_1
        let x_1: u32 = off_chain_result + 2u32;

        // 将 off_chain_result 值加到 x_2
        let x_2: u32 = off_chain_result + 5u32;

        // 条件语句：检查 x_1 是否大于 x_2
        // 如果是，则将 x_1 输出，否则将 x_2 输出到映射 (data)
        let final_value: u32 = (x_1 &gt; x_2) ? x_1 : x_2;

        // 设置映射中的值
        Mapping::set(data, 0u32, final_value);
    }

    // 链下函数，根据输入 x 计算一个值
    function compute_off_chain(x: u32) -&gt; u32 {
    
        // 简单计算：将输入值加倍
        return x * 2u32;
        
    }
}
"><code>program test1.aleo {

    <span class="hljs-comment">// 示例映射数据以存储全局状态</span>
    <span class="hljs-keyword">mapping</span> data: u32 <span class="hljs-operator">=</span><span class="hljs-operator">></span> u32; 

    <span class="hljs-comment">// 执行链上逻辑的异步过渡</span>
    transition main(<span class="hljs-keyword">public</span> x: u32) <span class="hljs-operator">-</span><span class="hljs-operator">></span> u32 {
    
        <span class="hljs-comment">// 链下逻辑：根据输入 x 计算一个值</span>
        let off_chain_result: u32 <span class="hljs-operator">=</span> compute_off_chain(x);

        <span class="hljs-comment">// 链上逻辑：使用链下结果更新全局状态</span>
        <span class="hljs-keyword">return</span> off_chain_result then finalize (off_chain_result));
        
    }

    <span class="hljs-comment">// 异步函数以 finalize 更新链上的全局状态</span>
    finalize main (off_chain_result: u32) {
    
        <span class="hljs-comment">// 将 off_chain_result 值加到 x_1</span>
        let x_1: u32 <span class="hljs-operator">=</span> off_chain_result <span class="hljs-operator">+</span> 2u32;

        <span class="hljs-comment">// 将 off_chain_result 值加到 x_2</span>
        let x_2: u32 <span class="hljs-operator">=</span> off_chain_result <span class="hljs-operator">+</span> 5u32;

        <span class="hljs-comment">// 条件语句：检查 x_1 是否大于 x_2</span>
        <span class="hljs-comment">// 如果是，则将 x_1 输出，否则将 x_2 输出到映射 (data)</span>
        let final_value: u32 <span class="hljs-operator">=</span> (x_1 <span class="hljs-operator">></span> x_2) ? x_1 : x_2;

        <span class="hljs-comment">// 设置映射中的值</span>
        Mapping::set(data, 0u32, final_value);
    }

    <span class="hljs-comment">// 链下函数，根据输入 x 计算一个值</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compute_off_chain</span>(<span class="hljs-params">x: u32</span>) -> <span class="hljs-title">u32</span> </span>{
    
        <span class="hljs-comment">// 简单计算：将输入值加倍</span>
        <span class="hljs-keyword">return</span> x <span class="hljs-operator">*</span> 2u32;
        
    }
}
</code></pre><ul><li><p>最新的 Async/Await 语法</p></li></ul><pre data-type="codeBlock" text="program test1.aleo {

    // 示例映射数据以存储全局状态
    mapping data: u32 =&gt; u32; 

    // 执行链上逻辑的异步过渡
    async transition main(public x: u32) -&gt; (u32, Future) {
    
        // 链下逻辑：根据输入 x 计算一个值
        let off_chain_result: u32 = compute_off_chain(x);

        // 链上逻辑：使用链下结果更新全局状态
        return (off_chain_result, finalize_update(off_chain_result));
        
    }

    // 异步函数以 finalize 更新链上的全局状态
    async function finalize_update(off_chain_result: u32) {
    
        // 将 off_chain_result 值加到 x_1
        let x_1: u32 = off_chain_result + 2u32;

        // 将 off_chain_result 值加到 x_2
        let x_2: u32 = off_chain_result + 5u32;

        // 条件语句：检查 x_1 是否大于 x_2
        // 如果是，则将 x_1 输出，否则将 x_2 输出到映射 (data)
        let final_value: u32 = (x_1 &gt; x_2) ? x_1 : x_2;

        // 设置映射中的值
        Mapping::set(data, 0u32, final_value);
        
    }

    // 链下函数，根据输入 x 计算一个值
    function compute_off_chain(x: u32) -&gt; u32 {
    
        // 简单计算：将输入值加倍
        return x * 2u32;
        
    }
}
"><code>program test1.aleo {

    <span class="hljs-comment">// 示例映射数据以存储全局状态</span>
    <span class="hljs-keyword">mapping</span> data: u32 <span class="hljs-operator">=</span><span class="hljs-operator">></span> u32; 

    <span class="hljs-comment">// 执行链上逻辑的异步过渡</span>
    async transition main(<span class="hljs-keyword">public</span> x: u32) <span class="hljs-operator">-</span><span class="hljs-operator">></span> (u32, Future) {
    
        <span class="hljs-comment">// 链下逻辑：根据输入 x 计算一个值</span>
        let off_chain_result: u32 <span class="hljs-operator">=</span> compute_off_chain(x);

        <span class="hljs-comment">// 链上逻辑：使用链下结果更新全局状态</span>
        <span class="hljs-keyword">return</span> (off_chain_result, finalize_update(off_chain_result));
        
    }

    <span class="hljs-comment">// 异步函数以 finalize 更新链上的全局状态</span>
    async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">finalize_update</span>(<span class="hljs-params">off_chain_result: u32</span>) </span>{
    
        <span class="hljs-comment">// 将 off_chain_result 值加到 x_1</span>
        let x_1: u32 <span class="hljs-operator">=</span> off_chain_result <span class="hljs-operator">+</span> 2u32;

        <span class="hljs-comment">// 将 off_chain_result 值加到 x_2</span>
        let x_2: u32 <span class="hljs-operator">=</span> off_chain_result <span class="hljs-operator">+</span> 5u32;

        <span class="hljs-comment">// 条件语句：检查 x_1 是否大于 x_2</span>
        <span class="hljs-comment">// 如果是，则将 x_1 输出，否则将 x_2 输出到映射 (data)</span>
        let final_value: u32 <span class="hljs-operator">=</span> (x_1 <span class="hljs-operator">></span> x_2) ? x_1 : x_2;

        <span class="hljs-comment">// 设置映射中的值</span>
        Mapping::set(data, 0u32, final_value);
        
    }

    <span class="hljs-comment">// 链下函数，根据输入 x 计算一个值</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compute_off_chain</span>(<span class="hljs-params">x: u32</span>) -> <span class="hljs-title">u32</span> </span>{
    
        <span class="hljs-comment">// 简单计算：将输入值加倍</span>
        <span class="hljs-keyword">return</span> x <span class="hljs-operator">*</span> 2u32;
        
    }
}
</code></pre><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">关键概念</h4><ol><li><p>异步函数和过渡：</p><ul><li><p>异步函数可以定义为异步运行。这些函数返回一个 Future，表示将来某个时间点将执行的代码。</p></li><li><p>异步过渡是特殊类型的异步函数，可以调用它们来在区块链上执行状态更改。</p></li></ul></li><li><p>Futures：</p><ul><li><p>Future 是表示将来某个时间点可用值的对象。在 async/await 语法中，函数不直接返回值；它们返回 Futures。</p></li></ul></li></ol><h4 id="h-asyncawait" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Async/Await 语法规则</h4><ol><li><p>调用异步函数：</p><ul><li><p>只能在异步过渡内部调用异步函数。</p></li><li><p>异步函数不能直接返回值；它们返回一个 Future。</p></li></ul></li><li><p>异步过渡：</p><ul><li><p>不能在条件块内调用异步过渡。</p></li><li><p>异步过渡调用返回一个可选值，并且必须返回一个单一的 Future。</p></li><li><p>异步过渡调用生成的 Future 不能被返回。</p></li></ul></li><li><p>处理 Futures：</p><ul><li><p>Future 可以传递给异步函数调用，必须等待它。</p></li><li><p>所有 Futures 必须由异步函数调用消费或作为输出返回。</p></li></ul></li></ol><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">总结</h3><p>Leo 语言通过引入 <code>Async/Await</code> 机制，简化了智能合约中异步操作的编写和管理过程。相比传统的 <code>Finalize</code> 方法，<code>Async/Await</code> 提供了一种更自然、更高效的方式来处理状态更新和清理，提高了代码的可读性和执行效率。</p><p>希望这些解释和示例能够帮助你更好地理解和使用 Leo 中的 <code>Async/Await</code> 特性。如果有具体问题或需求，请随时进一步讨论或提供详细信息。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[使用 Zpass 实现简单的年龄验证程序]]></title>
            <link>https://paragraph.com/@yaakov/zpass</link>
            <guid>iYqnnwgqp6JH6FExegLT</guid>
            <pubDate>Tue, 23 Jul 2024 07:43:50 GMT</pubDate>
            <description><![CDATA[Zpass 是一种基于零知识证明（Zero-Knowledge Proof, ZKP）技术的协议，用于验证身份信息，同时保护用户的隐私。在 Zpass 中，用户可以通过零知识证明的方式向验证者证明某些信息的真实性，而无需透露实际的详细信息。这种技术可以应用于多种场景，如年龄验证、资格证明、访问控制等。核心概念零知识证明（Zero-Knowledge Proof）： 零知识证明是一种密码学技术，允许证明者（Prover）向验证者（Verifier）证明某个声明是真实的，而无需提供任何除了声明真实性以外的额外信息。验证者可以确信声明的真实性，但不会得到任何其他的信息。凭证（Credential）： 凭证是一种包含用户身份信息的数据结构。在 Zpass 协议中，凭证通常由一个可信的签发机构（Issuer）签发，并包含用户的某些属性（如出生日期、国籍等）。签发机构（Issuer）： 签发机构是一个可信的实体，如政府、公司等，负责签发凭证。凭证包含签发机构的签名，以证明其真实性。验证者（Verifier）： 验证者是需要验证用户身份信息的实体。在 Zpass 协议中，验证者通过验证凭证的签...]]></description>
            <content:encoded><![CDATA[<p>Zpass 是一种基于零知识证明（Zero-Knowledge Proof, ZKP）技术的协议，用于验证身份信息，同时保护用户的隐私。在 Zpass 中，用户可以通过零知识证明的方式向验证者证明某些信息的真实性，而无需透露实际的详细信息。这种技术可以应用于多种场景，如年龄验证、资格证明、访问控制等。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">核心概念</h3><ol><li><p><strong>零知识证明（Zero-Knowledge Proof）</strong>： 零知识证明是一种密码学技术，允许证明者（Prover）向验证者（Verifier）证明某个声明是真实的，而无需提供任何除了声明真实性以外的额外信息。验证者可以确信声明的真实性，但不会得到任何其他的信息。</p></li><li><p><strong>凭证（Credential）</strong>： 凭证是一种包含用户身份信息的数据结构。在 Zpass 协议中，凭证通常由一个可信的签发机构（Issuer）签发，并包含用户的某些属性（如出生日期、国籍等）。</p></li><li><p><strong>签发机构（Issuer）</strong>： 签发机构是一个可信的实体，如政府、公司等，负责签发凭证。凭证包含签发机构的签名，以证明其真实性。</p></li><li><p><strong>验证者（Verifier）</strong>： 验证者是需要验证用户身份信息的实体。在 Zpass 协议中，验证者通过验证凭证的签名和零知识证明来确认用户的身份信息，而不需要知道具体的细节。</p></li></ol><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">典型应用场景</h3><ol><li><p><strong>年龄验证</strong>： 用户可以通过 Zpass 协议向验证者证明自己超过某个年龄（如18岁），而无需透露具体的出生日期。</p></li><li><p><strong>访问控制</strong>： 用户可以证明自己拥有某些权限（如会员资格、访问权限等），而无需透露具体的权限细节或身份信息。</p></li><li><p><strong>资格证明</strong>： 用户可以证明自己具有某些资格（如学历、证书等），而无需透露具体的资格细节。</p></li></ol><h3 id="h-zpass" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Zpass 的优势</h3><ol><li><p><strong>隐私保护</strong>： 用户不需要透露具体的身份信息，只需提供零知识证明，验证者就可以确认用户身份的真实性。</p></li><li><p><strong>安全性</strong>： 凭证由可信的签发机构签发，并使用加密技术保护，确保凭证的真实性和完整性。</p></li><li><p><strong>灵活性</strong>： Zpass 可以应用于多种场景，包括年龄验证、访问控制、资格证明等，具有广泛的适用性。</p></li></ol><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">例子</h3><p>假设有一个年龄验证的例子，如前面的代码所示，Zpass 协议可以如下工作：</p><ol><li><p><strong>签发凭证</strong>： 签发机构签发包含用户出生日期的凭证，并用自己的私钥对凭证进行签名。</p></li><li><p><strong>生成零知识证明</strong>： 用户根据自己的出生日期生成零知识证明，证明自己年满18岁，但不透露具体的出生日期。</p></li><li><p><strong>验证零知识证明</strong>： 验证者接收到用户提供的零知识证明和凭证，验证凭证的签名和零知识证明的有效性，从而确认用户年满18岁。</p></li></ol><p>以下是具体的代码实现：</p><pre data-type="codeBlock" text="program age_verification.aleo {

    // 时间戳辅助函数
    struct date_time {
        seconds: u8,        // 秒
        minutes: u8,        // 分钟
        hours: u8,          // 小时
        day: u8,            // 日
        month: u32,         // 月
        year: u32,          // 年
    }

    function timestamp_to_datetime(t: u32) -&gt; date_time {
        let seconds: u32 = t % 60u32;
        t /= 60u32;

        let minutes: u32 = t % 60u32;
        t /= 60u32;

        let hours: u32 = t % 24u32;
        t /= 24u32;

        let a: u32 = (4u32 * t + 102032u32) / 146097u32 + 15u32;
        let b: u32 = t + 2442113u32 + a - (a / 4u32);
        let c: u32 = (20u32 * b - 2442u32) / 7305u32;
        let d: u32 = b - 365u32 * c - (c / 4u32);
        let e: u32 = d * 1000u32 / 30601u32;
        let f: u32 = d - e * 30u32 - e * 601u32 / 1000u32;
        let g: u32 = 4716u32;
        let h: u32 = 1u32;

        if (e &gt; 13u32) {
            g = 4715u32;
            h = 13u32;
        }

        c -= g;
        e -= h;

        let dt: date_time = date_time {
            seconds: seconds as u8,
            minutes: minutes as u8,
            hours: hours as u8,
            day: f as u8,
            month: e as u32,
            year: c as u32,
        };

        return dt;
    }

    function datetime_to_timestamp(dt: date_time) -&gt; u32 {
        let y: u32 = dt.year as u32;
        let m: u32 = dt.month as u32;
        let d: u32 = dt.day as u32;

        if (m &lt;= 2u32) {
            m += 12u32;
            y -= 1u32;
        }

        let t: u32 = (365u32 * y) + (y / 4u32) - (y / 100u32) + (y / 400u32);
        t += (30u32 * m) + (3u32 * (m + 1u32) / 5u32) + d;
        t -= 719561u32;
        t *= 86400u32;
        t += (3600u32 * dt.hours as u32) + (60u32 * dt.minutes as u32) + dt.seconds as u32;

        return t;
    }

    struct Credentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    inline get_psd_hash(msg: Credentials) -&gt; field {
        return Poseidon2::hash_to_field(msg);
    }

    inline get_bhp_hash(msg: Credentials) -&gt; field {
        return BHP1024::hash_to_field(msg);
    }

    function get_hash(hash_type: u8, msg: Credentials) -&gt; field {
        if (hash_type.eq(1u8)) {
            return get_bhp_hash(msg);
        }
        return get_psd_hash(msg);
    }

    function signature_verification(msg_hash: field, sig: signature, issuer: address) -&gt; bool {
        return signature::verify(sig, issuer, msg_hash);
    }

    transition verify(
        sig: signature,
        hash_type: u8,
        currentDate: u32,
        msg: Credentials,
    ) -&gt; bool {
        let dob: date_time = timestamp_to_datetime(msg.dob);
        let current: date_time = timestamp_to_datetime(currentDate);
        let age: u32 = current.year - dob.year;

        return ( age.gte(18u32) &amp;&amp;
            signature_verification(get_hash(hash_type, msg), sig, msg.issuer));
    }
}
"><code>program age_verification.aleo {

    <span class="hljs-comment">// 时间戳辅助函数</span>
    <span class="hljs-keyword">struct</span> <span class="hljs-title">date_time</span> {
        <span class="hljs-literal">seconds</span>: u8,        <span class="hljs-comment">// 秒</span>
        <span class="hljs-literal">minutes</span>: u8,        <span class="hljs-comment">// 分钟</span>
        <span class="hljs-literal">hours</span>: u8,          <span class="hljs-comment">// 小时</span>
        day: u8,            <span class="hljs-comment">// 日</span>
        month: u32,         <span class="hljs-comment">// 月</span>
        year: u32,          <span class="hljs-comment">// 年</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">timestamp_to_datetime</span>(<span class="hljs-params">t: u32</span>) -> <span class="hljs-title">date_time</span> </span>{
        let <span class="hljs-literal">seconds</span>: u32 <span class="hljs-operator">=</span> t <span class="hljs-operator">%</span> 60u32;
        t <span class="hljs-operator">/</span><span class="hljs-operator">=</span> 60u32;

        let <span class="hljs-literal">minutes</span>: u32 <span class="hljs-operator">=</span> t <span class="hljs-operator">%</span> 60u32;
        t <span class="hljs-operator">/</span><span class="hljs-operator">=</span> 60u32;

        let <span class="hljs-literal">hours</span>: u32 <span class="hljs-operator">=</span> t <span class="hljs-operator">%</span> 24u32;
        t <span class="hljs-operator">/</span><span class="hljs-operator">=</span> 24u32;

        let a: u32 <span class="hljs-operator">=</span> (4u32 <span class="hljs-operator">*</span> t <span class="hljs-operator">+</span> 102032u32) <span class="hljs-operator">/</span> 146097u32 <span class="hljs-operator">+</span> 15u32;
        let b: u32 <span class="hljs-operator">=</span> t <span class="hljs-operator">+</span> 2442113u32 <span class="hljs-operator">+</span> a <span class="hljs-operator">-</span> (a <span class="hljs-operator">/</span> 4u32);
        let c: u32 <span class="hljs-operator">=</span> (20u32 <span class="hljs-operator">*</span> b <span class="hljs-operator">-</span> 2442u32) <span class="hljs-operator">/</span> 7305u32;
        let d: u32 <span class="hljs-operator">=</span> b <span class="hljs-operator">-</span> 365u32 <span class="hljs-operator">*</span> c <span class="hljs-operator">-</span> (c <span class="hljs-operator">/</span> 4u32);
        let e: u32 <span class="hljs-operator">=</span> d <span class="hljs-operator">*</span> 1000u32 <span class="hljs-operator">/</span> 30601u32;
        let f: u32 <span class="hljs-operator">=</span> d <span class="hljs-operator">-</span> e <span class="hljs-operator">*</span> 30u32 <span class="hljs-operator">-</span> e <span class="hljs-operator">*</span> 601u32 <span class="hljs-operator">/</span> 1000u32;
        let g: u32 <span class="hljs-operator">=</span> 4716u32;
        let h: u32 <span class="hljs-operator">=</span> 1u32;

        <span class="hljs-keyword">if</span> (e <span class="hljs-operator">></span> 13u32) {
            g <span class="hljs-operator">=</span> 4715u32;
            h <span class="hljs-operator">=</span> 13u32;
        }

        c <span class="hljs-operator">-</span><span class="hljs-operator">=</span> g;
        e <span class="hljs-operator">-</span><span class="hljs-operator">=</span> h;

        let dt: date_time <span class="hljs-operator">=</span> date_time {
            <span class="hljs-literal">seconds</span>: <span class="hljs-literal">seconds</span> <span class="hljs-keyword">as</span> u8,
            <span class="hljs-literal">minutes</span>: <span class="hljs-literal">minutes</span> <span class="hljs-keyword">as</span> u8,
            <span class="hljs-literal">hours</span>: <span class="hljs-literal">hours</span> <span class="hljs-keyword">as</span> u8,
            day: f <span class="hljs-keyword">as</span> u8,
            month: e <span class="hljs-keyword">as</span> u32,
            year: c <span class="hljs-keyword">as</span> u32,
        };

        <span class="hljs-keyword">return</span> dt;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">datetime_to_timestamp</span>(<span class="hljs-params">dt: date_time</span>) -> <span class="hljs-title">u32</span> </span>{
        let y: u32 <span class="hljs-operator">=</span> dt.year <span class="hljs-keyword">as</span> u32;
        let m: u32 <span class="hljs-operator">=</span> dt.month <span class="hljs-keyword">as</span> u32;
        let d: u32 <span class="hljs-operator">=</span> dt.day <span class="hljs-keyword">as</span> u32;

        <span class="hljs-keyword">if</span> (m <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> 2u32) {
            m <span class="hljs-operator">+</span><span class="hljs-operator">=</span> 12u32;
            y <span class="hljs-operator">-</span><span class="hljs-operator">=</span> 1u32;
        }

        let t: u32 <span class="hljs-operator">=</span> (365u32 <span class="hljs-operator">*</span> y) <span class="hljs-operator">+</span> (y <span class="hljs-operator">/</span> 4u32) <span class="hljs-operator">-</span> (y <span class="hljs-operator">/</span> 100u32) <span class="hljs-operator">+</span> (y <span class="hljs-operator">/</span> 400u32);
        t <span class="hljs-operator">+</span><span class="hljs-operator">=</span> (30u32 <span class="hljs-operator">*</span> m) <span class="hljs-operator">+</span> (3u32 <span class="hljs-operator">*</span> (m <span class="hljs-operator">+</span> 1u32) <span class="hljs-operator">/</span> 5u32) <span class="hljs-operator">+</span> d;
        t <span class="hljs-operator">-</span><span class="hljs-operator">=</span> 719561u32;
        t <span class="hljs-operator">*</span><span class="hljs-operator">=</span> 86400u32;
        t <span class="hljs-operator">+</span><span class="hljs-operator">=</span> (3600u32 <span class="hljs-operator">*</span> dt.hours <span class="hljs-keyword">as</span> u32) <span class="hljs-operator">+</span> (60u32 <span class="hljs-operator">*</span> dt.minutes <span class="hljs-keyword">as</span> u32) <span class="hljs-operator">+</span> dt.seconds <span class="hljs-keyword">as</span> u32;

        <span class="hljs-keyword">return</span> t;
    }

    <span class="hljs-keyword">struct</span> <span class="hljs-title">Credentials</span> {
        issuer: <span class="hljs-keyword">address</span>,
        subject: <span class="hljs-keyword">address</span>,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    inline get_psd_hash(<span class="hljs-built_in">msg</span>: Credentials) <span class="hljs-operator">-</span><span class="hljs-operator">></span> field {
        <span class="hljs-keyword">return</span> Poseidon2::hash_to_field(<span class="hljs-built_in">msg</span>);
    }

    inline get_bhp_hash(<span class="hljs-built_in">msg</span>: Credentials) <span class="hljs-operator">-</span><span class="hljs-operator">></span> field {
        <span class="hljs-keyword">return</span> BHP1024::hash_to_field(<span class="hljs-built_in">msg</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get_hash</span>(<span class="hljs-params">hash_type: u8, <span class="hljs-built_in">msg</span>: Credentials</span>) -> <span class="hljs-title">field</span> </span>{
        <span class="hljs-keyword">if</span> (hash_type.eq(1u8)) {
            <span class="hljs-keyword">return</span> get_bhp_hash(<span class="hljs-built_in">msg</span>);
        }
        <span class="hljs-keyword">return</span> get_psd_hash(<span class="hljs-built_in">msg</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signature_verification</span>(<span class="hljs-params">msg_hash: field, sig: signature, issuer: <span class="hljs-keyword">address</span></span>) -> <span class="hljs-title"><span class="hljs-keyword">bool</span></span> </span>{
        <span class="hljs-keyword">return</span> signature::verify(sig, issuer, msg_hash);
    }

    transition verify(
        sig: signature,
        hash_type: u8,
        currentDate: u32,
        <span class="hljs-built_in">msg</span>: Credentials,
    ) <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">bool</span> {
        let dob: date_time <span class="hljs-operator">=</span> timestamp_to_datetime(<span class="hljs-built_in">msg</span>.dob);
        let current: date_time <span class="hljs-operator">=</span> timestamp_to_datetime(currentDate);
        let age: u32 <span class="hljs-operator">=</span> current.year <span class="hljs-operator">-</span> dob.year;

        <span class="hljs-keyword">return</span> ( age.gte(18u32) <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
            signature_verification(get_hash(hash_type, <span class="hljs-built_in">msg</span>), sig, <span class="hljs-built_in">msg</span>.issuer));
    }
}
</code></pre><p>上面这段代码是一个基于 <code>aleo</code> 的零知识证明程序，用于验证用户是否超过特定年龄（例如18岁）。这个程序假设由一个受信任的机构签发了包含用户信息的凭证，并且验证者可以使用这些凭证来验证用户的年龄，而无需知道用户的实际出生日期。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">主要组件</h4><ol><li><p><strong>凭证结构（Credential Structure）</strong></p></li><li><p><strong>验证逻辑（Verification Logic）</strong></p></li><li><p><strong>辅助函数（Helper Functions）</strong></p></li></ol><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">具体解释</h4><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">凭证结构</h4><pre data-type="codeBlock" text="struct Credentials {
    issuer: address,
    subject: address,
    dob: u32,
    nationality: field,
    expiry: u32
}
"><code><span class="hljs-string">struct</span> <span class="hljs-string">Credentials</span> {
    <span class="hljs-attr">issuer:</span> <span class="hljs-string">address</span>,
    <span class="hljs-attr">subject:</span> <span class="hljs-string">address</span>,
    <span class="hljs-attr">dob:</span> <span class="hljs-string">u32</span>,
    <span class="hljs-attr">nationality:</span> <span class="hljs-string">field</span>,
    <span class="hljs-attr">expiry:</span> <span class="hljs-string">u32</span>
}
</code></pre><p><code>Credentials</code> 结构包含以下字段：</p><ul><li><p><code>issuer</code>: 签发机构的地址。</p></li><li><p><code>subject</code>: 持有人的地址。</p></li><li><p><code>dob</code>: 出生日期，以时间戳表示。</p></li><li><p><code>nationality</code>: 国籍。</p></li><li><p><code>expiry</code>: 过期日期，以时间戳表示。</p></li></ul><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">辅助函数</h4><p>这些函数用于日期和时间戳之间的转换。</p><pre data-type="codeBlock" text="struct date_time {
    seconds: u8,
    minutes: u8,
    hours: u8,
    day: u8,
    month: u32,
    year: u32,
}

function timestamp_to_datetime(t: u32) -&gt; date_time {
    // 省略的代码：将时间戳转换为日期时间结构
}

function datetime_to_timestamp(dt: date_time) -&gt; u32 {
    // 省略的代码：将日期时间结构转换为时间戳
}
"><code><span class="hljs-keyword">struct</span> <span class="hljs-title class_">date_time</span> {
    seconds: <span class="hljs-type">u8</span>,
    minutes: <span class="hljs-type">u8</span>,
    hours: <span class="hljs-type">u8</span>,
    day: <span class="hljs-type">u8</span>,
    month: <span class="hljs-type">u32</span>,
    year: <span class="hljs-type">u32</span>,
}

function <span class="hljs-title function_ invoke__">timestamp_to_datetime</span>(t: <span class="hljs-type">u32</span>) <span class="hljs-punctuation">-></span> date_time {
    <span class="hljs-comment">// 省略的代码：将时间戳转换为日期时间结构</span>
}

function <span class="hljs-title function_ invoke__">datetime_to_timestamp</span>(dt: date_time) <span class="hljs-punctuation">-></span> <span class="hljs-type">u32</span> {
    <span class="hljs-comment">// 省略的代码：将日期时间结构转换为时间戳</span>
}
</code></pre><p>这些函数将 UNIX 时间戳转换为日期时间结构，反之亦然。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">哈希函数</h4><p>用于计算凭证的哈希值。<code>Poseidon</code> 和 <code>BHP1024</code> 是两种不同的哈希算法。</p><pre data-type="codeBlock" text="inline get_psd_hash(msg: Credentials) -&gt; field {
    return Poseidon2::hash_to_field(msg);
}

inline get_bhp_hash(msg: Credentials) -&gt; field {
    return BHP1024::hash_to_field(msg);
}

function get_hash(hash_type: u8, msg: Credentials) -&gt; field {
    if (hash_type.eq(1u8)) {
        return get_bhp_hash(msg);
    }
    return get_psd_hash(msg);
}
"><code>inline get_psd_hash(<span class="hljs-built_in">msg</span>: Credentials) <span class="hljs-operator">-</span><span class="hljs-operator">></span> field {
    <span class="hljs-keyword">return</span> Poseidon2::hash_to_field(<span class="hljs-built_in">msg</span>);
}

inline get_bhp_hash(<span class="hljs-built_in">msg</span>: Credentials) <span class="hljs-operator">-</span><span class="hljs-operator">></span> field {
    <span class="hljs-keyword">return</span> BHP1024::hash_to_field(<span class="hljs-built_in">msg</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get_hash</span>(<span class="hljs-params">hash_type: u8, <span class="hljs-built_in">msg</span>: Credentials</span>) -> <span class="hljs-title">field</span> </span>{
    <span class="hljs-keyword">if</span> (hash_type.eq(1u8)) {
        <span class="hljs-keyword">return</span> get_bhp_hash(<span class="hljs-built_in">msg</span>);
    }
    <span class="hljs-keyword">return</span> get_psd_hash(<span class="hljs-built_in">msg</span>);
}
</code></pre><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">签名验证</h4><p>用于验证凭证的签名。</p><pre data-type="codeBlock" text="function signature_verification(msg_hash: field, sig: signature, issuer: address) -&gt; bool {
    return signature::verify(sig, issuer, msg_hash);
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signature_verification</span>(<span class="hljs-params">msg_hash: field, sig: signature, issuer: <span class="hljs-keyword">address</span></span>) -> <span class="hljs-title"><span class="hljs-keyword">bool</span></span> </span>{
    <span class="hljs-keyword">return</span> signature::verify(sig, issuer, msg_hash);
}
</code></pre><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">验证函数</h4><p>主要的验证逻辑，检查用户是否年满18岁，并验证凭证签名。</p><pre data-type="codeBlock" text="transition verify(
    sig: signature,
    hash_type: u8,
    currentDate: u32,
    msg: Credentials,
) -&gt; bool {
    let dob: date_time = timestamp_to_datetime(msg.dob);
    let current: date_time = timestamp_to_datetime(currentDate);
    let age: u32 = current.year - dob.year;

    return (age.gte(18u32) &amp;&amp;
        signature_verification(get_hash(hash_type, msg), sig, msg.issuer));
}
"><code>transition verify(
    sig: signature,
    hash_type: u8,
    currentDate: u32,
    <span class="hljs-built_in">msg</span>: Credentials,
) <span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-keyword">bool</span> {
    let dob: date_time <span class="hljs-operator">=</span> timestamp_to_datetime(<span class="hljs-built_in">msg</span>.dob);
    let current: date_time <span class="hljs-operator">=</span> timestamp_to_datetime(currentDate);
    let age: u32 <span class="hljs-operator">=</span> current.year <span class="hljs-operator">-</span> dob.year;

    <span class="hljs-keyword">return</span> (age.gte(18u32) <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span>
        signature_verification(get_hash(hash_type, <span class="hljs-built_in">msg</span>), sig, <span class="hljs-built_in">msg</span>.issuer));
}
</code></pre><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">验证过程</h4><ol><li><p><strong>时间戳转换</strong>：将出生日期和当前日期的时间戳转换为日期时间结构。</p></li><li><p><strong>年龄计算</strong>：计算当前年份与出生年份的差值。</p></li><li><p><strong>年龄检查</strong>：检查年龄是否大于等于18。</p></li><li><p><strong>签名验证</strong>：使用选择的哈希算法验证凭证的签名是否正确。</p></li></ol><p>通过以上步骤，可以在零知识的情况下验证用户是否超过特定年龄，而无需透露实际的出生日期或其他个人信息。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[Aleo PrivX 去中心化隐私交易所介绍]]></title>
            <link>https://paragraph.com/@yaakov/aleo-privx</link>
            <guid>lMkKi4BICE7aISVy4BpD</guid>
            <pubDate>Mon, 24 Jun 2024 12:21:27 GMT</pubDate>
            <description><![CDATA[随着数字资产管理领域对隐私和安全性的关注日益增加，中心化交易所（CEX）的固有漏洞逐渐显现。FTX 交易所的崩溃导致数十亿美元的损失，提醒了我们这些风险的存在。中心化交易所存在以下威胁：用户敏感信息泄露用户无法控制私钥导致资产丢失非透明和链下交易过程易受网络攻击为了解决这些问题，去中心化交易所（DEX）提供了隐私、透明度、安全性和自主性的替代方案：用户可以管理和控制自己的钱包和私钥链上交易透明且可追踪相比 CEX 更高的安全性和抗风险能力PrivX 是一个基于 Aleo 的去中心化交易所，将为生态系统带来巨大价值。通过利用 Aleo 的隐私特性，PrivX 确保了加密交易的匿名性和安全性，消除了中心化的担忧。它提升了流动性，吸引了注重隐私的用户，将 Aleo 打造成私密和安全交易的领先区块链平台。此外，PrivX 还将为 Aleo 生态系统带来以下好处：吸引新用户：PrivX 的隐私特性可以吸引那些寻找安全和私密交易方式的新用户加入 Aleo 生态系统。增加采用率：通过隐私保护 DEX 的存在，可以提高 Aleo 的采用率，因为 PrivX 将使用户更容易访问和交易基于 Aleo...]]></description>
            <content:encoded><![CDATA[<p>随着数字资产管理领域对隐私和安全性的关注日益增加，中心化交易所（CEX）的固有漏洞逐渐显现。FTX 交易所的崩溃导致数十亿美元的损失，提醒了我们这些风险的存在。中心化交易所存在以下威胁：</p><ol><li><p>用户敏感信息泄露</p></li><li><p>用户无法控制私钥导致资产丢失</p></li><li><p>非透明和链下交易过程</p></li><li><p>易受网络攻击</p></li></ol><p>为了解决这些问题，去中心化交易所（DEX）提供了隐私、透明度、安全性和自主性的替代方案：</p><ol><li><p>用户可以管理和控制自己的钱包和私钥</p></li><li><p>链上交易透明且可追踪</p></li><li><p>相比 CEX 更高的安全性和抗风险能力</p></li></ol><p>PrivX 是一个基于 Aleo 的去中心化交易所，将为生态系统带来巨大价值。通过利用 Aleo 的隐私特性，PrivX 确保了加密交易的匿名性和安全性，消除了中心化的担忧。它提升了流动性，吸引了注重隐私的用户，将 Aleo 打造成私密和安全交易的领先区块链平台。此外，PrivX 还将为 Aleo 生态系统带来以下好处：</p><ol><li><p>吸引新用户：PrivX 的隐私特性可以吸引那些寻找安全和私密交易方式的新用户加入 Aleo 生态系统。</p></li><li><p>增加采用率：通过隐私保护 DEX 的存在，可以提高 Aleo 的采用率，因为 PrivX 将使用户更容易访问和交易基于 Aleo 的资产。</p></li><li><p>促进新隐私应用的开发：PrivX 的存在可以促进新隐私应用的开发，我们的团队将与这些新项目合作，共同推动生态系统的发展。</p></li></ol><p>PrivX 选择 Aleo 作为其创新 DEX 的开发平台，主要是因为 Aleo 卓越的链上隐私保护。Aleo 的零知识证明技术允许用户在进行交易时隐藏账户余额、交易活动等敏感信息，从而确保强大的隐私保护。</p><p>尽管 DEX 有其优势，但在交易性能和流动性方面，仍存在一些不足。为了解决这些问题，PrivX 开发了一种独特的机制，将 CEX 的流动性和用户体验与 DEX 的透明性相结合。推出了首个隐私订单簿 DEX，在 Aleo 平台上具备无与伦比的链上隐私保护机制。</p><p>您可以在这里找到项目的<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/privx-exchange/privx-exchange-contract">源码</a>。</p><p><strong>构建</strong> 要编译这个 Aleo 程序，请运行：</p><pre data-type="codeBlock" text="aleo build
"><code></code></pre><p><strong>介绍</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>在 PrivX 进行交易，可以保护您的隐私，下面介绍 PrivX 核心合约的结构和提供的方法：</p><p><strong>数据映射</strong></p><ul><li><p><code>credits_balance</code>: 存储用户的余额</p></li><li><p><code>credits_deposited</code>: 存储用户的存款，可用于购买其他代币</p></li><li><p><code>credits_locked</code>: 存储用户锁定的余额，用于买单</p></li><li><p><code>token_balances</code>: 存储用户的代币余额</p></li><li><p><code>token_deposited</code>: 存储用户的代币存款，可用于购买其他代币</p></li><li><p><code>token_locked</code>: 存储用户锁定的代币，用于卖单</p></li><li><p><code>sequence</code>: 生成序列 ID 的解决方法</p></li></ul><p><strong>结构</strong></p><ul><li><p><code>Order</code>: 订单所需的数据</p></li></ul><p><strong>功能</strong></p><ol><li><p><strong>mint_credits</strong></p><ul><li><p>参数：</p><ul><li><p><code>address</code>: 接收余额的地址</p></li><li><p><code>amount</code>: 铸造的余额数量</p></li></ul></li><li><p>描述：铸造指定数量的余额到指定地址。</p></li></ul></li><li><p><strong>deposit_credits</strong></p><ul><li><p>参数：</p><ul><li><p><code>amount</code>: 从 <code>credits_balance</code> 转移到 <code>credits_deposited</code> 的余额数量</p></li></ul></li><li><p>描述：从 <code>credits_balance</code> 中转移指定数量的余额到 <code>credits_deposited</code>。</p></li></ul></li><li><p><strong>withdraw_credits</strong></p><ul><li><p>参数：</p><ul><li><p><code>amount</code>: 从 <code>credits_deposited</code> 转移到 <code>credits_balance</code> 的余额数量</p></li></ul></li><li><p>描述：从 <code>credits_deposited</code> 中转移指定数量的余额到 <code>credits_balance</code>。</p></li></ul></li><li><p><strong>mint_token</strong></p><ul><li><p>参数：</p><ul><li><p><code>address</code>: 接收代币的地址</p></li><li><p><code>amount</code>: 铸造的代币数量</p></li></ul></li><li><p>描述：铸造指定数量的 ARC20 代币到指定地址。</p></li></ul></li><li><p><strong>deposit_token</strong></p><ul><li><p>参数：</p><ul><li><p><code>amount</code>: 从 <code>token_balance</code> 转移到 <code>token_deposited</code> 的代币数量</p></li></ul></li><li><p>描述：从 <code>token_balance</code> 中转移指定数量的代币到 <code>token_deposited</code>。</p></li></ul></li><li><p><strong>withdraw_token</strong></p><ul><li><p>参数：</p><ul><li><p><code>amount</code>: 从 <code>token_deposited</code> 转移到 <code>token_balance</code> 的代币数量</p></li></ul></li><li><p>描述：从 <code>token_deposited</code> 中转移指定数量的代币到 <code>token_balance</code>。</p></li></ul></li><li><p><strong>buy</strong></p><ul><li><p>参数：</p><ul><li><p><code>quantity</code>: 订单数量</p></li><li><p><code>price</code>: 单个代币愿意支付的价格</p></li></ul></li><li><p>描述：减少 <code>credits_deposited</code>，增加 <code>credits_locked</code>，并生成一个带有序列 ID 的新买单。</p></li></ul></li><li><p><strong>sell</strong></p><ul><li><p>参数：</p><ul><li><p><code>quantity</code>: 订单数量</p></li><li><p><code>price</code>: 单个代币愿意出售的价格</p></li></ul></li><li><p>描述：减少 <code>token_deposited</code>，增加 <code>token_locked</code>，并生成一个带有序列 ID 的新卖单。</p></li></ul></li><li><p><strong>knockdown</strong></p><ul><li><p>参数：</p><ul><li><p><code>sell_order_id</code>: 交易的卖单 ID</p></li><li><p><code>buy_order_id</code>: 交易的买单 ID</p></li></ul></li><li><p>描述：指定一个卖单 ID 和一个买单 ID，检查交易条件是否满足，如果满足，则完成交易。</p></li></ul></li><li><p><strong>cancel</strong></p><ul><li><p>参数：</p><ul><li><p><code>order_id</code>: 需要取消的订单 ID</p></li></ul></li><li><p>描述：取消属于调用者的订单，将锁定的金额返回到存款金额中。</p></li></ul></li></ol><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">总结</h3><p>PrivX 作为 Aleo 上的去中心化交易所，不仅解决了传统中心化交易所的诸多问题，还为用户提供了高度隐私保护的交易平台。Aleo 的零知识证明技术确保了交易的隐私性，用户可以安全、匿名地进行加密货币交易。此外，PrivX 的独特机制结合了 CEX 的流动性和用户体验，同时保持了 DEX 的透明性。相信 PrivX 将吸引更多注重隐私的用户，促进 Aleo 生态系统的进一步发展。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[AleoSwap 合约接口总结]]></title>
            <link>https://paragraph.com/@yaakov/aleoswap</link>
            <guid>2dA7jkUCOWFPWIrjFNaH</guid>
            <pubDate>Mon, 24 Jun 2024 09:35:31 GMT</pubDate>
            <description><![CDATA[AleoSwap 是基于 Aleo 区块链的去中心化交易所（DEX），采用了 Uniswap 机制。利用 Aleo 区块链的独特功能，AleoSwap 为用户提供了更高的隐私保护和全新的功能。功能创建代币功能: create_token参数: info: TokenInfo (包括代币名称、符号、小数位和总供应量)命令示例:snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \ $program_id create_token "{name: 1431520340field, symbol: 1431520340field, decimals: 6u8, total_supply: 100000000000000u128, admin: $admin_addr}" 转账功能: transfer参数: token_id: field, to: address, amount: u128命令示例:snarkos developer execute -q $rpc_...]]></description>
            <content:encoded><![CDATA[<p>AleoSwap 是基于 Aleo 区块链的去中心化交易所（DEX），采用了 Uniswap 机制。利用 Aleo 区块链的独特功能，AleoSwap 为用户提供了更高的隐私保护和全新的功能。</p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">功能</h4><p><strong>创建代币</strong></p><ul><li><p><strong>功能</strong>: <code>create_token</code></p></li><li><p><strong>参数</strong>: <code>info: TokenInfo</code> (包括代币名称、符号、小数位和总供应量)</p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id create_token &quot;{name: 1431520340field, symbol: 1431520340field, decimals: 6u8, total_supply: 100000000000000u128, admin: $admin_addr}&quot;
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> create_token <span class="hljs-string">"{name: 1431520340field, symbol: 1431520340field, decimals: 6u8, total_supply: 100000000000000u128, admin: <span class="hljs-variable">$admin_addr</span>}"</span>
</code></pre></li></ul><p><strong>转账</strong></p><ul><li><p><strong>功能</strong>: <code>transfer</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>to: address</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id transfer 1field $to_address 100000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> transfer 1field <span class="hljs-variable">$to_address</span> 100000000u128
</code></pre></li></ul><p><strong>授权</strong></p><ul><li><p><strong>功能</strong>: <code>approve</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>spender: address</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id approve 1field $spender 10000000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> approve 1field <span class="hljs-variable">$spender</span> 10000000000u128
</code></pre></li></ul><p><strong>从账户转账</strong></p><ul><li><p><strong>功能</strong>: <code>transfer_from</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>from: address</code>, <code>to: address</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id transfer_from 1field $from_addr $to_addr 100000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> transfer_from 1field <span class="hljs-variable">$from_addr</span> <span class="hljs-variable">$to_addr</span> 100000000u128
</code></pre></li></ul><p><strong>转为私有</strong></p><ul><li><p><strong>功能</strong>: <code>transfer_to_private</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>to: address</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id transfer_to_private 1field $to_addr 100000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> transfer_to_private 1field <span class="hljs-variable">$to_addr</span> 100000000u128
</code></pre></li></ul><p><strong>转为公共</strong></p><ul><li><p><strong>功能</strong>: <code>transfer_to_public</code></p></li><li><p><strong>参数</strong>: <code>pt_in: PrivateToken</code>, <code>to: address</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id transfer_to_public $private_token_record $to_addr 10000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> transfer_to_public <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_addr</span> 10000000u128
</code></pre></li></ul><p><strong>私有转账</strong></p><ul><li><p><strong>功能</strong>: <code>transfer_privately</code></p></li><li><p><strong>参数</strong>: <code>pt_in: PrivateToken</code>, <code>to: address</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id transfer_privately $private_token_record $to_addr 50000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> transfer_privately <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_addr</span> 50000000u128
</code></pre></li></ul><p><strong>合并代币</strong></p><ul><li><p><strong>功能</strong>: <code>join</code></p></li><li><p><strong>参数</strong>: <code>pt1: PrivateToken</code>, <code>pt2: PrivateToken</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id join $private_token_record_1 $private_token_record_2
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> <span class="hljs-built_in">join</span> <span class="hljs-variable">$private_token_record_1</span> <span class="hljs-variable">$private_token_record_2</span>
</code></pre></li></ul><p><strong>创建交易对</strong></p><ul><li><p><strong>功能</strong>: <code>create_pair</code></p></li><li><p><strong>参数</strong>: <code>token_a: field</code>, <code>token_b: field</code>, <code>amount_a: u128</code>, <code>amount_b: u128</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id create_pair 1field 2field 100000000u128 10000000000u128 $to_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> create_pair 1field 2field 100000000u128 10000000000u128 <span class="hljs-variable">$to_addr</span>
</code></pre></li></ul><p><strong>私密创建交易对</strong></p><ul><li><p><strong>功能</strong>: <code>create_pair_privately</code></p></li><li><p><strong>参数</strong>: <code>pt_a: PrivateToken</code>, <code>pt_b: PrivateToken</code>, <code>amount_a: u128</code>, <code>amount_b: u128</code>, <code>to: address</code>, <code>liquidity: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id create_pair_privately $private_token_record_1 $private_token_record_2 $to_addr $liquidity
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> create_pair_privately <span class="hljs-variable">$private_token_record_1</span> <span class="hljs-variable">$private_token_record_2</span> <span class="hljs-variable">$to_addr</span> <span class="hljs-variable">$liquidity</span>
</code></pre></li></ul><p><strong>增加流动性</strong></p><ul><li><p><strong>功能</strong>: <code>add_liquidity</code></p></li><li><p><strong>参数</strong>: <code>token_a: field</code>, <code>token_b: field</code>, <code>amount_a: u128</code>, <code>amount_b: u128</code>, <code>min_a: u128</code>, <code>min_b: u128</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id add_liquidity 1field 2field 100000000u128 10000000000u128 0u128 0u128 $to_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> add_liquidity 1field 2field 100000000u128 10000000000u128 0u128 0u128 <span class="hljs-variable">$to_addr</span>
</code></pre></li></ul><p><strong>私密增加流动性</strong></p><ul><li><p><strong>功能</strong>: <code>add_liquidity_privately</code></p></li><li><p><strong>参数</strong>: <code>pt_a: PrivateToken</code>, <code>pt_b: PrivateToken</code>, <code>amount_a: u128</code>, <code>amount_b: u128</code>, <code>min_a: u128</code>, <code>min_b: u128</code>, <code>min_liquidity: u128</code>, <code>to: address</code>, <code>refund_to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id add_liquidity_privately $private_token_record_1 $private_token_record_2 $to_addr $refund_to
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> add_liquidity_privately <span class="hljs-variable">$private_token_record_1</span> <span class="hljs-variable">$private_token_record_2</span> <span class="hljs-variable">$to_addr</span> <span class="hljs-variable">$refund_to</span>
</code></pre></li></ul><p><strong>移除流动性</strong></p><ul><li><p><strong>功能</strong>: <code>remove_liquidity</code></p></li><li><p><strong>参数</strong>: <code>token_a: field</code>, <code>token_b: field</code>, <code>liquidity: u128</code>, <code>min_a: u128</code>, <code>min_b: u128</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id remove_liquidity 1field 2field 1000000000u128 0u128 0u128 $to_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> remove_liquidity 1field 2field 1000000000u128 0u128 0u128 <span class="hljs-variable">$to_addr</span>
</code></pre></li></ul><p><strong>私密移除流动性</strong></p><ul><li><p><strong>功能</strong>: <code>remove_liquidity_privately</code></p></li><li><p><strong>参数</strong>: <code>token_a: field</code>, <code>token_b: field</code>, <code>pt_lp: PrivateToken</code>, <code>liquidity: u128</code>, <code>min_a: u128</code>, <code>min_b: u128</code>, <code>to: address</code>, <code>refund_to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id remove_liquidity_privately $private_token_record $to_addr $refund_to
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> remove_liquidity_privately <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_addr</span> <span class="hljs-variable">$refund_to</span>
</code></pre></li></ul><p><strong>包装私有积分</strong></p><ul><li><p><strong>功能</strong>: <code>wrap_private_credits</code></p></li><li><p><strong>参数</strong>: <code>input: credits.leo/credits</code>, <code>to: address</code>, <code>amount: field</code>, <code>holder: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id wrap_private_credits $input_record $to_addr 10000000field $holder_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> wrap_private_credits <span class="hljs-variable">$input_record</span> <span class="hljs-variable">$to_addr</span> 10000000field <span class="hljs-variable">$holder_addr</span>
</code></pre></li></ul><p><strong>包装公共积分</strong></p><ul><li><p><strong>功能</strong>: <code>wrap_public_credits</code></p></li><li><p><strong>参数</strong>: <code>to: address</code>, <code>amount: field</code>, <code>holder: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id wrap_public_credits $to_addr 10000000field $holder_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> wrap_public_credits <span class="hljs-variable">$to_addr</span> 10000000field <span class="hljs-variable">$holder_addr</span>
</code></pre></li></ul><p><strong>解包</strong></p><ul><li><p><strong>功能</strong>: <code>unwrap</code></p></li><li><p><strong>参数</strong>: <code>to: address</code>, <code>amount: field</code>, <code>into_private: bool</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id unwrap $to_addr 10000000field true
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> unwrap <span class="hljs-variable">$to_addr</span> 10000000field <span class="hljs-literal">true</span>
</code></pre></li></ul><p><strong>处理私有解包</strong></p><ul><li><p><strong>功能</strong>: <code>handle_unwrap_to_private</code></p></li><li><p><strong>参数</strong>: <code>index: u64</code>, <code>to: address</code>, <code>amount: field</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id handle_unwrap_to_private 0u64 $to_addr 10000000field
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> handle_unwrap_to_private 0u64 <span class="hljs-variable">$to_addr</span> 10000000field
</code></pre></li></ul><p><strong>处理公共解包</strong></p><ul><li><p><strong>功能</strong>: <code>handle_unwrap_to_public</code></p></li><li><p><strong>参数</strong>: <code>index: u64</code>, <code>to: address</code>, <code>amount: field</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id handle_unwrap_to_public 1u64 $to_addr 10000000field
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> handle_unwrap_to_public 1u64 <span class="hljs-variable">$to_addr</span> 10000000field
</code></pre></li></ul><p><strong>固定数量代币换取代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_exact_tokens_for_tokens</code></p></li><li><p><strong>参数</strong>: <code>token_in: field</code>, <code>token_out: field</code>, <code>amount_in: u128</code>, <code>amount_out_min: u128</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_exact_tokens_for_tokens 1field 2field 1000000u128 98000000u128 $to_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_exact_tokens_for_tokens 1field 2field 1000000u128 98000000u128 <span class="hljs-variable">$to_addr</span>
</code></pre></li></ul><p><strong>私有代币换取公共代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_exact_private_for_public</code></p></li><li><p><strong>参数</strong>: <code>pt_in: PrivateToken</code>, <code>token_out: field</code>, <code>amount_in: u128</code>, <code>amount_out_min: u128</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_exact_private_for_public $private_token_record $to_addr 98000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_exact_private_for_public <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_addr</span> 98000000u128
</code></pre></li></ul><p><strong>私有代币换取私有代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_exact_private_for_private</code></p></li><li><p><strong>参数</strong>: <code>pt_in: PrivateToken</code>, <code>token_out: field</code>, <code>amount_in: u128</code>, <code>amount_out_min: u128</code>, <code>to_pri: address</code>, <code>to_pub: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_exact_private_for_private $private_token_record $to_pri $to_pub 98000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_exact_private_for_private <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_pri</span> <span class="hljs-variable">$to_pub</span> 98000000u128
</code></pre></li></ul><p><strong>公共代币换取私有代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_exact_public_for_private</code></p></li><li><p><strong>参数</strong>: <code>token_in: field</code>, <code>token_out: field</code>, <code>amount_in: u128</code>, <code>amount_out_min: u128</code>, <code>to_pri: address</code>, <code>to_pub: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_exact_public_for_private 1field 2field 1000000u128 98000000u128 $to_pri $to_pub
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_exact_public_for_private 1field 2field 1000000u128 98000000u128 <span class="hljs-variable">$to_pri</span> <span class="hljs-variable">$to_pub</span>
</code></pre></li></ul><p><strong>浮动输入换取固定输出</strong></p><ul><li><p><strong>功能</strong>: <code>swap_tokens_for_exact_tokens</code></p></li><li><p><strong>参数</strong>: <code>token_in: field</code>, <code>token_out: field</code>, <code>amount_in_max: u128</code>, <code>amount_out: u128</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_tokens_for_exact_tokens 2field 1field 50000000u128 500000u128 $to_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_tokens_for_exact_tokens 2field 1field 50000000u128 500000u128 <span class="hljs-variable">$to_addr</span>
</code></pre></li></ul><p><strong>私有代币换取固定数量的公共代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_private_for_exact_public</code></p></li><li><p><strong>参数</strong>: <code>pt_in: PrivateToken</code>, <code>token_out: field</code>, <code>amount_in_max: u128</code>, <code>amount_out: u128</code>, <code>to: address</code>, <code>refund_to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_private_for_exact_public $private_token_record $to_addr $refund_to 98000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_private_for_exact_public <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_addr</span> <span class="hljs-variable">$refund_to</span> 98000000u128
</code></pre></li></ul><p><strong>私有代币换取固定数量的私有代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_private_for_exact_private</code></p></li><li><p><strong>参数</strong>: <code>pt_in: PrivateToken</code>, <code>token_out: field</code>, <code>amount_in_max: u128</code>, <code>amount_out: u128</code>, <code>to_pri: address</code>, <code>refund_to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_private_for_exact_private $private_token_record $to_pri $refund_to 98000000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_private_for_exact_private <span class="hljs-variable">$private_token_record</span> <span class="hljs-variable">$to_pri</span> <span class="hljs-variable">$refund_to</span> 98000000u128
</code></pre></li></ul><p><strong>公共代币换取固定数量的私有代币</strong></p><ul><li><p><strong>功能</strong>: <code>swap_public_for_exact_private</code></p></li><li><p><strong>参数</strong>: <code>token_in: field</code>, <code>token_out: field</code>, <code>amount_in_max: u128</code>, <code>amount_out: u128</code>, <code>to_pri: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id swap_public_for_exact_private 1field 2field 1000000u128 98000000u128 $to_pri
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> swap_public_for_exact_private 1field 2field 1000000u128 98000000u128 <span class="hljs-variable">$to_pri</span>
</code></pre></li></ul><p><strong>代币水龙头</strong></p><ul><li><p><strong>功能</strong>: <code>token_faucet</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>to: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id token_faucet 1field $to_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> token_faucet 1field <span class="hljs-variable">$to_addr</span>
</code></pre></li></ul><p><strong>设置代币水龙头</strong></p><ul><li><p><strong>功能</strong>: <code>set_token_faucet</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>amount: u128</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id set_token_faucet 1field 1000u128
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> set_token_faucet 1field 1000u128
</code></pre></li></ul><p><strong>更改代币管理员</strong></p><ul><li><p><strong>功能</strong>: <code>change_token_admin</code></p></li><li><p><strong>参数</strong>: <code>token_id: field</code>, <code>admin: address</code></p></li><li><p><strong>命令示例</strong>:</p><pre data-type="codeBlock" text="snarkos developer execute -q $rpc_url -b $broadcast_url -p $private_key -r $fee_record \
  $program_id change_token_admin 1field $new_admin_addr
"><code>snarkos developer execute -q <span class="hljs-variable">$rpc_url</span> -b <span class="hljs-variable">$broadcast_url</span> -p <span class="hljs-variable">$private_key</span> -r <span class="hljs-variable">$fee_record</span> \
  <span class="hljs-variable">$program_id</span> change_token_admin 1field <span class="hljs-variable">$new_admin_addr</span>
</code></pre></li></ul><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">公共状态</h3><p><strong>余额</strong></p><ul><li><p><strong>描述</strong>: 存储所有代币和所有账户的余额。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/balances/$key
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>balances<span class="hljs-operator">/</span>$key
</code></pre></li></ul><p><strong>授权</strong></p><ul><li><p><strong>描述</strong>: 存储所有代币和所有账户的授权数据。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/allowance/$key
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>allowance<span class="hljs-operator">/</span>$key
</code></pre></li></ul><p><strong>代币信息</strong></p><ul><li><p><strong>描述</strong>: 存储所有代币的元信息。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/tokens/$token_id
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>tokens<span class="hljs-operator">/</span>$token_id
</code></pre></li></ul><p><strong>水龙头配置</strong></p><ul><li><p><strong>描述</strong>: 存储所有代币的水龙头配置。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/faucets/$token_id
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>faucets<span class="hljs-operator">/</span>$token_id
</code></pre></li></ul><p><strong>交易对信息</strong></p><ul><li><p><strong>描述</strong>: 存储所有交易对的信息。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/pairs/$pair_id
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>pairs<span class="hljs-operator">/</span>$pair_id
</code></pre></li></ul><p><strong>全局状态</strong></p><ul><li><p><strong>描述</strong>: 存储全局状态。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/global_state/true
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>global_state<span class="hljs-operator">/</span><span class="hljs-literal">true</span>
</code></pre></li></ul><p><strong>包装状态</strong></p><ul><li><p><strong>描述</strong>: 存储 WALEO（Wrapped Aleo）功能的状态。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/wrap_state/true
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>wrap_state<span class="hljs-operator">/</span><span class="hljs-literal">true</span>
</code></pre></li></ul><p><strong>解包历史</strong></p><ul><li><p><strong>描述</strong>: 存储所有 WALEO 的解包历史（包括待处理和已处理的）。</p></li><li><p><strong>查询命令</strong>:</p><pre data-type="codeBlock" text="curl $aleoRpc/testnet3/program/swap.aleo/mapping/unwraps/$index
"><code>curl $aleoRpc<span class="hljs-operator">/</span>testnet3<span class="hljs-operator">/</span>program<span class="hljs-operator">/</span>swap.aleo/<span class="hljs-keyword">mapping</span><span class="hljs-operator">/</span>unwraps<span class="hljs-operator">/</span>$index
</code></pre></li></ul><p>以上就是 AleoSwap 技术架构的详细介绍。通过利用 Aleo 区块链的独特功能，AleoSwap 提供了更高的隐私性和灵活性，适应了去中心化交易所和用户的多种需求。如果你有任何疑问或需要进一步的信息，可以随时访问我们的官方文档或加入我们的社区讨论。</p><p><strong>总结</strong></p><p>AleoSwap 作为基于 Aleo 区块链的去中心化交易所，通过集成 Uniswap 机制和 Aleo 区块链的独特隐私功能，极大地提升了交易所的隐私保护和功能多样性。无论是代币的创建、转账、流动性管理还是代币交换，AleoSwap 都提供了全面且安全的解决方案，为用户带来了更加自由和隐私的交易体验。期待在社区的共同努力下，AleoSwap 能够不断发展壮大，为更多用户提供优质的去中心化金融服务。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[ARC-21: 多代币标准程序提案]]></title>
            <link>https://paragraph.com/@yaakov/arc-21</link>
            <guid>KoNmJhDMXQhPFDAAbokv</guid>
            <pubDate>Mon, 24 Jun 2024 08:51:49 GMT</pubDate>
            <description><![CDATA[这也是目前正在讨论的一个 ARC-21提案，讨论的目的主要是当前版本的SnarkOS/SnarkVM不支持动态合约调用或标准接口，这使得组合性难以实现。为了应对这一挑战，团队提出了一个多代币支持程序（MTSP），用于管理多个ARC-20代币的余额。MTSP作为标准“中心”，所有代币和DeFi合约都可以与其接口，简化了新代币的部署和DeFi合约的集成。此外，MTSP还提供隐私益处，掩盖具体代币的身份。下面是MTSP的具体实现。规范import credits.aleo; // 定义MTSP程序 program mtsp.aleo { // 代币记录结构 record Token { owner: address, amount: u128, token_id: field, authorized: bool, authorized_until: u32 } // 代币元数据结构 struct TokenMetadata { token_id: field, name: u128, // 代币名称，使用ASCII编码表示的比特串 symbol: u128, // 代币符号，使用ASC...]]></description>
            <content:encoded><![CDATA[<p>这也是目前正在讨论的一个 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://aleo.up.railway.app/p/21">ARC-21提案</a>，讨论的目的主要是当前版本的SnarkOS/SnarkVM不支持动态合约调用或标准接口，这使得组合性难以实现。为了应对这一挑战，团队提出了一个多代币支持程序（MTSP），用于管理多个ARC-20代币的余额。MTSP作为标准“中心”，所有代币和DeFi合约都可以与其接口，简化了新代币的部署和DeFi合约的集成。此外，MTSP还提供隐私益处，掩盖具体代币的身份。下面是MTSP的具体实现。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">规范</h3><pre data-type="codeBlock" text="import credits.aleo;

// 定义MTSP程序
program mtsp.aleo {

  // 代币记录结构
  record Token {
    owner: address,
    amount: u128,
    token_id: field,
    authorized: bool,
    authorized_until: u32
  }

  // 代币元数据结构
  struct TokenMetadata {
    token_id: field,
    name: u128, // 代币名称，使用ASCII编码表示的比特串
    symbol: u128, // 代币符号，使用ASCII编码表示的比特串
    decimals: u8, // 小数位数
    supply: u128, // 代币供应量
    max_supply: u128, // 最大供应量
    admin: address, // 管理员地址
    external_authorization_required: bool // 是否需要外部程序授权
  }

  // 代币所有者结构
  struct TokenOwner {
    account: address,
    token_id: field
  }

  // 余额结构
  struct Balance {
    token_id: field,
    account: address,
    balance: u128,
    authorized_until: u32
  }

  // 授权结构
  struct Allowance {
    account: address,
    spender: address,
    token_id: field
  }

  // 映射
  mapping registered_tokens: field =&gt; TokenMetadata;
  mapping balances: field =&gt; Balance; // 余额映射
  mapping authorized_balances: field =&gt; Balance; // 授权余额映射
  mapping allowances: field =&gt; u128; // 授权映射

  // 代币管理员调用的方法

  // 注册代币
  transition register_token(token_id: field, name: u128, symbol: u128, decimals: u8, max_supply: u128, external_authorization_required: bool) {
    let token: TokenMetadata = TokenMetadata {
      token_id: token_id,
      name: name,
      symbol: symbol,
      decimals: decimals,
      supply: 0u128,
      max_supply: max_supply,
      admin: self.caller,
      external_authorization_required: external_authorization_required
    };
    return then finalize(token);
  }

  // 完成代币注册
  finalize register_token(token: TokenMetadata) {
    let token_exists: bool = registered_tokens.contains(token.token_id);
    assert_eq(token_exists, false); // 确保代币不存在
    registered_tokens.set(token.token_id, token); // 设置新代币
  }

  // 公开铸造代币
  transition mint_public(token_id: field, recipient: address, amount: u128, authorized_until: u32) {
    return then finalize(token_id, recipient, amount, authorized_until, self.caller);
  }

  // 完成公开铸造代币
  finalize mint_public(token_id: field, recipient: address, amount: u128, authorized_until: u32, token_admin: address) {
    let token: TokenMetadata = registered_tokens.get(token_id);
    assert_eq(token.admin, token_admin); // 检查调用者是否为代币管理员
    let new_supply: u128 = token.supply + amount;
    assert(new_supply &lt;= token.max_supply); // 确保供应量不超过最大供应量

    let token_owner: TokenOwner = TokenOwner {
      account: recipient,
      token_id: token_id
    };
    let balance_key: field = BHP256::hash_to_field(token_owner);
    let default_balance: Balance = Balance {
      token_id: token_id,
      account: recipient,
      balance: 0u128,
      authorized_until: authorized_until
    };
    let authorization_required: bool = token.external_authorization_required;
    let balance: Balance = authorization_required ? balances.get_or_use(balance_key, default_balance) : authorized_balances.get_or_use(balance_key, default_balance);
    let new_balance: Balance = Balance {
      token_id: token_id,
      account: recipient,
      balance: balance.balance + amount,
      authorized_until: balance.authorized_until
    };
    if (authorization_required) {
      balances.set(balance_key, new_balance); // 更新授权余额
    } else {
      authorized_balances.set(balance_key, new_balance); // 更新非授权余额
    }

    let new_metadata: TokenMetadata = TokenMetadata {
      token_id: token_id,
      name: token.name,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin,
      external_authorization_required: token.external_authorization_required
    };
    registered_tokens.set(token_id, new_metadata); // 更新代币元数据
  }

  // 私有铸造代币
  transition mint_private(token_id: field, recipient: address, amount: u128, authorized: bool, authorized_until: u32) -&gt; Token {
    let token: Token = Token {
      owner: recipient,
      amount: amount,
      token_id: token_id,
      authorized: authorized,
      authorized_until: authorized_until
    };

    return token then finalize(token_id, recipient, amount, authorized, self.caller);
  }

  // 完成私有铸造代币
  finalize mint_private(token_id: field, recipient: address, amount: u128, authorized: bool, token_admin: address) {
    let token: TokenMetadata = registered_tokens.get(token_id);
    assert_eq(token.admin, token_admin); // 检查调用者是否为代币管理员
    let new_supply: u128 = token.supply + amount;
    assert(new_supply &lt;= token.max_supply); // 确保供应量不超过最大供应量
    assert_eq(token.external_authorization_required, authorized); // 检查授权状态

    let new_metadata: TokenMetadata = TokenMetadata {
      token_id: token_id,
      name: token.name,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin,
      external_authorization_required: token.external_authorization_required
    };
    registered_tokens.set(token_id, new_metadata); // 更新代币元数据
  }

  // 公开销毁代币
  transition burn_public(owner: TokenOwner, amount: u128) {
    return then finalize(owner, amount, self.caller);
  }

  // 完成公开销毁代币
  finalize burn_public(owner: TokenOwner, amount: u128, token_admin: address) {
    let token: TokenMetadata = registered_tokens.get(owner.token_id);
    assert_eq(token.admin, token_admin); // 检查调用者是否为代币管理员
    let new_supply: u128 = token.supply - amount; // 更新供应量

    let balance_key: field = BHP256::hash_to_field(owner);
    let balance: Balance = balances.get(balance_key);
    let new_balance: Balance = Balance {
      token_id: owner.token_id,
      account: owner.account,
      balance: balance.balance - amount,
      authorized_until: balance.authorized_until
    };
    balances.set(balance_key, new_balance); // 更新余额

    let new_metadata: TokenMetadata = TokenMetadata {
      token_id: owner.token_id,
      name: token.name,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin,
      external_authorization_required: token.external_authorization_required
    };
    registered_tokens.set(owner.token_id, new_metadata); // 更新代币元数据
  }

  // 私有销毁代币
  transition burn_private(input_record: Token, amount: u128) -&gt; Token {
    let output_record: Token = Token {
        owner: input_record.owner,
        amount: input_record.amount - amount,
        token_id: input_record.token_id,
        authorized: input_record.authorized,
        authorized_until: input_record.authorized_until
    };
    return output_record then finalize(input_record.token_id, amount, self.caller);
  }

  // 完成私有销毁代币
  finalize burn_private(token_id: field, amount: u128, token_admin: address) {
    let token: TokenMetadata = registered_tokens.get(token_id);
    assert_eq(token.admin, token_admin); // 检查调用者是否为代币管理员
    let new_supply: u128 = token.supply - amount; // 更新供应量

    let new_metadata: TokenMetadata = TokenMetadata {
      token_id: token_id,
      name: token.name,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin
"><code><span class="hljs-keyword">import</span> <span class="hljs-title">credits</span>.<span class="hljs-title">aleo</span>;

<span class="hljs-comment">// 定义MTSP程序</span>
program mtsp.aleo {

  <span class="hljs-comment">// 代币记录结构</span>
  record Token {
    owner: <span class="hljs-keyword">address</span>,
    amount: u128,
    token_id: field,
    authorized: <span class="hljs-keyword">bool</span>,
    authorized_until: u32
  }

  <span class="hljs-comment">// 代币元数据结构</span>
  <span class="hljs-keyword">struct</span> <span class="hljs-title">TokenMetadata</span> {
    token_id: field,
    name: u128, <span class="hljs-comment">// 代币名称，使用ASCII编码表示的比特串</span>
    symbol: u128, <span class="hljs-comment">// 代币符号，使用ASCII编码表示的比特串</span>
    decimals: u8, <span class="hljs-comment">// 小数位数</span>
    supply: u128, <span class="hljs-comment">// 代币供应量</span>
    max_supply: u128, <span class="hljs-comment">// 最大供应量</span>
    admin: <span class="hljs-keyword">address</span>, <span class="hljs-comment">// 管理员地址</span>
    external_authorization_required: <span class="hljs-keyword">bool</span> <span class="hljs-comment">// 是否需要外部程序授权</span>
  }

  <span class="hljs-comment">// 代币所有者结构</span>
  <span class="hljs-keyword">struct</span> <span class="hljs-title">TokenOwner</span> {
    account: <span class="hljs-keyword">address</span>,
    token_id: field
  }

  <span class="hljs-comment">// 余额结构</span>
  <span class="hljs-keyword">struct</span> <span class="hljs-title">Balance</span> {
    token_id: field,
    account: <span class="hljs-keyword">address</span>,
    balance: u128,
    authorized_until: u32
  }

  <span class="hljs-comment">// 授权结构</span>
  <span class="hljs-keyword">struct</span> <span class="hljs-title">Allowance</span> {
    account: <span class="hljs-keyword">address</span>,
    spender: <span class="hljs-keyword">address</span>,
    token_id: field
  }

  <span class="hljs-comment">// 映射</span>
  <span class="hljs-keyword">mapping</span> registered_tokens: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> TokenMetadata;
  <span class="hljs-keyword">mapping</span> balances: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> Balance; <span class="hljs-comment">// 余额映射</span>
  <span class="hljs-keyword">mapping</span> authorized_balances: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> Balance; <span class="hljs-comment">// 授权余额映射</span>
  <span class="hljs-keyword">mapping</span> allowances: field <span class="hljs-operator">=</span><span class="hljs-operator">></span> u128; <span class="hljs-comment">// 授权映射</span>

  <span class="hljs-comment">// 代币管理员调用的方法</span>

  <span class="hljs-comment">// 注册代币</span>
  transition register_token(token_id: field, name: u128, symbol: u128, decimals: u8, max_supply: u128, external_authorization_required: <span class="hljs-keyword">bool</span>) {
    let token: TokenMetadata <span class="hljs-operator">=</span> TokenMetadata {
      token_id: token_id,
      name: name,
      symbol: symbol,
      decimals: decimals,
      supply: 0u128,
      max_supply: max_supply,
      admin: <span class="hljs-built_in">self</span>.caller,
      external_authorization_required: external_authorization_required
    };
    <span class="hljs-keyword">return</span> then finalize(token);
  }

  <span class="hljs-comment">// 完成代币注册</span>
  finalize register_token(token: TokenMetadata) {
    let token_exists: <span class="hljs-keyword">bool</span> <span class="hljs-operator">=</span> registered_tokens.contains(token.token_id);
    assert_eq(token_exists, <span class="hljs-literal">false</span>); <span class="hljs-comment">// 确保代币不存在</span>
    registered_tokens.set(token.token_id, token); <span class="hljs-comment">// 设置新代币</span>
  }

  <span class="hljs-comment">// 公开铸造代币</span>
  transition mint_public(token_id: field, recipient: <span class="hljs-keyword">address</span>, amount: u128, authorized_until: u32) {
    <span class="hljs-keyword">return</span> then finalize(token_id, recipient, amount, authorized_until, <span class="hljs-built_in">self</span>.caller);
  }

  <span class="hljs-comment">// 完成公开铸造代币</span>
  finalize mint_public(token_id: field, recipient: <span class="hljs-keyword">address</span>, amount: u128, authorized_until: u32, token_admin: <span class="hljs-keyword">address</span>) {
    let token: TokenMetadata <span class="hljs-operator">=</span> registered_tokens.get(token_id);
    assert_eq(token.admin, token_admin); <span class="hljs-comment">// 检查调用者是否为代币管理员</span>
    let new_supply: u128 <span class="hljs-operator">=</span> token.supply <span class="hljs-operator">+</span> amount;
    <span class="hljs-built_in">assert</span>(new_supply <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> token.max_supply); <span class="hljs-comment">// 确保供应量不超过最大供应量</span>

    let token_owner: TokenOwner <span class="hljs-operator">=</span> TokenOwner {
      account: recipient,
      token_id: token_id
    };
    let balance_key: field <span class="hljs-operator">=</span> BHP256::hash_to_field(token_owner);
    let default_balance: Balance <span class="hljs-operator">=</span> Balance {
      token_id: token_id,
      account: recipient,
      balance: 0u128,
      authorized_until: authorized_until
    };
    let authorization_required: <span class="hljs-keyword">bool</span> <span class="hljs-operator">=</span> token.external_authorization_required;
    let balance: Balance <span class="hljs-operator">=</span> authorization_required ? balances.get_or_use(balance_key, default_balance) : authorized_balances.get_or_use(balance_key, default_balance);
    let new_balance: Balance <span class="hljs-operator">=</span> Balance {
      token_id: token_id,
      account: recipient,
      balance: balance.<span class="hljs-built_in">balance</span> <span class="hljs-operator">+</span> amount,
      authorized_until: balance.authorized_until
    };
    <span class="hljs-keyword">if</span> (authorization_required) {
      balances.set(balance_key, new_balance); <span class="hljs-comment">// 更新授权余额</span>
    } <span class="hljs-keyword">else</span> {
      authorized_balances.set(balance_key, new_balance); <span class="hljs-comment">// 更新非授权余额</span>
    }

    let new_metadata: TokenMetadata <span class="hljs-operator">=</span> TokenMetadata {
      token_id: token_id,
      name: token.<span class="hljs-built_in">name</span>,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin,
      external_authorization_required: token.external_authorization_required
    };
    registered_tokens.set(token_id, new_metadata); <span class="hljs-comment">// 更新代币元数据</span>
  }

  <span class="hljs-comment">// 私有铸造代币</span>
  transition mint_private(token_id: field, recipient: <span class="hljs-keyword">address</span>, amount: u128, authorized: <span class="hljs-keyword">bool</span>, authorized_until: u32) <span class="hljs-operator">-</span><span class="hljs-operator">></span> Token {
    let token: Token <span class="hljs-operator">=</span> Token {
      owner: recipient,
      amount: amount,
      token_id: token_id,
      authorized: authorized,
      authorized_until: authorized_until
    };

    <span class="hljs-keyword">return</span> token then finalize(token_id, recipient, amount, authorized, <span class="hljs-built_in">self</span>.caller);
  }

  <span class="hljs-comment">// 完成私有铸造代币</span>
  finalize mint_private(token_id: field, recipient: <span class="hljs-keyword">address</span>, amount: u128, authorized: <span class="hljs-keyword">bool</span>, token_admin: <span class="hljs-keyword">address</span>) {
    let token: TokenMetadata <span class="hljs-operator">=</span> registered_tokens.get(token_id);
    assert_eq(token.admin, token_admin); <span class="hljs-comment">// 检查调用者是否为代币管理员</span>
    let new_supply: u128 <span class="hljs-operator">=</span> token.supply <span class="hljs-operator">+</span> amount;
    <span class="hljs-built_in">assert</span>(new_supply <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">=</span> token.max_supply); <span class="hljs-comment">// 确保供应量不超过最大供应量</span>
    assert_eq(token.external_authorization_required, authorized); <span class="hljs-comment">// 检查授权状态</span>

    let new_metadata: TokenMetadata <span class="hljs-operator">=</span> TokenMetadata {
      token_id: token_id,
      name: token.<span class="hljs-built_in">name</span>,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin,
      external_authorization_required: token.external_authorization_required
    };
    registered_tokens.set(token_id, new_metadata); <span class="hljs-comment">// 更新代币元数据</span>
  }

  <span class="hljs-comment">// 公开销毁代币</span>
  transition burn_public(owner: TokenOwner, amount: u128) {
    <span class="hljs-keyword">return</span> then finalize(owner, amount, <span class="hljs-built_in">self</span>.caller);
  }

  <span class="hljs-comment">// 完成公开销毁代币</span>
  finalize burn_public(owner: TokenOwner, amount: u128, token_admin: <span class="hljs-keyword">address</span>) {
    let token: TokenMetadata <span class="hljs-operator">=</span> registered_tokens.get(owner.token_id);
    assert_eq(token.admin, token_admin); <span class="hljs-comment">// 检查调用者是否为代币管理员</span>
    let new_supply: u128 <span class="hljs-operator">=</span> token.supply <span class="hljs-operator">-</span> amount; <span class="hljs-comment">// 更新供应量</span>

    let balance_key: field <span class="hljs-operator">=</span> BHP256::hash_to_field(owner);
    let balance: Balance <span class="hljs-operator">=</span> balances.get(balance_key);
    let new_balance: Balance <span class="hljs-operator">=</span> Balance {
      token_id: owner.token_id,
      account: owner.account,
      balance: balance.<span class="hljs-built_in">balance</span> <span class="hljs-operator">-</span> amount,
      authorized_until: balance.authorized_until
    };
    balances.set(balance_key, new_balance); <span class="hljs-comment">// 更新余额</span>

    let new_metadata: TokenMetadata <span class="hljs-operator">=</span> TokenMetadata {
      token_id: owner.token_id,
      name: token.<span class="hljs-built_in">name</span>,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin,
      external_authorization_required: token.external_authorization_required
    };
    registered_tokens.set(owner.token_id, new_metadata); <span class="hljs-comment">// 更新代币元数据</span>
  }

  <span class="hljs-comment">// 私有销毁代币</span>
  transition burn_private(input_record: Token, amount: u128) <span class="hljs-operator">-</span><span class="hljs-operator">></span> Token {
    let output_record: Token <span class="hljs-operator">=</span> Token {
        owner: input_record.owner,
        amount: input_record.amount <span class="hljs-operator">-</span> amount,
        token_id: input_record.token_id,
        authorized: input_record.authorized,
        authorized_until: input_record.authorized_until
    };
    <span class="hljs-keyword">return</span> output_record then finalize(input_record.token_id, amount, <span class="hljs-built_in">self</span>.caller);
  }

  <span class="hljs-comment">// 完成私有销毁代币</span>
  finalize burn_private(token_id: field, amount: u128, token_admin: <span class="hljs-keyword">address</span>) {
    let token: TokenMetadata <span class="hljs-operator">=</span> registered_tokens.get(token_id);
    assert_eq(token.admin, token_admin); <span class="hljs-comment">// 检查调用者是否为代币管理员</span>
    let new_supply: u128 <span class="hljs-operator">=</span> token.supply <span class="hljs-operator">-</span> amount; <span class="hljs-comment">// 更新供应量</span>

    let new_metadata: TokenMetadata <span class="hljs-operator">=</span> TokenMetadata {
      token_id: token_id,
      name: token.<span class="hljs-built_in">name</span>,
      symbol: token.symbol,
      decimals: token.decimals,
      supply: new_supply,
      max_supply: token.max_supply,
      admin: token.admin
</code></pre><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
        <item>
            <title><![CDATA[ARC-20: 同质化代币标准]]></title>
            <link>https://paragraph.com/@yaakov/arc-20</link>
            <guid>pi3ufzCVVXUjrM13y2AS</guid>
            <pubDate>Mon, 24 Jun 2024 08:31:08 GMT</pubDate>
            <description><![CDATA[Aleo 正在讨论中的ARC-20标准旨在为Aleo区块链提供代币互操作性和用户授权功能，类似于ERC-20。它允许代币轻松转账，并允许用户授权程序管理这些代币，特别适用于自动化金融应用。ARC-20标准的独特之处在于整合了Aleo的隐私特性，例如私有记录，提供用户在数字交易中的隐私和匿名性。这里我们将分别介绍这些方法。规范程序结构program token.aleo; mapping account: key as address.public; value as u64.public; record token: owner as address.private; amount as u64.private; struct approval: approver as address; spender as address; struct metadata: name as u128; // 16 bytes -> 16 characters with ASCII encoding symbol as u64; // 8 bytes -> 8 characters with A...]]></description>
            <content:encoded><![CDATA[<p>Aleo 正在讨论中的<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://aleo.up.railway.app/p/2bf1586d-b8de-419d-afac-f94f48a5de34">ARC-20标准</a>旨在为Aleo区块链提供代币互操作性和用户授权功能，类似于ERC-20。它允许代币轻松转账，并允许用户授权程序管理这些代币，特别适用于自动化金融应用。ARC-20标准的独特之处在于整合了Aleo的隐私特性，例如私有记录，提供用户在数字交易中的隐私和匿名性。这里我们将分别介绍这些方法。</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">规范</h3><p><strong>程序结构</strong></p><pre data-type="codeBlock" text="program token.aleo;

mapping account:
    key as address.public;
    value as u64.public;

record token:
    owner as address.private;
    amount as u64.private;

struct approval:
    approver as address;
    spender as address;

struct metadata:
    name as u128; // 16 bytes -&gt; 16 characters with ASCII encoding
    symbol as u64; // 8 bytes -&gt; 8 characters with ASCII encoding
    decimals as u8;
    total_supply as u64;

mapping approvals:
    key as field.public;
    value as u64.public;
"><code>program token.aleo;

<span class="hljs-keyword">mapping</span> account:
    key <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    value <span class="hljs-keyword">as</span> u64.public;

record token:
    owner <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.private;
    amount <span class="hljs-keyword">as</span> u64.private;

<span class="hljs-keyword">struct</span> <span class="hljs-title">approval</span>:
    <span class="hljs-title">approver</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>;
    <span class="hljs-title">spender</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>;

<span class="hljs-title"><span class="hljs-keyword">struct</span></span> <span class="hljs-title">metadata</span>:
    <span class="hljs-title">name</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">u128</span>; <span class="hljs-comment">// 16 bytes -> 16 characters with ASCII encoding</span>
    <span class="hljs-title">symbol</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">u64</span>; <span class="hljs-comment">// 8 bytes -> 8 characters with ASCII encoding</span>
    <span class="hljs-title">decimals</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">u8</span>;
    <span class="hljs-title">total_supply</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">u64</span>;

<span class="hljs-title"><span class="hljs-keyword">mapping</span></span> <span class="hljs-title">approvals</span>:
    <span class="hljs-title">key</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">field</span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span>;
    <span class="hljs-title">value</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">u64</span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span>;
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">核心功能介绍</h3><p><strong>1. 获取元数据</strong></p><pre data-type="codeBlock" text="function get_metadata:
    cast [name] [symbol] [decimals] [total_supply] into r0 as metadata;
    output r0 as metadata.public;
"><code>function get_metadata:
    cast <span class="hljs-section">[name]</span> <span class="hljs-section">[symbol]</span> <span class="hljs-section">[decimals]</span> <span class="hljs-section">[total_supply]</span> into r0 as metadata<span class="hljs-comment">;</span>
    output r0 as metadata.public<span class="hljs-comment">;</span>
</code></pre><p>此函数返回代币的元数据，包括名称、符号、小数位和总供应量。这些信息有助于钱包和dApp正确显示代币信息。</p><p><strong>2. 授权公共代币使用</strong></p><pre data-type="codeBlock" text="function approve_public:
    input r0 as address.public; // 授权的地址
    input r1 as u64.public; // 授权的代币数量

    cast self.caller r0 into r2 as approval;
    hash.bhp256 r2 into r3 as field;

    async approve_public r3 r1 into r4;
    output r4 as token.aleo/approve_public.future;

finalize approve_public:
    input r0 as field.public;
    input r1 as u64.public; // 增加授权的代币数量

    get.or_use approvals[r0] 0u64 into r2;
    add r1 r2 into r3;
    set r3 into approvals[r0];
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve_public</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span></span>; <span class="hljs-comment">// 授权的地址</span>
    input r1 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 授权的代币数量</span>

    cast <span class="hljs-built_in">self</span>.caller r0 into r2 <span class="hljs-keyword">as</span> approval;
    hash.bhp256 r2 into r3 <span class="hljs-keyword">as</span> field;

    async approve_public r3 r1 into r4;
    output r4 <span class="hljs-keyword">as</span> token.aleo/approve_public.future;

finalize approve_public:
    input r0 <span class="hljs-keyword">as</span> field.public;
    input r1 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 增加授权的代币数量</span>

    get.or_use approvals[r0] 0u64 into r2;
    add r1 r2 into r3;
    set r3 into approvals[r0];
</code></pre><p>此函数允许代币持有者授权某个地址使用一定数量的代币。这个功能对于允许智能合约代表用户执行代币操作至关重要。</p><p><strong>3. 取消授权</strong></p><pre data-type="codeBlock" text="function unapprove_public:
    input r0 as address.public; // 被取消授权的地址
    input r1 as u64.public; // 取消的代币数量

    cast self.caller r0 into r2 as approval;
    hash.bhp256 r2 into r3 as field;

    async unapprove_public r3 r1 into r4;
    output r4 as token.aleo/unapprove_public.future;

finalize unapprove_public:
    input r0 as field.public;
    input r1 as u64.public; // 减少授权的代币数量

    get approvals[r0] into r2;
    sub r2 r1 into r3;
    set r3 into approvals[r0];
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unapprove_public</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span></span>; <span class="hljs-comment">// 被取消授权的地址</span>
    input r1 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 取消的代币数量</span>

    cast <span class="hljs-built_in">self</span>.caller r0 into r2 <span class="hljs-keyword">as</span> approval;
    hash.bhp256 r2 into r3 <span class="hljs-keyword">as</span> field;

    async unapprove_public r3 r1 into r4;
    output r4 <span class="hljs-keyword">as</span> token.aleo/unapprove_public.future;

finalize unapprove_public:
    input r0 <span class="hljs-keyword">as</span> field.public;
    input r1 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 减少授权的代币数量</span>

    get approvals[r0] into r2;
    sub r2 r1 into r3;
    set r3 into approvals[r0];
</code></pre><p>此函数撤销之前授权的代币数量，用于减少或完全撤销对某个地址的授权。</p><p><strong>4. 从公共账户转账</strong></p><pre data-type="codeBlock" text="function transfer_from_public:
    input r0 as address.public; // 授权者
    input r1 as address.public; // 接收者
    input r2 as u64.public; // 转账数量

    cast r0 self.caller into r3 as approval;
    hash.bhp256 r3 into r4 as field;

    async transfer_from_public r4 r0 r1 r2 into r5;
    output r5 as token.aleo/transfer_from_public.future;

finalize transfer_from_public:
    input r0 as field.public;
    input r1 as address.public;
    input r2 as address.public;
    input r3 as u64.public;

    get approvals[r0] into r4;
    sub r4 r3 into r5;
    set r5 into approvals[r0];
    get account[r1] into r6;
    sub r6 r3 into r7;
    set r7 into account[r1];
    get.or_use account[r2] 0u64 into r8;
    add r8 r3 into r9;
    set r9 into account[r2];
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer_from_public</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span></span>; <span class="hljs-comment">// 授权者</span>
    input r1 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public; <span class="hljs-comment">// 接收者</span>
    input r2 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 转账数量</span>

    cast r0 <span class="hljs-built_in">self</span>.caller into r3 <span class="hljs-keyword">as</span> approval;
    hash.bhp256 r3 into r4 <span class="hljs-keyword">as</span> field;

    async transfer_from_public r4 r0 r1 r2 into r5;
    output r5 <span class="hljs-keyword">as</span> token.aleo/transfer_from_public.future;

finalize transfer_from_public:
    input r0 <span class="hljs-keyword">as</span> field.public;
    input r1 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    input r2 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    input r3 <span class="hljs-keyword">as</span> u64.public;

    get approvals[r0] into r4;
    sub r4 r3 into r5;
    set r5 into approvals[r0];
    get account[r1] into r6;
    sub r6 r3 into r7;
    set r7 into account[r1];
    get.or_use account[r2] 0u64 into r8;
    add r8 r3 into r9;
    set r9 into account[r2];
</code></pre><p>此函数实现从授权者账户向接收者账户的代币转账，用于实现代币的自动化管理和支付。</p><p><strong>5. 公共代币转账</strong></p><pre data-type="codeBlock" text="function transfer_public:
    input r0 as address.public; // 接收者地址
    input r1 as u64.public; // 转账数量

    async transfer_public self.caller r0 r1 into r2;
    output r2 as token.aleo/transfer_public.future;

finalize transfer_public:
    input r0 as address.public;
    input r1 as address.public;
    input r2 as u64.public;

    get.or_use account[r0] 0u64 into r3;
    sub r3 r2 into r4;
    set r4 into account[r0];
    get.or_use account[r1] 0u64 into r5;
    add r5 r2 into r6;
    set r6 into account[r1];
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer_public</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span></span>; <span class="hljs-comment">// 接收者地址</span>
    input r1 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 转账数量</span>

    async transfer_public <span class="hljs-built_in">self</span>.caller r0 r1 into r2;
    output r2 <span class="hljs-keyword">as</span> token.aleo/transfer_public.future;

finalize transfer_public:
    input r0 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    input r1 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    input r2 <span class="hljs-keyword">as</span> u64.public;

    get.or_use account[r0] 0u64 into r3;
    sub r3 r2 into r4;
    set r4 into account[r0];
    get.or_use account[r1] 0u64 into r5;
    add r5 r2 into r6;
    set r6 into account[r1];
</code></pre><p>此函数将代币从调用者账户转移到指定的公共账户，实现简单的代币转账。</p><p><strong>6. 私有代币转账</strong></p><pre data-type="codeBlock" text="function transfer_private:
    input r0 as token.record; // 代币记录
    input r1 as address.private; // 接收者地址
    input r2 as u64.private; // 转账数量

    sub r0.amount r2 into r3;
    cast r0.owner r3 into r4 as token.record;
    cast r1 r2 into r5 as token.record;
    output r4 as token.record;
    output r5 as token.record;
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer_private</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">token</span>.<span class="hljs-title">record</span></span>; <span class="hljs-comment">// 代币记录</span>
    input r1 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.private; <span class="hljs-comment">// 接收者地址</span>
    input r2 <span class="hljs-keyword">as</span> u64.private; <span class="hljs-comment">// 转账数量</span>

    sub r0.amount r2 into r3;
    cast r0.owner r3 into r4 <span class="hljs-keyword">as</span> token.record;
    cast r1 r2 into r5 <span class="hljs-keyword">as</span> token.record;
    output r4 <span class="hljs-keyword">as</span> token.record;
    output r5 <span class="hljs-keyword">as</span> token.record;
</code></pre><p>此函数实现私有代币的转账，用于在保持交易隐私的情况下进行代币转移。</p><p><strong>7. 私有代币转公共代币</strong></p><pre data-type="codeBlock" text="function transfer_private_to_public:
    input r0 as token.record; // 私有代币记录
    input r1 as address.public; // 公共接收者地址
    input r2 as u64.public; // 转账数量

    sub r0.amount r2 into r3;
    cast r0.owner r3 into r4 as token.record;
    async transfer_private_to_public r1 r2 into r5;
    output r4 as token.record;
    output r5 as token.aleo/transfer_private_to_public.future;

finalize transfer_private_to_public:
    input r0 as address.public;
    input r1 as u64.public;

    get.or_use account[r0] 0u64 into r2;
    add r2 r1 into r3;
    set r3 into account[r0];
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer_private_to_public</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">token</span>.<span class="hljs-title">record</span></span>; <span class="hljs-comment">// 私有代币记录</span>
    input r1 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public; <span class="hljs-comment">// 公共接收者地址</span>
    input r2 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 转账数量</span>

    sub r0.amount r2 into r3;
    cast r0.owner r3 into r4 <span class="hljs-keyword">as</span> token.record;
    async transfer_private_to_public r1 r2 into r5;
    output r4 <span class="hljs-keyword">as</span> token.record;
    output r5 <span class="hljs-keyword">as</span> token.aleo/transfer_private_to_public.future;

finalize transfer_private_to_public:
    input r0 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    input r1 <span class="hljs-keyword">as</span> u64.public;

    get.or_use account[r0] 0u64 into r2;
    add r2 r1 into r3;
    set r3 into account[r0];
</code></pre><p>此函数将私有代币转换为公共代币，允许在公共账户中持有之前私有的代币。</p><p><strong>8. 公共代币转私有代币</strong></p><pre data-type="codeBlock" text="function transfer_public_to_private:
    input r0 as address.public; // 公共账户地址
    input r1 as u64.public; // 转账数量

    cast r0 r1 into r2 as token.record;
    async transfer_public_to_private self.caller r1 into r3;
    output r2 as token.record;
    output r3 as token.aleo/transfer_public_to_private.future;

finalize transfer_public_to_private:
    input r0 as address.public;
    input r1 as u64.public;

    get.or_use account[r0] 0u64 into r2;
    sub r2 r1 into r3;
    set r3 into account[r0];
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer_public_to_private</span>:
    <span class="hljs-title">input</span> <span class="hljs-title">r0</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>.<span class="hljs-title"><span class="hljs-keyword">public</span></span></span>; <span class="hljs-comment">// 公共账户地址</span>
    input r1 <span class="hljs-keyword">as</span> u64.public; <span class="hljs-comment">// 转账数量</span>

    cast r0 r1 into r2 <span class="hljs-keyword">as</span> token.record;
    async transfer_public_to_private <span class="hljs-built_in">self</span>.caller r1 into r3;
    output r2 <span class="hljs-keyword">as</span> token.record;
    output r3 <span class="hljs-keyword">as</span> token.aleo/transfer_public_to_private.future;

finalize transfer_public_to_private:
    input r0 <span class="hljs-keyword">as</span> <span class="hljs-keyword">address</span>.public;
    input r1 <span class="hljs-keyword">as</span> u64.public;

    get.or_use account[r0] 0u64 into r2;
    sub r2 r1 into r3;
    set r3 into account[r0];
</code></pre><p>此函数将公共代币转换为私有代币，以确保交易隐私和安全。</p><p>通过这些规范和示例代码，ARC-20标准在Aleo区块链上实现了兼容且安全的同质化代币管理。</p><p><strong>Aleo 官方链接：</strong></p><blockquote><ul><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/aleohq"><em>Twitter</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://discord.gg/aleo"><em>Discord</em></a></p></li><li><p><em>Aleo </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aleo.org/"><em>Website</em></a></p></li><li><p>Aleo <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ProvableHQ">Github</a></p></li></ul></blockquote>]]></content:encoded>
            <author>yaakov@newsletter.paragraph.com (Yaakov)</author>
        </item>
    </channel>
</rss>