🟢
Aptos RU WiKi
  • Aptos Developer Network
  • Основы
    • Учётные записи (аккаунты)
    • События (events)
    • Полные ноды
    • Газ и комиссия за транзакции
    • Подтверждение
    • Топология сети
    • Транзакции и состояния
    • Валидирующие ноды
  • Гайды
    • Начало работы
    • Жизнь транзакции
    • Move в сети Aptos
    • Взаимодействие с блокчейном Aptos
  • Руководства по применению
    • Ваша первая транзакция
    • Ваш первый Move модуль
    • Ваш первый Dapp
    • Ваша первая монета
    • Ваш первый NFT
    • Расширение Wallet
  • Руководства по нодам
    • Запуск локального тестнета
    • Запуск полной ноды
      • Запуск полной ноды
      • Обновление полной ноды на новый релиз
      • Идентификация для полной ноды
      • Устранение неполадок при настройке полной ноды
  • Документы по вознаграждаемому тестнету
    • Введение
    • Запуск валидатора используя GCP
    • Запуск валидатора используя AWS
    • Запуск валидатора используя Azure
    • Запуск валидатора используя Docker
    • Запуск валидатора используя исходные файлы
    • Подключение к вознаграждаемому тестнету Aptos
  • Критерии работоспособности ноды
  • Телеметрия
  • Глоссарий
Powered by GitBook
On this page
  • Прежде чем начать
  • Источник GitHub
  • Шаг 1: Создайте представление учетной записи
  • Шаг 2: REST интерфейс
  • Шаг 3: Faucet интерфейс
  • Шаг 4: Запустите приложение
  1. Руководства по применению

Ваша первая транзакция

PreviousРуководства по применениюNextВаш первый Move модуль

Last updated 2 years ago

В этом руководстве в пошаговом порядке описывается создание, отправка и проверка транзакций, отправленных в Aptos Blockchain:

  1. Создайте представление учетной записи.

Каждая учетная запись Aptos имеет уникальный адрес учетной записи. Владелец этой учетной записи владеет парой открытого и закрытого ключей, которая сопоставляется с адресом учетной записи Aptos, и, в свою очередь, ключом аутентификации, хранящимся в этой учетной записи.

ПРИМЕЧАНИЕ

Подробнее об учетных записях Aptos см. в разделе .

2. Подготовьте оболочку для интерфейсов REST.

Aptos предоставляет для взаимодействия с блокчейном. Эти шаги подготавливают оболочки вокруг этого API для получения информации об учетной записи, а также для создания транзакции, ее подписания и отправки.

3. Подготовьте оболочку для интерфейса Faucet.

Используя интерфейс Faucet в Aptos devnet, этот обучающий код автоматически создает аккаунт с адресом 0x1 и пополняет его.

4. Объедините вышеуказанные оболочки в приложение, выполните и проверьте.

Прежде чем начать

Сначала убедитесь, что вы выполнили следующие шаги, чтобы вы могли запустить руководство.

  1. Клонируйте репозиторий Aptos.

git clone https://github.com/aptos-labs/aptos-core.git

2. Перейдитеcd в каталог aptos-core .

cd aptos-core

3. Проверьте ветку devnet, используя git checkout --track origin/devnet.

4. Запустите bash-скрипт scripts/dev_setup.sh , как показано ниже. Это подготовит вашу среду разработки.

./scripts/dev_setup.sh

5. Обновите текущую среду оболочки.

source ~/.cargo/env

Теперь, когда ваша среда разработки готова, вы можете запустить это руководство.

Источник GitHub

Перейдите по ссылкам ниже, чтобы получить доступ к исходному коду руководства:

Шаг 1: Создайте представление учетной записи

class Account:
    """Represents an account as well as the private, public key-pair for the Aptos blockchain."""

    def __init__(self, seed: bytes = None) -> None:
        if seed is None:
            self.signing_key = SigningKey.generate()
        else:
            self.signing_key = SigningKey(seed)

    def address(self) -> str:
        """Returns the address associated with the given account"""

        return self.auth_key()

    def auth_key(self) -> str:
        """Returns the auth_key for the associated account"""

        hasher = hashlib.sha3_256()
        hasher.update(self.signing_key.verify_key.encode() + b'\x00')
        return hasher.hexdigest()

    def pub_key(self) -> str:
        """Returns the public key for the associated account"""

        return self.signing_key.verify_key.encode().hex()
