Skip to content

permissioned_signer - [mainnet]

A permissioned signer consists of a pair of the original signer and a generated address which is used to store information about associated permissions.

A permissioned signer is a restricted version of a signer. Functions move_to and address_of behave the same, and can be passed wherever signer is needed. However, code can internally query for the permissions to assert additional restrictions on the use of the signer.

A client which is interested in restricting access granted via a signer can create a permissioned signer and pass on to other existing code without changes to existing APIs. Core functions in the framework, for example account functions, can then assert availability of permissions, effectively restricting existing code in a compatible way.

After introducing the core functionality, examples are provided for withdraw limit on accounts, and for blind signing.

use 0x1::big_ordered_map;
use 0x1::copyable_any;
use 0x1::create_signer;
use 0x1::error;
use 0x1::features;
use 0x1::option;
use 0x1::signer;
use 0x1::timestamp;
use 0x1::transaction_context;
use 0x1::vector;

Constants

Cannot authorize a permission.

const ECANNOT_AUTHORIZE: u64 = 2;

signer doesn’t have enough capacity to extract permission.

const ECANNOT_EXTRACT_PERMISSION: u64 = 4;

Trying to grant permission using non-master signer.

const ENOT_MASTER_SIGNER: u64 = 1;

Access permission information from a master signer.

const ENOT_PERMISSIONED_SIGNER: u64 = 3;

Permissioned signer feature is not activated.

const EPERMISSION_SIGNER_DISABLED: u64 = 9;

destroying permission handle that has already been revoked or not owned by the given master signer.

const E_NOT_ACTIVE: u64 = 8;

permission handle has expired.

const E_PERMISSION_EXPIRED: u64 = 5;

storing extracted permission into a different signer.

const E_PERMISSION_MISMATCH: u64 = 6;

permission handle has been revoked by the original signer.

const E_PERMISSION_REVOKED: u64 = 7;
const U256_MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;

Structs

RevokePermissionHandlePermission

If a permissioned signer has this permission, it would be able to revoke other granted permission handles in the same signer.

struct RevokePermissionHandlePermission has copy, drop, store
Fields
dummy_field: bool

Resources

GrantedPermissionHandles

Stores the list of granted permission handles for a given account.

struct GrantedPermissionHandles has key
Fields
active_handles: vector<address>
Each address refers to a permissions_storage_addr that stores the PermissionStorage.

Functions

create_permissioned_handle

Create an ephermeral permission handle based on the master signer.

This handle can be used to derive a signer that can be used in the context of the current transaction.

public fun create_permissioned_handle(master: &signer): permissioned_signer::PermissionedHandle
Implementation
public fun create_permissioned_handle(master: &signer): PermissionedHandle {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
assert_master_signer(master);
let permissions_storage_addr = generate_auid_address();
let master_account_addr = signer::address_of(master);
initialize_permission_address(permissions_storage_addr);
PermissionedHandle::V1 { master_account_addr, permissions_storage_addr }
}

destroy_permissioned_handle

Destroys an ephermeral permission handle. Clean up the permission stored in that handle

public fun destroy_permissioned_handle(p: permissioned_signer::PermissionedHandle)
Implementation
public fun destroy_permissioned_handle(p: PermissionedHandle) acquires PermissionStorage {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
let PermissionedHandle::V1 { master_account_addr: _, permissions_storage_addr } =
p;
destroy_permissions_storage_address(permissions_storage_addr);
}

signer_from_permissioned_handle

Generate the permissioned signer based on the ephermeral permission handle.

This signer can be used as a regular signer for other smart contracts. However when such signer interacts with various framework functions, it would subject to permission checks and would abort if check fails.

public fun signer_from_permissioned_handle(p: &permissioned_signer::PermissionedHandle): signer
Implementation
public fun signer_from_permissioned_handle(p: &PermissionedHandle): signer {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
signer_from_permissioned_handle_impl(
p.master_account_addr, p.permissions_storage_addr
)
}

is_permissioned_signer

Returns true if s is a permissioned signer.

public fun is_permissioned_signer(s: &signer): bool
Implementation
public fun is_permissioned_signer(s: &signer): bool {
// When the permissioned signer is disabled, no one is able to construct a permissioned
// signer. Thus we should return false here, as other on chain permission checks will
// depend on this checks.
if(!features::is_permissioned_signer_enabled()) {
return false;
};
is_permissioned_signer_impl(s)
}

