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

EIP-0031 - Babel Fees #54

Merged
merged 11 commits into from
Nov 9, 2022
Merged

EIP-0031 - Babel Fees #54

merged 11 commits into from
Nov 9, 2022

Conversation

nitram147
Copy link
Contributor

Hi,
please review my EIP-0028 Babel Fees proposal and let me know whether is there something to be changed :)

@MrStahlfelge
Copy link
Member

0028 already taken by #53 :)

@nitram147
Copy link
Contributor Author

0028 already taken by #53 :)

Oh, sorry I did not notice it - when I was creating my proposal "EIP-0028" name was still available. As I can see, your ErgoAuth proposal is still "WIP" and has a few "TODOs" in it. Babel Fees proposal is completed and is (should be) ready to be review and hopefully merged. Because of this, I expect that it would be probably merged earlier than the ErgoAuth proposal. Since I've used "EIP-0028" a lot across the babel fees proposal (branch name, in the proposal, in ergoplayground...) and it (probably) would be merged earlier, it would make me happier if I could just stay with the current "EIP-0028" name and the ErgoAuth proposal would be assigned with the next number. Would it be a problem for you? :) Thank you for your understanding. Sincerely, Martin.

@aslesarenko
Copy link
Member

Babel Fees proposal is completed and is (should be) ready to be review and hopefully merged

I think this proposal is way behind ErgoAuth, which is already implemented in Appkit and Wallet App.
And also, strictly speaking, ErgoAuth was submitted one day before this proposal.
With that said, I suggest to rename this proposal (check the next free number please)

@nitram147 nitram147 changed the title EIP-0028 - Babel Fees EIP-0031 - Babel Fees May 9, 2022
@nitram147
Copy link
Contributor Author

Babel Fees proposal is completed and is (should be) ready to be review and hopefully merged

I think this proposal is way behind ErgoAuth, which is already implemented in Appkit and Wallet App. And also, strictly speaking, ErgoAuth was submitted one day before this proposal. With that said, I suggest to rename this proposal (check the next free number please)

Did so. Could you review the EIP now? :)

eip-0031.md Outdated
--------------------------------------------

The term “babel fees“ refers to the concept of paying transaction fees in tokens (fe. stablecoins) instead of platform’s primary token (ERG). For more information about the origin of the term “babel fees“, please see the following IOHK article:
[https://iohk.io/en/blog/posts/2021/02/25/babel-fees/](https://iohk.io/en/blog/posts/2021/02/25/babel-fees/)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Historically, the idea was first proposed on ErgoForum back in 2019 https://www.ergoforum.org/t/paying-fee-in-ergomix-in-primary-tokens/73 , and implemented in Ergomixer in 2020

Copy link
Contributor Author

@nitram147 nitram147 Jul 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of this part of text (to which you left your comment), is to give credit to the place from which I've got inspiration for the name of this EIP. And since this EIP concept has the same name as the similar concept on Cardano, I thought it'd be appropriate to explain the difference to the EIP reader. Should I also mention somewhere in the EIP that the similar idea was implemented in ErgoMixer for mixing transactions fee payments?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that it would be reasonable to mention ErgoForum ideas and ErgoMixer, to give credits to their authors, and also there are babel fees variants there which can be useful in some use-cases.

eip-0031.md Outdated

val babelFeeBoxCreator = SELF.R4[SigmaProp].get

val recreatedBox = OUTPUTS(OUTPUTS.size - 2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this index chosen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm right, the Ergo core protocol does not specify transactions fee payment, however, the reference implementation has a hardcoded ErgoTree value on which it expects fees to the miner. If I'm also right (based on my observation), the reference implementation (ergo node) doesn't care about the index of such fee output and accepts it as fee on any transaction output index. Most of the wallet implementations (or to be more precise, the libraries which are used by the wallet developers) put fees UTXO as the last output of a transaction. Thus, I can consider the last output index of a transaction as reserved for fee paying in ERG. So I decided to use the penultimate (second from the end) output as "reserved" for fee paying in case that Babel Fees are used. Based on my observation, many smartcontracts written in ErgoScript use the first output of transaction (output with index = 0) for checking of recreation of some boxes etc. So selecting the penultimate output index as the index "reserved" for Babel Fees paying would be compliant with usage of such smartcontracts - the output indexes wouldn't be in conflict. Of course there can be also smartcontracts which will be using the penultimate output index for some purpose, but I haven't seen such a contract, while I have seen a lot of contracts using first transaction output from which I assume that this choice would be compliant with most of the contracts which are currently being used.

Copy link

@ldgaetano ldgaetano Jul 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the tx has a change box, for whatever reason, then it will be at index OUTPUTS.size-2. I could be wrong, but that's what I have noticed when using AppKit.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: I am wrong, the change box is last. Even then though, the miner fee box would end up in index OUTPUTS.size-2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change box is last, that is correct. But change box is not mandatory

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if the tx has a change box then you can't use this contract with Appkit, shouldn't EIP contracts take into account use with AppKit, isn't that the point of having a library?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With sigma-rust we also haven't a way to set a outputs order, so I just reorder the outputs after transaction is generated.

Copy link

@ldgaetano ldgaetano Aug 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I have been doing some more work on GuapSwap and may need to use more than one babel box, depending on the token, in one transaction. So OUTPUTS(OUTPUTS.size-2) is very restrictive in this case. Is doing:
OUTPUTS.filter{ output: Box => output.propositionBytes == SELF.propositionBytes }(0)
possible instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to set output index in context extension of spending input.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's cool way to do it

babelFeeBoxRecreated && exchangeOK && (nanoErgsDifference >= 0)
)
)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to enforce that the erg swapped from the babel box should be sent to a miner?

