Module 0x1::permissioned_signer
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.
- Struct
RevokePermissionHandlePermission - Resource
GrantedPermissionHandles - Enum
PermissionedHandle - Enum
StorablePermissionedHandle - Enum Resource
PermissionStorage - Enum
StoredPermission - Constants
- Function
create_permissioned_handle - Function
destroy_permissioned_handle - Function
signer_from_permissioned_handle - Function
is_permissioned_signer - Function
grant_revoke_permission - Function
revoke_permission_storage_address - Function
revoke_all_handles - Function
initialize_permission_address - Function
create_storable_permissioned_handle - Function
destroy_storable_permissioned_handle - Function
destroy_permissions_storage_address - Function
signer_from_storable_permissioned_handle - Function
permissions_storage_address - Function
assert_master_signer - Function
is_above - Function
consume_capacity - Function
increase_capacity - Function
merge - Function
map_or - Function
insert_or - Function
authorize_increase - Function
authorize_unlimited - Function
grant_unlimited_with_permissioned_signer - Function
increase_limit - Function
check_permission_exists - Function
check_permission_capacity_above - Function
check_permission_consume - Function
capacity - Function
revoke_permission - Function
address_of - Function
borrow_address - Function
is_permissioned_signer_impl - Function
permission_address - Function
signer_from_permissioned_handle_impl - Specification
- Function
create_permissioned_handle - Function
destroy_permissioned_handle - Function
is_permissioned_signer - Function
revoke_permission_storage_address - Function
create_storable_permissioned_handle - Function
destroy_storable_permissioned_handle - Function
authorize_increase - Function
check_permission_exists - Function
check_permission_capacity_above - Function
check_permission_consume - Function
capacity - Function
is_permissioned_signer_impl - Function
permission_address - Function
signer_from_permissioned_handle_impl
- Function
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;
Struct 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
Resource 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_addrthat stores thePermissionStorage.
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
Permissionstructs 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
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;
Function 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 }
}
Function 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);
}
Function 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
)
}
Function 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)
}
Function 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 {});
}
Function 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);
}
Function 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 = granted_permissions.active_handles.trim_reverse(0);
delete_list.destroy(|address| {
destroy_permissions_storage_address(address);
})
}
Function 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) }
);
}
Function 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
}
}
Function 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);
}
Function destroy_permissions_storage_address
fun destroy_permissions_storage_address(permissions_storage_addr: address)
Implementation
inline fun destroy_permissions_storage_address(permissions_storage_addr: address) {
if (exists<PermissionStorage>(permissions_storage_addr)) {
let PermissionStorage::V1 { perms } =
move_from<PermissionStorage>(permissions_storage_addr);
perms.destroy(|_dv| {});
}
}
Function 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
)
}
Function 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
}
Function 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)
);
}
Function 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,
}
}
Function 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 -= threshold;
true
} else { false }
}
StoredPermission::Unlimited => true
}
}
Function 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 += threshold;
}
StoredPermission::Unlimited => (),
}
}
Function 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 += new_capacity;
}
StoredPermission::Unlimited => (),
}
}
StoredPermission::Unlimited => *lhs = StoredPermission::Unlimited,
}
}
Function 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 (perms.contains(&key)) {
let value = perms.remove(&key);
let return_ = mutate(&mut value);
perms.add(key, value);
return_
} else {
default
}
}
Function 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);
}
}
Function 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),
)
}
Function 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,
)
}
Function 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,
)
}
Function 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),
)
}
Function 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)
}
Function 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,
)
}
Function 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,
)
}
Function 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(),
)
}
Function 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);
}
}
Function 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)
}
Function 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)
}
Function 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;
Function 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;
Function 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;
Function 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;
Function destroy_permissioned_handle
public fun destroy_permissioned_handle(p: permissioned_signer::PermissionedHandle)
ensures !exists<PermissionStorage>(p.permissions_storage_addr);
Function 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;
Function revoke_permission_storage_address
public entry fun revoke_permission_storage_address(s: &signer, permissions_storage_addr: address)
Function 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);
Function 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
);
Function 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)
);
Function 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;
Function 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;
Function 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;
Function 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>;
Function 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)
}
}
Function 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;
Function 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
);