Tortuga Finance Docs
  • Overview
    • Liquid Staking on Aptos
  • Stake APT
    • Tutorial: Stake APT via Tortuga
    • Tutorial: Buy tAPT from DEX
    • Use tAPT
    • Fees
    • Before You Stake
  • For Validators
    • How It Works
    • How to Join
  • For Developers
    • Integration Resources
    • Tortuga <> Pyth
  • Protocol
    • Overview
    • Whitepaper
    • Governance
    • Tokenomics
    • Reference
      • helpers::circular_buffer
      • helpers::math
      • helpers::pool
      • helpers::stake_pool_helpers
      • helpers::iterable_table_custom
      • oracle::validator_states
      • delegation::delegation_state
      • delegation::delegation_service
      • tortuga::validator_router
      • tortuga::stake_router
      • governance::permissions
      • governance::utils
      • tortuga_governance::staked_aptos
      • tortuga_governance::tortuga_governance
    • Security Audits
Powered by GitBook
On this page
  • Module 0xc0ded0c1::permissions
  • module governance::permissions
  • Resource AuthorizationCapability
  • Resource DeployerPermission
  • Resource Admins
  • Constants
  • Function is_deployer_authorized
  • Function initialize_permissions
  • Function assert_initialization
  • Function assert_deploy_authority
  • Function assert_authority
  • Function create_signer_for_an_upgrade_or_deploy
  • Function revoke_deployer_authorization_privilege
  • Function initialize
  • Function deploy
  • Function set_admin
  • Function assert_governance_permission
  • Function create_signer_for_proposal_resolution
  1. Protocol
  2. Reference

governance::permissions

Previoustortuga::stake_routerNextgovernance::utils

Last updated 2 years ago

Module 0xc0ded0c1::permissions

module governance::permissions

A module needing a governance can use this module to set up basic governance permissions, which we call Phase 0 of governance.

The workflow is as follows:

  • The deployer of the governance sets up a new package with a GovernanceType struct.

  • The deployer of GovernanceType deploys the module needing governance using <GovernanceType>(). This step can be skipped if governance does not control upgradability of the contract code, but only parameters of the protocol.

  • During initialization of the contract needing governance, initialize_permissions is called to set up permissions.

  • Any method in the contract needing governance that should be under governance must use <GovernanceType>().

  • The deployer of GovernanceType can initialize full fledged governance, which we call Phase 1 of governance, at any point.

  • Phase 1 governance can vote to revoke deployer permission. This uses ().

  • After revocation of deployer permission, governance is in full control.

  • The governance can use () to resolve successful proposals.

Note: Once the control of the contract is fully transferred to governance, it is not possible to return it to the deployer.

use 0x1::account;
use 0x1::code;
use 0x1::error;
use 0x1::signer;
use 0xc0ded0c1::utils;

Resource AuthorizationCapability

struct AuthorizationCapability<GovernanceType> has key
Fields

Resource DeployerPermission

Keeps track of deployer's permission.

struct DeployerPermission<GovernanceType> has key
Fields

is_deployer_authorized: boolWhether the deployer is authorized to perform actions on the contract.

The governance, or the deployer, can set this to false, which results in the deployer of the main contract loosing all authorization privileges in the main contract, leaving all authorized actions to the governance.

Resource Admins

struct Admins<GovernanceType> has key
Fields

admin: address

Constants

When the petitioner is not authorized to perform an action.

const EPERMISSION_DENIED: u64 = 1;

When the governance has already been initialized.

const EALREADY_INITIALIZED: u64 = 4;

When the deployer attempts to revoke their own deployer permission.

const EDEPLOYER_REVOKE_NOT_ALLOWED: u64 = 2;

When the deployer is not authorized to perform an action.

const EDEPLOYER_UNAUTHORIZED: u64 = 0;

When the governance has not been initialized.

const EPERMISSIONS_NOT_INITIALIZED: u64 = 3;

Random seed generated using aptos-crypto crate. This is used in creating new signer capabilities.

const RANDOM_SEED: vector<u8> = [16, 255, 222, 172, 207, 31, 104, 153, 235, 236, 70, 179, 127, 42, 232, 183, 157, 58, 223, 63, 36, 34, 133, 8, 219, 195, 166, 178, 84, 108, 90, 247];

Function is_deployer_authorized

Returns whether governance deployer's permissions are still valid

public fun is_deployer_authorized<GovernanceType>(): bool
Implementation
public fun is_deployer_authorized<GovernanceType>(): bool acquires DeployerPermission {
    assert_initialization<GovernanceType>();
    let governance_address = utils::governance_address<GovernanceType>();
    borrow_global<DeployerPermission<GovernanceType>>(
            governance_address
    ).is_deployer_authorized
}

Function initialize_permissions

Initializes the permissions for governance and deployer.

