Daml REPL¶
The Daml REPL allows you to use the Daml Script API interactively. This is useful for debugging and for interactively inspecting and manipulating a ledger.
Usage¶
First create a new project based on the script-example
template. Take a look at the documentation for
Daml Script for details on this template.
daml new script-example --template script-example # create a project called script-example based on the template
cd script-example # switch to the new project
Now, build the project and start Daml Sandbox, the in-memory
ledger included in the SDK. Note that we are starting Sandbox in
wallclock mode. Static time is not supported in daml repl
.
daml build
daml sandbox --wall-clock-time --port=6865 --dar .daml/dist/script-example-0.0.1.dar
Now that the ledger has been started, you can launch the REPL in a separate terminal using the following command.
daml repl --ledger-host=localhost --ledger-port=6865 .daml/dist/script-example-0.0.1.dar --import script-example
The --ledger-host
and --ledger-port
parameters point to the
host and port your ledger is running on. In addition to that, you also
need to pass in the name of a DAR containing the templates and other
definitions that will be accessible in the REPL. We also specify that we want
to import all modules from the script-example
package. If your modules
provide colliding definitions you can also import modules individually from
within the REPL. Note that you can also specify multiple DARs and they
will all be available.
You should now see a prompt looking like
daml>
You can think of this prompt like a line in a do
-block of the
Script
action. Each line of input has to have one of the following
two forms:
- An expression
expr
of typeScript a
for some typea
. This will execute the script and print the result ifa
is an instance ofShow
and not()
. - A pure expression
expr
of typea
for some typea
wherea
is an instance ofShow
. This will evaluateexpr
and print the result. If you are only interest in pure expressions you can also use Daml REPL without connecting to a ledger. - A binding of the form
pat <- expr
wherepat
is pattern, e.g., a variable namex
to bind the result to andexpr
is an expression of typeScript a
. This will execute the script and match the result against the patternpat
bindings the matches to the variables in the pattern. You can then use those variables on subsequent lines. - A
let
binding of the formlet pat = y
, wherepat
is a pattern andy
is a pure expression orlet f x = y
to define a function. The bound variables can be used on subsequent lines. - Next to Daml code the REPL also understands REPL commands which are prefixed
by
:
. Enter:help
to see a list of supported REPL commands.
First create two parties: A party with the display name "Alice"
and the party id "alice"
and a party with the display name
"Bob"
and the party id "bob"
.
daml> alice <- allocatePartyWithHint "Alice" (PartyIdHint "alice")
daml> bob <- allocatePartyWithHint "Bob" (PartyIdHint "bob")
Next, create a CoinProposal
from Alice
to Bob
daml> submit alice (createCmd (CoinProposal (Coin alice bob)))
As Bob, you can now get the list of active CoinProposal
contracts
using the query
function. The debug : Show a => a -> Script ()
function can be used to print values.
daml> proposals <- query @CoinProposal bob
daml> debug proposals
[Daml.Script:39]: [(<contract-id>,CoinProposal {coin = Coin {issuer = 'alice', owner = 'bob'}})]
Finally, accept all proposals using the forA
function to iterate
over them.
daml> forA proposals $ \(contractId, _) -> submit bob (exerciseCmd contractId Accept)
Using the query
function we can now verify that there is one
Coin
and no CoinProposal
:
daml> coins <- query @Coin bob
daml> debug coins
[Daml.Script:39]: [(<contract-id>,Coin {issuer = 'alice', owner = 'bob'})]
daml> proposals <- query @CoinProposal bob
[Daml.Script:39]: []
To exit daml repl
press Control-D
.
What is in scope at the prompt?¶
In the prompt, all modules from DALFs specified in --import
are
imported automatically. In addition to that, the Daml.Script
module is also imported and gives you access to the Daml Script API.
You can use the commands :module + ModA ModB …
to import additional modules
and :module - ModA ModB …
to remove previously added imports. Modules can
also be imported using regular import declarations instead of module +
.
The command :show imports
lists the currently active imports.
daml> import DA.Time
daml> debug (days 1)
Using Daml REPL without a Ledger¶
If you are only interested in pure expressions, e.g., because you want
to test how some function behaves you can omit the --ledger-host
and -ledger-port
parameters. Daml REPL will work as usual but any
attempts to call Daml Script APIs that interact with the ledger, e.g.,
submit
will result in the following error:
daml> java.lang.RuntimeException: No default participant
Connecting via TLS¶
You can connect to a ledger that requires TLS by passing --tls
. A
custom root certificate used for validating the server certificate can
be set via --cacrt
. Finally, you can also enable client
authentication by passing --pem client.key --crt client.crt
. If
--cacrt
or --pem
and --crt
are passed TLS is automatically
enabled so --tls
is redundant.
Connection to a Ledger with Authorization¶
If your ledger requires an authorization token you can pass it via
--access-token-file
.
Using Daml REPL to convert to JSON¶
Using the :json
command you can encode serializable Daml expressions as
JSON. For example using the definitions and imports from above:
daml> :json days 1
{"microseconds":86400000000}
daml> :json map snd coins
[{"issuer":"alice","owner":"bob"}]