Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[move-examples] Add multiple examples for resource accounts #8621

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aptos-move/e2e-move-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ mod token_event_store;
mod token_objects;
mod transaction_fee;
mod type_too_large;
mod upgradeable_resource_account_package;
mod vector_numeric_address;
mod vote;
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

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_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_account_package".to_string(), resource_address);

let mut package_builder =
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);
package_builder.add_local_dep("AptosFramework", &common::framework_dir_path("aptos-framework").to_string_lossy());
let pack_dir = package_builder.write_to_temp().unwrap();
let package = aptos_framework::BuiltPackage::build(
pack_dir.path().to_owned(),
build_options,
)
.expect("building package must succeed");

let code = package.extract_code();
let metadata = package
.extract_metadata()
.expect("extracting package metadata must succeed");

(metadata, code)
}

#[test]
fn code_upgrading_using_resource_account() {
let mut h = MoveHarness::new();

let deployer = h.new_account_at(AccountAddress::from_hex_literal("0xcafe").unwrap());
let resource_address = create_resource_address(*deployer.address(), &[]);

// get contract code from file
let package_manager_code =
std::fs::read_to_string(
&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_account_package/sources/basic_contract.move")
).unwrap();

let (metadata, code) = custom_build_helper(
*deployer.address(),
resource_address,
&package_manager_code,
&basic_contract_code
);

// create the resource account and publish the module under the resource account's address
assert_success!(h.run_transaction_payload(
&deployer,
aptos_cached_packages::aptos_stdlib::resource_account_create_resource_account_and_publish_package(
vec![],
bcs::to_bytes(&metadata).expect("PackageMetadata has BCS"),
code.clone(),
),
));

// run the view function and check the result
let bcs_result = h.execute_view_function(
str::parse(&format!(
"0x{}::basic_contract::upgradeable_function",
resource_address
)).unwrap(),
vec![],
vec![],
).unwrap().pop().unwrap();
let result = bcs::from_bytes::<u64>(&bcs_result).unwrap();

const BEFORE_VALUE: u64 = 9000;
const AFTER_VALUE: u64 = 9001;
// run the view function and check the result
assert_eq!(BEFORE_VALUE, result, "assert view function result {} == {}", result, BEFORE_VALUE);

let (metadata, code) = custom_build_helper(
*deployer.address(),
resource_address,
&package_manager_code,
&basic_contract_code.replace(&BEFORE_VALUE.to_string(), &AFTER_VALUE.to_string())
);
// test upgrading the code
assert_success!(h.run_entry_function(
&deployer,
str::parse(&format!(
"0x{}::package_manager::publish_package",
resource_address
)).unwrap(),
vec![],
vec![
bcs::to_bytes(&bcs::to_bytes(&metadata).unwrap()).unwrap(),
bcs::to_bytes(&code).unwrap(),
],
));

// run the view function and check the result
let bcs_result = h.execute_view_function(
str::parse(&format!(
"0x{}::basic_contract::upgradeable_function",
resource_address
)).unwrap(),
vec![],
vec![],
).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
@@ -0,0 +1,79 @@
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;

/// Stores permission config such as SignerCapability for controlling the resource account.
struct PermissionConfig has key {
/// Required to obtain the resource account signer.
signer_cap: SignerCapability,
/// Track the addresses created by the modules in this package.
addresses: SmartTable<String, address>,
}

/// Initialize PermissionConfig to establish control over the resource account.
/// This function is invoked only when this package is deployed the first time.
fun init_module(resource_signer: &signer) {
let signer_cap = resource_account::retrieve_resource_account_cap(resource_signer, @deployer);
move_to(resource_signer, PermissionConfig {
addresses: smart_table::new<String, address>(),
signer_cap,
});
}

public entry fun publish_package(
deployer: &signer,
package_metadata: vector<u8>,
code: vector<vector<u8>>,
) acquires PermissionConfig {
assert!(signer::address_of(deployer) == @deployer, error::permission_denied(ENOT_AUTHORIZED));
code::publish_package_txn(&get_signer(), package_metadata, code);
}

/// 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_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_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 named_address_exists(name: String): bool acquires PermissionConfig {
smart_table::contains(&safe_permission_config().addresses, name)
}

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_account_package)
}

