Building on Aptos: A Guide for Solana Developers #1
Open Github Page
Solana to Aptos Cheat Sheet
Similarities
Differences
To-Do List Example
Tips for Building on Aptos
Video Review
Aptos Developer Docs
Read and Write functions
Write Functions
Let's keep using the todo list app as an example, on Solana, we define the create_todo_list
function like this:
use crate::state::TodoList;use anchor_lang::prelude::*;#[derive(Accounts)]pub struct CreateTodoList<'info> { #[account(init, payer = user, space = 10240)] pub todo_list: Account<'info, TodoList>, #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>,}pub fn handle_create_todo_list(ctx: Context<CreateTodoList>) -> Result<()> { let todo_list = &mut ctx.accounts.todo_list; todo_list.owner = *ctx.accounts.user.key; todo_list.todos = Vec::new(); Ok(())}
Calling it off-chain
program.methods .createTodoList() .accounts({ todoList: todoListKeypair.publicKey, user: sender.publicKey, }) .signers([sender, todoListKeypair]) .rpc() .then((tx) => { console.log(tx); });
On Aptos we do this
public entry fun create_todo_list(sender: &signer) { let todo_list = TodoList { owner: signer::address_of(sender), todos: vector::empty(), }; // store the TodoList resource directly under the sender move_to(sender, todo_list);}
Calling it off-chain
import { Aptos, AptosConfig, Network, Account } from "@aptos-labs/ts-sdk";const config = new AptosConfig({ network: Network.TESTNET,});const aptos = new Aptos(config);const rawTxn = await aptos.transaction.build.simple({ sender: sender.accountAddress, data: { function: `${MODULE_ADDRESS}::${MODULE_NAME}::create_todo_list`, // sender will be automatically passed as the signer functionArguments: [], },});const pendingTxn = await aptos.signAndSubmitTransaction({ signer: sender, transaction: rawTxn,});const response = await aptos .waitForTransaction({ transactionHash: pendingTxn.hash, }) .then((response) => { console.log(response); });
Read Functions
On Solana, you usually read data by reading the data of an account, either on-chain or off-chain, and de-serialize it. But there is no easy way for a program to return some processed result of the account data.
// read todo list off-chainprogram.account.todoList.fetch(todoListKeypair.publicKey).then((todoList) => { console.log(todoList.owner.toBase58()); console.log(todoList.todos.length);});
Aptos supports view function like Ethereum, where you can define a function that reads some data, do some processing, and return the result. Since these functions are read-only, they don't charge gas fees.
// define view function in module, it can be called by other modules or off-chain#[view]public fun get_todo_list(sender: address): (address, u64) acquires TodoList { let todo_list = borrow_global<TodoList>(sender); (todo_list.owner, vector::length(&todo_list.todos))}
// call view function off-chainconst [owner, todosCount] = await aptos.view({ payload: { function: `${MODULE_ADDRESS}::${MODULE_NAME}::get_todo_list`, typeArguments: [], functionArguments: [userAddress], },});console.log(owner);console.log(todosCount);