General Protocols: Key issues for next generation UTXO smart contract wallets

Tiers of token wallets

CashTokens on BCH is a unique facility that satisfies two value propositions at once:

  1. Traditional “tokens” where fungible or non-fungible tokens represent items of value, and are transferred and traded on a public blockchain to take advantage of its permissionless security properties.
  2. Computation “tokens” where information is passed among both onchain contracts and off-chain entities for more complex operations.

Generally when developers talk “CashTokens wallet” they refer to 1), which is better understood, and we’ll describe its requirements briefly. To unleash the full power of CashTokens on BCH though, we will need to address 2) in detail as well.

Conventional token-handling

Traditional token-handling wallets shall be expected to have the following features:

  1. Sending
  2. Receiving
  3. Easy identification of Category IDs
  4. Access to history and transaction details(for full featured wallets) or balance (for minimalists)
  5. Detailed description of NFT characteristics (mutable, mintable…)
  6. Ability to handle BCH in parallel
  7. Noncustodial backup, through seed words or otherwise
  8. Sending tokens to requests, such as a version of BIP21

It can also optionally have the following features that can immediately yield a large improvement to quality of life:

  1. Minting, if a standard is agreed upon
  2. Identification of tokens, perhaps through Metadata Protocol
  3. Sending BCH in a single output along with tokens
  4. Sending tokens to Payment Protocols (such as a version of BIP70 or json-payment-protocol).

Other advanced features available to BCH such as fusion, shuffle, coin-management are desirable, but may not be immediately needed for “ready to go” functionality.

Note that even in a setup where these advanced features are available for native BCH, they may not be available to fungible tokens due to liquidity, demand or general maintenance hurdles, even if the implementation is theoretically straightforward.

Information-carrying tokens and smart contracts

The primary advantage of CashTokens over other UTXO token protocols lies in its ability to interact as information-carrier within an expressive BCH context. Without at least one competent wallet to take advantage of that this functionality can be stunted for a very long time. Facilitating it requires, as prerequisite, that the wallet be able to:

  1. Contexts : Display different contexts in interface, depending on the contract being handled. More on this below.
  2. External Interactions :Ability to interactively exchange information with external, non-node entities. An external example here is MetaMask, which is able to interact with web pages; an existing BCH example is Cashfusion, which interacts with the Cashfusion server. Early wallets may want to weigh their scope on whether to include ability to interact with servers in general.
  3. Script-spending : Given a template and sufficient supporting information, spend a UTXO in a custom way, perhaps with interaction steps to fetch additional information.
  4. UTXO Discoverability : Given a template and private seed or backup, query servers using custom filter criteria and fetch spendable UTXOs, along with possible additional information required to spend them. This is important in the UTXO context, as there is no singular, per user abstracted account where everything goes to and from. For some contracts discoverability from seed may be impractical, in which case suitably secure wallet backups need to be specified.
  5. Interaction history backup : Conventional wallets generally converge onto backing up by BIP39 seeds, from which an entire P2PKH history can be retrieved directly from the blockchain. Interactive script wallets have no such luxury - just as in the case of UTXOs, the wallets must either backup its history directly, or have templates where custom discovery-from-seed methods are specified.
  6. Template verification and use : Custom interactions can be tremendously insecure, a problem which MetaMask worked around by prompting trust on individual website certificates. We can do better - a templating system independent from the Web such as Bitauth can facilitate a permissionless, trust-once-per-usecase system that is much more secure.

These capabilities shall form a generalized baseline upon which countless customizations are possible via templates, and the ability of CashTokens to transfer information will lie at the heart of many of these contracts. We’ll explore CashTokens primitives in custom contracts in another article.

On contexts

Conventional wallets typically has one context, or at most two if we separate BCH and token spending, as seen in Electron-Cash-SLP. It is, however, impossible for one interface to account for all possible script usecases, many of whom will require customized input and output elements. It is therefore important for wallets to accommodate possible different interfaces, perhaps via tabbing, specified in each template’s context.

At the most basic, a “universal” interface is conceivable where templates specify all needed script input fields in their raw requirements such as num/binary-strings/public key…, and the wallet simply serializes the inputs to be used as-is in Script. This can, however, be very user unfriendly, especially for elements that gather from an external source, such as an oracle, instead of from the user. On the other hand, it would be unwise to allow arbitrary interaction and code-running with a remote server, as any vulnerabilities introduced by one template is no longer contained within its context.

