Wallet Connect V2 support for BitcoinCash

Hey everyone,

with an advent of CashTokens in May 2023 Bitcoin Cash contract system became even more powerful allowing for many new user facing applications. An example for that is an emerged series of NFT projects - Emerald DAO, BitCats Heroes Club, BCH Guru the first marketplace to trade CashTokens - TapSwap Cash. All these projects except BCH guru are powered by Paytaca Connect, a feature I have developed for Paytaca’s web extension. This approach has shown its power by highly resembling the Web3-enabled wallet behaviour, making these apps non-custodial, not requiring the user to import their private key or their seed phrase, increasing the security of user’s funds. The dApp-Wallet communication protocol involved is utilizing most basic primitives from LibAuth, ensuring safe and fast transaction building. The new version of WalletConnect, v2, became non-EVM bound, multi-chain protocol for exchanging arbitrary messages. I have been exploring the application of the Paytaca Connect protocol on WalletConnect v2 message relay framework for exchanging BCH-specific messages for signing messages and transactions, providing access to the relevant wallet information, etc. I have scored a success in this proof-of-concept and went ahead with its implementation in Cashonize (wallet) and TapSwap (dApp) (see this video demonstration).

I want to discuss my work with broader community in an effort to shape a spec or CHIP out this.

I have documented the message exchange protocol I use with WC2 which is employed in transaction building, message signing and wallet data communication. As well I have supplied a universal Wallet Connector implementation (supporting both Paytaca Connect and WalletConnect2) for react-js which I created for use in tapswap.

8 Likes

I had to remove the links to the projects mentioned in OP due to the platform limitation of 2 links per post for new users.

2 Likes

@mainnet_pat thanks heaps for putting all this together! I’ve been playing around a bit with WC and your Cashonize fork (I may have a few PR’s incoming - some bugs that I’ve run into, but overall works really nicely!).

Regarding the interfaces, there’s an additional method that should probably be implemented for retrieving the Public Key (as opposed to the derived addresses). This is needed for contracts that use CHECKSIG or CHECKDATASIG. An existing example contract that would require this would be the mutual redemption use-case of the AnyHedge Contract (see params for hedgeMutualRedeemPubKey and longMutualRedeemPubKey):

The interface could be near identical to the bch_getAddresses interface (but perhaps labelled bch_getPubKeys or something). At first I was thinking it could even replace bch_getAddresses (as addresses could be derived from the pubKeys), but some wallets might want to grant explicit permission for PubKey retrieval (to guard against the hypothetical attack where ECDSA is broken).

If it helps, happy to submit a PR to your Cashonize fork for an initial implementation of this bch_getPubKeys method. Let me know if that sounds okay.

1 Like

I’ve spoken to Pat out-of-band and insertion of the PubKey is already supported in the bch_signTransaction API (obvious but didn’t occur to me at the time, use-case was a bit different - see Supporting Script Population below), so this might be unnecessary (and, as Pat explained, some might view it as contentious?) There are a use-cases where it is required, but we might be able to handle these use-cases more elegantly. Will try to outline these (along with some other feedback/considerations) below.

NOTE: Some ideas below might be bad/unworkable. For those that sound acceptable, I’m happy to try to do the work to PoC these in Pat’s Cashonize Wallet fork.

Background on the Placeholder Approach

The current spec is very simple in that it supports using zero-byte placeholders within encoded transactions to populate inputs (pubKey, signature). This allows it to work with native transaction encoding formats, which (should) maximize compatibility across existing BCH libraries and wallets. Essentially, forEach input:

  • Replace 65 zero-byte OP_PUSH with signature.
  • Replace 33 zero-byte OP_PUSH with pubKey.

This allows us to work with both LibAuth and CashScript (and other libs and wallets) easily as we are using BCH’s Native Transaction Primitives.

If the following is viable and we retain this placeholder approach, I don’t think it is worth supporting LibAuth’s TransactionBCH payload in spec and are better off just using the Encoded Transaction Primitive. This will make WC compatibility much simpler/easier for non-JS wallets to implement - e.g. Electrum Cash, @tom’s Flowee Pay, Bitcoin.com, etc). From a LibAuth point of view, it is only an additional encodeTransaction(transactionBCH) to get it into this form too. More broadly, the more that we can retain use of standard primitives, the easier it will be for Wallets to integrate.

