Aptos Move dApp

En esta gu铆a, aprenderemos c贸mo crear una dApp "onchain bio" de extremo a extremo. Comenzaremos con el contrato Move. Luego, construiremos una interfaz de React y permitiremos que las billeteras se conecten y registren una biograf铆a.

Requisitos

Aseg煤rese de tener instalado Movement CLI . Si utiliza Aptos CLI, consulte nuestra gu铆a sobre c贸mo configurar Aptos CLI para Movement .

Vea un ejemplo de la dApp terminada aqu铆 .

Configuraci贸n

Cree un nuevo directorio y navegue hasta 茅l:

Copiar

mkdir my-onchain-bio && cd my-onchain-bio

Abra un editor de c贸digo para que pueda ver la estructura de archivos de su dApp. Aqu铆 usaremos VS Code:

Copiar

code .

Creaci贸n y publicaci贸n del contrato inteligente Onchain Bio

Ahora que nuestro entorno est谩 configurado, escribamos algo de c贸digo, 隆comenzando con el contrato Move!

Primero, cree un movedirectorio y navegue hasta 茅l:

Copiar

mkdir move && cd move

Luego cree un moveproyecto que contenga c贸digo para un paquete en cadena:

Copiar

movement aptos move init --name my_todo_list

Su estructura de archivos ahora deber铆a verse as铆:

Creando un m贸dulo

Cree un nuevo archivo nombrado onchain_bio.movedentro del sourcesdirectorio y agregue lo siguiente a ese archivo:

Escribiendo nuestro m贸dulo biol贸gico en cadena

Aqu铆 est谩 el m贸dulo Bio Move completo en cadena:

Copiar

module onchain_bio_addr::onchain_bio {
  use std::string::{String};
  use std::signer;

  struct Bio has key, store, drop {
      name: String,
      bio: String,
  }

  public entry fun register(account: &signer, name: String, bio: String) acquires Bio {
    // Check if an Bio already exists for the account
    if (exists<Bio>(signer::address_of(account))) {
      // Remove the existing Bio
      let _old_Bio = move_from<Bio>(signer::address_of(account));
    };
    // Create the new Bio
    let bio = Bio {
      name,
      bio,
    };
    // Store the new Bio under the account
    move_to<Bio>(account, bio);
  }
}

隆A continuaci贸n, implementemos en M1!

Implementaci贸n del m贸dulo en la cadena de bloques M1 de Movement

Primero, desde dentro del movedirectorio, inicialice su configuraci贸n de Movement Aptos:

Copiar

movement aptos init

Cuando se le solicite elegir una red, ingrese custom.

Luego ingrese el siguiente punto final REST:

Copiar

https://aptos.devnet.m1.movementlabs.xyz

Y la misma URL para el punto final del faucet.

Cuando se le solicite una clave privada, presione Entrar para generar un nuevo par de claves.

Tras una inicializaci贸n exitosa, ver谩 el mensaje de 茅xito (con la direcci贸n de su cuenta en lugar de 0x39883cbc29500a8bf79911ea1469e1c3b58104547a88fb0fbdf17470f80b2a91):

Copiar

No key given, generating key...
Account 0x39883cbc29500a8bf79911ea1469e1c3b58104547a88fb0fbdf17470f80b2a91 doesn't exist, creating it and funding it with 100000000 Octas
Account 0x39883cbc29500a8bf79911ea1469e1c3b58104547a88fb0fbdf17470f80b2a91 funded successfully

---
Aptos CLI is now set up for account 0x39883cbc29500a8bf79911ea1469e1c3b58104547a88fb0fbdf17470f80b2a91 as profile default!  Run `aptos --help` for more information about commands
{
  "Result": "Success"
}

Ahora su movedirectorio contendr谩 una .aptoscarpeta oculta que contiene un config.yamlarchivo. Puede ver el contenido de ese archivo para ver sus claves p煤blicas y privadas.

En la l铆nea debajo [addresses]de Move.toml, agregue la direcci贸n de su cuenta:

Copiar

