Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offers #802

Open
casey opened this issue Nov 15, 2022 · 54 comments
Open

Offers #802

casey opened this issue Nov 15, 2022 · 54 comments

Comments

@casey
Copy link
Collaborator

casey commented Nov 15, 2022

This doesn't need to be done for mainnet, but we need to make sure that it can be done eventually.

Ask: Offer to sell sats

Inputs

  • A: Zero-value dummy output, provided by taker
  • B: Value M output containing ordinals to be sold, provided by maker
  • C: Value N output containing cardinal sats to be used for payment, provided by taker

Outputs

  • X: Value M output with taker's address
  • Y: Value N output with maker's address

Steps

  • Maker creates PSBT providing a signature for B, which commits to Y, using SIGHASH_SINGLE | SIGHASH_ANYONECANPAY. Due to A, B and Y have same index
  • Maker broadcasts PSBT
  • Taker adds inputs A and C and output Y and finalizes transaction
  • Taker broadcasts transaction
  • When transaction is mined, maker receives cardinal sats in Y for payment, taker receives ordinal sats in X

Bid: Offer to buy sats

Inputs

  • A: Zero-value dummy output, provided by taker
  • B: Value N output containing ordinal sats to be bought, provided by taker
  • C: Value M output containing cardinal sats for payment, provided by maker

Outputs

  • X: Value N output with maker's address
  • Y: Value M output with taker's address

Steps

  • Maker creates PSBT providing a signature for C, which commits to A, B, C, and X, using SIGHASH_SINGLE
  • Maker broadcasts PSBT
  • Taker adds output Y
  • Taker signs and broadcasts transaction
  • When transaction is mined, maker receives ordinal sats in Y for payment, taker receives cardinal sats in X

Notes:

  • Offer to buy is wrong but can be fixed.

Related:

@casey casey added this to the Protocol Ossification milestone Nov 15, 2022
@casey casey modified the milestones: Feature Complete, Mainnet Inscriptions, Later Dec 9, 2022
@casey casey modified the milestones: Later, Mainnet Dec 23, 2022
@casey casey mentioned this issue Jan 16, 2023
@casey casey changed the title Trustless offers to buy and sell Offers Jan 16, 2023
@casey
Copy link
Collaborator Author

casey commented Jan 17, 2023

In offers to buy, can people include change so they an use input uxos of any size?

@raphjaph raphjaph added this to the Beta milestone Jan 19, 2023
@casey casey removed this from the Beta milestone Jan 22, 2023
@cryptoquick
Copy link
Contributor

This but also for inscriptions

@casey
Copy link
Collaborator Author

casey commented Jan 30, 2023

@cryptoquick This actually covers inscriptions! Since inscriptions are on sats, which transfer using the ordinals protocol, offers to buy and sell individual sats work for inscriptions. (UX obviously needs to be there too!)

@cryppadotta
Copy link

One of the things I think is critical for the design of this feature is that 3rd-parties can be optionally designated as recipients in the transaction. Most notably:

  • a fee for the exchange (e.g. OpenSea) and
  • a fee for the artist (royalties)

Ordinals will have the same issues as Ethereum in enforcing these, but both of those fees are massive forces for good and we should design offers to support them from the get-go

Because if tool-builders and artists know they can participate in the ongoing economy, you'll see an incredible amount of work poured into the ecosystem

@casey
Copy link
Collaborator Author

casey commented Feb 4, 2023

@cryppadotta As far as I can tell, there is no way to implement royalties in an enforcable, technically reasonable way. See https://github.com/casey/ord/discussions/773 for some discussion we've been having on the topic.

@casey
Copy link
Collaborator Author

casey commented Feb 4, 2023

Offers could certainly include a "tip" output to a third-partty, and venues (marketplaces, artist home pages, discords), etc could require that an offer file contain a tip in order to show it one the homepage, etc. I think this would be great. Offers are simple and flexible enough that we can add this in a v2 version. So I think no need to worry about it in the MVP. Offers are off-chain, and easy to upgrade!

@gnoblin
Copy link

gnoblin commented Feb 6, 2023

What are the options for writing more protocols around Ordinals - bitcoin script only? Or is it possible to use sapio, stacks/clarity? (or anything else like that). Thanks!

@SlowestTimelord
Copy link