On EVM wallets like MetaMask, contexts are usually granted by permitting access to web domains. The EVM/MetaMask model, however, suffers from high trust on domain name owners, as well as opaque and possibly unbounded permissions given to websites that can be changed in arbitrary ways. We assert that a trust-once-per-usecase “template” model, similar to how users traditionally trust downloaded software, is more appropriate for our purposes.

A good balance can be struck for a template-based wallet, if it adheres to the following rules:

  1. A template must not run arbitrary remote code. The only data that can be fetched from a remote server are direct inputs to Bitcoin Cash script, or (mutable) parts of Bitcoin Cash script itself. Any non-Script code must be local, and requires an explicit template update to change.
  2. Template contexts must be isolated. Templates shall not automatically pass information among themselves upon execution, without explicit user permission. They shall each have their isolated seed derivation path, backup file, interface instructions, etc. The wallet shall enforce this at low level design; failure to do so will result in contagion risk from a malicious template that the user inadvertently imported. While this contagion risk may be acceptable in a casual or small-community context, it is not scalable to wider, less sophisticated pools of users and developers.
  3. No persistent permissions for mutable interactions. Certain interactions, such as fetching a piece of Bitcoin Cash Script from external sources, are “mutable”: they do not simply fill inputs on already trusted Script, but may generate additional contexts that are not explicitly trusted yet. Each of these interactions must be explicitly granted permission each time. Developers who wish to streamline
7 Likes

Few more thoughts, I really liked Jason’s idea of “bytecode_pattern” he used for Chaingraph, so I came up with this: https://github.com/bitauth/chaingraph/issues/56#issuecomment-1467926936

With that, you san split a redeem script bytecode to fixed + variable parts (using STRIP_PUSHES and EXTRACT_PUSHES modes), and instead of storing the whole redeem script, user could store a reference to a script “fingerprint” + wallet-specific data + contract instance specific data, from which he could reconstruct all P2SH hashes he has access to.

This would let us index contract fingerprints and when an user is presented with some new redeem script, he could strip the pushes, compute the fingerprint, and check it against the register and see if it’s a familiar/vetted pattern, etc. If user wants, he could embed an OP_RETURN hint alongside the P2SH UTXO he’s creating.

We could generalize the approach to whole transactions, strip the whole TX of variable data and hash a particular configuration of inputs&outputs & their bytecode patterns

2 Likes

This ties in really well with my own thoughts on this. Those “let just chat” talks over video chat were definitely good for that! (Thanks mr Nieri!).

The basic are already starting to show in the Flowee Pay project, I took the time to describe this on the Wiki here: dev/modules - pay - Codeberg.org

2 Likes

There is a lot of overlap of the second part (contexts) with what @bitjson has been doing with AuthenticationTemplates. and the accompanying libauth Wallet API.

However, there also isn’t obvious of overlap there with the first token value proposition, because Jason’s general template schema and Wallet API don’t mention tokens.


While an AuthenticationTemplate may map to a specific or generic script instance, it seems like the second level value proposition may require something like an Integration Template.

So a protocol maintainer may fill in the protocol template schema, and the wallet could ensure that the some random script passed back or data supposedly for some protocol was following the rules.

There is some overlap with scenarios in AuthTemplates and the Script-spending above, but not total overlap.


Going back to the first tier. An NFT platform could specify it’s protocol for the wallet integration, reference it’s contracts with authentication templates, specify metadata sources with BCMR.

  • ProtocolTemplate
    • name, description, version etc
    • $ref → definition/integration.json
    • $ref → definition/authentication.json
    • $ref → definition/registry.json

Where a wallet template could carry the second tier features above:

  • Integration Template Schema
    • Location of context funds bip34#usecases?
    • UTXO Discovery (output bytecode matching?)
    • external interactions
    • history, data etc.
    • Authentication Template validations

In a json schema, a lot of the really weird stuff some protocols have been doing may have to be reduced to a set of standard functions with simple string arguments that can be implemented in any wallet.


