AJ, Interesting stuff! Just a couple thoughts on these proposed opcodes, at least one we discussed elsewhere: 1) OP_FORWARD_SELF is a JET of OP_FLU in the revaulting common case. Maybe obvious but I missed this initially and thought it was useful to be pointed out. 2) Using these extended primitives, you can do rate-limiting of the two step unvaulting, or just a single step vault by committing to the partial values. For the single stage case it's something like: $recovery = Same As Before $withdrawal = OP_CSV OP_DROP OP_CHECKSIG OP_DUP OP_LESSTHANOREQUAL OP_VERIFY OP_FORWARD_PARTIAL OP_FORWARD_TARGET OP_FORWARD_SELF $withdrawal is spent by: <0<=v<=V> where "V" is the max allowed withdrawal value, and "deposit-delay" the required gap in withdrawals Due to the OP_LEQ, you are bound to ~21 BTC in value for this operation, but for larger vaults it's pretty trivial to add larder fixed denominations to "peel out" value until you get to your final ~21 BTC. This rate-limiting(in either the two-stage or one-stage scheme) can limit the risk of theft during a watchtower outage to a constant value per utxo per time period of watchtower failure. As we've seen in the past with LN infrastructure, software risks are often correlated, so it's a good idea to build in belt and suspenders where we can or at least have them available when possible. Cheers, Greg On Tue, Mar 7, 2023 at 7:45 AM Anthony Towns wrote: > On Mon, Mar 06, 2023 at 10:25:38AM -0500, James O'Beirne via bitcoin-dev > wrote: > > What Greg is proposing above is to in essence TLUV-ify this proposal. > > FWIW, the way I'm thinking about this is that the "OP_VAULT" concept is > introducing two things: > > a) the concept of "forwarding" the input amount to specified > outputs in a way that elegantly allows merging/splitting > > b) various restrictions on the form of the output scripts > > These concepts go together well, because restricting an output script is > only an interesting thing to do if you're moving value from this input > into it. And then it's just a matter of figuring out a nice way to pick > opcodes that combine those two concepts in interesting ways. > > This is different from TLUV, in that TLUV only did part (b), and > assumed you'd do part (a) manually somehow, eg via "OP_IN_OUT_AMOUNT" > and arithmetic opcodes. The advantage of this new approach over that > one is that it makes it really easy to get the logic right (I often > forgot to include the IN_OUT_AMOUNT checks at all, for instance), and > also makes spending multiple inputs to a single output really simple, > something that would otherwise require kind-of gnarly logic. > > I think there are perhaps four opcodes that are interesting in this class: > > idx sPK OP_FORWARD_TARGET > -- sends the value to a particular output (given by idx), and > requires that output have a particular scriptPubKey (given > by sPK). > > idx [...] n script OP_FORWARD_LEAF_UPDATE > -- sends the value to a particular output (given by idx), and > requires that output to have almost the same scriptPubKey as this > input, _except_ that the current leaf is replaced by "script", > with that script prefixed by "n" pushes (of values given by [...]) > > idx OP_FORWARD_SELF > -- sends the value to a particular output (given by idx), and > requires that output to have the same scriptPubKey as this input > > amt OP_FORWARD_PARTIAL > -- modifies the next OP_FORWARD_* opcode to only affect "amt", > rather than the entire balance. opcodes after that affect the > remaining balance, after "amt" has been subtracted. if "amt" is > 0, the next OP_FORWARD_* becomes a no-op. > > Then each time you see OP_FORWARD_TARGET or OP_FORWARD_LEAF_UPDATE, you > accumulate the value that's expected to be forwarded to the output by > each input, and verify that the amount for that output is greater-or-equal > to the accumulated value. > > > ## Required opcodes > > - OP_VAULT: spent to trigger withdrawal > > - OP_VAULT_RECOVER: spent to recover > > Naming here is OP_VAULT ~= OP_FORWARD_LEAF_UPDATE; OP_VAULT_RECOVER ~= > OP_FORWARD_TARGET. > > > For each vault, vaulted coins are spent to an output with the taproot > > structure > > > > taproot(internal_key, {$recovery_leaf, $trigger_leaf, ...}) > > > > where > > > > $trigger_leaf = > >