Placeholder Limitations and Potential Solutions

In terms of the placeholder approach, the big limitation I’ve noted with use-cases I’m working with is that it does not (currently) allow for parameters (or flags) to be specified. For example, it does not currently support a Wallet signing a dataSig and nor does it support partially signed transactions (I do not actually have a use-case right now for this, but suspect there will be some).

We might be able to keep the current placeholder approach and still support these by (perhaps) doing something like the following:

Supporting DataSig

NOT VIABLE: See Wallet Connect V2 support for BitcoinCash - #5 by bitcoincashautist

DataSig’s are 64 bytes long. We could therefore look for an OP_PUSH 64 bytes with 32 leading zero-bytes. The remaining 32 bytes could then represent the SHA256 (32 byte) message hash. I’m a mathlet (so verification of my figures here would be good), but I think the chance of an organic DataSig leading with 32 zero bytes would be: 1 / (2 ^ 256) = 1 / 1.157920892373162e77.

I’m unsure whether ending up with an organic leading 32 zero byte dataSig is feasible in practice, if someone could chime in here, that would be most helpful.

Support Partially Signed Transactions (sigHash flags)

Signatures are 65 bytes long. We could therefore look for an OP_PUSH 65 bytes with 64 leading zero-bytes. The remaining 1 bytes could then represent the sigHash flags for signing ( Bitcoin Cash Protocol Documentation ). I think the chance of an organic signature leading with 64 zero bytes would be: 1 / (2 ^ 512) = 1 / 1.340780792994260e154.

(Again, I’m a Mathlet, so would appreciate someone chiming in on feasibility of actually organically producing a 64 zero-byte leading signature. If the 32 zero-byte above is safe, then this certainly should be too?)

Supporting Script Population

There are situations where we may want to build lockscripts without actually signing a transaction - but these might have a User’s PubKey (or a DataSig) as a pre-requisite. Imagine the following CashScript contract:

contract Contract (
    // ...
    pubkey userPubKey,
    datasig userSignedMessage,
) { ... }

Currently (using Cashonize), there is a workaround in that we can pass in a full transaction with the desired Locking Script as an Unlocking Script input (that we never broadcast and has spoofed parameters) to bch_signTransaction and then extract the resulting populated Unlocking Script from the returned SignedTransaction. This feels a bit dirty though - and it’s probably a bit incidental (implementation-specific) that it works.

We might want another interface for this sort of case (e.g. bch_signScript - but I don’t know if this name necessarily reflects what it always does?).

Batching Requests

We may want to combine the bch_signTransaction into a bch_batch interface that supports both transactions and populating bytecode with the necessary parameters.

@mainnet_pat has already suggested this (as bch_batchSignTransaction), but it might be advantageous if we allow this to batch any method? E.g.

[
  {
    method: "bch_signScript",
    payload: { ... }
  },
  {
    method: "bch_signTransaction",
    payload: { ... }
  }
]

From a Wallet UX point-of-view, these can be presented/approved one-at-a-time. IMO, the real benefit of this is that it can on some painful UX on Mobile Devices whereby many mobile devices/browers will kill the WebSocket (and WalletConnect) connection when the tab is non-visible. Without it, (I think?) the user would have to flick back-and-forth between App Tab and Wallet for each step required (so that the app can re-instantiate WC connection and send the next request). It might also enhance security in that a user approves a batch of actions before responding to wallet - if any are declined, the entire batch is disregarded, preserving privacy (you either get all or none).

An additional benefit (for a future iteration of the protocol) is that we might also be able to instantiate a Wallet Connect backend flow that performs a single set of batch operations and then immediately disconnects (@sahid.miller called out a valid concern here where a backend session can persist indefinitely until the wallet explicitly terminates it: Telegram: Contact @bch_wc2 ).

There might be an elegant way to “chain” the results of this batch call so that the result of the previous operations are available to those that follow, but this might be over-ambitious for now.

Contract in sourceOutputs

Apologies, I haven’t looked much at the contract portion of this, but it looks like this might just be to provide extra “humanizing” context to the Wallet UI for approval of a bch_signTransaction?

If that’s the case, I think the approach that Pat’s suggested here might work better:

... [we can lookup] contract information by looking up a redeem bytecode (stripped of contract function and constructor arguments) from a specialized contract registry akin to 4byte.directory.

