SUI+Move快速上手
Sui Move,一切以对象为核心。 官方文档: https://docs.sui.io/build 开发文档: https://examples.sui.io/1. 安装sui cli命令行工具$ cargo install --locked --git https://github.com/MystenLabs/sui.git --branch devnet sui sui-node 2. 初始化测试环境,创建本地测试地址$ sui client $ sui client addresses 可以看到,sui的地址长度与以太坊相同,都是20个字节,与Aptos不同。3. 安装sui浏览器插件钱包在插件钱包页面上申请测试币。 https://chrome.google.com/webstore/detail/sui-wallet/opcgpfmipidbgpenhmajoajpbobppdilrequest devnet sui token在sui浏览器中查看钱包地址信息: https://explorer.devnet.sui.io/addresses/0xdd36d012f...
Hardhat部署和验证合约指南
1. 初始化新建一个新的目录,在新目录中执行:$ yarn add -D hardhat $ yarn hardhat init 按照提示,初始化语言选择JavaScript,并下载全部默认npm包。 将目录中的contracts目录清空,将自己的合约代码拷贝到contracts目录中。 (contracts内自带一个示例合约,可以结合它来看示例部署脚本和测试脚本)2. 编译部署在配置文件hardhat.config.js中,配置合约solidity版本和rpc信息,其中apiKey是用作浏览器验证时使用,如果不需要验证,可不用配置。accounts是一个数组,其中存放私钥数组。 如下所示:require("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { version: "0.4.26", settings: { optimizer: { enabled: true, runs: 2...
Web3 developer
SUI+Move快速上手
Sui Move,一切以对象为核心。 官方文档: https://docs.sui.io/build 开发文档: https://examples.sui.io/1. 安装sui cli命令行工具$ cargo install --locked --git https://github.com/MystenLabs/sui.git --branch devnet sui sui-node 2. 初始化测试环境,创建本地测试地址$ sui client $ sui client addresses 可以看到,sui的地址长度与以太坊相同,都是20个字节,与Aptos不同。3. 安装sui浏览器插件钱包在插件钱包页面上申请测试币。 https://chrome.google.com/webstore/detail/sui-wallet/opcgpfmipidbgpenhmajoajpbobppdilrequest devnet sui token在sui浏览器中查看钱包地址信息: https://explorer.devnet.sui.io/addresses/0xdd36d012f...
Hardhat部署和验证合约指南
1. 初始化新建一个新的目录,在新目录中执行:$ yarn add -D hardhat $ yarn hardhat init 按照提示,初始化语言选择JavaScript,并下载全部默认npm包。 将目录中的contracts目录清空,将自己的合约代码拷贝到contracts目录中。 (contracts内自带一个示例合约,可以结合它来看示例部署脚本和测试脚本)2. 编译部署在配置文件hardhat.config.js中,配置合约solidity版本和rpc信息,其中apiKey是用作浏览器验证时使用,如果不需要验证,可不用配置。accounts是一个数组,其中存放私钥数组。 如下所示:require("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { version: "0.4.26", settings: { optimizer: { enabled: true, runs: 2...
Web3 developer

Subscribe to lolieatapple

Subscribe to lolieatapple
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
APTOS公链可视为Meta(原Facebook)Libra(后更名Diem)计划搁浅后的续篇。
今年1月底,Diem被Meta出售,一些核心成员出走,组建团队基于Diem的开源代码进行Aptos公链的开发。
其号称在理想状态下,每秒可处理16万笔交易。
链节点使用Rust语言开发。
链上智能合约的开发语言是Move,是 Diem 项目 专门为区块链开发的一种安全可靠的智能合约编程语言,其语法与Rust语言类似。
(浏览器搜索功能不好使,可以直接使用URL:https://explorer.devnet.aptos.dev/account/0x3e8bc3b97d4710c3cf1e89890756f7872ead687dbd4d9d4f9118b885bf81c5da )
TypeScript SDK: https://www.npmjs.com/package/aptos
MOVE语言教程(中文、不完整):https://move-book.com/cn/index.html
devnet API_URL: https://fullnode.devnet.aptoslabs.com/v1 (在SDK中使用)
devnet FAUCET: https://faucet.devnet.aptoslabs.com (在SDK中使用,最多申请1000000)
testnet FAUCET: (浏览器打开)
Ed25519签名算法:https://blog.csdn.net/sinat_34070003/article/details/79462557
(波卡、Cardano、NEAR 和 Solana 等区块链也在使用Ed25519签名算法:https://blog.csdn.net/mutourend/article/details/121264777)
(从Aptos标准库代码上看,它支持3种曲线签名算法: ed25519, secp256k1, bls12381,但发送交易时默认是使用ed25519)
testnet faucet
( 基于ts sdk,示例代码:https://github.com/aptos-labs/aptos-core/blob/main/developer-docs-site/static/examples/typescript/first_transaction.ts )
1)账户创建与测试币申请
从代码中看APTOS的decimals是8位,但目前在钱包中并没有使用小数,全部按wei在显示和使用,包括钱包转账,gas fee,浏览器展示等。
每个账户地址都关联了一个Authentication Key。这个Authentication Key实际上是钱包私钥的公钥。
但账户可以通过rotate的接口来更新这个Authentication Key,从而达到地址不变,但控制私钥变更的目的。
可以使用浏览器插件钱包创建地址和申请测试币。
也可以使用sdk+js脚本,脚本如下:
export const NODE_URL = "https://fullnode.devnet.aptoslabs.com";
export const FAUCET_URL = "https://faucet.devnet.aptoslabs.com";
/** AptosAccount provides methods around addresses, key-pairs */
import { AptosAccount, TxnBuilderTypes, BCS, MaybeHexString } from "aptos";
/** Wrappers around the Aptos Node and Faucet API */
import { AptosClient, FaucetClient } from "aptos";
const client = new AptosClient(NODE_URL);
const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL);
// 创建钱包账户
const alice = new AptosAccount();
const bob = new AptosAccount();
console.log(`Alice: ${alice.address()} Key Seed: ${Buffer.from(alice.signingKey.secretKey).toString("hex")}`);
console.log(`Bob: ${bob.address()} Key Seed: ${Buffer.from(bob.signingKey.secretKey).toString("hex")}`);
// 申请Faucet测试币,最多1_000_000
await faucetClient.fundAccount(alice.address(), 5_000);
await faucetClient.fundAccount(bob.address(), 0);
测试币申请完成后,可以在浏览器中查看余额。
2)账户余额查询
因为APTOS账户余额以状态数据的形式存储在用户地址中,因此需要对数据进行解析。
export async function accountBalance(accountAddress: MaybeHexString): Promise<number | null> {
const resource = await client.getAccountResource(accountAddress, "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>");
if (resource == null) {
return null;
}
return parseInt((resource.data as any)["coin"]["value"]);
}
在浏览器中查看地址信息的时候,也是JSON样式的状态数据:
!\image-20220817182221463\
3)发送转账交易
BCS是一种序列化的格式:Binary Canonical Serialization (BCS)
APTOS默认使用BCS格式发送交易。
APTOS使用使用块高度的同时,还使用区块链状态数据库的VERSION版本号。我理解每一笔导致状态变化的交易就会得到一个新的version,而一个块高度内可以包含多个version。(所以version可以理解为总交易序号?)
使用交易中的执行脚本实现用户账户状态数据的变更。
*注意:代码中的TransactionPayloadScriptFunction已经变更,请参考最新的example代码。
/**
* Transfers a given coin amount from a given accountFrom to the recipient's account address.
* Returns the transaction hash of the transaction used to transfer.
*/
async function transfer(accountFrom: AptosAccount, recipient: MaybeHexString, amount: number): Promise<string> {
// 获取token信息,这里是原生币0x1::aptos_coin::AptosCoin
const token = new TxnBuilderTypes.TypeTagStruct(TxnBuilderTypes.StructTag.fromString("0x1::aptos_coin::AptosCoin"));
// 构建转账脚本
const scriptFunctionPayload = new TxnBuilderTypes.TransactionPayloadScriptFunction(
TxnBuilderTypes.ScriptFunction.natural(
"0x1::coin",
"transfer",
[token],
[BCS.bcsToBytes(TxnBuilderTypes.AccountAddress.fromHex(recipient)), BCS.bcsSerializeUint64(amount)],
),
);
// 获取nonce和chainId
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
client.getAccount(accountFrom.address()),
client.getChainId(),
]);
// 生成rawTransaction, 填写gasPrice, maxGas和超时信息
const rawTxn = new TxnBuilderTypes.RawTransaction(
TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
BigInt(sequenceNumber),
scriptFunctionPayload,
1000n,
1n,
BigInt(Math.floor(Date.now() / 1000) + 10),
new TxnBuilderTypes.ChainId(chainId),
);
// 生成BCS格式的交易
const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
// 广播BCS格式的交易
const pendingTxn = await client.submitSignedBCSTransaction(bcsTxn);
return pendingTxn.hash;
}
4)使用DApp网页钱包发送普通交易
普通交易转账实际上是对预置合约的调用。
const transaction = {
type: "entry_function_payload",
function: `0x1::coin::transfer`,
arguments: ['0x0aa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471', '200'],
type_arguments: [`0x1::aptos_coin::AptosCoin`],
};
console.log('transaction', transaction);
let ret = await window.aptos.signAndSubmitTransaction(transaction);
type: "entry_function_payload" 交易类型:带参数的合约调用。
function: 0x1::coin::transfer调用接口:0x1是合约地址,coin是合约名,transfer是合约方法。
type_arguments: [0x1::aptos_coin::AptosCoin] 模板类型。(不同的模板类型会使操作作用在本地的不同状态数据)
arguments: ['0x0aa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471', '200'],合约参数。
目前插件钱包只支持以下6个接口函数:
CONNECT: 'connect',
DISCONNECT: 'disconnect',
GET_ACCOUNT_ADDRESS: 'getAccountAddress',
IS_CONNECTED: 'is_connected',
SIGN_AND_SUBMIT_TRANSACTION: 'signAndSubmitTransaction',
SIGN_TRANSACTION: 'signTransaction',
根据社区用户lyn建议,使用下面这个转账接口,才会自动注册账号,上面的不会自动注册。
"payload": {
"function": "0x1::aptos_account::transfer",
"type_arguments": [],
"arguments": [
"0x6f755f59b2dac9ee2b7b03f6332fd6bb0721b4d99cb385685f7e4adffc359b3c",
"333"
],
"type": "entry_function_payload"
}
APTOS公链可视为Meta(原Facebook)Libra(后更名Diem)计划搁浅后的续篇。
今年1月底,Diem被Meta出售,一些核心成员出走,组建团队基于Diem的开源代码进行Aptos公链的开发。
其号称在理想状态下,每秒可处理16万笔交易。
链节点使用Rust语言开发。
链上智能合约的开发语言是Move,是 Diem 项目 专门为区块链开发的一种安全可靠的智能合约编程语言,其语法与Rust语言类似。
(浏览器搜索功能不好使,可以直接使用URL:https://explorer.devnet.aptos.dev/account/0x3e8bc3b97d4710c3cf1e89890756f7872ead687dbd4d9d4f9118b885bf81c5da )
TypeScript SDK: https://www.npmjs.com/package/aptos
MOVE语言教程(中文、不完整):https://move-book.com/cn/index.html
devnet API_URL: https://fullnode.devnet.aptoslabs.com/v1 (在SDK中使用)
devnet FAUCET: https://faucet.devnet.aptoslabs.com (在SDK中使用,最多申请1000000)
testnet FAUCET: (浏览器打开)
Ed25519签名算法:https://blog.csdn.net/sinat_34070003/article/details/79462557
(波卡、Cardano、NEAR 和 Solana 等区块链也在使用Ed25519签名算法:https://blog.csdn.net/mutourend/article/details/121264777)
(从Aptos标准库代码上看,它支持3种曲线签名算法: ed25519, secp256k1, bls12381,但发送交易时默认是使用ed25519)
testnet faucet
( 基于ts sdk,示例代码:https://github.com/aptos-labs/aptos-core/blob/main/developer-docs-site/static/examples/typescript/first_transaction.ts )
1)账户创建与测试币申请
从代码中看APTOS的decimals是8位,但目前在钱包中并没有使用小数,全部按wei在显示和使用,包括钱包转账,gas fee,浏览器展示等。
每个账户地址都关联了一个Authentication Key。这个Authentication Key实际上是钱包私钥的公钥。
但账户可以通过rotate的接口来更新这个Authentication Key,从而达到地址不变,但控制私钥变更的目的。
可以使用浏览器插件钱包创建地址和申请测试币。
也可以使用sdk+js脚本,脚本如下:
export const NODE_URL = "https://fullnode.devnet.aptoslabs.com";
export const FAUCET_URL = "https://faucet.devnet.aptoslabs.com";
/** AptosAccount provides methods around addresses, key-pairs */
import { AptosAccount, TxnBuilderTypes, BCS, MaybeHexString } from "aptos";
/** Wrappers around the Aptos Node and Faucet API */
import { AptosClient, FaucetClient } from "aptos";
const client = new AptosClient(NODE_URL);
const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL);
// 创建钱包账户
const alice = new AptosAccount();
const bob = new AptosAccount();
console.log(`Alice: ${alice.address()} Key Seed: ${Buffer.from(alice.signingKey.secretKey).toString("hex")}`);
console.log(`Bob: ${bob.address()} Key Seed: ${Buffer.from(bob.signingKey.secretKey).toString("hex")}`);
// 申请Faucet测试币,最多1_000_000
await faucetClient.fundAccount(alice.address(), 5_000);
await faucetClient.fundAccount(bob.address(), 0);
测试币申请完成后,可以在浏览器中查看余额。
2)账户余额查询
因为APTOS账户余额以状态数据的形式存储在用户地址中,因此需要对数据进行解析。
export async function accountBalance(accountAddress: MaybeHexString): Promise<number | null> {
const resource = await client.getAccountResource(accountAddress, "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>");
if (resource == null) {
return null;
}
return parseInt((resource.data as any)["coin"]["value"]);
}
在浏览器中查看地址信息的时候,也是JSON样式的状态数据:
!\image-20220817182221463\
3)发送转账交易
BCS是一种序列化的格式:Binary Canonical Serialization (BCS)
APTOS默认使用BCS格式发送交易。
APTOS使用使用块高度的同时,还使用区块链状态数据库的VERSION版本号。我理解每一笔导致状态变化的交易就会得到一个新的version,而一个块高度内可以包含多个version。(所以version可以理解为总交易序号?)
使用交易中的执行脚本实现用户账户状态数据的变更。
*注意:代码中的TransactionPayloadScriptFunction已经变更,请参考最新的example代码。
/**
* Transfers a given coin amount from a given accountFrom to the recipient's account address.
* Returns the transaction hash of the transaction used to transfer.
*/
async function transfer(accountFrom: AptosAccount, recipient: MaybeHexString, amount: number): Promise<string> {
// 获取token信息,这里是原生币0x1::aptos_coin::AptosCoin
const token = new TxnBuilderTypes.TypeTagStruct(TxnBuilderTypes.StructTag.fromString("0x1::aptos_coin::AptosCoin"));
// 构建转账脚本
const scriptFunctionPayload = new TxnBuilderTypes.TransactionPayloadScriptFunction(
TxnBuilderTypes.ScriptFunction.natural(
"0x1::coin",
"transfer",
[token],
[BCS.bcsToBytes(TxnBuilderTypes.AccountAddress.fromHex(recipient)), BCS.bcsSerializeUint64(amount)],
),
);
// 获取nonce和chainId
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
client.getAccount(accountFrom.address()),
client.getChainId(),
]);
// 生成rawTransaction, 填写gasPrice, maxGas和超时信息
const rawTxn = new TxnBuilderTypes.RawTransaction(
TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
BigInt(sequenceNumber),
scriptFunctionPayload,
1000n,
1n,
BigInt(Math.floor(Date.now() / 1000) + 10),
new TxnBuilderTypes.ChainId(chainId),
);
// 生成BCS格式的交易
const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
// 广播BCS格式的交易
const pendingTxn = await client.submitSignedBCSTransaction(bcsTxn);
return pendingTxn.hash;
}
4)使用DApp网页钱包发送普通交易
普通交易转账实际上是对预置合约的调用。
const transaction = {
type: "entry_function_payload",
function: `0x1::coin::transfer`,
arguments: ['0x0aa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471', '200'],
type_arguments: [`0x1::aptos_coin::AptosCoin`],
};
console.log('transaction', transaction);
let ret = await window.aptos.signAndSubmitTransaction(transaction);
type: "entry_function_payload" 交易类型:带参数的合约调用。
function: 0x1::coin::transfer调用接口:0x1是合约地址,coin是合约名,transfer是合约方法。
type_arguments: [0x1::aptos_coin::AptosCoin] 模板类型。(不同的模板类型会使操作作用在本地的不同状态数据)
arguments: ['0x0aa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471', '200'],合约参数。
目前插件钱包只支持以下6个接口函数:
CONNECT: 'connect',
DISCONNECT: 'disconnect',
GET_ACCOUNT_ADDRESS: 'getAccountAddress',
IS_CONNECTED: 'is_connected',
SIGN_AND_SUBMIT_TRANSACTION: 'signAndSubmitTransaction',
SIGN_TRANSACTION: 'signTransaction',
根据社区用户lyn建议,使用下面这个转账接口,才会自动注册账号,上面的不会自动注册。
"payload": {
"function": "0x1::aptos_account::transfer",
"type_arguments": [],
"arguments": [
"0x6f755f59b2dac9ee2b7b03f6332fd6bb0721b4d99cb385685f7e4adffc359b3c",
"333"
],
"type": "entry_function_payload"
}
Aptos上的智能合约称做Move Module,合约发布后有一个合约地址,这个合约地址就是发布人的账户地址。
编译合约需要用的命令行工具下载地址:https://github.com/aptos-labs/aptos-core/releases/
(使用代码直接编译此工具会报错,建议直接下载编译好的二进制文件)
*注意,Aptos接口变化极快,script_function_payload类型已经不可用,变成了entry_function_payload
当前支持3种交易类型:
entry_function_payload:调用module接口的交易
script_payload:脚本执行交易
module_bundle_payload:module部署
其中entry_function类似于一种内置在module中的脚本,在函数定义时使用public entry fun xxxx() { }.
scritp是链下编写,编译成bytecode后,随交易一起执行的脚本。
module是链上的合约。
对命令行工具初始化后,即可使用它来部署合约。首先用插件钱包创建一个地址,导出私钥后,执行如下初始化指令:
$ aptos init
# 按照提示,选择网络(可默认),然后输入导出的私钥
然后使用如下指令,即可查看地址的状态数据:
$ aptos account list
为方便web3开发,插件钱包启用后,会在浏览器内注入一个window.aptos对象,在DApp中使用这个对象可以与插件钱包交互。
例如获取地址信息:
await window.aptos.connect()
await window.aptos.account()
下载示例合约代码: the hello_blockchain package.
使用命令行发布合约代码,填写账户地址在发布指令中:
$ aptos move publish --package-dir /path/to/hello_blockchain/ --named-addresses HelloBlockchain=<address>
(这里的路径需要写绝对路径,相对路径好像不支持)
其中的**--named-addresses**表示命名替换,将module中的
module HelloBlockchain::Message {
替换成
module 0x5af503b5c379bd69f46184304975e1ef1fa57f422dd193cdad67dc139d532481::Message {
在状态数据存储中,只能看到这个地址,看不到之前的Module名字。通过这种方式,将合约发布到账户地址上。
在浏览器上查看此地址,即可在account modules下方看到此合约的bytecode和开放的ABI接口信息,包括名称、函数、数据结构等。
web钱包需要先connect,然后才能使用。
const address = '0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471';
const message = 'Hello Wanchain';
const transaction = {
type: "entry_function_payload",
function: `${address}::message::set_message`,
arguments: [stringToHex(message)],
type_arguments: [],
};
await window.aptos.connect();
let ret = await window.aptos.signAndSubmitTransaction(transaction);
console.log('ret', ret);
其中address是部署合约的account地址,同时也是合约地址。
可以更换不同的地址来调用此合约,可以在浏览器中看到,修改的是每个account自己的状态数据。
示例代码中的set_message函数需要两个参数,函数声明如下:
public(script) fun set_message(account: signer, message_bytes: vector<u8>)
第一个参数signer由钱包自动提供。用户只需要提供第二个参数即可。
使用getAccountResources接口读取全部的状态数据信息,从中挑选需要读取的项。
const client = new AptosClient('https://fullnode.devnet.aptoslabs.com/v1');
console.log('account', await client.getAccount('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471'));
console.log('modules', await client.getAccountModules('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471'));
console.log('module', await client.getAccountModule('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471', 'message'));
console.log('resources', await client.getAccountResources('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471'));
1. 部署合约
在Aptos连的标准框架中,有一个专用的代币合约:0x1::coin,使用它可以创建一个标准代币。
(此外,标准框架中0x1::managed_coin是带有mint/burn方法的标准代币)
(在浏览器中查看0x1地址的详细信息,可以看到所有的标准框架合约信息:https://explorer.devnet.aptos.dev/account/0x1)
自定义代币的合约代码如下:(示例代码: aptos-move/move-examples/moon_coin)
module MoonCoinType::moon_coin {
struct MoonCoin {}
}
将这个数据注册到标准代币合约0x1::coin中,即可得到一个自定义代币。
首先使用第3)节的指令部署合约:
$ aptos init
$ aptos move publish --package-dir XXXX --named-addresses MoonCoinType=0xXXXXX
每个不同的代码目录,都需要重新init一次,init的信息回保存到当前目录下的**.aptos/config.yaml**文件中,用完记得删除以保证私钥安全。
2. 初始化代币
接下来使用预置合约0x1::managed_coin对我们部署的合约进行初始化initialize。
managed_coin比coin多了mint、burn接口。
初始化时,填写代币的name, symbol, decimals, monitor_supply等4个信息。
我理解的初始化,是使用0x1::managed_coin合约的initialize方法对本地状态数据进行配置和变更。
使用Web钱包对自定义代币初始化代码如下:
const transaction = {
type: "entry_function_payload",
function: `0x1::managed_coin::initialize`,
arguments: [stringToHex('Moon Coin'), stringToHex('MOON'), 6, false],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
初始化完成后,可以在浏览器中看到,自定义的代币decimals, name, symbol信息已经有了:
{
"decimals": 6,
"name": "Moon Coin",
"supply": {
"vec": []
},
"symbol": "MOON"
}
在初始化后,调用初始化的地址自动成为代币合约的owner。
3. 注册接收人
在Aptos链,一个用户想要接收除APTOS默认币以外的代币时,必须先由接受者主动明确的注册register接收这个代币,然后才能接收。(不能随意空投代币)
接受者通过调用预置合约的此接口来接收预置代币:
0x1::coins::register<CoinType>:
注册代码:
const transaction = {
type: "entry_function_payload",
function: `0x1::coins::register`,
arguments: [],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
注册完成之后,可以在浏览器上看到,在地址的0x1::coin::CoinStore下面多了一个自定义代币类型的数据段:
0x1::coin::CoinStore<0xb2e77a8f90524cf30f6f6540530b67a66b7b5fb511ec0d0319668aa9bd3a106d::moon_coin::MoonCoin>
...
这个字段与原生币类似,只是尖括号内的类型不同,其它的数据字段和事件完全相同。原生币:
0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>
4.铸造代币
铸币代码:
const transaction = {
type: "entry_function_payload",
function: `0x1::managed_coin::mint`,
arguments: ['0xb2e77a8f90524cf30f6f6540530b67a66b7b5fb511ec0d0319668aa9bd3a106d', '1000000'],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
5. 代币转账
自定义转账的方法与原生币基本相同。代码如下:(接收地址需要先注册才能接收,否则交易会上链但链上执行失败)
const transaction = {
type: "entry_function_payload",
function: `0x1::coin::transfer`,
arguments: ['0x8ded6d8821f7e9a4ea9ecdd953cabf29f263866a0e50a0d66cc0561ef5a99db6', '1000'],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
rotate:
APTOS的地址可以更换auth key,实现在账户地址不变的前提下更换(rotate)签名私钥。可以通过这种方式迁移或释放地址权限。
地址类型:
地址类型有两种,一种是普通地址,另一种是资源地址resource account,可以由合约或脚本创建,不与创建者地址相同。
状态访问接口:
内置的访问状态数据的函数一共有5个:
move_to: 创建资源
move_from: 删除资源
borrow_global: 获取只读引用
borrow_global_mut: 获取可写入引用
exists: 判断资源是否存在
这四个函数只能访问本module内的结构体数据,但可以通过封装公开的函数接口,提供外部访问本地状态数据的权限。
!\image-20220830163511359\
宏定义函数:
函数后面带!符号的是宏定义函数,例如assert!()
函数访问权限:
Module中,函数访问权限有3种,一种是公开public,一种是不带public,默认只有module内部可以访问,最后一种是public(friend) 只有定义成friend的module有权限访问。因此,原生APT coin转账不需要接收人主动注册(register),因为原生APT coin的module有friend权限,可以自动帮接收地址注册(register)。
合约升级:
有权限的地址,可以对部署好的module升级。有3种升级策略:强制(arbitrary),兼容(compatible),不可升级(immutable)。通过在Move.toml文件中可以配置,默认是兼容模式。
[package]
name = "MyApp"
version = "0.0.1"
upgrade_policy = "compatible"
...
部署为兼容模式的module,可以更改为不可升级,反之则不可。
兼容模式要求所有旧的全局都不可更改,所有旧的公开api接口定义不可变更。
钱包签名:
module函数入口参数的第一个&signer类型参数可省略不填,SDK会自动填写当前钱包。
合约event发送:
event的创建需要首先使用 account::new_event_handle<T>(sender) 接口来创建event handler,然后使用 event::emit_event<T>()接口来发送event信息。
在查询时,有2种形式,一种是通过handler查询,一种是通过guid来查询。
使用handler查询时,需要输入地址,主存储结构体名称,event handler所属字段名称。
使用guid查询时,使用 creation_num + account的形式,creation_num是event种的数字,以小端模式uint64数字存储。例如create_num是4时:0x0400000000000000166e192a37e1b17dfdb201a2bc8c4cbc25a6e24c5059c05b8f5188fd9ccf4c76
查询条件的start是event的序号,每个event序号从0开始递增。
/// Event emitted when some amount of a coin is deposited into an account.
struct DepositEvent has drop, store {
amount: u64,
}
...
let handler = account::new_event_handle<T>(sender)
...
event::emit_event<T>(
&mut handler,
DepositEvent { amount: coin.value },
);
地址校验:
正则表达式:"^(0x)[0-9A-Fa-f]{64}$"
常用cli指令:
aptos move init 初始化工程目录(Move.toml文件中AptosFramework的rev设置为devnet,并运行clean)
aptos move clean 清理缓存(更最新新标准库)
aptos move compile 编译
aptos move publish 发布module
aptos move run 发交易调用module的entry函数
编译命令:
$ aptos move compile --package-dir . --named-addresses HelloBlockchain=0x{alice_address_here}
这里编译的示例Move代码中的HelloBlockchain:aptos-core/aptos-move/move-examples/hello_blockchain
这里的--named-addresses后面的地址,是提前生成好的钱包地址。
使用这个地址来部署这个合约。同时,这个合约地址也是部署者的地址。
其它用户地址访问这个合约时,修改的是自己地址下的状态数据。
HelloBlockchain示例代码可以为调用者地址增加一个MessageHolder字段,并存储设置的message信息。
调用成功后,在浏览器中可以查看调用者地址状态数据时,即可看到新增的数据字段:
!\image-20220818114723563\
使用aptos move run 指令执行时,args类型支持:[u8, u64, u128, bool, hex, string, address, raw]。
查询event时,可以使用序号或guid,使用序号的方式为:
curl --request GET \
--url https://fullnode.devnet.aptoslabs.com/v1/accounts/address/events/creation_number \
--header 'Content-Type: application/json'
Aptos上的智能合约称做Move Module,合约发布后有一个合约地址,这个合约地址就是发布人的账户地址。
编译合约需要用的命令行工具下载地址:https://github.com/aptos-labs/aptos-core/releases/
(使用代码直接编译此工具会报错,建议直接下载编译好的二进制文件)
*注意,Aptos接口变化极快,script_function_payload类型已经不可用,变成了entry_function_payload
当前支持3种交易类型:
entry_function_payload:调用module接口的交易
script_payload:脚本执行交易
module_bundle_payload:module部署
其中entry_function类似于一种内置在module中的脚本,在函数定义时使用public entry fun xxxx() { }.
scritp是链下编写,编译成bytecode后,随交易一起执行的脚本。
module是链上的合约。
对命令行工具初始化后,即可使用它来部署合约。首先用插件钱包创建一个地址,导出私钥后,执行如下初始化指令:
$ aptos init
# 按照提示,选择网络(可默认),然后输入导出的私钥
然后使用如下指令,即可查看地址的状态数据:
$ aptos account list
为方便web3开发,插件钱包启用后,会在浏览器内注入一个window.aptos对象,在DApp中使用这个对象可以与插件钱包交互。
例如获取地址信息:
await window.aptos.connect()
await window.aptos.account()
下载示例合约代码: the hello_blockchain package.
使用命令行发布合约代码,填写账户地址在发布指令中:
$ aptos move publish --package-dir /path/to/hello_blockchain/ --named-addresses HelloBlockchain=<address>
(这里的路径需要写绝对路径,相对路径好像不支持)
其中的**--named-addresses**表示命名替换,将module中的
module HelloBlockchain::Message {
替换成
module 0x5af503b5c379bd69f46184304975e1ef1fa57f422dd193cdad67dc139d532481::Message {
在状态数据存储中,只能看到这个地址,看不到之前的Module名字。通过这种方式,将合约发布到账户地址上。
在浏览器上查看此地址,即可在account modules下方看到此合约的bytecode和开放的ABI接口信息,包括名称、函数、数据结构等。
web钱包需要先connect,然后才能使用。
const address = '0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471';
const message = 'Hello Wanchain';
const transaction = {
type: "entry_function_payload",
function: `${address}::message::set_message`,
arguments: [stringToHex(message)],
type_arguments: [],
};
await window.aptos.connect();
let ret = await window.aptos.signAndSubmitTransaction(transaction);
console.log('ret', ret);
其中address是部署合约的account地址,同时也是合约地址。
可以更换不同的地址来调用此合约,可以在浏览器中看到,修改的是每个account自己的状态数据。
示例代码中的set_message函数需要两个参数,函数声明如下:
public(script) fun set_message(account: signer, message_bytes: vector<u8>)
第一个参数signer由钱包自动提供。用户只需要提供第二个参数即可。
使用getAccountResources接口读取全部的状态数据信息,从中挑选需要读取的项。
const client = new AptosClient('https://fullnode.devnet.aptoslabs.com/v1');
console.log('account', await client.getAccount('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471'));
console.log('modules', await client.getAccountModules('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471'));
console.log('module', await client.getAccountModule('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471', 'message'));
console.log('resources', await client.getAccountResources('0xaa630f7e14a5bc07d822f35007a5e316cee9f1b359e4bec3a13a0721ff5f471'));
1. 部署合约
在Aptos连的标准框架中,有一个专用的代币合约:0x1::coin,使用它可以创建一个标准代币。
(此外,标准框架中0x1::managed_coin是带有mint/burn方法的标准代币)
(在浏览器中查看0x1地址的详细信息,可以看到所有的标准框架合约信息:https://explorer.devnet.aptos.dev/account/0x1)
自定义代币的合约代码如下:(示例代码: aptos-move/move-examples/moon_coin)
module MoonCoinType::moon_coin {
struct MoonCoin {}
}
将这个数据注册到标准代币合约0x1::coin中,即可得到一个自定义代币。
首先使用第3)节的指令部署合约:
$ aptos init
$ aptos move publish --package-dir XXXX --named-addresses MoonCoinType=0xXXXXX
每个不同的代码目录,都需要重新init一次,init的信息回保存到当前目录下的**.aptos/config.yaml**文件中,用完记得删除以保证私钥安全。
2. 初始化代币
接下来使用预置合约0x1::managed_coin对我们部署的合约进行初始化initialize。
managed_coin比coin多了mint、burn接口。
初始化时,填写代币的name, symbol, decimals, monitor_supply等4个信息。
我理解的初始化,是使用0x1::managed_coin合约的initialize方法对本地状态数据进行配置和变更。
使用Web钱包对自定义代币初始化代码如下:
const transaction = {
type: "entry_function_payload",
function: `0x1::managed_coin::initialize`,
arguments: [stringToHex('Moon Coin'), stringToHex('MOON'), 6, false],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
初始化完成后,可以在浏览器中看到,自定义的代币decimals, name, symbol信息已经有了:
{
"decimals": 6,
"name": "Moon Coin",
"supply": {
"vec": []
},
"symbol": "MOON"
}
在初始化后,调用初始化的地址自动成为代币合约的owner。
3. 注册接收人
在Aptos链,一个用户想要接收除APTOS默认币以外的代币时,必须先由接受者主动明确的注册register接收这个代币,然后才能接收。(不能随意空投代币)
接受者通过调用预置合约的此接口来接收预置代币:
0x1::coins::register<CoinType>:
注册代码:
const transaction = {
type: "entry_function_payload",
function: `0x1::coins::register`,
arguments: [],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
注册完成之后,可以在浏览器上看到,在地址的0x1::coin::CoinStore下面多了一个自定义代币类型的数据段:
0x1::coin::CoinStore<0xb2e77a8f90524cf30f6f6540530b67a66b7b5fb511ec0d0319668aa9bd3a106d::moon_coin::MoonCoin>
...
这个字段与原生币类似,只是尖括号内的类型不同,其它的数据字段和事件完全相同。原生币:
0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>
4.铸造代币
铸币代码:
const transaction = {
type: "entry_function_payload",
function: `0x1::managed_coin::mint`,
arguments: ['0xb2e77a8f90524cf30f6f6540530b67a66b7b5fb511ec0d0319668aa9bd3a106d', '1000000'],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
5. 代币转账
自定义转账的方法与原生币基本相同。代码如下:(接收地址需要先注册才能接收,否则交易会上链但链上执行失败)
const transaction = {
type: "entry_function_payload",
function: `0x1::coin::transfer`,
arguments: ['0x8ded6d8821f7e9a4ea9ecdd953cabf29f263866a0e50a0d66cc0561ef5a99db6', '1000'],
type_arguments: [`${address}::moon_coin::MoonCoin`],
};
let ret = await window.aptos.signAndSubmitTransaction(transaction);
rotate:
APTOS的地址可以更换auth key,实现在账户地址不变的前提下更换(rotate)签名私钥。可以通过这种方式迁移或释放地址权限。
地址类型:
地址类型有两种,一种是普通地址,另一种是资源地址resource account,可以由合约或脚本创建,不与创建者地址相同。
状态访问接口:
内置的访问状态数据的函数一共有5个:
move_to: 创建资源
move_from: 删除资源
borrow_global: 获取只读引用
borrow_global_mut: 获取可写入引用
exists: 判断资源是否存在
这四个函数只能访问本module内的结构体数据,但可以通过封装公开的函数接口,提供外部访问本地状态数据的权限。
!\image-20220830163511359\
宏定义函数:
函数后面带!符号的是宏定义函数,例如assert!()
函数访问权限:
Module中,函数访问权限有3种,一种是公开public,一种是不带public,默认只有module内部可以访问,最后一种是public(friend) 只有定义成friend的module有权限访问。因此,原生APT coin转账不需要接收人主动注册(register),因为原生APT coin的module有friend权限,可以自动帮接收地址注册(register)。
合约升级:
有权限的地址,可以对部署好的module升级。有3种升级策略:强制(arbitrary),兼容(compatible),不可升级(immutable)。通过在Move.toml文件中可以配置,默认是兼容模式。
[package]
name = "MyApp"
version = "0.0.1"
upgrade_policy = "compatible"
...
部署为兼容模式的module,可以更改为不可升级,反之则不可。
兼容模式要求所有旧的全局都不可更改,所有旧的公开api接口定义不可变更。
钱包签名:
module函数入口参数的第一个&signer类型参数可省略不填,SDK会自动填写当前钱包。
合约event发送:
event的创建需要首先使用 account::new_event_handle<T>(sender) 接口来创建event handler,然后使用 event::emit_event<T>()接口来发送event信息。
在查询时,有2种形式,一种是通过handler查询,一种是通过guid来查询。
使用handler查询时,需要输入地址,主存储结构体名称,event handler所属字段名称。
使用guid查询时,使用 creation_num + account的形式,creation_num是event种的数字,以小端模式uint64数字存储。例如create_num是4时:0x0400000000000000166e192a37e1b17dfdb201a2bc8c4cbc25a6e24c5059c05b8f5188fd9ccf4c76
查询条件的start是event的序号,每个event序号从0开始递增。
/// Event emitted when some amount of a coin is deposited into an account.
struct DepositEvent has drop, store {
amount: u64,
}
...
let handler = account::new_event_handle<T>(sender)
...
event::emit_event<T>(
&mut handler,
DepositEvent { amount: coin.value },
);
地址校验:
正则表达式:"^(0x)[0-9A-Fa-f]{64}$"
常用cli指令:
aptos move init 初始化工程目录(Move.toml文件中AptosFramework的rev设置为devnet,并运行clean)
aptos move clean 清理缓存(更最新新标准库)
aptos move compile 编译
aptos move publish 发布module
aptos move run 发交易调用module的entry函数
编译命令:
$ aptos move compile --package-dir . --named-addresses HelloBlockchain=0x{alice_address_here}
这里编译的示例Move代码中的HelloBlockchain:aptos-core/aptos-move/move-examples/hello_blockchain
这里的--named-addresses后面的地址,是提前生成好的钱包地址。
使用这个地址来部署这个合约。同时,这个合约地址也是部署者的地址。
其它用户地址访问这个合约时,修改的是自己地址下的状态数据。
HelloBlockchain示例代码可以为调用者地址增加一个MessageHolder字段,并存储设置的message信息。
调用成功后,在浏览器中可以查看调用者地址状态数据时,即可看到新增的数据字段:
!\image-20220818114723563\
使用aptos move run 指令执行时,args类型支持:[u8, u64, u128, bool, hex, string, address, raw]。
查询event时,可以使用序号或guid,使用序号的方式为:
curl --request GET \
--url https://fullnode.devnet.aptoslabs.com/v1/accounts/address/events/creation_number \
--header 'Content-Type: application/json'
No activity yet