grant_revoke_permission

Grant the permissioned signer the permission to revoke granted permission handles under its address.

public fun grant_revoke_permission(master: &signer, permissioned: &signer)
Implementation
public fun grant_revoke_permission(
master: &signer,
permissioned: &signer,
) acquires PermissionStorage {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
authorize_unlimited(master, permissioned, RevokePermissionHandlePermission {});
}

revoke_permission_storage_address

Revoke a specific storable permission handle immediately. This will disallow owner of the storable permission handle to derive signer from it anymore.

public entry fun revoke_permission_storage_address(s: &signer, permissions_storage_addr: address)
Implementation
public entry fun revoke_permission_storage_address(
s: &signer, permissions_storage_addr: address
) acquires GrantedPermissionHandles, PermissionStorage {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
assert!(
check_permission_exists(s, RevokePermissionHandlePermission {}),
error::permission_denied(ENOT_MASTER_SIGNER)
);
let master_account_addr = signer::address_of(s);
assert!(
exists<GrantedPermissionHandles>(master_account_addr),
error::permission_denied(E_PERMISSION_REVOKED),
);
let active_handles = &mut GrantedPermissionHandles[master_account_addr].active_handles;
let (found, idx) = active_handles.index_of(&permissions_storage_addr);
// The address has to be in the activated list in the master account address.
assert!(found, error::permission_denied(E_NOT_ACTIVE));
active_handles.swap_remove(idx);
destroy_permissions_storage_address(permissions_storage_addr);
}

revoke_all_handles

Revoke all storable permission handle of the signer immediately.

public entry fun revoke_all_handles(s: &signer)
Implementation
public entry fun revoke_all_handles(s: &signer) acquires GrantedPermissionHandles, PermissionStorage {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
assert!(
check_permission_exists(s, RevokePermissionHandlePermission {}),
error::permission_denied(ENOT_MASTER_SIGNER)
);
let master_account_addr = signer::address_of(s);
if (!exists<GrantedPermissionHandles>(master_account_addr)) { return };
let granted_permissions =
borrow_global_mut<GrantedPermissionHandles>(master_account_addr);
let delete_list = vector::trim_reverse(
&mut granted_permissions.active_handles, 0
);
vector::destroy(
delete_list,
|address| {
destroy_permissions_storage_address(address);
}
)
}

initialize_permission_address

initialize permission storage by putting an empty storage under the address.

fun initialize_permission_address(permissions_storage_addr: address)
Implementation
inline fun initialize_permission_address(permissions_storage_addr: address) {
move_to(
&create_signer(permissions_storage_addr),
// Each key is ~100bytes, the value is 12 bytes.
PermissionStorage::V1 { perms: big_ordered_map::new_with_config(40, 35, false) }
);
}

create_storable_permissioned_handle

Create an storable permission handle based on the master signer.

This handle can be used to derive a signer that can be stored by a smart contract. This is as dangerous as key delegation, thus it remains public(package) for now.

The caller should check if expiration_time is not too far in the future.

public(friend) fun create_storable_permissioned_handle(master: &signer, expiration_time: u64): permissioned_signer::StorablePermissionedHandle
Implementation
public(package) fun create_storable_permissioned_handle(
master: &signer, expiration_time: u64
): StorablePermissionedHandle acquires GrantedPermissionHandles {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
assert_master_signer(master);
let permissions_storage_addr = generate_auid_address();
let master_account_addr = signer::address_of(master);
assert!(
timestamp::now_seconds() < expiration_time,
error::permission_denied(E_PERMISSION_EXPIRED)
);
if (!exists<GrantedPermissionHandles>(master_account_addr)) {
move_to<GrantedPermissionHandles>(
master, GrantedPermissionHandles { active_handles: vector::empty() }
);
};
GrantedPermissionHandles[master_account_addr]
.active_handles.push_back(permissions_storage_addr);
initialize_permission_address(permissions_storage_addr);
StorablePermissionedHandle::V1 {
master_account_addr,
permissions_storage_addr,
expiration_time
}
}

destroy_storable_permissioned_handle

Destroys a storable permission handle. Clean up the permission stored in that handle

