Skip to content

Commit

Permalink
Finishing the resource account tutorial with kevin's package manager,…
Browse files Browse the repository at this point in the history
… explanation of it and features, and separating the guide into 3 sections. Updated unit test.
  • Loading branch information
xbtmatt committed Jul 25, 2023
1 parent e53e354 commit 451263c
Show file tree
Hide file tree
Showing 13 changed files with 313 additions and 234 deletions.
2 changes: 1 addition & 1 deletion aptos-move/e2e-move-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ mod token_event_store;
mod token_objects;
mod transaction_fee;
mod type_too_large;
mod upgradeable_resource_contract;
mod upgradeable_resource_account_package;
mod vector_numeric_address;
mod vote;
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,31 @@ use crate::{assert_success, tests::common, MoveHarness};
use aptos_package_builder::PackageBuilder;
use aptos_types::account_address::{create_resource_address, AccountAddress};
use aptos_framework::natives::code::{PackageMetadata, UpgradePolicy};
use move_core_types::parser::parse_struct_tag;
use serde::Deserialize;

#[derive(Debug, Deserialize, Eq, PartialEq)]
struct SomeResource {
value: u64,
}

fn custom_build_helper(
deployer_address: AccountAddress,
resource_address: AccountAddress,
package_manager_code: &String,
basic_contract_code: &String,
) -> (PackageMetadata, Vec<Vec<u8>>) {
// add the named addresses for `deployer` and `upgradeable_resource_contract`
// add the named addresses for `deployer` and `upgradeable_resource_account_package`
let mut build_options = aptos_framework::BuildOptions::default();
build_options
.named_addresses
.insert("deployer".to_string(), deployer_address);
build_options
.named_addresses
.insert("upgradeable_resource_contract".to_string(), resource_address);
.insert("upgradeable_resource_account_package".to_string(), resource_address);

let mut package_builder =
PackageBuilder::new("Upgradeable Resource Account Contract")
PackageBuilder::new("Upgradeable Module With Resource Account")
.with_policy(UpgradePolicy::compat());
package_builder.add_source("package_manager", &package_manager_code);
package_builder.add_source("basic_contract", &basic_contract_code);
Expand All @@ -49,23 +56,14 @@ fn code_upgrading_using_resource_account() {
let deployer = h.new_account_at(AccountAddress::from_hex_literal("0xcafe").unwrap());
let resource_address = create_resource_address(*deployer.address(), &[]);

// add the named addresses for `deployer` and `upgradeable_resource_contract`
let mut build_options = aptos_framework::BuildOptions::default();
build_options
.named_addresses
.insert("deployer".to_string(), *deployer.address());
build_options
.named_addresses
.insert("upgradeable_resource_contract".to_string(), resource_address);

// get contract code from file
let package_manager_code =
std::fs::read_to_string(
&common::test_dir_path("../../../move-examples/upgradeable_resource_contract/sources/package_manager.move")
&common::test_dir_path("../../../move-examples/upgradeable_resource_account_package/sources/package_manager.move")
).unwrap();
let basic_contract_code =
std::fs::read_to_string(
&common::test_dir_path("../../../move-examples/upgradeable_resource_contract/sources/basic_contract.move")
&common::test_dir_path("../../../move-examples/upgradeable_resource_account_package/sources/basic_contract.move")
).unwrap();

let (metadata, code) = custom_build_helper(
Expand Down Expand Up @@ -132,4 +130,25 @@ fn code_upgrading_using_resource_account() {
).unwrap().pop().unwrap();
let result = bcs::from_bytes::<u64>(&bcs_result).unwrap();
assert_eq!(AFTER_VALUE, result, "assert view function result {} == {}", result, AFTER_VALUE);

// test the `move_to_rseource_account(...)` function by moving SomeResource into the resource
// account
assert_success!(h.run_entry_function(
&deployer,
str::parse(&format!(
"0x{}::basic_contract::move_to_resource_account",
resource_address
)).unwrap(),
vec![],
vec![],
));

let some_resource = parse_struct_tag(&format!(
"0x{}::basic_contract::SomeResource",
resource_address
)).unwrap();
let some_resource_value = h
.read_resource::<SomeResource>(&resource_address, some_resource)
.unwrap();
assert_eq!(some_resource_value.value, 42, "assert SomeResource.value == 42");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "Upgradeable Module With Resource Account"
version = "0.0.0"
upgrade_policy = "compatible"

[addresses]
aptos_framework = "0x1"
deployer = "_"
upgradeable_resource_account_package = "_"

[dependencies]
AptosFramework = { local = "../../framework/aptos-framework" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module upgradeable_resource_account_package::basic_contract {
use upgradeable_resource_account_package::package_manager;
use std::error;
use std::signer;

struct SomeResource has key {
value: u64,
}

/// You are not authorized to perform this action.
const ENOT_AUTHORIZED: u64 = 0;

#[view]
public fun upgradeable_function(): u64 {
9000
}

// An example of doing something with the resource account that requires its signer
public entry fun move_to_resource_account(deployer: &signer) {
// Only the deployer can call this function.
assert!(signer::address_of(deployer) == @deployer, error::permission_denied(ENOT_AUTHORIZED));

// Do something with the resource account's signer
// For example, a simple `move_to` call
let resource_signer = package_manager::get_signer();
move_to(
&resource_signer,
SomeResource {
value: 42,
}
);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module upgradeable_resource_contract::package_manager {
module upgradeable_resource_account_package::package_manager {
use aptos_framework::account::{Self, SignerCapability};
use aptos_framework::resource_account;
use aptos_std::smart_table::{Self, SmartTable};
use std::string::String;
use aptos_std::code;
use std::error;
use std::signer;
friend upgradeable_resource_account_package::basic_contract;

/// The signer is not authorized to deploy this module.
const ENOT_AUTHORIZED: u64 = 0;
Expand Down Expand Up @@ -39,27 +40,27 @@ module upgradeable_resource_contract::package_manager {

/// Can be called by friended modules to obtain the resource account signer.
public(friend) fun get_signer(): signer acquires PermissionConfig {
let signer_cap = &borrow_global<PermissionConfig>(@upgradeable_resource_contract).signer_cap;
let signer_cap = &borrow_global<PermissionConfig>(@upgradeable_resource_account_package).signer_cap;
account::create_signer_with_capability(signer_cap)
}

/// Can be called by friended modules to keep track of a system address.
public(friend) fun add_address(name: String, object: address) acquires PermissionConfig {
let addresses = &mut borrow_global_mut<PermissionConfig>(@upgradeable_resource_contract).addresses;
public(friend) fun add_named_address(name: String, object: address) acquires PermissionConfig {
let addresses = &mut borrow_global_mut<PermissionConfig>(@upgradeable_resource_account_package).addresses;
smart_table::add(addresses, name, object);
}

public fun address_exists(name: String): bool acquires PermissionConfig {
public fun named_address_exists(name: String): bool acquires PermissionConfig {
smart_table::contains(&safe_permission_config().addresses, name)
}

public fun get_address(name: String): address acquires PermissionConfig {
let addresses = &borrow_global<PermissionConfig>(@upgradeable_resource_contract).addresses;
public fun get_named_address(name: String): address acquires PermissionConfig {
let addresses = &borrow_global<PermissionConfig>(@upgradeable_resource_account_package).addresses;
*smart_table::borrow(addresses, name)
}

inline fun safe_permission_config(): &PermissionConfig acquires PermissionConfig {
borrow_global<PermissionConfig>(@upgradeable_resource_contract)
borrow_global<PermissionConfig>(@upgradeable_resource_account_package)
}

#[test_only]
Expand Down
12 changes: 0 additions & 12 deletions aptos-move/move-examples/upgradeable_resource_contract/Move.toml

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: "Conceptual understanding"
id: "understanding-resource-accounts"
title: "Common questions"
id: "common-questions"
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Conceptual understanding
# Common questions

## What is a resource account?

Expand Down Expand Up @@ -102,7 +102,7 @@ You might be wondering "*Why does this work? Isn't it dangerous to be able to cr
Move's [privileged struct operations](../../move/book/structs-and-resources#privileged-struct-operations) require that creating structs and accessing their inner fields can only occur from within the module that defines the struct. This means that unless the developer provides a public accessor function to a stored `SignerCapability`, there is no way for another account to gain access to it.

:::warning
Be mindful of properly gating access to a function that uses a `SignerCapability` and be extra careful when returning it from a function, since this gives the caller unrestricted access to control the account.
Be mindful of properly gating access to a function that uses a `SignerCapability` and be extra careful when returning a `signer` from a public function, since this gives the caller unrestricted access to control the account.
:::

A good rule of thumb is to by default set all functions that return a `SignerCapability` or a `signer` to internal private functions unless you've very carefully thought about the implications.
Expand Down
5 changes: 3 additions & 2 deletions developer-docs-site/docs/guides/resource-accounts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
title: "Resource Accounts"
---

# Examples of the various ways to use resource accounts
# Resource Accounts

- ### [Utilizing resource accounts](./utilizing-resource-accounts)
- ### [Understanding resource accounts](./understanding-resource-accounts)
- ### [Publishing an upgradeable module](./publishing-an-upgradeable-module)
- ### [Common questions](./common-questions)
Loading

0 comments on commit 451263c

Please sign in to comment.