I can see a scenario were the price of a certain token spikes above the rate settled on R5, and anyone can make use of babel boxes for arbitrage. I don't know if this is something desired.

PS: I'm on my first steps on ErgoScript so It's almost certain that I'm missing something. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's ok. Babel fee box is in reality just an order book order to sell ERG in exchange for specified tokens at specified price. The babel fee box creator doesn't care about how these ERGs are spent - he earned revenue by selling these ERGs for a higher price than the ordinary market price (see text about financial incentives in this EIP). It's fully up to him to monitor whether he still wants to sell ERGs for the price specified in the R5, in case he no longer wants doing so, he can withdraw all funds from his babel fee box (and recreate it with new price in R5 in case he just wanted to update the price).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can be coded offchain bots which will monitor current market price for some token and always recreate babel fee box with price equal to market price times some constant (in case that it would be worth spending ERG to pay fees for box recreation).

eip-0031.md Outdated
--------------------------------------------

The term “babel fees“ refers to the concept of paying transaction fees in tokens (fe. stablecoins) instead of platform’s primary token (ERG). For more information about the origin of the term “babel fees“, please see the following IOHK article:
[https://iohk.io/en/blog/posts/2021/02/25/babel-fees/](https://iohk.io/en/blog/posts/2021/02/25/babel-fees/)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that it would be reasonable to mention ErgoForum ideas and ErgoMixer, to give credits to their authors, and also there are babel fees variants there which can be useful in some use-cases.

@MrStahlfelge
Copy link
Member

Two remarks:

  • Maybe we want to add the testnet/mainnet addresses here.The compiled address might change in future compiler versions, so having it as a constant in the EIP would help to find babel fee boxes
  • At the moment, this is nothing else than a token buy contract. If the price is good, someone can completely buy out. Maybe further restrictions should be added.

@nitram147
Copy link
Contributor Author

nitram147 commented Jul 11, 2022

Two remarks:

  • Maybe we want to add the testnet/mainnet addresses here.The compiled address might change in future compiler versions, so having it as a constant in the EIP would help to find babel fee boxes
  • At the moment, this is nothing else than a token buy contract. If the price is good, someone can completely buy out. Maybe further restrictions should be added.

@MrStahlfelge
Answer to the first of your remarks:

I can provide example ergoTree (which is the same for both mainnet/testnet) together with tokenId for which was the ErgoScript source compiled. Getting an address for some token would then mean just replacing this tokenId with a new tokenId inside of this ergoTree bytes and then converting those ergoTree bytes to the P2S address (simple operation).

What do you think about such a solution?

Example tokenId:

280221121e65e1d8123bd9a9ab02143c39c01b1afbe5983c604a37521880d871

Example ergoTree:

1008040404000e20280221121e65e1d8123bd9a9ab02143c39c01b1afbe5983c604a37521880d87104000400040005000500d804d601e4c6a70408d602b2a599b1a5730000d603db6308a7d60499c1a7c17202eb027201d1ededededed93c27202c2a793e4c672020408720193e4c672020505e4c6a70505938cb2db63087202730100017302929c998cb2db63087202730300029591b1720373048cb27203730500027306e4c6a7050572049272047307

Answer to the second of your remarks:

Yes, it is the equivalent of an order book buy entry. The babel fees exchange providers don't need to care about to whom they are selling the ERGs, nor how the buyer would use them. They do it simply for profit, thus they setup the babel fee box with price (probably a much higher than the ordinary market price on exchange) which will bring them some profit, while utilizing the fact that the users are willing to pay more in exchange for the opportunity to pay the transaction cost in babel token (eg. SigmaUSD) instead of having to bother with buying ERGs.

@MrStahlfelge
Copy link
Member

What do you think about such a solution?

Yes, it could be done this way. Or the tokenId could be a register parameter, which has ups and downs.

By the way: the precondition
val recreatedBox = OUTPUTS(OUTPUTS.size - 2)
is very restricting. Maybe it could be done in a more dynamic way.

@capt-nemo429
Copy link

capt-nemo429 commented Jul 13, 2022

Unique ergoTree per tokenId is the way to go IMO, makes it scalable and easer to find babel boxes.

@MrStahlfelge
Copy link
Member

Okay then, in any case the ergotree should be added to the EIP so that wallets and liquidity providers know where to look for/store the babel fee contract.

@capt-nemo429
Copy link

During the last community chat an idea come up: why not to make babel contract to allow two-way swaps?

With this, liquidity providers can potentially take advantage of arbitrage actors to make profits from babel boxes.

Here is an example

Let's say that ERG is at 2 SigUSD at current market price, a liquidity provider can create an ERG/SigUSD box, optionally filled with only ERG, accepting to sell ERG for, let's say, 2.5 SigUSD, and rebuy ERG with the accumulated SigUSD for 1.9 SigUSD. This way a liquidity provider will be buying low and selling hight, something remotely analogue to a grid trading system.

Pros

  • With realistic prices and considering that the arbitrage actors will use Babel boxes for arbitrage, a liquidity provider can increase the amount of assets with time.
  • This can be a good incentive to keep liquidity flowing to inside the Babel Fees protocol.

Cons

  • A considerable increase in contract complexity.

@MrStahlfelge
Copy link
Member

Maybe I am understanding wrong, but anyone can create a babel fee box according to the EIP, so this already works in two ways.

@ldgaetano
Copy link

During the last community chat an idea come up: why not to make babel contract to allow two-way swaps?

With this, liquidity providers can potentially take advantage of arbitrage actors to make profits from babel boxes.

Here is an example

Let's say that ERG is at 2 SigUSD at current market price, a liquidity provider can create an ERG/SigUSD box, optionally filled with only ERG, accepting to sell ERG for, let's say, 2.5 SigUSD, and rebuy ERG with the accumulated SigUSD for 1.9 SigUSD. This way a liquidity provider will be buying low and selling hight, something remotely analogue to a grid trading system.

Pros

* With realistic prices and considering that the arbitrage actors will use Babel boxes for arbitrage, a liquidity provider can increase the amount of assets with time.

* This can be a good incentive to keep liquidity flowing to inside the Babel Fees protocol.

Cons

* A considerable increase in contract complexity.

Could you not just search for a box with the right babel contract and the user's PK in R4?

@capt-nemo429
Copy link

capt-nemo429 commented Jul 28, 2022

Could you not just search for a box with the right babel contract and the user's PK in R4?

Of course! Specially with ergo-graphql ;) But this is intended to be used when a LP wants to withdraw their funds.