I know you've taken a look at Chia and ChiaLisp @casey but not sure if you've dived into how Offers are implemented there that may offer some ideas: https://chialisp.com/offers/

The defined NFT1 standard also enforces royalties on-chain via the transfer function part of the standard NFT1 program @cryppadotta

There are differences between Chia's coin set model vs Bitcoin's UTXO namely Chia's use of BLS enables signature aggregation in a better way than Schnorr but I'm not sure if there are other shortcomings in Bitcoin Script that makes a similar implementation not possible...

@casey
Copy link
Collaborator Author

casey commented Feb 7, 2023

What are the options for writing more protocols around Ordinals - bitcoin script only? Or is it possible to use sapio, stacks/clarity? (or anything else like that). Thanks!

Stacks is has a separate token, and is only thematically related to Bitcoin, so it and clarity will never be supported.

Sapio is an excellent project, and although I believe that @JeremyRubin is no longer working on it, it is open source and someone dedicated could pick up the torch. Sapio would be a great fit for filling in the gaps in Bitcoin Script for markets and services related to ordinals.

@casey
Copy link
Collaborator Author

casey commented Feb 7, 2023

I know you've taken a look at Chia and ChiaLisp @casey but not sure if you've dived into how Offers are implemented there that may offer some ideas: https://chialisp.com/offers/

Thanks for the link! I have looked at offers, and they definitely seem similar to what we want to do here.

The defined NFT1 standard also enforces royalties on-chain via the transfer function part of the standard NFT1 program @cryppadotta

Royalties cannot be enforced on-chain, because the buyer and the seller can simply use another channel to perform the actual transfer of funds, and lie on chain about the actual sale price. Until I see a good implementation proposed that does not have this and other problems, I do not plan to add any royalty related functionality to ord.

There are differences between Chia's coin set model vs Bitcoin's UTXO namely Chia's use of BLS enables signature aggregation in a better way than Schnorr but I'm not sure if there are other shortcomings in Bitcoin Script that makes a similar implementation not possible...

Offers as sketched out don't really use script, only input and output selection, but I would be curious if something is missing. The coin set model and the UTXO model are pretty much the same, so I often actually use the "coin set" terminology when describing bitcoin, because "output" is a pretty unfamiliar term to most people 😅

@SlowestTimelord
Copy link

Royalties cannot be enforced on-chain, because the buyer and the seller can simply use another channel to perform the actual transfer of funds, and lie on chain about the actual sale price. Until I see a good implementation proposed that does not have this and other problems, I do not plan to add any royalty related functionality to ord.

Well of course one can always get around royalties if you are okay with some level of trust. At the extreme I can sell you my private key to my wallet containing the NFT in exchange for cash and no information will take place on chain. The point with on-chain royalties (on Chia) is to create a standard where royalties are enforced when trustless Offer Files are used to exchange assets that follow that standard.

Offers as sketched out don't really use script, only input and output selection, but I would be curious if something is missing. The coin set model and the UTXO model are pretty much the same, so I often actually use the "coin set" terminology when describing bitcoin, because "output" is a pretty unfamiliar term to most people 😅

Fair point. BLS aggregation also opens the door to things like aggregation of Offers so multiple can be taken simultaneously.

A bit off topic but I heard your interview on Bankless and was intrigued by how you think tokens (like ERC-20 or CAT1 on Chia) can be implemented in a similar way. I think that's what would make Offers very exciting if its utility can go beyond just BTC for ordinal trades (or ordinals for ordinals).

@casey
Copy link
Collaborator Author

casey commented Feb 7, 2023

Well of course one can always get around royalties if you are okay with some level of trust. At the extreme I can sell you my private key to my wallet containing the NFT in exchange for cash and no information will take place on chain. The point with on-chain royalties (on Chia) is to create a standard where royalties are enforced when trustless Offer Files are used to exchange assets that follow that standard.

Someone can probably figure out trustless atomic swaps to remove trust and still use offer files. I want to avoid a scenario where we advertise that we have royalties to artists, but then as the amount of the value in the system increases, it becomes a confusing and chaotic race to the bottom like we're seeing in Ethereum.

A bit off topic but I heard your interview on Bankless and was intrigued by how you think tokens (like ERC-20 or CAT1 on Chia) can be implemented in a similar way. I think that's what would make Offers very exciting if its utility can go beyond just BTC for ordinal trades (or ordinals for ordinals).

