Canto Application Specific Dollars and Bonding Curves for 1155s - D1r3Wolf's results

Tokenizable bonding curves using a Stablecoin-as-a-Service token

General Information

Platform: Code4rena

Start Date: 13/11/2023

Pot Size: $24,500 USDC

Total HM: 3

Participants: 120

Period: 4 days

Judge: 0xTheC0der

Id: 306

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 31/120

Findings: 1

Award: $207.11

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

207.1122 USDC - $207.11

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-9

External Links

Lines of code

https://github.com/code-423n4/2023-11-canto/blob/main/1155tech-contracts/src/Market.sol#L156-L159

Vulnerability details

Impact

In the buy function, the fee which is split amount the stake holders is being restricted not for the self. It is being done by changing the rewardsLastClaimedValue of user to current shareHolderRewardsPerTokenScaled In the remaining functions (sell, mint, burn), the updated shareHolderRewardsPerTokenScaled is being considered for rewardsSinceLastClaim calculation, and the rewardsLastClaimedValue of user is being updated with the used shareHolderRewardsPerTokenScaled.

Whereas in buy function, the rewardsLastClaimedValue value of user is being updated to current shareHolderRewardsPerTokenScaled, with using that value for reward calculation at the start (which is main cause of this issue.)

So the users portion of fees which should be claimed by considering the current shareHolderRewardsPerTokenScaled is not going that user and those funds are getting locked forever.

Proof of Concept

Lets take the current state of the Market's share values as

  • tokensInCirculation = 1000
  • shareHolderRewardsPerTokenScaled = 1e36 (can be anything we can take x too, wont bother with the POC) A user (0x1) is holding those 1000 shares. tokensByAddress[id][0x1] = 1000 rewardsLastClaimedValue[id][0x1] = 1e36 (same as above, claimed recently)

Now that user (0x1) is depositing 100 ETH to get 1000 more tokens. Now in buy function link rewardsSinceLastClaim = 0 _splitFees(_id, 5 ETH, 1000)

  • holderFee = 1.65 ETH which will be distributed to current circulation (1000 shares)
  • shareHolderRewardsPerTokenScaled = 1e36 + (1.65 ETH * 1e18 / 1000) = 1.00165e36 (This reward per share is meant to distributed to the 1000 tokens, which means to the user (0x1) who is buying now. For this distribution the fee (1.65 ETH) has been taken from the user) Now the main line which have the issue rewardsLastClaimedValue[_id][msg.sender] = shareData[_id].shareHolderRewardsPerTokenScaled; The shareHolderRewardsPerTokenScaled is directly override into the rewardsLastClaimedValue, without claiming the rewards using the shareHolderRewardsPerTokenScaled value.
  • rewardsLastClaimedValue[id][0x1] = 1.00165e36 At this point, it was like the holder fee (1.65 ETH) is claimed by the user (0x1) according to rewardsLastClaimedValue, but it was not happened and those funds (1.65 ETH) will get locked in the contract balance forever.

There are two solution for this:

  1. It doesn't seems like a design issue for giving the buy fee to old holder shares of the same user.
  2. If avoiding the buy fee to old holder shares of the same user is big concern, then subtract the tokensByAddress[_id][msg.sender] value from totalCirculation for _splitFees function call in buy function.
_splitFees(_id, fee, totalCirculation);```



## Assessed type

DoS

#0 - c4-pre-sort

2023-11-18T04:11:35Z

minhquanym marked the issue as duplicate of #302

#1 - c4-judge

2023-11-28T22:39:43Z

MarioPoneder changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-11-28T22:40:32Z

MarioPoneder marked the issue as satisfactory

#3 - c4-judge

2023-11-28T23:54:05Z

MarioPoneder marked the issue as duplicate of #9

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter