Im vorherigen Artikel haben wir kurz vorgestellt, wie man ein Hello World-Programm im Aptos-Netzwerk entwickelt. Von nun an werden wir uns etwas tiefer mit der Entwicklung von DeFi-Anwendungen und deren Sicherheitsaspekten befassen. Wie immer möchten wir mit einigen grundlegenden, aber wichtigen Konzepten beginnen. In diesem Artikel werden wir uns auf Aptos Coin konzentrieren (d. h. den fungiblen Token in Aptos [1]), einschließlich seiner Entwicklung und Verwaltung sowie Interaktion.
TL;DR
Dieser Artikel wird Ihnen Folgendes erklären:
- Was ist Aptos Coin?
- Wie erstelle und verwalte ich meinen Coin?
- Wie interagiere ich mit meinem Coin?
0x1. Über Aptos Coin
Als Atome von DeFi werden Tokens (oder Coins) in Blockchain-Ökosystemen weit verbreitet eingesetzt. Sie können zur Darstellung vieler Arten von Dingen verwendet werden, einschließlich elektronischer Währungen, Staking-Anteile und Stimmrechte für die Verwaltung von Organisationen. Bis zu einem gewissen Grad kann die tägliche Aktivität von DeFi einfach als ein riesiges Volumen an Token-Flüssen über Blockchain-Systeme betrachtet werden.
Ethereum hat einen Satz von Standards für Tokens entwickelt. Der bekannteste ist ERC20, der Schnittstellen definiert, denen ein Standard ERC20 Token entsprechen muss. ERC20 ist ein Standard für fungible Tokens, während es auch Standards für nicht-fungible Tokens gibt, wie z.B. ERC721.
Ähnlich wie andere Blockchain-Systeme verfügt auch Aptos über seinen Token-Standard [2], der definiert, wie digitale Assets auf den jeweiligen Blockchains erstellt und verwendet werden. Insbesondere in Aptos wird der fungible Token als Coin bezeichnet, während der nicht-fungible Token (d. h. NFT) Token genannt wird. Im Folgenden werden wir die Erstellung, Verwaltung und Interaktion mit einem Aptos Coin besprechen.
0x2. Erstelle und verwalte deinen ersten Coin
Aptos bietet ein offizielles Standardmodul (ähnlich wie ERC20): coin.move. Durch den Aufruf der API dieses Moduls kann jeder Benutzer ganz einfach seinen eigenen Coin erstellen. Darüber hinaus bietet coin.move auch einen Berechtigungsmechanismus zur Verwaltung von Coins, der für den Aufbau komplexer DeFi-Anwendungen wichtig und nützlich ist. Im Folgenden werden wir demonstrieren, wie ein Coin basierend auf diesem Modul erstellt wird.
Wie im vorherigen Artikel erwähnt, können Sie ein Projekt erstellen, indem Sie den folgenden Befehl eingeben:
aptos move init --name my_coin
Anschließend müssen Sie eine neue Move-Datei unter dem Ordner sources erstellen. Füllen wir sie nun mit dem folgenden Beispielcode, der ein Modul namens bsc definiert, um einen Standard-Coin namens BSC zu erstellen und zu verwalten.
module BlockSec::bsc{
use aptos_framework::coin;
use aptos_framework::event;
use aptos_framework::account;
use aptos_std::type_info;
use std::string::{utf8, String};
use std::signer;
struct BSC{}
struct CapStore has key{
mint_cap: coin::MintCapability<BSC>,
freeze_cap: coin::FreezeCapability<BSC>,
burn_cap: coin::BurnCapability<BSC>
}
struct BSCEventStore has key{
event_handle: event::EventHandle<String>,
}
fun init_module(account: &signer){
let (burn_cap, freeze_cap, mint_cap) = coin::initialize<BSC>(account, utf8(b"BSC"), utf8(b"BSC"), 6, true);
move_to(account, CapStore{mint_cap: mint_cap, freeze_cap: freeze_cap, burn_cap: burn_cap});
}
public entry fun register(account: &signer){
let address_ = signer::address_of(account);
if(!coin::is_account_registered<BSC>(address_)){
coin::register<BSC>(account);
};
if(!exists<BSCEventStore>(address_)){
move_to(account, BSCEventStore{event_handle: account::new_event_handle(account)});
};
}
fun emit_event(account: address, msg: String) acquires BSCEventStore{
event::emit_event<String>(&mut borrow_global_mut<BSCEventStore>(account).event_handle, msg);
}
public entry fun mint_coin(cap_owner: &signer, to_address: address, amount: u64) acquires CapStore, BSCEventStore{
let mint_cap = &borrow_global<CapStore>(signer::address_of(cap_owner)).mint_cap;
let mint_coin = coin::mint<BSC>(amount, mint_cap);
coin::deposit<BSC>(to_address, mint_coin);
emit_event(to_address, utf8(b"minted BSC"));
}
public entry fun burn_coin(account: &signer, amount: u64) acquires CapStore, BSCEventStore{
let owner_address = type_info::account_address(&type_info::type_of<BSC>());
let burn_cap = &borrow_global<CapStore>(owner_address).burn_cap;
let burn_coin = coin::withdraw<BSC>(account, amount);
coin::burn<BSC>(burn_coin, burn_cap);
emit_event(signer::address_of(account), utf8(b"burned BSC"));
}
public entry fun freeze_self(account: &signer) acquires CapStore, BSCEventStore{
let owner_address = type_info::account_address(&type_info::type_of<BSC>());
let freeze_cap = &borrow_global<CapStore>(owner_address).freeze_cap;
let freeze_address = signer::address_of(account);
coin::freeze_coin_store<BSC>(freeze_address, freeze_cap);
emit_event(freeze_address, utf8(b"freezed self"));
}
public entry fun emergency_freeze(cap_owner: &signer, freeze_address: address) acquires CapStore, BSCEventStore{
let owner_address = signer::address_of(cap_owner);
let freeze_cap = &borrow_global<CapStore>(owner_address).freeze_cap;
coin::freeze_coin_store<BSC>(freeze_address, freeze_cap);
emit_event(freeze_address, utf8(b"emergency freezed"));
}
public entry fun unfreeze(cap_owner: &signer, unfreeze_address: address) acquires CapStore, BSCEventStore{
let owner_address = signer::address_of(cap_owner);
let freeze_cap = &borrow_global<CapStore>(owner_address).freeze_cap;
coin::unfreeze_coin_store<BSC>(unfreeze_address, freeze_cap);
emit_event(unfreeze_address, utf8(b"unfreezed"));
}
}
0x2.1 Grundlegende Gestaltung
Betrachten wir zuerst den Strukturteil. Insgesamt werden drei Strukturen definiert.
- Die Struktur
BSCdient als eindeutiger Identifikator des Coins. Daher kann dieser Coin eindeutig über den PfadBlockSec::bsc::BSCbestimmt werden. - Die Struktur
CapStorewird verwendet, um einige Berechtigungen aus dem Modulaptos_framework::coinzu speichern. Diese Berechtigungen entsprechen den Rechten für einige spezielle Operationen und werden später erklärt. - Die Struktur
BSCEventStoredient zur Aufzeichnung von Benutzerereignissen.
Nach diesen Strukturen gibt es die Funktion init_module, die zur Initialisierung des Moduls verwendet wird und nur einmal aufgerufen wird, wenn das Modul auf der Kette veröffentlicht wird. In dieser Funktion ruft das Modul coin::initialize<BSC> auf, um BlockSec::bsc::BSC als eindeutigen Identifikator für einen neuen Coin zu registrieren.
public fun initialize<CoinType>(
account: &signer,
name: string::String,
symbol: string::String,
decimals: u8,
monitor_supply: bool,
): (BurnCapability<CoinType>, FreezeCapability<CoinType>, MintCapability<CoinType>) {
initialize_internal(account, name, symbol, decimals, monitor_supply, false)
}
/// Capability required to mint coins.
struct MintCapability<phantom CoinType> has copy, store {}
/// Capability required to freeze a coin store.
struct FreezeCapability<phantom CoinType> has copy, store {}
/// Capability required to burn coins.
struct BurnCapability<phantom CoinType> has copy, store {}
Nach der Registrierung werden alle generischen Funktionen, die den Typ BlockSec::bsc::BSC im aptos_framework::coin verwenden, auf diesen Coin angewendet. Dieser Registrierungsprozess gibt drei Berechtigungen zurück, nämlich MintCapability, FreezeCapability und BurnCapability. Diese Berechtigungen sind für das Prägen von Coins, das Einfrieren von Benutzerkonten und das Verbrennen von Coins erforderlich. Bis zu einem gewissen Grad ist die Funktionalität einer solchen Berechtigungsstruktur ähnlich einem Schlüssel, der zum Öffnen eines bestimmten Rechts verwendet wird. Wenn jemand den Schlüssel hat, kann er die entsprechende Berechtigung erhalten. Hier speichern wir diese Berechtigungen in der Struktur CapStore (im Besitz des Administrators/Herausgebers dieses Moduls) für spätere Verwendung.
Während des Registrierungsprozesses wird außerdem eine Struktur CoinInfo unter der Adresse des Administrators gespeichert, um relevante Informationen aufzuzeichnen:
/// Information about a specific coin type. Stored on the creator of the coin's account.
struct CoinInfo<phantom CoinType> has key {
name: string::String,
/// Symbol of the coin, usually a shorter version of the name.
/// For example, Singapore Dollar is SGD.
symbol: string::String,
/// Number of decimals used to get its user representation.
/// For example, if `decimals` equals `2`, a balance of `505` coins should
/// be displayed to a user as `5.05` (`505 / 10 ** 2`).
decimals: u8,
/// Amount of this coin type in existence.
supply: Option<OptionalAggregator>,
}
Nach dem Aufruf der Funktion init_module ist Ihr Coin auf der Kette registriert. Allerdings kann niemand diesen Coin verwenden, da derzeit keine Zirkulation existiert. Um den Coin nutzbar zu machen, müssen einige Operationen, einschließlich Emission, Zuteilung und Vernichtung, unterstützt werden. Diese Operationen erfordern die Berechtigungen, die wir bei der Registrierung des Coins erhalten haben.
0x2.2 Coin-Verwaltung
Dieser Coin ist so konzipiert, dass er den folgenden Regeln folgt:
- Nur der Administrator (Admin) kann Coins prägen.
- Benutzer können ihre eigenen Coins jederzeit verbrennen.
- Benutzer können ihre Konten jederzeit einfrieren/entfroren.
Entsprechend definieren wir fünf Verwaltungsfunktionen, nämlich mint_coin, burn_coin, freeze_self, emergency_freeze und unfreeze. Die ersten beiden Funktionen sind für das Prägen bzw. Verbrennen von Coins zuständig; die letzteren drei dienen zum Einfrieren und Entfroren von Konten.
Prägen von Coins
In unserem Modul wird die Funktion mint_coin zum Prägen von Coins verwendet. Da nur Admins Coins prägen dürfen, müssen wir die entsprechende Berechtigung in dieser Funktion überprüfen.
public entry fun mint_coin(cap_owner: &signer, to_address: address, amount: u64) acquires CapStore, BSCEventStore{
let mint_cap = &borrow_global<CapStore>(signer::address_of(cap_owner)).mint_cap;
let mint_coin = coin::mint<BSC>(amount, mint_cap);
coin::deposit<BSC>(to_address, mint_coin);
emit_event(to_address, utf8(b"minted BSC"));
}
Diese Funktion erfordert drei Parameter:
cap_ownerist vom Typ&signer, d. h. der Initiator der Transaktion.to_addressgibt die Adresse an, auf die die geprägten Coins eingezahlt werden.amountgibt die Anzahl der geprägten Coins an.
Sie besteht aus drei Schritten: Erwerb der Berechtigung zum Prägen von Coins, Prägen von Coins und Einzahlen von Coins.
Zuerst, zu Beginn der Funktion mint_coin, kann die Kontoadresse des Transaktionsinitiators über signer::address_of(cap_owner) abgerufen werden. Danach wird borrow_global<CapStore> verwendet, um zu bestätigen, ob das Konto CapStore besitzt, um zu verifizieren, dass es der Admin des Moduls ist. Dadurch können wir sicherstellen, dass nur der Admin Coins prägen kann, während andere Benutzer in diesem Schritt fehlschlagen.
Zweitens wird die Funktion mint_coin dann die Funktion mint des Moduls aptos_framework::coin aufrufen, um Coins zu prägen.
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 }
}
Hier wird MintCapability benötigt. Insbesondere muss ein Parameter namens _cap als Referenz auf MintCapability übergeben werden. Dann wird die damit verbundene Berechtigung entsprechend übertragen. Obwohl keine explizite Zugriffskontrolle vorhanden ist, wird die Überprüfung durch die Move-Sprache erzwungen.
Drittens ruft die Funktion mint_coin die Funktion deposit auf, um die geprägten Coins an die angegebene to_address einzuzahlen.
Tipp#1: Zugriffskontrollen für privilegierte Konten können mit einer ähnlichen Methode verifiziert werden.
Verbrennen von Coins
Der Vorgang des Verbrennens von Coins unterscheidet sich vom Prägen. Insbesondere darf nur der Admin die Funktion mint_coin aufrufen, während jeder Benutzer die Funktion burn_coin aufrufen kann. Zu diesem Zweck muss die Funktion burn_coin vorübergehend die Berechtigung eskalieren, d. h. die BurnCapability-Berechtigung für diese Benutzer erhalten.
public entry fun burn_coin(account: &signer, amount: u64) acquires CapStore, BSCEventStore{
let owner_address = type_info::account_address(&type_info::type_of<BSC>());
let burn_cap = &borrow_global<CapStore>(owner_address).burn_cap;
let burn_coin = coin::withdraw<BSC>(account, amount);
coin::burn<BSC>(burn_coin, burn_cap);
emit_event(signer::address_of(account), utf8(b"burned BSC"));
}
Diese Funktion erfordert zwei Parameter:
accountist vom Typ&signer, d. h. der Initiator der Transaktion.amountgibt die Anzahl der zu verbrennenden Coins an.
Sie besteht ebenfalls aus drei Schritten: Erwerb der Berechtigung zum Verbrennen von Coins, Abheben von Coins und Verbrennen von Coins.
Offensichtlich erfordert die Funktion burn des Moduls aptos_framework::coin, dass der Aufrufer eine Referenz auf BurnCapability übergibt, aber diese Berechtigung ist in der CapStore des Admins gespeichert. Daher müssen wir gewöhnlichen Benutzern erlauben, diese Berechtigung zum Verbrennen der von ihnen gehaltenen Coins zu erhalten.
public fun burn<CoinType>(
coin: Coin<CoinType>,
_cap: &BurnCapability<CoinType>,
) acquires CoinInfo {
let Coin { value: amount } = coin;
assert!(amount > 0, error::invalid_argument(EZERO_COIN_AMOUNT));
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::sub(supply, (amount as u128));
}
}
Um dies zu erreichen, können wir den von der Move-Sprache bereitgestellten Operator borrow_global verwenden. Er wird verwendet, um einen bestimmten Datentyp aus dem unveränderlichen globalen Speicher eines Kontos zu lesen. Mit diesem Operator kann ein Modul anderen Benutzern die Berechtigung des Admins ausleihen. Das heißt, die Admin-Adresse wird benötigt, um die gewünschte Berechtigung zu erhalten.
Da der Transaktionsinitiator der Funktion burn_coin jedoch der Benutzer und nicht der Admin ist, kann die Admin-Adresse nicht wie bei der Funktion mint_coin über signer ermittelt werden. Glücklicherweise kann sie über aptos_std::type_info mit BSC ermittelt werden, um die Adresse des Moduls zu erhalten, in dem diese Struktur definiert ist. Da das Modul unter der Admin-Adresse veröffentlicht wurde, können wir die Admin-Adresse entsprechend ermitteln und schließlich die BurnCapability-Berechtigung erhalten.
Tipp#2: Der Operator
_borrow_global_kann verwendet werden, um Berechtigungen eines Moduls vorübergehend zu erwerben.
Nachdem die BurnCapability erhalten wurde, kann das Modul die Coins des angegebenen Betrags vom Benutzer abheben und die Coins mit dieser Berechtigung verbrennen.
Einfrieren und Auftauen von Coin-Konten
Basierend auf den obigen Ausführungen können wir nun die Verwaltung der Coin-Konten leicht nachvollziehen. Insbesondere stellen wir die Funktion freeze_self bereit, damit Benutzer ihre Coin-Konten einfrieren können. Hier stellen wir auch die Funktion emergency_freeze für Notfall-Einfrierungen bereit, die nur vom Admin verwendet werden kann. Darüber hinaus sollten Benutzer aufgrund der Existenz des Notfall-Einfriermechanismus nicht in der Lage sein, sich selbst aufzutauen. Daher erfordert die Funktion unfreeze ebenfalls, dass der Admin die Benutzerkonten auftaut.
public entry fun freeze_self(account: &signer) acquires CapStore, BSCEventStore{
let owner_address = type_info::account_address(&type_info::type_of<BSC>());
let freeze_cap = &borrow_global<CapStore>(owner_address).freeze_cap;
let freeze_address = signer::address_of(account);
coin::freeze_coin_store<BSC>(freeze_address, freeze_cap);
emit_event(freeze_address, utf8(b"freezed self"));
}
public entry fun emergency_freeze(cap_owner: &signer, freeze_address: address) acquires CapStore, BSCEventStore{
let owner_address = signer::address_of(cap_owner);
let freeze_cap = &borrow_global<CapStore>(owner_address).freeze_cap;
coin::freeze_coin_store<BSC>(freeze_address, freeze_cap);
emit_event(freeze_address, utf8(b"emergency freezed"));
}
public entry fun unfreeze(cap_owner: &signer, unfreeze_address: address) acquires CapStore, BSCEventStore{
let owner_address = signer::address_of(cap_owner);
let freeze_cap = &borrow_global<CapStore>(owner_address).freeze_cap;
coin::unfreeze_coin_store<BSC>(unfreeze_address, freeze_cap);
emit_event(unfreeze_address, utf8(b"unfreezed"));
}
Tipp#3: Seien Sie vorsichtig, wenn Sie Berechtigungen über Funktionen zurückgeben! Böswillige Benutzer, die diese Berechtigungen erhalten, könnten sie missbrauchen, um Coin-Inhabern Schaden zuzufügen!
0x3. Interagiere mit dem Coin
Hier konzentrieren wir uns auf die Art und Weise der Interaktion mit dem Coin.
0x3.1 Registrierung
Möglicherweise haben Sie bemerkt, dass im Modul eine Funktion register existiert:
public entry fun register(account: &signer){
let address_ = signer::address_of(account);
if(!coin::is_account_registered<BSC>(address_)){
coin::register<BSC>(account);
};
if(!exists<BSCEventStore>(address_)){
move_to(account, BSCEventStore{event_handle: account::new_event_handle(account)});
};
}
Diese Funktion dient dazu, Benutzern die Rechte zur Nutzung von Coins und Ereignisaufzeichnern zu registrieren. Um einen bestimmten Coin zu verwenden, schreibt das Modul aptos_framework::coin vor, dass der Benutzer zuerst explizit das Recht zur Nutzung des Coins über die Funktion aptos_framework::coin::register registrieren muss.
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);
}
Benutzer können diesen Coin nur dann normal halten, wenn sie diesen Coin-Typ über diese Funktion registriert haben. Das heißt, wenn Sie einen bestimmten Coin nicht halten möchten, können andere diesen Coin nicht ohne Ihre Zustimmung auf Ihr Konto einzahlen. Die Registrierung fügt tatsächlich eine Struktur CoinStore (des Ziel-Coin-Typs) in Ihr Konto ein. Diese CoinStore-Struktur enthält eine Coin-Struktur, um Ihr Guthaben zu speichern.
Tipp#4: Im Gegensatz zu Ethereum-Tokens kann ein Aptos-Coin nicht gehalten und betrieben werden, ohne dass der Benutzer ihn explizit registriert hat.
0x3.2 Überweisung
Angenommen, Sie besitzen nun einige BSC-Coins, dann können Sie diese Coins durch Aufruf der Funktion transfer des Moduls aptos_framework::coin überweisen.
public entry fun transfer<CoinType>(
from: &signer,
to: address,
amount: u64,
) acquires CoinStore {
let coin = withdraw<CoinType>(from, amount);
deposit(to, coin);
}
Beachten Sie, dass dies eine Entry-Funktion des coin-Moduls ist. Die Logik besteht aus Aufrufen zweier öffentlicher Funktionen, nämlich withdraw und deposit. Die Funktion withdraw erfordert die &signer-Berechtigung, die zum Abheben eines bestimmten Betrags von Ihren Vermögenswerten von Ihrem Konto in einen Coin verwendet wird. Die Funktion deposit kann einen Coin auf jedes registrierte Konto des Coins einzahlen. Diese Funktion benötigt keine zusätzlichen Berechtigungen und zahlt die angegebenen Coins auf die Kontoadresse ein. Schließlich werden die überwiesenen Coins automatisch mit den in der CoinStore-Struktur der Zieladresse gespeicherten Coins zusammengeführt.
Tipp#5: Nach dem Abheben liegen die Vermögenswerte im Coin unter der Kontrolle der aktuellen
_transfer_Funktion. Diese Funktion kann diese Vermögenswerte an die_deposit_Funktion liefern, ohne zusätzliche Berechtigungen zu erwerben.
0x3.3 Aufteilen und Zusammenführen
Im Gegensatz zu Ethereum-Tokens kann die Zirkulation von Coins nicht durch Änderung der Benutzerguthaben aktualisiert werden. Stattdessen kann sie durch Abheben der Struktur Coin im coin-Modul erreicht werden. Dadurch realisieren Benutzer die Vermögenszirkulation, indem sie diese Struktur an andere Module übergeben. Da eine Struktur nur von dem Modul manipuliert werden kann, das sie definiert, bietet das coin-Modul einige Schnittstellen zur Bedienung der Coin-Struktur, einschließlich des Aufteilens von Coins in kleinere Einheiten und des Zusammenführens mehrerer Coins, um den Anforderungen verschiedener Szenarien gerecht zu werden.
-
Die Funktion
extractwird zum Aufteilen von Coins verwendet. Sie empfängt eineCoin-Struktur, extrahiert einen Teil der Vermögenswerte daraus, um eine neueCoin-Struktur zu erzeugen, und gibt die neue Struktur zurück.public fun extract<CoinType>(coin: &mut Coin<CoinType>, amount: u64): Coin<CoinType> { assert!(coin.value >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE)); coin.value = coin.value - amount; Coin { value: amount } } -
Die Funktion
extract_allwird verwendet, um den gesamten Wert der ursprünglichenCoin-Struktur zu extrahieren und in eine neueCoin-Struktur einzuzahlen. Infolgedessen wird der Wert der ursprünglichenCoin-Struktur Null (auch bekannt alszero_coin). Diezero_coin-Struktur kann durch Aufruf der Funktiondestroy_zerovernichtet werden.public fun extract_all<CoinType>(coin: &mut Coin<CoinType>): Coin<CoinType> { let total_value = coin.value; coin.value = 0; Coin { value: total_value } } public fun destroy_zero<CoinType>(zero_coin: Coin<CoinType>) { let Coin { value } = zero_coin; assert!(value == 0, error::invalid_argument(EDESTRUCTION_OF_NONZERO_TOKEN)) } -
Die Funktion
mergewird zum Zusammenführen von Coins verwendet. Sie können den Wert von zweiCoin-Strukturen,source_coinunddst_coin, in diedst_coin-Struktur zusammenführen und diesource_coin-Struktur vernichten.public fun merge<CoinType>(dst_coin: &mut Coin<CoinType>, source_coin: Coin<CoinType>) { spec { assume dst_coin.value + source_coin.value <= MAX_U64; }; dst_coin.value = dst_coin.value + source_coin.value; let Coin { value: _ } = source_coin; } -
Die Funktion
zerowird verwendet, um einezero_coin-Struktur zu erzeugen.public fun zero<CoinType>(): Coin<CoinType> { Coin<CoinType> { value: 0 } }
0x4. Teste den Coin
Um diesen Coin schnell zu testen, können Sie ihn zuerst mit dem folgenden Befehl bereitstellen (vergessen Sie nicht, Ihre Herausgeber-Konto-Adresse in Move.toml festzulegen!)
$ aptos move publish --package-dir ./
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING my_coin
package size 2751 bytes
Do you want to submit a transaction for a range of [868300 - 1302400] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "xxx",
...
Auf diese Weise wurde der Coin erfolgreich auf der Kette veröffentlicht, hat aber keine Zirkulation. Sie müssen Ihr Konto registrieren, um die geprägten Coins zu erhalten.
$ aptos move run --function-id default::bsc::register
Do you want to submit a transaction for a range of [153100 - 229600] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "xxx",
...
Beachten Sie, dass Your-address im zweiten Befehl durch Ihre eigene Adresse ersetzt werden muss (siehe account in .aptos/config.yaml). Geben Sie Ihre Adresse im Browser ein und klicken Sie auf die Registerkarte Resources. Sie können sehen, dass dieses Konto nun 100 BSC-Coins hat.