I’m not sure if this is what Jason had in mind, or if I mixed up the levels.

The Protocol Template wrapper could be just the simplest most generic thing that references the more complex schemas.

2 Likes

@bitjson Jason, I know you are super busy these days. Pinging you so you can insert this into your todo list b-tree.

Drilling down on one component, given a context of addresses to look for history in, a discovery from seed template could specify a StorageType(s) (i.e. https, ifps, or op_return). Depending on storage, it would specify an API endpoint, or ipld path. In the example of OP_RETURN, protocols might spec a Serializer, and then specify how the fields map to the correct unlocking script, version, parameters, & locking bytecode, etc.

With some existing examples:

For Last Will, @Licho 's protocol (>sh0x0, 6a 04 3e736800) is parsing the data using a string returned from electron-cash ui_string() fn of the ScriptOutput class. Which serializes to UTF8 or hex or OP Code. An example last will transaction is here.

The hodl protocol (hodl , 6a 04 686F646C) follows a similar pattern, an example op return is here.

For the unspent phi protocol (utxo , 6a 04 7574786f), it’s using data serialization like CashScript’s LockingBytecodeNullData(). An example is here

All three protocols are versioned to deserialize different arguments, if necessary, in the future. They use the spirit of Lokad’s four byte prefix guideline, but are all higher than 0x10000000.


So just from the small snapshot, it’s somewhat neatly packaged in the tools that were available for the job—however it could get weird if someone makes a new serializer, or decides to start chaining OP_RETURNS or having multiple returns in a broadcast.

There is also the endiness of numbers, and various encodings for strings (ascii, UTF-8).


The most straight-line path for wallet implementers would be to specify a json blob format served from a website or ipfs.

But for discoverability from a seed phrase (and permanence) a spec for what op_return storage, parsing and mapping features are accommodated would really keep people from inventing weird and terrible ways of storing and finding those 223 bytes.


Just as a note, the first two protocols currently have to iterate though a list of all wallet outputs to find matching data. If a contextual bip39 path were possible, it could make using those types of plugins faster.

With unspent, although a lot of the op_returns are generated by one contract, it’s also possible to publish from any transaction. So chaingraph’s SearchOutputsByLockingBytecodePrefix() has been super helpful.

Thanks for writing this. It provides sort of a roadmap for us, wallet devs, to follow. At Paytaca, we are currently tackling both the conventional token handling features as well as some of the pre-requisites of the more advanced handling of tokens, specifically the external interactions with web-based apps. We have shared an early video demo of our work in this tweet. That is showing our Paytaca browser extension interacting with a web-based application. Browser extensions are the easiest to work with for this purpose because they already have an ability to talk with web pages so have focused on this as a start.