public(friend) fun destroy_storable_permissioned_handle(p: permissioned_signer::StorablePermissionedHandle)
Implementation
public(package) fun destroy_storable_permissioned_handle(
p: StorablePermissionedHandle
) acquires PermissionStorage, GrantedPermissionHandles {
let StorablePermissionedHandle::V1 {
master_account_addr,
permissions_storage_addr,
expiration_time: _
} = p;
assert!(
exists<GrantedPermissionHandles>(master_account_addr),
error::permission_denied(E_PERMISSION_REVOKED),
);
let active_handles = &mut GrantedPermissionHandles[master_account_addr].active_handles;
let (found, idx) = active_handles.index_of(&permissions_storage_addr);
// Removing the address from the active handle list if it's still active.
if(found) {
active_handles.swap_remove(idx);
};
destroy_permissions_storage_address(permissions_storage_addr);
}

destroy_permissions_storage_address

fun destroy_permissions_storage_address(permissions_storage_addr: address)
Implementation
inline fun destroy_permissions_storage_address(
permissions_storage_addr: address
) acquires PermissionStorage {
if (exists<PermissionStorage>(permissions_storage_addr)) {
let PermissionStorage::V1 { perms } =
move_from<PermissionStorage>(permissions_storage_addr);
big_ordered_map::destroy(
perms,
|_dv| {},
);
}
}

signer_from_storable_permissioned_handle

Generate the permissioned signer based on the storable permission handle.

public(friend) fun signer_from_storable_permissioned_handle(p: &permissioned_signer::StorablePermissionedHandle): signer
Implementation
public(package) fun signer_from_storable_permissioned_handle(
p: &StorablePermissionedHandle
): signer {
assert!(
features::is_permissioned_signer_enabled(),
error::permission_denied(EPERMISSION_SIGNER_DISABLED)
);
assert!(
timestamp::now_seconds() < p.expiration_time,
error::permission_denied(E_PERMISSION_EXPIRED)
);
assert!(
exists<PermissionStorage>(p.permissions_storage_addr),
error::permission_denied(E_PERMISSION_REVOKED)
);
signer_from_permissioned_handle_impl(
p.master_account_addr, p.permissions_storage_addr
)
}

permissions_storage_address

Return the permission handle address so that it could be used for revocation purpose.

public(friend) fun permissions_storage_address(p: &permissioned_signer::StorablePermissionedHandle): address
Implementation
public(package) fun permissions_storage_address(
p: &StorablePermissionedHandle
): address {
p.permissions_storage_addr
}

assert_master_signer

Helper function that would abort if the signer passed in is a permissioned signer.

public(friend) fun assert_master_signer(s: &signer)
Implementation
public(package) fun assert_master_signer(s: &signer) {
assert!(
!is_permissioned_signer(s), error::permission_denied(ENOT_MASTER_SIGNER)
);
}

is_above

===================================================================================================== StoredPermission operations

check if StoredPermission has at least threshold capacity.

fun is_above(perm: &permissioned_signer::StoredPermission, threshold: u256): bool
Implementation
fun is_above(perm: &StoredPermission, threshold: u256): bool {
match (perm) {
StoredPermission::Capacity(capacity) => *capacity >= threshold,
StoredPermission::Unlimited => true,
}
}

consume_capacity

consume threshold capacity from StoredPermission

fun consume_capacity(perm: &mut permissioned_signer::StoredPermission, threshold: u256): bool
Implementation
fun consume_capacity(perm: &mut StoredPermission, threshold: u256): bool {
match (perm) {
StoredPermission::Capacity(current_capacity) => {
if (*current_capacity >= threshold) {
*current_capacity = *current_capacity - threshold;
true
} else { false }
}
StoredPermission::Unlimited => true
}
}

increase_capacity

increase threshold capacity from StoredPermission

fun increase_capacity(perm: &mut permissioned_signer::StoredPermission, threshold: u256)
Implementation
fun increase_capacity(perm: &mut StoredPermission, threshold: u256) {
match (perm) {
StoredPermission::Capacity(current_capacity) => {
*current_capacity = *current_capacity + threshold;
}
StoredPermission::Unlimited => (),
}
}

merge

merge the two stored permission

