Domain Specific Language (DSL) Documentation

This is the documentation for the txtx language. Txtx files that you write describe which blockchains and networks to use, what data to retrieve, and what transactions to broadcast. The txtx language also lets you define dependencies between resources and create multiple similar constructs from a single block.

Syntax

Txtx files contain a series of code blocks that look something like this:

input "query_path" {
  description = "An input that can be edited in the web UI!"
  default = "details"
}

action "http_query" "std::send_http_request" {
  description = "This action will make a GET request to the specified URL!"
  url = "https://example.com/${input.my_var.query_path}"
}

output "status_code" {
  description = "This output will be displayed in the Outputs section of the web UI!"
  value = action.http_query.status_code
}

Each block has a command type (in this example input, action, and output), a reference name ("query_path", "http_query", and "status_code"), and the inner data of the block (everything between the { ... }). Some command types also require that a command is specified ("std::send_http_request"). The inner data of the block is dictated by the command type and command that are specified. We'll get into the different command types soon.

First, let's observe a few things.

Command References

One command can reference the outputs of another command to build a chain of dependent commands. When you execute a Runbook, txtx creates a graph of all the commands to ensure they are always executed in the correct order. This does mean that dependency cycles need to be avoided when creating a Runbook.

Another command's output can be referenced in a block using command_type.ref_name.output_name. Here are some examples:

...
input "my_input" {
  description = input.another_input.value // references the `value` output of an `input` named `another_input`
  default = action.my_action.data // references the `data` output of an `action` named `my_action`
  value = prompt.my_prompt.result // references the `result` output of a `prompt` named `my_prompt`
}

Functions

The txtx standard library provides some functions that can be written in-line, as opposed to writing full command blocks with named arguments. These functions can be extended via integrations.

These functions can look like explicit function calls (e.g. add_uint(1, 3)), or they can look like in-line arithmetic operations (e.g. 1 + 3). Functions can reference other command outputs, or they can be stored in new command outputs. Here's an example using a few functions:

input "one" {
  value = 1
}
input "two" {
  value = 2
}
input "addem_up" {
  value = input.one.value + input.two.value
}
output "add_some_more" {
  value = add_uint(input.addem_up.value + input.one.value, input.two.value)
}

Environment Variables

Environment variables can be specified in the txtx.yaml file. Here is an example config with environment variables:

---
name: BNS Runbook
environments:
  development:
    stacks_network_id: testnet
    stacks_api_url: https://api.testnet.hiro.so
  staging:
    stacks_network_id: testnet
    stacks_api_url: https://api.testnet.hiro.so
  production:
    stacks_network_id: mainnet
    stacks_api_url: https://api.mainnet.hiro.so
runbooks:
  - name: Register BNS
    description: This runbook pre-orders and registers a user-input BNS name.
    location: "./run"

In any of the .tx files loaded by this runbook, the variables env.stacks_network_id and env.stacks_api_url will be available in the global scope. When the Web UI loads this runbook, the first action item will allow you to select which environment to load. Selecting a new environment will reload the current runbook with the new environment variables being injected into the execution.

...

Now that that's covered, let's dive into the different command types.

Inputs

Inputs can be used to store variables that can be used by other constructs and that can be edited by users in the Web UI. If the input's value field is specified, the input will appear on the Web UI in the Inputs Review section as a readonly value that can be verified. If the default field is specified, however, the input will appear as an editable input in the Web UI. The optional description field can be provided to add aditional context to the input. Finally, the type field can be provided to restrict the type of values that are valid for the input. In most cases, the type can be inferred from the initial default or value field. Here is an example input:

input "my_input" {
  description = "Enter your birthday"
  default = "MM/DD/YYYY"
  type = "String"
}

Runtimes & Defaults

Runtimes allow you to specify what addons will be used by the Runbook. These can also be used to declare some default variables that will be used by the addon. This will allow you to omit fields when using custom actions from that addon. For example, the Stacks addon has the following action for specifying defaults:

runtime "stacks::defaults" {
  network_id = env.stacks_network_id
  rpc_api_url = env.stacks_api_url
}

With this default added to a .tx file, any actions from the Stacks addon can omit both the network_id and rpc_api_url fields. They will automatically be pulled from the env.stacks_network_id and env.stacks_api_url fields, respectively.

Signers

Addons can define signers that provide various ways to sign transactions when using txtx. These signers can be used to sign transactions via a mnemonic or secret key, to prompt users to connect their web wallet and sign in the Txtx Web UI, to sign transactions asyncronously via secure enclave, to define multisig wallets, and more. Each addon signer implementation will have its own use cases and documentation.

Here is an example of a signer in use:

signer "alice" "stacks::connect" {
  expected_address = env.expected_address
}

action "my_tx" "stacks::sign_transaction" {
  ... tx data
  signer = signer.alice
}

This example defines a signer named alice, which uses the stacks::connect wallet. This signer definition will generate a prompt in the Web UI to connect a wallet, provide a public key via message signature, and to sign all transactions using this wallet as a signer.

Actions

Actions are multi-purpose constructs that are defined by addons and by the txtx standard library. Each action defines its own set of inputs (some optional and some required) that can be supplied to the action, what happens during each call to the action, and what outputs are created by the action, which can be referenced by subsequent commands.

Some examples of types of actions include making http requests and outputting the result, encoding transaction data to match a given chain's codec, signing a transaction with a wallet and outputting the signed transaction bytes, or broadcasting a transaction to a network.

Here is an example action:

action "my_ref" "stacks::send_contract_call" {
    description = "Encodes the contract call, prompts the user to sign, and broadcasts the set-token function."
    contract_id = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.pyth-oracle-v1"
    function_name = "verify-and-update-price-feeds"
    function_args = [
        encode_buffer(output.bitcoin_price_feed),
        encode_tuple({
            "pyth-storage-contract": encode_principal("${env.pyth_deployer}.pyth-store-v1"),
            "pyth-decoder-contract": encode_principal("${env.pyth_deployer}.pyth-pnau-decoder-v1"),
            "wormhole-core-contract": encode_principal("${env.pyth_deployer}.wormhole-core-v1")
        })
    ]
}
output "tx_id" {
  value = action.my_ref.tx_id
}
output "result" {
  value = action.my_ref.result
}

Modules

Coming soon.

Outputs

The output command can be used to display data at the end of the runbook execution. Here is an example of the output command:

output "my_output" {
  description = "An example output. I hope it equals 8."
  value = 4 + 4
}

Was this page helpful?