DerpHerpenstein / src-721

16 stars 6 forks source link

Enhancement Suggestions for SRC721 #1

Open btcopenstamp opened 1 year ago

btcopenstamp commented 1 year ago

[new] Check the latest version at https://github.com/btcopenstamp/src-721/tree/dev

[old] In order to establish a unified indexer for SRC721 and promote the development of the Stamp ecosystem, the OpenStamp team offers the following insights based on the conventional issuance of ERC721 projects and some remarks from Derp. This extends the current SRC721 standard and is proposed for reference and discussion:

  1. Roles

    • Owner: The address that holds the collection deployment stamp. The owner changes as the stamp is transferred.
    • Operator: The agent providing signature authorization. The primary function is for the owner to delegate the minting service to handle project issuance. The pubkey in the deploy json data corresponds to the operator's Bitcoin public key.
  2. Authority Operations

    • Change Operator: The owner can initiate a protocol operation to change the operator.
    • Generate Reveal Signature: The owner signs the hash(traits data objects) to obtain a signature. If the first input of the transaction is the owner, no signature is required.
    • Generate Mint Signature: The owner/operator signs the token id + hash(traits data objects) + user address to obtain a signature.
  3. Unique, Valid, Whitelist/MEV considerations and solutions for NFTs

    • Uniqueness: A collection can contain NFTs with identical traits. Uniqueness is denoted by token id.
    • Validity: The layers/traits of NFTs within a collection should be determined by the issuer, rather than arbitrarily assigned by users.
    • Whitelist: The issuer can specify a whitelist of addresses.
    • MEV: There may be MEV attacks during public sale if the signature data does not contain the user address.

    A unified solution to the above issues:

    The signature in the mint operation is generated by the operator/owner. The signature data is token id + hash(stamp's traits data objects) + user address. The current SRC721 standard suggests using a merkle root and merkle proof for whitelist verification, but this method may increase transaction costs due to larger on-chain data (mainly merkle proof). Therefore, it is suggested to remove the merkle tree verification method.

    Potential issue: To avoid wasting transaction fees, each token id can only be allocated to one address during the mint stage. However, if the user obtains the signature for the corresponding token id and does not publish the transaction, that token id cannot be minted. Therefore, during issuance, each token id will have a lock-up period. After this period, the project issuer or minting service needs to release the token id again.

  4. Signature Algorithm

    The deploy json should include a signature algorithm field. The default should be Elliptic Curve Digital Signature Algorithm (ECDSA).

  5. Minting Fee

    • Off-Protocol: Collection issuers can collect fees off-protocol via a whitelist.
    • On-Protocol: Add a "fee recipient" field to the deploy json, defaulting to the owner address, to serve as the recipient of the minting fee. Add a "price" field in satoshi to denote the fee per mint operation; absence indicates no charge. If the price field is greater than 0, a valid mint transaction must include an output for the fee recipient (default to owner address if not specified), and the amount cannot be less than the price. This adds complexity to the protocol but reduces workload for project issuers.
  6. Additional Operations Needed for the Specification

    • Change of operator by the owner.
    • If minting fees are to be collected on-protocol, an operation for the owner to change the minting fee is needed.

Feel free to join the discussion, share your thoughts, and help us make SRC721 better. We look forward to your feedback and active participation.

DerpHerpenstein commented 1 year ago

As discussed, the points raised are valid and need to be resolved. Here are my thoughts:

1) Roles: I think this is a good way to go. It will allow the owner to delegate minting to a service, which can make the process seamless.

2) Authority Operations: I think Change Operator and Generate Reveal Signature are good. This allows the owner of the collection to reveal if they would like, but also can allow a mint service to do reveal on their behalf. I'm not so sure about generate mint signature. To be clear, this functionality is definitely needed, and as we discussed putting id+traits+address into the same object certainly helps to minimize the overhead, but after spending a little bit of time exploring this solution today, it looks like this will increase the size of the mint op by a minimum of 90 bytes just for the sig. This is smaller then a merkle proof, so it is definitely a step in the right direction, but it is still very large, considering the entire mint op is around 130 bytes when base64 encoded. To ensure the mint costs remain reasonable we need the solution to not add two more utxo's if at all possible.