onchain_bio_addr = "<your-account-address>"

Despu茅s de compilar, ver谩 un mensaje de resultado con el formato siguiente:

Copiar

{
  "Result": [
    "39883cbc29500a8bf79911ea1469e1c3b58104547a88fb0fbdf17470f80b2a91::onchain_bio"
  ]
}

Ahora puedes publicar el paquete:

Copiar

movement aptos move publish

Despu茅s de confirmar que el precio est谩 bien, su transacci贸n se enviar谩 a la cadena de bloques.

Obtendr谩 un resultado con el formato siguiente, con valores asociados a su transacci贸n:

Copiar

{
  "Result": {
    "transaction_hash": "0x37ea722ad4f1ff0d8d0710965a47354cc903579d38b659d90c4286ddab946151",
    "gas_used": 1236,
    "gas_unit_price": 100,
    "sender": "39883cbc29500a8bf79911ea1469e1c3b58104547a88fb0fbdf17470f80b2a91",
    "sequence_number": 0,
    "success": true,
    "timestamp_us": 1707748417269022,
    "version": 248,
    "vm_status": "Executed successfully"
  }
}

隆Felicidades! Su m贸dulo ahora est谩 implementado.

Pasemos al frente.

Creaci贸n de una aplicaci贸n React para que los usuarios se registren y vean su biograf铆a en cadena

Navegue a la ra铆z de nuestro directorio de proyectos:

Copiar

cd ..

Crea una nueva aplicaci贸n React llamada client:

Copiar

npx create-react-app client --template typescript

En la ra铆z de su proyecto, tendr谩 dos directorios: clienty move.

cden el clientdirectorio y ejecute npm start.

Su aplicaci贸n ahora deber铆a ejecutarse en http://localhost:3000 y mostrar el dise帽o predeterminado de React.

Los archivos de sus aplicaciones est谩n en el client/srcdirectorio.

Reemplace el c贸digo Index.tsxcon lo siguiente:

Copiar

import { PetraWallet } from "petra-plugin-wallet-adapter";
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import './index.css';
const wallets = [new PetraWallet()];

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <AptosWalletAdapterProvider plugins={wallets} autoConnect={true}>
      <App />
    </AptosWalletAdapterProvider>
  </React.StrictMode>,
);
reportWebVitals();

Esto envuelve nuestra aplicaci贸n en la <AptosWalletAdapterProvider />etiqueta para que podamos conectar una billetera. Para agregar soporte para m谩s billeteras, consulte el archivo README del Adaptador de billetera Aptos .

Ahora reemplace su App.tsxc贸digo con lo siguiente:

Copiar

import { WalletSelector } from "@aptos-labs/wallet-adapter-ant-design";
import "@aptos-labs/wallet-adapter-ant-design/dist/index.css";
import { useRef, useState, useEffect } from "react";
import { useWallet, InputTransactionData } from '@aptos-labs/wallet-adapter-react';
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
import { ONCHAIN_BIO } from "./constants";
import './index.css';

// with custom configuration
const aptosConfig = new AptosConfig({ network: Network.CUSTOM });
const aptos = new Aptos(aptosConfig);

