# 第一个代币

本教程介绍了如何编译、部署和铸造 *Moon Coin* 代币。

## 第 1 步：选择 SDK

* [官方 Aptos Typescript SDK](https://aptos.dev/sdks/typescript-sdk)
* [官方 Aptos Python SDK](https://aptos.dev/sdks/python-sdk)
* [官方 Aptos Rust SDK](https://aptos.dev/sdks/rust-sdk)

## 第 2 步：获取 CLI

[从 Git 安装 CLI](https://aptos.dev/cli-tools/aptos-cli-tool/install-aptos-cli)

## 第 3 步：运行示例

克隆 `aptos-core`：

```bash
git clone <https://github.com/aptos-labs/aptos-core.git>
```

### 第 3.1 步：SDK 特定示例

* Typescript

  导航至 Typescript SDK 目录：

  ```bash
  cd ~/aptos-core/ecosystem/typescript/sdk
  ```

  安装必要的依赖项

  ```bash
  yarn
  ```

  运行 `your_coin` 示例：

  ```bash
  yarn your_coin ~/aptos-core/aptos-move/move-examples/moon_coin
  ```
* Python

  导航至 Python SDK 目录：

  ```bash
  cd ~/aptos-core/ecosystem/python/sdk
  ```

  安装必要的依赖项

  ```bash
  curl -sSL <https://install.python-poetry.org> | python3
  poetry update
  ```

  运行 `your_coin` 示例：

  ```bash
  poetry run python -m examples.your-coin ~/aptos-core/aptos-move/move-examples/moon_coin
  ```
* Rust

  待发布

### 第 3.2 步：构建包

进行到一半时，demo 会暂停并显示以下输出：

```
=== Addresses ===
Alice: 0x5e603a89cf690d7134cf2f24fdb16ba90c4f5686333721c12e835fb6c76bc7ba
Bob: 0xc8421fa4a99153f955e50f1de2a6acff2f3fd0bb33aa17ba1f5b32b699f6c825

Update the package with Alice's address, compile, and press enter.
```

此时，打开另一个终端并将目录更改为 *MoonCoin* 包的目录

```bash
cd ~/aptos-core/aptos-move/move-examples/moon_coin
```

现在使用 CLI 构建包：

```
aptos move compile --named-addresses MoonCoin=0x5e603a89cf690d7134cf2f24fdb16ba90c4f5686333721c12e835fb6c76bc7ba --save-metadata
```

`--named-addresses` 是一个必须转译的地址映射表，让编译后的软件包能够存储到 Alice 的帐户中。注意 `MoonCoin` 是如何被设置为上面显示的 Alice 地址的。另外，为了发布软件包，还需要 `--save-metadata`。

### 第 3.3 步：完成示例

返回前面的提示，按回车键，现在软件包已经准备好发布了。

应用程序将完成，显示：

```
Publishing MoonCoin package.

Bob registers the newly created coin so he can receive it from Alice.
Bob's initial MoonCoin balance: 0.
Alice mints Bob some of the new coin.
Bob's updated MoonCoin balance: 100.
```

## 第 4 步：深入了解 *MoonCoin*

### 第 4.1 步：构建和发布 *MoonCoin* 包

Move 软件或合约实际上是一组被称为包的模块。在部署或升级一个新的软件包时，必须用 `--save-metadata` 来调用编译器，以便发布该软件包。在 MoonCoin 的案例中，以下输出文件是至关重要的：

* `build/Examples/package-metadata.bcs` ——与软件包相关的元数据
* `build/Examples/bytecode_modules/moon_coin.mv` —— `moon_coin.move` 模块的字节码

这些都由示例读取并发布到区块链上：

* Typescript

  ```tsx
  const modulePath = process.argv[2];
  const packageMetadata = fs.readFileSync(path.join(modulePath, "build", "Examples", "package-metadata.bcs"));
  const moduleData = fs.readFileSync(path.join(modulePath, "build", "Examples", "bytecode_modules", "moon_coin.mv"));

  console.log("Publishing MoonCoin package.");
  let txnHash = await client.publishPackage(alice, new HexString(packageMetadata.toString("hex")).toUint8Array(), [
    new TxnBuilderTypes.Module(new HexString(moduleData.toString("hex")).toUint8Array()),
  ]);
  await client.waitForTransaction(txnHash, { checkSuccess: true });
  ```
* Python

  ```python
  moon_coin_path = sys.argv[1]
  module_path = os.path.join(
      moon_coin_path, "build", "Examples", "bytecode_modules", "moon_coin.mv"
  )
  with open(module_path, "rb") as f:
      module = f.read()

  metadata_path = os.path.join(
      moon_coin_path, "build", "Examples", "package-metadata.bcs"
  )
  with open(metadata_path, "rb") as f:
      metadata = f.read()

  print("\\nPublishing MoonCoin package.")
  txn_hash = rest_client.publish_package(alice, metadata, [module])
  rest_client.wait_for_transaction(txn_hash)
  ```
* Rust

  待发布

### 第 4.2 步：了解 *MoonCoin* 模块

MoonCoin 模块定义了 MoonCoin 结构，即不同的代币类型。此外，它还包含一个叫做 `init_module` 的函数。 `init_module` 在模块发布时被调用。在这种情况下，MoonCoin 将`MoonCoin` 币种初始化为 `ManagedCoin`，该币种由帐户所有者维护。`[ManagedCoin](<https://github.com/aptos-labs/aptos-core/blob/f81ccb01f00227f9c0f36856fead4879f185a9f6/aptos-move/framework/aptos-framework/sources/managed_coin.move#L1>)` 是一个简单的 代币管理框架，由用户直接管理代币。它为铸造和销毁提供了便捷的包装。

```rust
module MoonCoin::moon_coin {
    struct MoonCoin {}

    fun init_module(sender: &signer) {
        aptos_framework::managed_coin::initialize<MoonCoin>(
            sender,
            b"Moon Coin",
            b"MOON",
            6,
            false,
        );
    }
}
```

### 第 4.3 步：了解代币

代币有几个基本要素：

* 铸造——创造新的代币
* 销毁——删除代币
* 冻结——阻止一个帐户在 CoinStore 中储存代币
* 注册——在一个帐户上创建一个用于存储代币的 CoinStore 资源
* 转移——在 CoinStore 中提款和存款

创建一个新代币的实体也有铸造、销毁和冻结代币的能力。

为了转移、提取或存入代币，必须有一个为特定代币注册的 CoinStore。在本教程中，这就是 `CoinStore<MoonCoin>`

#### 第 4.3.1 步：初始化代币

一旦代币类型发布到区块链上，发布该代币的实体可以初始化代币：

```rust
public fun initialize<CoinType>(
    account: &signer,
    name: string::String,
    symbol: string::String,
    decimals: u8,
    monitor_supply: bool,
): (BurnCapability<CoinType>, FreezeCapability<CoinType>, MintCapability<CoinType>) {
    let account_addr = signer::address_of(account);

    assert!(
        coin_address<CoinType>() == account_addr,
        error::invalid_argument(ECOIN_INFO_ADDRESS_MISMATCH),
    );

    assert!(
        !exists<CoinInfo<CoinType>>(account_addr),
        error::already_exists(ECOIN_INFO_ALREADY_PUBLISHED),
    );

    let coin_info = CoinInfo<CoinType> {
        name,
        symbol,
        decimals,
        supply: if (monitor_supply) { option::some(optional_aggregator::new(MAX_U128, false)) } else { option::none() },
    };
    move_to(account, coin_info);

    (BurnCapability<CoinType>{ }, FreezeCapability<CoinType>{ }, MintCapability<CoinType>{ })
}
```

这样可以确保这种代币类型之前未被初始化过，注意检查以确保初始化的调用者确实发布了这个模块，并且他们的帐户上没有存储 `CoinInfo`。如果这两个条件都符合，那么就会存储一个 `CoinInfo`，调用者就会获得销毁、冻结和铸造的能力。

*MoonCoin* 软件包发布时自动调用这个函数。

#### 第 4.3.2 步：注册代币

实体必须在他们的帐户上为代币注册一个 `CoinStore` 才能使用代币：

```rust
public fun register<CoinType>(account: &signer) {
    let account_addr = signer::address_of(account);
    assert!(
        !is_account_registered<CoinType>(account_addr),
        error::already_exists(ECOIN_STORE_ALREADY_PUBLISHED),
    );

    account::register_coin<CoinType>(account_addr);
    let coin_store = CoinStore<CoinType> {
        coin: Coin { value: 0 },
        frozen: false,
        deposit_events: account::new_event_handle<DepositEvent>(account),
        withdraw_events: account::new_event_handle<WithdrawEvent>(account),
    };
    move_to(account, coin_store);
}
```

由于这是一个 `public fun` 而不是一个 `public entry fun` ，代币需要提供注册方式，或者用户可以构建 Move 脚本来调用该功能。

MoonCoin 使用 `ManagedCoin`，它提供了一个入口函数封装器：`managed_coin::register`

#### 第 4.3.3 步：铸造代币

铸造代币需要初始化时产生的铸造能力。它接受该功能和数量并返回一个包含代币数量的 `Coin<T>` 结构。它将在代币跟踪供应时更新。

```rust
public fun mint<CoinType>(
    amount: u64,
    _cap: &MintCapability<CoinType>,
): Coin<CoinType> acquires CoinInfo {
    if (amount == 0) {
        return zero<CoinType>()
    };

    let maybe_supply = &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;
    if (option::is_some(maybe_supply)) {
        let supply = option::borrow_mut(maybe_supply);
        optional_aggregator::add(supply, (amount as u128));
    };

    Coin<CoinType> { value: amount }
}
```

`ManagedCoin` 通过提供一个入口函数 `managed_coin::mint` 让这个过程变得更容易。

#### 第 4.3.4 步：转移代币

Aptos 提供了几个构建块来支持转移：

* `coin::deposit<CoinType>`允许任何实体将代币存入已经调用 `coin::register<CoinType>` 的帐户
* `coin::withdraw<CoinType>`允许任何实体从其帐户中提取代币金额
* `coin::transfer<CoinType>`利用提款和存款来执行端到端的转账

Aptos 不会发出转账事件，而是利用提款和存款事件。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gushi10546.gitbook.io/aptos-kai-fa-zhe-wen-dang/kai-fa-zhe-jiao-cheng/di-yi-ge-dai-bi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
