Skip to content
Merged
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# @sovryn-zero/contracts

[![GitHub license](https://img.shields.io/github/license/DistributedCollective/zero)](/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/DistributedCollective/zero)](https://github.com/DistributedCollective/zero/stargazers)
[![GitHub license](https://img.shields.io/github/license/DistributedCollective/zero-contracts)](/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/DistributedCollective/zero-contracts)](https://github.com/DistributedCollective/zero-contracts/stargazers)
[![Zero README](https://img.shields.io/badge/readme-gray?style=flat&logo=ZeroMQ&logoColor=green&link=/README.md)](/README.md)

Zero solidity contracts
Expand Down
100 changes: 100 additions & 0 deletions contracts/BorrowerOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ import "./Dependencies/CheckContract.sol";
import "./Dependencies/console.sol";
import "./BorrowerOperationsStorage.sol";
import "./Dependencies/Mynt/MyntLib.sol";
import "./Interfaces/IPermit2.sol";

contract BorrowerOperations is
LiquityBase,
BorrowerOperationsStorage,
CheckContract,
IBorrowerOperations
{
/** CONSTANT / IMMUTABLE VARIABLE ONLY */
IPermit2 public immutable permit2;

/* --- Variable container structs ---

Used to hold, return and assign variables inside a function, in order to avoid the error:
Expand Down Expand Up @@ -91,6 +95,11 @@ contract BorrowerOperations is
);
event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);

/** Constructor */
constructor(address _permit2) public {
permit2 = IPermit2(_permit2);
}

// --- Dependency setters ---

function setAddresses(
Expand Down Expand Up @@ -357,6 +366,17 @@ contract BorrowerOperations is
_adjustNueTrove(0, 0, _dllrAmount, false, _upperHint, _lowerHint, _permitParams);
}

/// Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly
function repayZusdFromDLLRWithPermit2(
uint256 _dllrAmount,
address _upperHint,
address _lowerHint,
ISignatureTransfer.PermitTransferFrom memory _permit,
bytes calldata _signature
) external override {
_adjustNueTroveWithPermit2(0, 0, _dllrAmount, false, _upperHint, _lowerHint, _permit, _signature);
}

function adjustTrove(
uint256 _maxFeePercentage,
uint256 _collWithdrawal,
Expand Down Expand Up @@ -397,6 +417,29 @@ contract BorrowerOperations is
);
}

// in case of _isDebtIncrease = false MassetManager contract must have an approval of NUE tokens
function adjustNueTroveWithPermit2(
uint256 _maxFeePercentage,
uint256 _collWithdrawal,
uint256 _ZUSDChange,
bool _isDebtIncrease,
address _upperHint,
address _lowerHint,
ISignatureTransfer.PermitTransferFrom memory _permit,
bytes calldata _signature
) external payable override {
_adjustNueTroveWithPermit2(
_maxFeePercentage,
_collWithdrawal,
_ZUSDChange,
_isDebtIncrease,
_upperHint,
_lowerHint,
_permit,
_signature
);
}

// in case of _isDebtIncrease = false Masset Manager contract must have an approval of NUE tokens
function _adjustNueTrove(
uint256 _maxFeePercentage,
Expand Down Expand Up @@ -436,6 +479,47 @@ contract BorrowerOperations is
}
}

// in case of _isDebtIncrease = false Masset Manager contract must have an approval of NUE tokens
function _adjustNueTroveWithPermit2(
uint256 _maxFeePercentage,
uint256 _collWithdrawal,
uint256 _ZUSDChange,
bool _isDebtIncrease,
address _upperHint,
address _lowerHint,
ISignatureTransfer.PermitTransferFrom memory _permit,
bytes calldata _signature
) internal {
require(address(massetManager) != address(0), "Masset address not set");

if (!_isDebtIncrease && _ZUSDChange > 0) {
MyntLib.redeemZusdFromDllrWithPermit2(
massetManager,
address(zusdToken),
_permit,
permit2,
_signature
);
}
_adjustSenderTrove(
msg.sender,
_collWithdrawal,
_ZUSDChange,
_isDebtIncrease,
_upperHint,
_lowerHint,
_maxFeePercentage,
address(this)
);
if (_isDebtIncrease && _ZUSDChange > 0) {
require(
zusdToken.approve(address(massetManager), _ZUSDChange),
"Failed to approve ZUSD amount for Mynt mAsset to redeem"
);
massetManager.mintTo(address(zusdToken), _ZUSDChange, msg.sender);
}
}

function _adjustTrove(
address _borrower,
uint256 _collWithdrawal,
Expand Down Expand Up @@ -626,6 +710,22 @@ contract BorrowerOperations is
_closeTrove();
}

function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external override {
require(address(massetManager) != address(0), "Masset address not set");

uint256 debt = troveManager.getTroveDebt(msg.sender);

MyntLib.redeemZusdFromDllrWithPermit2(
massetManager,
address(zusdToken),
_permit,
permit2,
_signature
);

_closeTrove();
}

function _closeTrove() internal {
ITroveManager troveManagerCached = troveManager;
IActivePool activePoolCached = activePool;
Expand Down
28 changes: 28 additions & 0 deletions contracts/Dependencies/Counters.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.11;

import "./SafeMath.sol";

library Counters {
using SafeMath for uint256;

struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}

function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}

function increment(Counter storage counter) internal {
// The {SafeMath} overflow check can be skipped here, see the comment at the top
counter._value += 1;
}

function decrement(Counter storage counter) internal {

Choose a reason for hiding this comment

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

Why is it possible to decrement a nonce?

Copy link
Contributor

Choose a reason for hiding this comment

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

because this is a general purpose library. the function is internal and we don't use it for nonces.

counter._value = counter._value.sub(1);
}
}
59 changes: 58 additions & 1 deletion contracts/Dependencies/Mynt/MyntLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity 0.6.11;
import "./IMassetManager.sol";
import "./IDLLR.sol";
import "../SafeMath.sol";
import { IPermit2, ISignatureTransfer } from "../../Interfaces/IPermit2.sol";

library MyntLib {
using SafeMath for uint256;
Expand All @@ -13,9 +14,11 @@ library MyntLib {
* @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit
* to reduce the additional sending transaction for doing the approval to the spender.
*
* @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.
*
* @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration
* @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken
* @param _toToken bAsset token address to wothdraw from DLLR
* @param _toToken bAsset token address to withdraw from DLLR
* @param _permitParams EIP-2612 permit params:
* _deadline Expiration time of the signature.
* _v Last 1 byte of ECDSA signature.
Expand Down Expand Up @@ -47,4 +50,58 @@ library MyntLib {
);
return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);
}

/**
* @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract
* to reduce the additional sending transaction for doing the approval to the spender.
*
* @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration
* @param _toToken bAsset token address to withdraw from DLLR
* @param _permit permit data, in form of PermitTransferFrom struct.
* @param _permit2 permit2 contract address
* @param _signature signatue of the permit data.
* @return redeemed ZUSD amount
*/
function redeemZusdFromDllrWithPermit2(
IMassetManager _myntMassetManager,
address _toToken,
ISignatureTransfer.PermitTransferFrom memory _permit,
IPermit2 _permit2,
bytes calldata _signature
) internal returns (uint256) {
IDLLR dllr = IDLLR(_myntMassetManager.getToken());
uint256 thisBalanceBefore = dllr.balanceOf(address(this));
address thisAddress = address(this);
uint256 _dllrAmount = _permit.permitted.amount;

_permit2.permitTransferFrom(
_permit,
_generateTransferDetails(thisAddress, _dllrAmount),
msg.sender,
_signature
);

require(
dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,
"DLLR transferred amount validation failed"
);
return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);
}

/**
* @dev view function to construct SignatureTransferDetails struct to be used by Permit2
*
* @param _to ultimate recipient
* @param _amount amount of transfer
*
* @return SignatureTransferDetails struct object
*/
function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {
ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({
to: _to,
requestedAmount: _amount
});

return transferDetails;
}
}
40 changes: 39 additions & 1 deletion contracts/Dependencies/TroveManagerRedeemOps.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ pragma experimental ABIEncoderV2;
import "../Dependencies/Mynt/MyntLib.sol";
import "../Interfaces/IBorrowerOperations.sol";
import "./TroveManagerBase.sol";
import "../Interfaces/IPermit2.sol";

/// This contract is designed to be used via delegatecall from the TroveManager contract
/// TroveManagerBase constructor param is bootsrap period when redemptions are not allowed
contract TroveManagerRedeemOps is TroveManagerBase {
/** CONSTANT / IMMUTABLE VARIABLE ONLY */
IPermit2 public immutable permit2;

/** Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption
request. Applies pending rewards to a Trove before reducing its debt and coll.

Expand All @@ -32,7 +36,10 @@ contract TroveManagerRedeemOps is TroveManagerBase {
to redeem later.
*/

constructor(uint256 _bootstrapPeriod) public TroveManagerBase(_bootstrapPeriod) {}
/** Constructor */
constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) {
permit2 = IPermit2(_permit2);
}

function redeemCollateral(
uint256 _ZUSDamount,
Expand Down Expand Up @@ -203,6 +210,37 @@ contract TroveManagerRedeemOps is TroveManagerBase {
);
}

///DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction
function redeemCollateralViaDllrWithPermit2(
uint256 _dllrAmount,
address _firstRedemptionHint,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint256 _partialRedemptionHintNICR,
uint256 _maxIterations,
uint256 _maxFeePercentage,
ISignatureTransfer.PermitTransferFrom memory _permit,
bytes calldata _signature
) external {
uint256 _zusdAmount = MyntLib.redeemZusdFromDllrWithPermit2(
IBorrowerOperations(borrowerOperationsAddress).getMassetManager(),
address(_zusdToken),
_permit,
permit2,
_signature
);

_redeemCollateral(
_zusdAmount,
_firstRedemptionHint,
_upperPartialRedemptionHint,
_lowerPartialRedemptionHint,
_partialRedemptionHintNICR,
_maxIterations,
_maxFeePercentage
);
}

function _isValidFirstRedemptionHint(
ISortedTroves _sortedTroves,
address _firstRedemptionHint,
Expand Down
Loading