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

Add thoughts for possibility of start earning #18

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 68 additions & 47 deletions src/WrappedM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {

mapping(address account => BalanceInfo balance) internal _balances;

bool public isEarner;
uint128 public lastIndexOfTotalEarningSupply;

modifier onlyWhenEarner() {
if (isEarner == true) revert NotInEarnerState();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (isEarner == true) revert NotInEarnerState();
if (!isEarner) revert NotInEarnerState();


_;
}

/* ============ Constructor ============ */

constructor(address mToken_) ERC20Extended("WrappedM by M^0", "wM", 6) {
Expand All @@ -48,6 +57,22 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {

/* ============ Interactive Functions ============ */

function wrap(address destination_, uint256 amount_) external onlyWhenEarner {
Copy link
Member

Choose a reason for hiding this comment

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

Users should be able to wrap even if the wrapper is not currently earning.

Suggested change
function wrap(address destination_, uint256 amount_) external onlyWhenEarner {
function wrap(address destination_, uint256 amount_) external {

emit Transfer(address(0), destination_, amount_);

_mint(destination_, UIntMath.safe240(amount_));

IMTokenLike(mToken).transferFrom(msg.sender, address(this), amount_);
}

function unwrap(address destination_, uint256 amount_) external {
emit Transfer(msg.sender, address(0), amount_);

_burn(msg.sender, UIntMath.safe240(amount_));

IMTokenLike(mToken).transfer(destination_, amount_);
}

function claimFor(address account_) external returns (uint240 yield_) {
return _claim(account_, currentIndex());
}
Expand All @@ -58,15 +83,18 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
IMTokenLike(mToken).transfer(vault, yield_);
}

function deposit(address destination_, uint256 amount_) external {
emit Transfer(address(0), destination_, amount_);

_addAmount(destination_, UIntMath.safe240(amount_));
function startEarningM() external {
isEarner = true;
IMTokenLike(mToken).startEarning();
}

IMTokenLike(mToken).transferFrom(msg.sender, address(this), amount_);
function stopEarningM() external {
toninorair marked this conversation as resolved.
Show resolved Hide resolved
isEarner = false;
lastIndexOfTotalEarningSupply = currentIndex();
IMTokenLike(mToken).stopEarning();
}

function startEarningFor(address account_) external {
function startEarningFor(address account_) external onlyWhenEarner {
if (!_isApprovedEarner(account_)) revert NotApprovedEarner();

(bool isEarning_, , uint240 rawBalance_) = _getBalanceInfo(account_);
Expand All @@ -89,7 +117,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
_addTotalEarningSupply(rawBalance_, currentIndex_);
}

function stopEarningFor(address account_) external {
function stopEarningFor(address account_) external onlyWhenEarner {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think onlyWhenEarner is necessary since you can't be earning if the wrapper hasn't been earning in the past and you should be able to stop earning if the wrapper is not earning anymore.

Suggested change
function stopEarningFor(address account_) external onlyWhenEarner {
function stopEarningFor(address account_) external {

if (_isApprovedEarner(account_)) revert ApprovedEarner();

(bool isEarning_, , ) = _getBalanceInfo(account_);
Expand All @@ -107,19 +135,12 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
uint240 amount_ = IndexingMath.getPresentAmountRoundedDown(uint112(rawBalance_), index_);

_setBalanceInfo(account_, false, 0, amount_);

totalNonEarningSupply += amount_;

_subtractTotalEarningSupply(amount_, currentIndex_);
}

function withdraw(address destination_, uint256 amount_) external {
emit Transfer(msg.sender, address(0), amount_);

_subtractAmount(msg.sender, UIntMath.safe240(amount_));

IMTokenLike(mToken).transfer(destination_, amount_);
}

/* ============ View/Pure Functions ============ */

function accruedYieldOf(address account_) external view returns (uint240 yield_) {
Expand All @@ -135,7 +156,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
}

function currentIndex() public view returns (uint128 index_) {
return IMTokenLike(mToken).currentIndex();
return isEarner ? IMTokenLike(mToken).currentIndex() : lastIndexOfTotalEarningSupply;
}

function excess() public view returns (uint240 yield_) {
Expand All @@ -159,7 +180,7 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {

/* ============ Internal Interactive Functions ============ */

function _addAmount(address recipient_, uint240 amount_) internal {
function _mint(address recipient_, uint240 amount_) internal {
(bool isEarning_, , ) = _getBalanceInfo(recipient_);

if (!isEarning_) return _addNonEarningAmount(recipient_, amount_);
Expand All @@ -170,12 +191,29 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
_addEarningAmount(recipient_, amount_, currentIndex_);
}

function _burn(address account_, uint240 amount_) internal {
(bool isEarning_, , ) = _getBalanceInfo(account_);

if (!isEarning_) return _subtractNonEarningAmount(account_, amount_);

uint128 currentIndex_ = currentIndex();

_claim(account_, currentIndex_);
_subtractEarningAmount(account_, amount_, currentIndex_);
}

function _addNonEarningAmount(address recipient_, uint240 amount_) internal {
(, , uint240 rawBalance_) = _getBalanceInfo(recipient_);
_setBalanceInfo(recipient_, false, 0, rawBalance_ + amount_);
totalNonEarningSupply += amount_;
}

function _subtractNonEarningAmount(address account_, uint240 amount_) internal {
(, , uint240 rawBalance_) = _getBalanceInfo(account_);
_setBalanceInfo(account_, false, 0, rawBalance_ - amount_);
totalNonEarningSupply -= amount_;
}

function _addEarningAmount(address recipient_, uint240 amount_, uint128 currentIndex_) internal {
(, , uint240 rawBalance_) = _getBalanceInfo(recipient_);

Expand All @@ -189,6 +227,19 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
_addTotalEarningSupply(amount_, currentIndex_);
}

function _subtractEarningAmount(address account_, uint240 amount_, uint128 currentIndex_) internal {
(, , uint240 rawBalance_) = _getBalanceInfo(account_);

_setBalanceInfo(
account_,
true,
currentIndex_,
rawBalance_ - IndexingMath.getPrincipalAmountRoundedUp(amount_, currentIndex_)
);

_subtractTotalEarningSupply(amount_, currentIndex_);
}

function _claim(address account_, uint128 currentIndex_) internal returns (uint240 yield_) {
(bool isEarner_, uint128 index_, uint240 rawBalance_) = _getBalanceInfo(account_);

Expand Down Expand Up @@ -219,36 +270,6 @@ contract WrappedM is IWrappedM, Migratable, ERC20Extended {
: BalanceInfo.wrap(uint256(amount_));
}

function _subtractAmount(address account_, uint240 amount_) internal {
(bool isEarning_, , ) = _getBalanceInfo(account_);

if (!isEarning_) return _subtractNonEarningAmount(account_, amount_);

uint128 currentIndex_ = currentIndex();

_claim(account_, currentIndex_);
_subtractEarningAmount(account_, amount_, currentIndex_);
}

function _subtractNonEarningAmount(address account_, uint240 amount_) internal {
(, , uint240 rawBalance_) = _getBalanceInfo(account_);
_setBalanceInfo(account_, false, 0, rawBalance_ - amount_);
totalNonEarningSupply -= amount_;
}

function _subtractEarningAmount(address account_, uint240 amount_, uint128 currentIndex_) internal {
(, , uint240 rawBalance_) = _getBalanceInfo(account_);

_setBalanceInfo(
account_,
true,
currentIndex_,
rawBalance_ - IndexingMath.getPrincipalAmountRoundedUp(amount_, currentIndex_)
);

_subtractTotalEarningSupply(amount_, currentIndex_);
}

function _transfer(address sender_, address recipient_, uint240 amount_, uint128 currentIndex_) internal {
_claim(sender_, currentIndex_);
_claim(recipient_, currentIndex_);
Expand Down
4 changes: 4 additions & 0 deletions src/interfaces/IMTokenLike.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ interface IMTokenLike {

function transferFrom(address sender, address recipient, uint256 amount) external returns (bool success);

function startEarning() external;

function stopEarning() external;

/* ============ View/Pure Functions ============ */

function balanceOf(address account) external view returns (uint256 balance);
Expand Down
10 changes: 6 additions & 4 deletions src/interfaces/IWrappedM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,22 @@ interface IWrappedM is IMigratable, IERC20Extended {

error ZeroMToken();

error NotInEarnerState();

/* ============ Interactive Functions ============ */

function wrap(address destination, uint256 amount) external;

function unwrap(address destination, uint256 amount) external;

function claimFor(address account) external returns (uint240 yield);

function claimExcess() external returns (uint240 yield);

function deposit(address destination, uint256 amount) external;

function startEarningFor(address account) external;

function stopEarningFor(address account) external;

function withdraw(address destination, uint256 amount) external;

/* ============ View/Pure Functions ============ */

function accruedYieldOf(address account) external view returns (uint240 yield);
Expand Down
16 changes: 8 additions & 8 deletions test/Test.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ contract Tests is Test {
_wrappedM.startEarningFor(_bob);

vm.prank(_alice);
_wrappedM.deposit(_alice, 100_000000);
_wrappedM.wrap(_alice, 100_000000);

_mToken.setBalanceOf(address(_wrappedM), 100_000000);

Expand All @@ -140,7 +140,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 0);

vm.prank(_carol);
_wrappedM.deposit(_carol, 100_000000);
_wrappedM.wrap(_carol, 100_000000);

_mToken.setBalanceOf(address(_wrappedM), 200_000000);

Expand Down Expand Up @@ -174,7 +174,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 100_000000);

vm.prank(_bob);
_wrappedM.deposit(_bob, 100_000000);
_wrappedM.wrap(_bob, 100_000000);

_mToken.setBalanceOf(address(_wrappedM), 500_000000);

Expand All @@ -191,7 +191,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 100_000000);

vm.prank(_dave);
_wrappedM.deposit(_dave, 100_000000);
_wrappedM.wrap(_dave, 100_000000);

_mToken.setBalanceOf(address(_wrappedM), 600_000000);

Expand Down Expand Up @@ -368,7 +368,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 600_000001);

vm.prank(_alice);
_wrappedM.withdraw(_alice, 266_666664);
_wrappedM.unwrap(_alice, 266_666664);

_mToken.setBalanceOf(address(_wrappedM), 1_233_333336);

Expand All @@ -384,7 +384,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 600_000001);

vm.prank(_bob);
_wrappedM.withdraw(_bob, 333_333330);
_wrappedM.unwrap(_bob, 333_333330);

_mToken.setBalanceOf(address(_wrappedM), 900_000006);

Expand All @@ -400,7 +400,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 600_000001);

vm.prank(_carol);
_wrappedM.withdraw(_carol, 250_000000);
_wrappedM.unwrap(_carol, 250_000000);

_mToken.setBalanceOf(address(_wrappedM), 650_000006);

Expand All @@ -416,7 +416,7 @@ contract Tests is Test {
assertEq(_wrappedM.excess(), 600_000001);

vm.prank(_dave);
_wrappedM.withdraw(_dave, 50_000000);
_wrappedM.unwrap(_dave, 50_000000);

_mToken.setBalanceOf(address(_wrappedM), 600_000006);

Expand Down
Loading