Maybe I am understanding wrong, but anyone can create a babel fee box according to the EIP, so this already works in two ways.

I'm sorry for not being clear enough. Let me try again:

I'm looking for a way to create a mechanism that offers better incentives for liquidity providers by taking advantage of arbitrage agents. Hopefully this will bring and retain more liquidity to babel boxes.

So the contract should allow three distinct operations, namely:

  1. ERG => Token swaps using the sell price fixed at R5;
  2. Token => ERG swaps using the rebuy price fixed at R6; and
  3. Withdraw funds by using owner's PK, stored at R4.

However, I'm not sure if this is something desired, in my opinion, Babel Fees are something intended to be heavily used, specially in composition with another contracts, so if the contract get too complex, the weigh and computational costs can affect adoption, so a balance should be met.

Copy link
Member

@kushti kushti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After second review, I've found that there is no protection from spending multiple babel fee box with a single output.

See ErgoScript whitepaper https://storage.googleapis.com/ergo-cms-media/Ergo_Script_39efbe3c3a/Ergo_Script_39efbe3c3a.pdf , pg 9 :

"This script ensures that the box can be spent only in a transaction that produces an output with
60 tokens of type token1 and gives them to Alice (Alice can reclaim the box after the deadline).
Moreover, the last condition (OUTPUTS(0).R4[Col[Byte]].get == SELF.id) ensures that if Alice
has multiple such boxes outstanding at a given time, each will produce a separate output that
identifies the corresponding input. This condition prevents the following attack: if Alice has two
such boxes outstanding but the last condition is not present, then they can be both used in a single
transaction that contains just one output with 60 tokens of type “token1” — the script of each
input box will be individually satisfied, but Alice will get less only half of what owed to her."

