// File: contracts/VaultParameters.sol
/*
Copyright 2020 Unit Protocol: Artem Zakharov (az@unit.xyz).
*/
pragma solidity ^0.7.1;
/**
* @title Auth
* @author Unit Protocol: Ivan Zakharov (@34x4p08)
* @dev Manages USDP's system access
**/
contract Auth {
// address of the the contract with vault parameters
VaultParameters public vaultParameters;
constructor(address _parameters) public {
vaultParameters = VaultParameters(_parameters);
}
// ensures tx's sender is a manager
modifier onlyManager() {
require(vaultParameters.isManager(msg.sender), "Unit Protocol: AUTH_FAILED");
_;
}
// ensures tx's sender is able to modify the Vault
modifier hasVaultAccess() {
require(vaultParameters.canModifyVault(msg.sender), "Unit Protocol: AUTH_FAILED");
_;
}
// ensures tx's sender is the Vault
modifier onlyVault() {
require(msg.sender == vaultParameters.vault(), "Unit Protocol: AUTH_FAILED");
_;
}
}
/**
* @title VaultParameters
* @author Unit Protocol: Ivan Zakharov (@34x4p08)
**/
contract VaultParameters is Auth {
// map token to stability fee percentage; 3 decimals
mapping(address => uint) public stabilityFee;
// map token to liquidation fee percentage, 0 decimals
mapping(address => uint) public liquidationFee;
// map token to USDP mint limit
mapping(address => uint) public tokenDebtLimit;
// permissions to modify the Vault
mapping(address => bool) public canModifyVault;
// managers
mapping(address => bool) public isManager;
// enabled oracle types
mapping(uint => mapping (address => bool)) public isOracleTypeEnabled;
// address of the Vault
address payable public vault;
// The foundation address
address public foundation;
/**
* The address for an Ethereum contract is deterministically computed from the address of its creator (sender)
* and how many transactions the creator has sent (nonce). The sender and nonce are RLP encoded and then
* hashed with Keccak-256.
* Therefore, the Vault address can be pre-computed and passed as an argument before deployment.
**/
constructor(address payable _vault, address _foundation) public Auth(address(this)) {
require(_vault != address(0), "Unit Protocol: ZERO_ADDRESS");
require(_foundation != address(0), "Unit Protocol: ZERO_ADDRESS");
isManager[msg.sender] = true;
vault = _vault;
foundation = _foundation;
}
/**
* @notice Only manager is able to call this function
* @dev Grants and revokes manager's status of any address
* @param who The target address
* @param permit The permission flag
**/
function setManager(address who, bool permit) external onlyManager {
isManager[who] = permit;
}
/**
* @notice Only manager is able to call this function
* @dev Sets the foundation address
* @param newFoundation The new foundation address
**/
function setFoundation(address newFoundation) external onlyManager {
require(newFoundation != address(0), "Unit Protocol: ZERO_ADDRESS");
foundation = newFoundation;
}
/**
* @notice Only manager is able to call this function
* @dev Sets ability to use token as the main collateral
* @param asset The address of the main collateral token
* @param stabilityFeeValue The percentage of the year stability fee (3 decimals)
* @param liquidationFeeValue The liquidation fee percentage (0 decimals)
* @param usdpLimit The USDP token issue limit
* @param oracles The enables oracle types
**/
function setCollateral(
address asset,
uint stabilityFeeValue,
uint liquidationFeeValue,
uint usdpLimit,
uint[] calldata oracles
) external onlyManager {
setStabilityFee(asset, stabilityFeeValue);
setLiquidationFee(asset, liquidationFeeValue);
setTokenDebtLimit(asset, usdpLimit);
for (uint i=0; i < oracles.length; i++) {
setOracleType(oracles[i], asset, true);
}
}
/**
* @notice Only manager is able to call this function
* @dev Sets a permission for an address to modify the Vault
* @param who The target address
* @param permit The permission flag
**/
function setVaultAccess(address who, bool permit) external onlyManager {
canModifyVault[who] = permit;
}
/**
* @notice Only manager is able to call this function
* @dev Sets the percentage of the year stability fee for a particular collateral
* @param asset The address of the main collateral token
* @param newValue The stability fee percentage (3 decimals)
**/
function setStabilityFee(address asset, uint newValue) public onlyManager {
stabilityFee[asset] = newValue;
}
/**
* @notice Only manager is able to call this function
* @dev Sets the percentage of the liquidation fee for a particular collateral
* @param asset The address of the main collateral token
* @param newValue The liquidation fee percentage (0 decimals)
**/
function setLiquidationFee(address asset, uint newValue) public onlyManager {
require(newValue <= 100, "Unit Protocol: VALUE_OUT_OF_RANGE");
liquidationFee[asset] = newValue;
}
/**
* @notice Only manager is able to call this function
* @dev Enables/disables oracle types
* @param _type The type of the oracle
* @param asset The address of the main collateral token
* @param enabled The control flag
**/
function setOracleType(uint _type, address asset, bool enabled) public onlyManager {
isOracleTypeEnabled[_type][asset] = enabled;
}
/**
* @notice Only manager is able to call this function
* @dev Sets USDP limit for a specific collateral
* @param asset The address of the main collateral token
* @param limit The limit number
**/
function setTokenDebtLimit(address asset, uint limit) public onlyManager {
tokenDebtLimit[asset] = limit;
}
}
// File: contracts/helpers/SafeMath.sol
/*
Copyright 2020 Unit Protocol: Artem Zakharov (az@unit.xyz).
*/
pragma solidity ^0.7.1;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
// File: contracts/USDP.sol
/*
Copyright 2020 Unit Protocol: Artem Zakharov (az@unit.xyz).
*/
pragma solidity ^0.7.1;
/**
* @title USDP token implementation
* @author Unit Protocol: Ivan Zakharov (@34x4p08)
* @dev ERC20 token
**/
contract USDP is Auth {
using SafeMath for uint;
// name of the token
string public constant name = "USDP Stablecoin";
// symbol of the token
string public constant symbol = "USDP";
// version of the token
string public constant version = "1";
// number of decimals the token uses
uint8 public constant decimals = 18;
// total token supply
uint public totalSupply;
// balance information map
mapping(address => uint) public balanceOf;
// token allowance mapping
mapping(address => mapping(address => uint)) public allowance;
/**
* @dev Trigger on any successful call to approve(address spender, uint amount)
**/
event Approval(address indexed owner, address indexed spender, uint value);
/**
* @dev Trigger when tokens are transferred, including zero value transfers
**/
event Transfer(address indexed from, address indexed to, uint value);
/**
* @param _parameters The address of system parameters contract
**/
constructor(address _parameters) public Auth(_parameters) {}
/**
* @notice Only Vault can mint USDP
* @dev Mints 'amount' of tokens to address 'to', and MUST fire the
* Transfer event
* @param to The address of the recipient
* @param amount The amount of token to be minted
**/
function mint(address to, uint amount) external onlyVault {
require(to != address(0), "Unit Protocol: ZERO_ADDRESS");
balanceOf[to] = balanceOf[to].add(amount);
totalSupply = totalSupply.add(amount);
emit Transfer(address(0), to, amount);
}
/**
* @notice Only manager can burn tokens from manager's balance
* @dev Burns 'amount' of tokens, and MUST fire the Transfer event
* @param amount The amount of token to be burned
**/
function burn(uint amount) external onlyManager {
_burn(msg.sender, amount);
}
/**
* @notice Only Vault can burn tokens from any balance
* @dev Burns 'amount' of tokens from 'from' address, and MUST fire the Transfer event
* @param from The address of the balance owner
* @param amount The amount of token to be burned
**/
function burn(address from, uint amount) external onlyVault {
_burn(from, amount);
}
/**
* @dev Transfers 'amount' of tokens to address 'to', and MUST fire the Transfer event. The
* function SHOULD throw if the _from account balance does not have enough tokens to spend.
* @param to The address of the recipient
* @param amount The amount of token to be transferred
**/
function transfer(address to, uint amount) external returns (bool) {
return transferFrom(msg.sender, to, amount);
}
/**
* @dev Transfers 'amount' of tokens from address 'from' to address 'to', and MUST fire the
* Transfer event
* @param from The address of the sender
* @param to The address of the recipient
* @param amount The amount of token to be transferred
**/
function transferFrom(address from, address to, uint amount) public returns (bool) {
require(to != address(0), "Unit Protocol: ZERO_ADDRESS");
require(balanceOf[from] >= amount, "Unit Protocol: INSUFFICIENT_BALANCE");
if (from != msg.sender) {
require(allowance[from][msg.sender] >= amount, "Unit Protocol: INSUFFICIENT_ALLOWANCE");
_approve(from, msg.sender, allowance[from][msg.sender].sub(amount));
}
balanceOf[from] = balanceOf[from].sub(amount);
balanceOf[to] = balanceOf[to].add(amount);
emit Transfer(from, to, amount);
return true;
}
/**
* @dev Allows 'spender' to withdraw from your account multiple times, up to the 'amount' amount. If
* this function is called again it overwrites the current allowance with 'amount'.
* @param spender The address of the account able to transfer the tokens
* @param amount The amount of tokens to be approved for transfer
**/
function approve(address spender, uint amount) external returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint subtractedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue));
return true;
}
function _approve(address owner, address spender, uint amount) internal virtual {
require(owner != address(0), "Unit Protocol: approve from the zero address");
require(spender != address(0), "Unit Protocol: approve to the zero address");
allowance[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _burn(address from, uint amount) internal virtual {
balanceOf[from] = balanceOf[from].sub(amount);
totalSupply = totalSupply.sub(amount);
emit Transfer(from, address(0), amount);
}
}
{
"compilationTarget": {
"USDP.sol": "USDP"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_parameters","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultParameters","outputs":[{"internalType":"contract VaultParameters","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]