Building on Aptos: A Guide for Ethereum Developers
Ethereum to Aptos Cheat Sheet
Account Models
Data Storage Models
Contract-Level Storage and Account-Centric Storage
Solidity to Move
Typescript SDK
Aptos Developer Docs
Solidity to Move
msg.sender
and signer
- Solidity: uses
msg.sender
to identify the caller of a function.function transfer(address recipient, uint256 amount) public {require(msg.sender != address(0), "Invalid sender");// Implementation} - Move: introduces a
&signer
reference, which provides a more secure way to represent the transaction authorizer.public entry fun transfer(account: &signer, recipient: address, amount: u64) {// Implementation}
msg.value
Equivalent in Move
- Solidity:
msg.value
represents the amount of native tokens sent within a function call. - Move: No direct equivalent. Transactions involving tokens in Move require explicit handling
through module functions. The example below uses the legacy Coin module.
public entry fun transfer(sender: &signer, recipient: address, amount: u64) {let sender_coins = coin::withdraw<Coin<MyTokenType>>(sender, amount);coin::deposit(recipient, sender_coins);}
Transferring Fungible Assets - Solidity: Ether and tokens are directly sent through address
operations and ERC-20 transfer calls. - Move: Used the coin module for native tokens and assets are handled through resources which are more tightly controlled. However, Aptos Move is now migrating to the Fungible Asset standard.
Vectors and Other Data Structures
- Solidity: Offers arrays and mappings as primary data structures.
- Move: Supports
vector<T>
for ordered collections and other modules for maps and sets.
State Variables, Resources and Struct Abilities
State Variables in Solidity are used to store data
that is part of the contract’s state on the blockchain. They are declared at contract level, outside
of functions, and can represent any data type. However, Move doesn’t use state variables, and instead
has a unique characteristic in which developers can give their structs abilities. Structs with the key
ability are known as “Resources”. These are unique, first-class citizens used to manage assets and other
critical data safely.
1. copy
Allows the struct to be copied. If omitted, the struct cannot be duplicated, and attempts to copy will result in a compile time error.
struct NoCopyStruct has drop { data: u64,}public fun try_to_copy() { let instance = NoCopyStruct { data: 42 }; let _copy_instance = instance; // This line will cause a compile-time error // Error: 'instance' cannot be copied because its type 'NoCopyExample::NoCopyStruct' // does not have the 'copy' ability}
2. drop
Allows the struct to be explicitly destroyed or go out of scope without being stored. If omitted, you must ensure that the struct is stored somewhere or passed on to avoid compile time error.
struct NoDropStruct has key, store { // Hypothetically, if 'drop' were not implicit data: u64,}public entry fun init(account: &signer) { let unused_instance = NoDropStruct { data: 42 }; // Error: 'NoDropStruct' without 'drop' ability must not be discarded.}
3. key
Indicates the struct can serve as a key for global storage. Structs with this ability can be uniquely identified in global storage, making them suitable for resources or data intended to be accessed across transactions.
4. store
Permits the struct to be stored in global storage. This is crucial for persistent
data that needs to live beyond the execution of a single transaction. A struct with the store
ability can be a part of other data structures or resources that are identified by a key in global storage. It’s suitable for components of larger entities, where direct access to those components isn’t required independently, but they still need to persist beyond a single transaction.
Here’s a code snippet that demonstrates all of the struct abilities.
module 0x1::my_module { use std::signer; // A simple struct with `copy` and `drop` abilities, but it cannot be stored in global storage struct CopyableDropable has copy, drop { data: u64, } // A resource struct that can be stored and uniquely identified in global storage struct MyResource has key, store { value: u64, } // Initialize and store a `MyResource` in the signer's account public entry fun init_resource(account: &signer, val: u64) { let resource = MyResource { value: val }; move_to(account, resource); // Requires `store` and `key` abilities to work } // Function demonstrating `copy` and `drop` public fun demonstrate_copy_drop(val: u64): u64 { let data = CopyableDropable { data: val }; let data_copy = data; // Allowed because of `copy` let sum = data.data + data_copy.data; // Use both structs // Both `data` and `data_copy` will be dropped here, allowed by `drop` sum }}