Add template update article
This commit is contained in:
committed by
Jonathan Silverblood
parent
d86f5b832d
commit
12a6350440
Generated
+2024
-991
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -60,7 +60,7 @@
|
||||
"eslint": "^9.10.0",
|
||||
"eslint-config-prettier": "^8.10.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"lerna": "^8.1.8",
|
||||
"lerna": "^9.0.3",
|
||||
"madge": "^8.0.0",
|
||||
"prettier": "^3.3.3",
|
||||
"typescript": "5.7.2",
|
||||
|
||||
@@ -10,7 +10,7 @@ tags: [general audience]
|
||||
|
||||
You may have heard about XO, General Protocols’ project that promises to make it easy for developers to create superior Bitcoin Cash applications. But what is it, actually? And why do we need it?
|
||||
|
||||
## The problems to be solved
|
||||
## The Problems to be Solved
|
||||
|
||||
The Bitcoin Cash (BCH) blockchain has undergone several groundbreaking protocol upgrades in recent years. These upgrades made it possible to build complex and innovative decentralized financial applications (or “dapps”) using Bitcoin Cash smart contracts.
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ The engine will deterministically create an identity based on the root entropy p
|
||||
|
||||
_More information on identities will be covered in a future article._
|
||||
|
||||
### Dynamic content
|
||||
### Dynamic Content
|
||||
|
||||
The templating system described here uses `CashASM` to provide dynamic descriptions, properties and other values.
|
||||
|
||||
@@ -98,11 +98,11 @@ Here's an example evaluating to `BitcoinCash`, for reference:
|
||||
|
||||
> $(<'Bitcoin'> <'Cash'> OP_CAT)
|
||||
|
||||
## Requesting fungible tokens
|
||||
## Requesting Fungible Tokens
|
||||
|
||||
We will now go over a very detailed example of how the engine, a template and invitations all go together to make a request for `100.00` `MUSD` fungible tokens in a way that creates great user experience by keeping the technical complexities confined in the templating system.
|
||||
|
||||
### Starting the engine
|
||||
### Starting the Engine
|
||||
|
||||
Before the engine can be used, it needs to be initialized.
|
||||
|
||||
@@ -129,7 +129,7 @@ const xoEngine = new Engine(seed, blockchainMonitor, [
|
||||
]);
|
||||
```
|
||||
|
||||
### Importing template
|
||||
### Importing a Template
|
||||
|
||||
Before we can use the P2PKH template, we need to import it into the engine:
|
||||
|
||||
@@ -216,7 +216,7 @@ This code will return an invitation that contains information such as the templa
|
||||
|
||||
In this example, we will use this invitation to coordinate the details of the request between the sender and the receiver.
|
||||
|
||||
### Under the hood
|
||||
### Under the Hood
|
||||
|
||||
As part of creating the starting invitation, the engine also needs to provide all information that should come from the current user. Since the starting action here was grouped under the `owner` role, it also automatically accepts the invitation in order to take on that role.
|
||||
|
||||
@@ -336,7 +336,7 @@ The `ownerKey` is not added to the invitation though, and we will go into more d
|
||||
|
||||
_At this point, we have gone through all the requirements for setting up a request to receive `100.00` `MUSD` and we have created an invitation that can be shared to complete that request._
|
||||
|
||||
## Handling the request
|
||||
## Handling the Request
|
||||
|
||||
Let's assume that we have received the request invitation above via an XO compatible transport, and that we have an XO compatible wallet with sufficient funds in it.
|
||||
|
||||
@@ -385,7 +385,7 @@ The action in this invitation only required two variables, the `requestedTokenAm
|
||||
|
||||
_In a more complex setup, this could be handled automaticelly by an app or require asking the user to manually input values for their required variables before moving on._
|
||||
|
||||
### Inputs and outputs
|
||||
### Inputs and Outputs
|
||||
|
||||
The last step is to determine what resources are required in terms of blockchain assets.
|
||||
|
||||
|
||||
+8
-8
@@ -58,7 +58,7 @@ mindmap
|
||||
|
||||
## State and Ownership
|
||||
|
||||
### Managing state
|
||||
### Managing State
|
||||
|
||||
After a transaction has been broadcast on chain that has an output matching the locking script used in our previous request, the engine will automatically detect this output and internally connect it with the template and action as well as keep track of the original variables.
|
||||
|
||||
@@ -190,7 +190,7 @@ The `selectable` property allows the template authors to indicate if it is sensi
|
||||
The `privacy` property allows the template authors to indicate what level of privacy an output has, which can be helpful to avoid mixing of inputs of different levels of privacy.
|
||||
|
||||
|
||||
## Other actions
|
||||
## Other Actions
|
||||
|
||||
Before we wrap up, let's take a deeper look at the `sign` and `verify`actions:
|
||||
|
||||
@@ -217,7 +217,7 @@ verify:
|
||||
|
||||
Contrary to previous actions we have looked at, these do not result in transactions, but instead provide arbitrary `data`.
|
||||
|
||||
### Signing message
|
||||
### Signing a message
|
||||
|
||||
In the messageSignature definition, we can see references to a `messagePrefix` constant:
|
||||
|
||||
@@ -249,7 +249,7 @@ Together, these encode the standard bitcoin message signing procedure to safely
|
||||
Note that a malicious template can already create dangerous situations by providing false descriptions of the actions being taken or request signing of such dangerous messages, and that it is important to properly audit any templates before trusting them.
|
||||
|
||||
|
||||
### Validating signatures
|
||||
### Validating Signatures
|
||||
|
||||
The validation of a signature is done in a similar way:
|
||||
|
||||
@@ -266,7 +266,7 @@ messageSignatureValidity:
|
||||
This means that any wallet that uses this P2PKH template would have this feature without needing to add any special handling or code for it. Simply find any address/lockscript or output, look at the associated actions and initiate an action to sign or verify a message.
|
||||
|
||||
|
||||
## The value of templates
|
||||
## The Value of Templates
|
||||
|
||||
Together with the [previous article](https://stack.xo.cash/blog/2025-10-16-Vision-to-Reality-P2PKH-Fungible-Token-Request.html) on how to make and handle a payment request, we have now covered the full featureset of a P2PKH template. We have gone into detail on how the engine can go from having almost no understanding of the standardness approved P2PKH lockscript, to being able to create all necessary parts required to complete a token request, manage the full lifecycle of related state and use associated functionality such as signing and verifying arbitrary messages.
|
||||
|
||||
@@ -275,7 +275,7 @@ By encoding the definition of state, secrets and private keys and how they are u
|
||||
This means that we can now build new applications both faster and safer, while providing a significantly better user experience.
|
||||
|
||||
|
||||
### Increased safety
|
||||
### Increased Safety
|
||||
|
||||
In the traditional wallet and app ecosystem today, the default is to run on HD wallets using seed words for backup and recovery.
|
||||
|
||||
@@ -292,7 +292,7 @@ This is also a missing piece in order to achieve fully non-custodial application
|
||||
Finally, by creating an invitation and coordination mechanic that doesn't rely on single-key operation and that does template based validation of provided data, we improve safety for users when interacting with 3rd party distributed applications.
|
||||
|
||||
|
||||
### Improved user experience
|
||||
### Improved User Experience
|
||||
|
||||
With templates, every transaction, input, output, lockscript and address can be described with dynamically evaluated CashASM names and descriptions. Further, every variable or input required by the user can be described as well, and their type and data can be validated.
|
||||
|
||||
@@ -303,7 +303,7 @@ Further, by having contextual actions, external links and other metadata it beco
|
||||
Finally, with templates it becomes possible to estimate a users aggregate net worth across a wide variety of contracts, as well as show how much of that value is readily accessible for spending and how much is currently locked.
|
||||
|
||||
|
||||
### Higher productivity
|
||||
### Higher Productivity
|
||||
|
||||
When using trusted templates, the correct use of a contract is directly encoded. Importing a template that someone else has made can be done to provide new features at almost no cost.
|
||||
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
---
|
||||
title: 'Vision to Reality 3: Template Updates'
|
||||
date: 2025-12-15
|
||||
description: Realization of the XO vision, part 3 covering recent improvements and extensions we have done to the XO template structures.
|
||||
author: Jonathan Silverblood
|
||||
tags: [templates, engine, technical audience]
|
||||
---
|
||||
|
||||
# Vision to Reality 3: Template Updates
|
||||
|
||||
This article covers improvements and extensions we have done to the XO template structures and highlights differences since the [Fungible Token Request](https://stack.xo.cash/blog/2025-10-16-Vision-to-Reality-P2PKH-Fungible-Token-Request.html) and [Managing State and Ownership](https://stack.xo.cash/blog/2025-10-30-Vision-to-Reality-2-Managing-State-and-Ownership.html) articles.
|
||||
|
||||
----
|
||||
|
||||
```mermaid
|
||||
mindmap
|
||||
root )Responsibilities(
|
||||
|
||||
[INVITATIONS]
|
||||
(Connects)
|
||||
📱 Apps
|
||||
👛 Wallets
|
||||
👥 Users
|
||||
(Coordinates)
|
||||
⚡ Actions
|
||||
🧩 Variables
|
||||
📥 Inputs
|
||||
📤 Outputs
|
||||
|
||||
[TEMPLATES]
|
||||
(Describes)
|
||||
🧩 Variables
|
||||
💸 Transactions
|
||||
📥 Inputs
|
||||
📤 Outputs
|
||||
🏷️ Lockscripts
|
||||
(Defines)
|
||||
⚡ Actions
|
||||
💸 Transactions
|
||||
💾 Data
|
||||
|
||||
[ENGINE]
|
||||
(Generates)
|
||||
🔑 Keys
|
||||
🪪 Identities
|
||||
✉️ Invitations
|
||||
💸 Transactions
|
||||
(Manages)
|
||||
🤫 Secrets
|
||||
🧩 Variables
|
||||
📤 Outputs
|
||||
🏷️ Lockscripts
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
## Templating Updates
|
||||
|
||||
### Simplified Burn Actions
|
||||
|
||||
When working with the token burn features in the P2PKH template, there was some edge case handling around change that was difficult to resolve with simple CashASM statements. Specifically, there was a case where the calculated values of the defined non-burn outputs would contain 0 tokens and therefore shouldn't exist.
|
||||
|
||||
To resolve this, we instead introduced a `omitChangeAmounts` parameter to inputs that allows a template to declare how much of the input values that should ignored when creating a potential change output.
|
||||
|
||||
```ts
|
||||
// Ignore the burned token amount when determining change for this output.
|
||||
omitChangeAmounts:
|
||||
{
|
||||
fungibleTokens: '${<burnedTokenAmount>}'
|
||||
}
|
||||
```
|
||||
|
||||
*This allows us to remove the full output definition in the burn actions and avoids the need for exact math and edge-case handling in burn actions.*
|
||||
|
||||
|
||||
### Action Intents
|
||||
|
||||
Previously, the expectations for the engine was that it would be capable of looking through the full dependency tree for requirements and then summarize a list of the requirements for the users. This actually works reasonably well, but while working on unrelated user experience improvements we reached a conclusion that simple references to actions are not sufficient in the starting points and follow-up actions from outputs or locking scripts.
|
||||
|
||||
When we redesigned the starting and follow-up action intents to carry additional information it became possible to front-load all requirements and simplify the engine implementation, so we now have a generic intent structure for starting points:
|
||||
|
||||
```ts
|
||||
start:
|
||||
[
|
||||
{
|
||||
action: 'receive',
|
||||
role: 'owner',
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
We also reuse this intent interface in the output and locking scripts follow-up actions:
|
||||
|
||||
```ts
|
||||
actions:
|
||||
[
|
||||
{
|
||||
action: 'sign',
|
||||
role: 'owner',
|
||||
secrets: 'ownerKey',
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
*This allows us to have both role based and role-less starting points, a place to declare which state should be carried through to the next action and a place to expand functionality to provide more contextful starting options.*
|
||||
|
||||
|
||||
### Generic Role Sections
|
||||
|
||||
In the previous template structures, we had a great set of descriptions for the various actions, inputs/outputs and locking scripts, but they were written to be generic such that they would fit for any participant looking at them. This is an acceptable solution, and the template retain this capability for those that prefer it, but we also wanted to make sure that it was possible to provide descriptions that are different based on who is looking at a given component.
|
||||
|
||||
For example, the funds in a `requestSatoshisTransaction` are `received` by one party, but they are `sent` by another.
|
||||
|
||||
While trying to address this and provide for role-specific ways to define descriptions, we decided to go with a generic approach where any property of a field that can have roles can be defined under the role and the engine can flatten the structure as needed:
|
||||
|
||||
```ts
|
||||
someSection:
|
||||
{
|
||||
propertyA: 'someGenericValue',
|
||||
propertyB: 'someGenericValue',
|
||||
propertyC: 'someGenericValue',
|
||||
|
||||
roles:
|
||||
{
|
||||
provider:
|
||||
{
|
||||
propertyA: 'aRoleBasedValue',
|
||||
},
|
||||
beneficiary:
|
||||
{
|
||||
propertyA: 'aDifferentRoleBasedValue',
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Depending on what role the participants engine have in this section, the value for `propertyA` can either come from the generic, provider's or beneficiary's definition.
|
||||
|
||||
*With this, user interfaces can show different names, icons, descriptions, requirements, etc. depending in the users role.*
|
||||
|
||||
|
||||
### Role Slots / Instances
|
||||
|
||||
Most use cases we have looked at have a fixed and well-defined set of roles. However, there are some cases where the number of participants is more fluid, and it is often not possible to know how many participants there will be, when the templates are created.
|
||||
|
||||
For example, a fundraising campaign could have any number of pledgers, and to address this we have added new restrictions to roles, which can be left undefined as needed in open-ended cases:
|
||||
|
||||
```ts
|
||||
roles:
|
||||
[
|
||||
{
|
||||
role: 'owner',
|
||||
slots: { min: 1, max: 1 }
|
||||
},
|
||||
{
|
||||
role: 'sender',
|
||||
slots: { min: 1, max: undefined }
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
*This allows the engine to verify that a valid number of roles have been claimed and adds support for use cases like fundraisers where the number of pledges are not known at the template level.*
|
||||
|
||||
|
||||
### Explicit Key Generation
|
||||
|
||||
In the previous versions of the templating system, keys were generated by the engine as needed. While implementing the engine, it wasn't always clear when this would happen, which always felt a little bit like black magic.
|
||||
|
||||
As part of adding the starting and follow-up intents, we now also have a `generate` section in the intents that lets the engine know when to create the `ownerKey`:
|
||||
|
||||
```ts
|
||||
requirements:
|
||||
{
|
||||
generate: [ 'ownerKey' ],
|
||||
},
|
||||
```
|
||||
|
||||
*This allows us to declare what data the engine should automatically generate, rather than rely on hidden assumed behaviour.*
|
||||
|
||||
|
||||
### Explicit Transaction Shape
|
||||
|
||||
While there is a goal to keep templates small and easy to work with, previously we had made an assumption around how `inputs` and `outputs` are specified which led to an implicit rather than explicit ordering. For most situations, this was not a problem, but when discussing how to support composing multiple transaction it wasn't not clear how to form the transaction shape.
|
||||
|
||||
Transaction composition is not fully complete yet, but we have restructured the `input` and `output` section of transactions to provide explicit ordering:
|
||||
|
||||
```ts
|
||||
outputs:
|
||||
[
|
||||
{
|
||||
output: 'receiveOutput',
|
||||
index: undefined,
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
*This allows us to simplify transaction composition and makes it easier to do validation.*
|
||||
|
||||
|
||||
### Testing Scenarios
|
||||
|
||||
The most ambitious change is the introduction of `scenarios`. These are template-defined examples for the various actions in the template that the engine can use to provide automatic testing.
|
||||
|
||||
This can be a great tool for the template authors, but also allows for more strict safety in the sense that a template that fails to execute on the provided scenarios can fail early, before users provide funding to it, rather than fail after funds have already been sent.
|
||||
|
||||
The scenarios are relatively large and are likely to undergo more changes as we implement more of them, but to illustrate the idea, here is a shortened example:
|
||||
|
||||
```ts
|
||||
scenarios:
|
||||
[
|
||||
{
|
||||
name: 'requesting satoshis',
|
||||
description: 'happy-path evaluation for requesting satoshis.',
|
||||
|
||||
// The action being run in the scenario.
|
||||
action: 'requestSatoshis',
|
||||
|
||||
// List of roles taken in this scenario, and the resources they provided.
|
||||
roles:
|
||||
[
|
||||
// See values below for example.
|
||||
],
|
||||
|
||||
// List of resources provided outside the context of a role.
|
||||
values:
|
||||
{
|
||||
generated:
|
||||
{
|
||||
// This scenario does not have any non-role generated values.
|
||||
},
|
||||
variables:
|
||||
{
|
||||
// This scenario does not have any non-role variables.
|
||||
},
|
||||
secrets:
|
||||
{
|
||||
// This scenario does not have any non-role secrets.
|
||||
},
|
||||
},
|
||||
|
||||
// Outcomes provides the set of resulting values created from the action.
|
||||
outcome:
|
||||
{
|
||||
roles:
|
||||
{
|
||||
// .. list of generated data per-role
|
||||
},
|
||||
|
||||
transactions:
|
||||
{
|
||||
requestSatoshisTransaction:
|
||||
{
|
||||
// .. list of all data related to the transction
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
*Note that scenarios are not suitable for providing trust, as a malicious template author can make actions that steal your funds, and write valid functional scenarios that prove that they would be successful at stealing your funds, if used.*
|
||||
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
We have also added and updated many of the descriptions, moved some inline number to constants, added some rationales for additional design decisions and other minor changes.
|
||||
Reference in New Issue
Block a user