pub struct Account {
    signing_key: SecretKey,
}

impl Account {
    /// Represents an account as well as the private, public key-pair for the Aptos blockchain.
    pub fn new(priv_key_bytes: Option<Vec<u8>>) -> Self {
        let signing_key = match priv_key_bytes {
            Some(key) => SecretKey::from_bytes(&key).unwrap(),
            None => SecretKey::generate(&mut rand::rngs::StdRng::from_seed(OsRng.gen())),
        };

        Account { signing_key }
    }
    /// Returns the address associated with the given account
    pub fn address(&self) -> String {
        self.auth_key()
    }

    /// Returns the auth_key for the associated account
    pub fn auth_key(&self) -> String {
        let mut sha3 = Sha3::v256();
        sha3.update(PublicKey::from(&self.signing_key).as_bytes());
        sha3.update(&vec![0u8]);

        let mut output = [0u8; 32];
        sha3.finalize(&mut output);
        hex::encode(output)
    }

    /// Returns the public key for the associated account
    pub fn pub_key(&self) -> String {
        hex::encode(PublicKey::from(&self.signing_key).as_bytes())
    }
}
/** A subset of the fields of a TransactionRequest, for this tutorial */
export type TxnRequest = Record<string, any> & { sequence_number: string };

/** Represents an account as well as the private, public key-pair for the Aptos blockchain */
export class Account {
  signingKey: Nacl.SignKeyPair;

  constructor(seed?: Uint8Array | undefined) {
    if (seed) {
      this.signingKey = Nacl.sign.keyPair.fromSeed(seed);
    } else {
      this.signingKey = Nacl.sign.keyPair();
    }
  }

  /** Returns the address associated with the given account */
  address(): string {
    return this.authKey();
  }

  /** Returns the authKey for the associated account */
  authKey(): string {
    let hash = SHA3.sha3_256.create();
    hash.update(Buffer.from(this.signingKey.publicKey));
    hash.update("\x00");
    return hash.hex();
  }

  /** Returns the public key for the associated account */
  pubKey(): string {
    return Buffer.from(this.signingKey.publicKey).toString("hex");
  }
}

Шаг 2: REST интерфейс

Хотя данные из интерфейса REST можно считывать напрямую, следующие примеры кода демонстрируют более эргономичный подход при использовании интерфейса REST для:

  • Получение данных реестра из полной ноды, включая данные учетной записи и ресурсов учетной записи.

  • Построение подписанных транзакций, представленных в формате JSON.

class RestClient:
    """A wrapper around the Aptos-core Rest API"""

    def __init__(self, url: str) -> None:
        self.url = url

#[derive(Clone)]
pub struct RestClient {
    url: String,
}

impl RestClient {
    /// A wrapper around the Aptos-core Rest API
    pub fn new(url: String) -> Self {
        Self { url }
    }
    
/** A wrapper around the Aptos-core Rest API */
export class RestClient {
  url: string;

  constructor(url: string) {
    this.url = url;
  }

Шаг 2.1: Чтение аккаунта

Ниже приведены оболочки для запроса данных учетной записи.

 def account(self, account_address: str) -> Dict[str, str]:
        """Returns the sequence number and authentication key for an account"""

        response = requests.get(f"{self.url}/accounts/{account_address}")
        assert response.status_code == 200, f"{response.text} - {account_address}"
        return response.json()

    def account_resource(self, account_address: str, resource_type: str) -> Optional[Dict[str, Any]]:
        response = requests.get(f"{self.url}/accounts/{account_address}/resource/{resource_type}")
        if response.status_code == 404:
            return None
        assert response.status_code == 200, response.text
        return response.json()
/// Returns the sequence number and authentication key for an account
    pub fn account(&self, account_address: &str) -> serde_json::Value {
        let res =
            reqwest::blocking::get(format!("{}/accounts/{}", self.url, account_address)).unwrap();

        if res.status() != 200 {
            assert_eq!(
                res.status(),
                200,
                "{} - {}",
                res.text().unwrap_or("".to_string()),
                account_address,
            );
        }

        res.json().unwrap()
    }

