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 thePermissionStorage
.
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