ergoplatform / eips

Ergo Improvement Proposals
64 stars 36 forks source link

EIP-40 Reproducible Assets #84

Closed oskin1 closed 1 year ago

MrStahlfelge commented 2 years ago

I see three suggestions in this EIP, listed and commented as follows.

1 Move token metadata from issueing box to permitting box

Fixes some drawbacks of the current solution (metadata not verifiable in contracts, metadata unambigious when there are multiple issueing boxes) which is great. But the EIP should address backwards compatiblity. Suggestions: Backwards compatibility can be done by search for EIP4-data in permitting box first, if not found look in issueing box. But a compatibility problem exists with suggestion 3.

With this PR, EIP-4 should get an update as well.

2 New EIP40-Asset-ID is hash of guarding script of permitting box

That is a good suggestion. The eip40 asset id could not only serve for reproducible assets, but also for token collections. Maybe we chould also add some kind of template script suggesion to generate artificial issueing of asset ids, so that p2pk holders can issue token collections.

3 EIP40 metadata using R7 as "emission value"

It is not completely clear why we should store the emission amount in a register. It seems it should be to reflect the latest valid value (so maybe better called circulating supply, not the emission amount). However, as the EIP points out, it needs to be checked to be trustless, the EIP gives no motivation why to store this value in the first place.

Additionally, placing this value in R7 makes the proposal incompatible with EIP44. The remark "does not apply for NFTs" looks valid as NFTs don't need to be reproducible in general, but broken compatibility can be a problem with contracts expecting this register to be Coll[Byte] or undefined and makes implementations harder. This can be fixed easily though: setting R7 to a non-used bytearray constant and use R8 for emission amount.

"Emission value" being a String is an unnatural choice.