    /// Returns all resources associated with the account
    pub fn account_resource(
        &self,
        account_address: &str,
        resource_type: &str,
    ) -> Option<serde_json::Value> {
        let res = reqwest::blocking::get(format!(
            "{}/accounts/{}/resource/{}",
            self.url, account_address, resource_type,
        ))
        .unwrap();

        if res.status() == 404 {
            None
        } else if res.status() != 200 {
            assert_eq!(
                res.status(),
                200,
                "{} - {}",
                res.text().unwrap_or("".to_string()),
                account_address,
            );
            unreachable!()
        } else {
            Some(res.json().unwrap())
        }
    }
    
/** Returns the sequence number and authentication key for an account */
  async account(accountAddress: string): Promise<Record<string, string> & { sequence_number: string }> {
    const response = await fetch(`${this.url}/accounts/${accountAddress}`, { method: "GET" });
    if (response.status != 200) {
      assert(response.status == 200, await response.text());
    }
    return await response.json();
  }

  /** Returns all resources associated with the account */
  async accountResource(accountAddress: string, resourceType: string): Promise<any> {
    const response = await fetch(`${this.url}/accounts/${accountAddress}/resource/${resourceType}`, { method: "GET" });
    if (response.status == 404) {
      return null;
    }
    if (response.status != 200) {
      assert(response.status == 200, await response.text());
    }
    return await response.json();
  }

  

Шаг 2.2: Отправка транзакции

Далее демонстрируются основные функции построения, подписания и ожидания транзакции.

def generate_transaction(self, sender: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        """Generates a transaction request that can be submitted to produce a raw transaction that
        can be signed, which upon being signed can be submitted to the blockchain. """

        account_res = self.account(sender)
        seq_num = int(account_res["sequence_number"])
        txn_request = {
            "sender": f"0x{sender}",
            "sequence_number": str(seq_num),
            "max_gas_amount": "2000",
            "gas_unit_price": "1",
            "gas_currency_code": "XUS",
            "expiration_timestamp_secs": str(int(time.time()) + 600),
            "payload": payload,
        }
        return txn_request

    def sign_transaction(self, account_from: Account, txn_request: Dict[str, Any]) -> Dict[str, Any]:
        """Converts a transaction request produced by `generate_transaction` into a properly signed
        transaction, which can then be submitted to the blockchain."""

        res = requests.post(f"{self.url}/transactions/signing_message", json=txn_request)
        assert res.status_code == 200, res.text
        to_sign = bytes.fromhex(res.json()["message"][2:])
        signature = account_from.signing_key.sign(to_sign).signature
        txn_request["signature"] = {
            "type": "ed25519_signature",
            "public_key": f"0x{account_from.pub_key()}",
            "signature": f"0x{signature.hex()}",
        }
        return txn_request

    def submit_transaction(self, txn: Dict[str, Any]) -> Dict[str, Any]:
        """Submits a signed transaction to the blockchain."""

        headers = {'Content-Type': 'application/json'}
        response = requests.post(f"{self.url}/transactions", headers=headers, json=txn)
        assert response.status_code == 202, f"{response.text} - {txn}"
        return response.json()
    
    def execute_transaction_with_payload(self, account_from: Account, payload: Dict[str, Any]) -> Dict[str, Any]:
        """Execute a transaction for the given payload."""
        
        txn_request = self.generate_transaction(account_from.address(), payload)
        signed_txn = self.sign_transaction(account_from, txn_request)
        return self.submit_transaction(signed_txn)

    def transaction_pending(self, txn_hash: str) -> bool:
        response = requests.get(f"{self.url}/transactions/{txn_hash}")
        if response.status_code == 404:
            return True
        assert response.status_code == 200, f"{response.text} - {txn_hash}"
        return response.json()["type"] == "pending_transaction"

    def wait_for_transaction(self, txn_hash: str) -> None:
        """Waits up to 10 seconds for a transaction to move past pending state."""

        count = 0
        while self.transaction_pending(txn_hash):
            assert count < 10, f"transaction {txn_hash} timed out"
            time.sleep(1)
            count += 1
        response = requests.get(f"{self.url}/transactions/{txn_hash}")
        assert "success" in response.json(), f"{response.text} - {txn_hash}"
    /// Generates a transaction request that can be submitted to produce a raw transaction that can be signed, which upon being signed can be submitted to the blockchain.
    pub fn generate_transaction(
        &self,
        sender: &str,
        payload: serde_json::Value,
    ) -> serde_json::Value {
        let account_res = self.account(sender);

        let seq_num = account_res
            .get("sequence_number")
            .unwrap()
            .as_str()
            .unwrap()
            .parse::<u64>()
            .unwrap();

        // Unix timestamp, in seconds + 10 minutes
        let expiration_time_secs = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("Time went backwards")
            .as_secs()
            + 600;

        serde_json::json!({
            "sender": format!("0x{}", sender),
            "sequence_number": seq_num.to_string(),
            "max_gas_amount": "1000",
            "gas_unit_price": "1",
            "gas_currency_code": "XUS",
            "expiration_timestamp_secs": expiration_time_secs.to_string(),
            "payload": payload,
        })
    }

    /// Converts a transaction request produced by `generate_transaction` into a properly signed transaction, which can then be submitted to the blockchain.
    pub fn sign_transaction(
        &self,
        account_from: &mut Account,
        mut txn_request: serde_json::Value,
    ) -> serde_json::Value {
        let res = reqwest::blocking::Client::new()
            .post(format!("{}/transactions/signing_message", self.url))
            .body(txn_request.to_string())
            .send()
            .unwrap();

        if res.status() != 200 {
            assert_eq!(
                res.status(),
                200,
                "{} - {}",
                res.text().unwrap_or("".to_string()),
                txn_request.as_str().unwrap_or(""),
            );
        }
        let body: serde_json::Value = res.json().unwrap();
        let to_sign_hex = Box::new(body.get("message").unwrap().as_str()).unwrap();
        let to_sign = hex::decode(&to_sign_hex[2..]).unwrap();
        let signature: String = ExpandedSecretKey::from(&account_from.signing_key)
            .sign(&to_sign, &PublicKey::from(&account_from.signing_key))
            .encode_hex();

        let signature_payload = serde_json::json!({
            "type": "ed25519_signature",
            "public_key": format!("0x{}", account_from.pub_key()),
            "signature": format!("0x{}", signature),
        });
        txn_request
            .as_object_mut()
            .unwrap()
            .insert("signature".to_string(), signature_payload);
        txn_request
    }

    /// Submits a signed transaction to the blockchain.
    pub fn submit_transaction(&self, txn_request: &serde_json::Value) -> serde_json::Value {
        let res = reqwest::blocking::Client::new()
            .post(format!("{}/transactions", self.url))
            .body(txn_request.to_string())
            .header("Content-Type", "application/json")
            .send()
            .unwrap();

        if res.status() != 202 {
            assert_eq!(
                res.status(),
                202,
                "{} - {}",
                res.text().unwrap_or("".to_string()),
                txn_request.as_str().unwrap_or(""),
            );
        }
        res.json().unwrap()
    }

    /// Submits a signed transaction to the blockchain.
    pub fn execution_transaction_with_payload(
        &self,
        account_from: &mut Account,
        payload: serde_json::Value,
    ) -> String {
        let txn_request = self.generate_transaction(&account_from.address(), payload);
        let signed_txn = self.sign_transaction(account_from, txn_request);
        let res = self.submit_transaction(&signed_txn);
        res.get("hash").unwrap().as_str().unwrap().to_string()
    }

    pub fn transaction_pending(&self, transaction_hash: &str) -> bool {
        let res = reqwest::blocking::get(format!("{}/transactions/{}", self.url, transaction_hash))
            .unwrap();

        if res.status() == 404 {
            return true;
        }

        if res.status() != 200 {
            assert_eq!(
                res.status(),
                200,
                "{} - {}",
                res.text().unwrap_or("".to_string()),
                transaction_hash,
            );
        }

        res.json::<serde_json::Value>()
            .unwrap()
            .get("type")
            .unwrap()
            .as_str()
            .unwrap()
            == "pending_transaction"
    }

    /// Waits up to 10 seconds for a transaction to move past pending state.
    pub fn wait_for_transaction(&self, txn_hash: &str) {
        let mut count = 0;
        while self.transaction_pending(txn_hash) {
            assert!(count < 10, "transaction {} timed out", txn_hash);
            thread::sleep(Duration::from_secs(1));
            count += 1;
        }
    }
    
  /** Generates a transaction request that can be submitted to produce a raw transaction that
   can be signed, which upon being signed can be submitted to the blockchain. */
  async generateTransaction(sender: string, payload: Record<string, any>): Promise<TxnRequest> {
    const account = await this.account(sender);
    const seqNum = parseInt(account["sequence_number"]);
    return {
      sender: `0x${sender}`,
      sequence_number: seqNum.toString(),
      max_gas_amount: "2000",
      gas_unit_price: "1",
      // Unix timestamp, in seconds + 10 minutes
      expiration_timestamp_secs: (Math.floor(Date.now() / 1000) + 600).toString(),
      payload: payload,
    };
  }

  /** Converts a transaction request produced by `generate_transaction` into a properly signed
   transaction, which can then be submitted to the blockchain. */
  async signTransaction(accountFrom: Account, txnRequest: TxnRequest): Promise<TxnRequest> {
    const response = await fetch(`${this.url}/transactions/signing_message`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(txnRequest),
    });
    if (response.status != 200) {
      assert(response.status == 200, (await response.text()) + " - " + JSON.stringify(txnRequest));
    }
    const result: Record<string, any> & { message: string } = await response.json();
    const toSign = Buffer.from(result["message"].substring(2), "hex");
    const signature = Nacl.sign(toSign, accountFrom.signingKey.secretKey);
    const signatureHex = Buffer.from(signature).toString("hex").slice(0, 128);
    txnRequest["signature"] = {
      type: "ed25519_signature",
      public_key: `0x${accountFrom.pubKey()}`,
      signature: `0x${signatureHex}`,
    };
    return txnRequest;
  }