#[test_only]
public fun initialize_for_test(deployer: &signer) {
let deployer_addr = std::signer::address_of(deployer);
if (!exists<PermissionConfig>(deployer_addr)) {
aptos_framework::timestamp::set_time_has_started_for_testing(&account::create_signer_for_test(@0x1));

account::create_account_for_test(deployer_addr);
move_to(deployer, PermissionConfig {
addresses: smart_table::new<String, address>(),
signer_cap: account::create_test_signer_cap(deployer_addr),
});
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"function_id": "f409bfe5ffffce1834d4f6045985c6ce9178380337f4cf3d7964e09115137e81::package_manager::publish_package",
"type_args": [],
"args": [
{
"type": "hex",
"value": "0x285570677261646561626c65204d6f64756c652057697468205265736f75726365204163636f756e740100000000000000004045463342424543333046313937354134464542394231314335394242453043314439354231424541373838384139343338314241383033334235433037393633cb011f8b08000000000002ff4d8e410ec2201045f7730ac2deaa0770e1c69d1b13e3a231648451899421d0aa8df1ee42db34061202ccffefd501f5036f74068f0d898d90c7708b68082f8ec49e4d978f936defe24089bba8496cb5e6ceb7129e1493655f42ab2a2f09dd9855819dd57df9d0dc046c6d2e9300351a1329254a67c0d07252d798a92f8e8fa1e4bd96602838ee2996073537161b15270385a3819adca751a87396bc21af6d216c0b61f707f808c71a5d19afaa65de337d39d82ce6bb145ff801354bc5571a010000020f7061636b6167655f6d616e61676572ac081f8b08000000000002ffad56db8edb36107dcf574c50c0900a6337058aa2d05eb0c53640f3d21459f7a5454150d2c8662d890a49add709fcef1992bacb4e9c4dfc625b9adb3967389c42a6758e50576bc553e4718e4ca196b54a90f12491756958c5932d5f6314353f58c14bfa52f0f105d0a7d608bc3252b34cf10277526da3a8f18da28f0f98674b7810eb12d53daf782c7261f687abd3bed302a6a6daa451a40bae0c33b6e23e897db6b28f06e1bdb551a25c47d183fb3e1a3091294ebc5029a9a6911c10ff305302cbf44cf262ae45c212591ac513c2e4225c5e5ec26a43a15d54101a4a6980d7662395f8802918092956b9dc83d9d0dbc2c975e17c299436f0facfb72bf6dbdfab3fdebe7bf3cfebdf23a87ff9196ee0d520c18391541654a80aa1b590a575cdc41a749d6c80eb9938904905ae5299e7c417e54668914183cc1741c4d68981bfbad8f73ef486c26e71dfb4485bc93b7c5f0be561c9d870511e0dddd071d1f9faff2ce155342b7639cab02272b72e284f538aab0978a2901b4a1aefdd0bcfa106979c386d14eab3759ed1a0a3ae7deb2cdbb7b73eefa1a7f94d298ce039c936a783f0a2b6cd2af4a66516e423497e9a5adf1b5460569789b1b2095bf4a3dc121659e67bd86d708cc15af876b11c53e44c28ea11238a061e85a210c2304f42d0b5ab67388285ff110e84cbd10c04a0de9af6b83db1440e3e1e697ff2982659c25d53a30aafba2c05b1c18c9c1bcfb8ec2b9b88351a0925ee669205e172e4dba3ea9f1f9a9a1a61ab9a344b0049b1bd63cf3dd09bf65c079d638ba9e3b08fd9cd4d343ce58647f088091dcaebfad7dbdeca0ea0ee4d6fd05884d41ceef0e8cf31c28909655e068d9c51839cc92ce838879b9b5e8125b82147b3bd0bca522c05a6c164b28403b15ca9d1840a669eca60b146d348476ccf902f9deb9862dbe7f7bc841821e179ee0faa1fadf4bb3dad5f3131bc66810f113ad5865545edb43d87d059f32f624984edd83a9731cfafa7aeb7c1dd39d74178d107ed69edce939f584dc56c27ccc61a36032fe85dc367f1b845acc0b8412933e0a0f7da60d19e92931cd27b56d2259db2c632b0ff684636a74cc6ff53d3466d9cf06c7efb494df416b58111c58c9e3c9fe62e76cff2684cd0fba0b3598245d422393a082c112312183e096dc65c508bc59206fc39048caab13703b5b80e169a67c80667d2dfd8c100902f363c51a36df8d362859d4acf13e93b9d8123e2fc38e2c3e7093e875994b4a1a0c37c8a339ac83370e7c0fe3e2887c5fef0afa13580d9cbfbbfa962a25b1f18ad5fcc1a06b33b657a2fb7064e655266b0a21e1ffe3dd32283e0a56fde23d84681c3707ae94e5776bb61d07e5354949d3acffe65b402d2664d6a5213b688a8f782c58931d7a1be7bf5f493bd6dc629274e2dcd33ae7cc55723e776b9e86fbd2f6c15dfba594c97d669f5ae0d7a8349f1e358870198433b930e2f3e01d480aa05ba0d000000000e62617369635f636f6e7472616374e0031f8b08000000000002ff8d52df6bdb400c7ecf5fa131e86c084d36ca602e8115dab1bd2cd0750fdb18d78b4f718eda27ef7ea4cb4afef729e7b317672f3d30be93f4499f3ea921156a84d056562a94ab1a854547c19628645952305eb4b27c901516c54a3a5d8a928cb7b2f4f034013ec13d179e2ea291867ff672803baf8a02ada5539bd395390446abf33670d52fd4e06daa011be9e0017789cae16c651db080f0f6621a6dfb0e3c9bcde01b059016c1900719fc86acfe830a3c418b764db601bfd10eb8354de63cc2b857e7e1e6f3f24e5c7dbdfbb8bcfdf4fde63a668705cc13b1973fb61a1f7fc67b1b56b52e611dcc48147ec7ac59de81fff17d379fbf1e13852b03f85b362dcf85d6a0489b0a1c77cdecf8f6a8fd868922f44243129a8dd2b3f557d0ec02ed1d74fa1d13439edd2ed26b688bc2d37ff3ca14b635edd01670d6e1f323ba4c6f69ea5d24d00742290d7f75dde9d7f77a3e80a47368fd8bac4b57145229aeea04ad8762392c16f0be7f4d216e03af0cda463bc7d98442a3516527b3c8f3348444ee9a9e23d5ab913409fa816caffb142407c409dc279dee6387437c8d7ec82aba5cbc11271b5e1415fae4cdf2cb019c526683e170ce4ed24d47ded1d63f8d5c475b7ff1668cda0faf547d3fd94ffe02f152d31bf303000000000300000000000000000000000000000000000000000000000000000000000000010e4170746f734672616d65776f726b00000000000000000000000000000000000000000000000000000000000000010b4170746f735374646c696200000000000000000000000000000000000000000000000000000000000000010a4d6f76655374646c696200"
},
{
"type": "hex",
"value": [
"0xa11ceb0b060000000d010010021014032453047708057f5707d6018b0308e1044006a1054e10ef05630ad2060d0cdf0692010df107040ff507020001010201030104010501060107010800090800070a0700011206000614040200000000000b000100000c020300000d010400000e050100000f0206000010070100061508010200000616090a02020001170b040004180d0e000619010f020704061a0906020200051b050300031c101000021d070100060007000a000b0002080105000108010105010c01060c010103060c0a020a0a0203070b0302090009010900090102060b03020900090109000106090101060802040b03020801050802060c080202060c05010802010b03020900090101030e62617369635f636f6e74726163740f7061636b6167655f6d616e61676572076163636f756e7404636f6465056572726f72107265736f757263655f6163636f756e74067369676e65720b736d6172745f7461626c6506737472696e67105065726d697373696f6e436f6e66696706537472696e67116164645f6e616d65645f61646472657373116765745f6e616d65645f616464726573730a6765745f7369676e65720b696e69745f6d6f64756c65146e616d65645f616464726573735f6578697374730f7075626c6973685f7061636b6167650a7369676e65725f636170105369676e65724361706162696c697479096164647265737365730a536d6172745461626c650361646406626f72726f771d6372656174655f7369676e65725f776974685f6361706162696c6974791d72657472696576655f7265736f757263655f6163636f756e745f636170036e657708636f6e7461696e730a616464726573735f6f66117065726d697373696f6e5f64656e696564137075626c6973685f7061636b6167655f74786ef409bfe5ffffce1834d4f6045985c6ce9178380337f4cf3d7964e09115137e810000000000000000000000000000000000000000000000000000000000000001030800000000000000000520f409bfe5ffffce1834d4f6045985c6ce9178380337f4cf3d7964e09115137e8105206fc8d6b07117b68c1cca1f276d25f5287371d012c3018f248d86b950a51da25e126170746f733a3a6d657461646174615f76314f0100000000000000000f454e4f545f415554484f52495a454433546865207369676e6572206973206e6f7420617574686f72697a656420746f206465706c6f792074686973206d6f64756c652e0000000202110802130b03020801050003000100010707012a000f000b000b013800020101000100010707012b0010000b00380114020203000100010507012b001001110802030000000c100a00070211090c040b000c0338020c010b040c020b030b020b0112002d00020401000100010607012b0010000b00380302050104010004100b00110c070221040605090700110d2711020c030e030b010b02110e0200010000000000",
"0xa11ceb0b060000000a010008020804030c1905250a072f950108c401400684022c10b002760aa603050cab033a0000010101020003000408000005000100000601020002080004000109020200030a01030001060c000103010c01050e62617369635f636f6e7472616374056572726f72067369676e65720f7061636b6167655f6d616e616765720c536f6d655265736f75726365186d6f76655f746f5f7265736f757263655f6163636f756e74147570677261646561626c655f66756e6374696f6e0576616c75650a616464726573735f6f66117065726d697373696f6e5f64656e6965640a6765745f7369676e6572f409bfe5ffffce1834d4f6045985c6ce9178380337f4cf3d7964e09115137e8100000000000000000000000000000000000000000000000000000000000000010308000000000000000005206fc8d6b07117b68c1cca1f276d25f5287371d012c3018f248d86b950a51da25e126170746f733a3a6d657461646174615f7631620100000000000000000f454e4f545f415554484f52495a45442e596f7520617265206e6f7420617574686f72697a656420746f20706572666f726d207468697320616374696f6e2e0001147570677261646561626c655f66756e6374696f6e01010000020107030001040003100b00110207012104060509070011032711040c010e01062a0000000000000012002d00020101000001020629230000000000000200"
]
}
]
}
Loading