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 &lt;<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>
&gt; I think there are perhaps four opcodes that are interesting in this cl=
ass:<br>
&gt; <br>
&gt;=C2=A0 =C2=A0 idx sPK OP_FORWARD_TARGET<br>
&gt;=C2=A0 =C2=A0 =C2=A0 -- sends the value to a particular output (given b=
y idx), and<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requires that output have a particula=
r scriptPubKey (given<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0by sPK).<br>
&gt; <br>
&gt;=C2=A0 =C2=A0 idx [...] n script OP_FORWARD_LEAF_UPDATE<br>
&gt;=C2=A0 =C2=A0 =C2=A0 -- sends the value to a particular output (given b=
y idx), and<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0requires that output to have almost the same=
 scriptPubKey as this<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0input, _except_ that the current leaf is rep=
laced by &quot;script&quot;,<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0with that script prefixed by &quot;n&quot; p=
ushes (of values given by [...])<br>
&gt; <br>
&gt;=C2=A0 =C2=A0 idx OP_FORWARD_SELF<br>
&gt;=C2=A0 =C2=A0 =C2=A0 -- sends the value to a particular output (given b=
y idx), and<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0requires that output to have the same=
 scriptPubKey as this input<br>
&gt; <br>
&gt;=C2=A0 =C2=A0 amt OP_FORWARD_PARTIAL<br>
&gt;=C2=A0 =C2=A0 =C2=A0 -- modifies the next OP_FORWARD_* opcode to only a=
ffect &quot;amt&quot;,<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rather than the entire balance. opcod=
es after that affect the<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0remaining balance, after &quot;amt&quot; has=
 been subtracted. if &quot;amt&quot; is<br>
&gt;=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&#39;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&#39;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&#39;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 &quot;SSS&quot; is a pushdata of the rest of the script (&quot;TOALT =
TOALT TOALT<br>
.. 1ADD&quot;).<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&#39;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 &quot;X&quot;<=
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&#39; V&#39;]. 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&#39; V&#39;], 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&#39; V&#39; X V&#39; V], altstack contain=
s [SSS]<br>
=C2=A0 =C2=A0[K] ADD GREATERTHANOREQUAL VERIFY<br>
=C2=A0 =C2=A0-- check V&#39; &gt;=3D V+K, stack contains [X&#39; V&#39; X]<=
br>
=C2=A0 =C2=A01 SWAP FORWARD_TARGET<br>
=C2=A0 =C2=A0-- output 1 pays to X (previous bidder&#39;s scriptPubKey), an=
d the<br>
=C2=A0 =C2=A0 =C2=A0 entire value of this input goes there; stack contains =
[X&#39; V&#39;]<br>
=C2=A0 =C2=A0DUP FORWARD_PARTIAL<br>
=C2=A0 =C2=A0-- execute &quot;V&#39; FORWARD_PARTIAL&quot;, stack contains =
[X&#39; V&#39;]<br>
=C2=A0 =C2=A00 ROT ROT<br>
=C2=A0 =C2=A0-- stack contains [0 X&#39; V&#39;]<br>
=C2=A0 =C2=A0FROMALT DUP 3 SWAP FORWARD_LEAF_UPDATE<br>
=C2=A0 =C2=A0-- execute &quot;0 X&#39; V&#39; SSS 3 SSS FORWARD_LEAF_UPDATE=
&quot; which checks<br>
=C2=A0 =C2=A0 =C2=A0 that output 0 spends at least V&#39; satoshis back to =
the same<br>
=C2=A0 =C2=A0 =C2=A0 script (because that&#39;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&#3=
9; V&#39; SSS.<br>
=C2=A0 =C2=A00<br>
=C2=A0ENDIF<br>
=C2=A0CSV<br>
=C2=A0 =C2=A0-- &quot;0 CSV&quot; requires nSequnce to be set, which makes =
the tx rbf&#39;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 &quot;SSS n SSS FORWARD_LEAF_UPDATE&quot; 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&#39;/V&#39;, 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&#39;t requ=
ire<br>
a signature -- it&#39;s size is effectively 6 pubkeys: X, X&#39; 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&#39;).<br>
<br>
This approach seems pretty &quot;MEV&quot; resistant: you pay fees via inpu=
t 1 if<br>
your bid succeeds; if it doesn&#39;t, you don&#39;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&#39;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&#39;d rather specify K as a percentage than an absoute increme=
nt;<br>
maybe you&#39;d like to have the auction definitely finish by some particul=
ar<br>
time; maybe you&#39;d like to be able to have the auction be able to contin=
ue<br>
above 21.47 BTC (2**31 sats); maybe you&#39;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&#39;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&#39;d need to build<br>
up merkle trees and do point tweaks beyond what&#39;s supported by<br>
OP_FORWARD_LEAF_UPDATE/OP_VAULT. Of course, without something like<br>
OP_PUSHCURRENTINPUTINDEX I don&#39;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--