Platform: Code4rena
Start Date: 29/03/2024
Pot Size: $36,500 USDC
Total HM: 5
Participants: 72
Period: 5 days
Judge: 3docSec
Total Solo HM: 1
Id: 357
League: ETH
Rank: 6/72
Findings: 2
Award: $2,980.53
π Selected for report: 1
π Solo Findings: 0
2916.3845 USDC - $2,916.38
https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L426-L429 https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L460
The OUSG Instant Redemption Manager contract contains an oversight in its redeem
function, specifically in the handling of BUIDL redemption limits. This oversight can potentially lead to failed redemption attempts when the redemption balance exceeds the BUIDL balance held by the manager contract while it has a right amount if its concatenated with USDC amount left by another redemption process. The impact of this issue is significant as it affects the usability of the redemption feature and can result in user frustration and loss of trust in the system.
The following Proof of Concept (POC) demonstrates the issue, use it as part of forge-tests/ousg/OUSGInstantManager/redeem.t.sol
file:
Run using this command
npm run test-forge -- --match-test test_POC_reddem_fail_when_alice_redeemtion_balance_is_over_manager_BUIDL_balance
function test_POC_reddem_fail_when_alice_redeemtion_balance_is_over_manager_BUIDL_balance() public setupSecuritize(500_000e6, 500_000e6) { uint256 aliceOUSGRedeemAmount = 1667e18; uint256 aliceUSDCAmount = 250_100e6; uint256 bobOUSGRedeemAmount = 1666e18; uint256 bobUSDCAmount = 249_900e6; // Mint OUSG tokens for Alice and Bob vm.prank(address(ousgInstantManager)); ousg.mint(alice, aliceOUSGRedeemAmount); vm.prank(address(ousgInstantManager)); ousg.mint(bob, bobOUSGRedeemAmount); // Bob redeems OUSG tokens successfully vm.startPrank(bob); ousg.approve(address(ousgInstantManager), (bobOUSGRedeemAmount)); ousgInstantManager.redeem(bobOUSGRedeemAmount); vm.stopPrank(); // Alice attempts to redeem OUSG tokens, but the redemption fails due to insufficient BUIDL balance vm.startPrank(alice); ousg.approve(address(ousgInstantManager), (aliceOUSGRedeemAmount)); vm.expectRevert('Not enough tokens'); ousgInstantManager.redeem(aliceOUSGRedeemAmount); vm.stopPrank(); assertEq(USDC.balanceOf(bob), bobUSDCAmount); assertEq( BUIDL.balanceOf(address(ousgInstantManager)) + USDC.balanceOf(address(ousgInstantManager)), aliceUSDCAmount ); // However if Alice try to reddem an amount that will be in usdc amount <= minBUIDLRedeemAmount in ousgInstantManager it will success vm.startPrank(alice); ousgInstantManager.redeem(aliceOUSGRedeemAmount - 10e18); vm.stopPrank(); // Tokens remaining in Alice's balance after successful redemption assertEq(ousg.balanceOf(alice), 10e18); }
To address this issue, the OUSG Instant Redemption Manager contract should implement a mechanism to ensure that redemption requests do not exceed the available BUIDL balance held by the manager contract. This can be achieved by incorporating proper checks and balances in the redemption process, such as verifying the BUIDL balance before processing redemption requests and adjusting the redemption amount accordingly. Additionally, consider an redeem implementation that concatenate the balance of remaining USDC amount with the BUIDL redeemed balance if the corresponding USDC amount or redeem amount of OUSG is more than minBUIDLRedeemAmount.
Error
#0 - 0xRobocop
2024-04-04T01:34:37Z
From the PoC:
assertEq( BUIDL.balanceOf(address(ousgInstantManager)) + USDC.balanceOf(address(ousgInstantManager)), aliceUSDCAmount );
Same problem as #235. Even if the current BUIDL balance + USDC balance of the contract is enough to cover the redeem, the contract cannot redeem BUIDL tokens if it does not have a minimum of 250k.
There is a BUIDL redemption minimum requirement that can assumed to be 250,000 BUIDL
#1 - c4-pre-sort
2024-04-04T01:34:41Z
0xRobocop marked the issue as duplicate of #235
#2 - c4-judge
2024-04-09T13:22:05Z
3docSec marked the issue as unsatisfactory: Out of scope
#3 - khalidfsh
2024-04-10T13:18:58Z
Hi,
I would like to respectfully address the assessment provided for this issue.
Upon careful analysis and consideration, I believe there are aspects of this issue that distinguish it from issue #235, indicating that it is not a duplicate nor out of scope. Allow me to provide a detailed breakdown:
In the PoC of this issue, the Instant Manager contract has the minimum requirement for BUIDL redemption when Alice fails to redeem his share amount. With all respect, pre-sort evident is not true! instant Manager balance at the failed redeem transaction is 250_000e6
BUIDL. This line from the assertion BUIDL.balanceOf(address(ousgInstantManager)) + USDC.balanceOf(address(ousgInstantManager))
represents Alice's share after Bob's redemption, which is equivalent to 250_000e6 + 100e6
.
In the primary issue it points the fail of the transaction in this require statement:
require( buidl.balanceOf(address(this)) >= minBUIDLRedeemAmount, "OUSGInstantManager::_redeemBUIDL: Insufficient BUIDL balance" );
while in this issue, when Alice try to redeem his OUSG token the revert expected in the PoC specifically by an error that coming from BUIDL redeemer contract (Error:'Not enough tokens'):
vm.expectRevert('Not enough tokens'); ousgInstantManager.redeem(aliceOUSGRedeemAmount);
This flow of tokens elucidates the sequence of events and the impact on user balances during redemption attempts from the PoC.
Tokens | Instant Manager Contract Balances | Alice's Balance | Bob's Balance |
---|---|---|---|
OUSG | 0 | 1,667 | 1,666 |
BUIDL | 500,000 | 0 | 0 |
USDC | 0 | 0 | 0 |
Tokens | Instant Manager Contract Balances | Alice's Balance | Bob's Balance |
---|---|---|---|
OUSG | 0 | 1,667 | 0 |
BUIDL | 250,000 | 0 | 0 |
USDC | 100 | 0 | 249,900 |
In this PoC Alice only lost 100e6 USDC as it can not be redeemed, but it can be bigger as long as it is less than the minimum redemption requirement.
Given the distinctions outlined above and the implications for system functionality and user experience, I respectfully request a reconsideration of the categorization of this issue. It addresses a separate aspect of the contract's behavior and presents a valid concern that warrants attention.
Thank you for your time and consideration.
#4 - 3docSec
2024-04-11T08:08:25Z
Hi,
I've done some debugging on your PoC and I thank you for having included a runnable PoC because it helped me understand how it's indeed different than #285.
The problem you are outlining is that OUSGInstantManager
unnecessarily makes the full-amount _redeemBUIDL(usdcAmountToRedeem);
swap, because it has sufficient USDC balance to cover the request with a smaller _redeemBUIDL(buidl.balanceOf(address(this)))
swap (given that the balance is at least equal to minBUIDLRedeemAmount
+ using its USDC balance.
I see this problem therefore closer to #109, but not quite the same, because the #109 fix won't fix this issue either.
I also agree that this one does not entirely fit the out-of-scope:
We are aware that if all BUIDL has been redeemed from our contract, we will not be able to provide instant redemptions for OUSG or rOUSG. We are also aware that there may be some USDC leftover in the contract that wouldn't be redeemable in this scenario.
because the balance of BUIDL being at least equal to minBUIDLRedeemAmount
means that we are not in the if all BUIDL has been redeemed from our contract
condition.
#5 - c4-judge
2024-04-11T08:08:34Z
3docSec marked the issue as not a duplicate
#6 - 3docSec
2024-04-11T08:13:37Z
Hi @cameronclifton we'd appreciate having a sponsor review on this one... could you please share your opinion? π
#7 - cameronclifton
2024-04-11T16:41:12Z
This was known and supposed to be covered in: ```We are aware that if all BUIDL has been redeemed from our contract, we will not be able to provide instant redemptions for OUSG or rOUSG. We are also aware that there may be some USDC leftover in the contract that wouldn't be redeemable in this scenario."``
I guess the wording we chose for the above doesn't technically cover this, but it was very much intended to be.
Our operational processes will ensure that there is sufficient BUIDL in our contract at all times relative to our global redemption limits, and do not expect this edge case to be hit.
#8 - 3docSec
2024-04-12T08:26:57Z
I see the point @cameronclifton and I agree with you that the intention is reasonable, but this issue does not clearly fall into the out-of-scope that was set in the README.
It may look like nitpicking, but we want to be fair with the warden's effort and if the finding is valid as per the contest rules, it deserves a reward.
This doesn't mean you will have to fix it, you still have the option to acknowledge it if as you say the processes outside the contest scope are enough to mitigate it.
#9 - c4-judge
2024-04-12T08:27:29Z
3docSec marked the issue as satisfactory
#10 - c4-judge
2024-04-12T08:27:32Z
3docSec marked the issue as selected for report
#11 - c4-judge
2024-04-13T17:08:10Z
3docSec marked the issue as primary issue
#12 - Brivan-26
2024-04-14T09:32:28Z
Hi @3docSec sorry for dropping the comment at this moment, but I just saw this issue is upgraded. There are some contradictions between the warden's description and the contest README phrases
Quoting from the warden's description:
The OUSG Instant Redemption Manager contract contains an oversight in its redeem function, specifically in the handling of BUIDL redemption limits. This oversight can potentially lead to failed redemption attempts when the redemption balance exceeds the BUIDL balance held by the manager contract while it has a right amount if its concatenated with USDC amount left by another redemption process..
This is wrong if we compare what was mentioned in the contest README, Quoting from contest README:
USDC may be utilized at a later time for servicing redemptions less than the minimumBUIDLRedemption amount OR retrieved through the permissioned retrieveTokens function.
It is mentioned that USDC left in the ousgManager
contract will be used only to serve redemptions less than the minimumBUIDLRedemption
Also, the warden has referenced this code snippet which is a wrong assumption that the contract may not have enough BUIDL balance. Quoting from contest README:
Ondo Finance will be responsible for ensuring enough BUIDL is in the contract at all times to satisfy investor redemptions.
#13 - radeveth
2024-04-14T09:48:03Z
Hi @3docSec sorry for dropping the comment at this moment, but I just saw this issue is upgraded. There are some contradictions between the warden's description and the contest README phrases
Quoting from the warden's description:
The OUSG Instant Redemption Manager contract contains an oversight in its redeem function, specifically in the handling of BUIDL redemption limits. This oversight can potentially lead to failed redemption attempts when the redemption balance exceeds the BUIDL balance held by the manager contract while it has a right amount if its concatenated with USDC amount left by another redemption process..
This is wrong if we compare what was mentioned in the contest README, Quoting from contest README:
USDC may be utilized at a later time for servicing redemptions less than the minimumBUIDLRedemption amount OR retrieved through the permissioned retrieveTokens function.
It is mentioned that USDC left in the
ousgManager
contract will be used only to serve redemptions less than theminimumBUIDLRedemption
Also, the warden has referenced this code snippet which is a wrong assumption that the contract may not have enough BUIDL balance. Quoting from contest README:
Ondo Finance will be responsible for ensuring enough BUIDL is in the contract at all times to satisfy investor redemptions.
Good Point, @Brivan-26!
#14 - lanrebayode
2024-04-14T10:37:47Z
Apologies for commenting at this point but there is no contradiction here,
USDC may be utilized at a later time for servicing redemptions less than the minimumBUIDLRedemption amount OR retrieved through the permissioned retrieveTokens function.
"may be utilized" not "will be utilised only for this". May is an if statement and for every if there is an else. Hope this clears the air. Thank you, once again apologies for commenting.
#15 - khalidfsh
2024-04-14T10:41:21Z
Hi @Brivan-26 Thank you for sharing your thought! You are quoting from the impact of the issue, there is no description in this report. I encourage you to read the PoC for more in-depth details of the issue.
If you see the PoC section, even if the instant manager has enough BUIDL balance to cover all redemptions that can be done, it will fail at some point if this edge case occurs (where the USDC balance leftover from another redemption is part of the issue but it is not the issue itself). Also, here is the full quoting of the known issue you are referring to clearer to be subjected here:
We are aware that USDC may be leftover and held within OUSGInstantManager when a user performs a redemption that is more than the minimumRedemption amount and less than the minimumBUIDLRedemption amount. We are also aware that this may cause temporary "cash drag" for the overall OUSG portfolio as USDC in the OUSGInstantManager contract does not earn yield. USDC may be utilized at a later time for servicing redemptions less than the minimumBUIDLRedemption amount OR retrieved through the permissioned retrieveTokens function.
You can see that this talks about something else! and this issue dose not fall under this known issue.
Maybe a part of the mitigation suggest to use USDC leftover from other redemption to solve this issue, but the issue is here and the impact is clear. So, enough BUIDL balance is not preventing failed redemption if users redeem the full global redemption limit and this edge case occurs (which is proofed under PoC section)! it should be a sufficient BUIDL balance relative to global redemption limits where it counts this edge case and prevent it from happening.
Apologies for commenting at this point.
#16 - radeveth
2024-04-14T11:11:07Z
Hello,
I appreciate the discussion and the points raised. However, after revisiting the README and the specific operational mechanisms of the OUSG Instant Redemption Manager, I maintain that the identified issue is invalid based on the intentional design and operational safeguards implemented by Ondo Finance. Hereβs a detailed breakdown of why this bug is considered out of scope or a non-issue:
The Ondo Finance protocol is designed with specific operational checks that ensure the adequacy of BUIDL within the OUSGInstantManager
. According to the protocol's operational procedures:
"Ondo Finance will be responsible for ensuring enough BUIDL is in the contract at all times to satisfy investor redemptions."
This statement implies a proactive management approach to maintaining BUIDL balances, which directly addresses concerns about potential redemption failures due to insufficient BUIDL.
The concerns raised about the potential for redemption failures when BUIDL balances are low seem to misinterpret the protocol's built-in safeguards. The protocol clearly outlines mechanisms for managing these situations:
"USDC may be utilized at a later time for servicing redemptions less than the minimumBUIDLRedemption amount OR retrieved through the permissioned retrieveTokens function."
This indicates that leftover USDC in the ousgManager
contract is a considered part of the system's design, intended to handle smaller redemptions effectively without causing operational disruptions.
The phrase "may be utilized" does not imply exclusivity but rather flexibility in handling scenarios where BUIDL is temporarily insufficient. It provides a fallback mechanism to ensure that user redemptions can be processed even under constrained conditions. This flexibility is critical in managing the liquidity needs of users without compromising the integrity of the operational process.
The Proof of Concept provided seems to highlight a scenario that is already accounted for in the operational guidelines of the protocol. The test cases assume a situation that the protocol's management strategy is designed to prevent. Furthermore, the focus on this specific edge case does not reflect the typical or intended use case scenarios that the protocol is designed to handle.
Based on the detailed operational guidelines and the flexible management of BUIDL and USDC within the Ondo Finance protocol, the reported issue does not constitute a valid bug but rather a misunderstanding of the system's intended functionalities and safeguards.
Apologies for commenting at this point.
#17 - Henrychang26
2024-04-15T05:28:26Z
Hi,
I would like to respectfully address the assessment provided for this issue.
Upon careful analysis and consideration, I believe there are aspects of this issue that distinguish it from issue #235, indicating that it is not a duplicate nor out of scope. Allow me to provide a detailed breakdown:
Issue Distinctions:
- In the PoC of this issue, the Instant Manager contract has the minimum requirement for BUIDL redemption when Alice fails to redeem his share amount. With all respect, pre-sort evident is not true! instant Manager balance at the failed redeem transaction is
250_000e6
BUIDL. This line from the assertionBUIDL.balanceOf(address(ousgInstantManager)) + USDC.balanceOf(address(ousgInstantManager))
represents Alice's share after Bob's redemption, which is equivalent to250_000e6 + 100e6
.- In the primary issue it points the fail of the transaction in this require statement:
require( buidl.balanceOf(address(this)) >= minBUIDLRedeemAmount, "OUSGInstantManager::_redeemBUIDL: Insufficient BUIDL balance" );
while in this issue, when Alice try to redeem his OUSG token the revert expected in the PoC specifically by an error that coming from BUIDL redeemer contract (Error:'Not enough tokens'):
vm.expectRevert('Not enough tokens'); ousgInstantManager.redeem(aliceOUSGRedeemAmount);
Clarification on Flow of Tokens From PoC:
This flow of tokens elucidates the sequence of events and the impact on user balances during redemption attempts from the PoC.
- Starting with these balances:
Tokens Instant Manager Contract Balances Alice's Balance Bob's Balance OUSG 0 1,667 1,666 BUIDL 500,000 0 0 USDC 0 0 0 2. After Bob redeem his tokens:
Tokens Instant Manager Contract Balances Alice's Balance Bob's Balance OUSG 0 1,667 0 BUIDL 250,000 0 0 USDC 100 0 249,900 3. Now when Alice try to redeem his 1667e18 OUSG tokens will fail since the Instant Manager contract try to redeem BUIDL above its balance (250_100e6 BUIDL). However, Alice can only redeem an equivalent amount of OUSG less than or equal to the minimum requirement for BUIDL redemption.
In this PoC Alice only lost 100e6 USDC as it can not be redeemed, but it can be bigger as long as it is less than the minimum redemption requirement.
Given the distinctions outlined above and the implications for system functionality and user experience, I respectfully request a reconsideration of the categorization of this issue. It addresses a separate aspect of the contract's behavior and presents a valid concern that warrants attention.
Thank you for your time and consideration.
Warden seems to make the wrong assumption that as long as OUSGInstantManager
holds at least minBUIDLRedeemAmount
amount, redemption should be successful. This assumption is not explicitly stated anywhere in the documentation. minBUIDLRedeemAmount
simply represents the minimum amount of BUIDL
that must be redeemed in a single redemption.
The root cause of this case is the lack of sufficient BUIDL
tokens in OUSGInstantManager
, which falls the on the responsibility of the protocol. This was clearly noted in Automated Findings / Publicly Known Issues:
We are aware that if all BUIDL has been redeemed from our contract, we would not be able to provide instant redemptions for OUSG or rOUSG. We are also aware that there may be some USDC leftover in the contract that wouldn't be redeemable in this scenario.
Also protocol does not explicitly guarantee redemption if amount of BUIDL + USDC >= usdcAmountToRedeem
since it acknowledges leftover USDC to be used at later time.
We are aware that USDC may be leftover and held within OUSGInstantManager when a user performs a redemption that is more than the minimumRedemption amount and less than the minimumBUIDLRedemption amount. We are also aware that this may cause temporary "cash drag" for the overall OUSG portfolio as USDC in the OUSGInstantManager contract does not earn yield. USDC may be utilized at a later time for servicing redemptions less than the minimumBUIDLRedemption amount OR retrieved through the permissioned retrieveTokens function.
Apologies for commenting at this point.
#18 - c4-sponsor
2024-04-21T16:40:40Z
cameronclifton (sponsor) confirmed
#19 - cameronclifton
2024-04-22T22:45:59Z
Due to changing requirements, the contract will now concatenate the USDC amount with BUIDL when performing redemptions. (This should mitigate this already known issue).
64.1515 USDC - $64.15
The current implementation of the burn
function in the rOUSG contract restricts the ability of the admin with the BURNER_ROLE
to burn tokens from addresses that have either been removed from the KYC list (KYCRegistry::removeKYCAddresses
) or added to the external chainalysis's sanction list. This is because the _beforeTokenTransfer
function enforces KYC checks for all token transfer operations, including burning tokens. As a result, if an address is no longer KYC-approved or has been sanctioned, the burn
function will fail to execute, preventing the admin from burning tokens as intended. This limitation can hinder essential operations, affecting the integrity and functionality of the protocol.
Letβs check the burn
function which calls the internal _burnShares
function (see line 632) :
contracts/ousg/rOUSG.sol: 618: /** 619: * @notice Admin burn function to burn rOUSG tokens from any account 620: * @param _account The account to burn tokens from 621: * @param _amount The amount of rOUSG tokens to burn 622: * @dev Transfers burned shares (OUSG) to `msg.sender` 623: */ 624: function burn( 625: address _account, 626: uint256 _amount 627: ) external onlyRole(BURNER_ROLE) { 628: uint256 ousgSharesAmount = getSharesByROUSG(_amount); 629: if (ousgSharesAmount < OUSG_TO_ROUSG_SHARES_MULTIPLIER) 630: revert UnwrapTooSmall(); 631: 632: _burnShares(_account, ousgSharesAmount); 633: 634: ousg.transfer( 635: msg.sender, 636: ousgSharesAmount / OUSG_TO_ROUSG_SHARES_MULTIPLIER 637: ); 638: emit Transfer(address(0), msg.sender, getROUSGByShares(ousgSharesAmount)); 639: emit TransferShares(_account, address(0), ousgSharesAmount); 640: } 554: function _burnShares( 555: address _account, 556: uint256 _sharesAmount 557: ) internal whenNotPaused returns (uint256) { 558: require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS"); 559: 560: _beforeTokenTransfer(_account, address(0), _sharesAmount); 561: 562: uint256 accountShares = shares[_account]; 563: require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE"); 564: 565: totalShares -= _sharesAmount; 566: 567: shares[_account] = accountShares - _sharesAmount; 568: 569: return totalShares; 570: }
As can be seen in _burnShares
function it calls _beforeTokenTransfer
in line 560 with the account that we want to burn tokens form. Here is the code of _beforeTokenTransfer
:
contracts/ousg/rOUSG.sol: 586: function _beforeTokenTransfer( 587: address from, 588: address to, 589: uint256 590: ) internal view { 591: // Check constraints when `transferFrom` is called to facliitate 592: // a transfer between two parties that are not `from` or `to`. 593: if (from != msg.sender && to != msg.sender) { 594: require(_getKYCStatus(msg.sender), "rOUSG: 'sender' address not KYC'd"); 595: } 596: 597: if (from != address(0)) { 598: // If not minting 599: require(_getKYCStatus(from), "rOUSG: 'from' address not KYC'd"); 600: } 601: 602: if (to != address(0)) { 603: // If not burning 604: require(_getKYCStatus(to), "rOUSG: 'to' address not KYC'd"); 605: } 606: }
The _beforeTokenTransfer
function enforces KYC checks for all token transfers. if we see code block in L597-L600 we can see the require statement that lock the ability of burning token from account that has false in its KYC status, since this function is also used when unwrap rOUSG it is very acceptable in its nature. However, the burn
function should not incorporate these checks. As a result, the admin with the BURNER_ROLE
cannot burn tokens from addresses that are no longer KYC-approved or have been added to the sanctions list.
If we dig deeper to see more about _getKYCStatus
which is part of KYCRegistryClientUpgradeable
contract:
contracts/kyc/KYCRegistryClient.sol: 64: function _getKYCStatus(address account) internal view returns (bool) { 65: return kycRegistry.getKYCStatus(kycRequirementGroup, account); 66: } contracts/kyc/KYCRegistry.sol: 119: /** 120: * @notice Get KYC status of `account` for the provided 121: * `kycRequirementGroup`. In order to return true, `account`'s state 122: * in this contract must be true and additionally pass a 123: * `sanctionsList` check. 124: * 125: * @param kycRequirementGroup KYC group to check KYC status for 126: * @param account Addresses to check KYC status for 127: */ 128: function getKYCStatus( 129: uint256 kycRequirementGroup, 130: address account 131: ) external view override returns (bool) { 132: return 133: kycState[kycRequirementGroup][account] && 134: !sanctionsList.isSanctioned(account); 135: }
We can tell that the state of the KYC is managed by separate roles in a separate contract and can be revoked at any given moment either by:
Address has been added to sanctions list where it checked in KYCRegistry#L134: !sanctionsList.isSanctioned
Address is revoked when utilizing KYCRegistry::removeKYCAddresses
by another role:
contracts/kyc/KYCRegistry.sol: 169: /** 170: * @notice Remove addresses from KYC list 171: * 172: * @param kycRequirementGroup KYC group associated with `addresses` 173: * @param addresses List of addresses to revoke KYC'd status 174: */ 175: function removeKYCAddresses( 176: uint256 kycRequirementGroup, 177: address[] calldata addresses 178: ) external onlyRole(kycGroupRoles[kycRequirementGroup]) { 179: uint256 length = addresses.length; 180: for (uint256 i = 0; i < length; i++) { 181: kycState[kycRequirementGroup][addresses[i]] = false; 182: } 183: emit KYCAddressesRemoved(msg.sender, kycRequirementGroup, addresses); 184: }
Thus, This inconsistency in enforcing KYC requirements hinders the admin's ability to perform critical token burning operations, impacting the overall functionality of the protocol.
Consider these analyzings before solving the issue
If the burn function will be used only by the admin; consider burning shares without checking the KYC status of the address we are burning from. But be caution here as we can not make changes to _burnShares
function since it used in unwrap! perhaps another enforced burn shares function can do the job.
If the burn function would be use by another contracts as of a tokenomics features like the one used by ousgInstantManager
and OUSG
token, then add another burn function that would be used only by the admin and enforce the burn regardless of the the KYC status of the address we are burning from.
Error
#0 - c4-pre-sort
2024-04-04T05:11:45Z
0xRobocop marked the issue as duplicate of #237
#1 - c4-judge
2024-04-09T08:30:33Z
3docSec marked the issue as satisfactory