Phase 0 initialization must happen when the main contract needing governance is initialized, otherwise, none of the permissioned methods would work in the main contract.

public fun initialize_permissions<GovernanceType>(deployer: &signer)
Implementation
public fun initialize_permissions<GovernanceType>(
    deployer: &signer,
) {
    let deployer_address = signer::address_of(deployer);
    assert_governance_permission<GovernanceType>(deployer_address);

    // If the contract needing governance was not deployed using governance,
    // we initialize the governance now (only useful for testing purposes)
    if(!exists<AuthorizationCapability<GovernanceType>>(deployer_address)) {
        initialize<GovernanceType>(deployer);
    };
}

Function assert_initialization

Assert if permissions have been initialized.

Abort conditions

  • If the permissions have not been initialized.

public fun assert_initialization<GovernanceType>()
Implementation
public fun assert_initialization<GovernanceType>() {
    assert!(
        exists<AuthorizationCapability<GovernanceType>>(
            utils::governance_address<GovernanceType>()
        ),
        error::invalid_state(EPERMISSIONS_NOT_INITIALIZED)
    );
}

Function assert_deploy_authority

Assert if the petitioner has the deploy authority. Checked upon deploy or fallback for admin.

Abort conditions

  • If the petitioner is not authorized to perform the action.

public fun assert_deploy_authority<GovernanceType>(petitioner: &signer)
Implementation
public fun assert_deploy_authority<GovernanceType>(
    petitioner: &signer
) acquires DeployerPermission, AuthorizationCapability {
    let governance_address = utils::governance_address<GovernanceType>();
    let petitioner_address = signer::address_of(petitioner);

    assert_initialization<GovernanceType>();

    if (petitioner_address == governance_address) {
        // Check if the petitioner is the deployer, and if so,
        // that deployer permissions are still valid
        let permission = borrow_global<DeployerPermission<GovernanceType>>(
            governance_address
        );
        assert!(
            permission.is_deployer_authorized,
            error::unauthenticated(EDEPLOYER_UNAUTHORIZED)
        );
    } else {
        // Check whether the signer is the signer for the correct signer cap
        let auth_cap =
            borrow_global<AuthorizationCapability<GovernanceType>>(
                governance_address
            );

        assert!(
            petitioner_address ==
              account::get_signer_capability_address(&auth_cap.signer_cap),
            error::unauthenticated(EPERMISSION_DENIED)
        );
    };
}

Function assert_authority

Assert if the petitioner has the authority to perform an action.

All methods in the main contract which need governance permissions must call this method. The main contract's methods that are not under the control of governance should not use this method.

Abort conditions

  • If the petitioner is not authorized to perform the action.

public fun assert_authority<GovernanceType>(petitioner: &signer)
Implementation
public fun assert_authority<GovernanceType>(
    petitioner: &signer
) acquires DeployerPermission, AuthorizationCapability, Admins {
    assert_initialization<GovernanceType>();

    let admin = borrow_global<Admins<GovernanceType>>(utils::governance_address<GovernanceType>());
    if (signer::address_of(petitioner) == admin.admin) {
        return
    };

    assert_deploy_authority<GovernanceType>(petitioner);
}

Function create_signer_for_an_upgrade_or_deploy

Abort conditions

  • If the deployer is not authorized to perform the action.

public fun create_signer_for_an_upgrade_or_deploy<GovernanceType>(deployer: &signer): signer
Implementation
public fun create_signer_for_an_upgrade_or_deploy<GovernanceType>(
     deployer: &signer
 ): signer acquires AuthorizationCapability, DeployerPermission {
     assert_deploy_authority<GovernanceType>(deployer);
     let auth_cap = borrow_global<AuthorizationCapability<GovernanceType>>(
         utils::governance_address<GovernanceType>()
     );

     // Return the signer so that deployer can upgrade the module
     create_signer_with_capability(&auth_cap.signer_cap)
 }

Function revoke_deployer_authorization_privilege

Revokes the deployer's permission to perform actions on the main.

The governance of type GovernanceType can permanently revoke GovernanceType's deployer's authorization privileges This cannot be reversed, so it should only be called via a successful governance proposal.

Abort conditions

  • If the dao is not authorized to perform the action.

  • If the dao signer is the same as the governance deployer.

public fun revoke_deployer_authorization_privilege<GovernanceType>(dao: &signer)
Implementation
public fun revoke_deployer_authorization_privilege<GovernanceType>(
    dao: &signer,
) acquires DeployerPermission, AuthorizationCapability {
    assert_deploy_authority<GovernanceType>(dao);

    // Make sure that the deployer doesn't revoke
    // it's own permissions.
    // It must be done via a successful governance proposal.
    // The following assert is only added as a deterrent, as the deployer
    // can still use `create_signer_for_an_upgrade_or_deploy` to
    // revoke its own permissions.
    let governance_address = utils::governance_address<GovernanceType>();
    assert!(
        signer::address_of(dao) != governance_address,
        error::invalid_argument(EDEPLOYER_REVOKE_NOT_ALLOWED)
    );

    let permission = borrow_global_mut<DeployerPermission<GovernanceType>>(
        governance_address
    );
    permission.is_deployer_authorized = false;
}