A more generic protocol for wallet interaction with apps is provided by WalletConnect (https://walletconnect.com). A few days ago, we have started exploring just adding BCH support to this protocol, if possible (docs here: Chain Onboarding | WalletConnect Docs). We are still assessing the work needed to get it done. If ever, this is going to be the easiest path to enticing developers to build apps that use BCH + CashTokens.

Regarding contexts, we think that individual apps can provide custom contexts and most of them won’t live within wallets but in standalone web-based apps. A reason why we prioritized working on external interactions is because we want this to give outsiders the impression that CashTokens is as accessible as other tokens in other chains, you just need to connect your wallet and do a few clicks, fill out inputs in a custom app, the app then submits the transaction to the wallet for inspection and signing, and done! This is the kind of experience that people are familiar with and we want that for CashTokens as early as possible.

3 Likes

Catching up on this forum, thanks for the ping @emergent_reasons! I made some comments on Telegram, just copying here too for future reference:

Nice, I think this gets the user-facing ideas right! I’ve been focused on designing a Libauth “wallet engine” that you could maybe think of as being one layer lower than some of this. A template can essentially be compiled to initialize any number of "wallet"s, and wallets have an internal view of their UTXO set + the cross-entity “shared” data from this earlier spec: Libauth Wallet API Planning · GitHub. Wallets then expose a set of “actions” (defined in the template) that are essentially a set of constraints on one or more transactions (so they can be composed if the constraints are compatible). Actions are generally human understandable concepts like “market buy”, “limit sell”, “redeem receipt”, etc. It should ultimately be possible to encapsulate most of the complexity of most on-chain protocols in this setup, including passing partially-signed transaction sets + shared data updates between wallet apps from different vendors. But that’s where the scope ends on the “engine” as I’m currently thinking about it – the actual UI that is exposed to users has to connect the dots by displaying some of the computed info the engine exposes: allocated addresses, balance/assets held by each address type, decoded token asset info, and buttons/controls/whatever for currently available actions (based on the balances/assets available across all wallets known to the engine).

It will be possible to generalize a huge number of DEX/exchange/voting/etc. protocols enough that power-user/developer focused tools (e.g. Bitauth IDE) can let you import arbitrary templates to create and use new types of wallets/protocols with standard controls + text-based UI, and all of those tools should (at the very least) understand a JSON format for passing around partially signed transactions and shared wallet data updates (and it will be common to have a file import/export as the MVP transmission strategy). But such “generated UIs” will be very unfriendly and require some mental context to be comprehensible. Most end users will need UIs that e.g. render a proper order book, price ticker, etc.

The vision is that we can get a pretty complete “engine” layer figured out and maybe have a few implementations, and then most apps would import a well-reviewed engine rather than building most “standard” features from scratch: UTXO management, TX signing, draft/partially-signed TX communication, NFT decoding, identity support, etc. (maybe someday even P2P connectivity components, especially if we had a WebRTC protocol). Then BCH security gets amazing too, e.g. complex multisig vaults can be split across apps produced by multiple vendors (attacker would need to compromise them all simultaneously to steal from anyone).

So anyways, some of this memo is addressing elements that I hope can be one layer higher than the “engine” template standard: how templates actually get shared/authenticated in practice, how engine JSON messages (wallet invites, partial transactions, and shared wallet data) actually get passed between devices/apps, and how we package up and/or authenticate UIs that end users ultimately use. It’s possible that various apps/vendors can develop some mutually-compatible plugin standards (e.g. a packaged web UI that uses a standard wallet-internal JS API) and/or standard JS API for trusted websites (as most of the EVM world currently relies on). And of course, many apps can have their own mobile/desktop UI entirely rather than just being a website or a plugin in a more complex wallet. (I hope we see a lot more of this in BCH land than currently happens in other “smart contract” ecosystems; BCH is well suited to supporting apps with built-in light or pruned nodes.)

A useful example is maybe what the generalized templates can’t do: CashFusion is a very specialized protocol with custom UTXO selection (though the engine should eventually be capable of running a selection algorithm defined in the template), signing math, and message types. So it’s actually possible to scaffold out many parts of the CashFusion protocol in a “CashFusion template”, but there’s no getting around the need for some custom JS/Python/whatever to call the various actions in the right order (to produce some of the messages), manually producing messages that can’t (yet) be produced by the typical signing infrastructure, and broadcast the messages to the right places (over Tor/clearnet with proper timings). So that’s a good example of a protocol that can’t be entirely baked into a template. On the other hand, a DEX system like Jedex uses exclusively on-chain transactions, so you can bake almost everything into a template. A power user should eventually be able to “manually” use Jedex exchanges via the auto-generated interface in a sufficiently advanced tool that supports arbitrary templates (eventually, Bitauth IDE). (And building nice UIs that support that “Jedex protocol” wouldn’t require much specialized knowledge, you just have to manage the data/P2P connections and display the decoded/computed info and action buttons nicely.)

4 Likes

Can you expand on this important separation of concerns issue a bit more? Since you are actually making a real wallet, I’m very interested to hear how you separate things.

I also have two questions about walletconnect

  1. Is walletconnect flexible enough to cover every possible BCH VM transaction?

  2. Will you be able to use libauth primitives underneath walletconnect for all the actual transaction building?

2 Likes

Hey,
Wallet Connect is looking into supporting UTXO’s…
There is already a thing called Sats Connect, but it’s not very known.
Looking into this myself, because Im looking into ways to connect Dash to dApps.

You should join the Wallet Connect discord. I’m making a group with people from Wallet Connect and the Dash Incubator team to discuss Dash integration.
You can send me a dm on Discord @GiMa#9550

Hey @joemar_taganna, would love to connect with you regarding this. What is your Telegram username?