  /** Submits a signed transaction to the blockchain. */
  async submitTransaction(txnRequest: TxnRequest): Promise<Record<string, any>> {
    const response = await fetch(`${this.url}/transactions`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(txnRequest),
    });
    if (response.status != 202) {
      assert(response.status == 202, (await response.text()) + " - " + JSON.stringify(txnRequest));
    }
    return await response.json();
  }

  async executeTransactionWithPayload(accountFrom: Account, payload: Record<string, any>): Promise<string> {
    const txnRequest = await this.generateTransaction(accountFrom.address(), payload);
    const signedTxn = await this.signTransaction(accountFrom, txnRequest);
    const res = await this.submitTransaction(signedTxn);
    return res["hash"];
  }

  async transactionPending(txnHash: string): Promise<boolean> {
    const response = await fetch(`${this.url}/transactions/${txnHash}`, { method: "GET" });
    if (response.status == 404) {
      return true;
    }
    if (response.status != 200) {
      assert(response.status == 200, await response.text());
    }
    return (await response.json())["type"] == "pending_transaction";
  }

  /** Waits up to 10 seconds for a transaction to move past pending state */
  async waitForTransaction(txnHash: string) {
    let count = 0;
    while (await this.transactionPending(txnHash)) {
      assert(count < 10);
      await new Promise((resolve) => setTimeout(resolve, 1000));
      count += 1;
      if (count >= 10) {
        throw new Error(`Waiting for transaction ${txnHash} timed out!`);
      }
    }
  }

  

Шаг 2.3: Логика, специфичная для конкретного приложения

Ниже показано, как считывать данные из блокчейна и как отправлять конкретную транзакцию.

def account_balance(self, account_address: str) -> Optional[int]:
        """Returns the test coin balance associated with the account"""
        return self.account_resource(account_address, "0x1::Coin::CoinStore<0x1::TestCoin::TestCoin>")

    def transfer(self, account_from: Account, recipient: str, amount: int) -> str:
        """Transfer a given coin amount from a given Account to the recipient's account address.
        Returns the sequence number of the transaction used to transfer."""

        payload = {
            "type": "script_function_payload",
            "function": "0x1::Coin::transfer",
            "type_arguments": ["0x1::TestCoin::TestCoin"],
            "arguments": [
                f"0x{recipient}",
                str(amount),
            ]
        }
        txn_request = self.generate_transaction(account_from.address(), payload)
        signed_txn = self.sign_transaction(account_from, txn_request)
        res = self.submit_transaction(signed_txn)
        return str(res["hash"])

/// Returns the test coin balance associated with the account
pub fn account_balance(&self, account_address: &str) -> Option<u64> {
    self.account_resource(account_address, "0x1::Coin::CoinStore<0x1::TestCoin::TestCoin>")
        .unwrap()["data"]["coin"]["value"]
        .as_str()
        .and_then(|s| s.parse::<u64>().ok())
}

/// Transfer a given coin amount from a given Account to the recipient's account address.
/// Returns the sequence number of the transaction used to transfer
pub fn transfer(&self, account_from: &mut Account, recipient: &str, amount: u64) -> String {
    let payload = serde_json::json!({
        "type": "script_function_payload",
        "function": "0x1::Coin::transfer",
        "type_arguments": ["0x1::TestCoin::TestCoin"],
        "arguments": [format!("0x{}", recipient), amount.to_string()]
    });
    let txn_request = self.generate_transaction(&account_from.address(), payload);
    let signed_txn = self.sign_transaction(account_from, txn_request);
    let res = self.submit_transaction(&signed_txn);

    res.get("hash").unwrap().as_str().unwrap().to_string()
}

}

  /** Returns the test coin balance associated with the account */
  async accountBalance(accountAddress: string): Promise<number | null> {
    const resource = await this.accountResource(accountAddress, "0x1::Coin::CoinStore<0x1::TestCoin::TestCoin>");
    if (resource == null) {
      return null;
    }
    return parseInt(resource["data"]["coin"]["value"]);
  }

  /** Transfer a given coin amount from a given Account to the recipient's account address.
   Returns the sequence number of the transaction used to transfer. */
  async transfer(accountFrom: Account, recipient: string, amount: number): Promise<string> {
    const payload: { function: string; arguments: string[]; type: string; type_arguments: any[] } = {
      type: "script_function_payload",
      function: "0x1::Coin::transfer",
      type_arguments: ["0x1::TestCoin::TestCoin"],
      arguments: [`0x${recipient}`, amount.toString()],
    };
    const txnRequest = await this.generateTransaction(accountFrom.address(), payload);
    const signedTxn = await this.signTransaction(accountFrom, txnRequest);
    const res = await this.submitTransaction(signedTxn);
    return res["hash"].toString();
  }
}