fun merge(lhs: &mut permissioned_signer::StoredPermission, rhs: permissioned_signer::StoredPermission)
Implementation
fun merge(lhs: &mut StoredPermission, rhs: StoredPermission) {
match (rhs) {
StoredPermission::Capacity(new_capacity) => {
match (lhs) {
StoredPermission::Capacity(current_capacity) => {
*current_capacity = *current_capacity + new_capacity;
}
StoredPermission::Unlimited => (),
}
}
StoredPermission::Unlimited => *lhs = StoredPermission::Unlimited,
}
}

map_or

===================================================================================================== Permission Management

Authorizes permissioned with the given permission. This requires to have access to the master signer.

fun map_or<PermKey: copy, drop, store, T>(permissioned: &signer, perm: PermKey, mutate: |&mut permissioned_signer::StoredPermission|T, default: T): T
Implementation
inline fun map_or<PermKey: copy + drop + store, T>(
permissioned: &signer,
perm: PermKey,
mutate: |&mut StoredPermission| T,
default: T,
): T {
let permission_signer_addr = permission_address(permissioned);
assert!(
exists<PermissionStorage>(permission_signer_addr),
error::permission_denied(E_NOT_ACTIVE)
);
let perms =
&mut borrow_global_mut<PermissionStorage>(permission_signer_addr).perms;
let key = copyable_any::pack(perm);
if (big_ordered_map::contains(perms, &key)) {
let value = perms.remove(&key);
let return_ = mutate(&mut value);
perms.add(key, value);
return_
} else {
default
}
}

insert_or

fun insert_or<PermKey: copy, drop, store>(permissioned: &signer, perm: PermKey, mutate: |&mut permissioned_signer::StoredPermission|, default: permissioned_signer::StoredPermission)
Implementation
inline fun insert_or<PermKey: copy + drop + store>(
permissioned: &signer,
perm: PermKey,
mutate: |&mut StoredPermission|,
default: StoredPermission,
) {
let permission_signer_addr = permission_address(permissioned);
assert!(
exists<PermissionStorage>(permission_signer_addr),
error::permission_denied(E_NOT_ACTIVE)
);
let perms =
&mut borrow_global_mut<PermissionStorage>(permission_signer_addr).perms;
let key = copyable_any::pack(perm);
if (perms.contains(&key)) {
let value = perms.remove(&key);
mutate(&mut value);
perms.add(key, value);
} else {
perms.add(key, default);
}
}

authorize_increase

Authorizes permissioned with a given capacity and increment the existing capacity if present.

Consumption using check_permission_consume will deduct the capacity.

public(friend) fun authorize_increase<PermKey: copy, drop, store>(master: &signer, permissioned: &signer, capacity: u256, perm: PermKey)
Implementation
public(package) fun authorize_increase<PermKey: copy + drop + store>(
master: &signer,
permissioned: &signer,
capacity: u256,
perm: PermKey
) acquires PermissionStorage {
assert!(
is_permissioned_signer(permissioned)
&& !is_permissioned_signer(master)
&& signer::address_of(master) == signer::address_of(permissioned),
error::permission_denied(ECANNOT_AUTHORIZE)
);
insert_or(
permissioned,
perm,
|stored_permission| {
increase_capacity(stored_permission, capacity);
},
StoredPermission::Capacity(capacity),
)
}

authorize_unlimited

Authorizes permissioned with the given unlimited permission. Unlimited permission can be consumed however many times.

public(friend) fun authorize_unlimited<PermKey: copy, drop, store>(master: &signer, permissioned: &signer, perm: PermKey)
Implementation
public(package) fun authorize_unlimited<PermKey: copy + drop + store>(
master: &signer,
permissioned: &signer,
perm: PermKey
) acquires PermissionStorage {
assert!(
is_permissioned_signer(permissioned)
&& !is_permissioned_signer(master)
&& signer::address_of(master) == signer::address_of(permissioned),
error::permission_denied(ECANNOT_AUTHORIZE)
);
insert_or(
permissioned,
perm,
|stored_permission| {
*stored_permission = StoredPermission::Unlimited;
},
StoredPermission::Unlimited,
)
}

grant_unlimited_with_permissioned_signer

Grant an unlimited permission to a permissioned signer without master signer’s approvoal.

