123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826 |
- import "helpers/helpers.spec";
- import "methods/IAccessManager.spec";
- methods {
- // FV
- function canCall_immediate(address,address,bytes4) external returns (bool);
- function canCall_delay(address,address,bytes4) external returns (uint32);
- function canCallExtended(address,address,bytes) external returns (bool,uint32);
- function canCallExtended_immediate(address,address,bytes) external returns (bool);
- function canCallExtended_delay(address,address,bytes) external returns (uint32);
- function getAdminRestrictions_restricted(bytes) external returns (bool);
- function getAdminRestrictions_roleAdminId(bytes) external returns (uint64);
- function getAdminRestrictions_executionDelay(bytes) external returns (uint32);
- function hasRole_isMember(uint64,address) external returns (bool);
- function hasRole_executionDelay(uint64,address) external returns (uint32);
- function getAccess_since(uint64,address) external returns (uint48);
- function getAccess_currentDelay(uint64,address) external returns (uint32);
- function getAccess_pendingDelay(uint64,address) external returns (uint32);
- function getAccess_effect(uint64,address) external returns (uint48);
- function getTargetAdminDelay_after(address target) external returns (uint32);
- function getTargetAdminDelay_effect(address target) external returns (uint48);
- function getRoleGrantDelay_after(uint64 roleId) external returns (uint32);
- function getRoleGrantDelay_effect(uint64 roleId) external returns (uint48);
- function hashExecutionId(address,bytes4) external returns (bytes32) envfree;
- function executionId() external returns (bytes32) envfree;
- function getSelector(bytes) external returns (bytes4) envfree;
- function getFirstArgumentAsAddress(bytes) external returns (address) envfree;
- function getFirstArgumentAsUint64(bytes) external returns (uint64) envfree;
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Helpers โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- definition isOnlyAuthorized(bytes4 selector) returns bool =
- selector == to_bytes4(sig:labelRole(uint64,string).selector ) ||
- selector == to_bytes4(sig:setRoleAdmin(uint64,uint64).selector ) ||
- selector == to_bytes4(sig:setRoleGuardian(uint64,uint64).selector ) ||
- selector == to_bytes4(sig:setGrantDelay(uint64,uint32).selector ) ||
- selector == to_bytes4(sig:setTargetAdminDelay(address,uint32).selector ) ||
- selector == to_bytes4(sig:updateAuthority(address,address).selector ) ||
- selector == to_bytes4(sig:setTargetClosed(address,bool).selector ) ||
- selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector) ||
- selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector ) ||
- selector == to_bytes4(sig:revokeRole(uint64,address).selector );
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: executionId must be clean when not in the middle of a call โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant cleanExecutionId()
- executionId() == to_bytes32(0);
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: public role โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant publicRole(env e, address account)
- hasRole_isMember(e, PUBLIC_ROLE(), account) &&
- hasRole_executionDelay(e, PUBLIC_ROLE(), account) == 0 &&
- getAccess_since(e, PUBLIC_ROLE(), account) == 0 &&
- getAccess_currentDelay(e, PUBLIC_ROLE(), account) == 0 &&
- getAccess_pendingDelay(e, PUBLIC_ROLE(), account) == 0 &&
- getAccess_effect(e, PUBLIC_ROLE(), account) == 0;
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: hasRole is consistent with getAccess โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant hasRoleGetAccessConsistency(env e, uint64 roleId, address account)
- hasRole_isMember(e, roleId, account) == (roleId == PUBLIC_ROLE() || isSetAndPast(e, getAccess_since(e, roleId, account))) &&
- hasRole_executionDelay(e, roleId, account) == getAccess_currentDelay(e, roleId, account);
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Functions: canCall, canCallExtended, getAccess, hasRole, isTargetClosed and getTargetFunctionRole do NOT revert โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule noRevert(env e) {
- require nonpayable(e);
- require sanity(e);
- address caller;
- address target;
- bytes data;
- bytes4 selector;
- uint64 roleId;
- canCall@withrevert(e, caller, target, selector);
- assert !lastReverted;
- // require data.length <= max_uint64;
- //
- // canCallExtended@withrevert(e, caller, target, data);
- // assert !lastReverted;
- getAccess@withrevert(e, roleId, caller);
- assert !lastReverted;
- hasRole@withrevert(e, roleId, caller);
- assert !lastReverted;
- isTargetClosed@withrevert(target);
- assert !lastReverted;
- getTargetFunctionRole@withrevert(target, selector);
- assert !lastReverted;
- // Not covered:
- // - getAdminRestrictions (_1, _2 & _3)
- // - getSelector
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Functions: admin restrictions are correct โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getAdminRestrictions(env e, bytes data) {
- bool restricted = getAdminRestrictions_restricted(e, data);
- uint64 roleId = getAdminRestrictions_roleAdminId(e, data);
- uint32 delay = getAdminRestrictions_executionDelay(e, data);
- bytes4 selector = getSelector(data);
- if (data.length < 4) {
- assert restricted == false;
- assert roleId == 0;
- assert delay == 0;
- } else {
- assert restricted ==
- isOnlyAuthorized(selector);
- assert roleId == (
- (restricted && selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector)) ||
- (restricted && selector == to_bytes4(sig:revokeRole(uint64,address).selector ))
- ? getRoleAdmin(getFirstArgumentAsUint64(data))
- : ADMIN_ROLE()
- );
- assert delay == (
- (restricted && selector == to_bytes4(sig:updateAuthority(address,address).selector )) ||
- (restricted && selector == to_bytes4(sig:setTargetClosed(address,bool).selector )) ||
- (restricted && selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector))
- ? getTargetAdminDelay(e, getFirstArgumentAsAddress(data))
- : 0
- );
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Functions: canCall โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule canCall(env e) {
- address caller;
- address target;
- bytes4 selector;
- // Get relevant values
- bool immediate = canCall_immediate(e, caller, target, selector);
- uint32 delay = canCall_delay(e, caller, target, selector);
- bool closed = isTargetClosed(target);
- uint64 roleId = getTargetFunctionRole(target, selector);
- bool isMember = hasRole_isMember(e, roleId, caller);
- uint32 currentDelay = hasRole_executionDelay(e, roleId, caller);
- // Can only execute without delay in specific cases:
- // - target not closed
- // - if self-execution: `executionId` must match
- // - if third party execution: must be member with no delay
- assert immediate <=> (
- !closed &&
- (
- (caller == currentContract && executionId() == hashExecutionId(target, selector))
- ||
- (caller != currentContract && isMember && currentDelay == 0)
- )
- );
- // Can only execute with delay in specific cases:
- // - target not closed
- // - third party execution
- // - caller is a member and has an execution delay
- assert delay > 0 <=> (
- !closed &&
- caller != currentContract &&
- isMember &&
- currentDelay > 0
- );
- // If there is a delay, then it must be the caller's execution delay
- assert delay > 0 => delay == currentDelay;
- // Immediate execute means no delayed execution
- assert immediate => delay == 0;
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Functions: canCallExtended โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule canCallExtended(env e) {
- address caller;
- address target;
- bytes data;
- bytes4 selector = getSelector(data);
- bool immediate = canCallExtended_immediate(e, caller, target, data);
- uint32 delay = canCallExtended_delay(e, caller, target, data);
- bool enabled = getAdminRestrictions_restricted(e, data);
- uint64 roleId = getAdminRestrictions_roleAdminId(e, data);
- uint32 operationDelay = getAdminRestrictions_executionDelay(e, data);
- bool inRole = hasRole_isMember(e, roleId, caller);
- uint32 executionDelay = hasRole_executionDelay(e, roleId, caller);
- if (target == currentContract) {
- // Can only execute without delay in the specific cases:
- // - caller is the AccessManager and the executionId is set
- // or
- // - data matches an admin restricted function
- // - caller has the necessary role
- // - operation delay is not set
- // - execution delay is not set
- assert immediate <=> (
- (
- caller == currentContract &&
- data.length >= 4 &&
- executionId() == hashExecutionId(target, selector)
- ) || (
- caller != currentContract &&
- enabled &&
- inRole &&
- operationDelay == 0 &&
- executionDelay == 0
- )
- );
- // Immediate execute means no delayed execution
- // This is equivalent to "delay > 0 => !immediate"
- assert immediate => delay == 0;
- // Can only execute with delay in specific cases:
- // - caller is a third party
- // - data matches an admin restricted function
- // - caller has the necessary role
- // -operation delay or execution delay is set
- assert delay > 0 <=> (
- caller != currentContract &&
- enabled &&
- inRole &&
- (operationDelay > 0 || executionDelay > 0)
- );
- // If there is a delay, then it must be the maximum of caller's execution delay and the operation delay
- assert delay > 0 => to_mathint(delay) == max(operationDelay, executionDelay);
- } else if (data.length < 4) {
- assert immediate == false;
- assert delay == 0;
- } else {
- // results are equivalent when targeting third party contracts
- assert immediate == canCall_immediate(e, caller, target, selector);
- assert delay == canCall_delay(e, caller, target, selector);
- }
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getAccess โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getAccessChangeTime(uint64 roleId, address account) {
- env e1;
- env e2;
- // values before
- mathint getAccess1Before = getAccess_since(e1, roleId, account);
- mathint getAccess2Before = getAccess_currentDelay(e1, roleId, account);
- mathint getAccess3Before = getAccess_pendingDelay(e1, roleId, account);
- mathint getAccess4Before = getAccess_effect(e1, roleId, account);
- // time pass: e1 โ e2
- require clock(e1) <= clock(e2);
- // values after
- mathint getAccess1After = getAccess_since(e2, roleId, account);
- mathint getAccess2After = getAccess_currentDelay(e2, roleId, account);
- mathint getAccess3After = getAccess_pendingDelay(e2, roleId, account);
- mathint getAccess4After = getAccess_effect(e2, roleId, account);
- // member "since" cannot change as a consequence of time passing
- assert getAccess1Before == getAccess1After;
- // any change of any other value should be a consequence of the effect timepoint being reached
- assert (
- getAccess2Before != getAccess2After ||
- getAccess3Before != getAccess3After ||
- getAccess4Before != getAccess4After
- ) => (
- getAccess4Before != 0 &&
- getAccess4Before > clock(e1) &&
- getAccess4Before <= clock(e2) &&
- getAccess2After == getAccess3Before &&
- getAccess3After == 0 &&
- getAccess4After == 0
- );
- }
- rule getAccessChangeCall(uint64 roleId, address account) {
- env e;
- // sanity
- require sanity(e);
- // values before
- mathint getAccess1Before = getAccess_since(e, roleId, account);
- mathint getAccess2Before = getAccess_currentDelay(e, roleId, account);
- mathint getAccess3Before = getAccess_pendingDelay(e, roleId, account);
- mathint getAccess4Before = getAccess_effect(e, roleId, account);
- // arbitrary function call
- method f; calldataarg args; f(e, args);
- // values before
- mathint getAccess1After = getAccess_since(e, roleId, account);
- mathint getAccess2After = getAccess_currentDelay(e, roleId, account);
- mathint getAccess3After = getAccess_pendingDelay(e, roleId, account);
- mathint getAccess4After = getAccess_effect(e, roleId, account);
- // transitions
- assert (
- getAccess1Before != getAccess1After ||
- getAccess2Before != getAccess2After ||
- getAccess3Before != getAccess3After ||
- getAccess4Before != getAccess4After
- ) => (
- (
- f.selector == sig:grantRole(uint64,address,uint32).selector &&
- getAccess1After > 0
- ) || (
- (
- f.selector == sig:revokeRole(uint64,address).selector ||
- f.selector == sig:renounceRole(uint64,address).selector
- ) &&
- getAccess1After == 0 &&
- getAccess2After == 0 &&
- getAccess3After == 0 &&
- getAccess4After == 0
- )
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: isTargetClosed โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule isTargetClosedChangeTime(address target) {
- env e1;
- env e2;
- // values before
- bool isClosedBefore = isTargetClosed(e1, target);
- // time pass: e1 โ e2
- require clock(e1) <= clock(e2);
- // values after
- bool isClosedAfter = isTargetClosed(e2, target);
- // transitions
- assert isClosedBefore == isClosedAfter;
- }
- rule isTargetClosedChangeCall(address target) {
- env e;
- // values before
- bool isClosedBefore = isTargetClosed(e, target);
- // arbitrary function call
- method f; calldataarg args; f(e, args);
- // values after
- bool isClosedAfter = isTargetClosed(e, target);
- // transitions
- assert isClosedBefore != isClosedAfter => (
- f.selector == sig:setTargetClosed(address,bool).selector
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getTargetFunctionRole โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getTargetFunctionRoleChangeTime(address target, bytes4 selector) {
- env e1;
- env e2;
- // values before
- mathint roleIdBefore = getTargetFunctionRole(e1, target, selector);
- // time pass: e1 โ e2
- require clock(e1) <= clock(e2);
- // values after
- mathint roleIdAfter = getTargetFunctionRole(e2, target, selector);
- // transitions
- assert roleIdBefore == roleIdAfter;
- }
- rule getTargetFunctionRoleChangeCall(address target, bytes4 selector) {
- env e;
- // values before
- mathint roleIdBefore = getTargetFunctionRole(e, target, selector);
- // arbitrary function call
- method f; calldataarg args; f(e, args);
- // values after
- mathint roleIdAfter = getTargetFunctionRole(e, target, selector);
- // transitions
- assert roleIdBefore != roleIdAfter => (
- f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getTargetAdminDelay โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getTargetAdminDelayChangeTime(address target) {
- env e1;
- env e2;
- // values before
- mathint delayBefore = getTargetAdminDelay(e1, target);
- mathint delayPendingBefore = getTargetAdminDelay_after(e1, target);
- mathint delayEffectBefore = getTargetAdminDelay_effect(e1, target);
- // time pass: e1 โ e2
- require clock(e1) <= clock(e2);
- // values after
- mathint delayAfter = getTargetAdminDelay(e2, target);
- mathint delayPendingAfter = getTargetAdminDelay_after(e2, target);
- mathint delayEffectAfter = getTargetAdminDelay_effect(e2, target);
- assert (
- delayBefore != delayAfter ||
- delayPendingBefore != delayPendingAfter ||
- delayEffectBefore != delayEffectAfter
- ) => (
- delayEffectBefore > clock(e1) &&
- delayEffectBefore <= clock(e2) &&
- delayAfter == delayPendingBefore &&
- delayPendingAfter == 0 &&
- delayEffectAfter == 0
- );
- }
- rule getTargetAdminDelayChangeCall(address target) {
- env e;
- // values before
- mathint delayBefore = getTargetAdminDelay(e, target);
- mathint delayPendingBefore = getTargetAdminDelay_after(e, target);
- mathint delayEffectBefore = getTargetAdminDelay_effect(e, target);
- // arbitrary function call
- method f; calldataarg args; f(e, args);
- // values after
- mathint delayAfter = getTargetAdminDelay(e, target);
- mathint delayPendingAfter = getTargetAdminDelay_after(e, target);
- mathint delayEffectAfter = getTargetAdminDelay_effect(e, target);
- // if anything changed ...
- assert (
- delayBefore != delayAfter ||
- delayPendingBefore != delayPendingAfter ||
- delayEffectBefore != delayEffectAfter
- ) => (
- (
- // ... it was the consequence of a call to setTargetAdminDelay
- f.selector == sig:setTargetAdminDelay(address,uint32).selector
- ) && (
- // ... delay cannot decrease instantly
- delayAfter >= delayBefore
- ) && (
- // ... if setback is not 0, value cannot change instantly
- minSetback() > 0 => (
- delayBefore == delayAfter
- )
- ) && (
- // ... if the value did not change and there is a minSetback, there must be something scheduled in the future
- delayAfter == delayBefore && minSetback() > 0 => (
- delayEffectAfter >= clock(e) + minSetback()
- )
- // note: if there is no minSetback, and if the caller "confirms" the current value,
- // then this as immediate effect and nothing is scheduled
- ) && (
- // ... if the value changed, then no further change should be scheduled
- delayAfter != delayBefore => (
- delayPendingAfter == 0 &&
- delayEffectAfter == 0
- )
- )
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getRoleGrantDelay โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getRoleGrantDelayChangeTime(uint64 roleId) {
- env e1;
- env e2;
- // values before
- mathint delayBefore = getRoleGrantDelay(e1, roleId);
- mathint delayPendingBefore = getRoleGrantDelay_after(e1, roleId);
- mathint delayEffectBefore = getRoleGrantDelay_effect(e1, roleId);
- // time pass: e1 โ e2
- require clock(e1) <= clock(e2);
- // values after
- mathint delayAfter = getRoleGrantDelay(e2, roleId);
- mathint delayPendingAfter = getRoleGrantDelay_after(e2, roleId);
- mathint delayEffectAfter = getRoleGrantDelay_effect(e2, roleId);
- assert (
- delayBefore != delayAfter ||
- delayPendingBefore != delayPendingAfter ||
- delayEffectBefore != delayEffectAfter
- ) => (
- delayEffectBefore > clock(e1) &&
- delayEffectBefore <= clock(e2) &&
- delayAfter == delayPendingBefore &&
- delayPendingAfter == 0 &&
- delayEffectAfter == 0
- );
- }
- rule getRoleGrantDelayChangeCall(uint64 roleId) {
- env e;
- // values before
- mathint delayBefore = getRoleGrantDelay(e, roleId);
- mathint delayPendingBefore = getRoleGrantDelay_after(e, roleId);
- mathint delayEffectBefore = getRoleGrantDelay_effect(e, roleId);
- // arbitrary function call
- method f; calldataarg args; f(e, args);
- // values after
- mathint delayAfter = getRoleGrantDelay(e, roleId);
- mathint delayPendingAfter = getRoleGrantDelay_after(e, roleId);
- mathint delayEffectAfter = getRoleGrantDelay_effect(e, roleId);
- // if anything changed ...
- assert (
- delayBefore != delayAfter ||
- delayPendingBefore != delayPendingAfter ||
- delayEffectBefore != delayEffectAfter
- ) => (
- (
- // ... it was the consequence of a call to setTargetAdminDelay
- f.selector == sig:setGrantDelay(uint64,uint32).selector
- ) && (
- // ... delay cannot decrease instantly
- delayAfter >= delayBefore
- ) && (
- // ... if setback is not 0, value cannot change instantly
- minSetback() > 0 => (
- delayBefore == delayAfter
- )
- ) && (
- // ... if the value did not change and there is a minSetback, there must be something scheduled in the future
- delayAfter == delayBefore && minSetback() > 0 => (
- delayEffectAfter >= clock(e) + minSetback()
- )
- // note: if there is no minSetback, and if the caller "confirms" the current value,
- // then this as immediate effect and nothing is scheduled
- ) && (
- // ... if the value changed, then no further change should be scheduled
- delayAfter != delayBefore => (
- delayPendingAfter == 0 &&
- delayEffectAfter == 0
- )
- )
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getRoleAdmin & getRoleGuardian โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getRoleAdminChangeCall(uint64 roleId) {
- // values before
- mathint adminIdBefore = getRoleAdmin(roleId);
- // arbitrary function call
- env e; method f; calldataarg args; f(e, args);
- // values after
- mathint adminIdAfter = getRoleAdmin(roleId);
- // transitions
- assert adminIdBefore != adminIdAfter => f.selector == sig:setRoleAdmin(uint64,uint64).selector;
- }
- rule getRoleGuardianChangeCall(uint64 roleId) {
- // values before
- mathint guardianIdBefore = getRoleGuardian(roleId);
- // arbitrary function call
- env e; method f; calldataarg args; f(e, args);
- // values after
- mathint guardianIdAfter = getRoleGuardian(roleId);
- // transitions
- assert guardianIdBefore != guardianIdAfter => (
- f.selector == sig:setRoleGuardian(uint64,uint64).selector
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getNonce โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getNonceChangeCall(bytes32 operationId) {
- // values before
- mathint nonceBefore = getNonce(operationId);
- // reasonable assumption
- require nonceBefore < max_uint32;
- // arbitrary function call
- env e; method f; calldataarg args; f(e, args);
- // values after
- mathint nonceAfter = getNonce(operationId);
- // transitions
- assert nonceBefore != nonceAfter => (
- f.selector == sig:schedule(address,bytes,uint48).selector &&
- nonceAfter == nonceBefore + 1
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ State transitions: getSchedule โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule getScheduleChangeTime(bytes32 operationId) {
- env e1;
- env e2;
- // values before
- mathint scheduleBefore = getSchedule(e1, operationId);
- // time pass: e1 โ e2
- require clock(e1) <= clock(e2);
- // values after
- mathint scheduleAfter = getSchedule(e2, operationId);
- // transition
- assert scheduleBefore != scheduleAfter => (
- scheduleBefore + expiration() > clock(e1) &&
- scheduleBefore + expiration() <= clock(e2) &&
- scheduleAfter == 0
- );
- }
- rule getScheduleChangeCall(bytes32 operationId) {
- env e;
- // values before
- mathint scheduleBefore = getSchedule(e, operationId);
- // arbitrary function call
- method f; calldataarg args; f(e, args);
- // values after
- mathint scheduleAfter = getSchedule(e, operationId);
- // transitions
- assert scheduleBefore != scheduleAfter => (
- (f.selector == sig:schedule(address,bytes,uint48).selector && scheduleAfter >= clock(e)) ||
- (f.selector == sig:execute(address,bytes).selector && scheduleAfter == 0 ) ||
- (f.selector == sig:cancel(address,address,bytes).selector && scheduleAfter == 0 ) ||
- (f.selector == sig:consumeScheduledOp(address,bytes).selector && scheduleAfter == 0 ) ||
- (isOnlyAuthorized(to_bytes4(f.selector)) && scheduleAfter == 0 )
- );
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Functions: restricted functions can only be called by owner โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule restrictedFunctions(env e) {
- require nonpayable(e);
- require sanity(e);
- method f;
- calldataarg args;
- f(e,args);
- assert (
- f.selector == sig:labelRole(uint64,string).selector ||
- f.selector == sig:setRoleAdmin(uint64,uint64).selector ||
- f.selector == sig:setRoleGuardian(uint64,uint64).selector ||
- f.selector == sig:setGrantDelay(uint64,uint32).selector ||
- f.selector == sig:setTargetAdminDelay(address,uint32).selector ||
- f.selector == sig:updateAuthority(address,address).selector ||
- f.selector == sig:setTargetClosed(address,bool).selector ||
- f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector
- ) => (
- hasRole_isMember(e, ADMIN_ROLE(), e.msg.sender) || e.msg.sender == currentContract
- );
- }
- rule restrictedFunctionsGrantRole(env e) {
- require nonpayable(e);
- require sanity(e);
- uint64 roleId;
- address account;
- uint32 executionDelay;
- // We want to check that the caller has the admin role before we possibly grant it.
- bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender);
- grantRole(e, roleId, account, executionDelay);
- assert hasAdminRoleBefore || e.msg.sender == currentContract;
- }
- rule restrictedFunctionsRevokeRole(env e) {
- require nonpayable(e);
- require sanity(e);
- uint64 roleId;
- address account;
- // This is needed if roleId is self-administered, the `revokeRole` call could target
- // e.msg.sender and remove the very role that is necessary for authorizing the call.
- bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender);
- revokeRole(e, roleId, account);
- assert hasAdminRoleBefore || e.msg.sender == currentContract;
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Functions: canCall delay is enforced for calls to execute (only for others target) โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- // getScheduleChangeCall proves that only {schedule} can set an operation schedule to a non 0 value
- rule callDelayEnforce_scheduleInTheFuture(env e) {
- address target;
- bytes data;
- uint48 when;
- // Condition: calling a third party with a delay
- mathint delay = canCallExtended_delay(e, e.msg.sender, target, data);
- require delay > 0;
- // Schedule
- schedule(e, target, data, when);
- // Get operation schedule
- mathint timepoint = getSchedule(e, hashOperation(e.msg.sender, target, data));
- // Schedule is far enough in the future
- assert timepoint == max(clock(e) + delay, when);
- }
- rule callDelayEnforce_executeAfterDelay(env e) {
- address target;
- bytes data;
- // Condition: calling a third party with a delay
- mathint delay = canCallExtended_delay(e, e.msg.sender, target, data);
- // Get operation schedule before
- mathint scheduleBefore = getSchedule(e, hashOperation(e.msg.sender, target, data));
- // Do call
- execute@withrevert(e, target, data);
- bool success = !lastReverted;
- // Get operation schedule after
- mathint scheduleAfter = getSchedule(e, hashOperation(e.msg.sender, target, data));
- // Can only execute if delay is set and has passed
- assert success => (
- delay > 0 => (
- scheduleBefore != 0 &&
- scheduleBefore <= clock(e)
- ) &&
- scheduleAfter == 0
- );
- }
|