I think there's an issue open for fungible ordinals. I'm not sure how to support that, but we could add a metadata field to an inscription that said "the next N sats after this inscription" are fungible tokens. Support in ord would be hard, because special tracking for all those sat ranges would be difficult, but it's such a simple protocol-level extension that I would be open to adding it, if only so that others could experiment with it in other repos.

@casey
Copy link
Collaborator Author

casey commented Feb 7, 2023

@SlowestTimelord Check out #787, I just copied my last comment there.

@JeremyRubin
Copy link
Contributor

Sapio would only need minor changes to support basic ord functionality, but the biggest issue would be convention around fees probably.

@dannydeezy
Copy link

question about incentives:
if i'm selling a rare sat, i set a price in my Ask offer
isn't there now an interesting dynamic where two buyers may compete with each other to fulfill it, and the one who pays a higher mining fee will win?

@casey
Copy link
Collaborator Author

casey commented Feb 9, 2023

question about incentives: if i'm selling a rare sat, i set a price in my Ask offer isn't there now an interesting dynamic where two buyers may compete with each other to fulfill it, and the one who pays a higher mining fee will win?

Yup, that is correct. Seller should set the price such that it's close to what sellers are willing to pay. If it's below what sellers are willing to pay, then they will increase their "bid" by adding fees, which will go to miners. There are probably a bunch of different auction mechanism, where the value is split in different ways between miners and sellers.

On the one hand, you have the #1611 method, where miners get all bids. On the other hand, you have a descending price auction where the seller continually releases PBSTs with lower and lower prices until someone takes it and pays EV - FEE to the seller, where EV is expected value, and FEE is what's required to get it mined, which goes to the miner.

@MuffinsThaCat
Copy link

Something like this:?

const bitcoin = require("bitcoinjs-lib");
const bip32 = require("bip32");
const bip39 = require("bip39");

const mnemonic = "a random mnemonic phrase used as seed for BIP32";
const seed = bip39.mnemonicToSeed(mnemonic);
const node = bip32.fromSeed(seed);
const keyPairB = node.derivePath("m/44'/0'/0'/0/1").keyPair;
const keyPairC = node.derivePath("m/44'/0'/0'/0/2").keyPair;

const network = bitcoin.networks.testnet;
const p2pkhB = bitcoin.payments.p2pkh({ pubkey: keyPairB.publicKey, network });
const p2pkhC = bitcoin.payments.p2pkh({ pubkey: keyPairC.publicKey, network });
const p2pkhMaker = "the address for the maker";
const p2pkhTaker = "the address for the taker";

let psbt = new bitcoin.Psbt({ network });

psbt.addInput({
hash: "the hash of transaction A",
index: 0,
nonWitnessUtxo: Buffer.from("00", "hex"),
});

psbt.addInput({
hash: "the hash of transaction B",
index: 0,
witnessUtxo: {
script: p2pkhB.output,
value: N,
},
});

psbt.addInput({
hash: "the hash of transaction C",
index: 0,
witnessUtxo: {
script: p2pkhC.output,
value: M,
},
});

psbt.addOutput({
address: p2pkhMaker,
value: N,
});

psbt.signInput(2, keyPairC, null, bitcoin.Transaction.SIGHASH_SINGLE | bitcoin.Transaction.SIGHASH_ANYONECANPAY);

const partiallySignedPsbt = psbt.toBase64();
console.log("Partially signed PSBT:", partiallySignedPsbt);

// Maker broadcasts PSBT

psbt = bitcoin.Psbt.fromBase64(partiallySignedPsbt);

psbt.addOutput({
address: p2pkhTaker,
value: M,
});

psbt.signAllInputs(keyPairB);

const signedTransaction = psbt.finalizeAllInputs().extractTransaction().toHex();
console.log("Signed transaction:", signedTransaction);

// Taker broadcasts transaction

// When transaction is mined, maker receives ordinal sats in Y for payment, taker receives cardinal sats in X

@dajuguan
Copy link

I think the script should use "p2tr" because ordinals are inscribed in the p2tr scripts.

@niftynei
Copy link
Contributor

The latest version of libwally has it, if iiuc. https://github.com/ElementsProject/libwally-core/releases/tag/release_0.8.8

