// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
contract BaseMath {
/// @notice Constant for the fractional arithmetics. Similar to 1 ETH = 1e18 wei.
uint256 constant internal DECIMAL_PRECISION = 1e18;
/// @notice Constant for the fractional arithmetics with ACR.
uint256 constant internal ACR_DECIMAL_PRECISION = 1e4;
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
/// @title Central logger contract
/// @notice Log collector with only 1 purpose - to emit the event. Can be called from any contract
/** @dev Use like this:
*
* bytes32 internal constant CENTRAL_LOGGER_ID = keccak256("CentralLogger");
* CentralLogger logger = CentralLogger(Registry(registry).getAddress(CENTRAL_LOGGER_ID));
*
* Or directly:
* CentralLogger logger = CentralLogger(0xDEPLOYEDADDRESS);
*
* logger.log(
* address(this),
* msg.sender,
* "myGreatFunction",
* abi.encode(msg.value, param1, param2)
* );
*
* DO NOT USE delegateCall as it defies the centralisation purpose of this logger.
*/
contract CentralLogger {
event LogEvent(
address indexed contractAddress,
address indexed caller,
string indexed logName,
bytes data
);
/* solhint-disable no-empty-blocks */
constructor() {
}
/// @notice Log the event centrally
/// @dev For gas impact see https://www.evm.codes/#a3
/// @param _logName length must be less than 32 bytes
function log(
address _contract,
address _caller,
string memory _logName,
bytes memory _data
) public {
emit LogEvent(_contract, _caller, _logName, _data);
}
}
// SPDX-License-Identifier: LGPL-3.0
pragma solidity =0.8.10;
import "./Ownable.sol";
contract CommunityAcknowledgement is Ownable {
/// @notice Recognised Community Contributor Acknowledgement Rate
/// @dev Id is keccak256 hash of contributor address
mapping (bytes32 => uint16) public rccar;
/// @notice Emit when owner recognises contributor
/// @param contributor Keccak256 hash of recognised contributor address
/// @param previousAcknowledgementRate Previous contributor acknowledgement rate
/// @param newAcknowledgementRate New contributor acknowledgement rate
event ContributorRecognised(bytes32 indexed contributor, uint16 indexed previousAcknowledgementRate, uint16 indexed newAcknowledgementRate);
/* solhint-disable-next-line no-empty-blocks */
constructor(address _adoptionDAOAddress) Ownable(_adoptionDAOAddress) {
}
/// @notice Getter for Recognised Community Contributor Acknowledgement Rate
/// @param _contributor Keccak256 hash of contributor address
/// @return Acknowledgement Rate
function getAcknowledgementRate(bytes32 _contributor) external view returns (uint16) {
return rccar[_contributor];
}
/// @notice Getter for Recognised Community Contributor Acknowledgement Rate for msg.sender
/// @return Acknowledgement Rate
function senderAcknowledgementRate() external view returns (uint16) {
return rccar[keccak256(abi.encodePacked(msg.sender))];
}
/// @notice Recognise community contributor and set its acknowledgement rate
/// @dev Only owner can recognise contributor
/// @dev Emits `ContributorRecognised` event
/// @param _contributor Keccak256 hash of recognised contributor address
/// @param _acknowledgementRate Contributor new acknowledgement rate
function recogniseContributor(bytes32 _contributor, uint16 _acknowledgementRate) public onlyOwner {
uint16 _previousAcknowledgementRate = rccar[_contributor];
rccar[_contributor] = _acknowledgementRate;
emit ContributorRecognised(_contributor, _previousAcknowledgementRate, _acknowledgementRate);
}
/// @notice Recognise list of contributors
/// @dev Only owner can recognise contributors
/// @dev Emits `ContributorRecognised` event for every contributor
/// @param _contributors List of keccak256 hash of recognised contributor addresses
/// @param _acknowledgementRates List of contributors new acknowledgement rates
function batchRecogniseContributor(bytes32[] calldata _contributors, uint16[] calldata _acknowledgementRates) external onlyOwner {
require(_contributors.length == _acknowledgementRates.length, "Lists do not match in length");
for (uint256 i = 0; i < _contributors.length; i++) {
recogniseContributor(_contributors[i], _acknowledgementRates[i]);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
import "./Ownable.sol";
/// @title APUS config contract
/// @notice Holds global variables for the rest of APUS ecosystem
contract Config is Ownable {
/// @notice Adoption Contribution Rate, where 100% = 10000 = ACR_DECIMAL_PRECISION.
/// @dev Percent value where 0 -> 0%, 10 -> 0.1%, 100 -> 1%, 250 -> 2.5%, 550 -> 5.5%, 1000 -> 10%, 0xffff -> 655.35%
/// @dev Example: x * adoptionContributionRate / ACR_DECIMAL_PRECISION
uint16 public adoptionContributionRate;
/// @notice Adoption DAO multisig address
address payable public adoptionDAOAddress;
/// @notice Emit when owner changes Adoption Contribution Rate
/// @param caller Who changed the Adoption Contribution Rate (i.e. who was owner at that moment)
/// @param previousACR Previous Adoption Contribution Rate
/// @param newACR New Adoption Contribution Rate
event ACRChanged(address indexed caller, uint16 previousACR, uint16 newACR);
/// @notice Emit when owner changes Adoption DAO address
/// @param caller Who changed the Adoption DAO address (i.e. who was owner at that moment)
/// @param previousAdoptionDAOAddress Previous Adoption DAO address
/// @param newAdoptionDAOAddress New Adoption DAO address
event AdoptionDAOAddressChanged(address indexed caller, address previousAdoptionDAOAddress, address newAdoptionDAOAddress);
/* solhint-disable-next-line func-visibility */
constructor(address payable _adoptionDAOAddress, uint16 _initialACR) Ownable(_adoptionDAOAddress) {
adoptionContributionRate = _initialACR;
adoptionDAOAddress = _adoptionDAOAddress;
}
/// @notice Change Adoption Contribution Rate
/// @dev Only owner can change Adoption Contribution Rate
/// @dev Emits `ACRChanged` event
/// @param _newACR Adoption Contribution Rate
function setAdoptionContributionRate(uint16 _newACR) external onlyOwner {
uint16 _previousACR = adoptionContributionRate;
adoptionContributionRate = _newACR;
emit ACRChanged(msg.sender, _previousACR, _newACR);
}
/// @notice Change Adoption DAO address
/// @dev Only owner can change Adoption DAO address
/// @dev Emits `AdoptionDAOAddressChanged` event
function setAdoptionDAOAddress(address payable _newAdoptionDAOAddress) external onlyOwner {
address payable _previousAdoptionDAOAddress = adoptionDAOAddress;
adoptionDAOAddress = _newAdoptionDAOAddress;
emit AdoptionDAOAddressChanged(msg.sender, _previousAdoptionDAOAddress, _newAdoptionDAOAddress);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
import "./DSAuthority.sol";
contract DSAuthEvents {
event LogSetAuthority(address indexed authority);
event LogSetOwner(address indexed owner);
}
abstract contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
constructor() {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_) public virtual;
function setAuthority(DSAuthority authority_) public virtual;
function isAuthorized(address src, bytes4 sig) internal view virtual returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
abstract contract DSAuthority {
function canCall(
address src,
address dst,
bytes4 sig
) public view virtual returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
import "./DSAuth.sol";
abstract contract DSProxy is DSAuth {
DSProxyCache public cache; // global cache for contracts
constructor(address _cacheAddr) {
require(setCache(_cacheAddr), "Cache not set");
}
// solhint-disable-next-line no-empty-blocks
receive() external payable {}
// use the proxy to execute calldata _data on contract _code
function execute(bytes memory _code, bytes memory _data)
public
payable
virtual
returns (address target, bytes32 response);
function execute(address _target, bytes memory _data)
public
payable
virtual
returns (bytes32 response);
//set new cache
function setCache(address _cacheAddr) public payable virtual returns (bool);
}
abstract contract DSProxyCache {
mapping(bytes32 => address) cache;
function read(bytes memory _code) public view virtual returns (address);
function write(bytes memory _code) public virtual returns (address target);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
import "./DSProxy.sol";
abstract contract DSProxyFactory {
function build(address owner) public virtual returns (DSProxy proxy);
function build() public virtual returns (DSProxy proxy);
function isProxy(address proxy) public virtual view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
interface ICollSurplusPool {
// --- Events ---
event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
event TroveManagerAddressChanged(address _newTroveManagerAddress);
event ActivePoolAddressChanged(address _newActivePoolAddress);
event CollBalanceUpdated(address indexed _account, uint _newBalance);
event EtherSent(address _to, uint _amount);
// --- Contract setters ---
function setAddresses(
address _borrowerOperationsAddress,
address _troveManagerAddress,
address _activePoolAddress
) external;
function getETH() external view returns (uint);
function getCollateral(address _account) external view returns (uint);
function accountSurplus(address _account, uint _amount) external;
function claimColl(address _account) external;
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
interface IHintHelpers {
function getRedemptionHints(
uint _LUSDamount,
uint _price,
uint _maxIterations
)
external
view
returns (
address firstRedemptionHint,
uint partialRedemptionHintNICR,
uint truncatedLUSDamount
);
function getApproxHint(uint _CR, uint _numTrials, uint _inputRandomSeed)
external
view
returns (address hintAddress, uint diff, uint latestRandomSeed);
function computeNominalCR(uint _coll, uint _debt) external pure returns (uint);
function computeCR(uint _coll, uint _debt, uint _price) external pure returns (uint);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
// Common interface for the SortedTroves Doubly Linked List.
interface ISortedTroves {
// --- Events ---
event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);
event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);
event NodeAdded(address _id, uint _NICR);
event NodeRemoved(address _id);
// --- Functions ---
function setParams(uint256 _size, address _TroveManagerAddress, address _borrowerOperationsAddress) external;
function insert(address _id, uint256 _ICR, address _prevId, address _nextId) external;
function remove(address _id) external;
function reInsert(address _id, uint256 _newICR, address _prevId, address _nextId) external;
function contains(address _id) external view returns (bool);
function isFull() external view returns (bool);
function isEmpty() external view returns (bool);
function getSize() external view returns (uint256);
function getMaxSize() external view returns (uint256);
function getFirst() external view returns (address);
function getLast() external view returns (address);
function getNext(address _id) external view returns (address);
function getPrev(address _id) external view returns (address);
function validInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (bool);
function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address);
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
// Common interface for the Trove Manager.
interface ITroveManager {
// --- Events ---
event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);
event PriceFeedAddressChanged(address _newPriceFeedAddress);
event LUSDTokenAddressChanged(address _newLUSDTokenAddress);
event ActivePoolAddressChanged(address _activePoolAddress);
event DefaultPoolAddressChanged(address _defaultPoolAddress);
event StabilityPoolAddressChanged(address _stabilityPoolAddress);
event GasPoolAddressChanged(address _gasPoolAddress);
event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);
event SortedTrovesAddressChanged(address _sortedTrovesAddress);
event LQTYTokenAddressChanged(address _lqtyTokenAddress);
event LQTYStakingAddressChanged(address _lqtyStakingAddress);
event Liquidation(uint _liquidatedDebt, uint _liquidatedColl, uint _collGasCompensation, uint _LUSDGasCompensation);
event Redemption(uint _attemptedLUSDAmount, uint _actualLUSDAmount, uint _ETHSent, uint _ETHFee);
event TroveUpdated(address indexed _borrower, uint _debt, uint _coll, uint stake, uint8 operation);
event TroveLiquidated(address indexed _borrower, uint _debt, uint _coll, uint8 operation);
event BaseRateUpdated(uint _baseRate);
event LastFeeOpTimeUpdated(uint _lastFeeOpTime);
event TotalStakesUpdated(uint _newTotalStakes);
event SystemSnapshotsUpdated(uint _totalStakesSnapshot, uint _totalCollateralSnapshot);
event LTermsUpdated(uint _L_ETH, uint _L_LUSDDebt);
event TroveSnapshotsUpdated(uint _L_ETH, uint _L_LUSDDebt);
event TroveIndexUpdated(address _borrower, uint _newIndex);
function getTroveOwnersCount() external view returns (uint);
function getTroveFromTroveOwnersArray(uint _index) external view returns (address);
function getNominalICR(address _borrower) external view returns (uint);
function getCurrentICR(address _borrower, uint _price) external view returns (uint);
function liquidate(address _borrower) external;
function liquidateTroves(uint _n) external;
function batchLiquidateTroves(address[] calldata _troveArray) external;
function redeemCollateral(
uint _LUSDAmount,
address _firstRedemptionHint,
address _upperPartialRedemptionHint,
address _lowerPartialRedemptionHint,
uint _partialRedemptionHintNICR,
uint _maxIterations,
uint _maxFee
) external;
function updateStakeAndTotalStakes(address _borrower) external returns (uint);
function updateTroveRewardSnapshots(address _borrower) external;
function addTroveOwnerToArray(address _borrower) external returns (uint index);
function applyPendingRewards(address _borrower) external;
function getPendingETHReward(address _borrower) external view returns (uint);
function getPendingLUSDDebtReward(address _borrower) external view returns (uint);
function hasPendingRewards(address _borrower) external view returns (bool);
function getEntireDebtAndColl(address _borrower) external view returns (
uint debt,
uint coll,
uint pendingLUSDDebtReward,
uint pendingETHReward
);
function closeTrove(address _borrower) external;
function removeStake(address _borrower) external;
function getRedemptionRate() external view returns (uint);
function getRedemptionRateWithDecay() external view returns (uint);
function getRedemptionFeeWithDecay(uint _ETHDrawn) external view returns (uint);
function getBorrowingRate() external view returns (uint);
function getBorrowingRateWithDecay() external view returns (uint);
function getBorrowingFee(uint LUSDDebt) external view returns (uint);
function getBorrowingFeeWithDecay(uint _LUSDDebt) external view returns (uint);
function decayBaseRateFromBorrowing() external;
function getTroveStatus(address _borrower) external view returns (uint);
function getTroveStake(address _borrower) external view returns (uint);
function getTroveDebt(address _borrower) external view returns (uint);
function getTroveColl(address _borrower) external view returns (uint);
function setTroveStatus(address _borrower, uint num) external;
function increaseTroveColl(address _borrower, uint _collIncrease) external returns (uint);
function decreaseTroveColl(address _borrower, uint _collDecrease) external returns (uint);
function increaseTroveDebt(address _borrower, uint _debtIncrease) external returns (uint);
function decreaseTroveDebt(address _borrower, uint _collDecrease) external returns (uint);
function getTCR(uint _price) external view returns (uint);
function checkRecoveryMode(uint _price) external view returns (bool);
function Troves(address) external view returns (uint256, uint256, uint256, uint8, uint128);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import "./BaseMath.sol";
/// @title Business calculation logic related to the Liquity protocol
/// @dev To be inherited only
contract LiquityMath is BaseMath {
// Maximum protocol fee as defined in the Liquity contracts
// https://github.com/liquity/dev/blob/cb583ddf5e7de6010e196cfe706bd0ca816ea40e/packages/contracts/contracts/TroveManager.sol#L48
uint256 internal constant LIQUITY_PROTOCOL_MAX_BORROWING_FEE = DECIMAL_PRECISION / 100 * 5; // 5%
// Amount of LUSD to be locked in Liquity's gas pool on opening troves
// https://github.com/liquity/dev/blob/cb583ddf5e7de6010e196cfe706bd0ca816ea40e/packages/contracts/contracts/TroveManager.sol#L334
uint256 internal constant LIQUITY_LUSD_GAS_COMPENSATION = 200e18;
/// @notice Calculates the needed amount of LUSD parameter for Liquity protocol when borrowing LUSD
/// @param _LUSDRequestedAmount Amount the user wants to withdraw
/// @param _expectedLiquityProtocolRate Current / expected borrowing rate of the Liquity protocol
/// @param _adoptionContributionRate Adoption Contribution Rate in uint16 form (xxyy defines xx.yy %). LPR is applied when ACR < LPR. Thus LPR is always used When AR is set to 0.
/* solhint-disable-next-line var-name-mixedcase */
function calcNeededLiquityLUSDAmount(uint256 _LUSDRequestedAmount, uint256 _expectedLiquityProtocolRate, uint16 _adoptionContributionRate) internal pure returns (
uint256 neededLiquityLUSDAmount
) {
// Normalise ACR 1e4 -> 1e18
uint256 acr = DECIMAL_PRECISION / ACR_DECIMAL_PRECISION * _adoptionContributionRate;
// Apply Liquity protocol rate when ACR is lower
acr = acr < _expectedLiquityProtocolRate ? _expectedLiquityProtocolRate : acr;
// Includes requested debt and adoption contribution which covers also liquity protocol fee
uint256 expectedDebtToRepay = _LUSDRequestedAmount * acr / DECIMAL_PRECISION + _LUSDRequestedAmount;
// = x / ( 1 + fee rate<0.005 - 0.05> )
neededLiquityLUSDAmount = DECIMAL_PRECISION * expectedDebtToRepay / ( DECIMAL_PRECISION + _expectedLiquityProtocolRate );
require(neededLiquityLUSDAmount >= _LUSDRequestedAmount, "Cannot mint less than requested.");
}
/// @notice Calculates adjusted Adoption Contribution Rate decreased by RCCAR down to min 0.
/// @param _rccar Recognised Community Contributor Acknowledgement Rate in uint16 form (xxyy defines xx.yy % points).
/// @param _adoptionContributionRate Adoption Contribution Rate in uint16 form (xxyy defines xx.yy %).
function applyRccarOnAcr(uint16 _rccar, uint16 _adoptionContributionRate) internal pure returns (
uint16 adjustedAcr
) {
return (_adoptionContributionRate > _rccar ? _adoptionContributionRate - _rccar : 0);
}
}
// SPDX-License-Identifier: MIT
// Adapted from OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)
// Using less gas and initiating the first owner to the provided multisig address
pragma solidity ^0.8.10;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one provided during the deployment of the contract.
* This can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable {
/**
* @dev Address of the current owner.
*/
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @param _firstOwner Initial owner
* @dev Initializes the contract setting the initial owner.
*/
constructor(address _firstOwner) {
_transferOwnership(_firstOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner == msg.sender, "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address _newOwner) public virtual onlyOwner {
require(_newOwner != address(0), "Ownable: cannot be zero address");
_transferOwnership(_newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address _newOwner) internal virtual {
address oldOwner = owner;
owner = _newOwner;
emit OwnershipTransferred(oldOwner, _newOwner);
}
}
// SPDX-License-Identifier: MIT
pragma solidity =0.8.10;
import "./Ownable.sol";
/// @title Registry contract for whole Apus ecosystem
/// @notice Holds addresses of all essential Apus contracts
contract Registry is Ownable {
/// @notice Stores address under its id
/// @dev Id is keccak256 hash of its string representation
mapping (bytes32 => address) public addresses;
/// @notice Emit when owner registers address
/// @param id Keccak256 hash of its string id representation
/// @param previousAddress Previous address value under given id
/// @param newAddress New address under given id
event AddressRegistered(bytes32 indexed id, address indexed previousAddress, address indexed newAddress);
/* solhint-disable-next-line no-empty-blocks */
constructor(address _initialOwner) Ownable(_initialOwner) {
}
/// @notice Getter for registered addresses
/// @dev Returns zero address if address have not been registered before
/// @param _id Registered address identifier
function getAddress(bytes32 _id) external view returns(address) {
return addresses[_id];
}
/// @notice Register address under given id
/// @dev Only owner can register addresses
/// @dev Emits `AddressRegistered` event
/// @param _id Keccak256 hash of its string id representation
/// @param _address Registering address
function registerAddress(bytes32 _id, address _address) public onlyOwner {
require(_address != address(0), "Can't register 0x0 address");
address _previousAddress = addresses[_id];
addresses[_id] = _address;
emit AddressRegistered(_id, _previousAddress, _address);
}
/// @notice Register list of addresses under given list of ids
/// @dev Only owner can register addresses
/// @dev Emits `AddressRegistered` event for every address
/// @param _ids List of keccak256 hashes of its string id representation
/// @param _addresses List of registering addresses
function batchRegisterAddresses(bytes32[] calldata _ids, address[] calldata _addresses) external onlyOwner {
require(_ids.length == _addresses.length, "Lists do not match in length");
for (uint256 i = 0; i < _ids.length; i++) {
registerAddress(_ids[i], _addresses[i]);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
contract SqrtMath {
/// @notice Calculates the square root of x, rounding down.
/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Caveats:
/// - This function does not work with fixed-point numbers.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as an uint256.
// source: https://github.com/paulrberg/prb-math/blob/86c068e21f9ba229025a77b951bd3c4c4cf103da/contracts/PRBMath.sol#L591
function sqrt(uint256 x) internal pure returns (uint256 result) {
if (x == 0) {
return 0;
}
// Set the initial guess to the least power of two that is greater than or equal to sqrt(x).
uint256 xAux = uint256(x);
result = 1;
if (xAux >= 0x100000000000000000000000000000000) {
xAux >>= 128;
result <<= 64;
}
if (xAux >= 0x10000000000000000) {
xAux >>= 64;
result <<= 32;
}
if (xAux >= 0x100000000) {
xAux >>= 32;
result <<= 16;
}
if (xAux >= 0x10000) {
xAux >>= 16;
result <<= 8;
}
if (xAux >= 0x100) {
xAux >>= 8;
result <<= 4;
}
if (xAux >= 0x10) {
xAux >>= 4;
result <<= 2;
}
if (xAux >= 0x8) {
result <<= 1;
}
// The operations can never overflow because the result is max 2^127 when it enters this block.
unchecked {
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1; // Seven iterations should be enough
uint256 roundedDownResult = x / result;
return result >= roundedDownResult ? roundedDownResult : result;
}
}
}
// SPDX-License-Identifier: LGPL-3.0
pragma solidity =0.8.10;
import "./Registry.sol";
import "./dapphub/DSProxyFactory.sol";
import "./dapphub/DSProxy.sol";
import "./Config.sol";
import "./CentralLogger.sol";
import "./CommunityAcknowledgement.sol";
import "./LiquityMath.sol";
import "./SqrtMath.sol";
import "./interfaces/ITroveManager.sol";
import "./interfaces/IHintHelpers.sol";
import "./interfaces/ISortedTroves.sol";
import "./interfaces/ICollSurplusPool.sol";
/// @title Stargate contract serves as a gateway and a gatekeeper into the APUS protocol ecosystem
/// @notice The main motivation of Stargate is to give user understandable transaction to sign (i.e. no bytecode giberish)
/// and to chain common sequence of transactions thus saving gas.
/// @dev It encodes all arguments and calls given user's Smart Account proxy with any additional arguments
contract Stargate is LiquityMath, SqrtMath {
/* solhint-disable var-name-mixedcase */
/// @notice Registry's contracts IDs
bytes32 private constant EXECUTOR_ID = keccak256("Executor");
bytes32 private constant CONFIG_ID = keccak256("Config");
bytes32 private constant AUTHORITY_ID = keccak256("Authority");
bytes32 private constant COMMUNITY_ACKNOWLEDGEMENT_ID = keccak256("CommunityAcknowledgement");
bytes32 private constant CENTRAL_LOGGER_ID = keccak256("CentralLogger");
/// @notice APUS registry address
address public immutable registry;
// MakerDAO's deployed contracts - Proxy Factory
// see https://changelog.makerdao.com/
DSProxyFactory public immutable ProxyFactory;
// L1 Liquity deployed contracts addresses
// see https://docs.liquity.org/documentation/resources#contract-addresses
ITroveManager public immutable TroveManager;
IHintHelpers public immutable HintHelpers;
ISortedTroves public immutable SortedTroves;
ICollSurplusPool public immutable CollSurplusPool;
/// @notice Event raised on Stargate when a new Smart Account is created.
/// Corresponding event is also raised on the Central Logger
event SmartAccountCreated(
address indexed owner,
address indexed smartAccountAddress
);
/// @notice Modifier will fail if message sender is not the proxy owner
/// @param _proxy Proxy address that must be owned
modifier onlyProxyOwner(address payable _proxy) {
require(DSProxy(_proxy).owner() == msg.sender, "Sender has to be proxy owner");
_;
}
/* solhint-disable-next-line func-visibility */
constructor(
address _registry,
address _troveManager,
address _hintHelpers,
address _sortedTroves,
address _collSurplusPool,
address _proxyFactory
) {
registry = _registry;
TroveManager = ITroveManager(_troveManager);
HintHelpers = IHintHelpers(_hintHelpers);
SortedTroves = ISortedTroves(_sortedTroves);
CollSurplusPool = ICollSurplusPool(_collSurplusPool);
ProxyFactory = DSProxyFactory(_proxyFactory);
}
/// @notice Execute proxy call with encoded transaction data and eth value
/// @dev Proxy delegates call to executor address which is obtained from registry contract
/// @param _proxy Proxy address to execute encoded transaction
/// @param _value Value of eth to transfer with function call
/// @param _data Transaction data to execute
function _execute(address payable _proxy, uint256 _value, bytes memory _data) internal onlyProxyOwner(_proxy) {
DSProxy(_proxy).execute{ value: _value }(Registry(registry).getAddress(EXECUTOR_ID), _data);
}
/// @notice Execute proxy call with encoded transaction data and eth value by anyone
/**
* @dev Proxy delegates call to executor address which is obtained from registry contract
*
* This is the DANGEROUS version as it enables the proxy call to be performed by anyone!
*
* However suitable for cases when user wants to provide ETH from other (proxy non-owning) accounts.
*/
/// @param _proxy Proxy address to execute encoded transaction
/// @param _value Value of eth to transfer with function call
/// @param _data Transaction data to execute
function _executeByAnyone(address payable _proxy, uint256 _value, bytes memory _data) internal {
DSProxy(_proxy).execute{ value: _value }(Registry(registry).getAddress(EXECUTOR_ID), _data);
}
// Stargate MUST NOT be able to receive ETH from sender to itself
// in 0.8.x function() is split to receive() and fallback(); if both are undefined -> tx reverts
// ------------------------------------------ User functions ------------------------------------------
/// @notice Creates the Smart Account directly. Its new address is emitted to the event.
/// It is cheaper to open Smart Account while opening Credit Line wihin 1 transaction.
function openSmartAccount() external {
_openSmartAccount();
}
/// @notice Builds the new MakerDAO's proxy aka Smart Account with enabled calls from this Stargate
function _openSmartAccount() internal returns (address payable) {
// Deploy a new MakerDAO's proxy onto blockchain
DSProxy smartAccount = ProxyFactory.build();
// Enable Stargate's user functions to call the Smart Account
DSAuthority stargateAuthority = DSAuthority(Registry(registry).getAddress(AUTHORITY_ID));
smartAccount.setAuthority(stargateAuthority);
// Set owner of MakerDAO's proxy aka Smart Account to be the user
smartAccount.setOwner(msg.sender);
// Emit centraly at this contract and the Central Logger
emit SmartAccountCreated(msg.sender, address(smartAccount));
CentralLogger logger = CentralLogger(Registry(registry).getAddress(CENTRAL_LOGGER_ID));
logger.log(
address(this), msg.sender, "openSmartAccount", abi.encode(smartAccount)
);
return payable(smartAccount);
}
/// @notice Get the gasless information on Credit Line (Liquity) status of the given Smart Account
/// @param _smartAccount Smart Account address.
/// @return status Status of the Credit Line within Liquity protocol, where:
/// 0..nonExistent,
/// 1..active,
/// 2..closedByOwner,
/// 3..closedByLiquidation,
/// 4..closedByRedemption
/// @return collateral ETH collateral.
/// @return debtToRepay Total amount of LUSD needed to close the Credit Line (exluding the 200 LUSD liquidation reserve).
/// @return debtComposite Composite debt including the liquidation reserve. Valid for LTV (CR) calculations.
function getCreditLineStatusLiquity(address payable _smartAccount) external view returns (
uint8 status,
uint256 collateral,
uint256 debtToRepay,
uint256 debtComposite
) {
(debtComposite, collateral, , status, ) = TroveManager.Troves(_smartAccount);
debtToRepay = debtComposite > LIQUITY_LUSD_GAS_COMPENSATION ? debtComposite - LIQUITY_LUSD_GAS_COMPENSATION : 0;
}
/// @notice Calculates Liquity sorting hints based on the provided NICR
function getLiquityHints(uint256 NICR) internal view returns (
address upperHint,
address lowerHint
) {
// Get an approximate address hint from the deployed HintHelper contract.
uint256 numTroves = SortedTroves.getSize();
uint256 numTrials = sqrt(numTroves) * 15;
(address approxHint, , ) = HintHelpers.getApproxHint(NICR, numTrials, 0x41505553);
// Use the approximate hint to get the exact upper and lower hints from the deployed SortedTroves contract
(upperHint, lowerHint) = SortedTroves.findInsertPosition(NICR, approxHint, approxHint);
}
/// @notice Calculates LUSD expected debt to repay.
/// Includes _LUSDRequested, Adoption Contribution, Liquity protocol fee.
/// Adoption Contribution reflects the Adoption Contribution Rate and Recognised Community Contributor Acknowledgement Rate if applicable.
function getLiquityExpectedDebtToRepay(uint256 _LUSDRequested) internal view returns (uint256 expectedDebtToRepay) {
uint16 applicableAcr;
uint256 expectedLiquityProtocolRate;
(applicableAcr, expectedLiquityProtocolRate) = getLiquityRates();
uint256 neededLUSDAmount = calcNeededLiquityLUSDAmount(_LUSDRequested, expectedLiquityProtocolRate, applicableAcr);
uint256 expectedLiquityProtocolFee = TroveManager.getBorrowingFeeWithDecay(neededLUSDAmount);
expectedDebtToRepay = neededLUSDAmount + expectedLiquityProtocolFee;
}
/// @notice Calculates the rates related to Liquity for the msg.sender
/// @return applicableAcr Adoption Contribution Rate with applied Recognised Community Contributor Acknowledgement Rate of msg.sender if applicable.
/// @return expectedLiquityProtocolRate Current rate of the Liquity protocol
function getLiquityRates() internal view returns (uint16 applicableAcr, uint256 expectedLiquityProtocolRate) {
// Get and apply Recognised Community Contributor Acknowledgement Rate
CommunityAcknowledgement ca = CommunityAcknowledgement(Registry(registry).getAddress(COMMUNITY_ACKNOWLEDGEMENT_ID));
uint16 rccar = ca.getAcknowledgementRate(keccak256(abi.encodePacked(msg.sender)));
Config config = Config(Registry(registry).getAddress(CONFIG_ID));
applicableAcr = applyRccarOnAcr(rccar, config.adoptionContributionRate());
expectedLiquityProtocolRate = TroveManager.getBorrowingRateWithDecay();
}
/// @notice Calculates the current rate for the msg.sender as related to Liquity and Adoption Contribution incl. RCCAR
function userAdoptionRate() external view returns (uint256) {
uint16 applicableAcr;
uint256 expectedLiquityProtocolRate;
(applicableAcr, expectedLiquityProtocolRate) = getLiquityRates();
// Normalise applicable ACR 1e4 -> 1e18
uint256 r = DECIMAL_PRECISION / ACR_DECIMAL_PRECISION * applicableAcr;
// Apply Liquity protocol rate when applicable ACR is lower
return r < expectedLiquityProtocolRate ? expectedLiquityProtocolRate : r;
}
/// @notice Makes a gasless calculation to get the data for the Credit Line's initial setup on Liquity protocol
/// @param _LUSDRequested Requested LUSD amount to be taken by borrower. In e18 (1 LUSD = 1e18).
/// Adoption Contribution including protocol's fees is applied in the form of additional debt.
/// @param _collateralAmount Amount of ETH to be deposited into the Credit Line. In wei (1 ETH = 1e18).
/// @return expectedDebtToRepay Total amount of LUSD needed to close the Credit Line (exluding the 200 LUSD liquidation reserve).
/// @return liquidationReserve Liquidation gas reserve required by the Liquity protocol.
/// @return expectedCompositeDebtLiquity Total debt of the new Credit Line including the liquidation reserve. Valid for LTV (CR) calculations.
/// @return NICR Nominal Individual Collateral Ratio for this calculation as defined and used by Liquity protocol.
/// @return upperHint Calculated hint for gas optimalization of the Liquity protocol when opening new Credit Line with openCreditLineLiquity.
/// @return lowerHint Calculated hint for gas optimalization of the Liquity protocol when opening new Credit Line with openCreditLineLiquity.
function calculateInitialLiquityParameters(uint256 _LUSDRequested, uint256 _collateralAmount) public view returns (
uint256 expectedDebtToRepay,
uint256 liquidationReserve,
uint256 expectedCompositeDebtLiquity,
uint256 NICR,
address upperHint,
address lowerHint
) {
liquidationReserve = LIQUITY_LUSD_GAS_COMPENSATION;
expectedDebtToRepay = getLiquityExpectedDebtToRepay(_LUSDRequested);
expectedCompositeDebtLiquity = expectedDebtToRepay + LIQUITY_LUSD_GAS_COMPENSATION;
// Get the nominal NICR of the new Liquity's trove
NICR = _collateralAmount * 1e20 / expectedCompositeDebtLiquity;
(upperHint, lowerHint) = getLiquityHints(NICR);
}
/// @notice Makes a gasless calculation to get the data for the Credit Line's adjustement on Liquity protocol
/// @param _isDebtIncrease Indication whether _LUSDRequestedChange increases debt (true), decreases debt(false) or does not impact debt (false).
/// @param _LUSDRequestedChange Amount of LUSD to be returned or further borrowed. The increase or decrease is indicated by _isDebtIncrease.
/// Adoption Contribution including protocol's fees is applied in the form of additional debt in case of requested debt increase.
/// @param _isCollateralIncrease Indication whether _LUSDRequestedChange increases debt (true), decreases debt(false) or does not impact debt (false).
/// @param _collateralChange Amount of ETH collateral to be withdrawn or added. The increase or decrease is indicated by _isCollateralIncrease.
/// @return newCollateral Calculated future collateral.
/// @return expectedDebtToRepay Total future amount of LUSD needed to close the Credit Line (exluding the 200 LUSD liquidation reserve).
/// @return liquidationReserve Liquidation gas reserve required by the Liquity protocol.
/// @return expectedCompositeDebtLiquity Total future debt of the new Credit Line including the liquidation reserve. Valid for LTV (CR) calculations.
/// @return NICR Nominal Individual Collateral Ratio for this calculation as defined and used by Liquity protocol.
/// @return upperHint Calculated hint for gas optimalization of the Liquity protocol when opening new Credit Line with openCreditLineLiquity.
/// @return lowerHint Calculated hint for gas optimalization of the Liquity protocol when opening new Credit Line with openCreditLineLiquity.
/// @dev bools and uints are used to avoid typecasting and overflow issues and to explicitely signal the direction
function calculateChangedLiquityParameters(
bool _isDebtIncrease,
uint256 _LUSDRequestedChange,
bool _isCollateralIncrease,
uint256 _collateralChange,
address payable _smartAccount
) public view returns (
uint256 newCollateral,
uint256 expectedDebtToRepay,
uint256 liquidationReserve,
uint256 expectedCompositeDebtLiquity,
uint256 NICR,
address upperHint,
address lowerHint
) {
liquidationReserve = LIQUITY_LUSD_GAS_COMPENSATION;
// Get the current LUSD debt and ETH collateral
(uint256 currentCompositeDebt, uint256 currentCollateral, , ) = TroveManager.getEntireDebtAndColl(_smartAccount);
uint256 currentDebtToRepay = currentCompositeDebt - LIQUITY_LUSD_GAS_COMPENSATION;
if (_isCollateralIncrease) {
newCollateral = currentCollateral + _collateralChange;
} else {
newCollateral = currentCollateral - _collateralChange;
}
if (_isDebtIncrease) {
uint256 additionalDebtToRepay = getLiquityExpectedDebtToRepay(_LUSDRequestedChange);
expectedDebtToRepay = currentDebtToRepay + additionalDebtToRepay;
} else {
expectedDebtToRepay = currentDebtToRepay - _LUSDRequestedChange;
}
expectedCompositeDebtLiquity = expectedDebtToRepay + LIQUITY_LUSD_GAS_COMPENSATION;
// Get the nominal NICR of the new Liquity's trove
NICR = newCollateral * 1e20 / expectedCompositeDebtLiquity;
(upperHint, lowerHint) = getLiquityHints(NICR);
}
/// @notice Opens a new Credit Line using Liquity protocol by depositing ETH collateral and borrowing LUSD.
/// Creates the new Smart Account (MakerDAO's proxy) if requested.
/// Use calculateInitialLiquityParameters for gasless calculation of proper Hints for _LUSDRequested.
/// @param _LUSDRequested Amount of LUSD caller wants to borrow and withdraw. In e18 (1 LUSD = 1e18).
/// @param _LUSDTo Address that will receive the generated LUSD. Can be different to save gas on transfer.
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateInitialLiquityParameters for gasless calculation of proper Hints for _LUSDRequested.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateInitialLiquityParameters for gasless calculation of proper Hints for _LUSDRequested.
/// @param _smartAccount Smart Account address. When 0x0000...00 sender requests to open a new Smart Account.
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
/// @dev Value is amount of ETH to deposit into Liquity protocol.
function openCreditLineLiquity(uint256 _LUSDRequested, address _LUSDTo, address _upperHint, address _lowerHint, address payable _smartAccount) external payable {
// By submitting 0x00..0 as the smartAccount address the caller wants to open a new Smart Account during this 1 transaction and thus saving gas.
_smartAccount = (_smartAccount == address(0)) ? _openSmartAccount() : _smartAccount;
_execute(_smartAccount, msg.value, abi.encodeWithSignature(
"openCreditLineLiquity(uint256,address,address,address,address)",
_LUSDRequested, _LUSDTo, _upperHint, _lowerHint, msg.sender
));
}
/// @notice Allows a borrower to repay all LUSD debt, withdraw all their ETH collateral, and close their Credit Line on Liquity protocol.
/// @param _LUSDFrom Address where the LUSD is being pulled from to repay debt.
/// @param _collateralTo Address that will receive the withdrawn ETH.
/// @param _smartAccount Smart Account address
function closeCreditLineLiquity(address _LUSDFrom, address payable _collateralTo, address payable _smartAccount) public {
_execute(_smartAccount, 0,
abi.encodeWithSignature(
"closeCreditLineLiquity(address,address,address)",
_LUSDFrom,
_collateralTo,
msg.sender
));
}
/// @notice Allows a borrower to repay all LUSD debt, withdraw all their ETH collateral, and close their Credit Line on Liquity protocol using EIP2612 Permit.
/// @param _LUSDFrom Address where the LUSD is being pulled from to repay debt.
/// @param _collateralTo Address that will receive the withdrawn ETH.
/// @param v EIP2612 secp256k1 permit signature part
/// @param r EIP2612 secp256k1 permit signature part
/// @param s EIP2612 secp256k1 permit signature part
/// @param _smartAccount Smart Account address
function closeCreditLineLiquityWithPermit(address _LUSDFrom, address payable _collateralTo, uint8 v, bytes32 r, bytes32 s, address payable _smartAccount) external {
_execute(_smartAccount, 0, abi.encodeWithSignature(
"closeCreditLineLiquityWithPermit(address,address,uint8,bytes32,bytes32,address)",
_LUSDFrom, _collateralTo, v, r, s, msg.sender
));
}
/// @notice Enables a borrower to simultaneously change both their collateral and debt.
/// Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _isDebtIncrease Indication whether _LUSDRequestedChange increases debt (true), decreases debt(false) or does not impact debt (false).
/// @param _LUSDRequestedChange Amount of LUSD to be returned or further borrowed.
/// The increase or decrease is indicated by _isDebtIncrease.
/// Adoption Contribution and protocol's fees are applied in the form of additional debt in case of requested debt increase.
/// @param _LUSDAddress Address where the LUSD is being pulled from in case of to repaying debt.
/// Or address that will receive the generated LUSD in case of increasing debt.
/// Approval of LUSD transfers for given Smart Account is required in case of repaying debt.
/// @param _collWithdrawal Amount of ETH collateral to withdraw. MUST be 0 if ETH is provided to increase collateral.
/// @param _collateralTo Address that will receive the withdrawn collateral ETH.
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _smartAccount Smart Account address
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
/// @dev Hints should reflect calculated neededLUSDAmount instead of _LUSDRequestedChange
/// @dev Value is amount of ETH to deposit into Liquity protocol
function adjustCreditLineLiquity(
bool _isDebtIncrease,
uint256 _LUSDRequestedChange,
address _LUSDAddress,
uint256 _collWithdrawal,
address payable _collateralTo,
address _upperHint, address _lowerHint,
address payable _smartAccount) external payable {
_execute(_smartAccount, msg.value, abi.encodeWithSignature(
"adjustCreditLineLiquity(bool,uint256,address,uint256,address,address,address,address)",
_isDebtIncrease, _LUSDRequestedChange, _LUSDAddress, _collWithdrawal, _collateralTo, _upperHint, _lowerHint, msg.sender
));
}
/// @notice Enables a borrower to simultaneously change both their collateral and decrease debt providing LUSD from ANY ADDRESS using EIP2612 Permit.
/// Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// It is useful only when the debt decrease is requested while working with collateral.
/// In all other cases [adjustCreditLineLiquity()] MUST be used. It is cheaper on gas.
/// @param _LUSDRequestedChange Amount of LUSD to be returned.
/// @param _LUSDFrom Address where the LUSD is being pulled from. Can be ANY ADDRESS with enough LUSD.
/// Approval of LUSD transfers for given Smart Account is ensured by the offchain signature from that address.
/// @param _collWithdrawal Amount of ETH collateral to withdraw. MUST be 0 if ETH is provided to increase collateral.
/// @param _collateralTo Address that will receive the withdrawn collateral ETH.
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param v EIP2612 secp256k1 permit signature part
/// @param r EIP2612 secp256k1 permit signature part
/// @param s EIP2612 secp256k1 permit signature part
/// @param _smartAccount Smart Account address
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
/// @dev Value is amount of ETH to deposit into Liquity protocol
function adjustCreditLineLiquityWithPermit(
uint256 _LUSDRequestedChange,
address _LUSDFrom,
uint256 _collWithdrawal,
address payable _collateralTo,
address _upperHint, address _lowerHint,
uint8 v, bytes32 r, bytes32 s,
address payable _smartAccount) external payable {
_execute(_smartAccount, msg.value, abi.encodeWithSignature(
"adjustCreditLineLiquityWithPermit(uint256,address,uint256,address,address,address,uint8,bytes32,bytes32,address)",
_LUSDRequestedChange, _LUSDFrom, _collWithdrawal, _collateralTo, _upperHint, _lowerHint, v, r, s, msg.sender
));
}
/// @notice Gasless check if there is anything to be claimed after the forced closure of the Liquity Credit Line
function checkClaimableCollateralLiquity(address _smartAccount) external view returns (uint256) {
return CollSurplusPool.getCollateral(_smartAccount);
}
/// @notice Claims remaining collateral from the user's closed Credit Line (Liquity protocol) due to a redemption or a liquidation.
/// @param _collateralTo Address that will receive the claimed collateral ETH.
/// @param _smartAccount Smart Account address
function claimRemainingCollateralLiquity(address payable _collateralTo, address payable _smartAccount) external {
_execute(_smartAccount, 0, abi.encodeWithSignature(
"claimRemainingCollateralLiquity(address,address)",
_collateralTo,
msg.sender
));
}
/// @notice Allows ANY ADDRESS (calling and paying) to add ETH collateral to borrower's Credit Line (Liquity protocol) and thus increase CR (decrease LTV ratio).
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints.
/// @param _smartAccount Smart Account address
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
function addCollateralLiquity(address _upperHint, address _lowerHint, address payable _smartAccount) external payable {
// Must be executable by anyone in order to be able to provide ETH by addresses, which do not own smart account proxy
_executeByAnyone(_smartAccount, msg.value, abi.encodeWithSignature(
"addCollateralLiquity(address,address,address)",
_upperHint, _lowerHint, msg.sender
));
}
/// @notice Withdraws amount of ETH collateral from the Credit Line and transfer to _collateralTo address.
/// @param _collWithdrawal Amount of ETH collateral to withdraw
/// @param _collateralTo Address that will receive the withdrawn collateral ETH
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints.
/// @param _smartAccount Smart Account address
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
function withdrawCollateralLiquity(uint256 _collWithdrawal, address payable _collateralTo, address _upperHint, address _lowerHint, address payable _smartAccount) external {
_execute(_smartAccount, 0, abi.encodeWithSignature(
"withdrawCollateralLiquity(uint256,address,address,address,address)",
_collWithdrawal, _collateralTo, _upperHint, _lowerHint, msg.sender
));
}
/// @notice Issues amount of LUSD from the liquity's protocol to the provided address.
/// This increases the debt on the Credit Line, decreases CR (increases LTV).
/// @param _LUSDRequestedChange Amount of LUSD to further borrow.
/// @param _LUSDTo Address that will receive the generated LUSD. When 0 msg.sender is used.
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _smartAccount Smart Account address
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
/// @dev Hints should reflect calculated new debt instead of _LUSDRequestedChange
/// @dev This is facade to adjustCreditLineLiquity
function borrowLUSDLiquity(uint256 _LUSDRequestedChange, address _LUSDTo, address _upperHint, address _lowerHint, address payable _smartAccount) external {
_execute(_smartAccount, 0, abi.encodeWithSignature(
"adjustCreditLineLiquity(bool,uint256,address,uint256,address,address,address,address)",
true, _LUSDRequestedChange, _LUSDTo, 0, msg.sender, _upperHint, _lowerHint, msg.sender
// _isDebtIncrease, _LUSDRequestedChange, _LUSDAddress, _collWithdrawal, _collateralTo, _upperHint, _lowerHint, msg.sender
));
}
/// @notice Enables credit line owner to partially repay the debt from ANY ADDRESS by the given amount of LUSD.
/// Approval of LUSD transfers for given Smart Account is required.
/// Cannot repay below 2000 LUSD composite debt. Use closeCreditLineLiquity to repay whole debt instead.
/// @param _LUSDRequestedChange Amount of LUSD to be repaid in e18 (1 LUSD = 1e18). Repaying is subject to leaving 2000 LUSD min. debt in the Liquity protocol.
/// @param _LUSDFrom Address where the LUSD is being pulled from to repay debt.
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _smartAccount Smart Account address.
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
function repayLUSDLiquity(uint256 _LUSDRequestedChange, address _LUSDFrom, address _upperHint, address _lowerHint, address payable _smartAccount) external {
_execute(_smartAccount, 0, abi.encodeWithSignature(
"repayLUSDLiquity(uint256,address,address,address,address)",
_LUSDRequestedChange, _LUSDFrom, _upperHint, _lowerHint, msg.sender
));
}
/// @notice Enables credit line owner to partially repay the debt from ANY ADDRESS by the given amount of LUSD using EIP2612 Permit.
/// Approval of LUSD transfers for given Smart Account is ensured by the offchain signature.
/// Cannot repay below 2000 LUSD composite debt. Use closeCreditLineLiquity to repay whole debt instead.
/// @param _LUSDRequestedChange Amount of LUSD to be repaid in e18 (1 LUSD = 1e18). Repaying is subject to leaving 2000 LUSD min. debt in the Liquity protocol.
/// @param _LUSDFrom Address where the LUSD is being pulled from to repay debt.
/// @param _upperHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param _lowerHint For gas optimalisation when using Liquity protocol. Use calculateChangedLiquityParameters for gasless calculation of proper Hints for _LUSDRequestedChange.
/// @param v EIP2612 secp256k1 permit signature part
/// @param r EIP2612 secp256k1 permit signature part
/// @param s EIP2612 secp256k1 permit signature part
/// @param _smartAccount Smart Account address.
/// @dev Hints explained: https://github.com/liquity/dev#supplying-hints-to-trove-operations
function repayLUSDLiquityWithPermit(uint256 _LUSDRequestedChange, address _LUSDFrom, address _upperHint, address _lowerHint, uint8 v, bytes32 r, bytes32 s, address payable _smartAccount) external {
_execute(_smartAccount, 0, abi.encodeWithSignature(
"repayLUSDLiquityWithPermit(uint256,address,address,address,uint8,bytes32,bytes32,address)",
_LUSDRequestedChange, _LUSDFrom, _upperHint, _lowerHint, v, r, s, msg.sender
));
}
}
{
"compilationTarget": {
"contracts/Stargate.sol": "Stargate"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address","name":"_troveManager","type":"address"},{"internalType":"address","name":"_hintHelpers","type":"address"},{"internalType":"address","name":"_sortedTroves","type":"address"},{"internalType":"address","name":"_collSurplusPool","type":"address"},{"internalType":"address","name":"_proxyFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"smartAccountAddress","type":"address"}],"name":"SmartAccountCreated","type":"event"},{"inputs":[],"name":"CollSurplusPool","outputs":[{"internalType":"contract ICollSurplusPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HintHelpers","outputs":[{"internalType":"contract IHintHelpers","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ProxyFactory","outputs":[{"internalType":"contract DSProxyFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SortedTroves","outputs":[{"internalType":"contract ISortedTroves","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TroveManager","outputs":[{"internalType":"contract ITroveManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"addCollateralLiquity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"uint256","name":"_LUSDRequestedChange","type":"uint256"},{"internalType":"address","name":"_LUSDAddress","type":"address"},{"internalType":"uint256","name":"_collWithdrawal","type":"uint256"},{"internalType":"address payable","name":"_collateralTo","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"adjustCreditLineLiquity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LUSDRequestedChange","type":"uint256"},{"internalType":"address","name":"_LUSDFrom","type":"address"},{"internalType":"uint256","name":"_collWithdrawal","type":"uint256"},{"internalType":"address payable","name":"_collateralTo","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"adjustCreditLineLiquityWithPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LUSDRequestedChange","type":"uint256"},{"internalType":"address","name":"_LUSDTo","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"borrowLUSDLiquity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"uint256","name":"_LUSDRequestedChange","type":"uint256"},{"internalType":"bool","name":"_isCollateralIncrease","type":"bool"},{"internalType":"uint256","name":"_collateralChange","type":"uint256"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"calculateChangedLiquityParameters","outputs":[{"internalType":"uint256","name":"newCollateral","type":"uint256"},{"internalType":"uint256","name":"expectedDebtToRepay","type":"uint256"},{"internalType":"uint256","name":"liquidationReserve","type":"uint256"},{"internalType":"uint256","name":"expectedCompositeDebtLiquity","type":"uint256"},{"internalType":"uint256","name":"NICR","type":"uint256"},{"internalType":"address","name":"upperHint","type":"address"},{"internalType":"address","name":"lowerHint","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LUSDRequested","type":"uint256"},{"internalType":"uint256","name":"_collateralAmount","type":"uint256"}],"name":"calculateInitialLiquityParameters","outputs":[{"internalType":"uint256","name":"expectedDebtToRepay","type":"uint256"},{"internalType":"uint256","name":"liquidationReserve","type":"uint256"},{"internalType":"uint256","name":"expectedCompositeDebtLiquity","type":"uint256"},{"internalType":"uint256","name":"NICR","type":"uint256"},{"internalType":"address","name":"upperHint","type":"address"},{"internalType":"address","name":"lowerHint","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_smartAccount","type":"address"}],"name":"checkClaimableCollateralLiquity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_collateralTo","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"claimRemainingCollateralLiquity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_LUSDFrom","type":"address"},{"internalType":"address payable","name":"_collateralTo","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"closeCreditLineLiquity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_LUSDFrom","type":"address"},{"internalType":"address payable","name":"_collateralTo","type":"address"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"closeCreditLineLiquityWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"getCreditLineStatusLiquity","outputs":[{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"debtToRepay","type":"uint256"},{"internalType":"uint256","name":"debtComposite","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LUSDRequested","type":"uint256"},{"internalType":"address","name":"_LUSDTo","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"openCreditLineLiquity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"openSmartAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LUSDRequestedChange","type":"uint256"},{"internalType":"address","name":"_LUSDFrom","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"repayLUSDLiquity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LUSDRequestedChange","type":"uint256"},{"internalType":"address","name":"_LUSDFrom","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"repayLUSDLiquityWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"userAdoptionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collWithdrawal","type":"uint256"},{"internalType":"address payable","name":"_collateralTo","type":"address"},{"internalType":"address","name":"_upperHint","type":"address"},{"internalType":"address","name":"_lowerHint","type":"address"},{"internalType":"address payable","name":"_smartAccount","type":"address"}],"name":"withdrawCollateralLiquity","outputs":[],"stateMutability":"nonpayable","type":"function"}]