CaveatEnforcer
contracts enable a delegator to place granular restrictions on the delegations, So dApps can create highly specific delegations that permit actions only under certain conditions. Caveats serve as a mechanism to verify the state both before and after execution, but not the final state post-redemption. However, caveats can still influence the final state of the transaction.
NOTE: Each
CaveatEnforcer
is called by theDelegationManager
contract. This is important when storing data in theCaveatEnforcer
, asmsg.sender
will always be the address of theDelegationManager
.
NOTE: There is no guarantee that the action will be executed. Keep this in mind when designing Caveat Enforcers. If your logic depends on the action being performed, ensure you use the afterHook and afterAllHook methods to validate any expected state changes.
The execution order of the caveat hooks may vary depending on the delegation manager implementation, but they are designed to be used in the following sequence:
beforeAllHook
: Called for all delegations before any executions begin, proceeding from the leaf delegation to the root delegation.beforeHook
: Called before each individual execution tied to a delegation, also proceeding from the leaf delegation to the root delegation.- Execution: The specified execution is performed.
afterHook
: Called after each individual execution tied to a delegation, proceeding from the root delegation back to the leaf delegation.afterAllHook
: Called for all delegations after all executions have been processed, proceeding from the root delegation back to the leaf delegation.
The NativeTokenPaymentEnforcer
is a mechanism used within a delegation (D1) that requires a payment in order to allow the execution of an action. In this enforcer, the redeemer provides a secondary delegation (D2) that grants an allowance, which the enforcer redeems to process the payment.
This redemption may alter the state of other contracts. For example, the balance of the delegator providing the allowance will decrease, while the balance of the recipient specified by the payment delegation will increase. These state changes can impact other enforcers that rely on balance validations, depending on their order in the caveats array.
Consider a scenario where D1 includes an array of caveats: one caveat is the NativeBalanceGteEnforcer
, which verifies that Bob’s balance has increased as a result of the execution attached to D1. The second caveat is the NativeTokenPaymentEnforcer
, which deducts from Bob’s balance by redeeming D2. If these enforcers are not correctly ordered, they could conflict. For instance, if the NativeTokenPaymentEnforcer
is executed before the NativeBalanceGteEnforcer
, Bob’s balance would be reduced first, potentially causing the NativeBalanceGteEnforcer
to fail its validation of ensuring Bob’s balance exceeds a certain threshold.
Because the NativeTokenPaymentEnforcer
modifies the state of external contracts, it is essential to carefully order enforcers in the delegation to prevent conflicts. The enforcers are designed to protect the execution process, but they do not guarantee a final state after the redemption. This means that even if the NativeBalanceGteEnforcer
validates Bob’s balance at one point, subsequent enforcers, such as the NativeTokenPaymentEnforcer
, may modify it later.