public(friend) fun grant_unlimited_with_permissioned_signer<PermKey: copy, drop, store>(permissioned: &signer, perm: PermKey)
Implementation
public(package) fun grant_unlimited_with_permissioned_signer<PermKey: copy + drop + store>(
permissioned: &signer,
perm: PermKey
) acquires PermissionStorage {
if(!is_permissioned_signer(permissioned)) {
return;
};
insert_or(
permissioned,
perm,
|stored_permission| {
*stored_permission = StoredPermission::Unlimited;
},
StoredPermission::Unlimited,
)
}

increase_limit

Increase the capacity of a permissioned signer without master signer’s approvoal.

The caller of the module will need to make sure the witness type PermKey can only be constructed within its own module, otherwise attackers can refill the permission for itself to bypass the checks.

public(friend) fun increase_limit<PermKey: copy, drop, store>(permissioned: &signer, capacity: u256, perm: PermKey)
Implementation
public(package) fun increase_limit<PermKey: copy + drop + store>(
permissioned: &signer,
capacity: u256,
perm: PermKey
) acquires PermissionStorage {
if(!is_permissioned_signer(permissioned)) {
return;
};
insert_or(
permissioned,
perm,
|stored_permission| {
increase_capacity(stored_permission, capacity);
},
StoredPermission::Capacity(capacity),
)
}

check_permission_exists

public(friend) fun check_permission_exists<PermKey: copy, drop, store>(s: &signer, perm: PermKey): bool
Implementation
public(package) fun check_permission_exists<PermKey: copy + drop + store>(
s: &signer, perm: PermKey
): bool acquires PermissionStorage {
// 0 capacity permissions will be treated as non-existant.
check_permission_capacity_above(s, 1, perm)
}

check_permission_capacity_above

public(friend) fun check_permission_capacity_above<PermKey: copy, drop, store>(s: &signer, threshold: u256, perm: PermKey): bool
Implementation
public(package) fun check_permission_capacity_above<PermKey: copy + drop + store>(
s: &signer, threshold: u256, perm: PermKey
): bool acquires PermissionStorage {
if (!is_permissioned_signer(s)) {
// master signer has all permissions
return true
};
map_or(
s,
perm,
|stored_permission| {
is_above(stored_permission, threshold)
},
false,
)
}

check_permission_consume

public(friend) fun check_permission_consume<PermKey: copy, drop, store>(s: &signer, threshold: u256, perm: PermKey): bool
Implementation
public(package) fun check_permission_consume<PermKey: copy + drop + store>(
s: &signer, threshold: u256, perm: PermKey
): bool acquires PermissionStorage {
if (!is_permissioned_signer(s)) {
// master signer has all permissions
return true
};
map_or(
s,
perm,
|stored_permission| {
consume_capacity(stored_permission, threshold)
},
false,
)
}

capacity

public(friend) fun capacity<PermKey: copy, drop, store>(s: &signer, perm: PermKey): option::Option<u256>
Implementation
public(package) fun capacity<PermKey: copy + drop + store>(
s: &signer, perm: PermKey
): Option<u256> acquires PermissionStorage {
if (!is_permissioned_signer(s)) {
return option::some(U256_MAX)
};
map_or(
s,
perm,
|stored_permission: &mut StoredPermission| {
option::some(match (stored_permission) {
StoredPermission::Capacity(capacity) => *capacity,
StoredPermission::Unlimited => U256_MAX,
})
},
option::none(),
)
}

revoke_permission

public(friend) fun revoke_permission<PermKey: copy, drop, store>(permissioned: &signer, perm: PermKey)
Implementation
public(package) fun revoke_permission<PermKey: copy + drop + store>(
permissioned: &signer, perm: PermKey
) acquires PermissionStorage {
if (!is_permissioned_signer(permissioned)) {
// Master signer has no permissions associated with it.
return
};
let addr = permission_address(permissioned);
if (!exists<PermissionStorage>(addr)) { return };
let perm_storage = &mut PermissionStorage[addr].perms;
let key = copyable_any::pack(perm);
if (perm_storage.contains(&key)) {
perm_storage.remove(&key);
}
}

address_of

Unused function. Keeping it for compatibility purpose.

public fun address_of(_s: &signer): address
Implementation
public fun address_of(_s: &signer): address {
abort error::permission_denied(EPERMISSION_SIGNER_DISABLED)
}