Wenn Sie Coins an ein anderes Konto übertragen möchten, vergessen Sie nicht, dieses Konto für die Nutzung des Coins zu registrieren. Da die Funktion transfer eine generische Funktion ist, müssen Sie den generischen Parameter als BSC und die to_address angeben, wie folgt:
$ aptos move run — function-id 0x1::coin::transfer — type-args BSC-module-address::bsc::BSC — args address:To_address u64:1
Dieser Befehl ruft die Funktion transfer des Coin-Moduls auf, um 1 BSC-Coin an To_address zu übertragen. Hier ist 0x1::coin::transfer die Funktions-ID der transfer-Funktion. Denken Sie daran, dass BlockSec::bsc::BSC der Identifikator Ihres Coins ist, der generische Parameter muss darauf gesetzt werden. Außerdem sollte BSC-module-address durch die Konto-Adresse des Modul-Herausgebers ersetzt werden, die in Move.toml als BlockSec zugewiesen ist.
0x5. Was kommt als Nächstes
Nachdem Sie verstanden haben, wie Sie Ihren eigenen Coin erstellen, verwalten und damit interagieren, werden wir zeigen, wie Sie das erste Eckpfeilerprojekt von DeFi bauen: Automated Market Maker (AMM). Weitere interessante Themen im Zusammenhang mit der Move-Entwicklung und Sicherheitspraktiken werden behandelt. Bleiben Sie dran!
Referenz
[1] https://aptos.dev/concepts/coin-and-token/aptos-coin/ [2] https://aptos.dev/concepts/coin-and-token/index [3] https://aptos.dev/concepts/coin-and-token/aptos-token



