Closed sherlock-admin4 closed 1 week ago
transfer_private
requires a fee at the consensus layer & split
doesn't require a fee at the consensus layer (split
is the only function that does not, every other function on every other program requires a fee). transfer_private
does not require a fee natively in the credits.aleo program and split
charges a fee natively in the credits.aleo
program.
The reason for this is to handle an edge case where a user has only a single credits
record but cannot transfer it because they have no public balance (fee_public
) and no other records (fee_private
). So the user can call split
with a single record without a fee transition and the native fee prevents DOSing
transfer_private
requires a fee at the consensus layer &split
doesn't require a fee at the consensus layer (split
is the only function that does not, every other function on every other program requires a fee).transfer_private
does not require a fee natively in the credits.aleo program andsplit
charges a fee natively in thecredits.aleo
program.The reason for this is to handle an edge case where a user has only a single
credits
record but cannot transfer it because they have no public balance (fee_public
) and no other records (fee_private
). So the user can callsplit
with a single record without a fee transition and the native fee prevents DOSing
@evanmarshall Hello sir, please excuse my interruption.
I am confused. If the following quote is true, then the fee recipient address information should be updated in credits.aleo::split, because the call occurs in credits.aleo, otherwise the fee will be lost.
transfer_private does not require a fee natively in the credits.aleo program and split charges a fee natively in the credits.aleo program.
The more confusing question is, in the face of this edge case, even if the user can call split, what is the meaning of the split? He just has one more credit, but still no fee_private or fee_public
The reason for this is to handle an edge case where a user has only a single credits record but cannot transfer it because they have no public balance (fee_public) and no other records (fee_private). So the user can call split with a single record without a fee transition and the native fee prevents DOSing
By default in Aleo, base fees are burned for all transactions ie the supply decreases by the base fee amount.
The split
function is intended to provide users a way who only have a single record (encrypted UTXO) and no public balance to still conduct a transaction. Without this setup for split
, users who found themselves with a single record and no public balance would never be able to spend it.
By default in Aleo, base fees are burned for all transactions ie the supply decreases by the base fee amount.
The
split
function is intended to provide users a way who only have a single record (encrypted UTXO) and no public balance to still conduct a transaction. Without this setup forsplit
, users who found themselves with a single record and no public balance would never be able to spend it.
But here is simply deducting costs from user credit. If the cost is calculated in a combustion, then we seem to update the total amount of money at the same time. I hope I didn't ignore anything, thank you
Escalate
Quoting the sponsor's comments:
The reason for this is to handle an edge case where a user has only a single credits record but cannot transfer it because they have no public balance (fee_public) and no other records (fee_private). So the user can call split with a single record without a fee transition and the native fee prevents DOSing
In a specific edge case, a user without
fee_public
andfee_private
, the only method they can call iscredits.aleo::split
. But no matter how they split, they will keeprecord.owner == self.signer
. The only difference is that the user gets 2 or morecredits.record
.Quoting the sponsor's comments again:
The split function is intended to provide users a way who only have a single record (encrypted UTXO) and no public balance to still conduct a transaction. Without this setup for split, users who found themselves with a single record and no public balance would never be able to spend it.
This operation still does not solve the problem of being unable to trade. In the end, a certain amount of funds are still needed to pay the
consensus layer
fee (however, there are many ways to obtain relevant funds, and it is not as difficult as imagined). Combined with the quote below, users still have no motivation to executecredits.aleo::split
, and ultimately the10_000u64
fee will never be chargedA fee is already charged (at the program layer instead of consensus layer). The base fee is about twice was a transfer_private requires as a base fee.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
It is clear from the sponsor's comments that this is a design decision. Also, a user can use transfer_private()
for the same purpose.
Just because a user has no motivation to call a function, I don't think we can classify it as Medium severity.
For me, this problem is at most Low severity.
It is clear from the sponsor's comments that this is a design decision. Also, a user can use
transfer_private()
for the same purpose. Just because a user has no motivation to call a function, I don't think we can classify it as Medium severity. For me, this problem is at most Low severity.
Sir, I accept your judgment. But it is not because the credits.aleo::split
-related issues involved here are not enough to be medium, but because my original report did not mention the relevant content. Thank you for your patience in replying.
But here is simply deducting costs from user credit. If the cost is calculated in a combustion, then we seem to update the total amount of money at the same time. I hope I didn't ignore anything, thank you
It is worth noting that all fees are burned in Aleo whether they are consumed in-program (like in the split
case), or in fee commitments like al other cases. This is affecting the overall money supply but this is known and by design.
But here is simply deducting costs from user credit. If the cost is calculated in a combustion, then we seem to update the total amount of money at the same time. I hope I didn't ignore anything, thank you
It is worth noting that all fees are burned in Aleo whether they are consumed in-program (like in the
split
case), or in fee commitments like al other cases. This is affecting the overall money supply but this is known and by design.
I'm not sure if I should agree with this statement. If so, I will raise another question. The report #31mentioned that some problems will occur when the validator and the delegator use the same withdrawal address. In other words, should this be the user's own problem? Consider a scenario where credits.aleo::split
and credits.aleo::transfer_private
can achieve the same effect, but the fees are different. Then user A uses credits.aleo::split
to split and user B uses credits.aleo::transfer_private
to split, then A pays twice the cost of B. Should this be counted as a loss for user A? Because A doesn't know, right?
Finally, I accept all the decisions of the judge.
I am not following what you mean by the last message.
I think I understand where the confusion is on this issue though- the title of this submission is "The user has no incentive to call credits.aleo::split
". This is incorrect and I will attempt to explain why-
Some background - What are the relevant differences between split
and transfer_private
?
split
:
split
transfer_private
-
So why would a user ever use split
over transfer_private
? They will do this if they do not have a public balance.
This is inline with the sponsor's comment:
The split function is intended to provide users a way who only have a single record (encrypted UTXO) and no public balance to still conduct a transaction. Without this setup for split, users who found themselves with a single record and no public balance would never be able to spend it.
This is why a user would call split
. This is why the claim that "The user has no incentive to call credits.aleo::split
" is incorrect. The user will have no choice to use anything but split if they do not have a public balance. split
is provided specifically for this reason.
I am not following what you mean by the last message.
I think I understand where the confusion is on this issue though- the title of this submission is "The user has no incentive to call
credits.aleo::split
". This is incorrect and I will attempt to explain why-Some background - What are the relevant differences between
split
andtransfer_private
?
split
:
- fee is charges directly in the program
- the caller only needs a record, no pubic balance is needed to call
split
transfer_private
-
- the fee is charged via a fee commitment
- the caller needs a record AND a public balance
So why would a user ever use
split
overtransfer_private
? They will do this if they do not have a balance.This is inline with the sponsor's comment:
The split function is intended to provide users a way who only have a single record (encrypted UTXO) and no public balance to still conduct a transaction. Without this setup for split, users who found themselves with a single record and no public balance would never be able to spend it.
This is why a user would use
split
. This is why the claim that "The user has no incentive to callcredits.aleo::split
" is incorrect. The user will have no choice to use anything but split if they do not have a public balance.
I don't really want to argue about this. But even if the user has a public balance, he can still use splitting and will not be blocked, right? The result is that he pays more cost for the call. As for why he called it, I don't quite understand what he thinks. It is probably the same as setting the same withdrawal address. It depends on whether he is happy. In fact, the key point of this issue is that I haven't figured out whether a user without a public balance calls this method and whether he can get the public balance required to call other methods, and how splitting allows him to get the public balance. I think this is more meaningful to me than whether this question is valid.
Sir, I really hope you can tell me the process of users calling credits.aleo::split
to get the public balance, thank you. Although I don't know his process at present, but if you are willing to teach me, I believe I can learn it.
But even if the user has a public balance, he can still use splitting and will not be blocked, right?
Yes. The issue is not that he is blocked from using split
if he has a public balance. It is that he cannot use transfer_private
if he does not have a public balance. Here is something to illustrate this:
User has a public balance? | can use split |
can use transfer_private |
User has the following options: |
---|---|---|---|
yes | yes | yes | can use either transfer_private or split |
no | yes | no | must use split |
When a user does not have a public balance they must use split because they cannot use transfer_private
. split
was created specifically for users in this situation in the last row.
So, do users lose funds by using split
? Do users get public balances by using split
?
They do not lose funds. They pay the split
fee of 10 credits (which is burned). They put one record in and get 2 records out. They do not put any public balance in and do not receive any public balance out.
Is the cost greater than transfer_private
? A user splits 100 times to get 101 credits, spending 10_000u64
* 100, and he still cannot call other methods. What's the point?
Firstly, I cannot see the escalated message, so I assume it was deleted?
Secondly, I don't see any issue in the code and it works perfectly as intended.
Thirdly, this report is only about one function having larger fees than others, hence, lower incentives. I believe it's not an issue and it's up to the protocol to determine the fees. Each function has its purpose which has been perfectly explained by the Sponsor and LSW.
Planning to reject the escalation and leave the issue as it is.
Result: Invalid Has duplicates
joicygiore
Medium
The user has no incentive to call
credits.aleo::split
, the expected10_000u64
fee in that method will never be chargedSummary
The user has no incentive to call
credits.aleo::split
, the expected10_000u64
fee in that method will never be chargedVulnerability Detail
The
credits.aleo::split
method is used to splitcredits.record
and output the splitcredits.record
after charging a fee of10_000u64
, but users can use free methods to splitcredits.record
The
credits.aleo::transfer_private
method is as follows. This method is almost the same ascredits.aleo::split
, and the user experience is even better thancredits.aleo::split
. As a result, users usecredits.aleo::transfer_private
to splitcredits.record
, and the project owner will never receive the10_000u64
fee incredits.aleo::split
.poc
please add to
synthesizer/process/src/tests/test_credits.rs
->mod sanity_checks {}
and runoutput:
Impact
The user has no incentive to call
credits.aleo::split
, the expected10_000u64
fee in that method will never beCode Snippet
https://github.com/ProvableHQ/snarkVM/blob/a3c9403a581ab03be3fdd075860e815c72e35065/synthesizer/program/src/resources/credits.aleo#L947-L972 https://github.com/ProvableHQ/snarkVM/blob/a3c9403a581ab03be3fdd075860e815c72e35065/synthesizer/program/src/resources/credits.aleo#L829-L850
Tool used
Manual Review
Recommendation
If you are sure that you need to charge a split fee, we recommend adding the corresponding charging logic in the
credits.aleo::transfer_private
method.