Function initialize

Upon initialization, the deployer is authorized to perform all actions on the contract, and can also upgrade the contract code.

public fun initialize<GovernanceType>(deployer: &signer)
Implementation
public entry fun initialize<GovernanceType>(deployer: &signer) {
    let deployer_address = signer::address_of(deployer);
    assert_governance_permission<GovernanceType>(deployer_address);

    assert!(
        !exists<AuthorizationCapability<GovernanceType>>(deployer_address),
        error::invalid_state(EALREADY_INITIALIZED)
    );

    let (_signer, signer_cap) =
        account::create_resource_account(deployer, RANDOM_SEED);

    move_to(deployer, AuthorizationCapability<GovernanceType> {
        signer_cap: signer_cap,
    });

    move_to(deployer, DeployerPermission<GovernanceType> {
        is_deployer_authorized: true,
    });

    // No admin by default
    move_to(deployer, Admins<GovernanceType> {
        admin: @0x0,
    });
}

Function deploy

The governance can deploy the code using this method, which will enable governance to control upgradability of the code.

public fun deploy<GovernanceType>(deployer: &signer, metadata_serialized: vector<u8>, code: vector<vector<u8>>)
Implementation
public entry fun deploy<GovernanceType>(
    deployer: &signer,
    metadata_serialized: vector<u8>,
    code: vector<vector<u8>>,
) acquires AuthorizationCapability, DeployerPermission {
    assert_initialization<GovernanceType>();

    // below also calls assert_deploy_authority
    let auth_signer =
        create_signer_for_an_upgrade_or_deploy<GovernanceType>(
            deployer
        );
    aptos_framework::code::publish_package_txn(
        &auth_signer,
        metadata_serialized, code
    );
}

Function set_admin

set the admin for the governance

public fun set_admin<GovernanceType>(auth_signer: &signer, new_admin: address)
Implementation
public entry fun set_admin<GovernanceType>(
    auth_signer: &signer,
    new_admin: address,
) acquires AuthorizationCapability, DeployerPermission, Admins {
    assert_initialization<GovernanceType>();
    assert_deploy_authority<GovernanceType>(auth_signer);

    let admin = borrow_global_mut<Admins<GovernanceType>>(utils::governance_address<GovernanceType>());
    admin.admin = new_admin;
}

Function assert_governance_permission

Assert if the deployer_address is the same as the governance_address().

Abort conditions

  • If the deployer_address is not the governance address.

fun assert_governance_permission<GovernanceType>(deployer_address: address)
Implementation
fun assert_governance_permission<GovernanceType>(
    deployer_address: address
) {
    assert!(
        utils::governance_address<GovernanceType>() == deployer_address,
        error::unauthenticated(EPERMISSION_DENIED)
    );
}

Function create_signer_for_proposal_resolution

public(friend) fun create_signer_for_proposal_resolution<GovernanceType>(): signer
Implementation
public(friend) fun create_signer_for_proposal_resolution<GovernanceType>(
): signer acquires AuthorizationCapability {
    let auth_cap = borrow_global<AuthorizationCapability<GovernanceType>>(
        utils::governance_address<GovernanceType>()
    );

    // Return the signer to execute the proposal
    create_signer_with_capability(&auth_cap.signer_cap)
}

When a governance proposal passes, this signer capability is used to create a which can execute the proposal in the main_contract which is under governance.

signer_cap: The capability to sign on behalf of the governance

Creates a for the deployer which can be used to perform actions on the main contract.

Creates a resource account derived from the deployer, gives the deployer the to create a signer for running authorized actions on the contract and the which tracks the permissions the deployer has.

This function creates a in order to resolve a governance proposal.

signer
account::SignerCapability
signer
signer
deploy
assert_authority
revoke_deployer_authorization_privilege
create_signer_for_proposal_resolution
module governance::permissions
Resource AuthorizationCapability
Resource DeployerPermission
Resource Admins
Constants
Function is_deployer_authorized
Function initialize_permissions
Function assert_initialization
Abort conditions
Function assert_deploy_authority
Abort conditions
Function assert_authority
Abort conditions
Function create_signer_for_an_upgrade_or_deploy
Abort conditions
Function revoke_deployer_authorization_privilege
Abort conditions
Function initialize
Function deploy
Function set_admin
Function assert_governance_permission
Abort conditions
Function create_signer_for_proposal_resolution
AuthorizationCapability
DeployerPermission