Capabilities
compose-capability
Use compose-capability
to compose and grant capabilities in a nested structure to control the scope of how the capabilities are applied.
By convention, capabilities are defined using all uppercase letters.
With this function, you can define the specified CAPABILITY
within the context of an outer defcap
declaration.
The function is only valid within the distinct defcap
body of its outer capability, such that the CAPABILITY
you specify for the compose-capability
function is included when you call the with-capability
function for its outer capability.
For example, if you call (with-capability (OUTER-CAP) OUTER-BODY)
and the OUTER-CAP
declaration includes the (compose-capability (INNER-CAP))
function, the INNER-CAP
capability is granted in the scope of the OUTER-BODY
logic.
Basic syntax
To compose and grant a specified CAPABILITY
within an outer capability body, use the following syntax:
(compose-capability CAPABILITY)
(compose-capability CAPABILITY)
Arguments
Use the following argument to specify the CAPABILITY
for the compose-capability
Pact function.
Argument | Type | Description |
---|---|---|
CAPABILITY | capability | Specifies the capability to include in the scope of an outer capability. |
Return values
The compose-capability
function returns a boolean value to indicate success or failure in requesting the grant of the specified CAPABILITY
.
Examples
The following example demonstrates how to use the compose-capability
function within the body of the TRANSFER
capability and include the DEBIT and CREDIT capabilities when the with-capability
function is called:
(defcap TRANSFER:bool ( id:string sender:string receiver:string amount:decimal ) @managed amount TRANSFER-mgr (enforce-unit id amount) (enforce (> amount 0.0) "Amount must be positive") (compose-capability (DEBIT id sender)) (compose-capability (CREDIT id receiver)))... (with-capability (TRANSFER id sender receiver amount) ... )
(defcap TRANSFER:bool ( id:string sender:string receiver:string amount:decimal ) @managed amount TRANSFER-mgr (enforce-unit id amount) (enforce (> amount 0.0) "Amount must be positive") (compose-capability (DEBIT id sender)) (compose-capability (CREDIT id receiver)))... (with-capability (TRANSFER id sender receiver amount) ... )
emit-event
Use emit-event
to emit a specified CAPABILITY
as an event without evaluating the body of the capability.
This function fails if the specified CAPABILITY
doesn't include the @managed
or @event
keyword in its declaration.
By convention, capabilities are defined using all uppercase letters.
Basic syntax
To emit a CAPABILITY
as an event without evaluating its body, use the following syntax:
(emit-event CAPABILITY)
(emit-event CAPABILITY)
Arguments
Use the following argument to specify the CAPABILITY
for the emit-event
Pact function.
Argument | Type | Description |
---|---|---|
CAPABILITY | capability | Specifies the capability to emit as an event. |
Return values
The emit-event
function returns a boolean value indicating success or failure of emitting the event.
Examples
The following example demonstrates how to use the emit-event
function to emit an event for the TRANSFER
capability with the parameters "Bob"
, "Alice"
, and 12.0
:
pact> (emit-event (TRANSFER "Bob" "Alice" 12.0))true
pact> (emit-event (TRANSFER "Bob" "Alice" 12.0))true
The function returns a boolean value indicating the success or failure of emitting the event.
install-capability
Use install-capability
to specify and provision a managed capability.
Managed capabilities are defined in defcap
declarations that include the @managed
keyword. The @managed
keyword designates a single parameter to be managed by a specified management function.
After a capability is installed, it must still be brought into scope using the with-capability
function.
When the capability is brought into scope, its management function is invoked to validate the request.
The management function takes the type of the managed parameter, executes the logic required to validate the requested capability or perform the managed operation, and returns the new managed value that results from the request.
The type signature for the management function is managed:<type> requested:<type> -> <type>
, where <type>
indicates the type of the managed parameter.
For example, assume you define a managed capability as:
(defcap FOO (bar:string baz:integer) @managed baz FOO-mgr ...)
(defcap FOO (bar:string baz:integer) @managed baz FOO-mgr ...)
The management function for this capability would be:
(defun FOO-mgr:integer (managed:integer requested:integer) ...)
(defun FOO-mgr:integer (managed:integer requested:integer) ...)
Any capability that has static unmanaged parameters will invoke the management function with the current managed value and that of the requested capability.
The function should perform whatever logic, presumably linear, to validate the request, and return the new managed value representing the balance
of the request.
Note that signatures scoped to a managed capability cause the capability to be automatically provisioned in a manner similar to how capabilities are installed with this function.
By convention, capabilities are defined using all uppercase letters.
Basic syntax
To specify and provision a managed capability, use the following syntax:
(install-capability CAPABILITY)
(install-capability CAPABILITY)
Arguments
Use the following argument to specify the capability you want to install using the install-capability
Pact function.
Argument | Type | Description |
---|---|---|
CAPABILITY | any | Specifies the capability to be installed. |
Return value
The install-capability
function returns a boolean value indicating the success or failure of the installation, along with a string message providing additional information.
Examples
The following example demonstrates how to use the install-capability
to install a capability named coin.TRANSFER
with specified parameters:
(install-capability (coin.TRANSFER ESCROW_ID merchant merchant-payout))
(install-capability (coin.TRANSFER ESCROW_ID merchant merchant-payout))
The following example illustrates the definition for a capability with a management function and a managed parameter.
(defcap TRANSFER:bool ( id:string sender:string receiver:string amount:decimal ) @managed amount TRANSFER-mgr (enforce-unit id amount) (enforce (> amount 0.0) "Amount must be positive") (compose-capability (DEBIT id sender)) (compose-capability (CREDIT id receiver)) ) (defun TRANSFER-mgr:decimal ( managed:decimal requested:decimal ) (let ((newbal (- managed requested))) (enforce (>= newbal 0.0) (format "TRANSFER exceeded for balance {}" [managed])) newbal) )
(defcap TRANSFER:bool ( id:string sender:string receiver:string amount:decimal ) @managed amount TRANSFER-mgr (enforce-unit id amount) (enforce (> amount 0.0) "Amount must be positive") (compose-capability (DEBIT id sender)) (compose-capability (CREDIT id receiver)) ) (defun TRANSFER-mgr:decimal ( managed:decimal requested:decimal ) (let ((newbal (- managed requested))) (enforce (>= newbal 0.0) (format "TRANSFER exceeded for balance {}" [managed])) newbal) )
The following example demonstrates the use of install-capability
in the Pact REPL to install a capability named PAY
with specified parameters:
pact> (install-capability (PAY "alice" "bob" 10.0))
pact> (install-capability (PAY "alice" "bob" 10.0))
If the PAY
capability is installed successfully, the function returns a boolean value indicating success.
If the capability isn't installed, the function returns an error message indicating the reason for failure.
require-capability
Use require-capability
to require a specific CAPABILITY
to be granted before allowing the current body of code to be executed.
If the required capability isn't found in the environment, the code fails to execute.
By convention, capabilities are defined using all uppercase letters.
Basic syntax
To test whether a specific CAPABILITY
has been granted before executing a portion of code in a contract, use the following syntax:
(require-capability CAPABILITY)
(require-capability CAPABILITY)
Arguments
Use the following argument to specify the CAPABILITY
to be tested for using the require-capability
Pact function.
Argument | Type | Description |
---|---|---|
CAPABILITY | Specifies the capability that must be granted before executing a certain portion of code. |
Return value
The require-capability
function returns a boolean value indicating whether the specified CAPABILITY
exists in the environment.
Examples
The following example demonstrates how to use the require-capability
function to check whether the capability to transfer funds from one source to another has been granted:
(require-capability (TRANSFER src dest))
(require-capability (TRANSFER src dest))
If the capability isn't found, the function fails.
The following example uses the require-capability
function to create a guard that ensure both the GAS and ALLOW_GAS capabilities have been granted:
(defun gas-payer-guard () (require-capability (GAS)) (require-capability (ALLOW_GAS)))
(defun gas-payer-guard () (require-capability (GAS)) (require-capability (ALLOW_GAS)))
with-capability
Use with-capability
to apply the access to a specific capability to execute a body of code.
This function ensures that an elevated privilege—defined as a capability using a defcap
code block—is present during the execution of the provided body of code.
You can only call the with-capability
function in the same module that contains the corresponding defcap
declaration.
If the token that grants permission to use the specified capability isn't found, the with-capability
evaluates the capability definition to install or grant the permission token.
The permission token is automatically revoked after executing the code body.
Nested with-capability
calls for the same permission token detect the presence of the token and execute the body without reapplying the capability.
By convention, capabilities are defined using all uppercase letters.
Basic syntax
To request the grant of an acquired CAPABILITY
, use the following syntax:
(with-capability CAPABILITY body)
(with-capability CAPABILITY body)
Arguments
Use the following arguments to specify the name of the capability and the body of expressions to be executed using the with-capability
Pact function.
Argument | Type | Description |
---|---|---|
CAPABILITY | capability | Specifies the name of the capability to grant access to. |
body | any | Specifies the body of expressions to be executed using the granted capability. |
Return value
The with-capability
function returns the result of executing the provided body of code using the granted capability.
Examples
The following example demonstrates how to use the with-capability
function to request access to the UPDATE-USERS
capability to execute the code that updates user information:
(with-capability (UPDATE-USERS id) (update users id { salary: new-salary }))
(with-capability (UPDATE-USERS id) (update users id { salary: new-salary }))
In this example, the with-capability
function ensures that a sensitive operation can only be executed with an elevated permission granted using the UPDATE-USERS
capability.