@niftynei
Copy link
Contributor

Oh that's not consumer grade wallets tho. Yeah no, it'll probably be a good bit before they update.

@niftynei
Copy link
Contributor

If you wanted to play around with it though, that'd be a decent way to try it out.

@niftynei
Copy link
Contributor

niftynei commented Feb 26, 2023

There's a really bad bug in the Bid flow fyi, cc @casey.

This line is problematic.

Maker creates PSBT providing a signature for C, which commits to A, B, C, and X, using SIGHASH_SINGLE

Given

Inputs
A: Zero-value dummy output, provided by taker
B: Value N output containing ordinal sats to be bought, provided by taker
C: Value M output containing cardinal sats for payment, provided by maker
Outputs
X: Value N output with maker's address
Y: Value M output with taker's address

SIGHASH_SINGLE on C is equivalent to SIGHASH_NONE. Yikes...

The transaction should instead be constructed as follows:

Inputs
C: Value M output containing cardinal sats for payment, provided by maker
B: Value N output containing ordinal sats to be bought, provided by taker
A: Zero-value dummy output, provided by taker

Outputs
X: Value N output with maker's address
Y: Value M output with taker's address

This makes the original instruction correct.

Edit: Just realized this doesn't work at all, you'd have to use SIGHASH_SINGLE|SIGHASH_ANYONECANPAY on the signature for C. Otherwise A can't be updated later.

Oh just noticed the "Offer to buy is wrong but can be fixed."... except I don't think it can with existing sighash flags and zero-rounds of communication; multiround PSBTv2 or an input version of SIGHASH_GROUP (or OP_TXHASH) i think will fix.

Gonna use this as an opportunity to shill @base58btc classes, we cover how SIGHASH works in our in-person classes ;) https://base58.info

there's a MEV-like dynamic that arises with miners and fees in a hot inscription market. Since a miner can always break the transaction apart and try to snipe the purchase from the buyer,

PSBTv2 and +1 round trip fixes this iiuc; you separate the compose phase from the sign phase, which lets you use SIGHASH_ALL to sign. This prevents anyone from outbidding you once broadcast.

@roadbuilder
Copy link

  • Taker adds inputs A and C and output Y and finalizes transaction

In the Asks sections for this shouldn't it say that : Taker adds inputs A and C and output X and finalizes transaction?

Being that:
X: Value M output with taker's address
Y: Value N output with maker's address

Also, could someone please explain why the Dummy UTXO is needed and why it needs to be empty or have less than 1000 Sats?

Any help great appreciated!

@niftynei
Copy link
Contributor

Also, could someone please explain why the Dummy UTXO is needed and why it needs to be empty or have less than 1000 Sats?

Dummy UTXO is required for SIGHASH_SINGLE, so the inputs/output indexes of the maker get lined up/covered for their signature (B + Y have same index position in their respective lists)

@roadbuilder
Copy link

Thank you but I still don't understand this, need to study this more; some diagrams would help!

@ghost
Copy link

ghost commented Feb 28, 2023

Did an inscription swap without dummy UTXO:

  1. Created PSBT 1 using createpsbt in which input is inscription UTXO and output is sell amount

    cHNidP8BAF4CAAAAAf6QBbK23/kX2b6+TwOMD+5K/3f/jev+O2ISBwUFJkjpAAAAAAD9////AUANAwAAAAAAIlEgggRYhIl33bjKgdv+G5AXrcTRKGyWQXBY/93IME8F4EYAAAAAAAAA
    
  2. Created PSBT 2 using createpsbt in which input is some UTXO from wallet (cardinal) and output is change left after deducting fees and output amount used in 1

    cHNidP8BAIkCAAAAAXm7jKQnPdFALnyfAMZ/4LktlmM2ae/x1zClF3eZFHh3AQAAAAD9////AvgqAAAAAAAAIlEgmeAiGFUfme2tsJ+HAT89PjkFYrYsn37nwN/Uckj23wpgrgoAAAAAACJRIObgyCXaE9gvj1wPqzq/SO1DVitTmnl2XYV3Y4dK8N0bAAAAAAAAAAA=
    
  3. Joined both PSBTs using joinpsbts RPC

    cHNidP8BAN0CAAAAAv6QBbK23/kX2b6+TwOMD+5K/3f/jev+O2ISBwUFJkjpAAAAAAD9////ebuMpCc90UAufJ8Axn/guS2WYzZp7/HXMKUXd5kUeHcBAAAAAP3///8D+CoAAAAAAAAiUSCZ4CIYVR+Z7a2wn4cBPz0+OQVitiyffufA39RySPbfCkANAwAAAAAAIlEgggRYhIl33bjKgdv+G5AXrcTRKGyWQXBY/93IME8F4EZgrgoAAAAAACJRIObgyCXaE9gvj1wPqzq/SO1DVitTmnl2XYV3Y4dK8N0bAAAAAAAAAAAAAA==
    
  4. Signed PSBT using walletprocesspsbt and finalized using finalizepsbt

  5. Broadcasted the transaction using sendrawtransaction: https://mempool.space/signet/tx/1e34d8c00eae244a725ca0beecb9ff63f42d70072c49908ca17b9f98df08463d