I guess similar check is needed here as well

@nitram147
Copy link
Contributor Author

Sorry for such a long time without response (I was busy and later away from PC).

Firstly (few weeks ago) I wanted to reply to @lucagdangelo that his proposed solution for multiple babel fee boxes using OUTPUTS.filter{ output: Box => output.propositionBytes == SELF.propositionBytes }(0) would introduce critical vulnerability to contract allowing anybody to spend more babel fee boxes but recreating only one babel fee box, thus fulfilling the before mentioned (proposed) condition on OUTPUTS filter but draining funds from babel fee boxes liquidity providers.

Later (a week ago) I realized that there already exists the very same critical vulnerability in the current version of contract. However, it needs a very specific scenario to be exploitable (following one):

When there exists two babel fee boxes belonging to the very same owner for the very same babel token, with very same price value set and also "compliant" amount of nanoERGs on each of them to fulfill the nanoErgsDifference smartcontract condition on both of them.

Then somebody could exploit this, spent both boxes while recreating only one of them, thus draining funds from the affected user (owner of the affected babel fee boxes).

However, when I was thinking about the possible solutions to this problem (happening only in the very specific scenario (explained earlier)) only more complicated ones came to my mind.

One of them was an usage of special identification NFTs which would complicate the smartcontract a bit but will allow to implement similar scalability solution as proposed earlier by me in the InERGitance documentation; see here. This could make searching for the babel fees belonging to a specific user (owner) much faster.