Шаг 3: Faucet интерфейс

Сборщики Aptos Blockchain выдают учетным записям тестовые токены. Эти тестовые токены можно использовать для тестирования, например, для оплаты газа или передачи токенов между пользователями. Aptos Faucet также может создавать учетные записи, если они не существуют. Для интерфейса Aptos Faucet требуется открытый ключ, представленный в виде строки в шестнадцатеричном коде.

class FaucetClient:
    """Faucet creates and funds accounts. This is a thin wrapper around that."""

    def __init__(self, url: str, rest_client: RestClient) -> None:
        self.url = url
        self.rest_client = rest_client

    def fund_account(self, address: str, amount: int) -> None:
        """This creates an account if it does not exist and mints the specified amount of
        coins into that account."""
        txns = requests.post(f"{self.url}/mint?amount={amount}&address={address}")
        assert txns.status_code == 200, txns.text
        for txn_hash in txns.json():
            self.rest_client.wait_for_transaction(txn_hash)
pub struct FaucetClient {
    url: String,
    rest_client: RestClient,
}

impl FaucetClient {
    /// Faucet creates and funds accounts. This is a thin wrapper around that.
    pub fn new(url: String, rest_client: RestClient) -> Self {
        Self { url, rest_client }
    }

    /// This creates an account if it does not exist and mints the specified amount of coins into that account.
    pub fn fund_account(&self, auth_key: &str, amount: u64) {
        let res = reqwest::blocking::Client::new()
            .post(format!(
                "{}/mint?amount={}&auth_key={}",
                self.url, amount, auth_key
            ))
            .send()
            .unwrap();

        if res.status() != 200 {
            assert_eq!(
                res.status(),
                200,
                "{}",
                res.text().unwrap_or("".to_string()),
            );
        }
        for txn_hash in res.json::<serde_json::Value>().unwrap().as_array().unwrap() {
            self.rest_client
                .wait_for_transaction(txn_hash.as_str().unwrap())
        }
    }
}
/** Faucet creates and funds accounts. This is a thin wrapper around that. */
export class FaucetClient {
  url: string;
  restClient: RestClient;

