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-chain
program.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-chain
const [owner, todosCount] = await aptos.view({
payload: {
function: `${MODULE_ADDRESS}::${MODULE_NAME}::get_todo_list`,
typeArguments: [],
functionArguments: [userAddress],
},
});
console.log(owner);
console.log(todosCount);