borrow_address

Unused function. Keeping it for compatibility purpose.

public fun borrow_address(_s: &signer): &address
Implementation
public fun borrow_address(_s: &signer): &address {
abort error::permission_denied(EPERMISSION_SIGNER_DISABLED)
}

is_permissioned_signer_impl

Check whether this is a permissioned signer.

fun is_permissioned_signer_impl(s: &signer): bool
Implementation
native fun is_permissioned_signer_impl(s: &signer): bool;

permission_address

Return the address used for storing permissions. Aborts if not a permissioned signer.

fun permission_address(permissioned: &signer): address
Implementation
native fun permission_address(permissioned: &signer): address;

signer_from_permissioned_handle_impl

Creates a permissioned signer from an existing universal signer. The function aborts if the given signer is already a permissioned signer.

The implementation of this function requires to extend the value representation for signers in the VM. invariants: signer::address_of(master) == signer::address_of(signer_from_permissioned_handle(create_permissioned_handle(master))),

fun signer_from_permissioned_handle_impl(master_account_addr: address, permissions_storage_addr: address): signer
Implementation
native fun signer_from_permissioned_handle_impl(
master_account_addr: address, permissions_storage_addr: address
): signer;

Specification

pragma verify = true;
axiom forall a: GrantedPermissionHandles:
(
forall i in 0..len(a.active_handles):
forall j in 0..len(a.active_handles):
i != j ==>
a.active_handles[i] != a.active_handles[j]
);
fun spec_is_permissioned_signer_impl(s: signer): bool;

create_permissioned_handle

public fun create_permissioned_handle(master: &signer): permissioned_signer::PermissionedHandle
pragma opaque;
aborts_if [abstract] spec_is_permissioned_signer(master);
let permissions_storage_addr = transaction_context::spec_generate_unique_address();
modifies global<PermissionStorage>(permissions_storage_addr);
let master_account_addr = signer::address_of(master);
ensures result.master_account_addr == master_account_addr;
ensures result.permissions_storage_addr == permissions_storage_addr;

destroy_permissioned_handle

public fun destroy_permissioned_handle(p: permissioned_signer::PermissionedHandle)
ensures !exists<PermissionStorage>(p.permissions_storage_addr);

is_permissioned_signer

public fun is_permissioned_signer(s: &signer): bool
pragma opaque;
aborts_if [abstract] false;
ensures [abstract] result == spec_is_permissioned_signer(s);
fun spec_permission_address(s: signer): address;

revoke_permission_storage_address

public entry fun revoke_permission_storage_address(s: &signer, permissions_storage_addr: address)

create_storable_permissioned_handle

public(friend) fun create_storable_permissioned_handle(master: &signer, expiration_time: u64): permissioned_signer::StorablePermissionedHandle
pragma opaque;
aborts_if [abstract] spec_is_permissioned_signer(master);
let permissions_storage_addr = transaction_context::spec_generate_unique_address();
modifies global<PermissionStorage>(permissions_storage_addr);
let master_account_addr = signer::address_of(master);
modifies global<GrantedPermissionHandles>(master_account_addr);
ensures result.master_account_addr == master_account_addr;
ensures result.permissions_storage_addr == permissions_storage_addr;
ensures result.expiration_time == expiration_time;
ensures vector::spec_contains(
global<GrantedPermissionHandles>(master_account_addr).active_handles,
permissions_storage_addr
);
ensures exists<GrantedPermissionHandles>(master_account_addr);

destroy_storable_permissioned_handle

public(friend) fun destroy_storable_permissioned_handle(p: permissioned_signer::StorablePermissionedHandle)
ensures !exists<PermissionStorage>(p.permissions_storage_addr);
let post granted_permissions = global<GrantedPermissionHandles>(
p.master_account_addr
);

authorize_increase

public(friend) fun authorize_increase<PermKey: copy, drop, store>(master: &signer, permissioned: &signer, capacity: u256, perm: PermKey)
pragma aborts_if_is_partial;
aborts_if !spec_is_permissioned_signer(permissioned);
aborts_if spec_is_permissioned_signer(master);
aborts_if signer::address_of(permissioned) != signer::address_of(master);
ensures exists<PermissionStorage>(
spec_permission_address(permissioned)
);