However, such a solution would probably be non-necessary overkill (assuming that there will not be thousands of babel fee boxes for some specific token, thus we don't need such a scaling solution).

@kushti 's proposed solution is simple and would be more than enough to fix this problem. With combination of this solution with "dynamic" search for the recreated babel fee box in the OUTPUTS list we can solve two another "problems":

  • need for a fixed output position of recreated babel fee box
  • ability to safely spend more than one babel fee box in transaction

I'm going to update the smartcontract accordingly. Thanks for the feedback of all of you who commented :)

@ldgaetano
Copy link

Sorry for such a long time without response (I was busy and later away from PC).

Firstly (few weeks ago) I wanted to reply to @lucagdangelo that his proposed solution for multiple babel fee boxes using OUTPUTS.filter{ output: Box => output.propositionBytes == SELF.propositionBytes }(0) would introduce critical vulnerability to contract allowing anybody to spend more babel fee boxes but recreating only one babel fee box, thus fulfilling the before mentioned (proposed) condition on OUTPUTS filter but draining funds from babel fee boxes liquidity providers.

Later (a week ago) I realized that there already exists the very same critical vulnerability in the current version of contract. However, it needs a very specific scenario to be exploitable (following one):

When there exists two babel fee boxes belonging to the very same owner for the very same babel token, with very same price value set and also "compliant" amount of nanoERGs on each of them to fulfill the nanoErgsDifference smartcontract condition on both of them.

Then somebody could exploit this, spent both boxes while recreating only one of them, thus draining funds from the affected user (owner of the affected babel fee boxes).

However, when I was thinking about the possible solutions to this problem (happening only in the very specific scenario (explained earlier)) only more complicated ones came to my mind.

One of them was an usage of special identification NFTs which would complicate the smartcontract a bit but will allow to implement similar scalability solution as proposed earlier by me in the InERGitance documentation; see here. This could make searching for the babel fees belonging to a specific user (owner) much faster.

However, such a solution would probably be non-necessary overkill (assuming that there will not be thousands of babel fee boxes for some specific token, thus we don't need such a scaling solution).

@kushti 's proposed solution is simple and would be more than enough to fix this problem. With combination of this solution with "dynamic" search for the recreated babel fee box in the OUTPUTS list we can solve two another "problems":

  • need for a fixed output position of recreated babel fee box
  • ability to safely spend more than one babel fee box in transaction

I'm going to update the smartcontract accordingly. Thanks for the feedback of all of you who commented :)

For GuapSwap I am working on a subproject that would let miners contribute to providing liquidity to babel boxes. So it might happen that 1000+ babel boxes for one token could exist.

@nitram147
Copy link
Contributor Author

As I've promised, I made an update to the smartcontract code - using @kushti 's approach. This way we solved not only the critical vulnerability which was possible in very specific scenario (see comments above), but also made contract more general - right now, a recreated babel fee box can be located at any index in the transaction output list. Also, multiple babel fee boxes can be safely spent in one transaction (feature requested by @lucagdangelo ).

Instead of making a new commit to the EIP markdown source, I'm posting a new version of the contract here in the comments for review and discussion.

Current changes:

  • added requirement that a recreated babel fee box should have Coll[Byte] value in its R6 register corresponding to the id of its babel fee box predecessor
  • there's dynamic search for recreated babel fee box - getOrElse is required in order to avoid AOT costing problems, thus there's also another check for existence of correctly recreated babel fee box in allOK condition before checking correctness of value exchange

New smartcontract source code:

{

    val babelFeeBoxCreator = SELF.R4[SigmaProp].get
    
    val isRecreatedBabelFeeBox = {(outputBox: Box) => (
        outputBox.propositionBytes == SELF.propositionBytes &&
        outputBox.R4[SigmaProp].get == SELF.R4[SigmaProp].get &&
        outputBox.R5[Long].get == SELF.R5[Long].get &&
        outputBox.tokens(0)._1 == tokenId &&
        outputBox.R6[Coll[Byte]].get == SELF.id
    )}

    val recreatedBox = OUTPUTS.filter(isRecreatedBabelFeeBox).getOrElse(0, SELF)

    val nanoErgsDifference = SELF.value - recreatedBox.value
    val babelTokensBefore = if(SELF.tokens.size > 0){ SELF.tokens(0)._2 }else{ 0L }
    val babelTokensDifference = recreatedBox.tokens(0)._2 - babelTokensBefore
    val exchangeOK = babelTokensDifference * SELF.R5[Long].get >= nanoErgsDifference

    val allOK = { if(OUTPUTS.exists(isRecreatedBabelFeeBox)) { exchangeOK && (nanoErgsDifference >= 0) } else { false } }

    sigmaProp(
        babelFeeBoxCreator || allOK
    ) 
}

Reference updated ErgoScript playground here

Looking forward for your feedback, gonna post new ergoTree template after getting enough feedback for the contract code above.

@MrStahlfelge
Copy link
Member

The only thing I would change now is using a variable for SELF.R5[Long].get

@ldgaetano
Copy link

The only thing I would change now is using a variable for SELF.R5[Long].get

And maybe use the babelFeeBoxCreator variable in the isRecreatedBabelFeeBox check?

@ldgaetano
Copy link

ldgaetano commented Aug 20, 2022

I rewrote the contract to include the use of context variables for the output index, as kushti suggested, so the filter and exist loops can be removed and you don't have to check for the box being in the output two separate times. This is just an idea.

{

    // ===== Contract Information ===== //
    // Name: EIP-0031 Babel Fees Contract
    // Description: Contract guarding the babel fee box, checking if valid output babel box was recreated and the token exchange was valid.

    // ===== Relevant Variables ===== //
    val babelFeeBoxCreator: SigmaProp = SELF.R4[SigmaProp].get
    val ergPricePerToken: Long = SELF.R5[Long].get
    val recreatedBabelBoxIndex: Int = getVar[Int](0).get
    val tokenId: Coll[Byte] = _tokenId

    // ===== Outputs ===== //
    val recreatedBabelBox: Box = OUTPUTS(recreatedBabelBoxIndex)

    // Check conditions for a valid babel fee swap
    val validBabelFeeSwap: Boolean = {
        
        // Check that the babel fee box is recreated correctly
        val validBableFeeBoxRecreation: Boolean = {

            allOf(Coll(
                (recreatedBabelBox.propositionBytes == SELF.propositionBytes),
                (recreatedBabelBox.tokens(0)._1 == tokenId),
                (recreatedBabelBox.R4[SigmaProp].get == babelFeeBoxCreator),
                (recreatedBabelBox.R5[Long].get == ergPricePerToken),
                (recreatedBabelBox.R6[Coll[Byte]].get == SELF.id)
            ))

        }

        // Check that the user's token was exchanged correctly
        val validBabelFeeExchange: Boolean = {

            val nanoErgsDifference: Long = SELF.value - recreatedBabelBox.value
            val babelTokensBefore: Long = if (SELF.tokens.size > 0) SELF.tokens(0)._2 else 0L 
            val babelTokensDifference: Long = recreatedBabelBox.tokens(0)._2 - babelTokensBefore

            allOf(Coll(
                (babelTokensDifference * ergPricePerToken >= nanoErgsDifference),
                (nanoErgsDifference >= 0)
            ))

        }

        allOf(Coll(
            validBabelFeeBoxRecreation,
            validBabelFeeExchange
        ))

    }

    sigmaProp(validBabelFeeSwap) || babelFeeBoxCreator

}

@nitram147
Copy link
Contributor Author

Thank you for your effort to improve current babel fee contract @lucagdangelo.

In the first place, there are a few typos in your proposed contract which need to be fixed in order to render your contract to be compilable.

Your version of contract has a few disadvantages - it allows only one babel fee box to be spent in transaction (thus it's going against your requirement mentioned a few comments earlier) and requires additional efforts to add context extension while creating the transaction.

I tried to do a comparison to see the size (amount of Bytes in corresponding ergoTree) difference between various compiled versions of contract. See table bellow:

Version Size (Bytes) Total size (Bytes)
Original 177 177
NewFV 187 187
NewAP 188 188
LGD 186 188
NewOK 262 262

Total size denotes the total size occupied in transaction, in case of version LGD there are 2 more Bytes consumed by Int serialization inside of context extension.

Versions legend:

  • Original - original version of contract
  • NewFV - (FV == fixed_vulnerability) original version of contract with fixed vulnerability (added check for recreateBox.R6[Coll[Byte]] == SELF.id)
  • NewAP - (AP == AOT_problem) new version fixing vulnerability together with addition of ability to spend multiple babel boxes inside of one transaction on arbitrary indexes, however this version has AOT problem when the babel fee owner is trying to destroy the babel fee box
  • LGD - version proposed by @lucagdangelo one comment earlier (with fixed typos to be compilable), don't support multiple babel fee boxes spending
  • NewOK - version I proposed a few comments earlier in order to fix the vulnerability and increase generality of the contract

As we can see, version NewOK has the most abilities, however it has a 48% bigger ergoTree footprint than the original version. Version NewAP has the same abilities as the NewOK version and it has only 1 Byte higher footprint than the NewFV version, however there's the problem with AOT costing. LGD version lack functionality while having same footprint as the NewAP version.

I propose that we should find a way how to fix AOT costing problem in NewAP version while trying to keep resulting footprint as low as possible.

If anybody want to experiment with it, it can be easily done via ErgoScript playground, just include Pay2SAddress function and print compiled address:

import org.ergoplatform.Pay2SAddress
//contract definition
//contract compilation
println(Pay2SAddress(babelFeesContract.ergoTree))

Now just copy compiled P2S address and use node's endpoint to get ergoTree from address (needs to be done on testnet node), for example:
https://ergotestnetnode.blocpow.io/script/addressToTree/put_address_here
Last step - just divide the length of ergoTree (in characters) by 2 to get its size in Bytes :)

@ldgaetano
Copy link

ldgaetano commented Aug 21, 2022

How would it prevent multiple boxes from being spent? Each input babel box must be provided an output index context variable for its corresponding recreated box. What am I not seeing? Also using context extensions is super easy with appkit. Also, where is the NewAP version you mention?

@nitram147
Copy link
Contributor Author

Sorry, my fault (I mistakenly assumed that the context extension is the same for all inputs - I never used it). You are right, your code then should be semantically equivalent to mine.

However, I would still prefer to not require an implicit output index via the context extension.
There are mainly two reasons for it:

  1. Requirement for explicit output index specification makes implementation a bit more complicated. Implementer needs to be able to not only specify context extension, but he also needs to be able to serialize output index as integer in ergo's serialization format. This can be a trivial task or a non-trivial task dependent on implementation specifics (whether he is using some already built ergo library or he's building it from scratch). If we use a non-explicit variant of contract, there's no need to implement neither context extensions nor serialization while utilizing babel fees in transaction building.

  2. Another reason is that I want to stay "compatible" with the ErgoScript playground, so anybody reading this EIP will be able to easily play with the contract inside of it, and to my knowledge the context extension are not currently supported inside of ErgoScript playground.

eip-0031.md Outdated

Wallet developers will need to decide whether they want to support EIP-0031 or not. If they do decide to support this standard, they should also decide on which tokens they want to support (this could be done based on user requirements – e.g. implementing big stablecoins or “meme” coins, etc.), as this could be more convenient than supporting all tokens.

As P2S addresses belonging to specific token of interest stay the same, these addresses could be easily “hardcoded” when supporting only a few tokens. If the developers decide to support any token, the previously mentioned smartcontract for each token which user holds should be compiled and the availability of babel fee boxes (UTXOs) for the specific tokens of interest in the blockchain should be subsequently checked.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pointed out before, the P2S addresses can change when a new compiler version is used. The addresses for a token should be defined in the EIP to avoid having diverging addresses in the future.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no need for that.

  • Address will change from token to token;
  • It's very unlikely to have compiler serializations changes, I could be wrong but it requires a hard fork to happen.

Copy link
Member

@aslesarenko aslesarenko Oct 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is some misconception, in the EIP text "smartcontract for each token which user holds should be compiled".
When we talk about smart contracts we should really mean contract templates (see EIP-5) or at least ErgoTree.

ErgoScript should be out of question as well as any compilation. Compilation should not be part of any on-chain protocol. First, it is unstable, second it is not standardized.

Contract Template capture the parameterized nature of smart contracts and ideally any App which want to support pre-defined list of contracts should actually use a predefined list of Contract Templates.

Potentially unlimited P2S addresses can belong to the same Contract Template.
At the same time, any protocol usually require fixed list of Contract Tempates which can be hard-coded.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't know about EIP-5, contract template sounds like a great addition to have on EIP text. Thanks for the clarification )

Copy link
Member

@MrStahlfelge MrStahlfelge Nov 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no need for that.

I see a high need for a more defined approach, as the contract in the EIP does not compile for me. So changes are needed on my side to get it working, and the chances are high that I end up with another ergotree than others.
Maybe EIP-5 is a solution as well.

Btw, ergotree I came up with is 100604000e20 tokenId 0400040005000500d803d601e30004d602e4c6a70408d603e4c6a7050595e67201d804d604b2a5e4720100d605b2db63087204730000d606db6308a7d60799c1a7c17204d1968302019683050193c27204c2a7938c720501730193e4c672040408720293e4c672040505720393e4c67204060ec5a796830201929c998c7205029591b1720673028cb272067303000273047203720792720773057202

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contract fixes pushed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is your ergo tree the same?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What stops us from adding it to the eip? :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Contract Template" subsection added

eip-0031.md Outdated Show resolved Hide resolved
Copy link

@ldgaetano ldgaetano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nitram147 wrote the original playground for the previous version of the contract. I tried editing it but I don't know how to use context variables in the simulator, it doesn't seem like that functionality is available. Do we need the playground example?

@arobsn
Copy link
Member

arobsn commented Nov 3, 2022

@nitram147 wrote the original playground for the previous version of the contract. I tried editing it but I don't know how to use context variables in the simulator, it doesn't seem like that functionality is available. Do we need the playground example?

I don't think so, I can link AppKit and Nautilus as reference implementations, should be enougth.

@arobsn
Copy link
Member

arobsn commented Nov 7, 2022

Added missing R6 register description, please, do another pass: 81edece

@arobsn arobsn merged commit a9771d3 into ergoplatform:master Nov 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants