Skip to content

Commit

Permalink
add a bunch of utility functions:
Browse files Browse the repository at this point in the history
- transferAll
- transferAllFrom
- redeemAll
- redeemAndTransferAll
  • Loading branch information
hellwolf committed Aug 24, 2019
1 parent a89bbb5 commit 2339ee8
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 33 deletions.
23 changes: 23 additions & 0 deletions contracts/IRToken.sol
Expand Up @@ -60,13 +60,29 @@ contract IRToken is IERC20 {
address[] calldata recipients,
uint32[] calldata proportions) external returns (bool);

/**
* @notice Moves all tokens from the caller's account to `dst`.
*/
function transferAll(address dst) external returns (bool);

/**
* @notice Moves all tokens from `src` account to `dst`.
*/
function transferAllFrom(address src, address dst) external returns (bool);

/**
* @notice Sender redeems rTokens in exchange for the underlying asset
* @param redeemTokens The number of rTokens to redeem into underlying
* @return uint 0=success, otherwise a failure
*/
function redeem(uint256 redeemTokens) external returns (bool);

/**
* @notice Sender redeems all rTokens in exchange for the underlying asset
* @return uint 0=success, otherwise a failure
*/
function redeemAll() external returns (bool);

/**
* @notice Sender redeems rTokens in exchange for the underlying asset then immediately transfer them to a differen user
* @param redeemTo Destination address to send the redeemed tokens to
Expand All @@ -75,6 +91,13 @@ contract IRToken is IERC20 {
*/
function redeemAndTransfer(address redeemTo, uint256 redeemTokens) external returns (bool);

/**
* @notice Sender redeems all rTokens in exchange for the underlying asset then immediately transfer them to a differen user
* @param redeemTo Destination address to send the redeemed tokens to
* @return uint 0=success, otherwise a failure
*/
function redeemAndTransferAll(address redeemTo) external returns (bool);

/**
* @notice Create a new Hat
* @param recipients List of beneficial recipients
Expand Down
107 changes: 80 additions & 27 deletions contracts/RToken.sol
Expand Up @@ -67,7 +67,7 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
/**
* @notice Total number of tokens in circulation
*/
uint256 public totalSupply;
uint256 public totalSupply;

/**
* @notice Returns the amount of tokens owned by `account`.
Expand All @@ -76,17 +76,6 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
return accounts[owner].rAmount;
}

/**
* @notice Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {
return transferInternal(msg.sender, msg.sender, dst, amount);
}

/**
* @notice Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through `transferFrom`. This is
Expand Down Expand Up @@ -119,6 +108,32 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
return true;
}

/**
* @notice Moves `amount` tokens from the caller's account to `dst`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
* May also emit `InterestPaid` event.
*/
function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {
return transferInternal(msg.sender, msg.sender, dst, amount);
}

/// @dev IRToken.transferAll implementation
function transferAll(address dst) external returns (bool) {
address src = msg.sender;
payInterestInternal(src);
return transferInternal(src, src, dst, accounts[src].rAmount);
}

/// @dev IRToken.transferAllFrom implementation
function transferAllFrom(address src, address dst) external returns (bool) {
payInterestInternal(src);
payInterestInternal(dst);
return transferInternal(msg.sender, src, dst, accounts[src].rAmount);
}

/**
* @notice Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
Expand Down Expand Up @@ -169,15 +184,36 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
* It withdraws equal amount of initially supplied underlying assets
*/
function redeem(uint256 redeemTokens) external nonReentrant returns (bool) {
redeemInternal(msg.sender, redeemTokens);
address src = msg.sender;
payInterestInternal(src);
redeemInternal(src, redeemTokens);
return true;
}

/// @dev IRToken.redeemAll implementation
function redeemAll() external nonReentrant returns (bool) {
address src = msg.sender;
payInterestInternal(src);
redeemInternal(src, accounts[src].rAmount);
return true;
}

/// @dev IRToken.redeemAndTransfer implementation
function redeemAndTransfer(address redeemTo, uint256 redeemTokens) external returns (bool) {
address src = msg.sender;
payInterestInternal(src);
redeemInternal(redeemTo, redeemTokens);
return true;
}

/// @dev IRToken.redeemAndTransferAll implementation
function redeemAndTransferAll(address redeemTo) external returns (bool) {
address src = msg.sender;
payInterestInternal(src);
redeemInternal(redeemTo, accounts[src].rAmount);
return true;
}

/// @dev IRToken.createHat implementation
function createHat(
address[] calldata recipients,
Expand Down Expand Up @@ -253,19 +289,8 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {

/// @dev IRToken.payInterest implementation
function payInterest(address owner) external nonReentrant returns (bool) {
Account storage account = accounts[owner];

ias.accrueInterest();
uint256 interestAmount = getInterestPayableOf(account);

if (interestAmount > 0) {
account.stats.cumulativeInterest = account.stats.cumulativeInterest.add(interestAmount);
account.rInterest = account.rInterest.add(interestAmount);
account.rAmount = account.rAmount.add(interestAmount);
totalSupply = totalSupply.add(interestAmount);
emit InterestPaid(owner, interestAmount);
emit Transfer(address(this), owner, interestAmount);
}
payInterestInternal(owner);
return true;
}

/// @dev IRToken.getAccountStats implementation!1
Expand Down Expand Up @@ -384,6 +409,10 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
*/
function transferInternal(address spender, address src, address dst, uint256 tokens) internal returns (bool) {
require(src != dst, "src should not equal dst");

// pay the interest before doing the transfer
payInterestInternal(src);

require(accounts[src].rAmount >= tokens, "Not enough balance to transfer");

/* Get the allowance, infinite for the account owner */
Expand Down Expand Up @@ -486,7 +515,11 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
totalSupply = totalSupply.sub(redeemAmount);

// update global stats
savingAssetOrignalAmount -= sOriginalBurned;
if (savingAssetOrignalAmount > sOriginalBurned) {
savingAssetOrignalAmount -= sOriginalBurned;
} else {
savingAssetOrignalAmount = 0;
}

// transfer the token back
token.transfer(redeemTo, redeemAmount);
Expand Down Expand Up @@ -741,4 +774,24 @@ contract RToken is IRToken, Ownable, ReentrancyGuard {
}
}
}

/**
* @dev pay interest to the owner
* @param owner Account owner address
*/
function payInterestInternal(address owner) internal {
Account storage account = accounts[owner];

ias.accrueInterest();
uint256 interestAmount = getInterestPayableOf(account);

if (interestAmount > 0) {
account.stats.cumulativeInterest = account.stats.cumulativeInterest.add(interestAmount);
account.rInterest = account.rInterest.add(interestAmount);
account.rAmount = account.rAmount.add(interestAmount);
totalSupply = totalSupply.add(interestAmount);
emit InterestPaid(owner, interestAmount);
emit Transfer(address(this), owner, interestAmount);
}
}
}

0 comments on commit 2339ee8

Please sign in to comment.