anon-real commented 2 years ago
  1. I don't get how this EIP solves the inconsistent burning issue explained at the end of the EIP. The holder of the tokens has full control over the token just like EIP-4. Could you elaborate on how this fixes the burning inconsistency? The only thing I see fixed in this standard is the ability to mint as many tokens as one needs through time. However, it doesn't solve the problem of inconsistent burning itself as tokens are not tied to contracts. I have some questions regarding this:
    • What happens if the EIP-40 issuance amount gets bigger than MaxAmountMint so that it can not be fitted in 64 bits? Wouldn't that be a problem for existing libraries and some languages?
    • I believe that with carefully designed procedures, inconsistent burning won't happen. For example in the case of SigUSD bank box, although the issuance amount is fixed, 1- it is large enough, 2- there is no incentive for burning the tokens but to return them to the bank and get back ERG! As far as I understand, the same can be true for bridges. Could you provide some details on when that can be an issue?
  2. One issue I see with this EIP is that it makes minting much trickier, especially without providing "permitting box ergo tree" templates. As now the EIP-40-tokenID is tied to the ergo tree and if that ergo tree is making use of some register, data input to any other external information, infinite values of that external information will lead to the same tokenID (as ergo tree doesn't change). This may seem like a feature but I believe it opens many doors for new unpredicted bugs.
  3. One other related concern I have is that without strictly following some template for "permitting box" ergo tree, it is virtually impossible for end users to verify the "real" emission amount. Who can mint this token, until when, and how many? These are the questions that are important to be answered in this EIP with introducing "permitting box" template!
  4. "permitting box" in other contexts such as EIP-24 and EIP-34 (not merged yet) is referred to as "issuer box". It may be better to make terms consistent.
oskin1 commented 2 years ago
  1. I don't get how this EIP solves the inconsistent burning issue explained at the end of the EIP. The holder of the tokens has full control over the token just like EIP-4. Could you elaborate on how this fixes the burning inconsistency?

The only thing I see fixed in this standard is the ability to mint as many tokens as one needs through time. However, it doesn't solve the problem of inconsistent burning itself as tokens are not tied to contracts. I have some questions regarding this:

  • What happens if the EIP-40 issuance amount gets bigger than MaxAmountMint so that it can not be fitted in 64 bits? Wouldn't that be a problem for existing libraries and some languages?

  • I believe that with carefully designed procedures, inconsistent burning won't happen. For example in the case of SigUSD bank box, although the issuance amount is fixed, 1- it is large enough, 2- there is no incentive for burning the tokens but to return them to the bank and get back ERG! As far as I understand, the same can be true for bridges. Could you provide some details on when that can be an issue?

  1. One issue I see with this EIP is that it makes minting much trickier, especially without providing "permitting box ergo tree" templates. As now the EIP-40-tokenID is tied to the ergo tree and if that ergo tree is making use of some register, data input to any other external information, infinite values of that external information will lead to the same tokenID (as ergo tree doesn't change). This may seem like a feature but I believe it opens many doors for new unpredicted bugs.

  2. One other related concern I have is that without strictly following some template for "permitting box" ergo tree, it is virtually impossible for end users to verify the "real" emission amount. Who can mint this token, until when, and how many? These are the questions that are important to be answered in this EIP with introducing "permitting box" template!

  3. "permitting box" in other contexts such as EIP-24 and EIP-34 (not merged yet) is referred to as "issuer box". It may be better to make terms consistent.

  1. Inconsistent burning is irrelevant within the proposed framework, so not an issue. 1.2. Good point. Luckily we can use non-fixed BigInt and store it as a vector of bytes. I'll outline this in the EIP.
  2. Exactly, devs should be really careful with scripts they use as minting validators. I'll try to describe a simple way to deduplication of EIP-40-AssetID.
  3. I guess emission cap is more about public contract between a project and its community. Although, I think some ergo script templates pre-defining max emission are possible.
oskin1 commented 2 years ago

I see three suggestions in this EIP, listed and commented as follows.

1 Move token metadata from issueing box to permitting box

Fixes some drawbacks of the current solution (metadata not verifiable in contracts, metadata unambigious when there are multiple issueing boxes) which is great. But the EIP should address backwards compatiblity. Suggestions: Backwards compatibility can be done by search for EIP4-data in permitting box first, if not found look in issueing box. But a compatibility problem exists with suggestion 3.

With this PR, EIP-4 should get an update as well.

2 New EIP40-Asset-ID is hash of guarding script of permitting box

That is a good suggestion. The eip40 asset id could not only serve for reproducible assets, but also for token collections. Maybe we chould also add some kind of template script suggesion to generate artificial issueing of asset ids, so that p2pk holders can issue token collections.

3 EIP40 metadata using R7 as "emission value"

It is not completely clear why we should store the emission amount in a register. It seems it should be to reflect the latest valid value (so maybe better called circulating supply, not the emission amount). However, as the EIP points out, it needs to be checked to be trustless, the EIP gives no motivation why to store this value in the first place.

Additionally, placing this value in R7 makes the proposal incompatible with EIP44. The remark "does not apply for NFTs" looks valid as NFTs don't need to be reproducible in general, but broken compatibility can be a problem with contracts expecting this register to be Coll[Byte] or undefined and makes implementations harder. This can be fixed easily though: setting R7 to a non-used bytearray constant and use R8 for emission amount.

"Emission value" being a String is an unnatural choice.

  1. I'd propose to use EIP-40 not as a replacement for EIP-4, but as an alternative. Where the metadata is stored (permitting box or minting box) unambiguously tells us which standard is used.
  2. The protocol allows to use P2PK as a minting guard as well as scripts. So not sure what kind of additions are needed to support token collections?
  3. Good point. Storing emission amount (circulating supply) in a register was a compromise between "trustlessness" and convenience for applications which don't won't to do complex queries. Circulating supply is a sensitive thing for community and a part of project<>community public agreement. That's why I think big projects won't try to manipulate this data, so we don't have to check "real" supply each time it's requested, but only periodically check it. Still a controversial topic for me, so definitely worth discussing.
  4. "Emission value" being a String is an unnatural choice.

The reason is that actual emission amount can easily overflow int64. Other option is to store it as a BigInt.

oskin1 commented 2 years ago

@MrStahlfelge @anon-real answered above^

arobsn commented 2 years ago

The reason is that actual emission amount can easily overflow int64. Other option is to store it as a BigInt.

I would go with Coll[Byte] for "Circulating supply" for two reasons:

  1. Keep it in coercion with EIP-4, where integers are represented as string;
  2. It's way easer to write parser for a Coll[Byte] value than a Big Integer in languages where we do not have SDKs, like Go or C#, for example.

Some suggestions:

  1. EIP40-Asset-ID uniqueness Different tokens minted with the same script will aways result in the same EIP40-Asset-ID, maybe worths to change the hash to take the fist minted token id in consideration (let's call it the genesis token id), something like sha256(concat(Box{boxId=tokenId}.ergoTreeBytes, bytes(tokenId))). Additionally, would be good if we can "carry" EIP40-Asset-ID across additional minting boxes, as described on point 2.

  2. EIP-40 standard Identifier I think we should have something to undoubtably identify a EIP-40, so I propose using R8 = ("EIP40", EIP40-Asset-ID), this way we have some easily checkable "magic bytes" on the begin of R8, plus the corresponding EIP40-Asset-ID.

    Another advantage of having it stored as a register is that explorers doesn't need to have another column on node_outputs and a huge index that only makes sense for a few boxes.

oskin1 commented 1 year ago

The reason is that actual emission amount can easily overflow int64. Other option is to store it as a BigInt.

I would go with Coll[Byte] for "Circulating supply" for two reasons:

  1. Keep it in coercion with EIP-4, where integers are represented as string;

  2. It's way easer to write parser for a Coll[Byte] value than a Big Integer in languages where we do not have SDKs, like Go or C#, for example.

Some suggestions:

  1. EIP40-Asset-ID uniqueness

Different tokens minted with the same script will aways result in the same EIP40-Asset-ID, maybe worths to change the hash to take the fist minted token id in consideration (let's call it the genesis token id), something like sha256(concat(Box{boxId=tokenId}.ergoTreeBytes, bytes(tokenId))). Additionally, would be good if we can "carry" EIP40-Asset-ID across additional minting boxes, as described on point 2.

  1. EIP-40 standard Identifier

I think we should have something to undoubtably identify a EIP-40, so I propose using R8 = ("EIP40", EIP40-Asset-ID), this way we have some easily checkable "magic bytes" on the begin of R8, plus the corresponding EIP40-Asset-ID.

Another advantage of having it stored as a register is that explorers doesn't need to have another column on `node_outputs` and a huge index that only makes sense for a few boxes.
  1. Adding anything other that the script itself to the hash kills the main advantage of EIP-40-AssetId - constant time verification. There is another way of enforcing EIP-40-AssetId: always add some kind of proposition (e.g ProveDlog) to the guarding script. Then, in the case of DAO governed asset the script may involve governance result reading and also multisig.

  2. Indeed. Although currently EIP-40 asset is pretty unambiguous, bc token metadata is placed in permitting box rather than in minting one (as in EIP-4). But can be good for compatibility with other standards that may come in future

arobsn commented 1 year ago
  1. Adding anything other that the script itself to the hash kills the main advantage of EIP-40-AssetId - constant time verification. There is another way of enforcing EIP-40-AssetId: always add some kind of proposition (e.g ProveDlog) to the guarding script. Then, in the case of DAO governed asset the script may involve governance result reading and also multisig.

Yeah, you're right, it might be worth adding a new section on EIP on this topic.

arobsn commented 1 year ago

Alternatively we can make EIP-40 as a token versioning standard, so that we can update not only the amount of tokens in circulation, but also the metadata.

We can keep R8 as an identifier. Example: R8 = ("EIP40", "1.0") where ("EIP40" constant, token version)

MrStahlfelge commented 1 year ago

2. Although currently EIP-40 asset is pretty unambiguous, bc token metadata is placed in permitting box rather than in minting one (as in EIP-4)

Because of the apparent downsides of using the minting box, I still think it would be good to switch to permitting box completely. Additionally, it is weird to break EIP-4 compatibility with describing fields in permitting box for some type of tokens and not all.

oskin1 commented 1 year ago

Alternatively we can make EIP-40 as a token versioning standard, so that we can update not only the amount of tokens in circulation, but also the metadata.

We can keep R8 as an identifier. Example: R8 = ("EIP40", "1.0") where ("EIP40" constant, token version)

@anon-br Makes sense. But I'd propose to store version as Short instead of Coll[Byte], this way it becomes easily to work with it from scripts.

oskin1 commented 1 year ago

@anon-br @MrStahlfelge added explicit EIP40 magic bytes and versioning. Please make another round of review.

Luivatra commented 1 year ago

So just to be clear, to support this in contracts a dev needs to assume an arbitrary number of tokens each with their own token id referring to the same asset id? Wouldn't that make contracts dealing with tokens much more complex?

oskin1 commented 1 year ago

So just to be clear, to support this in contracts a dev needs to assume an arbitrary number of tokens each with their own token id referring to the same asset id? Wouldn't that make contracts dealing with tokens much more complex?

You're right, it's almost impossible to use those assets with contracts. I've completely missed it.

arobsn commented 1 year ago

After carefully looking into it a second time, I came to a conclusion that the first approach described in the EIP will considerably increase the complexity for the whole ecosystem, not sure if it is something desired.

That being said, I suggest to change it, or at least consider changing it, to a vault based approach. For many reasons:

arobsn commented 1 year ago

Oh, I just noticed that PR is already closed. Perhaps it worths taking the idea further. Will scratch a new PR based on what's discussed here.