  constructor(url: string, restClient: RestClient) {
    this.url = url;
    this.restClient = restClient;
  }

  /** This creates an account if it does not exist and mints the specified amount of
   coins into that account */
  async fundAccount(address: string, amount: number) {
    const url = `${this.url}/mint?amount=${amount}&address=${address}`;
    const response = await fetch(url, { method: "POST" });
    if (response.status != 200) {
      assert(response.status == 200, await response.text());
    }
    const tnxHashes = (await response.json()) as Array<string>;
    for (const tnxHash of tnxHashes) {
      await this.restClient.waitForTransaction(tnxHash);
    }
  }
}

Шаг 4: Запустите приложение

Наконец, мы можем запустить приложение и проверить вывод.

Для Python3:

  1. Перейдите cd в каталог aptos-core/developer-docs-site/static/examples/python .

  2. Установите необходимые библиотеки: pip3 install -r requirements.txt.

  3. Запустите пример: python3 first_transaction.py.

Для Rust:

  1. Перейдите cd в каталог aptos-core/developer-docs-site/static/examples/rust .

  2. Выполните пример: cargo run --bin first-transaction (убедитесь, что вы используете first-transaction , а не first_transaction).

Для Typescript:

  1. Перейдите cd в каталог aptos-core/developer-docs-site/static/examples/typescript .

  2. Установите необходимые библиотеки: yarn install.

  3. Выполните пример: yarn first_transaction.

Результат

Результат после выполнения:

=== Addresses ===
Alice: e26d69b8d3ff12874358da6a4082a2ac
Bob: c8585f009c8a90f22c6b603f28b9ed8c

=== Initial Balances ===
Alice: 1000000000
Bob: 0

=== Final Balances ===
Alice: 999998957
Bob: 1000

Результат показывает, что Боб получил 1000 монет от Алисы. Алиса заплатила 43 монеты за газ.

Проверка

Данные можно проверить, посетив либо интерфейс REST, либо программу анализа:

ПРИМЕЧАНИЕ

См. first_transaction.py код в данного руководства.

См. first_transaction.rs код в данного руководства.

См. first_transaction.ts код в данного руководства.

Эти шаги создают представление учетной записи. См. также разделы и .

Убедитесь, что выполнены предварительные требования, описанные в разделе .

Убедитесь, что выполнены предварительные требования, описанные в разделе .

Убедитесь, что выполнены предварительные требования, описанные в разделе .

Учетная запись Алисы через .

Учетная запись Боба через .

Aptos devnet периодически перезапускается, поэтому приведенные выше ссылки могут не работать. Попробуйте выполнить инструкцию самостоятельно, а затем проверьте учетные записи в .

Учетные записи
REST API
Python version
Rust project
Typescript project
Учетные записи
Creating a Signed Transaction
Прежде чем начать
Прежде чем начать
Прежде чем начать
Aptos REST interface
Aptos Explorer
Aptos Explorer