If it’s only use is humanizing some of the contract parameters, leaving this out of spec (or making-optional) and having wallets look up the artifact from unlocking bytecode as a “best practice” would probably simplify many implementations. (Perhaps this could work similar to BCMR?)

locking and unlocking bytecodes can be obtained from Fulcrum and contract information by looking up a redeem bytecode

I’m inbetween on this. Personally, just to simplify wallet implementations (and shift the heavy juggling away from the wallet and to the app), I think it’s better if the App provides these to the wallet. Otherwise, I think we’ll find weird bugs in wallets that might make assumptions (e.g. all inputs are P2PKH) that kill compatibility? (i.e. an app’s WC flow works on one wallet, but mysteriously fails on another - BIP70/JPP implementations were like this).

Not really sure if what I’ve got above is feasible in practice, just spit-balling on how we might be able to simplify this part of the spec for wallets.

Final Thoughts

I don’t think we should (or need to) aim for perfection with this first iteration, but should strive to make it versatile just so that interesting use-cases can be realized (and demonstrated). We can work on improving the protocol/interfaces for better UX once we’ve got a more concrete idea of the many use-cases that are available and common contract patterns (imo, we’re still discovering these). As a stop-gap between now and then, I think what Pat’s built (with a few amendments) would work very well.

In general, from my point of view, I think that we should:

  • Aim to keep the spec/implementation simple and try to use existing BCH primitives. This will allow easier integration for other wallets (working with BIP70/JPP, this has been a nightmare). It also minimizes technical debt for when the next iteration is built and we still want to retain support for this version.
  • Try to make it so that we can support the placeholders that many contracts will likely require in the long-run (dataSig, sigHash flags).
  • Support basic batching. This one isn’t really that important imo and I’m not sure if it will really help UX that much. But, if it can be done simply, it might be worth it (though many contracts will probably still require multiple batched steps? E.g. mint tokens → construct contracts). I mention it above more-so because I think the idea of being able to batch any method gives us the most flexibility (as opposed to specific methods for specific batch ops).
3 Likes

This would work, BUT there’s one big security problem with it. The signer MUST be presented with the full message, not just the hash, else he could be fooled into blindly signing an actual transaction that spends coins locked by his keys.

2 Likes

Great point! We probably need to find a way to explicitly pass in parameters (perhaps as an extra argument to bch_signTransaction). Something like:

{
  "transaction": '${txHex}`,
  "params": ["pubKey", "schnorr:someMessage", ...], // Replace the placeholders, in order that they appear, with these?
  "sourceOutputs": { ... }
}

Would love suggestions on how we might be able to do this if people have some.

2 Likes

Lot’s of food for thought in this post, so thanks for compiling and sharing this @jimtendo.

@bitcoincashautist brings up a good point about unwittingly signing something that’s actually a contract. That’s an issue at several layers. To work around it, we could include a “bch_unsafeSignMessage” that has the same security concerns as “bch_signTransaction” and handled by the Wallet UX - but issue with that though is social engineering and uninformed users/devs abusing the method. Also, messages are often encoded to something non-human readable before being signed so there’s a limited amount we can present to the user without more complexity (allowing wallet to encode for example).

But without bch_unsafeSignMessage we’d have to inform developers that:

  1. Contracts/applications that can include magic (while having same functionality), should. Then they can just use the safe bch_signMessage.
  2. Contracts/applications that can’t include magic (without breaking functionality), should consider using bch_signTransaction. Then they can treat any information embedded in the transaction as a signature in their application or with introspection.

I’m not sure that’ll fly for most developers, so a “bch_unsafeSignMessage” might be necessary… Also, similar might apply to partially signed transactions - if we don’t have a placeholder for sigHashFlags or wide support for it in wallets, then introspection is a natural alternative.

2 Likes

Just need to point out that this is not a given. A public key should only ever use one type of signature, and you assume Schnorr which may not be safe or possible in the scenario it is used in.

(secondly) The reading of ‘op-push 65’ implying it is a signature is hackish, it may work most times. But the proper way is to pattern match the output script it is unlocking and then you just use the n-th push based on which locking script you find. Like p2pkh.