function App() {
  const { signAndSubmitTransaction, account } = useWallet();
  const name = useRef<HTMLInputElement>(null);
  const bio = useRef<HTMLTextAreaElement>(null);

  const [accountHasBio, setAccountHasBio] = useState(false);
  const [currentName, setCurrentName] = useState(null);
  const [currentBio, setCurrentBio] = useState(null);

  const fetchBio = async () => {
    if (!account) {
      console.log("No account")
      return [];
    }
  
    try {
      const bioResource = await aptos.getAccountResource(
        {
          accountAddress:account?.address,
          resourceType:`${ONCHAIN_BIO}::onchain_bio::Bio`
        }
      );
      console.log("Name:", bioResource.name, "Bio:", bioResource.bio);
      setAccountHasBio(true);
      if (bioResource) {
        setCurrentName(bioResource.name);
        setCurrentBio(bioResource.bio);
      } else {
        console.log("no bio")
      }
    } catch (e: any) {
      setAccountHasBio(false);
    }
  };

  async function registerBio() {
    if (bio.current !== null && name.current !== null) { 
      const onchainName = name.current.value;
      const onchainBio = bio.current.value;
      const transaction: InputTransactionData = {
        data: {
          function:`${ONCHAIN_BIO}::onchain_bio::register`,
          functionArguments:[onchainName, onchainBio]
        }
      }
      try {
        // sign and submit transaction to chain
        const response = await signAndSubmitTransaction(transaction);
        // wait for transaction
        console.log(`Success! View your transaction at https://explorer.aptoslabs.com/txn/${response.hash}`)
        await aptos.waitForTransaction({transactionHash:response.hash});
        fetchBio();
      } catch (error: any) {
        console.log("Error:", error)
      }
    }
  }

  return (
    <>
      <div className="navbar">
        <div className="navbar-text">Your Onchain Bio</div>
        <div>
          <WalletSelector />
        </div>
      </div>
      <div className="center-container">
        
        <div className="row">
          <h1>You Onchain Bio</h1>
        </div>

        <div className="row">
          <h3>Your name:</h3>
        </div>
        <div className="row">
          <input ref={name} type="text" className="name" placeholder="Enter your name"/>
        </div>

        <div className="row">
          <h3>Your Bio:</h3>
        </div>
        <div className="row">
          <textarea ref={bio} className="bio" placeholder="Your onchain bio"
          />
        </div>

        <div className="row">
          <button onClick={registerBio}>Register Bio</button>
        </div>

        <div className="row">
          <button onClick={fetchBio}>Fetch Bio</button>
        </div>


        <div className="row">
          <center>
            <h3>Your Name:</h3>
            <p>{currentName}</p>
          </center>
        </div>

        <div className="row">
          <center>
            <h3>Your Bio:</h3>
            <p>{currentBio}</p>
          </center>
        </div>

      </div>
    </>
  );
}

export default App;

Por 煤ltimo, reemplace el c贸digo en index.css:

Copiar

:root {
    font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
    line-height: 1.5;
    font-weight: 400;
  
    font-synthesis: none;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-text-size-adjust: 100%;
  }
  body {
    margin: 0;
  }
  
  h1, h3 {
    margin-bottom: 5px;
  }
  h3 {
    margin-top: 0;
  }
  
  .navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #333;
    color: #fff;
    padding: 10px 20px;
  }
  
  .navbar-text {
    font-size: 20px;
  }
  
  .center-container {
    display: flex;
    flex-direction: column;
    
    align-items: center;
    height: 100vh; /* Adjust this to control vertical centering */
  }
  
  .row {
    display: flex;
    justify-content: center;
  }
  
  .name {
    margin-bottom: 10px;
    width: 200px;
  }
  
  .bio {
    margin-bottom: 10px;
    width: 300px;
    height: 200px;
    resize: vertical; 
  }

Su aplicaci贸n que se ejecuta localmente ahora deber铆a verse as铆:

Si茅ntete libre de dise帽ar la aplicaci贸n como prefieras.

Usando tu aplicaci贸n

Para usar la dApp, primero configure una billetera Aptos en M1.

Dir铆gete a Movement Faucet y deposita fondos en tu billetera M1 devnet. Ingrese un nombre y biograf铆a. Haga clic en el bot贸n Registrar biograf铆a. La billetera deber铆a aparecer para que la firmes. Despu茅s de que la transacci贸n se haya enviado a la cadena de bloques, ver谩 actualizada su informaci贸n biogr谩fica en la cadena:

驴Qu茅 dApps desarrollar谩s en Movement?

Ahora ya sabe c贸mo implementar una dApp Aptos para M1.

Compruebe onchain_bio.movela l贸gica, intente una redistribuci贸n modific谩ndola. Como desaf铆o, intenta modificar el Front End para mostrar mejor tu nombre y biograf铆a.

隆Estamos ansiosos por ver qu茅 dApps creas e implementas en Movement Network!

Last updated