Permission
The swissKnife library provides a bunch of other cool stuff, like ACL (Access-Control List) permission leveling.
The subjectIsAuthorizedFor
and authorizedOnly
modifiers here are provided by the LazyInitCapableElement
contract. They can be used to build sophisticated permission systems for your applications and protocols, setting which addresses or contracts can perform actions or trigger some specific methods in all contracts that integrate the LazyInitCapableElement
.
You can use these utility functions to create complex, multi-layer permission systems.
How Permission Levels Work
Multi-layer permission systems allow you to define who can and who can’t perform actions on your smart contracts. You can even define who can and who can’t use each of a contract’s specific internal functions.
This is possible with any contract that integrates LazyInitCapable
Element, and thus also DynamicMetadataCapableElement
and the standard Factory
contract.
subjectIsAuthorizedFor
This is a view function:
Its purpose is to define that an address (subject
) can call a function (selector
) to trigger a behavior of a contract (location
) passing a value
and a payload
.
This is a permission layer. You can give it a quantitative aspect too, so that the address can only operate within a defined balance range.
How the subjectIsAuthorizedFor function works
The function takes all the input parameters and passes them to the _subjectIsAuthorizedFor
function. This is a virtual function provided by the LazyInitCapableElement
contract so that its behavior can be overridden by an inheriting contract to create customized permission logic.
The function has two boolean outputs, the first is childElementValidationIsConsistent
and the second is childElementValidationResult
. Since in Solidity an undefined
or a null
is expressed as false
, the first output represents if the result is consistent. In this way, a null
or undefined
result doesn't affect the second childElementValidationResult
. In fact, the second parameter represents the "real" result of the function.
So the subjectIsAuthorizedFor
has only one output boolean value that is the permission result:
If
childElementValidationIsConsistent
, the output result is represented bychildElementValidationResult
of the_subjectIsAuthorizedFor
.if the
subject
is equal to thehost
, the output result is true.if the
host
address is not a contract, the output result is false.If the
host
address is a contract and it implements thelazyInitCapableElement
, thesubjectIsAuthorizedFor
function on thathost
address is called.
authorizedOnly
subjectIsAuthorizedFor
is used to build the authorizedOnly
modifier:
Here, _authorizedOnly
is simply the result of the subjectIsAuthorizedFor
view function:
By overriding _subjectIsAuthorizedFor
in your inheriting child contract, you can create a customized authorizedOnly
modifier, which you can use in your application or protocol to distinguish who can do what, e.g. change a host, set an organization’s component, change the model contract to clone in a Factory, etc.
Integrate Your Smart Contract With a Permission Level
You don’t have to build a complex permissions system, and if you choose not to, your contract will follow the default behavior where only the host address (which is defined at the LazyInitCapableElement
level) can call functions integrated with the authorizedOnly
modifier; no further restrictions will be applied.
In fact, if the _subjectIsAuthorizedFor
is not overridden, the default result of chidlElementValidationIsConsistent
is false and so the if
is skipped.
If you want to customize your contract’s permission levels coding on your own, build your own custom authorizedOnly
modifier and use it to override the _subjectIsAuthorizedFor
function.
For some examples of customized permission systems in Factory-compliant contracts, see below.
Example
Here is a practical example of a smart contract that integrates customized permission levels: the Organization
contract.
Only active components attached to the Organization have writing rights on other components of the Organization, as well as on the Organization itself. The authorizedOnly
modifier is customized to represent this behavior.
As established earlier, authorizedOnly
is built by the _subjectIsAuthorizedFor
function; so, an organization must implement _subjectIsAuthorizedFor
:
The first part of the function says that no one can call the setHost function to change the host of an Organization.
The second part says the function’s outputs, in all other cases, are composed as:
Here, the true parameter refers to childElementValidationIsConsistent
, and the second one refers to childElementValidationResult
. Keep in mind that if childElementValidationIsConsistent
is true, the final result of subjectIsAuthorizedFor
is represented by childElementValidationResult
.
In this case, childElementValidationResult
is the result of the isActive
function. This function checks if the subject is an active key and therefore an active Component. In this case, the result will be true. But if the subject doesn’t correspond to an active key, the result will be false, and it will have no permission to act on the Organization.
The authorizedOnly
modifier represents the result behavior explained above:
authorizedOnly
will only ever be an active Component expressed in the _subjectIsAuthorizedFor
function.
To summarize: the _subjectIsAuthorizedFor
and authorizedOnly
modifiers can be customized by developers as they see fit; i.e, as required by the requirements and business logic of their protocols and applications.
Last updated