Tu Primera Moneda
Este tutorial introduce cómo puedes compilar, desplegar y acuñar tu propia moneda (como se define aquí), llamada MoonCoin.
Paso 1: Elige un SDK
Sección titulada «Paso 1: Elige un SDK»Instala tu SDK preferido de la lista de abajo:
Paso 2: Instala el CLI
Sección titulada «Paso 2: Instala el CLI»Instala el binario precompilado para el Aptos CLI.
Paso 3: Ejecuta el ejemplo
Sección titulada «Paso 3: Ejecuta el ejemplo»Clona el repositorio aptos-ts-sdk
y compílalo:
git clone https://github.com/aptos-labs/aptos-ts-sdk.gitcd aptos-ts-sdkpnpm installpnpm build
Navega al directorio de ejemplos de TypeScript:
cd examples/typescript/
Instala las dependencias necesarias:
pnpm install
Ejecuta el ejemplo de TypeScript your_coin
:
pnpm run your_coin
La aplicación se completará, imprimiendo:
Balance inicial de MoonCoin de Bob: 0.Alice se acuña 100 MoonCoin.Alice transfiere 100 MoonCoin a Bob.Balance actualizado de MoonCoin de Bob: 100.
Clona el repositorio aptos-core
:
git clone https://github.com/aptos-labs/aptos-core
Navega al directorio del SDK de Python:
cd aptos-core/ecosystem/python/sdk
Instala las dependencias necesarias:
curl -sSL https://install.python-poetry.org | python3poetry install
Ejecuta el ejemplo de Python your_coin
:
poetry run python -m examples.your_coin ~/aptos-core/aptos-move/move-examples/moon_coin
Paso 3.1: Compila el paquete
Sección titulada «Paso 3.1: Compila el paquete»La ejecución del ejemplo se pausará con la siguiente salida:
=== Direcciones ===Alice: 0x5e603a89cf690d7134cf2f24fdb16ba90c4f5686333721c12e835fb6c76bc7baBob: 0xc8421fa4a99153f955e50f1de2a6acff2f3fd0bb33aa17ba1f5b32b699f6c825
Actualiza el paquete con la dirección de Alice, compila y presiona enter.
At this point, open another terminal and change directories to the MoonCoin package’s directory:
cd ~/aptos-core/aptos-move/move-examples/moon_coin
Next, build the package using the CLI:
aptos move compile --named-addresses MoonCoin=0x5e603a89cf690d7134cf2f24fdb16ba90c4f5686333721c12e835fb6c76bc7ba --save-metadata
The --named-addresses
is a list of address mappings that must be translated in order for the package to be compiled to be stored in Alice’s account. Notice how MoonCoin
is set to Alice’s address printed above. Also --save-metadata
is required to publish the package.
Step 3.2: Completing the example
Sección titulada «Step 3.2: Completing the example»Returning to the previous prompt, press ENTER as the package is now ready to be published.
The application will complete, printing:
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.
Step 4: MoonCoin in depth
Sección titulada «Step 4: MoonCoin in depth»Step 4.1: Building and publishing the MoonCoin package
Sección titulada «Step 4.1: Building and publishing the MoonCoin package»Move contracts are effectively a set of Move modules known as a package. When deploying or upgrading a new package, the compiler must be invoked with --save-metadata
to publish the package. In the case of MoonCoin, the following output files are critical:
build/Examples/package-metadata.bcs
: Contains the metadata associated with the package.build/Examples/bytecode_modules/moon_coin.mv
: Contains the bytecode for themoon_coin.move
module.
These are read by the example and published to the Aptos blockchain:
In the TypeScript example, we use aptos move build-publish-payload
command to compile and build the module.
That command builds the build
folder that contains the package-metadata.bcs
and the bytecode for the moon_coin.mv
module. The command also builds a publication transaction payload and stores it in a JSON output file that we can later read from to get the metadataBytes
and byteCode
to publish the contract to chain with.
Compile the package:
export function compilePackage( packageDir: string, outputFile: string, namedAddresses: Array<{ name: string; address: AccountAddress }>,) { const addressArg = namedAddresses .map(({ name, address }) => `${name}=${address}`) .join(" "); // Assume-yes automatically overwrites the previous compiled version, only do this if you are sure you want to overwrite the previous version. const compileCommand = `aptos move build-publish-payload --json-output-file ${outputFile} --package-dir ${packageDir} --named-addresses ${addressArg} --assume-yes`; execSync(compileCommand);}
compilePackage("move/moonCoin", "move/moonCoin/moonCoin.json", [ { name: "MoonCoin", address: alice.accountAddress },]);
Publish the package to chain:
export function getPackageBytesToPublish(filePath: string) { // current working directory - the root folder of this repo const cwd = process.cwd(); // target directory - current working directory + filePath (filePath JSON file is generated with the previous, compilePackage, CLI command) const modulePath = path.join(cwd, filePath);
const jsonData = JSON.parse(fs.readFileSync(modulePath, "utf8"));
const metadataBytes = jsonData.args[0].value; const byteCode = jsonData.args[1].value;
return { metadataBytes, byteCode };}
const { metadataBytes, byteCode } = getPackageBytesToPublish( "move/moonCoin/moonCoin.json",);
// Publish MoonCoin package to chainconst transaction = await aptos.publishPackageTransaction({ account: alice.accountAddress, metadataBytes, moduleBytecode: byteCode,});
const pendingTransaction = await aptos.signAndSubmitTransaction({ signer: alice, transaction,});
await aptos.waitForTransaction({ transactionHash: pendingTransaction.hash });
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.")package_publisher = PackagePublisher(rest_client)txn_hash = await package_publisher.publish_package(alice, metadata, [module])await rest_client.wait_for_transaction(txn_hash)
Step 4.2: Understanding the MoonCoin module
Sección titulada «Step 4.2: Understanding the MoonCoin module»The MoonCoin module defines the MoonCoin
struct, or the distinct type of coin type. In addition, it contains a function called init_module
. The init_module
function is called when the module is published. In this case, MoonCoin initializes the MoonCoin
coin type as a ManagedCoin
, which is maintained by the owner of the account.
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, ); }}
Step 4.3: Understanding coins
Sección titulada «Step 4.3: Understanding coins»Coins have several primitives:
- Minting: Creating new coins.
- Burning: Deleting coins.
- Freezing: Preventing an account from storing coins in
CoinStore
. - Registering: Creating a
CoinStore
resource on an account for storing coins. - Transferring: Withdrawing and depositing coins into
CoinStore
.
Step 4.3.1: Initializing a coin
Sección titulada «Step 4.3.1: Initializing a coin»Once a coin type has been published to the Aptos blockchain, the entity that published that coin type can initialize it:
module 0x1::coin { 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>{ }) }}
This ensures that this coin type has never been initialized before. Notice the check on lines 10 and 15 to ensure that the caller to initialize
is the same one that actually published this module, and that there is no CoinInfo
stored on their account. If both those conditions check, then a CoinInfo
is stored and the caller obtains capabilities for burning, freezing, and minting.
Step 4.3.2: Registering a coin
Sección titulada «Step 4.3.2: Registering a coin»To use a coin, an entity must register a CoinStore
for it on their account:
public entry fun registerCoinType(account: &signer) {
MoonCoin uses ManagedCoin
that provides an entry function wrapper: managed_coin::register
. Here is an example script for registration:
script { fun register(account: &signer) { aptos_framework::managed_coin::register<MoonCoin::moon_coin::MoonCoin>(account) }}
Step 4.3.3: Minting a coin
Sección titulada «Step 4.3.3: Minting a coin»Minting coins requires the mint capability that was produced during initialization. the function mint
(see below) takes in that capability and an amount, and returns back a Coin<T>
struct containing that amount of coins. If the coin tracks supply, it will be updated.
module 0x1::coin { 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
makes this easier by providing an entry function managed_coin::mint
.
Step 4.3.4: Transferring a coin
Sección titulada «Step 4.3.4: Transferring a coin»Aptos provides several building blocks to support coin transfers:
coin::deposit<CoinType>
: Allows any entity to deposit a coin into an account that has already calledcoin::register<CoinType>
.coin::withdraw<CoinType>
: Allows any entity to extract a coin amount from their account.aptos_account::transfer_coins<CoinType>
: Transfer coins of specific CoinType to a receiver.