And I have to, for completeness sake, be a bit negative on this approach. This is impossible to do securely. People will lose their coins with this approach as they need to essentially trust the ‘connected’ component. Even if the tech is perfect, the user can not possibly decide if the thing they Ok to is indeed safe or Ok. Hence, they need to trust it. The social attack surface is basically huge. Make an attractive looking site, ask for wallet connect and ask to sign something the user doesn’t understand following with the emptying of the wallet. :man_shrugging:

1 Like

Guys, thanks very much for the feedback! Very good points raised and it’s good to finally get discussion rolling on this.

I’m going to experiment on my end to see if I can address some of the concerns posted. I have a few ideas that hopefully, at minimum, can bring us to security parity (if not beyond) the “WebApp Wallet” approach that is currently used (where BCH is deposited temporarily into a WebWallet and contracts/txs are constructed). Will report back in a few days once I’ve tested feasibility and determined complexity of this.

To cover this, we probably want to avoid any direct signing operations in the spec (i.e. all sign operations MUST do the SHA256 themselves sign(sha256(message)) to prevent a hash being passed in).

But there’s another slight risk to this: as @sahid.miller pointed out to me, more often that not, a message that is being passed in to be signed is already going to be encoded (thus, not really human-readable). Therefore, a malicious service could still pass in a full transaction for us to sign(sha256(transaction)). Most users (myself included) probably wouldn’t recognise this.

As mitigation, we might be able to detect this by mandating a check of the message. Something like so:

function doesMessageToSignLookMalicious(message: Uint8Array): boolean {
  // Attempt to decode the message as a transaction (LibAuth example).
  const decodeTransactionResult = decodeTransaction(message);

  // If a string is NOT returned, then this message is encoded as a transaction and is LIKELY malicious.
  if (typeof decodeTransactionResult !== 'string') {
    return true;
  }

  // Otherwise, it's not a transaction (not malicious).
  return false;
}

Are there any similar cases that anyone can think of that could be dangerous like this? Or perhaps specific sigHash cases (I think the Covered Bytecode always includes the tx version, locktime, etc, so it should always have to be encoded as a transaction)?

1 Like

Very important initiative Pat! Will be reviewing your open PR to add wallet connect v2 to Cashonize, hoping to have it merged soon!

The Paytaca browser extension and newly released Zapit browser extension both use the same “Connector interface” as wallet connect but it would be good if we can fully converge on the wallet connect standard.

It is interesting to think about the tradeoffs with a built-in webwallet (like BCH Bull) which only holds a limited set of funds an directly forwards that to a smart contract. I think wallet connect helps a lot in that wallet information is communicated automatically (the wallet address and hence the UTXOs which gives the wallets balance and unique tokens). The big improvement in security will only come when the wallet understands what smart contract template the web3 app is using, otherwise it is still signing transactions without understanding their full context.

In short, I think wallet connect v2 is the way forward for smart contract apps on BCH. We should attempt to attempt to extend the specification so it supports the different smart contracts we can anticipate, we should try to converge on wallet connect v2 for different wallets across the BCH ecosystem, and finally we should strive to keep improving the set-up with templates, so wallet can start to recognize the specific transactions they are signing.

1 Like

Hi all, just reporting back with a quick summary/dot-points of my thoughts/experiments. Happy to expand on any of these if anyone would like more info, but will try to keep this summary relatively concise.

  1. To achieve good security, we really need a flow/templating engine (one RPC call, multistep).
  2. We would want wallets to be able to somehow support whitelisting this template/RPC payload.
    1. This could be done by SHA256 hashing the template and then looking up that hash in a trusted directory (or could be hard-coded in wallet - but former is probably better).
    2. The hashing would have to allow specific variables to be omitted (e.g. imagine an expiresAt/maturesAt parameter in a contract - or an OracleMessage).
  3. @bitjson is already working on a template schema which looks very good but is still WIP (?).
    1. Once complete, we could probably use WC as a transport for Jason’s templates.
    2. Jason’s templates use the concept of entities - may be able to support multi-entity if we assume one participant is the “co-ordinating party” (i.e. each entity sends to the co-ordinating party/entity and that party relays what’s needed to other entities). Would need to think more on this.
    3. Implementation into WebWallets that use LibAuth should be very easy (LibAuth supports these already) - other wallets/languages will be more complex and we will likely need to be build parsers (probably high-effort).
  4. My recommendations for now:
    1. We proceed without support of templates and mark current RPC’s as experimental (with intent to deprecate). This lowers security but allows us to experiment with different CashToken use-cases. Later, once finalized/stable, we look at an RPC to support Jason’s templates.
    2. We try to keep the current RPC minimal to allow easy integration into other Wallets (we don’t want a situation where this proto is hard for wallets to implement and support for specific features across wallets becomes patchy).
    3. We add a bch_compileScript (or similar) RPC parameter so that we can support lockscript compilation (think of CashScript Contract’s constructor - sometimes we need user’s Pubkey or a Datasig when trying to build a contract address).
  5. On my end, I’m working on a few things:
    1. A BCH WalletConnect TS/JS library for easy integration into wallets. This is to try ensure we maintain interoperability between wallets. The idea is that the necessary hooks will be passed into the constructor (e.g. approveSignTransaction: (...) => { ... }) but the rest of the logic/RPC can be handled by the library. It should also make it easier to see what’s required to port to other langs (or build custom implementation if so desired). Hoping to have code up for this next week.
    2. I’m toying with a basic template/flow RPC currently. This is, at most, a stop-gap and I’m not sure we’ll ultimately want to integrate this. The idea here is to propose a template engine that’s easy/simple to port across languages in case we need it. Timeline for this is longer - I’m not treating it as priority, just something for consideration in case we do need a stop-gap between now and LibAuth Templates that’s more secure than current approach.