Note: Order of inputs and outputs is important however joinpsbts RPC randomizes the order to improve privacy. So I had to keep trying until I get the right order. This can be fixed by either compiling core and remove the changes made in #16512 or open a pull request in bitcoin core to add another argument in joinspsbts RPC that is true by default and could be change to false for not shuffling inputs and outputs.

@AdamISZ
Copy link

AdamISZ commented Feb 28, 2023

@niftynei

Does this not work (for the "buy sats" case discussed above)?

0v = zero value dummy utxo

Inputs:
A: N, ordinal, taker
B: M, cardinal, maker

Outputs:
X: 0v
Y: N, ordinal, maker
Z: M, cardinal, taker.

Then maker can SINGLE|ACP sign over input B with safety right?

PSBTv2 and +1 round trip fixes this iiuc; you separate the compose phase from the sign phase, which lets you use SIGHASH_ALL to sign. This prevents anyone from outbidding you once broadcast.

Yeah I haven't thought it through at all but I could well imagine all this "jigsaw piece" stuff with single|acp is academic if you start thinking about markets.

@niftynei
Copy link
Contributor

Yeah I think that works nicely. You'd want to use just SIGHASH_SINGLE as originally suggested though, otherwise anyone could swap out the other ordinal input, and change what you're buying.

(I hadn't realized it til I saw this tweet, but the ordinal input/output needs to go at the top to make it work out)

You can make SIGHASH_ALL work for it and remove the 0v dummy output if the maker's pay-to address is known at the time you're constructing the offer to buy.

@AdamISZ
Copy link

AdamISZ commented Feb 28, 2023

You'd want to use just SIGHASH_SINGLE as originally suggested though, otherwise anyone could swap out the other ordinal input, and change what you're buying.

Oh yes, good catch! Huh, interesting that it's different this way round, because the "special" ordinal input isn't owned by the signer at the start.

It's interesting how many dimensions these setups have.

You can make SIGHASH_ALL work for it and remove the 0v dummy output if the maker's pay-to address is known at the time you're constructing the offer to buy.

Still struggling with this one 😄 Did you mean taker, not maker there (i.e. the guy who has the ordinals and is accepting the offer to buy them?). I guess in case where all inputs and outputs are known in advance then none of this shenanigans is necessary right? You just ALL all of it in the usual way like a traditional coinjoin (except, where the ordering is fixed and no privacy is achieved).

@niftynei
Copy link
Contributor

niftynei commented Mar 1, 2023

in case where all inputs and outputs are known in advance then none of this shenanigans is necessary right?

Yeah exactly :D

@ghost
Copy link

ghost commented Mar 1, 2023

I am trying to write a spec for PSBT to be used in any inscription swap:

Let me know if you have any feedback or opinions

Cc: @casey @rot13maxi @niftynei @AdamISZ @JeremyRubin

@ghost
Copy link

ghost commented Mar 2, 2023

@Christewart
Copy link

Christewart commented Mar 8, 2023

Also, could someone please explain why the Dummy UTXO is needed and why it needs to be empty or have less than 1000 Sats?

Dummy UTXO is required for SIGHASH_SINGLE, so the inputs/output indexes of the maker get lined up/covered for their signature (B + Y have same index position in their respective lists)

I don't understand why this is required.

Ask: Offer to sell sats
Inputs

    A: Zero-value dummy output, provided by taker
    B: Value M output containing ordinals to be sold, provided by maker
    C: Value N output containing cardinal sats to be used for payment, provided by taker

Outputs

    X: Value M output with taker's address
    Y: Value N output with maker's address

Why not just reorganize to be

Inputs
    B: Value M output containing ordinals to be sold, provided by maker
    C: Value N output containing cardinal sats to be used for payment, provided by taker
Outputs
    Y: Value N output with maker's address
    X: Value M output with taker's address

Now B and Y are sharing the same index (0) which should be valid for SINGLE|ANYONECANPAY. This allows the taker to add his input C at index 1 to fund the payment for the ordinal? This removes A from the transaction which simplifies things. Am i missing something?

EDIT:

Explained by @niftynei and @rot13maxi . Thank you! For other readers i highly suggest reading the ordinal BIP

@niftynei
Copy link
Contributor

niftynei commented Mar 8, 2023

Am i missing something?

iiuc you're missing how ordinals flow/are reassigned to the outputs from the inputs. The person buying the ordinals needs their address to be at output 0, so they get the sat that the inscription is associated with.

@rot13maxi
Copy link
Contributor

@niftynei has it. Sats get assigned to outputs in the same order that they are provided as inputs. So if the first sat of the first input is an inscription or otherwise desirable sat (rare/exotic?), then it will go to the first sat of the first output. If the seller provides the first input and the first output with SINGLE|ANYONECANPAY, they will just be sending that sat to themselves.

@0xankylosaurus
Copy link

@rot13maxi thanks for the helpful answer...
did you get the answer to your earlier question re. zero-value dummy output? Could we actually put a zero-value input in A? Currently I'm using a non-zero dummy output (1000 sats) to get around the same index position requirement.

@AdamISZ
Copy link

AdamISZ commented Mar 9, 2023

Yes, 0 value OP_RETURN outputs are valid and standard.

@ep150de
Copy link

ep150de commented Mar 13, 2023

Hey folks. What's the safest way to parse out sats without messing up dummy utxo for ordinals ? So that you can inscribe a specific art to a specific sat and sell it eventually. What's the best known method for creating dummy UTXO's today?

@rot13maxi
Copy link
Contributor

@ep150de you should create a Discussion or a new Issue for that. Sounds related but separable

@dajuguan
Copy link

PSBTv2 and +1 round trip fixes this iiuc; you separate the compose phase from the sign phase, which lets you use SIGHASH_ALL to sign. This prevents anyone from outbidding you once broadcast.

Could you offer the detailed solution, hard for me to understand. Thanks!

@ghost
Copy link

ghost commented Mar 26, 2023

I have started working on a marketplace which uses multisig instead of SIGHASH_SINGLE | ACP and there is no conceot of dummy UTXO

https://github.com/1440000bytes/zordex

@dannydeezy
Copy link

dannydeezy commented Apr 5, 2023

A: Zero-value dummy output, provided by taker

In practice, how do you create a zero-value output? I understand that OP_RETURNs can be created, but OP_RETURNs are not spendable right?

It seems instead a practical path is to use two small dummy utxos, like they do here: https://github.com/magiceden-oss/msigner

So that the final transaction looks like this:

Inputs:
(# 0) - 600 sat dummy output, provided by taker
(# 1) - 600 sat dummy output, provided by taker
(# 2) - Value M output containing ordinal to be sold, provided by maker
(# 3) - Value N+C output containing cardinal sats to be used for payment, provided by taker

Outputs
(# 0) - Value 1200 sat dummy output to taker's address, provided by taker
(# 1) - Value M output with taker's address, provided by taker
(# 2) - Value N output with maker's address, provided by maker
(# 3) - Value C output with takers address (change), provided by taker

With this flow, the maker signs with sighash-single | anyone-can-pay on input/output # 2 and broadcasts that PSBT, then the taker can come along and add all their inputs and outputs and sign with Sighash-All

Am i understanding correctly?

@casey casey added this to Tracker Feb 12, 2024
@casey casey linked a pull request Feb 12, 2024 that will close this issue
@raphjaph raphjaph moved this to To Do in Tracker Mar 11, 2024
@raphjaph raphjaph removed the status in Tracker Apr 12, 2024
@casey casey removed this from Tracker Apr 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.