This article will describe a scaffolding for an Aptos dApp created by NonceGeekDAO -- Scaffold-Aptos.
https://github.com/NonceGeek/scaffold-move
For example contracts used see:
https://github.com/NonceGeek/MoveDID
It has implications for the following projects:
https://github.com/Amovane/aptos-NFT-marketplace
The main technology stack of the project:Next.js
,Tailwind
The
0x00 Running the program
$ git clone https://github.com/NonceGeek/scaffold-move.git
$ cd scaffold-aptos & yarn
$ direnv allow # If using direnv
$ export [... .things in .envrc...] # If setting environment variables directly
$ yarn dev
0x01 Project structure
.
├── README.md
├── next-env.d.ts
├── next.config.js
├── node_modules
├── package.json
├── postcss.config.js
postcss.config.js
scripts
src
├── components /* important */ │ ├── AptosConnect.js
│ ├── AptosConnect.tsx
│ ├── ModalContext.tsx
│ ├── NavBar.tsx
│ ├── NavItem.tsx
│ ├── TooltipSection.tsx
│ └── WalletModal.tsx
├── config /* important */ │ └── constants.tsx
│ └── constants.ts
├── hooks
│ ├── index.ts
│ ├── useOffers.ts
│ └── useTokens.ts
├─ pages /* important */ │ ├─ _app.ts │ ├─ _app.ts │ ├─ _app.ts
│ ├── _app.tsx
│ ├── api
│ ├── did_querier.tsx
│ ├── endpoint.tsx
│ └── index.tsx
├── styles
│ ├── globals.css
│ └── loading.css
├─ types
│ ├── Offer.ts
│ └─ index.ts
└── utils
├─ aptos.ts
├── nftstorage.ts
└─ supabase.ts
├─ tailwind.config.js
├── .envrc
├── tsconfig.json
└── yarn.lock
The three main folders we'll be focusing on arecomponents
,config
respond in singing pages
The
0x02 Config - Environment Variable Management
Environment variables are written in the.envrc
file, it is recommended to pass thedirenv
This environment variable management tool performs environment variable management.
But directly in thebash
It is also possible to execute the command to set environment variables in the
export NEXT_PUBLIC_DAPP_ADDRESS=0x0c78cfc8cf31129444f22da3e527a48732f5b6e4e09ffbe82ffb900f84b22a17
export NEXT_PUBLIC_DAPP_NAME=DID
export NEXT_PUBLIC_MARKET_COIN_TYPE=0x1::aptos_coin::AptosCoin
export NEXT_PUBLIC_APTOS_NODE_URL=https://fullnode.testnet.aptoslabs.com/v1/
export NEXT_PUBLIC_APTOS_FAUCET_URL=https://faucet.devnet.aptoslabs.com/v1/
export NEXT_PUBLIC_APTOS_NETWORK=testnet
exist constants.ts
file, we convert the environment variable into a global variable with a command like this:
export const DAPP_NAME = process.env.NEXT_PUBLIC_DAPP_NAME!; // changed here.
If we want to add a new environment variable, we can follow suit. For example, add a URL that points to the browser:
export const NETWORK=process.env.NEXT_PUBLIC_APTOS_NETWORK!
export const MODULE_URL="https://explorer.aptoslabs.com/account/" + DAPP_ADDRESS + "/modules?network=" + NETWORK
0x03 Components - Page Components
The main set of components includes the following --
- Wallet Connection Component: by
AptosConnect.tsx
,ModalContext.tsx
respond in singingWalletModal.tsx
Ingredients. - Navigation Component: by
NavBar.tsx
respond in singingNavItem.tsx
Ingredients.
3.1 Wallet Connection Component
AptosConnect.tsx
The source code for this is below:
import { useWallet } from "@manahippo/aptos-wallet-adapter" ;
import { useContext } from "react";
import { ModalContext } from ". /ModalContext"; import { useContext } from "react"; import { ModalContext } from ".
import { WalletModal } from ". /WalletModal";
export function AptosConnect() {
const { account } = useWallet(); const { modalState, setModal(); const { modalState, setModal()
const { modalState, setModalState } = useContext(ModalContext);
return (
{account?.address ? (
useContext:
Receives a context object (React.createContext
) and returns the current value of the context. The current context value is returned by the closest component in the hierarchy. <MyContext.
(used form a nominal expression) value
prop Decision.
https://zh-hans.reactjs.org/docs/hooks-reference.html#usecontext
So after clicking on theConnect Wallet
button will call thescaffold-aptos/src/pages/_app.tsx
hit the nail on the headProvider
::
...
return (
<walletprovider wallets="{wallets}" autoconnect="{false}">
<ModalContext.Provider value={modals}>
<div classname="px-8">
<navbar />
<component {...pageprops} classname="bg-base-300" />
</div>
</ModalContext.Provider>
</walletprovider>
);
...
pass (a bill or inspection etc)useMemo
We can adjust the wallets we can log into, and naturally we can refer to Adapter's writeup to support new wallets.
const wallets = useMemo(
() => [
new AptosWalletAdapter(),
new MartianWalletAdapter(),
new PontemWalletAdapter(),
]
[]
).
3.2 Navigation components
NavBar.tsx
The source code is below:
import Image from "next/image" ;
import { NavItem } from ". /NavItem"; import { AptosConnect } from ".
import { AptosConnect } from ". /AptosConnect"; import { AptosConnect } from ".
import {
MODULE_URL
} from ".. /config/constants";
export function NavBar() {
return (
<nav classname="navbar py-4 px-4 bg-base-100">
<div classname="flex-1">
<a href="http://movedid.build" target="_blank">
<image src="/logo.png" width="{64}" height="{64}" alt="logo" />
</a>
<ul classname="menu menu-horizontal p-0 ml-5">
<navitem href="/" title="AddrAggregatorManager" />
<navitem href="/endpoint" title="EndpointManager" />
<navitem href="/did_querier" title="DIDQuerier" />
<li classname="font-sans font-semibold text-lg">
<a href="https://github.com/NonceGeek/MoveDID/" target="_blank">Source Code</a>
<a href="/en/{MODULE_URL}/" target="_blank">Contract on Explorer</a>
</li>
</ul>
</div>
<aptosconnect />
</nav>
);
pass (a bill or inspection etc)NavBar
We can set the URL in the navigation bar.
If it is an outbound link, you can use it as shown in the code, using thetag to mark it.
It is important to note that inNext
framework, pages are routed according to thepages
automatically generated from the files added in the
...
├── pages /* important */
│ ├── _app.tsx
│ ├── api
│ ├── did_querier.tsx
│ ├── endpoint.tsx
│ └── index.tsx
...
0x04 Pages and Chain Interaction
We are based onindex.tsx
module as an example. The function points involved in this module are summarized below:
- Page Related:
- Getting a value from an input box
- Returns the value to the page
- Chain interaction correlation:
- Get the full amount of resources under an account from the chain (Resources)
- Getting specific resources under an account from the chain
- Calling a method in a module (contract)
4.1 Page Related Logic
The lazier way of handling this is used here, through a one-timeuseState
Groups all incoming values on the page into theformInput
Down.
const [formInput, updateFormInput] = useState<{
description: string;
resource_path: string;
addr: string; addr_description: string; addr_type: number; addr_description
addr_description: string; addr_description: string; addr_description: string; addr: string
chains: Array;
}>({
description: "",
resource_path: "",
addr_type: 1,
addr: "",
addr_description: "",
chains: [],
}).
Then just assign the value in Input or any other type of component:
updateFormInput({ . .formInput, chains: JSON.parse(e.target.value) })
}
/>
Get the variable at the time of use with the following code:
const { description, resource_path, addr_type, addr, addr_description, chains } = formInput;
The method to pass the value into the page is shown in the following code:
<p>{JSON.stringify(resource)}</p>
4.2 Chain interaction logic
(1) Access to all resources
By calling the aptosClient wrapped method with the following code, we can get all the resources:
import {
DAPP_ADDRESS,
APTOS_FAUCET_URL,
APTOS_NODE_URL
} from "... /config/constants".
import {
WalletClient
} from "@martiandao/aptos-web3-bip44.js";
const { account, signAndSubmitTransaction } = useWallet();
const client = new WalletClient(APTOS_NODE_URL, APTOS_FAUCET_URL);
async function get_resources() {
client.aptosClient.getAccountResources(account!.address!.toString()).then(value =>
// do something to value!
);
}
(2) Getting resources based on resource path addresses
import { MoveResource } from "@martiandao/aptos-web3-bip44.js/dist/generated";
const [resource, setResource] = React.useState();
async function get_did_resource() {
client.aptosClient.getAccountResource(account!.address!.toString(), DAPP_ADDRESS + "::addr_aggregator::AddrAggregator").then(
setResource
);
}
setResource
After that, we can pass theresource
variable provides access to this resource.
(3) Calling contract methods
Take the Add Address method in MoveDID as an example:
async function create_addr() {
await signAndSubmitTransaction(
add_addr(), { gas_unit_price: 100 }
{ gas_unit_price: 100 }
);
}
...
function add_addr() {
const { description, resource_path, addr_type, addr, addr_description, chains } = formInput; }
return {
type: "entry_function_payload",
function: DAPP_ADDRESS + "::addr_aggregator::add_addr",
type_arguments: [],
arguments: [
addr_type,
addr,
chains,
addr_description, [], arguments: [ addr_type, addr, chains, addr_description
]
}
}
with respect totype_arguments
respond in singingarguments
See here for an explanation of this:
https://aptos.dev/guides/interacting-with-the-aptos-blockchain/
When using this method, the browser wallet plugin is called to initiate the transaction:
All of the above content is reproduced from the Internet, does not represent the position of AptosNews, is not investment advice, investment risk, the market need to be cautious, such as infringement, please contact the administrator to delete.