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

Prevent CELO Transfer to Unreleased Treasury #11222

Conversation

soloseng
Copy link
Contributor

@soloseng soloseng commented Sep 24, 2024

Description

I propose this change to prevent sending funds back to the the CeloUnreleasedTreasury because the epochRewards contract uses the funds left in that contract to calculate the epoch rewards to be distributed.

This could potentially be used by malicious actors wanting to hide their identity, by registering as validator(elected) and/or voters, then sending stolen fund back to the CeloUnreleasedTreasury and receiving the stolen funds as rewards.

Although this scenario would distribute the funds to all validators and voters, depending on the amount it could be appealing.

In addition to that, any stolen funds received by legitimate validators could become a legal burden.

Tested

unit tests updated

Closes https://github.com/celo-org/celo-blockchain-planning/issues/643

@martinvol
Copy link
Contributor

I'd add a fallback function and make it revert to make sure nobody overlooks this in the future

Base automatically changed from feat/l2-epoch-system to release/core-contracts/12 September 25, 2024 11:24
@martinvol martinvol requested a review from a team as a code owner September 25, 2024 11:24
Copy link

gitguardian bot commented Sep 25, 2024

⚠️ GitGuardian has uncovered 3 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
10538986 Triggered Generic High Entropy Secret efebfb7 packages/protocol/scripts/foundry/constants.sh View secret
10538986 Triggered Generic High Entropy Secret 04af0f7 packages/protocol/scripts/foundry/constants.sh View secret
10538986 Triggered Generic High Entropy Secret 29aadbb packages/protocol/scripts/foundry/constants.sh View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link
Contributor

@m-chrzan m-chrzan left a comment

Choose a reason for hiding this comment

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

Looks good overall, one comment about a missing test.

One concern: do we still have SELFDESTRUCT that will send CELO unconditionally? If so, this change is unfortunately somewhat moot.

packages/protocol/test-sol/unit/common/GoldToken.t.sol Outdated Show resolved Hide resolved
@soloseng
Copy link
Contributor Author

soloseng commented Oct 1, 2024

do we still have SELFDESTRUCT that will send CELO unconditionally? If so, this change is unfortunately somewhat moot

This is a valid point. Will have to think about mitigation for this case.

@m-chrzan
Copy link
Contributor

m-chrzan commented Oct 3, 2024

This is a valid point. Will have to think about mitigation for this case.

If there is still SELFDESTRUCT, I think @pahor167's comment here becomes much more relevant - if this change doesn't fully provide the intended mitigation, might not be worth it to increase CELO ERC20 transfer costs.

Would a potential alternative solution be to keep account of the unreleased CELO within this contract, and simply ignore any balance transferred to it? I.e. for any calculations, rather than using this.balance, use a storage variable that gets decremented on release, and any CELO that gets transferred in accidentally/maliciously would become frozen (just as it would when transferring to any other core contract).

@soloseng
Copy link
Contributor Author

soloseng commented Oct 3, 2024

Would a potential alternative solution be to keep account of the unreleased CELO within this contract

Yes, thats what I was thinking would be an alternate solution to this. We could then remove the CELOToken check to keep the ERC20 transfer gas low

Copy link

Prevent CELO Transfer to Unreleased Treasury

Generated at commit: c51610997ecc0236fa078b472fe126ff8c254845

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
3
2
0
14
43
62
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

Comment on lines +62 to +66
remainingBalanceToRelease = address(this).balance;
hasAlreadyReleased = true;
}

require(remainingBalanceToRelease >= amount, "Insufficient balance.");
Copy link
Contributor

@martinvol martinvol Oct 14, 2024

Choose a reason for hiding this comment

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

I'd use ERC20 balance so that it can be ported to another token if needed.

Copy link
Contributor Author

@soloseng soloseng Oct 14, 2024

Choose a reason for hiding this comment

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

Not sure I understand what you mean by porting to another token. As in distributing a different ERC20 token instead of CELO?

Copy link
Contributor

Choose a reason for hiding this comment

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

if we ever want to use this contract for another ERC20, it won't work at we use ERC20 interfaces instead of native ones.


import "../../contracts/common/Initializable.sol";
import "./interfaces/ICeloUnreleasedTreasuryInitializer.sol";

/**
* @title Contract for unreleased Celo tokens.
* @notice This contract is not allowed to receive transfers of CELO,
* to avoid miscalculating the epoch rewards and to prevent any malicious actor
* from routing stolen fund through the epoch reward distribution.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the fallback payable function explicitly revert?

Copy link
Contributor Author

@soloseng soloseng Oct 14, 2024

Choose a reason for hiding this comment

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

We could add a fallback function to make it explicitly revert, but that would acheive the same result as it is currently.

Comment on lines +132 to +137
vm.prank(sender);
uint256 balanceBefore = celoToken.balanceOf(celoUnreleasedTreasuryAddress);

celoToken.transfer(celoUnreleasedTreasuryAddress, ONE_CELOTOKEN);
uint256 balanceAfter = celoToken.balanceOf(celoUnreleasedTreasuryAddress);
assertGt(balanceAfter, balanceBefore);
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't this fail?

Copy link
Contributor Author

@soloseng soloseng Oct 14, 2024

Choose a reason for hiding this comment

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

no, that's why we are now using the internal accounting. ERc20 transfers will succeeed, but we do not account for in in the release.

This is done to avoid checking the to address on every CELO token transfers.

See above comments 1 & 2 for more details

Copy link
Contributor

Choose a reason for hiding this comment

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

if ERC20 token transfer succeed, for consistency shouldn't we make native transfer for as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This follows the same pattern as all other core contracts. No fallback implemented but still receive ERC20 transfers. Since it now keeps an internal accounting of the remaining distribution, any transfers are ignored.

@soloseng soloseng merged commit 591b114 into release/core-contracts/12 Oct 15, 2024
39 of 42 checks passed
@soloseng soloseng deleted the soloseng/prevent-celo-transfer-to-unreleased-treasury branch October 15, 2024 16:16
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.

4 participants