3) Unique, Valid, Whitelist/MEV considerations and solutions for NFTs: same comments as two. Just to reiterate, i think this type of solution is the way to go, we just need it to be at least half that size. Perhaps if we base64 encode the raw hash and sign that. I will explore this more.

4) Signature Algorithm: Sounds good, use bitcoins-cli default algo unless otherwise specified

5) Minting Fee: I think this is a good idea as well. There needs to be a path forward to easily earn income for these projects.

6)Additional Operations Needed for the Specification: these look good

So for DEPLOY the optional "pubkey" property should be changed to "operator" to make the function of that property obvious and the value should be a bitcoin address. To my knowledge there have been no deploys using this feature so a change wont effect anyone. Additionally an optional price property denominated in satoshi should be added.

A new op called "update" that will allow for changing mutable aspects of collection should be added

{ "p": "src-721", "op": "update", "operator": "1ABC...321", // the bitcoin address of the new operator [optional] "price":"10000" // the price for the mint in satoshis [optional] }

And some more work still needs to be done to reduce the footprint of authoritative mints.

btcopenstamp commented 1 year ago

Hi Derp. Thanks for sharing your thoughts.

Regarding controlling the encoding of mint json data within two utxos, we can wait to reference the encode rules defined in the coming new Stamp protocol. I believe the new stamp protocol will greatly simplify the coding rules while introducing a compression mechanism. Maybe we could ask the devs of StampChain to share more details about the this.

I didn't quite understand what you mean by 'reduce the footprint of authoritative mints', could you elaborate on that?

DerpHerpenstein commented 1 year ago

Sorry for the delayed response. its been a very bust week. that sounds good. I look forward to seeing updates to the protocol that will reduce the footprint of these types of mint operations.

What i meant was that by using the signature of a hash of information to prove that a mint was valid, the size goes up quite a bit. Using a SHA256 hash of (token id + traits+ user address) will add another 90 bytes of data (before base64 encoding) which doubles the SRC721 mint cost. If the sha256 is in bytes and not hex then base64 encoded that number can get slashed in half down to 44 bytes. We could even do the sha256 in bytes, then truncate to 128 bits and base64 encode for a proof of 22 bytes, or 64 bits and 11 bytes?. I'm not 100% sure what the best route is. We need a reasonably secure way to allow an authority to provide a hash proving the mint was authorized, but it has to be small enough to not drive the src721 cost to 2x what it currently is

DerpHerpenstein commented 1 year ago

https://github.com/DerpHerpenstein/src-721/commit/b83762b7ac673bf35e1c48eefc1c8679e92cf74c

feel free to make a PR

btcopenstamp commented 1 year ago

Cool. We will check it.

DerpHerpenstein commented 1 year ago

What do you think about the idea of having a "mode" property that allows for changing the drop type?

Right now in the mint ts[] stores the traits. If you wanted to do a random drop with a known trait distribution, you could remove ts[] and add an ID like you talked about. then in the reveal function, a weight percentage array is used to assign a weight to each trait and a seed is used to randomize a deterministic distribution so that each id gets a random sample of traits determined by the weight.

I'm tinkering with a simple example to show how it could work. but it gives eth like drop functionality and doesn't require a owner/operator signature for each mint. Im thinking the easier we can make this process the better it will be

n4kashu commented 1 year ago

what about a mode without randomization? Authoritative mint where randomization is done by artist (as it usually is..) and then minted are pre-compiled sets of traits. Assuming mint will be performed by single entity, maybe a simple allowed wallet whitelist for minting would do the trick with authorization. (for example owner and operator only allowed, or public mode..)

this way it can work with or without reveal, based on preference of artist..

DerpHerpenstein commented 1 year ago

@n4kashu In this scenario, would the idea be that only the operator can initiate the generation of the src721? All transactions that don't start with the operator would be considered invalid? This could definitely work. This would require a transaction by the user and a second transaction by a minting service.

In the above scenario, I'm trying to imagine a way to make it so anyone with knowledge of how to manually generate an src721 can do so in a single transactions without being able to game the system.

n4kashu commented 1 year ago

yes thats what I meant with this usecase. Only owner and operator can mint a valid src-721from the collection and yes it would require 2 transactions but thats exactly how minting services do work atm.

From service provider a separate endpoint and automation to do the mint + distribute funds raised immediatelly will be needed.

I believe this is rather easy to implement on protocol level and it does not bloat the datapart..It expects work from service provider but I believe its doable.. lets see how openstamp will see this part.

btcopenstamp commented 1 year ago

@DerpHerpenstein @n4kashu

Hi, I apologize for the late response. I'll first provide some basic information, and I'll need some time to think the specific design.

  1. Unfortunately, the new Stamp protocol applies only to SRC20 transactions. SRC721 transactions will still follow the CounterParty transaction format, so we can't rely on the new protocol design to reduce data volume just yet.

  2. Within the Mint JSON, I believe we only need to retain one of the symbol and c (which points to the deploy stamp). This could reduce the length of the Mint JSON. If the symbol is not unique within the entire SRC721 protocol index, then it's necessary to keep the c attribute.

  3. The first multisig UTXO can only encode 27 bytes of data (after deducting CounterParty protocol information and prefix stamp:), and each subsequent UTXO can encode 53 bytes of data. If you want to control the data of the Mint transaction within two UTXOs, then the hexadecimal number of the data Base64 must be a maximum of 80 bytes.

  4. Having a "mode" property is a great idea. One potential issue is that without an authorization control process, it may lead to some invalid transactions with the same tokenId. Additionally, it's crucial to ensure the randomness of the algorithm as much as possible. I'm unsure whether most artists prefer this fully random generation process or a pre-generation process that can be adjusted offline.

  5. {"p":"src-721","op":"mint","c":"A9286823293586848000","id":"10000"} requires 3 UTXOs.

n4kashu commented 1 year ago

For the mode with operator only mint would require offline randomization process. It desired to have full set of pre-generated trait sets. This can be easily randomized (order) and fed into minting automation. Or even during mint it can pick randomly a number, just to make sure one is not minted already.. But in general It depends on usecase. For something I could use pure random but If I want to create balanced collection I need control over weights and I can tell you that its a process to get a good balance...

re 5. I would expect that a set of traits will be passed in this transaction ( should look like a simple array of numbers , count as per layer count..) or am I wrong?

btcopenstamp commented 1 year ago

You are right about the 5th point. It's just an example of the complete random mode.

By the way, for the complete random mode, we don't even need token id. We just assign the token id one by one to the valid mints. So the final mint json would be like {"p":"src-721","op":"mint","c":"A9286823293586848000"} that can be encoded into 2 utxos.

For the whitelist mint of complete random mode, the only way to keep 2 utxo of mint operation is a mode that only operator can mint.

Just share some thoughts on different situations.

DerpHerpenstein commented 1 year ago

I think the idea of a random mode that is set by coefficients in the reveal op is probably the most ideal mint solution and gives us a very clear path forward toward mass adoption. Using the base64 encoded data with the stamp prefix we can keep the size down to two UTXOs.

its worth noting we can get this type of mint into a single utxo if we change the format from base64 to ascii and drop the "stamp:" in favor of a special purpose mint format like: 721|mint|A95428956661682176

This is exactly 27 characters so it will fit into a single UTXO making mint costs the same as sending btc to a multisig. Perhaps thats a bit too much change for the moment, as the proposed solution by btcopenstamp doesn't require any major indexer changes. This should definitely be looked at more closely long term.

For the mint randomization function, collection creators would provide a set of coefficients in the reveal op that correspond to the layers giving each layer a coefficient and a seed use to deterministically generate the dataset

seed: "Can literally be any string" t0:[a12..3, a12..4, a12..5] ct0:[1,1000,10000] // must add up to 10,000, allows for random generation as little as 0.01% of the time

let layerSeed = sha256(seed+tokenId+layerNumber) % 10000 for(let i=0;i<ctx.length;i++) if(layerSeed <= ctx[i]) return(i)


This type of minting above could be used in combination with a simple whitelist token burning type of mint to give the founders a good mix of control over the mint process and randomization, without adding the additional overhead of needing to have an authority sign portions of every transaction to ensure validity. The original deploy can list a wl-token, which would require the minters to burn their WL token and make the memo the asset they want included in the collection and then after a time, the owner can call an update function and set the wl-token to null opening the mint to anyone for the remainder of the supply.

This hybrid approach would allow the src721 transactions to remain small, gives the collection creator the option to use a wl-token to authorize specific users to mint early, and ensures that the collection creator does not lock their collection into a specific mint service. I think it gives a very balanced and sustainable path forward.

What do you guys think?

DerpHerpenstein commented 1 year ago

i started writing the idea into: https://github.com/DerpHerpenstein/src-721/tree/dev_minimalist_idea

I need to work up a simple example of how the rarity distribution would be calculated

n4kashu commented 1 year ago

I was trying to wrap my head around the rarity distribution, that would definitelly help. if I can run few tests on the model. But assuming Ill be able to assign weight to traits per layer (each layer separately) im ok with that. This is what im simulating on my traits anyway. Tho I would also recommend to have a mode/possibility to mint with defining the traits in the mint message manually. Randomizing is a nice feature to have, and im for using it if it is applicable but the most added value in src-721 is not randomization rather the image stacking function.. I believe that the mint with 2 UTXO is sufficiently small, the 1UTXO alternative is rather minimalistic.. :P but we are are the very beginning and there will not be better time to make fundamental changes..

n4kashu commented 1 year ago

i started writing the idea into: https://github.com/DerpHerpenstein/src-721/tree/dev_minimalist_idea

I need to work up a simple example of how the rarity distribution would be calculated

this looks very good !!! I want to test the rarity distribution mechanism thoroughly as it is critical if creator wants to achieve certain distribution. perfect is that it provides possibility to make 1 of 1 traits... (1 of 10k..)

DerpHerpenstein commented 1 year ago

If you check the latest in the dev_minimalist_idea branch, i added an examples folder and a rarity.html that shows how it would work. Essentially you randomly generate a seed for each layer until the result is "good enough". In the example, it will enforce that the first 3 traits distributions are exact matches, while the rest are close but not perfect.

image image

If you want or need more or even all of the traits to have an exact distribution, thats easy enough. But it could take hours to get the proper seed instead of a minute or two like the example.

then at the end it gives you the reveal op that you would use to get that result

image

The end result is we can enforce exact trait distributions selectable by the collection creator, while lowering the UTXO count for a mint from 3 to 2, even when base64 encoded

btcopenstamp commented 1 year ago

@DerpHerpenstein @n4kashu

Based on our discussion, I just pushed a comprehensive SRC721 design specification at https://github.com/btcopenstamp/src-721/tree/dev

Please have a check and feel free to share your thoughts.

I haven't reviewed it yet after writing, so there might be some errors in expression.

DerpHerpenstein commented 1 year ago

i just spent a few minutes going over this but is great! Let me look over the details more carefully later today when i have more time. I think we're like 90% there. This takes care of the minting process, I think we need to explore some slight changes and possible field additions that will allow us to put also put web applications on chain.

mkeresty commented 1 year ago

@btcopenstamp very good ideas for the signature concept. The earlier signature example I made didn't include addresses which made it susceptible for front-running.

I recently forked this repo and in included a new branch with a working POC of this upgraded spec.

I am now looking into acceptable truncation methods and other hashing methods to decrease the byte size of the signature

https://github.com/mkeresty/src-721/tree/dev_sig_examples

justswash commented 1 year ago

@DerpHerpenstein @btcopenstamp Just went through this and the enhancements are great, but with each addition comes increased cost due to the extra bytes. The entire premise of src721 is to provide users with a cost-effective way to mint higher resolution NFTs, which should be the priority. Avime has set the benchmark on cost so anything higher (wl + mint cost) is not viable regardless of the enhancement. There is also the added complexity which comes with these for mass adoption. Enhancements should strictly be on minimum viable functions needed to use and protect the protocol.

Additionally allowing an “open” whitelist token functionality is adding to the overall cost and risk to the minter. Whitelist should enforce restrictions such as a sacrifice from the operator i.e. no profits on minting and vice versa. price + wl set together should not be considered valid. This mitigates exploitation and extortionate fees from the operator and introduces a level of risk to match with the minters. This will also consolidate the operator and recipient fields.

n4kashu commented 1 year ago

there is no need for recipient field, recipient should be by default owner o deploy stamp. I believe that the additional complexity is needed in order to make a seamless mint of 10k collections..

mkeresty commented 1 year ago

The rationale behind having a signature consisting of (id+traits+recipient) is so no one can copy the tx hash and submit with a higher fee.

Without this, there would be no easy way to effectively and verifiably index a collection.

DerpHerpenstein commented 1 year ago

@justswash you definitely have a point in that we need to focus on keeping the size down. Avime required 3 utxo's per mint. that said, i dont agree with the idea that a collection creator shouldn't be allowed to set a price with a whitelist. The details are in flux but the idea would be that the whitelist for v2 isnt a token, users just need a valid signed message signature from the operator or collection owner to prove they can mint. this would allow the collection owner to restrict minting to certain individuals at the beginning, then they can sign messages for everyone later on, or possibly change the mode to open mint(still needs more thought). Have you looked at @btcopenstamp latest dev repo? it kind of merges the ideas together

@mkeresty i also agree that if a mint is going to use a whitelist method that involved signature verification, there needs to be some mechanism in the transaction with a proof. Were thinking its a signature, but it could be as simple as a small block cypher with a key kept secret until revel? This can allow the size to be very small, but certainly less secure. need to think about the trade offs

@n4kashu good point, that could definitely be optional. Did you test out the rarity generation code with a larger dataset?

With this minimalist idea and an open randomized mint, we are able to drop the utxo count per mint to 2 instead of 3. I think alot of collections would opt to go this route and it will lower miner fees 33%. We cant get smaller then this without changing the base encoding so this is the best we can do for the time being.

For the signature i was tinkering with @mkeresty repo This is a great start. We need to get creative here because with this current signature method we would be at 5 utxo's. It would be awesome to get it down to 3 utxo's if possible. that would mean the entire property needs to be 33 bytes "sig":"[24bytes here]",. that may be a hard sell. 4 utxos we can have a 57 byte sig.

DerpHerpenstein commented 1 year ago

@n4kashu @justswash @mkeresty @btcopenstamp

thank you for taking the time to help with this. it means alot to me that you are all taking the time to have a discussion here and we are moving toward a good long term solution

while i have you all here! can you checkout this other update im working on

TLDR: We will be able to put rich dynamic web content on stamps with some minor updates. This means websites as well as 3d generative collections. I have done some tests with webgl and its looking good. it will be 2+ utxo's depending on what data is needed in the mint.

n4kashu commented 1 year ago

@DerpHerpenstein im doing it atm. I made a reduced set. tho it runs long (23k itteration now..) in general it needs a bit of tinkering but I believe I can come to results..

n4kashu commented 1 year ago

this is something i was looking for.. READING IN! I love to play with processing (p5.js) making generative art...

DerpHerpenstein commented 1 year ago

@n4kashu its a single threaded script that was quickly written in javascript with no attention given to performance. i'm sure can be written to be at least 10x faster, if a gpu is used it can be hundreds of times faster.

n4kashu commented 1 year ago

sure it could, but its not worth the hustle atm.. later i'll fiddle with creating a tool for creators to set the rarities easily..

and deploy it on 721.. :P

btcopenstamp commented 1 year ago

@n4kashu @mkeresty @DerpHerpenstein @justswash

A comprehensive SRC721 design specification at https://github.com/btcopenstamp/src-721/tree/dev

Because the specification takes into account various possibilities, it seems a little bit complex. However, I think it's necessary for us to design a relatively complete reference framework for the protocol initially, and we don't need to implement everything at the start.

The indexer can initially support some minting modes, and then the protocol can be upgraded to support more.

DerpHerpenstein commented 1 year ago

@btcopenstamp i look over this and i like it. i think there are some details that need to still be ironed out but its looking good.

@n4kashu @justswash @mkeresty @btcopenstamp

I really like how this solution lowers minting to 2 utxo for open mints.

the biggest issue i still see is the 5 utxo for whitelist mint. I dont think this should be acceptable.

After looking at this more closely, the size of the proposed minimal whitelist mint is ~198b. In order to fit into 3 utxo's we need to lower that size down to 133b. With an empty sig field and no id field, the stamps size is 82b, with an id of "9999" it is 94b. If we take the first 24 bytes of the base64 signature and use that as the sig field, we can keep the size to 3 utxo.

this then requires the collection owner to reveal the private key used for these signatures at the end of the process...

If a new wallet with a random private key is created at the beginning of the process and generates all of the valid whitelist mints and nothing else is done with this wallet, then it isn't really an issue. When the whitelist period is over they can change the mode to open mint to finish out the minting process and reveal the key after the mint is complete. that releal op would have to also set the operator to null or another key to ensure the reveled key cannot be used for any other operations.

This would change the role of operator a bit, which is not desirable. that said i think the mint cost 67% higher for a whitelist mint is much worse than generating a new key per collection and revealing it.

It is also worth noting that this less secure. I'm not sure how much less secure though? we are still using 16 bytes. Ultimately i don't see people spending large quantities of compute resources to brute force a solution to get a whitelist valued at $50...

I really think 3 utxos needs to be our upper limit here.

If anyone has another solution that can solve this problem i would love to hear it. This is all i could come up with.

btcopenstamp commented 1 year ago

@DerpHerpenstein

The Whitelist Sale with Random Traits Allocation mode can be achieved with just 2 utxos. This can be achieved by constructing a transaction where the first input comes from the user's address, while one of the remaining inputs is the operator's address. The first output then goes to the user's address.

DerpHerpenstein commented 1 year ago

@btcopenstamp @justswash @n4kashu @mkeresty

Please check the latest dev. it has the PR from @btcopenstamp for the spec updates merged in, then i made some small changes

DerpHerpenstein commented 1 year ago

it should allow for random trait mints with two multisig utxos for wl and non wl mints. @btcopenstamp suggested the idea that a dust input from the operator or owner could be used to validate the transaction, which removes the need for signatures if that input is present.

From a practical perspective, this would mean that the collection owner would likely add the minting service as the operator. The minting service would generate hundreds of dust outputs with a tx, then use those as inputs to minting operations to prove authority. Those outputs will likely be used as future inputs for something, and should be 547+sats to ensure not conflicts with ordinals

It's a very good solution that keeps miner fee cost down for the end user.

DerpHerpenstein commented 1 year ago

@n4kashu @justswash @mkeresty @btcopenstamp

Please check the latest dev branch. I think its ready to merge into main, but want to get some eyes on it first.

We have both normal mints and wl mints that can be done with random trait allocation that fit into 2 utxos. Then for specific trait or data allocation the utxo count will go up based on what the collection owner wants to pack in, but for those cases it is 3+. Theres also an option to use signatures for wl mints that doesn't require the use of a psbt that will take 5 utxos.

I think this allows us to take off running