diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index d3cb8f47..a5ea5bc1 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - main + - genesis_dao jobs: build-and-test: diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index 9c75150e..42d78ef9 100644 --- a/build/StarcoinFramework/BuildInfo.yaml +++ b/build/StarcoinFramework/BuildInfo.yaml @@ -45,6 +45,9 @@ compiled_package_info: ? address: "0x00000000000000000000000000000001" name: Config : StarcoinFramework + ? address: "0x00000000000000000000000000000001" + name: ConfigProposalPlugin + : StarcoinFramework ? address: "0x00000000000000000000000000000001" name: ConsensusConfig : StarcoinFramework @@ -207,6 +210,9 @@ compiled_package_info: ? address: "0x00000000000000000000000000000001" name: STCUSDOracle : StarcoinFramework + ? address: "0x00000000000000000000000000000001" + name: SalaryGovPlugin + : StarcoinFramework ? address: "0x00000000000000000000000000000001" name: SharedEd25519PublicKey : StarcoinFramework @@ -291,7 +297,7 @@ compiled_package_info: ? address: "0x00000000000000000000000000000001" name: YieldFarmingV2 : StarcoinFramework - source_digest: 37973FE3F7BCD58FFE2521CE3319C0ED239522F2B0DDE5A5F32751C9C324DFF2 + source_digest: 7F51997501DC9F3AFC1EA8C06C8025E33EA666DF2E3F15C374AF7C7555F061D5 build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/bytecode_modules/DaoAccount.mv b/build/StarcoinFramework/bytecode_modules/DaoAccount.mv index 5c9c0f46..12f1b495 100644 Binary files a/build/StarcoinFramework/bytecode_modules/DaoAccount.mv and b/build/StarcoinFramework/bytecode_modules/DaoAccount.mv differ diff --git a/build/StarcoinFramework/bytecode_modules/GenesisDao.mv b/build/StarcoinFramework/bytecode_modules/GenesisDao.mv index 74ed0653..77fcdc3b 100644 Binary files a/build/StarcoinFramework/bytecode_modules/GenesisDao.mv and b/build/StarcoinFramework/bytecode_modules/GenesisDao.mv differ diff --git a/build/StarcoinFramework/docs/DaoAccount.md b/build/StarcoinFramework/docs/DaoAccount.md index 98cdef61..e0e96aed 100644 --- a/build/StarcoinFramework/docs/DaoAccount.md +++ b/build/StarcoinFramework/docs/DaoAccount.md @@ -11,7 +11,9 @@ - [Function `create_account`](#0x1_DaoAccount_create_account) - [Function `create_account_entry`](#0x1_DaoAccount_create_account_entry) - [Function `extract_dao_account_cap`](#0x1_DaoAccount_extract_dao_account_cap) +- [Function `restore_dao_account_cap`](#0x1_DaoAccount_restore_dao_account_cap) - [Function `upgrade_to_dao`](#0x1_DaoAccount_upgrade_to_dao) +- [Function `upgrade_to_dao_with_signer_cap`](#0x1_DaoAccount_upgrade_to_dao_with_signer_cap) - [Function `dao_signer`](#0x1_DaoAccount_dao_signer) - [Function `submit_upgrade_plan`](#0x1_DaoAccount_submit_upgrade_plan) - [Function `submit_upgrade_plan_entry`](#0x1_DaoAccount_submit_upgrade_plan_entry) @@ -19,10 +21,12 @@
use 0x1::Account;
+use 0x1::Config;
 use 0x1::Errors;
 use 0x1::Option;
 use 0x1::PackageTxnManager;
 use 0x1::Signer;
+use 0x1::Version;
 
@@ -55,6 +59,12 @@ DaoAccount
+
+
+upgrade_plan_cap: PackageTxnManager::UpgradePlanCapability +
+
+
@@ -121,17 +131,8 @@ Dao Account is a delegate account, the creator has the public fun create_account(creator: &signer): DaoAccountCap { - let (dao_address, signer_cap) = Account::create_delegate_account(creator); - let dao_signer = Account::create_signer_with_cap(&signer_cap); - - PackageTxnManager::update_module_upgrade_strategy(&dao_signer, PackageTxnManager::get_strategy_two_phase(), Option::some(0)); - move_to(&dao_signer, DaoAccount{ - dao_address, - signer_cap: signer_cap, - }); - DaoAccountCap{ - dao_address - } + let (_dao_address, signer_cap) = Account::create_delegate_account(creator); + upgrade_to_dao_with_signer_cap(signer_cap) } @@ -169,6 +170,7 @@ Entry function for create dao account, the extract_dao_account_cap(sender: &signer): DaoAccount::DaoAccountCap @@ -189,6 +191,31 @@ Entry function for create dao account, the + +## Function `restore_dao_account_cap` + +Restore the DaoAccountCap to the sender + + +
public fun restore_dao_account_cap(sender: &signer, cap: DaoAccount::DaoAccountCap)
+
+ + + +
+Implementation + + +
public fun restore_dao_account_cap(sender: &signer, cap: DaoAccountCap) {
+    move_to(sender, cap)
+}
+
+ + +
@@ -208,16 +235,49 @@ Upgrade sender account to Dao account
public fun upgrade_to_dao(sender: signer): DaoAccountCap {
-    //TODO assert sender not Dao
     let signer_cap = Account::remove_signer_capability(&sender);
-    //TODO check the account upgrade_strategy
-    PackageTxnManager::update_module_upgrade_strategy(&sender, PackageTxnManager::get_strategy_two_phase(), Option::some(0));
-    let dao_address = Signer::address_of(&sender);
-    move_to(&sender, DaoAccount{
+    upgrade_to_dao_with_signer_cap(signer_cap)
+}
+
+ + + + + + + +## Function `upgrade_to_dao_with_signer_cap` + +Upgrade the account which have the signer_cap to a Dao Account + + +
public fun upgrade_to_dao_with_signer_cap(signer_cap: Account::SignerCapability): DaoAccount::DaoAccountCap
+
+ + + +
+Implementation + + +
public fun upgrade_to_dao_with_signer_cap(signer_cap: SignerCapability): DaoAccountCap {
+   let dao_signer = Account::create_signer_with_cap(&signer_cap);
+   let dao_address = Signer::address_of(&dao_signer);
+
+    let upgrade_plan_cap = if(Config::config_exist_by_address<Version::Version>(dao_address)){
+        //TODO if the account has extract the upgrade plan cap
+        PackageTxnManager::extract_submit_upgrade_plan_cap(&dao_signer)
+    }else{
+        Config::publish_new_config<Version::Version>(&dao_signer, Version::new_version(1));
+        PackageTxnManager::update_module_upgrade_strategy(&dao_signer, PackageTxnManager::get_strategy_two_phase(), Option::some(1));
+        PackageTxnManager::extract_submit_upgrade_plan_cap(&dao_signer)
+    };
+    move_to(&dao_signer, DaoAccount{
         dao_address,
-        signer_cap: signer_cap,
+        signer_cap,
+        upgrade_plan_cap,
     });
-    DaoAccountCap{
+     DaoAccountCap{
         dao_address
     }
 }
@@ -271,8 +331,8 @@ This function is a shortcut for create signer with DaoAccountCap and invoke public fun submit_upgrade_plan(cap: &DaoAccountCap, package_hash: vector<u8>, version:u64, enforced: bool) acquires DaoAccount{
-    let dao_signer = dao_signer(cap);
-    PackageTxnManager::submit_upgrade_plan_v2(&dao_signer, package_hash, version, enforced);
+    let upgrade_plan_cap = &borrow_global<DaoAccount>(cap.dao_address).upgrade_plan_cap;
+    PackageTxnManager::submit_upgrade_plan_with_cap_v2(upgrade_plan_cap, package_hash, version, enforced);
 }
 
diff --git a/build/StarcoinFramework/docs/GenesisDao.md b/build/StarcoinFramework/docs/GenesisDao.md index f4b4a59f..6a274960 100644 --- a/build/StarcoinFramework/docs/GenesisDao.md +++ b/build/StarcoinFramework/docs/GenesisDao.md @@ -8,6 +8,7 @@ - [Resource `Dao`](#0x1_GenesisDao_Dao) - [Resource `DaoExt`](#0x1_GenesisDao_DaoExt) - [Struct `DaoConfig`](#0x1_GenesisDao_DaoConfig) +- [Struct `DaoCustomConfig`](#0x1_GenesisDao_DaoCustomConfig) - [Resource `DaoAccountCapHolder`](#0x1_GenesisDao_DaoAccountCapHolder) - [Resource `DaoTokenMintCapHolder`](#0x1_GenesisDao_DaoTokenMintCapHolder) - [Resource `DaoTokenBurnCapHolder`](#0x1_GenesisDao_DaoTokenBurnCapHolder) @@ -15,6 +16,7 @@ - [Resource `DaoNFTBurnCapHolder`](#0x1_GenesisDao_DaoNFTBurnCapHolder) - [Resource `DaoNFTUpdateCapHolder`](#0x1_GenesisDao_DaoNFTUpdateCapHolder) - [Resource `DaoConfigModifyCapHolder`](#0x1_GenesisDao_DaoConfigModifyCapHolder) +- [Resource `DaoCustomConfigModifyCapHolder`](#0x1_GenesisDao_DaoCustomConfigModifyCapHolder) - [Struct `CapType`](#0x1_GenesisDao_CapType) - [Struct `DaoRootCap`](#0x1_GenesisDao_DaoRootCap) - [Struct `DaoInstallPluginCap`](#0x1_GenesisDao_DaoInstallPluginCap) @@ -65,6 +67,7 @@ - [Function `do_remove_member`](#0x1_GenesisDao_do_remove_member) - [Function `increase_member_sbt`](#0x1_GenesisDao_increase_member_sbt) - [Function `decrease_member_sbt`](#0x1_GenesisDao_decrease_member_sbt) +- [Function `query_sbt`](#0x1_GenesisDao_query_sbt) - [Function `is_member`](#0x1_GenesisDao_is_member) - [Function `validate_cap`](#0x1_GenesisDao_validate_cap) - [Function `acquire_install_plugin_cap`](#0x1_GenesisDao_acquire_install_plugin_cap) @@ -104,6 +107,7 @@ - [Function `min_proposal_deposit`](#0x1_GenesisDao_min_proposal_deposit) - [Function `get_config`](#0x1_GenesisDao_get_config) - [Function `modify_dao_config`](#0x1_GenesisDao_modify_dao_config) +- [Function `set_custom_config`](#0x1_GenesisDao_set_custom_config) - [Function `set_voting_delay`](#0x1_GenesisDao_set_voting_delay) - [Function `set_voting_period`](#0x1_GenesisDao_set_voting_period) - [Function `set_voting_quorum_rate`](#0x1_GenesisDao_set_voting_quorum_rate) @@ -260,6 +264,33 @@ Configuration of the DAO. +
+ + + +## Struct `DaoCustomConfig` + + + +
struct DaoCustomConfig<ConfigT> has copy, drop, store
+
+ + + +
+Fields + + +
+
+config: ConfigT +
+
+ +
+
+ +
@@ -449,6 +480,33 @@ Configuration of the DAO. + + + + +## Resource `DaoCustomConfigModifyCapHolder` + + + +
struct DaoCustomConfigModifyCapHolder<DaoT, ConfigT: copy, drop, store> has key
+
+ + + +
+Fields + + +
+
+cap: Config::ModifyConfigCapability<ConfigT> +
+
+ +
+
+ +
@@ -1440,7 +1498,7 @@ Creates a install plugin capability type. Implementation -
public fun install_plugin_cap_type(): CapType { CapType{ code : 0 } }
+
public fun install_plugin_cap_type(): CapType { CapType{ code: 0 } }
 
@@ -1463,7 +1521,7 @@ Creates a upgrade module capability type. Implementation -
public fun upgrade_module_cap_type(): CapType { CapType{ code : 1 } }
+
public fun upgrade_module_cap_type(): CapType { CapType{ code: 1 } }
 
@@ -1486,7 +1544,7 @@ Creates a modify dao config capability type. Implementation -
public fun modify_config_cap_type(): CapType { CapType{ code : 2 } }
+
public fun modify_config_cap_type(): CapType { CapType{ code: 2 } }
 
@@ -1509,7 +1567,7 @@ Creates a withdraw Token capability type. Implementation -
public fun withdraw_token_cap_type(): CapType { CapType{ code : 3 } }
+
public fun withdraw_token_cap_type(): CapType { CapType{ code: 3 } }
 
@@ -1532,7 +1590,7 @@ Creates a withdraw NFT capability type. Implementation -
public fun withdraw_nft_cap_type(): CapType { CapType{ code : 4 } }
+
public fun withdraw_nft_cap_type(): CapType { CapType{ code: 4 } }
 
@@ -1555,7 +1613,7 @@ Creates a write data to Dao account capability type. Implementation -
public fun storage_cap_type(): CapType { CapType{ code : 5 } }
+
public fun storage_cap_type(): CapType { CapType{ code: 5 } }
 
@@ -1579,7 +1637,7 @@ This cap can issue Dao member NFT or update member's SBT Implementation -
public fun member_cap_type(): CapType { CapType{ code : 6 } }
+
public fun member_cap_type(): CapType { CapType{ code: 6 } }
 
@@ -1602,7 +1660,7 @@ Creates a vote capability type. Implementation -
public fun proposal_cap_type(): CapType { CapType{ code : 7 } }
+
public fun proposal_cap_type(): CapType { CapType{ code: 7 } }
 
@@ -1625,7 +1683,7 @@ Creates all capability types. Implementation -
public fun all_caps(): vector<CapType>{
+
public fun all_caps(): vector<CapType> {
     let caps = Vector::singleton(install_plugin_cap_type());
     Vector::push_back(&mut caps, upgrade_module_cap_type());
     Vector::push_back(&mut caps, modify_config_cap_type());
@@ -1738,7 +1796,7 @@ Create a dao with a exists Dao account
 Implementation
 
 
-
public fun upgrade_to_dao<DaoT: store>(sender:signer, name: vector<u8>, ext: DaoT, config: DaoConfig): DaoRootCap<DaoT> {
+
public fun upgrade_to_dao<DaoT: store>(sender: signer, name: vector<u8>, ext: DaoT, config: DaoConfig): DaoRootCap<DaoT> {
     let cap = DaoAccount::upgrade_to_dao(sender);
     create_dao<DaoT>(cap, name, ext, config)
 }
@@ -1764,7 +1822,7 @@ Burn the root cap after init the Dao
 Implementation
 
 
-
public fun burn_root_cap<DaoT>(cap: DaoRootCap<DaoT>){
+
public fun burn_root_cap<DaoT>(cap: DaoRootCap<DaoT>) {
     let DaoRootCap{} = cap;
 }
 
@@ -1789,7 +1847,7 @@ Install ToInstallPluginT to Dao and grant the capabilites Implementation -
public fun install_plugin_with_root_cap<DaoT:store, ToInstallPluginT>(_cap: &DaoRootCap<DaoT>, granted_caps: vector<CapType>) acquires DaoAccountCapHolder{
+
public fun install_plugin_with_root_cap<DaoT: store, ToInstallPluginT>(_cap: &DaoRootCap<DaoT>, granted_caps: vector<CapType>) acquires DaoAccountCapHolder {
     do_install_plugin<DaoT, ToInstallPluginT>(granted_caps);
 }
 
@@ -1814,7 +1872,7 @@ Install plugin with DaoInstallPluginCap Implementation -
public fun install_plugin<DaoT:store, PluginT, ToInstallPluginT>(_cap: &DaoInstallPluginCap<DaoT, PluginT>, granted_caps: vector<CapType>) acquires DaoAccountCapHolder{
+
public fun install_plugin<DaoT: store, PluginT, ToInstallPluginT>(_cap: &DaoInstallPluginCap<DaoT, PluginT>, granted_caps: vector<CapType>) acquires DaoAccountCapHolder {
     do_install_plugin<DaoT, ToInstallPluginT>(granted_caps);
 }
 
@@ -1838,7 +1896,7 @@ Install plugin with DaoInstallPluginCap Implementation -
fun do_install_plugin<DaoT:store, ToInstallPluginT>(granted_caps: vector<CapType>) acquires DaoAccountCapHolder{
+
fun do_install_plugin<DaoT: store, ToInstallPluginT>(granted_caps: vector<CapType>) acquires DaoAccountCapHolder {
     assert_no_repeat(&granted_caps);
     let dao_signer = dao_signer<DaoT>();
     assert!(!exists<InstalledPluginInfo<ToInstallPluginT>>(Signer::address_of(&dao_signer)), Errors::already_published(ERR_PLUGIN_HAS_INSTALLED));
@@ -1868,9 +1926,9 @@ Submit upgrade module plan
 Implementation
 
 
-
public fun submit_upgrade_plan<DaoT: store, PluginT>(_cap: &DaoUpgradeModuleCap<DaoT, PluginT>, package_hash: vector<u8>, version:u64, enforced: bool) acquires DaoAccountCapHolder{
-   let dao_account_cap = &mut borrow_global_mut<DaoAccountCapHolder>(dao_address<DaoT>()).cap;
-   DaoAccount::submit_upgrade_plan(dao_account_cap, package_hash, version, enforced);
+
public fun submit_upgrade_plan<DaoT: store, PluginT>(_cap: &DaoUpgradeModuleCap<DaoT, PluginT>, package_hash: vector<u8>, version: u64, enforced: bool) acquires DaoAccountCapHolder {
+    let dao_account_cap = &mut borrow_global_mut<DaoAccountCapHolder>(dao_address<DaoT>()).cap;
+    DaoAccount::submit_upgrade_plan(dao_account_cap, package_hash, version, enforced);
 }
 
@@ -1894,10 +1952,10 @@ Save the item to the storage Implementation -
public fun save<DaoT:store, PluginT, V: store>(_cap: &DaoStorageCap<DaoT, PluginT>, item: V) acquires DaoAccountCapHolder{
+
public fun save<DaoT: store, PluginT, V: store>(_cap: &DaoStorageCap<DaoT, PluginT>, item: V) acquires DaoAccountCapHolder {
     let dao_signer = dao_signer<DaoT>();
     assert!(!exists<StorageItem<PluginT, V>>(Signer::address_of(&dao_signer)), Errors::already_published(ERR_STORAGE_ERROR));
-    move_to(&dao_signer, StorageItem<PluginT,V>{
+    move_to(&dao_signer, StorageItem<PluginT, V>{
         item
     });
 }
@@ -1923,10 +1981,10 @@ Get the item from the storage
 Implementation
 
 
-
public fun take<DaoT:store, PluginT, V: store>(_cap: &DaoStorageCap<DaoT, PluginT>): V acquires StorageItem{
+
public fun take<DaoT: store, PluginT, V: store>(_cap: &DaoStorageCap<DaoT, PluginT>): V acquires StorageItem {
     let dao_address = dao_address<DaoT>();
-    assert!(exists<StorageItem<PluginT, V>>(dao_address),  Errors::not_published(ERR_STORAGE_ERROR));
-    let StorageItem{item} = move_from<StorageItem<PluginT, V>>(dao_address);
+    assert!(exists<StorageItem<PluginT, V>>(dao_address), Errors::not_published(ERR_STORAGE_ERROR));
+    let StorageItem{ item } = move_from<StorageItem<PluginT, V>>(dao_address);
     item
 }
 
@@ -1951,7 +2009,7 @@ Withdraw the token from the Dao account Implementation -
public fun withdraw_token<DaoT:store, PluginT, TokenT:store>(_cap: &DaoWithdrawTokenCap<DaoT, PluginT>, amount: u128): Token<TokenT> acquires DaoAccountCapHolder{
+
public fun withdraw_token<DaoT: store, PluginT, TokenT: store>(_cap: &DaoWithdrawTokenCap<DaoT, PluginT>, amount: u128): Token<TokenT> acquires DaoAccountCapHolder {
     let dao_signer = dao_signer<DaoT>();
     //we should extract the WithdrawCapability from account, and invoke the withdraw_with_cap ?
     Account::withdraw<TokenT>(&dao_signer, amount)
@@ -1978,7 +2036,7 @@ Withdraw the NFT from the Dao account
 Implementation
 
 
-
public fun withdraw_nft<DaoT:store, PluginT, NFTMeta: store + copy + drop, NFTBody: store>(_cap: &DaoWithdrawNFTCap<DaoT, PluginT>, id: u64): NFT<NFTMeta, NFTBody> acquires DaoAccountCapHolder{
+
public fun withdraw_nft<DaoT: store, PluginT, NFTMeta: store + copy + drop, NFTBody: store>(_cap: &DaoWithdrawNFTCap<DaoT, PluginT>, id: u64): NFT<NFTMeta, NFTBody> acquires DaoAccountCapHolder {
     let dao_signer = dao_signer<DaoT>();
     let nft = NFTGallery::withdraw<NFTMeta, NFTBody>(&dao_signer, id);
     assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_ERROR));
@@ -2006,8 +2064,7 @@ Join Dao and get a membership
 Implementation
 
 
-
public fun join_member<DaoT:store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, to_address: address, init_sbt: u128) acquires DaoNFTMintCapHolder, DaoTokenMintCapHolder, Dao{
-
+
public fun join_member<DaoT: store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, to_address: address, init_sbt: u128) acquires DaoNFTMintCapHolder, DaoTokenMintCapHolder, Dao {
     assert!(!is_member<DaoT>(to_address), Errors::already_published(ERR_NOT_ALREADY_MEMBER));
 
     let member_id = next_member_id<DaoT>();
@@ -2056,7 +2113,7 @@ Member quit Dao by self
 Implementation
 
 
-
public fun quit_member<DaoT: store>(sender: &signer) acquires DaoNFTBurnCapHolder, DaoTokenBurnCapHolder{
+
public fun quit_member<DaoT: store>(sender: &signer) acquires DaoNFTBurnCapHolder, DaoTokenBurnCapHolder {
     let member_addr = Signer::address_of(sender);
     do_remove_member<DaoT>(member_addr);
 }
@@ -2082,7 +2139,7 @@ Revoke membership with cap
 Implementation
 
 
-
public fun revoke_member<DaoT:store,PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, member_addr: address) acquires DaoNFTBurnCapHolder, DaoTokenBurnCapHolder{
+
public fun revoke_member<DaoT: store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, member_addr: address) acquires DaoNFTBurnCapHolder, DaoTokenBurnCapHolder {
     do_remove_member<DaoT>(member_addr);
 }
 
@@ -2106,7 +2163,7 @@ Revoke membership with cap Implementation -
fun do_remove_member<DaoT:store>(member_addr: address) acquires DaoNFTBurnCapHolder, DaoTokenBurnCapHolder{
+
fun do_remove_member<DaoT: store>(member_addr: address) acquires DaoNFTBurnCapHolder, DaoTokenBurnCapHolder {
     assert!(is_member<DaoT>(member_addr), Errors::already_published(ERR_NOT_MEMBER));
     let dao_address = dao_address<DaoT>();
 
@@ -2139,7 +2196,7 @@ Increment the member SBT
 Implementation
 
 
-
public fun increase_member_sbt<DaoT:store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, member_addr: address, amount: u128) acquires DaoNFTUpdateCapHolder, DaoTokenMintCapHolder {
+
public fun increase_member_sbt<DaoT: store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, member_addr: address, amount: u128) acquires DaoNFTUpdateCapHolder, DaoTokenMintCapHolder {
     assert!(is_member<DaoT>(member_addr), Errors::already_published(ERR_NOT_MEMBER));
     let dao_address = dao_address<DaoT>();
 
@@ -2175,7 +2232,7 @@ Decrement the member SBT
 Implementation
 
 
-
public fun decrease_member_sbt<DaoT:store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, member_addr: address, amount: u128) acquires DaoNFTUpdateCapHolder, DaoTokenBurnCapHolder {
+
public fun decrease_member_sbt<DaoT: store, PluginT>(_cap: &DaoMemberCap<DaoT, PluginT>, member_addr: address, amount: u128) acquires DaoNFTUpdateCapHolder, DaoTokenBurnCapHolder {
     assert!(is_member<DaoT>(member_addr), Errors::already_published(ERR_NOT_MEMBER));
     let dao_address = dao_address<DaoT>();
 
@@ -2193,6 +2250,44 @@ Decrement the member SBT
 
 
 
+
+
+
+
+## Function `query_sbt`
+
+Query amount of the member SBT
+
+
+
public fun query_sbt<DaoT: store, PluginT>(member_addr: address): u128
+
+ + + +
+Implementation + + +
public fun query_sbt<DaoT: store, PluginT>(member_addr: address)
+: u128 acquires DaoNFTUpdateCapHolder {
+    assert!(is_member<DaoT>(member_addr), Errors::already_published(ERR_NOT_MEMBER));
+    let dao_address = dao_address<DaoT>();
+
+    let nft_update_cap =
+        &mut borrow_global_mut<DaoNFTUpdateCapHolder<DaoT>>(dao_address).cap;
+    let borrow_nft =
+        IdentifierNFT::borrow_out<DaoMember<DaoT>, DaoMemberBody<DaoT>>(nft_update_cap, member_addr);
+    let nft = IdentifierNFT::borrow_nft(&mut borrow_nft);
+    let body = NFT::borrow_body(nft);
+
+    let result = Token::value(&body.sbt);
+    IdentifierNFT::return_back(borrow_nft);
+    result
+}
+
+ + +
@@ -2211,7 +2306,7 @@ Check the member_addr account is a member of DaoT Implementation -
public fun is_member<DaoT: store>(member_addr: address): bool{
+
public fun is_member<DaoT: store>(member_addr: address): bool {
     IdentifierNFT::owns<DaoMember<DaoT>, DaoMemberBody<DaoT>>(member_addr)
 }
 
@@ -2235,13 +2330,13 @@ Check the member_addr account is a member of DaoT Implementation -
fun validate_cap<DaoT: store, PluginT>(cap: CapType) acquires InstalledPluginInfo{
+
fun validate_cap<DaoT: store, PluginT>(cap: CapType) acquires InstalledPluginInfo {
     let addr = dao_address<DaoT>();
     if (exists<InstalledPluginInfo<PluginT>>(addr)) {
         let plugin_info = borrow_global<InstalledPluginInfo<PluginT>>(addr);
         assert!(Vector::contains(&plugin_info.granted_caps, &cap), Errors::requires_capability(E_NO_GRANTED));
     } else {
-        abort(Errors::requires_capability(E_NO_GRANTED))
+        abort (Errors::requires_capability(E_NO_GRANTED))
     }
 }
 
@@ -2267,7 +2362,7 @@ _witness parameter ensures that the caller is the module which define PluginT Implementation -
public fun acquire_install_plugin_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoInstallPluginCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_install_plugin_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoInstallPluginCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(install_plugin_cap_type());
     DaoInstallPluginCap<DaoT, PluginT>{}
 }
@@ -2294,7 +2389,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_upgrade_module_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoUpgradeModuleCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_upgrade_module_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoUpgradeModuleCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(upgrade_module_cap_type());
     DaoUpgradeModuleCap<DaoT, PluginT>{}
 }
@@ -2321,7 +2416,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_modify_config_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoModifyConfigCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_modify_config_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoModifyConfigCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(modify_config_cap_type());
     DaoModifyConfigCap<DaoT, PluginT>{}
 }
@@ -2348,7 +2443,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_withdraw_token_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoWithdrawTokenCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_withdraw_token_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoWithdrawTokenCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(withdraw_token_cap_type());
     DaoWithdrawTokenCap<DaoT, PluginT>{}
 }
@@ -2375,7 +2470,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_withdraw_nft_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoWithdrawNFTCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_withdraw_nft_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoWithdrawNFTCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(withdraw_nft_cap_type());
     DaoWithdrawNFTCap<DaoT, PluginT>{}
 }
@@ -2402,7 +2497,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_storage_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoStorageCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_storage_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoStorageCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(storage_cap_type());
     DaoStorageCap<DaoT, PluginT>{}
 }
@@ -2429,7 +2524,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_member_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoMemberCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_member_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoMemberCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(member_cap_type());
     DaoMemberCap<DaoT, PluginT>{}
 }
@@ -2456,7 +2551,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun acquire_proposal_cap<DaoT:store, PluginT>(_witness: &PluginT): DaoProposalCap<DaoT, PluginT> acquires InstalledPluginInfo{
+
public fun acquire_proposal_cap<DaoT: store, PluginT>(_witness: &PluginT): DaoProposalCap<DaoT, PluginT> acquires InstalledPluginInfo {
     validate_cap<DaoT, PluginT>(proposal_cap_type());
     DaoProposalCap<DaoT, PluginT>{}
 }
@@ -2481,7 +2576,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
public fun choice_yes(): VotingChoice{VotingChoice{choice: VOTING_CHOICE_YES}}
+
public fun choice_yes(): VotingChoice { VotingChoice{ choice: VOTING_CHOICE_YES } }
 
@@ -2503,7 +2598,7 @@ _witness parameter ensures that the caller is the module which define PluginT Implementation -
public fun choice_no(): VotingChoice{VotingChoice{choice: VOTING_CHOICE_NO}}
+
public fun choice_no(): VotingChoice { VotingChoice{ choice: VOTING_CHOICE_NO } }
 
@@ -2525,7 +2620,7 @@ _witness parameter ensures that the caller is the module which define PluginT Implementation -
public fun choice_no_with_veto(): VotingChoice{VotingChoice{choice: VOTING_CHOICE_NO_WITH_VETO}}
+
public fun choice_no_with_veto(): VotingChoice { VotingChoice{ choice: VOTING_CHOICE_NO_WITH_VETO } }
 
@@ -2547,7 +2642,7 @@ _witness parameter ensures that the caller is the module which define PluginT Implementation -
public fun choice_abstain(): VotingChoice{VotingChoice{choice: VOTING_CHOICE_ABSTAIN}}
+
public fun choice_abstain(): VotingChoice { VotingChoice{ choice: VOTING_CHOICE_ABSTAIN } }
 
@@ -2575,7 +2670,6 @@ _witness parameter ensures that the caller is the module which define PluginT action: ActionT, action_delay: u64, ): u64 acquires GlobalProposals, DaoAccountCapHolder, ProposalActions { - if (action_delay == 0) { action_delay = min_action_delay<DaoT>(); } else { @@ -2591,7 +2685,7 @@ _witness parameter ensures that the caller is the module which define PluginT let start_time = Timestamp::now_milliseconds() + voting_delay<DaoT>(); let quorum_votes = quorum_votes<DaoT>(); - let (block_number,state_root) = block_number_and_state_root(); + let (block_number, state_root) = block_number_and_state_root(); //four choise, so init four length vector. let votes = Vector::singleton(0u128); @@ -2599,7 +2693,7 @@ _witness parameter ensures that the caller is the module which define PluginT Vector::push_back(&mut votes, 0u128); Vector::push_back(&mut votes, 0u128); - let proposal = Proposal { + let proposal = Proposal{ id: proposal_id, proposer, start_time, @@ -2622,11 +2716,11 @@ _witness parameter ensures that the caller is the module which define PluginT let actions = Vector::singleton(proposal_action); //TODO check ProposalActions is exists - if(exists<ProposalActions<ActionT>>(dao_address)){ + if (exists<ProposalActions<ActionT>>(dao_address)) { //TODO add limit to max action before support Table. let current_actions = borrow_global_mut<ProposalActions<ActionT>>(dao_address); Vector::append(&mut current_actions.actions, actions); - }else{ + }else { move_to(&dao_signer, ProposalActions<ActionT>{ actions, }); @@ -2658,7 +2752,7 @@ _witness parameter ensures that the caller is the module which define PluginT Implementation -
fun block_number_and_state_root():(u64, vector<u8>){
+
fun block_number_and_state_root(): (u64, vector<u8>) {
     //TODO how to get state root
     (0, Vector::empty())
 }
@@ -2683,7 +2777,7 @@ _witness parameter ensures that the caller is the module which define PluginT
 Implementation
 
 
-
fun generate_next_proposal_id<DaoT>(): u64{
+
fun generate_next_proposal_id<DaoT>(): u64 {
     //TODO
     0
 }
@@ -2713,17 +2807,17 @@ _witness parameter ensures that the caller is the module which define PluginT
     proposal_id: u64,
     sbt_proof: vector<u8>,
     choice: VotingChoice,
-)  acquires GlobalProposals, MyVotes{
+)  acquires GlobalProposals, MyVotes {
     let dao_address = dao_address<DaoT>();
     let proposals = borrow_global_mut<GlobalProposals>(dao_address);
     let proposal = borrow_proposal_mut(proposals, proposal_id);
 
-    {
-        let state = proposal_state(proposal);
-        // only when proposal is active, use can cast vote.
-        //TODO
-        assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID));
-    };
+        {
+            let state = proposal_state(proposal);
+            // only when proposal is active, use can cast vote.
+            //TODO
+            assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID));
+        };
 
     let sender_addr = Signer::address_of(sender);
 
@@ -2752,7 +2846,6 @@ _witness parameter ensures that the caller is the module which define PluginT
             votes: Vector::singleton(vote),
         });
     };
-
 }
 
@@ -2780,7 +2873,7 @@ Just change vote choice, the weight do not change. _sender: &signer, _proposal_id: u64, _choice: VotingChoice, -){ +) { //TODO }
@@ -2807,7 +2900,7 @@ Just change vote choice, the weight do not change.
public fun revoke_vote<DaoT>(
     _sender: &signer,
     _proposal_id: u64,
-){
+) {
     //TODO
 }
 
@@ -2868,7 +2961,7 @@ Just change vote choice, the weight do not change. Implementation -
fun take_proposal_action<ActionT: store>(dao_address: address, proposal_id: u64): ActionT acquires ProposalActions, GlobalProposals{
+
fun take_proposal_action<ActionT: store>(dao_address: address, proposal_id: u64): ActionT acquires ProposalActions, GlobalProposals {
     let actions = borrow_global_mut<ProposalActions<ActionT>>(dao_address);
     let index_opt = find_action(&actions.actions, proposal_id);
     //TODO error code.
@@ -2878,7 +2971,7 @@ Just change vote choice, the weight do not change.
     let proposal = borrow_proposal(global_proposals, proposal_id);
 
     let index = Option::extract(&mut index_opt);
-    let ProposalAction{ proposal_id:_, deposit, action} = Vector::remove(&mut actions.actions, index);
+    let ProposalAction{ proposal_id: _, deposit, action } = Vector::remove(&mut actions.actions, index);
     //TODO check the proposal state and do deposit or burn.
     Account::deposit(proposal.proposer, deposit);
     action
@@ -2904,12 +2997,12 @@ Just change vote choice, the weight do not change.
 Implementation
 
 
-
fun find_action<ActionT: store>(actions: &vector<ProposalAction<ActionT>>, proposal_id: u64): Option<u64>{
+
fun find_action<ActionT: store>(actions: &vector<ProposalAction<ActionT>>, proposal_id: u64): Option<u64> {
     let i = 0;
     let len = Vector::length(actions);
-    while(i < len){
+    while (i < len) {
         let action = Vector::borrow(actions, i);
-        if(action.proposal_id == proposal_id){
+        if (action.proposal_id == proposal_id) {
             return Option::some(i)
         };
         i = i + 1;
@@ -2937,12 +3030,12 @@ Just change vote choice, the weight do not change.
 Implementation
 
 
-
fun has_voted<DaoT>(sender: address, proposal_id: u64): bool acquires MyVotes{
-    if(exists<MyVotes<DaoT>>(sender)){
+
fun has_voted<DaoT>(sender: address, proposal_id: u64): bool acquires MyVotes {
+    if (exists<MyVotes<DaoT>>(sender)) {
         let my_votes = borrow_global<MyVotes<DaoT>>(sender);
         let vote = get_vote<DaoT>(my_votes, proposal_id);
         Option::is_some(vote)
-    }else{
+    }else {
         false
     }
 }
@@ -2967,7 +3060,7 @@ Just change vote choice, the weight do not change.
 Implementation
 
 
-
fun do_cast_vote(proposal: &mut Proposal, vote: &mut Vote){
+
fun do_cast_vote(proposal: &mut Proposal, vote: &mut Vote) {
     let weight = *Vector::borrow(&proposal.votes, (vote.choice as u64));
     let total_weight = Vector::borrow_mut(&mut proposal.votes, (vote.choice as u64));
     *total_weight = weight + vote.weight;
@@ -2993,7 +3086,7 @@ Just change vote choice, the weight do not change.
 Implementation
 
 
-
fun get_vote<DaoT>(_my_votes: &MyVotes<DaoT>, _proposal_id: u64):&Option<Vote>{
+
fun get_vote<DaoT>(_my_votes: &MyVotes<DaoT>, _proposal_id: u64): &Option<Vote> {
     //TODO
     abort 0
 }
@@ -3018,7 +3111,7 @@ Just change vote choice, the weight do not change.
 Implementation
 
 
-
public fun proposal_state(_proposal: &Proposal):u8 {
+
public fun proposal_state(_proposal: &Proposal): u8 {
     //TOOD
     0
 }
@@ -3043,7 +3136,7 @@ Just change vote choice, the weight do not change.
 Implementation
 
 
-
fun borrow_proposal_mut(_proposals: &mut GlobalProposals, _proposal_id: u64): &mut Proposal{
+
fun borrow_proposal_mut(_proposals: &mut GlobalProposals, _proposal_id: u64): &mut Proposal {
     //TODO
     abort 0
 }
@@ -3071,9 +3164,9 @@ Just change vote choice, the weight do not change.
 
fun borrow_proposal(proposals: &GlobalProposals, proposal_id: u64): &Proposal {
     let i = 0;
     let len = Vector::length(&proposals.proposals);
-    while(i < len){
+    while (i < len) {
         let proposal = Vector::borrow(&proposals.proposals, i);
-        if(proposal.id == proposal_id){
+        if (proposal.id == proposal_id) {
             return proposal
         };
         i = i + 1;
@@ -3103,7 +3196,7 @@ Return a copy of Proposal
 Implementation
 
 
-
public fun proposal<DaoT>(proposal_id: u64): Proposal acquires GlobalProposals{
+
public fun proposal<DaoT>(proposal_id: u64): Proposal acquires GlobalProposals {
     let dao_address = dao_address<DaoT>();
     let global_proposals = borrow_global<GlobalProposals>(dao_address);
     *borrow_proposal(global_proposals, proposal_id)
@@ -3138,7 +3231,7 @@ create a dao config
     voting_quorum_rate: u8,
     min_action_delay: u64,
     min_proposal_deposit: u128,
-): DaoConfig{
+): DaoConfig {
     assert!(voting_delay > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
     assert!(voting_period > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
     assert!(
@@ -3146,7 +3239,7 @@ create a dao config
         Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID),
     );
     assert!(min_action_delay > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
-    DaoConfig { voting_delay, voting_period, voting_quorum_rate, min_action_delay, min_proposal_deposit }
+    DaoConfig{ voting_delay, voting_period, voting_quorum_rate, min_action_delay, min_proposal_deposit }
 }
 
@@ -3298,7 +3391,7 @@ Get the min proposal deposit of the DAO. Implementation -
fun min_proposal_deposit<DaoT: store>(): u128{
+
fun min_proposal_deposit<DaoT: store>(): u128 {
     get_config<DaoT>().min_proposal_deposit
 }
 
@@ -3323,7 +3416,7 @@ Get the min proposal deposit of the DAO.
fun get_config<DaoT: store>(): DaoConfig {
-    let dao_address= dao_address<DaoT>();
+    let dao_address = dao_address<DaoT>();
     Config::get_by_address<DaoConfig>(dao_address)
 }
 
@@ -3362,6 +3455,44 @@ Update function, modify dao config. + + + + +## Function `set_custom_config` + +Update, save function of custom plugin configuration + + +
public fun set_custom_config<DaoT: store, PluginT: drop, ConfigT: copy, drop, store>(_cap: &mut GenesisDao::DaoModifyConfigCap<DaoT, PluginT>, config: ConfigT)
+
+ + + +
+Implementation + + +
public fun set_custom_config<DaoT: store,
+                             PluginT: drop,
+                             ConfigT: copy + store + drop>(
+    _cap: &mut DaoModifyConfigCap<DaoT, PluginT>,
+    config: ConfigT)
+acquires DaoCustomConfigModifyCapHolder, DaoAccountCapHolder {
+    let dao_address = dao_address<DaoT>();
+    if (Config::config_exist_by_address<ConfigT>(dao_address)) {
+        let modify_config_cap =
+            &mut borrow_global_mut<DaoCustomConfigModifyCapHolder<DaoT, ConfigT>>(dao_address).cap;
+        Config::set_with_capability(modify_config_cap, config);
+    } else {
+        let signer = dao_signer<DaoT>();
+        Config::publish_new_config<ConfigT>(&signer, config);
+    }
+}
+
+ + +
@@ -3526,11 +3657,11 @@ Helpers
fun next_member_id<DaoT>(): u64 acquires Dao {
-   let dao_address = dao_address<DaoT>();
-   let dao = borrow_global_mut<Dao>(dao_address);
-   let member_id = dao.next_member_id;
-   dao.next_member_id = member_id + 1;
-   member_id
+    let dao_address = dao_address<DaoT>();
+    let dao = borrow_global_mut<Dao>(dao_address);
+    let member_id = dao.next_member_id;
+    dao.next_member_id = member_id + 1;
+    member_id
 }
 
@@ -3556,9 +3687,9 @@ Helpers
fun assert_no_repeat<E>(v: &vector<E>) {
     let i = 0;
     let len = Vector::length(v);
-    while(i < len){
+    while (i < len) {
         let e = Vector::borrow(v, i);
-        if(Vector::contains(v, e)){
+        if (Vector::contains(v, e)) {
             abort Errors::invalid_argument(ERR_REPEAT_ELEMENT)
         };
         i = i + 1;
@@ -3640,7 +3771,7 @@ Helper to add an element to a vector.
 Implementation
 
 
-
fun dao_signer<DaoT>(): signer acquires DaoAccountCapHolder{
+
fun dao_signer<DaoT>(): signer acquires DaoAccountCapHolder {
     let cap = &borrow_global<DaoAccountCapHolder>(dao_address<DaoT>()).cap;
     DaoAccount::dao_signer(cap)
 }
diff --git a/build/StarcoinFramework/docs/README.md b/build/StarcoinFramework/docs/README.md
index c28a332a..87a8d456 100644
--- a/build/StarcoinFramework/docs/README.md
+++ b/build/StarcoinFramework/docs/README.md
@@ -25,6 +25,7 @@ This is the root document for the Move StarcoinFramework module documentation. T
 -  [`0x1::Collection2`](Collection2.md#0x1_Collection2)
 -  [`0x1::Compare`](Compare.md#0x1_Compare)
 -  [`0x1::Config`](Config.md#0x1_Config)
+-  [`0x1::ConfigProposalPlugin`](ConfigProposalPlugin.md#0x1_ConfigProposalPlugin)
 -  [`0x1::ConsensusConfig`](ConsensusConfig.md#0x1_ConsensusConfig)
 -  [`0x1::ConsensusStrategy`](ConsensusStrategy.md#0x1_ConsensusStrategy)
 -  [`0x1::CoreAddresses`](CoreAddresses.md#0x1_CoreAddresses)
@@ -79,6 +80,7 @@ This is the root document for the Move StarcoinFramework module documentation. T
 -  [`0x1::SIP_3`](SIPs.md#0x1_SIP_3)
 -  [`0x1::STC`](STC.md#0x1_STC)
 -  [`0x1::STCUSDOracle`](Oracle.md#0x1_STCUSDOracle)
+-  [`0x1::SalaryGovPlugin`](SalaryGovPlugin.md#0x1_SalaryGovPlugin)
 -  [`0x1::SharedEd25519PublicKey`](SharedEd25519PublicKey.md#0x1_SharedEd25519PublicKey)
 -  [`0x1::Signature`](Signature.md#0x1_Signature)
 -  [`0x1::SignedInteger64`](SignedInteger64.md#0x1_SignedInteger64)
diff --git a/build/StarcoinFramework/source_maps/DaoAccount.mvsm b/build/StarcoinFramework/source_maps/DaoAccount.mvsm
index 25867c36..da9c47a5 100644
Binary files a/build/StarcoinFramework/source_maps/DaoAccount.mvsm and b/build/StarcoinFramework/source_maps/DaoAccount.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/GenesisDao.mvsm b/build/StarcoinFramework/source_maps/GenesisDao.mvsm
index 6367905e..dc480906 100644
Binary files a/build/StarcoinFramework/source_maps/GenesisDao.mvsm and b/build/StarcoinFramework/source_maps/GenesisDao.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/XDao.mvsm b/build/StarcoinFramework/source_maps/XDao.mvsm
index 0a001cec..5c205f58 100644
Binary files a/build/StarcoinFramework/source_maps/XDao.mvsm and b/build/StarcoinFramework/source_maps/XDao.mvsm differ
diff --git a/integration-tests/dao_account/dao_account.exp b/integration-tests/dao_account/dao_account.exp
new file mode 100644
index 00000000..bdc5da32
--- /dev/null
+++ b/integration-tests/dao_account/dao_account.exp
@@ -0,0 +1,17 @@
+processed 4 tasks
+
+task 2 'run'. lines 6-23:
+{
+  "gas_used": 827652,
+  "status": {
+    "Keep": "Executed"
+  }
+}
+
+task 3 'run'. lines 28-40:
+{
+  "gas_used": 74662,
+  "status": {
+    "Keep": "Executed"
+  }
+}
diff --git a/integration-tests/dao_account/dao_account.move b/integration-tests/dao_account/dao_account.move
new file mode 100644
index 00000000..dc3c21b5
--- /dev/null
+++ b/integration-tests/dao_account/dao_account.move
@@ -0,0 +1,40 @@
+//# init -n dev
+
+//# faucet --addr alice --amount 1000000
+
+
+//# run --signers alice
+script {
+    use StarcoinFramework::STC::STC;
+    use StarcoinFramework::Account;
+    use StarcoinFramework::DaoAccount;
+    use StarcoinFramework::Signer;
+
+    fun main(sender: signer) {
+        let dao_cap = DaoAccount::create_account(&sender);
+        let dao_signer = DaoAccount::dao_signer(&dao_cap);
+        let dao_address= Signer::address_of(&dao_signer);
+        Account::pay_from(&sender, dao_address, 10000);
+        let dao_balance = Account::balance(dao_address);
+        assert!(dao_balance == 10000, 1001);
+        DaoAccount::restore_dao_account_cap(&sender, dao_cap);
+    }
+}
+// check: EXECUTED
+
+
+
+
+//# run --signers alice
+script {
+    use StarcoinFramework::DaoAccount;
+    use StarcoinFramework::Vector;
+
+    fun main(sender: signer) {
+        let dao_cap = DaoAccount::extract_dao_account_cap(&sender);
+        let package_hash = Vector::empty();
+        DaoAccount::submit_upgrade_plan(&dao_cap, package_hash, 2, false);
+        DaoAccount::restore_dao_account_cap(&sender, dao_cap);
+    }
+}
+// check: EXECUTED
\ No newline at end of file
diff --git a/sources/genesis_dao/DaoAccount.move b/sources/genesis_dao/DaoAccount.move
index a7d8f6bf..2a79557c 100644
--- a/sources/genesis_dao/DaoAccount.move
+++ b/sources/genesis_dao/DaoAccount.move
@@ -1,9 +1,11 @@
 module StarcoinFramework::DaoAccount{
     use StarcoinFramework::Account::{Self, SignerCapability};
-    use StarcoinFramework::PackageTxnManager;
+    use StarcoinFramework::PackageTxnManager::{Self, UpgradePlanCapability};
     use StarcoinFramework::Option;
     use StarcoinFramework::Signer;
     use StarcoinFramework::Errors;
+    use StarcoinFramework::Version;
+    use StarcoinFramework::Config;
 
     spec module {
         pragma verify = false;
@@ -16,6 +18,7 @@ module StarcoinFramework::DaoAccount{
     struct DaoAccount has key{
         dao_address: address,
         signer_cap: SignerCapability,
+        upgrade_plan_cap: UpgradePlanCapability,
     }
 
     /// This capability can control the Dao account
@@ -26,17 +29,8 @@ module StarcoinFramework::DaoAccount{
     /// Create a new Dao Account and return DaoAccountCap
     /// Dao Account is a delegate account, the `creator` has the `DaoAccountCap` 
     public fun create_account(creator: &signer): DaoAccountCap {
-        let (dao_address, signer_cap) = Account::create_delegate_account(creator);
-        let dao_signer = Account::create_signer_with_cap(&signer_cap);
-
-        PackageTxnManager::update_module_upgrade_strategy(&dao_signer, PackageTxnManager::get_strategy_two_phase(), Option::some(0));
-        move_to(&dao_signer, DaoAccount{
-            dao_address,
-            signer_cap: signer_cap,
-        });
-        DaoAccountCap{
-            dao_address
-        }
+        let (_dao_address, signer_cap) = Account::create_delegate_account(creator);
+        upgrade_to_dao_with_signer_cap(signer_cap)
     }
 
     /// Entry function for create dao account, the `DaoAccountCap` save to the `creator` account
@@ -45,27 +39,47 @@ module StarcoinFramework::DaoAccount{
         move_to(&sender, cap);
     }
 
+    /// Extract the DaoAccountCap from the `sender`
     public fun extract_dao_account_cap(sender: &signer): DaoAccountCap acquires DaoAccountCap {
         let sender_addr = Signer::address_of(sender);
         assert!(exists(sender_addr), Errors::not_published(ERR_ACCOUNT_CAP_NOT_EXISTS));
         move_from(sender_addr)
     }
 
+    /// Restore the DaoAccountCap to the `sender`
+    public fun restore_dao_account_cap(sender: &signer, cap: DaoAccountCap) {
+        move_to(sender, cap)
+    }
+
     /// Upgrade `sender` account to Dao account
     public fun upgrade_to_dao(sender: signer): DaoAccountCap {
-        //TODO assert sender not Dao
         let signer_cap = Account::remove_signer_capability(&sender);
-        //TODO check the account upgrade_strategy
-        PackageTxnManager::update_module_upgrade_strategy(&sender, PackageTxnManager::get_strategy_two_phase(), Option::some(0));
-        let dao_address = Signer::address_of(&sender);
-        move_to(&sender, DaoAccount{
+        upgrade_to_dao_with_signer_cap(signer_cap)
+    }
+
+     /// Upgrade the account which have the `signer_cap` to a Dao Account
+    public fun upgrade_to_dao_with_signer_cap(signer_cap: SignerCapability): DaoAccountCap {
+       let dao_signer = Account::create_signer_with_cap(&signer_cap);
+       let dao_address = Signer::address_of(&dao_signer);
+ 
+        let upgrade_plan_cap = if(Config::config_exist_by_address(dao_address)){
+            //TODO if the account has extract the upgrade plan cap
+            PackageTxnManager::extract_submit_upgrade_plan_cap(&dao_signer)
+        }else{
+            Config::publish_new_config(&dao_signer, Version::new_version(1));
+            PackageTxnManager::update_module_upgrade_strategy(&dao_signer, PackageTxnManager::get_strategy_two_phase(), Option::some(1));
+            PackageTxnManager::extract_submit_upgrade_plan_cap(&dao_signer)
+        };
+        move_to(&dao_signer, DaoAccount{
             dao_address,
-            signer_cap: signer_cap,
+            signer_cap,
+            upgrade_plan_cap,
         });
-        DaoAccountCap{
+         DaoAccountCap{
             dao_address
         }
     }
+
     
     /// Provide a function to create signer with `DaoAccountCap`
     public fun dao_signer(cap: &DaoAccountCap): signer acquires DaoAccount {
@@ -76,8 +90,8 @@ module StarcoinFramework::DaoAccount{
     /// Sumbit upgrade plan for the Dao account
     /// This function is a shortcut for create signer with DaoAccountCap and invoke `PackageTxnManager::submit_upgrade_plan_v2`
     public fun submit_upgrade_plan(cap: &DaoAccountCap, package_hash: vector, version:u64, enforced: bool) acquires DaoAccount{
-        let dao_signer = dao_signer(cap);
-        PackageTxnManager::submit_upgrade_plan_v2(&dao_signer, package_hash, version, enforced);
+        let upgrade_plan_cap = &borrow_global(cap.dao_address).upgrade_plan_cap;
+        PackageTxnManager::submit_upgrade_plan_with_cap_v2(upgrade_plan_cap, package_hash, version, enforced);
     }
 
     /// Sumbit upgrade plan for the Dao account, sender must hold the `DaoAccountCap`