Skip to content

Commit 063e12a

Browse files
committed
Add governance opt-in
1 parent 5b8856c commit 063e12a

File tree

2 files changed

+62
-28
lines changed

2 files changed

+62
-28
lines changed

contracts/contracts/token/OUSD.sol

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,44 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable {
473473
return nonRebasingCreditsPerToken[_account] > 0;
474474
}
475475

476+
/**
477+
* @dev Ensures internal account for rebasing and non-rebasing credits and
478+
* supply is updated following deployment of frozen yield change.
479+
*/
480+
function _ensureMigrationToRebasing(address _account) internal {
481+
if (nonRebasingCreditsPerToken[_account] == 0) {
482+
return; // Account already is rebasing
483+
}
484+
// Precalculate old balance so that no partial
485+
// account changes will affect it
486+
uint256 oldBalance = balanceOf(msg.sender);
487+
488+
// Precalculate new credits, so that we avoid internal calls when
489+
// atomically updating account.
490+
// Convert balance into the same amount at the current exchange rate
491+
uint256 newCreditBalance = _creditBalances[msg.sender]
492+
.mul(_rebasingCreditsPerToken)
493+
.div(_creditsPerToken(msg.sender));
494+
495+
// Atomicly update this account:
496+
// Important that no internal calls happen during this.
497+
// Remove pinned fixed credits per token
498+
delete nonRebasingCreditsPerToken[msg.sender];
499+
// New credits
500+
_creditBalances[msg.sender] = newCreditBalance;
501+
502+
// Update global totals:
503+
// Decrease non rebasing supply. We use the old balance, since that
504+
// would have been the value that was originally used to adjust the
505+
// nonRebasingSupply.
506+
nonRebasingSupply = nonRebasingSupply.sub(oldBalance);
507+
// Increase rebasing credits, totalSupply remains unchanged so no
508+
// adjustment necessary
509+
_rebasingCredits = _rebasingCredits.add(_creditBalances[msg.sender]);
510+
511+
emit RebasingEnabled(msg.sender, oldBalance, _rebasingCreditsPerToken);
512+
}
513+
476514
/**
477515
* @dev Ensures internal account for rebasing and non-rebasing credits and
478516
* supply is updated following deployment of frozen yield change.
@@ -529,36 +567,9 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable {
529567
function rebaseOptIn() public nonReentrant {
530568
require(_isNonRebasingAccount(msg.sender), "Account has not opted out");
531569

532-
// Precalculate old balance so that no partial
533-
// account changes will affect it
534-
uint256 oldBalance = balanceOf(msg.sender);
535-
536-
// Precalculate new credits, so that we avoid internal calls when
537-
// atomically updating account.
538-
// Convert balance into the same amount at the current exchange rate
539-
uint256 newCreditBalance = _creditBalances[msg.sender]
540-
.mul(_rebasingCreditsPerToken)
541-
.div(_creditsPerToken(msg.sender));
570+
_ensureMigrationToRebasing(msg.sender);
542571

543-
// Atomicly update this account:
544-
// Important that no internal calls happen during this.
545-
// Remove pinned fixed credits per token
546-
delete nonRebasingCreditsPerToken[msg.sender];
547-
// New credits
548-
_creditBalances[msg.sender] = newCreditBalance;
549-
// Mark explicitly opted in to rebasing
550572
rebaseState[msg.sender] = RebaseOptions.OptIn;
551-
552-
// Update global totals:
553-
// Decrease non rebasing supply. We use the old balance, since that
554-
// would have been the value that was originally used to adjust the
555-
// nonRebasingSupply.
556-
nonRebasingSupply = nonRebasingSupply.sub(oldBalance);
557-
// Increase rebasing credits, totalSupply remains unchanged so no
558-
// adjustment necessary
559-
_rebasingCredits = _rebasingCredits.add(_creditBalances[msg.sender]);
560-
561-
emit RebasingEnabled(msg.sender, oldBalance, _rebasingCreditsPerToken);
562573
}
563574

564575
/**
@@ -572,6 +583,22 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable {
572583
rebaseState[msg.sender] = RebaseOptions.OptOut;
573584
}
574585

586+
/**
587+
* @dev Governance action to allow a contract that does not support
588+
* opting in to earn yield
589+
*/
590+
function rebaseOptInByGovernance(address _account)
591+
external
592+
onlyGovernor
593+
nonReentrant
594+
{
595+
require(_isNonRebasingAccount(_account), "Account has not opted out");
596+
597+
_ensureMigrationToRebasing(_account);
598+
599+
rebaseState[_account] = RebaseOptions.OptIn;
600+
}
601+
575602
/**
576603
* @dev Modify the supply without minting new tokens. This uses a change in
577604
* the exchange rate between "credits" and OUSD tokens to change balances.

contracts/test/token/ousd.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,13 @@ describe("Token", function () {
530530
);
531531
});
532532

533+
it("Should not allow a non governor account to call rebaseOptInByGovernance", async () => {
534+
let { ousd, matt } = await loadFixture(defaultFixture);
535+
await expect(
536+
ousd.connect(matt).rebaseOptInByGovernance(matt.address)
537+
).to.be.revertedWith("Caller is not the Governor");
538+
});
539+
533540
it("Should maintain the correct balance on a partial transfer for a non-rebasing account without previously set creditsPerToken", async () => {
534541
let { ousd, matt, josh, mockNonRebasing } = await loadFixture(
535542
defaultFixture

0 commit comments

Comments
 (0)