5 Likes

Hi all, sorry for radio silence, just want to provide a brief update.

  1. Originally, I thought that maybe we should keep WC as a “dumb signer” (dependent upon Private Keys only), but @sahid.miller has persuaded against this. It is probably best to have the capability for WC to be (optionally) provided with UTXOs by the wallet. This enhances security, privacy and (probably) reliability.
    1. With CashTokens, selecting appropriate unspents (and adding change) becomes more complex. There is a lot of room for error if the service is selecting UTXOs and could easily lead to accidentally wiping out a user’s tokens (omission of token change output).
    2. Enhances privacy: Service cannot see all of the users unspents and addresses (pertinent when it comes to HD Wallets). This means we’ll likely want an explicit bch_getBalance_V0 like call as the service will not longer be able to calculate balance itself (this RPC should also allow parameters to retrieve token balances).
    3. Enhances security (and probably simplicity): It should be (relatively) trivial for a wallet to show a user how much of their own funds (wallet-controlled unspents) are being drained with a given transaction.
    4. This may also allow us, in future, to allow WC to allocate each individual service its own Signer Keypair (enhancing privacy/security).
      1. “In future” because there are some complications with this from a service implementation point of view: Service would have to introduce a backend dependency so that it could PROVE it is who it says it is.
  2. I’m still working on:
    1. a TS/JS WC Library for easy integration into wallets, but this might be another week or two away as I try to properly flesh out the above.
    2. I might also create a TS/JS WC Library for services - at the very least, I’d like to have the RPC interfaces available.
  3. Regarding templates, I’ve noticed that people are familiarizing themselves more with the LibAuth Templates. I probably won’t have support for these in my first (experimental) release of any library, but have been tinkering a bit and think we might eventually want to replace individual RPC methods with a singular bch_authTemplate_V0 RPC call.
    1. For now, we might want to suffix all RPC calls with _V0 to indicate that they’re experimental and subject to change.
    2. For Auth Template variables, we may want to see if Jason can add a “type hint” field - the intent of this is to give a hint to Wallet UI’s as to how a particular data payload should be displayed in the wallet UI for approval (e.g. cash.oracles.priceMessage, unixTimestamp, etc). If a wallet does not support a given hint, it can just fallback to hexadecimal display.

Will try to give another update with some examples in a few days. If any questions, or elaboration on points above desired, let me know and I’ll follow up.

4 Likes

Hi all, just an update:

LibAuth Templates

Some of the contracts I’m testing with are quite complex - and after trying many different approaches (and then realizing they can’t do what we’d need it to do), I’ve eventually settled on using LibAuth templates for the signTransaction/compileScripts calls. This has several benefits:

  1. We will hopefully be able to eventually converge on what BitJSON is building (so we don’t end up with fractured standards).
  2. CashASM (used by LibAuth Templates) is very flexible/powerful.
  3. These templates are hashable - thus, we can provide methods for whitelisting a given template.
  4. Code to handle these is pretty simple/clean.
  5. With good tooling, it is relatively trivial to convert CashScript Artifacts to LibAuth templates.

On Point 5, I’ve created a rudimentary tool for this here:

https://tools.developers.cash/#/tools/artifacts-to-auth-template

(A more refined and well-thought out version might eventually be integrated direct into CashScript Lib).

Wallet Connect Library

I’m testing the Library I’m building by integrating into a forked version of Cashonize. Cashonize is HTML/VanillaJS and I’m not very efficient at working with that - so it may take me a little longer than anticipated to get a demo out.

However, I just want to give an example of how this library might be used to integrate into other (TS/JS-based) Wallets in future:

const walletConnect = new WalletConnect(
  'yourWCProjectId',
  {
    name: 'Cashonize',
    description: 'Cashonize BitcoinCash Web Wallet',
    url: 'cashonize.com/',
    icons: ['https://cashonize.com/images/favicon.ico'],
  },
  {
    // Session Callbacks.
    onSessionProposal: (sessionProposal) => {
      // Present UI to approve session.

      // Get master WC Private Key from Derivation Path.

      // NOTE: Each service will derive its own Sandboxed Private Key from the given Master Key.
      //       E.g. sandboxedPrivateKey = hash256(Uint8Array([...masterPrivateKey, ...serviceId]);
      //       Where serviceId is the WC Project ID.
      // NOTE: The RPC's are intended to be transport agnostic so, in future, serviceId might refer to a Domain, LibP2P pubkey, etc. 
      // return { masterPrivateKey }
    },
    onSessionDelete: {
      // Notify user that session was deleted.
    },

    // RPC Callbacks.
    // NOTE: Wallet might choose to auto-approve some RPC calls.
    onCompileScriptV0: (session, req, res) => {
      // Present UI to approve RPC call.
    },
    onGetBalanceV0: (session, req, res) => {
      // Present UI to approve RPC call.
    }
    onGetTokensV0: (session, req, res) => {
      // Present UI to approve RPC call.
    },
    onSignTransactionV0: (session, req, res) => {
      // Present UI to approve RPC call.
    },
    
    // Wallet Connectivity.
    getUnspents: () => {
      // Provide Unspents from Wallet to WalletConnect.
      // return unspents;
    },
    getSourceOutputs: (sourceOutputs) => {
      // Provide Source Outputs to WalletConnect.
      // return sourceOutputs;
    },
    getChangeAddresess: () => {
      // Haven't fleshed this one out yet, but will likely need it.
    }
  }
);

// Start Wallet Connect.
await walletConnect.start();

Note that the above is still being fleshed out - so will likely change quite a bit.

3 Likes

Self-shill, but I think it’s valuable. Extended section of the latest BCH Podcast with Emergent reasons dives a lot into the ideas around transaction templates and wallet standards the community can converge on.

I have rewatched it already twice myself.

4 Likes

Hoping to have a write-up and demo available of what I’ve got so far either late tomorrow (Sunday) or Monday.

Just want to write up some tooling too so people can fool around with it.

2 Likes

Any such thing should keep security in mind.

In short, when the user is incapable of looking and understanding at the script or bytearray the “can we sign this thing?” shows, it probably isn’t secure.

Trusting 3rd party things that spend your money is mostly a bad idea.

Hi all, apologies for delay. I’m just working on some tooling and experimenting with a slight refactor in my approach that might allow us (in future) to better support multi-sig/multi-entity contracts.

Basically, for bch_signTransaction_V0, the implementation I have right now returns:

  1. The transaction.
  2. The redeem script for each output.

The redeem scripts are necessary in many cases because, otherwise, the service would only have access to the Script Hash and would not be able to reconstruct the data required for redemption in a later transaction (or, in some cases, for a Settlement Service).

With a bit of customization to the LibAuth generateTransaction method, we might be able to return resolved variables/scripts instead: This would give us a few advantages:

  1. Retrieval of Redeem Script Construction Parameters is simpler (could extract by variable name instead of splitting on PUSH_OP positions).
  2. Multi-entity contracts would (probably) become possible in the sense that the bch_signTransaction_V0 RPC could return Resolved Variables even in the case where construction of a fully signed transaction was not possible (in a multi-entity setup, if we assume one party as co-ordinator, I think we may even be able to use this with WC).
  3. We can probably eliminate the need for the bch_compileScript_V0 method as we would now have access to variables resolved in referenced scripts (and the scripts themselves?). I was using this RPC as a way to construct a lockscript that could be passed as a locking parameter of another contract).

I need to investigate/experiment a bit more, but provided CashASM parser behaves as follows:

  1. A referenced script is returned as a resolved variable.
  2. A Bytecode Variable is returned as a resolved variable.
  3. Inline evaluations ARE NOT returned as a resolved variable (security).
  4. A referenced script containing the same name as a Bytecode variable takes precedence (i.e. overwrites) the value of a resolved variable (not sure if this is really essential, but it allows us to keep some information hidden from the service for datasigs - which might be useful in some cases).

… I think this is possible.

Regarding tooling, I’m aiming for something like this where it can take multiple contracts, combine them into a LibAuth template and then test them in-tool with WC by providing the tx template + data:

Should have this tool available to play with by week’s end latest, with a customized version of Cashonize that’ll work with it. Hoping people will be able to test more advanced multi-contract flows to see whether this approach would actually be workable in practice or not.

Thanks all.

4 Likes

Hi all, sorry this is taking a lot longer than anticipated. It’s kind of a “three steps forward, two steps back” exercise where I write an implementation, realize there’s a use-case gap, and then have to redesign and refactor.

To give a brief high-level outline of what I’m going for:

BRIEF OVERVIEW

  1. To help preserve privacy (inc. with HD Wallets) and improve security, the Session established between Service (“Dapp”) and Wallet uses a Sandboxed Keypair generated using sandboxedPrivateKey = hash256(sha256(masterPrivateKey) + sha256(domainName)).
  2. This PoC uses LibAuth templates. In future, these template can be hashed and whitelisted (trusted) by a wallet. For security, the Service (“Dapp”) can only specify inputs and outputs by their corresponding scripts in the provided template (no raw locking/unlocking bytecode allowed).
  3. The Service (“Dapp”) CAN request that the Wallet provides additional UTXOs to automatically meet the Satoshi and Token amounts that are summed in the outputs. In this respect, UTXO selection is done by the Wallet, but the Service can also provide inputs that it knows about.
  4. The Service (“Dapp”) CAN request a Wallet’s UTXOs provided they a) contain tokens and b) access to those token category ID’s have been granted upon Session Negotiation (sessionProperties.allowedTokens as an array of category ids or * for ALL tokens). This allows us to support token-specific use-cases (e.g. a particular NFT as input or more vague Crypto-Exchange use-cases).
  5. To prevent standards fracturing, the underlying RPC’s are intended to be transport agnostic: They should be applicable to HTTP, LibP2P any other transports (not just WalletConnect). Thus, we should be able to use them for a future HTTP-based Payment Protocols, etc.
  6. The hope is that, in future, we will be able to converge with what BitJSON is building. The idea is that a wallet CAN (if the template is natively supported) save the data payloads and use the built-in Wallet UX to execute contract actions. But, for WC, the idea is that the SERVICE (“Dapp”) stores the data associated with a given WC account.
  7. There is currently no support for batching requests (or “actions”): We could build this, but BitJSON is working on something similar (“actions”) and we should probably wait to see what his implementation looks like. These will likely replace specifying the transaction manually. NOTE: This is no longer the case and we will need basic batch/actions support. I’m reaching out to BitJSON to see if he knows approx. what this may look like in his implementation so that migration to it is less painful in future, but am going to use a very rudimentary approach in the meantime.
  8. Type-hinting is currently hacked into a variable’s description field. We want to think a little about how to handle this as they are not always static (e.g. using oracles.cash, we may set a price - but we want that to show depending upon which Oracle was chosen in another variable according to the scaling factor).
  9. Currently, the bch_signTransaction_V0 RPC returns redeem scripts for the compiled outputs, but we want to return resolved variables instead (I think this’ll both simplify things and potentially allow us to support multisig).
  10. Accounts are currently identified by address - but there are some benefits we may gain if we use the Public Key instead (e.g. ability to sign and encrypt messages for another user on a Dapp given their pubkey.)

I really hope I can get a tool that’ll be able to demo most of the above by Monday. Assuming my current approach is versatile enough, I think this is realistic. But, if I bump into another use-case gap, might be a bit longer still (apologies).

If any questions in the meantime, please feel free to ask.

5 Likes

Update here:

4 Likes