Return-Path: <zachgrw@gmail.com> Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 9239BC002F for <bitcoin-dev@lists.linuxfoundation.org>; Wed, 29 Mar 2023 07:10:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 5777B41D78 for <bitcoin-dev@lists.linuxfoundation.org>; Wed, 29 Mar 2023 07:10:35 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 5777B41D78 Authentication-Results: smtp4.osuosl.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=f6Jzw6zc X-Virus-Scanned: amavisd-new at osuosl.org X-Spam-Flag: NO X-Spam-Score: -2.098 X-Spam-Level: X-Spam-Status: No, score=-2.098 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HpXrJbHlnqrZ for <bitcoin-dev@lists.linuxfoundation.org>; Wed, 29 Mar 2023 07:10:32 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org B914B41D76 Received: from mail-yw1-x1130.google.com (mail-yw1-x1130.google.com [IPv6:2607:f8b0:4864:20::1130]) by smtp4.osuosl.org (Postfix) with ESMTPS id B914B41D76 for <bitcoin-dev@lists.linuxfoundation.org>; Wed, 29 Mar 2023 07:10:31 +0000 (UTC) Received: by mail-yw1-x1130.google.com with SMTP id 00721157ae682-5416698e889so277297017b3.2 for <bitcoin-dev@lists.linuxfoundation.org>; Wed, 29 Mar 2023 00:10:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680073830; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=C7NskZD03Bedl/fUL+2smrockG2fHkkO/PNX5rTtSmk=; b=f6Jzw6zceZEgJnWQFyckanCibBwHMDo8sr3Zh4D1L6U7KsSzqAWii2kVbkWGSz5XXW P56+s6GM+TdVb1ePo78Tgl2/WOV9Q1VjwkU4WdZiFWE8pd//Gm2FWyF3OF1u4fiPoIyC TbRvRgxSz/sBQ1EIOoy5oJCLU38dsZve3zbHpSInmLxQXEQVJ1QQkd6UPfqDlaSaR8fE Bxfa8nIQiMStd/LibfiXEIUBVkp09+RP6TxN3Q3DW7X8Kh/ajSilqiidz3mCqYghIrzX MyxCoZTKXwLgh1SpFqd2kSZOC+I8+EOZx3F93EnAjBkR9RydOjsEF7Xw7AeF8O3ZdUEa Ir6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680073830; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=C7NskZD03Bedl/fUL+2smrockG2fHkkO/PNX5rTtSmk=; b=gB1rTTEebCrwy6e7rNbxNendNpiA7ZN/e6x/brZVdjj0S0zRaPyIXwPJB9y0PlxBBi ajmLug206GOpTpzXOq5jA+ozdmD257QS+O9xu/sTb6q+DhKGpMI/UralC9o4H8WmX9Su 4eTHSxEFZcucyDz2bLwhbunDVrZxhBR3ivFPXxPqyu+ufH146NAIH7LzI7BuQMl8PVN1 IBvZblI4KHT1ixvSBYyEPuFC+5OQmo9NirzYhwG4Z1UJocnU4jJ5S+h+vzujVJVUY6m6 21PLRppqihYO5jZU8bixriGCdDetCRnAdx7IEN48PI0Qk11snq7QUUFkCKZp0ZRHX/P4 AXTg== X-Gm-Message-State: AAQBX9dmstFwa/YE9Zc10+u1Ncf5t6fCYUrlaq31DT2uC8Y5kUmSIa7U aaxbbFLqOcHLQpqmVBnztZ+lD3XZEVIueOg9MUg= X-Google-Smtp-Source: AKy350ZNjslGroINmDyZEtXNxz1EBf+qk05kHi2vn2GFI7XPAWs8oXTd35l0MiHHzVbSiAfHNztQ2dmOFe/xw4f9Xks= X-Received: by 2002:a81:b620:0:b0:541:8995:5334 with SMTP id u32-20020a81b620000000b0054189955334mr8727408ywh.3.1680073830565; Wed, 29 Mar 2023 00:10:30 -0700 (PDT) MIME-Version: 1.0 References: <CAPfvXfJQKb7i8GBvTEvTTz-3dU_5mH8jOv8Nm4Q8gPt=KxrqLQ@mail.gmail.com> <CAB3F3DveCDz6yy-rd3ttV8+4sMufsvB+9J-qVK95yh9aLYX+Mw@mail.gmail.com> <ZAAqIZZO1KK32Th9@erisian.com.au> <CAB3F3DtGpVHkyT_=KLS42rvdP=dgnMvChhR1Rs0BHO5yOEabmw@mail.gmail.com> <CAPfvXf+4iX0h-nSuyTai_VvJHkDvAyKtgSk6DsaEwE8N3wnYEg@mail.gmail.com> <ZAcx7oEZxC9BiWvg@erisian.com.au> <ZB2THW3WT2wiU7Ni@erisian.com.au> In-Reply-To: <ZB2THW3WT2wiU7Ni@erisian.com.au> From: Zac Greenwood <zachgrw@gmail.com> Date: Wed, 29 Mar 2023 15:10:19 +0800 Message-ID: <CAJ4-pEAyuHi-1iBzYWbpUNi2-YkxFLVBKAWTV=TyP1TVTFYMfA@mail.gmail.com> To: Anthony Towns <aj@erisian.com.au>, Bitcoin Protocol Discussion <bitcoin-dev@lists.linuxfoundation.org> Content-Type: multipart/alternative; boundary="000000000000de0b9005f804ab5e" X-Mailman-Approved-At: Wed, 29 Mar 2023 09:09:19 +0000 Subject: Re: [bitcoin-dev] BIP for OP_VAULT X-BeenThere: bitcoin-dev@lists.linuxfoundation.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Bitcoin Protocol Discussion <bitcoin-dev.lists.linuxfoundation.org> List-Unsubscribe: <https://lists.linuxfoundation.org/mailman/options/bitcoin-dev>, <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=unsubscribe> List-Archive: <http://lists.linuxfoundation.org/pipermail/bitcoin-dev/> List-Post: <mailto:bitcoin-dev@lists.linuxfoundation.org> List-Help: <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=help> List-Subscribe: <https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev>, <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=subscribe> X-List-Received-Date: Wed, 29 Mar 2023 07:10:35 -0000 --000000000000de0b9005f804ab5e Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable I=E2=80=99m not sure why any effort should be spent on theorizing how new o= pcodes might be used to facilitate parasitical use cases of the blockchain. If anything, business models relying on the ability to abuse the blockchain as a data store must be made less feasible, not more. Zac On Fri, 24 Mar 2023 at 20:10, Anthony Towns via bitcoin-dev < bitcoin-dev@lists.linuxfoundation.org> wrote: > On Tue, Mar 07, 2023 at 10:45:34PM +1000, Anthony Towns via bitcoin-dev > wrote: > > 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 inpu= t > > > > 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. > > The BIP 345 draft has been updated [0] [1] and now pretty much defines > OP_VAULT to have the behaviour specced for OP_FORWARD_LEAF_UPDATE above, > and OP_VAULT_RECOVER to behave as OP_FORWARD_TARGET above. Despite > that, for this email I'm going to continue using the OP_FORWARD_* > naming convention. > > Given the recent controversy over the Yuga labs ordinal auction [2], > perhaps it's interesting to consider that these proposed opcodes come > close to making it possible to do a fair, non-custodial, on-chain auction > of ordinals [3]. > > The idea here is that you create a utxo on chain that contains the ordina= l > in question, which commits to the address of the current leading bidder, > and can be spent in two ways: > > 1) it can be updated to a new bidder, if the bid is raised by at least > K satoshis, in which case the previous bidder is refunded their > bid; or, > > 2) if there have been no new bids for a day, the current high bidder > wins, and the ordinal is moved to their address, while the funds > from their winning bid are sent to the original vendor's address. > > I believe this can be implemented in script as follows, > assuming the opcodes OP_FORWARD_TARGET(OP_VAULT_RECOVER), > OP_FORWARD_LEAF_UPDATE(OP_VAULT), OP_FORWARD_PARTIAL (as specced above), > and OP_PUSHCURRENTINPUTINDEX (as implemented in liquid/elements [4]) > are all available. > > First, figure out the parameters: > > * Set VENDOR to the scriptPubKey corresponding to the vendor's address. > * Set K to the minimum bid increment [5]. > * Initially, set X equal to VENDOR. > * Initially, set V to just below the reserve price (V+K is the > minimum initial bid). > > Then construct the following script: > > [X] [V] [SSS] TOALT TOALT TOALT > 0 PUSHCURRENTINPUTINDEX EQUALVERIFY > DEPTH NOT IF > 0 10000 FORWARD_PARTIAL > 0 FROMALT FORWARD_TARGET > 1 [VENDOR] FWD_TARGET > 144 > ELSE > FROMALT SWAP TUCK FROMALT > [K] ADD GREATERTHANOREQUAL VERIFY > 1 SWAP FORWARD_TARGET > DUP FORWARD_PARTIAL > 0 ROT ROT > FROMALT DUP 3 SWAP FORWARD_LEAF_UPDATE > 0 > ENDIF > CSV > 1ADD > > where "SSS" is a pushdata of the rest of the script ("TOALT TOALT TOALT > .. 1ADD"). > > Finally, make that script the sole tapleaf, accompanied by a NUMS point > as the internal public key, calculate the taproot address corresponding > to that, and send the ordinal to that address as the first satoshi. > > There are two ways to spend that script. With an empty witness stack, > the following will be executed: > > [X] [V] [SSS] TOALT TOALT TOALT > -- altstack now contains [SSS V X] > 0 PUSHCURRENTINPUTINDEX EQUALVERIFY > -- this input is the first, so the ordinal will move to the first > output > DEPTH NOT IF > -- take this branch: the auction is over! > 1 [VENDOR] FWD_TARGET > -- output 1 gets the entire value of this input, and pays to > the vendor's hardcoded scriptPubKey > 0 10000 FORWARD_PARTIAL > 0 FROMALT FORWARD_TARGET > -- we forward at least 10k sats to output 0 (if there were 0 sats, > the ordinal would end up in output 1 instead, which would be a > bug), and output 0 pays to scriptPubKey "X" > 144 > ELSE .. ENDIF > -- skip over the other branch > CSV > -- check that this input has baked for 144 blocks (~1 day) > 1ADD > -- leave 145 on the stack, which is true. success! > > Alternatively, if you want to increase the bid you provide a stack with > two items: your scriptPubKey and the new bid [X' V']. Execution this > time looks like: > > [X] [V] [SSS] TOALT TOALT TOALT > -- stack contains [X' V'], altstack now contains [SSS V X] > 0 PUSHCURRENTINPUTINDEX EQUALVERIFY > -- this input is the first, so the ordinal will move to the first > output > DEPTH NOT IF ... ELSE > -- skip over the other branch (without violating minimalif rules) > FROMALT SWAP TUCK FROMALT > -- stack contains [X' V' X V' V], altstack contains [SSS] > [K] ADD GREATERTHANOREQUAL VERIFY > -- check V' >=3D V+K, stack contains [X' V' X] > 1 SWAP FORWARD_TARGET > -- output 1 pays to X (previous bidder's scriptPubKey), and the > entire value of this input goes there; stack contains [X' V'] > DUP FORWARD_PARTIAL > -- execute "V' FORWARD_PARTIAL", stack contains [X' V'] > 0 ROT ROT > -- stack contains [0 X' V'] > FROMALT DUP 3 SWAP FORWARD_LEAF_UPDATE > -- execute "0 X' V' SSS 3 SSS FORWARD_LEAF_UPDATE" which checks > that output 0 spends at least V' satoshis back to the same > script (because that's how we defined SSS), except the first > three pushes (previously X V SSS) are replaced by X' V' SSS. > 0 > ENDIF > CSV > -- "0 CSV" requires nSequnce to be set, which makes the tx rbf'able, > which hopefully makes it harder to pin > 1ADD > -- ends with 1 on the stack; success! > > (The "SSS n SSS FORWARD_LEAF_UPDATE" construct is more or less a quine, > ie a program that outputs its own source code) > > I think that script is about 211 witness bytes, with an additional 40 > witness bytes for X'/V', so when making a bid, your tx would be > something like: > > tx header, 10vb > input 0: 103vb for the old bid including witness and control block > input 1: 58vb for a taproot key path spend > output 0: 43vb for the new bid > output 1: 43vb for your change > > for a total of about 257vb -- slightly larger than a regular 2-in-2-out > transaction, but not terribly much. Mostly because input 0 doesn't requir= e > a signature -- it's size is effectively 6 pubkeys: X, X' VENDOR twice, > and the script code twice, along with a little extra to encode the > various numbers (10000, 144, K, V, V'). > > This approach seems pretty "MEV" resistant: you pay fees via input 1 if > your bid succeeds; if it doesn't, you don't pay any fees. A potential > scalper might want to put in an early low ball bid, then prevent > higher bidders from winning the auction, take control of the ordinal, > and resell it later, but unless they can prevent another miner from > mining alternative bids for 144 blocks, they will fail at that. The bid > is fixed by the bidder and committed to by the signature on input 1, so > frontrunning a bid can't do anything beyond invalidate the bid entirely. > > Obviously, this is a pretty limited auction mechanism in various ways; > eg maybe you'd rather specify K as a percentage than an absoute increment= ; > maybe you'd like to have the auction definitely finish by some particular > time; maybe you'd like to be able to have the auction be able to continue > above 21.47 BTC (2**31 sats); maybe you'd like to do a dutch auction > rather than an english auction. I think you can probably do all those > things with this set of opcodes and clever scripting, though it probably > gets ugly. > > I don't think this is easily extensible to taro or rgb style assets, > as rather than being able to ensure the asset is transferred by > controlling the input/output positions, I think you'd need to build > up merkle trees and do point tweaks beyond what's supported by > OP_FORWARD_LEAF_UPDATE/OP_VAULT. Of course, without something like > OP_PUSHCURRENTINPUTINDEX I don't think you could do it for ordinals > either. > > Cheers, > aj > > [0] > https://github.com/bitcoin/bips/blob/7f747fba82675f28c239df690a07b75529bd= 0960/bip-0345.mediawiki > > [1] https://twitter.com/jamesob/status/1639019107432513537 > > [2] > https://cointelegraph.com/news/scammers-dream-yuga-s-auction-model-for-bi= tcoin-nfts-sees-criticism > > [3] Inscriptions remain a wasteful way of publishing/committing > to content, however! > > [4] > https://github.com/ElementsProject/elements/blob/master/doc/tapscript_opc= odes.md > > [5] Setting K too low probably invites griefing, where a bidder may be > able to use rbf pinning vectors to prevent people who would be willin= g > to bid substantially higher from getting their bid confirmed on > chain. > _______________________________________________ > bitcoin-dev mailing list > bitcoin-dev@lists.linuxfoundation.org > https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev > --000000000000de0b9005f804ab5e Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"auto">I=E2=80=99m not sure why any effort should be spent on th= eorizing how new opcodes might be used to facilitate parasitical use cases = of the blockchain.</div><div dir=3D"auto"><br></div><div dir=3D"auto">If an= ything, business models relying on the ability to abuse the blockchain as a= data store must be made less feasible, not more.</div><div dir=3D"auto"><b= r></div><div dir=3D"auto">Zac</div><div dir=3D"auto"><br></div><div><br><di= v class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Fri, 24 Ma= r 2023 at 20:10, Anthony Towns via bitcoin-dev <<a href=3D"mailto:bitcoi= n-dev@lists.linuxfoundation.org">bitcoin-dev@lists.linuxfoundation.org</a>&= gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0= px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex= ;border-left-color:rgb(204,204,204)">On Tue, Mar 07, 2023 at 10:45:34PM +10= 00, Anthony Towns via bitcoin-dev wrote:<br> > I think there are perhaps four opcodes that are interesting in this cl= ass:<br> > <br> >=C2=A0 =C2=A0 idx sPK OP_FORWARD_TARGET<br> >=C2=A0 =C2=A0 =C2=A0 -- sends the value to a particular output (given b= y idx), and<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requires that output have a particula= r scriptPubKey (given<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0by sPK).<br> > <br> >=C2=A0 =C2=A0 idx [...] n script OP_FORWARD_LEAF_UPDATE<br> >=C2=A0 =C2=A0 =C2=A0 -- sends the value to a particular output (given b= y idx), and<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0requires that output to have almost the same= scriptPubKey as this<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0input, _except_ that the current leaf is rep= laced by "script",<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0with that script prefixed by "n" p= ushes (of values given by [...])<br> > <br> >=C2=A0 =C2=A0 idx OP_FORWARD_SELF<br> >=C2=A0 =C2=A0 =C2=A0 -- sends the value to a particular output (given b= y idx), and<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requires that output to have the same= scriptPubKey as this input<br> > <br> >=C2=A0 =C2=A0 amt OP_FORWARD_PARTIAL<br> >=C2=A0 =C2=A0 =C2=A0 -- modifies the next OP_FORWARD_* opcode to only a= ffect "amt",<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rather than the entire balance. opcod= es after that affect the<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0remaining balance, after "amt" has= been subtracted. if "amt" is<br> >=C2=A0 =C2=A0 =C2=A0 =C2=A00, the next OP_FORWARD_* becomes a no-op.<br= > <br> The BIP 345 draft has been updated [0] [1] and now pretty much defines<br> OP_VAULT to have the behaviour specced for OP_FORWARD_LEAF_UPDATE above,<br= > and OP_VAULT_RECOVER to behave as OP_FORWARD_TARGET above. Despite<br> that, for this email I'm going to continue using the OP_FORWARD_*<br> naming convention.<br> <br> Given the recent controversy over the Yuga labs ordinal auction [2],<br> perhaps it's interesting to consider that these proposed opcodes come<b= r> close to making it possible to do a fair, non-custodial, on-chain auction<b= r> of ordinals [3].<br> <br> The idea here is that you create a utxo on chain that contains the ordinal<= br> in question, which commits to the address of the current leading bidder,<br= > and can be spent in two ways:<br> <br> =C2=A0 1) it can be updated to a new bidder, if the bid is raised by at lea= st<br> =C2=A0 =C2=A0 =C2=A0K satoshis, in which case the previous bidder is refund= ed their<br> =C2=A0 =C2=A0 =C2=A0bid; or,<br> <br> =C2=A0 2) if there have been no new bids for a day, the current high bidder= <br> =C2=A0 =C2=A0 =C2=A0wins, and the ordinal is moved to their address, while = the funds<br> =C2=A0 =C2=A0 =C2=A0from their winning bid are sent to the original vendor&= #39;s address.<br> <br> I believe this can be implemented in script as follows,<br> assuming the opcodes OP_FORWARD_TARGET(OP_VAULT_RECOVER),<br> OP_FORWARD_LEAF_UPDATE(OP_VAULT), OP_FORWARD_PARTIAL (as specced above),<br= > and OP_PUSHCURRENTINPUTINDEX (as implemented in liquid/elements [4])<br> are all available.<br> <br> First, figure out the parameters:<br> <br> =C2=A0* Set VENDOR to the scriptPubKey corresponding to the vendor's ad= dress.<br> =C2=A0* Set K to the minimum bid increment [5].<br> =C2=A0* Initially, set X equal to VENDOR.<br> =C2=A0* Initially, set V to just below the reserve price (V+K is the<br> =C2=A0 =C2=A0minimum initial bid).<br> <br> Then construct the following script:<br> <br> =C2=A0[X] [V] [SSS] TOALT TOALT TOALT<br> =C2=A00 PUSHCURRENTINPUTINDEX EQUALVERIFY<br> =C2=A0DEPTH NOT IF<br> =C2=A0 =C2=A00 10000 FORWARD_PARTIAL<br> =C2=A0 =C2=A00 FROMALT FORWARD_TARGET<br> =C2=A0 =C2=A01 [VENDOR] FWD_TARGET<br> =C2=A0 =C2=A0144<br> =C2=A0ELSE<br> =C2=A0 =C2=A0FROMALT SWAP TUCK FROMALT<br> =C2=A0 =C2=A0[K] ADD GREATERTHANOREQUAL VERIFY<br> =C2=A0 =C2=A01 SWAP FORWARD_TARGET<br> =C2=A0 =C2=A0DUP FORWARD_PARTIAL<br> =C2=A0 =C2=A00 ROT ROT<br> =C2=A0 =C2=A0FROMALT DUP 3 SWAP FORWARD_LEAF_UPDATE<br> =C2=A0 =C2=A00<br> =C2=A0ENDIF<br> =C2=A0CSV<br> =C2=A01ADD<br> <br> where "SSS" is a pushdata of the rest of the script ("TOALT = TOALT TOALT<br> .. 1ADD").<br> <br> Finally, make that script the sole tapleaf, accompanied by a NUMS point<br> as the internal public key, calculate the taproot address corresponding<br> to that, and send the ordinal to that address as the first satoshi.<br> <br> There are two ways to spend that script. With an empty witness stack,<br> the following will be executed:<br> <br> =C2=A0[X] [V] [SSS] TOALT TOALT TOALT<br> =C2=A0 =C2=A0-- altstack now contains [SSS V X]<br> =C2=A00 PUSHCURRENTINPUTINDEX EQUALVERIFY<br> =C2=A0 =C2=A0-- this input is the first, so the ordinal will move to the fi= rst<br> =C2=A0 =C2=A0 =C2=A0 output<br> =C2=A0DEPTH NOT IF<br> =C2=A0 =C2=A0-- take this branch: the auction is over!<br> =C2=A0 =C2=A01 [VENDOR] FWD_TARGET<br> =C2=A0 =C2=A0-- output 1 gets the entire value of this input, and pays to<b= r> =C2=A0 =C2=A0 =C2=A0 the vendor's hardcoded scriptPubKey<br> =C2=A0 =C2=A00 10000 FORWARD_PARTIAL<br> =C2=A0 =C2=A00 FROMALT FORWARD_TARGET<br> =C2=A0 =C2=A0-- we forward at least 10k sats to output 0 (if there were 0 s= ats,<br> =C2=A0 =C2=A0 =C2=A0 the ordinal would end up in output 1 instead, which wo= uld be a<br> =C2=A0 =C2=A0 =C2=A0 bug), and output 0 pays to scriptPubKey "X"<= br> =C2=A0 =C2=A0144<br> =C2=A0ELSE .. ENDIF<br> =C2=A0 =C2=A0-- skip over the other branch<br> =C2=A0CSV<br> =C2=A0 =C2=A0-- check that this input has baked for 144 blocks (~1 day)<br> =C2=A01ADD<br> =C2=A0 =C2=A0-- leave 145 on the stack, which is true. success!<br> <br> Alternatively, if you want to increase the bid you provide a stack with<br> two items: your scriptPubKey and the new bid [X' V']. Execution thi= s<br> time looks like:<br> <br> =C2=A0[X] [V] [SSS] TOALT TOALT TOALT<br> =C2=A0 =C2=A0-- stack contains [X' V'], altstack now contains [SSS = V X]<br> =C2=A00 PUSHCURRENTINPUTINDEX EQUALVERIFY<br> =C2=A0 =C2=A0-- this input is the first, so the ordinal will move to the fi= rst<br> =C2=A0 =C2=A0 =C2=A0 output<br> =C2=A0DEPTH NOT IF ... ELSE<br> =C2=A0 =C2=A0-- skip over the other branch (without violating minimalif rul= es)<br> =C2=A0 =C2=A0FROMALT SWAP TUCK FROMALT<br> =C2=A0 =C2=A0-- stack contains [X' V' X V' V], altstack contain= s [SSS]<br> =C2=A0 =C2=A0[K] ADD GREATERTHANOREQUAL VERIFY<br> =C2=A0 =C2=A0-- check V' >=3D V+K, stack contains [X' V' X]<= br> =C2=A0 =C2=A01 SWAP FORWARD_TARGET<br> =C2=A0 =C2=A0-- output 1 pays to X (previous bidder's scriptPubKey), an= d the<br> =C2=A0 =C2=A0 =C2=A0 entire value of this input goes there; stack contains = [X' V']<br> =C2=A0 =C2=A0DUP FORWARD_PARTIAL<br> =C2=A0 =C2=A0-- execute "V' FORWARD_PARTIAL", stack contains = [X' V']<br> =C2=A0 =C2=A00 ROT ROT<br> =C2=A0 =C2=A0-- stack contains [0 X' V']<br> =C2=A0 =C2=A0FROMALT DUP 3 SWAP FORWARD_LEAF_UPDATE<br> =C2=A0 =C2=A0-- execute "0 X' V' SSS 3 SSS FORWARD_LEAF_UPDATE= " which checks<br> =C2=A0 =C2=A0 =C2=A0 that output 0 spends at least V' satoshis back to = the same<br> =C2=A0 =C2=A0 =C2=A0 script (because that's how we defined SSS), except= the first<br> =C2=A0 =C2=A0 =C2=A0 three pushes (previously X V SSS) are replaced by X= 9; V' SSS.<br> =C2=A0 =C2=A00<br> =C2=A0ENDIF<br> =C2=A0CSV<br> =C2=A0 =C2=A0-- "0 CSV" requires nSequnce to be set, which makes = the tx rbf'able,<br> =C2=A0 =C2=A0 =C2=A0 which hopefully makes it harder to pin<br> =C2=A01ADD<br> =C2=A0 =C2=A0-- ends with 1 on the stack; success!<br> <br> (The "SSS n SSS FORWARD_LEAF_UPDATE" construct is more or less a = quine,<br> ie a program that outputs its own source code)<br> <br> I think that script is about 211 witness bytes, with an additional 40<br> witness bytes for X'/V', so when making a bid, your tx would be<br> something like:<br> <br> =C2=A0 =C2=A0tx header, 10vb<br> =C2=A0 =C2=A0input 0: 103vb for the old bid including witness and control b= lock<br> =C2=A0 =C2=A0input 1: 58vb for a taproot key path spend<br> =C2=A0 =C2=A0output 0: 43vb for the new bid<br> =C2=A0 =C2=A0output 1: 43vb for your change<br> <br> for a total of about 257vb -- slightly larger than a regular 2-in-2-out<br> transaction, but not terribly much. Mostly because input 0 doesn't requ= ire<br> a signature -- it's size is effectively 6 pubkeys: X, X' VENDOR twi= ce,<br> and the script code twice, along with a little extra to encode the<br> various numbers (10000, 144, K, V, V').<br> <br> This approach seems pretty "MEV" resistant: you pay fees via inpu= t 1 if<br> your bid succeeds; if it doesn't, you don't pay any fees. A potenti= al<br> scalper might want to put in an early low ball bid, then prevent<br> higher bidders from winning the auction, take control of the ordinal,<br> and resell it later, but unless they can prevent another miner from<br> mining alternative bids for 144 blocks, they will fail at that. The bid<br> is fixed by the bidder and committed to by the signature on input 1, so<br> frontrunning a bid can't do anything beyond invalidate the bid entirely= .<br> <br> Obviously, this is a pretty limited auction mechanism in various ways;<br> eg maybe you'd rather specify K as a percentage than an absoute increme= nt;<br> maybe you'd like to have the auction definitely finish by some particul= ar<br> time; maybe you'd like to be able to have the auction be able to contin= ue<br> above 21.47 BTC (2**31 sats); maybe you'd like to do a dutch auction<br= > rather than an english auction. I think you can probably do all those<br> things with this set of opcodes and clever scripting, though it probably<br= > gets ugly.<br> <br> I don't think this is easily extensible to taro or rgb style assets,<br= > as rather than being able to ensure the asset is transferred by<br> controlling the input/output positions, I think you'd need to build<br> up merkle trees and do point tweaks beyond what's supported by<br> OP_FORWARD_LEAF_UPDATE/OP_VAULT. Of course, without something like<br> OP_PUSHCURRENTINPUTINDEX I don't think you could do it for ordinals<br> either.<br> <br> Cheers,<br> aj<br> <br> [0] <a href=3D"https://github.com/bitcoin/bips/blob/7f747fba82675f28c239df6= 90a07b75529bd0960/bip-0345.mediawiki" rel=3D"noreferrer" target=3D"_blank">= https://github.com/bitcoin/bips/blob/7f747fba82675f28c239df690a07b75529bd09= 60/bip-0345.mediawiki</a><br> <br> [1] <a href=3D"https://twitter.com/jamesob/status/1639019107432513537" rel= =3D"noreferrer" target=3D"_blank">https://twitter.com/jamesob/status/163901= 9107432513537</a><br> <br> [2] <a href=3D"https://cointelegraph.com/news/scammers-dream-yuga-s-auction= -model-for-bitcoin-nfts-sees-criticism" rel=3D"noreferrer" target=3D"_blank= ">https://cointelegraph.com/news/scammers-dream-yuga-s-auction-model-for-bi= tcoin-nfts-sees-criticism</a><br> <br> [3] Inscriptions remain a wasteful way of publishing/committing<br> =C2=A0 =C2=A0 to content, however!<br> <br> [4] <a href=3D"https://github.com/ElementsProject/elements/blob/master/doc/= tapscript_opcodes.md" rel=3D"noreferrer" target=3D"_blank">https://github.c= om/ElementsProject/elements/blob/master/doc/tapscript_opcodes.md</a><br> <br> [5] Setting K too low probably invites griefing, where a bidder may be<br> =C2=A0 =C2=A0 able to use rbf pinning vectors to prevent people who would b= e willing<br> =C2=A0 =C2=A0 to bid substantially higher from getting their bid confirmed = on<br> =C2=A0 =C2=A0 chain.<br> _______________________________________________<br> bitcoin-dev mailing list<br> <a href=3D"mailto:bitcoin-dev@lists.linuxfoundation.org" target=3D"_blank">= bitcoin-dev@lists.linuxfoundation.org</a><br> <a href=3D"https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev" = rel=3D"noreferrer" target=3D"_blank">https://lists.linuxfoundation.org/mail= man/listinfo/bitcoin-dev</a><br> </blockquote></div></div> --000000000000de0b9005f804ab5e--