From db44fac5d01f75a9fabe15eab12c151f603c1a16 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 21 Nov 2024 12:32:17 +0100 Subject: [PATCH 1/4] accurate balance accounting v2 for nonRebasingSupply calculation --- contracts/contracts/token/OUSD.sol | 34 ++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index b00a76facb..d62947ccb8 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -267,7 +267,7 @@ contract OUSD is Governable { if (state == RebaseOptions.YieldDelegationSource) { address target = yieldTo[_account]; uint256 targetOldBalance = balanceOf(target); - uint256 targetNewCredits = _balanceToRebasingCredits( + (uint256 targetNewCredits,) = _balanceToRebasingCredits( targetOldBalance + newBalance ); rebasingCreditsDiff = @@ -277,7 +277,7 @@ contract OUSD is Governable { creditBalances[_account] = newBalance; creditBalances[target] = targetNewCredits; } else if (state == RebaseOptions.YieldDelegationTarget) { - uint256 newCredits = _balanceToRebasingCredits( + (uint256 newCredits,) = _balanceToRebasingCredits( newBalance + creditBalances[yieldFrom[_account]] ); rebasingCreditsDiff = @@ -291,7 +291,7 @@ contract OUSD is Governable { alternativeCreditsPerToken[_account] = 1e18; creditBalances[_account] = newBalance; } else { - uint256 newCredits = _balanceToRebasingCredits(newBalance); + (uint256 newCredits,) = _balanceToRebasingCredits(newBalance); rebasingCreditsDiff = newCredits.toInt256() - creditBalances[_account].toInt256(); @@ -419,16 +419,25 @@ contract OUSD is Governable { } } + /** + * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and + * also balance that corresponds to those credits. The latter is important + * when adjusting the contract's global rebasingCredits to circumvent any + * possible rounding errors. + * + * @param _balance Address of the account. + */ function _balanceToRebasingCredits(uint256 _balance) internal view - returns (uint256) + returns (uint256 rebasingCredits, uint256 balance) { // Rounds up, because we need to ensure that accounts always have // at least the balance that they should have. // Note this should always be used on an absolute account value, // not on a possibly negative diff, because then the rounding would be wrong. - return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18; + rebasingCredits = ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18; + balance = rebasingCredits * 1e18 / rebasingCreditsPerToken_; } /** @@ -469,9 +478,10 @@ contract OUSD is Governable { // Account rebaseState[_account] = RebaseOptions.StdRebasing; alternativeCreditsPerToken[_account] = 0; - creditBalances[_account] = _balanceToRebasingCredits(balance); + (uint256 newCredits, uint256 newBalance) = _balanceToRebasingCredits(balance); + creditBalances[_account] = newCredits; // Globals - _adjustGlobals(creditBalances[_account].toInt256(), -balance.toInt256()); + _adjustGlobals(creditBalances[_account].toInt256(), -newBalance.toInt256()); emit AccountRebasingEnabled(_account); } @@ -593,9 +603,10 @@ contract OUSD is Governable { // Local creditBalances[_from] = fromBalance; alternativeCreditsPerToken[_from] = 1e18; - creditBalances[_to] = _balanceToRebasingCredits(fromBalance + toBalance); + (creditBalances[_to],) = _balanceToRebasingCredits(fromBalance + toBalance); // Global - _adjustGlobals(_balanceToRebasingCredits(fromBalance).toInt256(), -fromBalance.toInt256()); + (uint256 fromCredits, uint256 fromBalanceAccurate) = _balanceToRebasingCredits(fromBalance); + _adjustGlobals(fromCredits.toInt256(), -fromBalanceAccurate.toInt256()); emit YieldDelegated(_from, _to); } @@ -620,9 +631,10 @@ contract OUSD is Governable { // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()` creditBalances[_from] = fromBalance; // alternativeCreditsPerToken[to] already 0 from `delegateYield()` - creditBalances[to] = _balanceToRebasingCredits(toBalance); + (creditBalances[to],) = _balanceToRebasingCredits(toBalance); // Global - _adjustGlobals(-(_balanceToRebasingCredits(fromBalance).toInt256()), fromBalance.toInt256()); + (uint256 fromCredits, uint256 fromBalanceAccurate) = _balanceToRebasingCredits(fromBalance); + _adjustGlobals(-(fromCredits.toInt256()), fromBalanceAccurate.toInt256()); emit YieldUndelegated(_from, to); } } From 6e31957b4eb2c8d469deeec5c84d5241277908a1 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 21 Nov 2024 12:33:38 +0100 Subject: [PATCH 2/4] prettier --- contracts/contracts/token/OUSD.sol | 51 ++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index d62947ccb8..0de7dca7ea 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -38,7 +38,6 @@ contract OUSD is Governable { YieldDelegationTarget } - uint256[154] private _gap; // Slots to align with deployed contract uint256 private constant MAX_SUPPLY = type(uint128).max; uint256 public totalSupply; @@ -267,7 +266,7 @@ contract OUSD is Governable { if (state == RebaseOptions.YieldDelegationSource) { address target = yieldTo[_account]; uint256 targetOldBalance = balanceOf(target); - (uint256 targetNewCredits,) = _balanceToRebasingCredits( + (uint256 targetNewCredits, ) = _balanceToRebasingCredits( targetOldBalance + newBalance ); rebasingCreditsDiff = @@ -277,7 +276,7 @@ contract OUSD is Governable { creditBalances[_account] = newBalance; creditBalances[target] = targetNewCredits; } else if (state == RebaseOptions.YieldDelegationTarget) { - (uint256 newCredits,) = _balanceToRebasingCredits( + (uint256 newCredits, ) = _balanceToRebasingCredits( newBalance + creditBalances[yieldFrom[_account]] ); rebasingCreditsDiff = @@ -291,7 +290,7 @@ contract OUSD is Governable { alternativeCreditsPerToken[_account] = 1e18; creditBalances[_account] = newBalance; } else { - (uint256 newCredits,) = _balanceToRebasingCredits(newBalance); + (uint256 newCredits, ) = _balanceToRebasingCredits(newBalance); rebasingCreditsDiff = newCredits.toInt256() - creditBalances[_account].toInt256(); @@ -315,7 +314,7 @@ contract OUSD is Governable { } /** - * @notice Function to check the amount of tokens that _owner has allowed + * @notice Function to check the amount of tokens that _owner has allowed * to `_spender`. * @param _owner The address which owns the funds. * @param _spender The address which will spend the funds. @@ -342,7 +341,7 @@ contract OUSD is Governable { } /** - * @notice Creates `_amount` tokens and assigns them to `_account`, + * @notice Creates `_amount` tokens and assigns them to `_account`, * increasing the total supply. */ function mint(address _account, uint256 _amount) external onlyVault { @@ -424,7 +423,7 @@ contract OUSD is Governable { * also balance that corresponds to those credits. The latter is important * when adjusting the contract's global rebasingCredits to circumvent any * possible rounding errors. - * + * * @param _balance Address of the account. */ function _balanceToRebasingCredits(uint256 _balance) @@ -436,8 +435,10 @@ contract OUSD is Governable { // at least the balance that they should have. // Note this should always be used on an absolute account value, // not on a possibly negative diff, because then the rounding would be wrong. - rebasingCredits = ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18; - balance = rebasingCredits * 1e18 / rebasingCreditsPerToken_; + rebasingCredits = + ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / + 1e18; + balance = (rebasingCredits * 1e18) / rebasingCreditsPerToken_; } /** @@ -457,7 +458,7 @@ contract OUSD is Governable { function _rebaseOptIn(address _account) internal { uint256 balance = balanceOf(_account); - + // prettier-ignore require( alternativeCreditsPerToken[_account] > 0 || @@ -478,10 +479,15 @@ contract OUSD is Governable { // Account rebaseState[_account] = RebaseOptions.StdRebasing; alternativeCreditsPerToken[_account] = 0; - (uint256 newCredits, uint256 newBalance) = _balanceToRebasingCredits(balance); + (uint256 newCredits, uint256 newBalance) = _balanceToRebasingCredits( + balance + ); creditBalances[_account] = newCredits; // Globals - _adjustGlobals(creditBalances[_account].toInt256(), -newBalance.toInt256()); + _adjustGlobals( + creditBalances[_account].toInt256(), + -newBalance.toInt256() + ); emit AccountRebasingEnabled(_account); } @@ -603,9 +609,14 @@ contract OUSD is Governable { // Local creditBalances[_from] = fromBalance; alternativeCreditsPerToken[_from] = 1e18; - (creditBalances[_to],) = _balanceToRebasingCredits(fromBalance + toBalance); + (creditBalances[_to], ) = _balanceToRebasingCredits( + fromBalance + toBalance + ); // Global - (uint256 fromCredits, uint256 fromBalanceAccurate) = _balanceToRebasingCredits(fromBalance); + ( + uint256 fromCredits, + uint256 fromBalanceAccurate + ) = _balanceToRebasingCredits(fromBalance); _adjustGlobals(fromCredits.toInt256(), -fromBalanceAccurate.toInt256()); emit YieldDelegated(_from, _to); } @@ -631,10 +642,16 @@ contract OUSD is Governable { // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()` creditBalances[_from] = fromBalance; // alternativeCreditsPerToken[to] already 0 from `delegateYield()` - (creditBalances[to],) = _balanceToRebasingCredits(toBalance); + (creditBalances[to], ) = _balanceToRebasingCredits(toBalance); // Global - (uint256 fromCredits, uint256 fromBalanceAccurate) = _balanceToRebasingCredits(fromBalance); - _adjustGlobals(-(fromCredits.toInt256()), fromBalanceAccurate.toInt256()); + ( + uint256 fromCredits, + uint256 fromBalanceAccurate + ) = _balanceToRebasingCredits(fromBalance); + _adjustGlobals( + -(fromCredits.toInt256()), + fromBalanceAccurate.toInt256() + ); emit YieldUndelegated(_from, to); } } From d9f7e71967b266120fccc2fb842149987f09ace9 Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 21 Nov 2024 12:35:34 +0100 Subject: [PATCH 3/4] correct comment --- contracts/contracts/token/OUSD.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index 0de7dca7ea..792cab2e3a 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -421,7 +421,7 @@ contract OUSD is Governable { /** * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and * also balance that corresponds to those credits. The latter is important - * when adjusting the contract's global rebasingCredits to circumvent any + * when adjusting the contract's global nonRebasingSupply to circumvent any * possible rounding errors. * * @param _balance Address of the account. From 491353aacd2b57fe5ba81dc64d32f9a47280691b Mon Sep 17 00:00:00 2001 From: Domen Grabec Date: Thu, 21 Nov 2024 12:38:45 +0100 Subject: [PATCH 4/4] minor gas optimisation --- contracts/contracts/token/OUSD.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index 792cab2e3a..643dfc2c99 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -485,7 +485,7 @@ contract OUSD is Governable { creditBalances[_account] = newCredits; // Globals _adjustGlobals( - creditBalances[_account].toInt256(), + newCredits.toInt256(), -newBalance.toInt256() );