Built in Functions
Welcome to this introduction to some more advanced Pact built-in functions.
In this guide, we will go through and explain specific built-in functions that are listed in the pact reference page.
Simple Payment Verification
The quick explanation of the verify-spv
function can be found
here.
verify-spv
takes some blob, a binary data type, provided by the user and runs
code on it that would be too expensive to do in pact. Thus, in the statement
(verify-spv "ETH")
, "ETH" has code in the chainweb-node binary to validate
that the data is well-formed and returns a normal Pact object with all of the
data. It is NOT an oracle; it is a tool that an oracle would use to guarantee
data integrity.
Here
is example code using the chain relay to validate a proof that the sender has
retrieved from infura.
In a REPL script, all you can do is simulate this, as the "ETH" support does not
ship with Pact. The
mock-spv
REPL native allows you to mock a call to verify-spv
(github).
You can simulate any protocol desired. However, getting a protocol added to
Chainweb requires support in the Chainweb binary and is a hard fork. Therefore,
the community would need to spearhead by opening a pull request for a KIP,
Kadena Improvement Process. For instance, to support BTC proofs, a KIP would be
opened to add verify-spv "BTC"
to discuss and specify what is needed.
Afterwards, the Haskell support would need to be implemented and released with a
Chainweb version upgrade. Currently Chainweb supports "ETH" and "TXOUT" only
(github).
TXOUT is the same as what is used for crosschain, but should not be used for "once-and-only-once" which demands using a cross-chain defpact to enforce. TXOUT can be used for "broadcast" of e.g. a price feed to other chains.
::
Managed Capabilities
Documentation for understanding capabilities can be found here.
The capability built-in functions can be found here.
Before diving into managed capabilities, it is important to understand the
difference between managed and unmanaged capabilities. Capabilities are never
"changed" since they are only granted by with-capability
. In addition to
defining a capability, managed capabilities also define a "resource" that is
decreased whenever the associated capability is granted.
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
, then deduct from the resource, granted by
with-capability
, and are demanded by require-capability
.
Note that install-capability
is unique to managed capabilities while
with-capability
does double duty. with-capability
essentially is two
separate operations composed together in the managed case:
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.
Now lets take a look at the TRANSFER managed capability to get a better understanding.
The @managed
keyword identifies the argument referring to the resource
parameter. In the case of TRANSFER
, this is the amount
argument, as declared
by:
This also states that TRANSFER_mgr
will receive two arguments related to the
amount:
- The current amount of the resource
- The proposed amount to be deducted by the call to
with
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.
@managed
allows for only a single argument, but lists and objects are valid
arguments too. For example, you could provide a list of names as the "resource"
and write a management function that removes names from the list as they are
"used." If you wanted a single managed capability to manage multiple resources,
you could use an object instead.
;; 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 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)))
@managed amount TRANSFER_mgr
@managed amount TRANSFER_mgr
(defun TRANSFER_mgr:decimal (current:decimal requested:decimal)
(defun TRANSFER_mgr:decimal (current:decimal requested:decimal)
The managed capability feature is most commonly used by coin contracts to govern transfer amounts.
The manager function has the job of 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.
Select
The select
built-in function can be found
here.
The select
function is able to pull information from a table under specific
conditions.
This is an example of finding people in a table with a single condition, having "Fatima" as their first or last name.
(select people ['firstName,'lastName] (where 'name (= "Fatima")))
(select people ['firstName,'lastName] (where 'name (= "Fatima")))
But, what if you want to use multiple clauses to get a more specific result.
In this example, you can use the following format to find someone with the name "Fatima" that is older than 40.
(select people ['firstName,'lastName] (and? (where 'name (= "Fatima")) (where 'age (> 40))))
(select people ['firstName,'lastName] (and? (where 'name (= "Fatima")) (where 'age (> 40))))