check_permission_exists

public(friend) fun check_permission_exists<PermKey: copy, drop, store>(s: &signer, perm: PermKey): bool
pragma opaque;
modifies global<PermissionStorage>(spec_permission_address(s));
ensures [abstract] result == spec_check_permission_exists(s, perm);
fun spec_check_permission_exists<PermKey: copy + drop + store>(s: signer, perm: PermKey): bool;

check_permission_capacity_above

public(friend) fun check_permission_capacity_above<PermKey: copy, drop, store>(s: &signer, threshold: u256, perm: PermKey): bool
modifies global<PermissionStorage>(spec_permission_address(s));
let permissioned_signer_addr = spec_permission_address(s);
ensures !spec_is_permissioned_signer(s) ==> result == true;
ensures (
spec_is_permissioned_signer(s)
&& !exists<PermissionStorage>(permissioned_signer_addr)
) ==> result == false;

check_permission_consume

public(friend) fun check_permission_consume<PermKey: copy, drop, store>(s: &signer, threshold: u256, perm: PermKey): bool
pragma opaque;
let permissioned_signer_addr = spec_permission_address(s);
modifies global<PermissionStorage>(spec_permission_address(s));
ensures [abstract] result == spec_check_permission_consume(s, threshold, perm);
fun spec_check_permission_consume<PermKey: copy + drop + store>(s: signer, threshold: u256, perm: PermKey): bool;

capacity

public(friend) fun capacity<PermKey: copy, drop, store>(s: &signer, perm: PermKey): option::Option<u256>
pragma opaque;
let permissioned_signer_addr = spec_permission_address(s);
modifies global<PermissionStorage>(spec_permission_address(s));
ensures [abstract] result == spec_capacity(s, perm);
fun spec_capacity<PermKey: copy + drop + store>(s: signer, perm: PermKey): Option<u256>;

is_permissioned_signer_impl

fun is_permissioned_signer_impl(s: &signer): bool
pragma opaque;
ensures [abstract] result == spec_is_permissioned_signer_impl(s);
fun spec_is_permissioned_signer(s: signer): bool {
use std::features;
use std::features::PERMISSIONED_SIGNER;
if (!features::spec_is_enabled(PERMISSIONED_SIGNER)) {
false
} else {
spec_is_permissioned_signer_impl(s)
}
}

permission_address

fun permission_address(permissioned: &signer): address
pragma opaque;
aborts_if [abstract]!spec_is_permissioned_signer(permissioned);
ensures [abstract] result == spec_permission_address(permissioned);
fun spec_signer_from_permissioned_handle_impl(
master_account_addr: address, permissions_storage_addr: address
): signer;

signer_from_permissioned_handle_impl

fun signer_from_permissioned_handle_impl(master_account_addr: address, permissions_storage_addr: address): signer
pragma opaque;
ensures [abstract] result
== spec_signer_from_permissioned_handle_impl(
master_account_addr, permissions_storage_addr
);

Enum PermissionedHandle

A ephermeral permission handle that can be used to generate a permissioned signer with permission configuration stored within.

enum PermissionedHandle
Variants
V1
Fields
master_account_addr: address
Address of the signer that creates this handle.
permissions_storage_addr: address
Address that stores PermissionStorage.

Enum StorablePermissionedHandle

A permission handle that can be used to generate a permissioned signer.

This handle is storable and thus should be treated very carefully as it serves similar functionality as signer delegation.

enum StorablePermissionedHandle has store
Variants
V1
Fields
master_account_addr: address
Address of the signer that creates this handle.
permissions_storage_addr: address
Address that stores PermissionStorage.
expiration_time: u64
Permissioned signer can no longer be generated from this handle after expiration_time.

Enum Resource PermissionStorage

The actual permission configuration stored on-chain.

The address that holds PermissionStorage will be generated freshly every time a permission handle gets created.

enum PermissionStorage has key
Variants
V1
Fields
perms: big_ordered_map::BigOrderedMap<copyable_any::Any, permissioned_signer::StoredPermission>
A hetherogenous map from Permission structs defined by each different modules to its permission capacity.

Enum StoredPermission

Types of permission capacity stored on chain.

enum StoredPermission has copy, drop, store
Variants
Unlimited
Fields
Capacity
Fields
0: u256