133 lines
9.2 KiB
Ruby
133 lines
9.2 KiB
Ruby
methods {
|
|
hasRole(bytes32, address) returns(bool) envfree
|
|
getRoleAdmin(bytes32) returns(bytes32) envfree
|
|
|
|
grantRole(bytes32, address)
|
|
revokeRole(bytes32, address)
|
|
renounceRole(bytes32, address)
|
|
}
|
|
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: only grantRole can grant a role │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule onlyGrantCanGrant(env e, bytes32 role, address account) {
|
|
require !hasRole(role, account);
|
|
|
|
method f; calldataarg args;
|
|
f(e, args);
|
|
|
|
assert hasRole(role, account) => f.selector == grantRole(bytes32, address).selector;
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: only revokeRole and renounceRole can grant a role │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule onlyRevokeAndRenounceCanRevoke(env e, bytes32 role, address account) {
|
|
require hasRole(role, account);
|
|
|
|
method f; calldataarg args;
|
|
f(e, args);
|
|
|
|
assert !hasRole(role, account) => (f.selector == revokeRole(bytes32, address).selector || f.selector == renounceRole(bytes32, address).selector);
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: only an account with admin role can call grantRole │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule onlyAdminCanGrant(env e, bytes32 role, address account) {
|
|
bool isAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
|
|
|
|
grantRole@withrevert(e, role, account);
|
|
|
|
assert !lastReverted => isAdmin;
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: only an account with admin role can call revokeRole │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule onlyAdminCanRevoke(env e, bytes32 role, address account) {
|
|
bool isAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
|
|
|
|
revokeRole@withrevert(e, role, account);
|
|
|
|
assert !lastReverted => isAdmin;
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: only the affected account can revoke │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule onlyUserCanRenounce(env e, bytes32 role, address account) {
|
|
renounceRole@withrevert(e, role, account);
|
|
assert !lastReverted => account == e.msg.sender;
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: grantRole only affects the specified user/role combo │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule grantRoleEffect(env e) {
|
|
bytes32 role1; bytes32 role2;
|
|
address account1; address account2;
|
|
|
|
bool hasRoleBefore = hasRole(role1, account1);
|
|
grantRole(e, role2, account2);
|
|
bool hasRoleAfter = hasRole(role1, account1);
|
|
|
|
assert (
|
|
hasRoleBefore != hasRoleAfter
|
|
) => (
|
|
hasRoleAfter == true && role1 == role2 && account1 == account2
|
|
);
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: revokeRole only affects the specified user/role combo │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule revokeRoleEffect(env e) {
|
|
bytes32 role1; bytes32 role2;
|
|
address account1; address account2;
|
|
|
|
bool hasRoleBefore = hasRole(role1, account1);
|
|
revokeRole(e, role2, account2);
|
|
bool hasRoleAfter = hasRole(role1, account1);
|
|
|
|
assert (
|
|
hasRoleBefore != hasRoleAfter
|
|
) => (
|
|
hasRoleAfter == false && role1 == role2 && account1 == account2
|
|
);
|
|
}
|
|
|
|
/*
|
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ Rule: renounceRole only affects the specified user/role combo │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
*/
|
|
rule renounceRoleEffect(env e) {
|
|
bytes32 role1; bytes32 role2;
|
|
address account1; address account2;
|
|
|
|
bool hasRoleBefore = hasRole(role1, account1);
|
|
renounceRole(e, role2, account2);
|
|
bool hasRoleAfter = hasRole(role1, account1);
|
|
|
|
assert (
|
|
hasRoleBefore != hasRoleAfter
|
|
) => (
|
|
hasRoleAfter == false && role1 == role2 && account1 == account2
|
|
);
|
|
} |