The project aims to show Aptos
features and highlight important security points
Aptos CLI is the primary tool needed for development on the Aptos blockchain
It manages accounts, compiles and publishes blockchain modules, resolves transactions, etc.
Download the binary file from github release and put it to any directory defined in $PATH
Use aptos config set-global-config --config-type VALUE
to choose where profiles info will be stored:
Workspace
- in a local directory of each projectGlobal
- in theHOME
dir
-
aptos init
- create a new on-chain account profileCommon used option is
PROFILE
-
aptos account fund-with-faucet --account PROFILE
- fund specified account from a faucetCommon known error is
411_LENGTH_REQUIRED
-
aptos move compile
- compile the module depending onMove.toml
configCommon used option is
NAMED_ADDRESSES
-
aptos move publish
- publish the module to blockchainCommon used options are
NAMED_ADDRESSES
andPROFILE
Common known error is
RESOURCE_NOT_FOUND
-
aptos move run
- run entry function of the specified moduleCommon used options are
FUNCTION_ID
,TYPE_ARGS
,ARGS
andPROFILE
Common known errors are
RESOURCE_NOT_FOUND
andMAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS
-
aptos move test
- run tests for the moduleCommon used option is
NAMED_ADDRESSES
-
Option<PROFILE>
- is needed for defining the profile which is used for a context of the command--profile NAME
-
Option<NAMED_ADDRESSES>
- is needed for defining addresses that are described inMove.toml
as_
(for example, address where a module will be published)--named-addresses NAME=ADDRESS
-
Option<FUNCTION_ID>
- is needed for defining which exactlyFUNCTION
in whichMODULE
at whichADDRESS
should be called--function-id 'ADDRESS::MODULE::FUNCTION'
-
Option<TYPE_ARGS>
- is needed for defining genericRESOURCE
type located in specifiedMODULE
at theADDRESS
, it may be used by the function if it process different data types depending on resource (for example, functions processing different coin types)--type-args 'ADDRESS::MODULE::RESOURCE'
-
Option<FUNCTION_ID>
- is needed for defining function parameters ofTYPE
containingVALUE
, look help command for a list of all supported types--args 'TYPE:VALUE'
-
Error<RESOURCE_NOT_FOUND>
- it may appear in case if not enough APT is presented on the account: use a faucet to get moreAPT Coin
"Error": "API error: API error Error(ResourceNotFound): Resource not found by Address(ADDRESS), Struct tag(TAG) and Ledger version(VERSION)"
-
Error<MAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS>
- it may appear in case if the amount of APT presented on the account is enough for the transaction but is lower than minimum Gas units attached to the transaction: use a faucet to get moreAPT Coin
"Error": "Simulation failed with status: Transaction Executed and Committed with Error MAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS"
-
Error<411_LENGTH_REQUIRED>
- it may happen if you use an outdated Aptos CLI version, it was fixed onv0.3.7
"Error": "API error: Faucet issue: 411 Length Required"
-
Error<502_BAD_GATEWAY>
- it happens sometimes, try again"Error": "API error: 502 Bad Gateway"
build/
- dir contains module artifacts
sources/
- dir contains move modules
Move.toml
- configuration file
[package]
section contains
name
identifier - is used when adding the repo as a dependency of another projectversion
- simple semver identifierupgrade_policy
- may beimmutable
- no code updates allowedcompatible
(is default) - new resources and functions may be added but old ones should be kept
[addresses]
section contains named addresses that may be used in code
- Common used
aptos_std = "0x1"
or juststd = "0x1"
- Named address that should be provided as parameter during compilation
NAME = "_"
[dependencies]
section may contain local and global deps
-
Common used
devnet
version ofaptos-framework
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "devnet" }
-
Or just import a local package (may be useful in case of huge project with a lot of modules interacting each other)
LOCAL_PACK = { local = "LOCAL_PATH" }
Module definition is module ADDRESS::MODULE_NAME { ... }
In module there are:
-
Imports:
Imports are defined by the
use ADDRESS::MODULE
pattern and the imported modules/functions/structs may be used through the code -
Structs and Resources:
-
Structs are defined by keyword
struct
and may have typed fieldsStructs may be copyable and droppable like simple variables
Struct may be generated based on generic type
struct NAME<phantom GENERIC>{ ... }
-
Resources are undroppable and uncopyable structs
Resources should be moved to storage or destroyed according to module policy before the transaction ends
It is considered storing resources on user accounts (not in module storage)
-
-
Friends:
Friends are modules whitelisted to run
public(friend)
functionsfriend ADDRESS::MODULE
-
Functions
Functions could be
entry
- callable by user outside from blockchainpublic
- callable by any other modulespublic(friend)
- callable by friend modulesno modifier
- are internal only accessible in the module
Functions could have generic
type argument
fun FUNCTION<GENERIC>(ARGS: TYPES): RETURN_TYPE { CODE_DEPENDS_ON<GENERIC> }
Structs, friends and functions may be marked by #[test_only]
This means the code is applied only for tests and is not accessible on-chain
According to the current implementation of the aptos_std::coin
it is possible for anyone who has access to the signer
object to withdraw any coins stored in the account. In EVM
systems, it is called authorization through tx.origin
and is considered to be a critical issue as any contract (module) which user calls may be confused with the user.
However, it is the expected behavior in the Aptos network, and when a user starts a transaction, the called module gets the signer
object which is the only thing that could be checked for auth.
In such a way, it is important to check contracts (or contract audits at least) before calling them. It needs to be mentioned that contracts may be updated, so the current version should be checked. Generally, a Front-Running attack may be used: contract owner sees a rich user calls the contract and adds harmful code making gas cost extremely higher.
Moreover, all the module dependencies should be checked as the signer
object is transmitted to most of the dependencies.
In EVM
systems, upgrades are also vulnerable but only attached (allowed) deposit may be stolen, whether all funds may be withdrawn in the Aptos network.
Storing funds wrapped by a module like this one is safe because only the owner itself can withdraw funds from there. The withdraw
function of the module is marked public(friends) entry
, and there are no friends specified in the module, so only the owner is able to call the function outside of the network. The contract upgrade policy is defined as immutable
in the Move.toml
config, so it is not possible for the contract maintainer to change the contract code and steal any funds.
- Remove
upgrade_policy = "immutable"
line fromMove.toml
file and deploy the module. - Currently it is be possible to udgrade the module, so uncomment lines in the
sources/coin_storage.move
file located between//==> hack
and//==< hack
. - Update module.
- Now, all the user coins on the
deposit
function call will be transferred to your account!
Clone the repo from GitHub
git clone git@github.com:SteMak/aptos_coin_storage.git
Create accounts and fund it
aptos init
aptos init --profile coin_storage
aptos account fund-with-faucet --account default
aptos account fund-with-faucet --account coin_storage
Update code in coin_storage.move
and tests in coin_storage_test.move
files
Compile the module
aptos move compile --named-addresses coin_storage=coin_storage
Check that tests are ok
aptos move test --named-addresses coin_storage=coin_storage
Deploy the module on-chain
aptos move publish --named-addresses coin_storage=coin_storage
Try do some deposits and withdrawals
aptos move run \
--function-id 'default::coin_storage::deposit' \
--type-args '0x1::aptos_coin::AptosCoin' \
--args 'u64:100'
aptos move run \
--function-id 'default::coin_storage::withdraw' \
--type-args '0x1::aptos_coin::AptosCoin' \
--args 'u64:77'
Check your account resources in explorer
Deploy MoonCoin
according the tutorial and check interactions
aptos move run \
--function-id 'default::coin_storage::deposit' \
--type-args 'moon_coin_address::moon_coin::MoonCoin' \
--args 'u64:30'
Module CoinStorage
should be have
- immutable upgrade policy
- deployable on any address
It should be implemented a mechanism of depositing/withdrawing of any standard coin
It should be possible for anyone who manages user's signer
object to deposit coins
It should not be possible for anyone except of the user directly to withdraw user funds
Accepts user deposit, creates wrapper resource moving it to caller account
Signature:
<CoinType>
:resource
- resource of coin which will be depositedaccount
:&signer
- link to caller signer objectamount
:u64
- amount of coins to deposit
Fail conditions:
NotFound(ECOIN_STORE_NOT_PUBLISHED)
- user is not registred in the coin modulePermissionDenied(EFROZEN)
- user coin account is frozenInvalidArgument(EINSUFFICIENT_BALANCE)
- user don't have enough funds
Return: void
Transfer user deposit back, is callable only by user itself
Signature:
<CoinType>
:resource
- resource of coin which will be withdrawnaccount
:&signer
- link to caller signer objectamount
:u64
- amount of coins to withdraw
Fail conditions:
NotFound(E_USER_IS_NOT_FOUND)
- user is not registred in the storageInvalidArgument(E_USER_INSUFFICIENT_BALANCE)
- user deposit is too smallPermissionDenied(EFROZEN)
- user coin account is frozen
Return: void
Return current user balance
Signature:
<CoinType>
:resource
- resource of coin which will be checkedaccount_addr
:address
- address of user checked
Fail conditions: void
Return: u64
- stored balance