FLIP-934: Interaction Templates

Abstract

This FLIP proposes a new standard for how contract developers, wallets, users, auditors and applications, can create, audit and verify the intent, security and metadata of Flow scripts and transactions, with the goal to improve the understandability and security of authorizing transactions and promote patterns for change resilient composability of applications on Flow.

3 Likes

[I read through the proposal and I really like the concept alot, I think this is needed SO much to avoid users getting scammed and I would strongly advice it becomes a requirement for all wallets to follow this.

However there is one part of it that I would advice a slightly different approach on. Right now the code that is stored contains variables that have to be replaced for each network, and then you store the addresses for the different networks. The problem with this is that when wallets receive the transaction these replacements are already made, so we make the work for wallets very hard.

In stead I propose that we replace all addresses and just duplicate the code and hash for each network.

I have done some work on this in overflow. The code uses the cadence runtime to parse the code and extract the arguments. Based on the work bluesign did for flow cli without arguments. It is possible to parse doctags here I think I just have not had time for it.

https://github.com/bjartek/overflow/blob/main/overflow/parse.go you can call it like this


package main

import (
	"encoding/json"
	"fmt"

	"github.com/bjartek/overflow/overflow"
)

func main() {
	g := overflow.NewOverflow().ExistingEmulator().Start()

	res, err := g.ParseAllWithConfig(true, []string{
		"^admin*",
		"^setup_*",
	}, []string{})
	if err != nil {
		panic(err)
	}

	merged := res.MergeSpecAndCode()

	file, _ := json.MarshalIndent(merged, "", "   ")
	fmt.Println(string(file))
}

it will produce a json file like this

This is an example for bl0x.

We then publish an NPM module for that file that the frontend code uses.](https://github.com/onflow/flow/pull/934)

2 Likes

I strongly feel this should be stored on chain.

  • It would be more secure
  • It would be more discoverable
  • It would be more decentralized

Also I think some common tasks should be standard, Initialize new account etc

Ofc best would be to add new Storage to Flow called interactions. Second best would be a Registry contract to manage interactions on chain.

Making this onchain would also allow finally to use Ledger with FCL

Also I feel like with MetadataViews, if we store interactions on chain, we can reference interactions on resources. Send to another address this NFT , Add to collection etc

2 Likes

This is one of the reasons it so so important. https://twitter.com/JLRoyal42/status/1525222565278494720

2 Likes

Thank you for your reply @bjartek !

Re: “The problem with this is that when wallets receive the transaction these replacements are already made, so we make the work for wallets very hard […] Instead I propose that we replace all addresses and just duplicate the code and hash for each network”

A path forward here would be for us to provide utilities that could consume an interaction template and a network identifier, and then produce the cadence code with dependencies filled in for that given network. This would lessen the burden on wallets having to write this logic themselves.

Ideally there would be lots of utilities created to do many of the operations upon an interaction template.

Also - one of the benefits of having the cadence dependency info outside of the cadence code itself in the template is that it:

  • Allows dependency pins to be specified for each dependency on each network. This makes it so consumers of the template can know if an upstream dependency has changed since it was used to create the template.
  • Allows other areas of the template to reference a dependency. For example, an “amount” argument in a “transfer” template might reference a dependency to show that it refers to an amount of that specific fungible token. (see: FLIP: Interaction Templates by JeffreyDoyle · Pull Request #934 · onflow/flow · GitHub)
  • Minimizes duplicated information in the template.

I also believe a single identifier (hash) for each Interaction Template is extremely valuable. It allows developers to reference a single identifier when querying for and carrying out a template, regardless of the network they’re operating on - reducing the amount of logic needed to be changed in their code between networks.

I would love to hear your thoughts on these points!

Re: “I have done some work on this in overflow. The code uses the cadence runtime to parse the code and extract the arguments.”

I think we’ll need tooling to make generating Interaction Templates from cadence code as easy as possible. I’ve experimented myself by creating a CLI tool to do just this, consume a .cdc file and go through collecting the additional information to create the template for it. The end solution might be a CLI tool, perhaps a web app or something else; regardless, the end goal should be to make generating templates as simple as possible.

Thank you for your reply @bluesign !

Re: “I strongly feel this should be stored on chain.”

An Interaction Template is just data, and could be serialized and stored on any medium. This might be on-chain, on a web-server, IPFS, wherever. You can imagine a template registry contract on-chain which stores Interaction Templates and makes them available to consumers.

If an Interaction Template, Audit or Interface is stored on-chain it is no more or less secure than if it were stored anywhere else. Interaction Template identifiers can be recomputed, audits of it verified, and interface usage validated if the template comes from an on-chain registry or was queried for using some off-chain system.

Re: “I think some common tasks should be standard, Initialize new account etc

Absolutely agree! Lots of standard actions could be constructed as Interaction Templates and used across projects.

Re: “Making this onchain would also allow finally to use Ledger with FCL”

Could you expand on what you mean by this?

Re: “Also I feel like with MetadataViews, if we store interactions on chain, we can reference interactions on resources. Send to another address this NFT , Add to collection etc”

Whether the template is stored on-chain or not, this would be possible! Interaction Template IDs could be referenced inside a resource, and a consumer could look up the Interaction Templates corresponding to those IDs on-chain or from elsewhere to find how to perform operations on the resource. These IDs could be stored in a metadata view or elsewhere.

Hey @JeffreyDoyle, Thank you for the detailed answers, few pointers I have I think it is better we don’t miss.

This is unfortunately not true anymore in today’s world. One related example is Certificate Transparency (https://certificate.transparency.dev)

Trust is not binary anymore, it is more defensive with trust but verify. Problem we have here, if it will be not on chain and decentralized, we will not know about what auditors are signed. So this will require total trust to auditors. ( without any audit trail )

There are a lot of more angles on this, on-chain vs not-on-chain discussion. But I think security needs beats the others.

Re: “Making this onchain would also allow finally to use Ledger with FCL”

Currently not using dapps in ledger is biggest blocker for ledger usage. When I looked at ledger code ledger is totally fine with transaction hashes approach, technically they should also be totally fine with transaction signatures approach. ( I mean hashes are generated by Dapper Labs or Flow Team how you call it ) So instead of hashes, they would be ok with signatures generated by auditor.

So technically you can put auditor public keys inside code, and verify a signature per transaction ( by sending signature of transaction hash + timestamp + etc etc ( usual yada yada ) )

Re: “Also I feel like with MetadataViews, if we store interactions on chain, we can reference interactions on resources. Send to another address this NFT , Add to collection etc”

Yeah my point was total on-chain use:

Now for example, if I want to write a function that creates a newCollection and moves the NFT to new collection. ( Like add to new playlist functionality on music players) it is not possible.

But if we can make these interaction templates first class interaction templates ( something like function in Cadence with AuthAccount parameter ) like technically which transactions are.

You will have something like interactions in cadence, which is basically like contracts but for storing functions. ( which may have one or more AuthAccount parameter ) Which makes them practically transactions.

Then we can have a simple key-weight check by sending auditor weights I granted, { Auditor Address: Weight } and a simple function can answer me if is it ok to run or not.

This can work on both on-chain and off-chain.

I would really love to have the wallet makers input on this. I am not familiar with their implementation details.

Personally I think it is a lot of work to get dependency pinning and unique hash right. Yes it is an advantage but it is also a lot of work. Also the identifier for the hash will not be enough to make it unique since you also need the know version pinning information. golang went through this with go.mod and then having to make go.sum to pin versions.

I think the ecosystem needs this sooner rather then later and a version where you have fully resolved transactions is both easier to understand, implement and debug.

I very much agree with @bjartek that suggested solutions thus far are overcomplicating the issue.

I believe it is simple enough to simply store transaction code in the form of a string on-chain, and then have wallets check if that string exists as a verified tx code or not.

In addition, this auditing should be community managed as to not run into similar issues with the extremely long process of getting NFT metadata supported by current wallet solutions. I would be happy to make very quick progress inside of Emerald City DAO, but of course it does not have to be managed by us. I just think we can manage this quickly and easily, and have this tool out there in a matter of weeks for wallets to support.

I was more thinking of storing something like this:

  • code
  • hash
  • data structure with arguments and their types
  • friendly description that can be i18n by community members

@jacob @bjartek @bluesign

I think an important quality of a solution to this problem is that the correctness of a template should not be a product of where it is stored, but that it’s correctness can be validated wherever it is stored.

With this proposal there is an on-chain component in the creation and verification of Interaction Template Audits.

Auditors would create their audits and audit signatures using keys stored on accounts on-chain that are known to be controlled by them. Users validating an Interaction Template Audit would verify the audit signature for correctness by verifying the audit signature using the key on the account controlled by the auditor it corresponds to.

This pattern means that if a template is stored on-chain, off chain, wherever, it’s correctness is able to be verified using on-chain keys.

Nice work writing up a solution proposal for this problem Jeffrey!
There is definitely a big need to improve the UX and such a standard would help with it.

I like the proposal’s feature set, it is great that it includes internationalization.

My biggest concern / question is with the storage / provision of it:

Contract developers should make available their Interaction Templates to others who wish to use them.
They can do this through providing them using a webserver, and have consumers query them.
They may also choose to store them on-chain. They may even choose to store them on IPFS.

Do we want to encourage an on-chain solution here, so this becomes authoritative?
When a template is provided on-chain, and provided by the contract itself, it can be easily trusted.
When a template is provided off-chain, anyone can publish templates for anything, how can they be trusted / verified?

As for the concrete format of the template:

  • Maybe improve the naming. Instead of shortening fields, just spell them out, e.g. vsnversion
  • What is the purpose of the f_ prefix?
  • What is the difference between the outer version and the inner “data” version?
  • What is the “data”? What is the reason for nesting it – could it just be at the top-level?
  • data.arguments:
    • Could this just be an array, instead of an object where each entry has to specify an index?
    • Is the idea to allow lookups based on name?
  • Keys in messagesi18n, e.g en-US, should be strings if they are not identifiers, e.g. "en-US"

@bluesign

This is roughly where we’re thinking in regards to the Flow Ledger integration! It would be excellent if we could leverage Interaction Templates and Interaction Template Audits to open the Ledger Flow app up to safely support more transactions

thanks @JeffreyDoyle for the answer.

Auditors would create their audits and audit signatures using keys stored on accounts on-chain that are known to be controlled by them. Users validating an Interaction Template Audit would verify the audit signature for correctness by verifying the audit signature using the key on the account controlled by the auditor it corresponds to.

This part is the problem I see. I think Trust Chain is broken when we blindly trust the Auditor.

Let’s consider a scenario:

Imagine I am Evil Auditor bluesign (address: 0x0B) with key (K1). And I am signing a transaction like below:

import EvilContract from 0x0b

transaction {

  prepare(acct: AuthAccount) {
    EvilContract.evilMethod(acct)
  }

  execute {
  }
}

And interaction template I put it something innocent as description.

I put my Interaction Template somewhere off chain. Somehow blocto reads it, checks the signature with K1, it verifies, does not even show code to the user. Only my innocent description. ( maybe “claim your free 100 Flow, Flows will be sent in 24 hours.” etc )

Now we have a problem:

  • Best case blocto logs all interactions ( we figure out bluesign is Evil )
  • There is no audit trail for the signing ( when I sign the Interaction template, nobody knows )
  • Revoking is not easy ( we need to inform all wallets about the breach, they have to revoke my signature, that means they have to also maintain a blacklist of auditors )

Imagine auditor is not evil. ( let’s call it Jeff )

  • Jeff is a hard working auditor, he audited many Interaction Templates
  • Jeff signs this transaction accidentally. ( or maybe it was not this obvious at the time, but somehow bluesign, the evil dapp owner tricked him somewhow)
  • Now there is no audit trail, but luckily we caught the evil transaction by user report
  • Now we can revoke, Jeff’s key, but we have an dilemma here, all other signed Interactions has to go
  • So we decide to inform wallets, so they can blacklist this transaction only. ( now they have to hold a blacklist of transactions, again some will update fast, some will not respond, some even don’t have control like lilico, they will fix on next version, or we will wait ledger to review security fix )

Those are the 2 scenarios out of my head I wrote, but I think we can create much more.

I think 3 things are essential in this kind of system:

  • Audit trail
  • Being able to revoke the Transaction Interaction
  • Being able to revoke an Auditor

I think storing on chain covers all those cases.

I am strongly in favor of making Interaction Templates a integral part of Flow Blockchain. More like contracts in contracts domain, interactions can be stored interactions domain. They can be audited ( even better vouched for by anybody )

Also I think making wallet’s work here minimal is critical. As we slowly see rise of new wallets, which is exciting, keeping them in feature parity will be challenging at best.

Who controls this on chain repository?

  • The dapp?
  • The auditor?
  • The wallets?
  • Someone else?

Contract can be deployed by Service Account ( if it will be contract ) Considering Service Account is God like anyway.

edit: btw it will not be controlled by Service Account, easily will be self governed.

Can this not be controled by a community consiting of all of the above? I belive the USDC contract has OnChainMultisign. This could be used here so that atleast x amount of signers have to sign to approve a change? And since it is onChain then you can audit if somebody approves something that is not good.

Auditors could perform audits any number of times using a specific key(s) on the account(s) they maintain.

For example, an auditor may choose to perform all of their audits using the same key on an account. Alternatively, they may put a new key on their account when generating each new audit - having a 1:1 relationship between audit and key. This way, the auditor could revoke the individual key on their account to show to verifiers of the audit that they no longer vouch for it.

An auditor could bundle audits to keys used to generate them in any number of ways, perhaps one key per audit, or one key per grouping of audits.

I’ve updated the FLIP to highlight these points in more clarity:

Interaction Audit Revocation

An auditor may want to revoke an audit they previously produced.

To do so, the auditor will execute a transaction to revoke the key corresponding to key_id on the account corresponding to address on the data.signer of the Interaction Template Audit.

Interaction Audit Creation

When an auditor creates an Interaction Template Audit, they do so by creating a signature over the data.id of the Interaction Template they’re auditing. The key used to generate this signature corresponds to a key on an on-chain account the auditor maintains.

When generating this signature, the auditor may choose to use a unique key pair to do so. They may alternatively choose to use a key pair thats previously been used to create signatures for other Interaction Template Audits.

If the auditor chooses a unique key-pair for each Interaction Template Audit, they can revoke this individual key at a future date, thereby revoking a single audit. If a key was used to produce multiple Interaction Template Audits, the revocation of the single key would revoke multiple audits.

An auditor can choose to “bundle” Interaction Template Audits to keys used to generate them in any number of ways.

Interaction Audits Verification

A verifier of an Interaction Template Audit should first check that the key_id on the account corresponding to address on the data.signer is not revoked. Then the verifier should check that the signature is valid for the key_id on the account corresponding to address on the data.signer. If both checks pass, the Interaction Template Audit should be considered valid.

I put out a lot of reasons why this will be better on chain, I even gave example of certificate transparency from Server Certificates, audit trail, revoking, hostile auditor, leaked keys etc. Those are the tip of the iceberg.

Coming to me with “having a 1:1 relationship between audit and key” starting to feel like Dragon in my Garage [0]. You guys are building a blockchain but for some weird reason, everything you want off the chain.

Sorry to say, but more and more things are getting decided internally or maybe considerations are not shared enough with community vibe I am getting lately.

I am always trying to stay on technical side recently, but this proposal also has a lot of political consequences. This is not discussed in the FLIP.

[0] http://people.whitman.edu/~herbrawt/classes/110/Sagan.pdf

Edit: Also there can be some pros of keeping it not on chain, and I may be missing them, so it would be nice to hear that as a reply, I re-read my comment here now, feels like little attacking but I am totally opposite, I mean this is one of the best and most needed FLIPs and @JeffreyDoyle made a great job with it.