Just one clarification on the difference between managed and unmanaged
capabilities before I answer your questions, since they are a little bit
different from the picture described above:
Capabilities are never "changed": they are only granted by with-capability
.
What happens with a managed capability is that, in addition to defining a
capability, it also defines a "resource" that is decreased in some way
whenever the associated capability is granted.
You can think of it like this: stateless capabilities are granted by
with-capability
and demanded by require-capability
; managed capabilities
setup an initial resource by install-capability
(which ought to have a
different name, more like install-resource
), deduct from the resource AND
grant by with-capability
, and are demanded by require-capability
.
Note how install-capability
is unique to managed capabilities, while
with-capability
does double duty. In a way, with-capability
is really two
separate operations composed together in the managed case:
;; You write this:
(install-capability (TRANSFER FROM TO PROVIDED))
...
(with-capability (TRANSFER FROM TO REQUESTED) EXPR)
;; ----
;; But what it does internally is more like this:
(install-capability (TRANSFER FROM TO) PROVIDED)
...
(if (already-granted-p (TRANSFER FROM TO))
EXPR
(consume-resource (TRANSFER FROM TO) REQUESTED
(with-capability (TRANSFER FROM TO) EXPR)))
You can see here that (TRANSFER FROM TO)
identifies the capability -- in
both the managed and unmanaged cases. The extra parameter relating to the
resource is what's new in the managed case. The fact that it gets passed as an
argument in (TRANSFER FROM TO AMOUNT)
to both install-capability
and
with-capability
is just a syntactic convenience. Which brings us directly to
your questions...
Where do the parameters come from in TRANSFER_mgr? (Is managed first the
amount provided via @managed and then the result of prior calls to
TRANSFER_mgr? Is requested the amount provided in calls to with-capability
in the module code?)
The @managed
keyword identifies the argument referring to the resource
parameter. In the case of TRANSFER
, this is the amount
argument, as
declared by:
@managed amount TRANSFER_mgr
This also states that TRANSFER_mgr
will receive two arguments related to the
amount: The first being the current amount of the resource, and the second
being the proposed amount to be deducted by the call to with
.
(defun TRANSFER_mgr:decimal (current:decimal requested:decimal)
For install-capability
, the amount
argument passed is the initial amount
of the resource. For with-capability
, the amount
argument is the amount of
resource being requested before the capability can be granted. In that case,
the current amount that is passed as the first argument to the management function
comes from the current state of the Pact evaluator.
How many arguments can @managed take? (Is it a single argument, or can there
be many? If many, how does that affect the parameters that the manager
function takes?)
@managed
allows for only a single argument, although that argument could be
a list or an object. For example, you could provide a list of names as the
"resource", and write a management functions that removes names from the list
as they are "used"; or the resource could be an object, if you wanted a single
managed capability to manage multiple resources.
In practice, however, the managed capability feature is used mainly by coin
contracts to govern transfer amounts.
When is the manager function invoked? (Is it on calls to with-capability for
this capability?)
The manager function has the job of both confirming that sufficient resource
exists, and deducting from the resource. It is called whenever
with-capability
is used and the capability has not yet been granted.