/*
___ _ ___ _
| .\ ___ _ _ <_> ___ | __><_>._ _ ___ ._ _ ___ ___
| _// ._>| '_>| ||___|| _> | || ' |<_> || ' |/ | '/ ._>
|_| \___.|_| |_| |_| |_||_|_|<___||_|_|\_|_.\___.
* PeriFinance: PeriFinanceToEthereum.sol
*
* Latest source (may be newer): https://github.com/perifinance/peri-finance/blob/master/contracts/PeriFinanceToEthereum.sol
* Docs: Will be added in the future.
* https://docs.peri.finance/contracts/source/contracts/PeriFinanceToEthereum
*
* Contract Dependencies:
* - BasePeriFinance
* - ExternStateToken
* - IAddressResolver
* - IERC20
* - IPeriFinance
* - MixinResolver
* - Owned
* - PeriFinance
* - Proxyable
* - State
* Libraries:
* - SafeDecimalMath
* - SafeMath
* - VestingEntries
*
* MIT License
* ===========
*
* Copyright (c) 2024 PeriFinance
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.5.16;
// https://docs.peri.finance/contracts/source/interfaces/ierc20
interface IERC20 {
// ERC20 Optional Views
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
// Views
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
// Mutative functions
function transfer(address to, uint value) external returns (bool);
function approve(address spender, uint value) external returns (bool);
function transferFrom(
address from,
address to,
uint value
) external returns (bool);
// Events
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
// https://docs.peri.finance/contracts/source/contracts/owned
contract Owned {
address public owner;
address public nominatedOwner;
constructor(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}
// Inheritance
// Internal references
// https://docs.peri.finance/contracts/source/contracts/proxy
contract Proxy is Owned {
Proxyable public target;
constructor(address _owner) public Owned(_owner) {}
function setTarget(Proxyable _target) external onlyOwner {
target = _target;
emit TargetUpdated(_target);
}
function _emit(
bytes calldata callData,
uint numTopics,
bytes32 topic1,
bytes32 topic2,
bytes32 topic3,
bytes32 topic4
) external onlyTarget {
uint size = callData.length;
bytes memory _callData = callData;
assembly {
/* The first 32 bytes of callData contain its length (as specified by the abi).
* Length is assumed to be a uint256 and therefore maximum of 32 bytes
* in length. It is also leftpadded to be a multiple of 32 bytes.
* This means moving call_data across 32 bytes guarantees we correctly access
* the data itself. */
switch numTopics
case 0 {
log0(add(_callData, 32), size)
}
case 1 {
log1(add(_callData, 32), size, topic1)
}
case 2 {
log2(add(_callData, 32), size, topic1, topic2)
}
case 3 {
log3(add(_callData, 32), size, topic1, topic2, topic3)
}
case 4 {
log4(add(_callData, 32), size, topic1, topic2, topic3, topic4)
}
}
}
// solhint-disable no-complex-fallback
function() external payable {
// Mutable call setting Proxyable.messageSender as this is using call not delegatecall
target.setMessageSender(msg.sender);
assembly {
let free_ptr := mload(0x40)
calldatacopy(free_ptr, 0, calldatasize)
/* We must explicitly forward ether to the underlying contract as well. */
let result := call(gas, sload(target_slot), callvalue, free_ptr, calldatasize, 0, 0)
returndatacopy(free_ptr, 0, returndatasize)
if iszero(result) {
revert(free_ptr, returndatasize)
}
return(free_ptr, returndatasize)
}
}
modifier onlyTarget {
require(Proxyable(msg.sender) == target, "Must be proxy target");
_;
}
event TargetUpdated(Proxyable newTarget);
}
// Inheritance
// Internal references
// https://docs.peri.finance/contracts/source/contracts/proxyable
contract Proxyable is Owned {
// This contract should be treated like an abstract contract
/* The proxy this contract exists behind. */
Proxy public proxy;
Proxy public integrationProxy;
/* The caller of the proxy, passed through to this contract.
* Note that every function using this member must apply the onlyProxy or
* optionalProxy modifiers, otherwise their invocations can use stale values. */
address public messageSender;
constructor(address payable _proxy) internal {
// This contract is abstract, and thus cannot be instantiated directly
require(owner != address(0), "Owner must be set");
proxy = Proxy(_proxy);
emit ProxyUpdated(_proxy);
}
function setProxy(address payable _proxy) external onlyOwner {
proxy = Proxy(_proxy);
emit ProxyUpdated(_proxy);
}
function setIntegrationProxy(address payable _integrationProxy) external onlyOwner {
integrationProxy = Proxy(_integrationProxy);
}
function setMessageSender(address sender) external onlyProxy {
messageSender = sender;
}
modifier onlyProxy {
_onlyProxy();
_;
}
function _onlyProxy() private view {
require(Proxy(msg.sender) == proxy || Proxy(msg.sender) == integrationProxy, "Only the proxy can call");
}
modifier optionalProxy {
_optionalProxy();
_;
}
function _optionalProxy() private {
if (Proxy(msg.sender) != proxy && Proxy(msg.sender) != integrationProxy && messageSender != msg.sender) {
messageSender = msg.sender;
}
}
modifier optionalProxy_onlyOwner {
_optionalProxy_onlyOwner();
_;
}
// solhint-disable-next-line func-name-mixedcase
function _optionalProxy_onlyOwner() private {
if (Proxy(msg.sender) != proxy && Proxy(msg.sender) != integrationProxy && messageSender != msg.sender) {
messageSender = msg.sender;
}
require(messageSender == owner, "Owner only function");
}
event ProxyUpdated(address proxyAddress);
}
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}
// Libraries
// https://docs.peri.finance/contracts/source/libraries/safedecimalmath
library SafeDecimalMath {
using SafeMath for uint;
/* Number of decimal places in the representations. */
uint8 public constant decimals = 18;
uint8 public constant highPrecisionDecimals = 27;
/* The number representing 1.0. */
uint public constant UNIT = 10**uint(decimals);
/* The number representing 1.0 for higher fidelity numbers. */
uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals);
uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals);
/**
* @return Provides an interface to UNIT.
*/
function unit() external pure returns (uint) {
return UNIT;
}
/**
* @return Provides an interface to PRECISE_UNIT.
*/
function preciseUnit() external pure returns (uint) {
return PRECISE_UNIT;
}
/**
* @return The result of multiplying x and y, interpreting the operands as fixed-point
* decimals.
*
* @dev A unit factor is divided out after the product of x and y is evaluated,
* so that product must be less than 2**256. As this is an integer division,
* the internal division always rounds down. This helps save on gas. Rounding
* is more expensive on gas.
*/
function multiplyDecimal(uint x, uint y) internal pure returns (uint) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
return x.mul(y) / UNIT;
}
/**
* @return The result of safely multiplying x and y, interpreting the operands
* as fixed-point decimals of the specified precision unit.
*
* @dev The operands should be in the form of a the specified unit factor which will be
* divided out after the product of x and y is evaluated, so that product must be
* less than 2**256.
*
* Unlike multiplyDecimal, this function rounds the result to the nearest increment.
* Rounding is useful when you need to retain fidelity for small decimal numbers
* (eg. small fractions or percentages).
*/
function _multiplyDecimalRound(
uint x,
uint y,
uint precisionUnit
) private pure returns (uint) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
uint quotientTimesTen = x.mul(y) / (precisionUnit / 10);
if (quotientTimesTen % 10 >= 5) {
quotientTimesTen += 10;
}
return quotientTimesTen / 10;
}
/**
* @return The result of safely multiplying x and y, interpreting the operands
* as fixed-point decimals of a precise unit.
*
* @dev The operands should be in the precise unit factor which will be
* divided out after the product of x and y is evaluated, so that product must be
* less than 2**256.
*
* Unlike multiplyDecimal, this function rounds the result to the nearest increment.
* Rounding is useful when you need to retain fidelity for small decimal numbers
* (eg. small fractions or percentages).
*/
function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
return _multiplyDecimalRound(x, y, PRECISE_UNIT);
}
/**
* @return The result of safely multiplying x and y, interpreting the operands
* as fixed-point decimals of a standard unit.
*
* @dev The operands should be in the standard unit factor which will be
* divided out after the product of x and y is evaluated, so that product must be
* less than 2**256.
*
* Unlike multiplyDecimal, this function rounds the result to the nearest increment.
* Rounding is useful when you need to retain fidelity for small decimal numbers
* (eg. small fractions or percentages).
*/
function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) {
return _multiplyDecimalRound(x, y, UNIT);
}
/**
* @return The result of safely dividing x and y. The return value is a high
* precision decimal.
*
* @dev y is divided after the product of x and the standard precision unit
* is evaluated, so the product of x and UNIT must be less than 2**256. As
* this is an integer division, the result is always rounded down.
* This helps save on gas. Rounding is more expensive on gas.
*/
function divideDecimal(uint x, uint y) internal pure returns (uint) {
/* Reintroduce the UNIT factor that will be divided out by y. */
return x.mul(UNIT).div(y);
}
/**
* @return The result of safely dividing x and y. The return value is as a rounded
* decimal in the precision unit specified in the parameter.
*
* @dev y is divided after the product of x and the specified precision unit
* is evaluated, so the product of x and the specified precision unit must
* be less than 2**256. The result is rounded to the nearest increment.
*/
function _divideDecimalRound(
uint x,
uint y,
uint precisionUnit
) private pure returns (uint) {
uint resultTimesTen = x.mul(precisionUnit * 10).div(y);
if (resultTimesTen % 10 >= 5) {
resultTimesTen += 10;
}
return resultTimesTen / 10;
}
/**
* @return The result of safely dividing x and y. The return value is as a rounded
* standard precision decimal.
*
* @dev y is divided after the product of x and the standard precision unit
* is evaluated, so the product of x and the standard precision unit must
* be less than 2**256. The result is rounded to the nearest increment.
*/
function divideDecimalRound(uint x, uint y) internal pure returns (uint) {
return _divideDecimalRound(x, y, UNIT);
}
/**
* @return The result of safely dividing x and y. The return value is as a rounded
* high precision decimal.
*
* @dev y is divided after the product of x and the high precision unit
* is evaluated, so the product of x and the high precision unit must
* be less than 2**256. The result is rounded to the nearest increment.
*/
function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
return _divideDecimalRound(x, y, PRECISE_UNIT);
}
/**
* @dev Convert a standard decimal representation to a high precision one.
*/
function decimalToPreciseDecimal(uint i) internal pure returns (uint) {
return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
}
/**
* @dev Convert a high precision decimal to a standard decimal representation.
*/
function preciseDecimalToDecimal(uint i) internal pure returns (uint) {
uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10);
if (quotientTimesTen % 10 >= 5) {
quotientTimesTen += 10;
}
return quotientTimesTen / 10;
}
/**
* @dev Round down the value with given number
*/
function roundDownDecimal(uint x, uint d) internal pure returns (uint) {
return x.div(10**d).mul(10**d);
}
/**
* @dev Round up the value with given number
*/
function roundUpDecimal(uint x, uint d) internal pure returns (uint) {
uint _decimal = 10**d;
if (x % _decimal > 0) {
x = x.add(10**d);
}
return x.div(_decimal).mul(_decimal);
}
}
// Inheritance
// https://docs.peri.finance/contracts/source/contracts/state
contract State is Owned {
// the address of the contract that can modify variables
// this can only be changed by the owner of this contract
address public associatedContract;
constructor(address _associatedContract) internal {
// This contract is abstract, and thus cannot be instantiated directly
require(owner != address(0), "Owner must be set");
associatedContract = _associatedContract;
emit AssociatedContractUpdated(_associatedContract);
}
/* ========== SETTERS ========== */
// Change the associated contract to a new address
function setAssociatedContract(address _associatedContract) external onlyOwner {
associatedContract = _associatedContract;
emit AssociatedContractUpdated(_associatedContract);
}
/* ========== MODIFIERS ========== */
modifier onlyAssociatedContract {
require(msg.sender == associatedContract, "Only the associated contract can perform this action");
_;
}
/* ========== EVENTS ========== */
event AssociatedContractUpdated(address associatedContract);
}
// Inheritance
// https://docs.peri.finance/contracts/source/contracts/tokenstate
contract TokenState is Owned, State {
/* ERC20 fields. */
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
constructor(address _owner, address _associatedContract) public Owned(_owner) State(_associatedContract) {}
/* ========== SETTERS ========== */
/**
* @notice Set ERC20 allowance.
* @dev Only the associated contract may call this.
* @param tokenOwner The authorising party.
* @param spender The authorised party.
* @param value The total value the authorised party may spend on the
* authorising party's behalf.
*/
function setAllowance(
address tokenOwner,
address spender,
uint value
) external onlyAssociatedContract {
allowance[tokenOwner][spender] = value;
}
/**
* @notice Set the balance in a given account
* @dev Only the associated contract may call this.
* @param account The account whose value to set.
* @param value The new balance of the given account.
*/
function setBalanceOf(address account, uint value) external onlyAssociatedContract {
balanceOf[account] = value;
}
}
// Inheritance
// Libraries
// Internal references
// https://docs.peri.finance/contracts/source/contracts/externstatetoken
contract ExternStateToken is Owned, Proxyable {
using SafeMath for uint;
using SafeDecimalMath for uint;
/* ========== STATE VARIABLES ========== */
/* Stores balances and allowances. */
TokenState public tokenState;
/* Other ERC20 fields. */
string public name;
string public symbol;
uint public totalSupply;
uint8 public decimals;
mapping(address => bool) private _blockedAddress;
constructor(
address payable _proxy,
TokenState _tokenState,
string memory _name,
string memory _symbol,
uint _totalSupply,
uint8 _decimals,
address _owner
) public Owned(_owner) Proxyable(_proxy) {
tokenState = _tokenState;
name = _name;
symbol = _symbol;
totalSupply = _totalSupply;
decimals = _decimals;
}
/* ========== VIEWS ========== */
/**
* @notice Returns the ERC20 allowance of one party to spend on behalf of another.
* @param owner The party authorising spending of their funds.
* @param spender The party spending tokenOwner's funds.
*/
function allowance(address owner, address spender) public view returns (uint) {
return tokenState.allowance(owner, spender);
}
/**
* @notice Returns the ERC20 token balance of a given account.
*/
function balanceOf(address account) external view returns (uint) {
return tokenState.balanceOf(account);
}
/* ========== MUTATIVE FUNCTIONS ========== */
function setBlockedAddress(address _target, bool _set) external onlyOwner {
_blockedAddress[_target] = _set;
}
/**
* @notice Set the address of the TokenState contract.
* @dev This can be used to "pause" transfer functionality, by pointing the tokenState at 0x000..
* as balances would be unreachable.
*/
function setTokenState(TokenState _tokenState) external optionalProxy_onlyOwner {
tokenState = _tokenState;
emitTokenStateUpdated(address(_tokenState));
}
function _internalTransfer(
address from,
address to,
uint value
) internal returns (bool) {
/* Disallow transfers to irretrievable-addresses. */
require(to != address(0) && to != address(this) && to != address(proxy), "Cannot transfer to this address");
require(_blockedAddress[from] == false, "Blocked address");
// Insufficient balance will be handled by the safe subtraction.
tokenState.setBalanceOf(from, tokenState.balanceOf(from).sub(value));
tokenState.setBalanceOf(to, tokenState.balanceOf(to).add(value));
// Emit a standard ERC20 transfer event
emitTransfer(from, to, value);
return true;
}
/**
* @dev Perform an ERC20 token transfer. Designed to be called by transfer functions possessing
* the onlyProxy or optionalProxy modifiers.
*/
function _transferByProxy(
address from,
address to,
uint value
) internal returns (bool) {
return _internalTransfer(from, to, value);
}
/*
* @dev Perform an ERC20 token transferFrom. Designed to be called by transferFrom functions
* possessing the optionalProxy or optionalProxy modifiers.
*/
function _transferFromByProxy(
address sender,
address from,
address to,
uint value
) internal returns (bool) {
/* Insufficient allowance will be handled by the safe subtraction. */
tokenState.setAllowance(from, sender, tokenState.allowance(from, sender).sub(value));
return _internalTransfer(from, to, value);
}
function _mintByProxy(address _minter, uint _value) internal returns (bool) {
tokenState.setBalanceOf(_minter, tokenState.balanceOf(_minter).add(_value));
emitTransfer(address(0), _minter, _value);
return true;
}
function _burnByProxy(address _burner, uint _value) internal returns (bool) {
tokenState.setBalanceOf(_burner, tokenState.balanceOf(_burner).sub(_value));
emitTransfer(_burner, address(0), _value);
return true;
}
/**
* @notice Approves spender to transfer on the message sender's behalf.
*/
function approve(address spender, uint value) public optionalProxy returns (bool) {
address sender = messageSender;
tokenState.setAllowance(sender, spender, value);
emitApproval(sender, spender, value);
return true;
}
/* ========== EVENTS ========== */
function addressToBytes32(address input) internal pure returns (bytes32) {
return bytes32(uint256(uint160(input)));
}
event Transfer(address indexed from, address indexed to, uint value);
bytes32 internal constant TRANSFER_SIG = keccak256("Transfer(address,address,uint256)");
function emitTransfer(
address from,
address to,
uint value
) internal {
proxy._emit(abi.encode(value), 3, TRANSFER_SIG, addressToBytes32(from), addressToBytes32(to), 0);
}
event Approval(address indexed owner, address indexed spender, uint value);
bytes32 internal constant APPROVAL_SIG = keccak256("Approval(address,address,uint256)");
function emitApproval(
address owner,
address spender,
uint value
) internal {
proxy._emit(abi.encode(value), 3, APPROVAL_SIG, addressToBytes32(owner), addressToBytes32(spender), 0);
}
event TokenStateUpdated(address newTokenState);
bytes32 internal constant TOKENSTATEUPDATED_SIG = keccak256("TokenStateUpdated(address)");
function emitTokenStateUpdated(address newTokenState) internal {
proxy._emit(abi.encode(newTokenState), 1, TOKENSTATEUPDATED_SIG, 0, 0, 0);
}
}
// https://docs.peri.finance/contracts/source/interfaces/iaddressresolver
interface IAddressResolver {
function getAddress(bytes32 name) external view returns (address);
function getPynth(bytes32 key) external view returns (address);
function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address);
}
// https://docs.peri.finance/contracts/source/interfaces/ipynth
interface IPynth {
// Views
function currencyKey() external view returns (bytes32);
function transferablePynths(address account) external view returns (uint);
// Mutative functions
function transferAndSettle(address to, uint value) external returns (bool);
function transferFromAndSettle(
address from,
address to,
uint value
) external returns (bool);
// Restricted: used internally to PeriFinance
function burn(address account, uint amount) external;
function issue(address account, uint amount) external;
}
// https://docs.peri.finance/contracts/source/interfaces/iissuer
interface IIssuer {
// Views
function anyPynthOrPERIRateIsInvalid() external view returns (bool anyRateInvalid);
function availableCurrencyKeys() external view returns (bytes32[] memory);
function availablePynthCount() external view returns (uint);
function availablePynths(uint index) external view returns (IPynth);
function canBurnPynths(address account) external view returns (bool);
function collateral(address account) external view returns (uint);
function collateralisationRatio(address issuer) external view returns (uint);
function collateralisationRatioAndAnyRatesInvalid(address _issuer)
external
view
returns (uint cratio, bool anyRateIsInvalid);
function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint debtBalance);
function lastIssueEvent(address account) external view returns (uint);
function maxIssuablePynths(address issuer)
external
view
returns (
uint,
uint,
uint
);
// function externalTokenQuota(
// address _account,
// uint _addtionalpUSD,
// uint _addtionalExToken,
// bool _isIssue
// ) external view returns (uint);
// function debtsCollateral(address _account, bool _rateCheck) external
// view
// returns (
// uint,
// uint,
// uint
// );
function getRatios(address _account, bool _checkRate)
external
view
returns (
uint,
uint,
uint,
uint,
uint,
uint
);
function getTargetRatio(address account) external view returns (uint);
// function getTRatioCRatio(address _account)
// external
// view
// returns (
// uint,
// uint,
// uint,
// uint
// );
function remainingIssuablePynths(address issuer)
external
view
returns (
uint maxIssuable,
uint alreadyIssued,
uint totalSystemDebt
);
function pynths(bytes32 currencyKey) external view returns (IPynth);
function getPynths(bytes32[] calldata currencyKeys) external view returns (IPynth[] memory);
function pynthsByAddress(address pynthAddress) external view returns (bytes32);
function totalIssuedPynths(bytes32 currencyKey, bool excludeEtherCollateral) external view returns (uint, bool);
function transferablePeriFinanceAndAnyRateIsInvalid(address account, uint balance)
external
view
returns (uint transferable, bool anyRateIsInvalid);
function amountsToFitClaimable(address _account) external view returns (uint burnAmount, uint exTokenAmountToUnstake);
// Restricted: used internally to PeriFinance
function issuePynths(
address _issuer,
bytes32 _currencyKey,
uint _issueAmount
) external;
function issueMaxPynths(address _issuer) external;
function issuePynthsToMaxQuota(address _issuer, bytes32 _currencyKey) external;
function burnPynths(
address _from,
bytes32 _currencyKey,
uint _burnAmount
) external;
function fitToClaimable(address _from) external;
function exit(address _from) external;
function liquidateDelinquentAccount(
address account,
uint pusdAmount,
address liquidator
) external returns (uint totalRedeemed, uint amountToLiquidate);
}
// Inheritance
// Internal references
// https://docs.peri.finance/contracts/source/contracts/addressresolver
contract AddressResolver is Owned, IAddressResolver {
mapping(bytes32 => address) public repository;
constructor(address _owner) public Owned(_owner) {}
/* ========== RESTRICTED FUNCTIONS ========== */
function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner {
require(names.length == destinations.length, "Input lengths must match");
for (uint i = 0; i < names.length; i++) {
bytes32 name = names[i];
address destination = destinations[i];
repository[name] = destination;
emit AddressImported(name, destination);
}
}
/* ========= PUBLIC FUNCTIONS ========== */
function rebuildCaches(MixinResolver[] calldata destinations) external {
for (uint i = 0; i < destinations.length; i++) {
destinations[i].rebuildCache();
}
}
/* ========== VIEWS ========== */
function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) {
for (uint i = 0; i < names.length; i++) {
if (repository[names[i]] != destinations[i]) {
return false;
}
}
return true;
}
function getAddress(bytes32 name) external view returns (address) {
return repository[name];
}
function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address) {
address _foundAddress = repository[name];
require(_foundAddress != address(0), reason);
return _foundAddress;
}
function getPynth(bytes32 key) external view returns (address) {
IIssuer issuer = IIssuer(repository["Issuer"]);
require(address(issuer) != address(0), "Cannot find Issuer address");
return address(issuer.pynths(key));
}
/* ========== EVENTS ========== */
event AddressImported(bytes32 name, address destination);
}
// solhint-disable payable-fallback
// https://docs.peri.finance/contracts/source/contracts/readproxy
contract ReadProxy is Owned {
address public target;
constructor(address _owner) public Owned(_owner) {}
function setTarget(address _target) external onlyOwner {
target = _target;
emit TargetUpdated(target);
}
function() external {
// The basics of a proxy read call
// Note that msg.sender in the underlying will always be the address of this contract.
assembly {
calldatacopy(0, 0, calldatasize)
// Use of staticcall - this will revert if the underlying function mutates state
let result := staticcall(gas, sload(target_slot), 0, calldatasize, 0, 0)
returndatacopy(0, 0, returndatasize)
if iszero(result) {
revert(0, returndatasize)
}
return(0, returndatasize)
}
}
event TargetUpdated(address newTarget);
}
// Inheritance
// Internal references
// https://docs.peri.finance/contracts/source/contracts/mixinresolver
contract MixinResolver {
AddressResolver public resolver;
mapping(bytes32 => address) private addressCache;
constructor(address _resolver) internal {
resolver = AddressResolver(_resolver);
}
/* ========== INTERNAL FUNCTIONS ========== */
function combineArrays(bytes32[] memory first, bytes32[] memory second)
internal
pure
returns (bytes32[] memory combination)
{
combination = new bytes32[](first.length + second.length);
for (uint i = 0; i < first.length; i++) {
combination[i] = first[i];
}
for (uint j = 0; j < second.length; j++) {
combination[first.length + j] = second[j];
}
}
/* ========== PUBLIC FUNCTIONS ========== */
// Note: this function is public not external in order for it to be overridden and invoked via super in subclasses
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {}
function rebuildCache() public {
bytes32[] memory requiredAddresses = resolverAddressesRequired();
// The resolver must call this function whenver it updates its state
for (uint i = 0; i < requiredAddresses.length; i++) {
bytes32 name = requiredAddresses[i];
// Note: can only be invoked once the resolver has all the targets needed added
address destination =
resolver.requireAndGetAddress(name, string(abi.encodePacked("Resolver missing target: ", name)));
addressCache[name] = destination;
emit CacheUpdated(name, destination);
}
}
/* ========== VIEWS ========== */
function isResolverCached() external view returns (bool) {
bytes32[] memory requiredAddresses = resolverAddressesRequired();
for (uint i = 0; i < requiredAddresses.length; i++) {
bytes32 name = requiredAddresses[i];
// false if our cache is invalid or if the resolver doesn't have the required address
if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) {
return false;
}
}
return true;
}
/* ========== INTERNAL FUNCTIONS ========== */
function requireAndGetAddress(bytes32 name) internal view returns (address) {
address _foundAddress = addressCache[name];
require(_foundAddress != address(0), string(abi.encodePacked("Missing address: ", name)));
return _foundAddress;
}
/* ========== EVENTS ========== */
event CacheUpdated(bytes32 name, address destination);
}
interface IVirtualPynth {
// Views
function balanceOfUnderlying(address account) external view returns (uint);
function rate() external view returns (uint);
function readyToSettle() external view returns (bool);
function secsLeftInWaitingPeriod() external view returns (uint);
function settled() external view returns (bool);
function pynth() external view returns (IPynth);
// Mutative functions
function settle(address account) external;
}
// https://docs.peri.finance/contracts/source/interfaces/iperiFinance
interface IPeriFinance {
// Views
function getRequiredAddress(bytes32 contractName) external view returns (address);
// function anyPynthOrPERIRateIsInvalid() external view returns (bool anyRateInvalid);
// function availableCurrencyKeys() external view returns (bytes32[] memory);
// function availablePynthCount() external view returns (uint);
// function availablePynths(uint index) external view returns (IPynth);
function collateral(address account) external view returns (uint);
function collateralisationRatio(address issuer) external view returns (uint);
function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint);
function isWaitingPeriod(bytes32 currencyKey) external view returns (bool);
function maxIssuablePynths(address issuer) external view returns (uint maxIssuable);
function remainingIssuablePynths(address issuer)
external
view
returns (
uint maxIssuable,
uint alreadyIssued,
uint totalSystemDebt
);
// function pynths(bytes32 currencyKey) external view returns (IPynth);
// function pynthsByAddress(address pynthAddress) external view returns (bytes32);
function totalIssuedPynths(bytes32 currencyKey) external view returns (uint);
function totalIssuedPynthsExcludeEtherCollateral(bytes32 currencyKey) external view returns (uint);
function transferablePeriFinance(address account) external view returns (uint transferable);
function amountsToFitClaimable(address account) external view returns (uint burnAmount, uint exTokenAmountToUnstake);
// Mutative Functions
function issuePynths(bytes32 _currencyKey, uint _issueAmount) external;
function issueMaxPynths() external;
function issuePynthsToMaxQuota(bytes32 _currencyKey) external;
function burnPynths(bytes32 _currencyKey, uint _burnAmount) external;
// function fitToClaimable() external payable;
function exit() external;
function exchange(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
) external returns (uint amountReceived);
function exchangeOnBehalf(
address exchangeForAddress,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
) external returns (uint amountReceived);
function exchangeWithTracking(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address originator,
bytes32 trackingCode
) external returns (uint amountReceived);
function exchangeOnBehalfWithTracking(
address exchangeForAddress,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address originator,
bytes32 trackingCode
) external returns (uint amountReceived);
function exchangeWithVirtual(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
bytes32 trackingCode
) external returns (uint amountReceived, IVirtualPynth vPynth);
function mint(address _user, uint _amount) external returns (bool);
function inflationalMint() external returns (bool);
function settle(bytes32 currencyKey)
external
returns (
uint reclaimed,
uint refunded,
uint numEntries
);
// Liquidations
function liquidateDelinquentAccount(address account, uint pusdAmount) external returns (bool);
// Restricted Functions
function mintSecondary(address account, uint amount) external;
function mintSecondaryRewards(uint amount) external;
function burnSecondary(address account, uint amount) external;
}
// https://docs.peri.finance/contracts/source/interfaces/iperiFinancestate
interface IPeriFinanceState {
// Views
function debtLedger(uint index) external view returns (uint);
function issuanceData(address account) external view returns (uint initialDebtOwnership, uint debtEntryIndex);
function debtLedgerLength() external view returns (uint);
function hasIssued(address account) external view returns (bool);
function lastDebtLedgerEntry() external view returns (uint);
// Mutative functions
function incrementTotalIssuerCount() external;
function decrementTotalIssuerCount() external;
function setCurrentIssuanceData(address account, uint initialDebtOwnership) external;
function appendDebtLedgerValue(uint value) external;
function clearIssuanceData(address account) external;
}
// https://docs.peri.finance/contracts/source/interfaces/isystemstatus
interface ISystemStatus {
struct Status {
bool canSuspend;
bool canResume;
}
struct Suspension {
bool suspended;
// reason is an integer code,
// 0 => no reason, 1 => upgrading, 2+ => defined by system usage
uint248 reason;
}
// Views
function accessControl(bytes32 section, address account) external view returns (bool canSuspend, bool canResume);
function requireSystemActive() external view;
function requireIssuanceActive() external view;
function requireExchangeActive() external view;
function requireExchangeBetweenPynthsAllowed(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view;
function requirePynthActive(bytes32 currencyKey) external view;
function requirePynthsActive(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey) external view;
function systemSuspension() external view returns (bool suspended, uint248 reason);
function issuanceSuspension() external view returns (bool suspended, uint248 reason);
function exchangeSuspension() external view returns (bool suspended, uint248 reason);
function pynthExchangeSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason);
function pynthSuspension(bytes32 currencyKey) external view returns (bool suspended, uint248 reason);
function getPynthExchangeSuspensions(bytes32[] calldata pynths)
external
view
returns (bool[] memory exchangeSuspensions, uint256[] memory reasons);
function getPynthSuspensions(bytes32[] calldata pynths)
external
view
returns (bool[] memory suspensions, uint256[] memory reasons);
// Restricted functions
function suspendPynth(bytes32 currencyKey, uint256 reason) external;
function updateAccessControl(
bytes32 section,
address account,
bool canSuspend,
bool canResume
) external;
}
// https://docs.peri.finance/contracts/source/interfaces/iexchanger
interface IExchanger {
// Views
function calculateAmountAfterSettlement(
address from,
bytes32 currencyKey,
uint amount,
uint refunded
) external view returns (uint amountAfterSettlement);
function isPynthRateInvalid(bytes32 currencyKey) external view returns (bool);
function maxSecsLeftInWaitingPeriod(address account, bytes32 currencyKey) external view returns (uint);
function settlementOwing(address account, bytes32 currencyKey)
external
view
returns (
uint reclaimAmount,
uint rebateAmount,
uint numEntries
);
function hasWaitingPeriodOrSettlementOwing(address account, bytes32 currencyKey) external view returns (bool);
function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey)
external
view
returns (uint exchangeFeeRate);
function getAmountsForExchange(
uint sourceAmount,
bytes32 sourceCurrencyKey,
bytes32 destinationCurrencyKey
)
external
view
returns (
uint amountReceived,
uint fee,
uint exchangeFeeRate
);
function priceDeviationThresholdFactor() external view returns (uint);
function waitingPeriodSecs() external view returns (uint);
// Mutative functions
function exchange(
address from,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address destinationAddress
) external returns (uint amountReceived);
function exchangeOnBehalf(
address exchangeForAddress,
address from,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
) external returns (uint amountReceived);
function exchangeWithTracking(
address from,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address destinationAddress,
address originator,
bytes32 trackingCode
) external returns (uint amountReceived);
function exchangeOnBehalfWithTracking(
address exchangeForAddress,
address from,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address originator,
bytes32 trackingCode
) external returns (uint amountReceived);
function exchangeWithVirtual(
address from,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address destinationAddress,
bytes32 trackingCode
) external returns (uint amountReceived, IVirtualPynth vPynth);
function settle(address from, bytes32 currencyKey)
external
returns (
uint reclaimed,
uint refunded,
uint numEntries
);
function setLastExchangeRateForPynth(bytes32 currencyKey, uint rate) external;
function suspendPynthWithInvalidRate(bytes32 currencyKey) external;
}
// https://docs.peri.finance/contracts/source/interfaces/irewardsdistribution
interface IRewardsDistribution {
// Structs
struct DistributionData {
address destination;
uint amount;
}
// Views
function authority() external view returns (address);
function distributions(uint index) external view returns (address destination, uint amount); // DistributionData
function distributionsLength() external view returns (uint);
// Mutative Functions
function distributeRewards(uint amount) external returns (bool);
}
// https://docs.peri.finance/contracts/source/interfaces/isystemsettings
interface ISystemSettings {
// Views
function priceDeviationThresholdFactor() external view returns (uint);
function waitingPeriodSecs() external view returns (uint);
function issuanceRatio() external view returns (uint);
function feePeriodDuration() external view returns (uint);
function targetThreshold() external view returns (uint);
function liquidationDelay() external view returns (uint);
function liquidationRatio() external view returns (uint);
function liquidationPenalty() external view returns (uint);
function rateStalePeriod() external view returns (uint);
function exchangeFeeRate(bytes32 currencyKey) external view returns (uint);
function minimumStakeTime() external view returns (uint);
function externalTokenQuota() external view returns (uint);
function bridgeTransferGasCost() external view returns (uint);
function bridgeClaimGasCost() external view returns (uint);
function syncStaleThreshold() external view returns (uint);
function debtSnapshotStaleTime() external view returns (uint);
}
// Inheritance
// Libraries
// Internal references
interface IBlacklistManager {
function flagged(address _account) external view returns (bool);
}
contract BasePeriFinance is IERC20, ExternStateToken, MixinResolver, IPeriFinance {
using SafeMath for uint;
using SafeDecimalMath for uint;
// ========== STATE VARIABLES ==========
// Available Pynths which can be used with the system
string public constant TOKEN_NAME = "Peri Finance Token";
string public constant TOKEN_SYMBOL = "PERI";
uint8 public constant DECIMALS = 18;
bytes32 public constant pUSD = "pUSD";
// ========== ADDRESS RESOLVER CONFIGURATION ==========
bytes32 private constant CONTRACT_PERIFINANCESTATE = "PeriFinanceState";
bytes32 private constant CONTRACT_SYSTEMSTATUS = "SystemStatus";
bytes32 private constant CONTRACT_EXCHANGER = "Exchanger";
bytes32 private constant CONTRACT_ISSUER = "Issuer";
bytes32 private constant CONTRACT_REWARDSDISTRIBUTION = "RewardsDistribution";
bytes32 private constant CONTRACT_SYSTEMSETTINGS = "SystemSettings";
IBlacklistManager public blacklistManager;
// ========== CONSTRUCTOR ==========
constructor(
address payable _proxy,
TokenState _tokenState,
address _owner,
uint _totalSupply,
address _resolver,
address _blacklistManager
)
public
ExternStateToken(_proxy, _tokenState, TOKEN_NAME, TOKEN_SYMBOL, _totalSupply, DECIMALS, _owner)
MixinResolver(_resolver)
{
blacklistManager = IBlacklistManager(_blacklistManager);
}
// ========== VIEWS ==========
// Note: use public visibility so that it can be invoked in a subclass
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
addresses = new bytes32[](6);
addresses[0] = CONTRACT_PERIFINANCESTATE;
addresses[1] = CONTRACT_SYSTEMSTATUS;
addresses[2] = CONTRACT_EXCHANGER;
addresses[3] = CONTRACT_ISSUER;
addresses[4] = CONTRACT_REWARDSDISTRIBUTION;
addresses[5] = CONTRACT_SYSTEMSETTINGS;
}
function periFinanceState() internal view returns (IPeriFinanceState) {
return IPeriFinanceState(requireAndGetAddress(CONTRACT_PERIFINANCESTATE));
}
function systemStatus() internal view returns (ISystemStatus) {
return ISystemStatus(requireAndGetAddress(CONTRACT_SYSTEMSTATUS));
}
function exchanger() internal view returns (IExchanger) {
return IExchanger(requireAndGetAddress(CONTRACT_EXCHANGER));
}
function issuer() internal view returns (IIssuer) {
return IIssuer(requireAndGetAddress(CONTRACT_ISSUER));
}
function rewardsDistribution() internal view returns (IRewardsDistribution) {
return IRewardsDistribution(requireAndGetAddress(CONTRACT_REWARDSDISTRIBUTION));
}
function systemSettings() internal view returns (ISystemSettings) {
return ISystemSettings(requireAndGetAddress(CONTRACT_SYSTEMSETTINGS));
}
function getRequiredAddress(bytes32 _contractName) external view returns (address) {
return requireAndGetAddress(_contractName);
}
function debtBalanceOf(address account, bytes32 currencyKey) external view returns (uint) {
return issuer().debtBalanceOf(account, currencyKey);
}
function totalIssuedPynths(bytes32 currencyKey) external view returns (uint totalIssued) {
(totalIssued, ) = issuer().totalIssuedPynths(currencyKey, false);
}
function totalIssuedPynthsExcludeEtherCollateral(bytes32 currencyKey) external view returns (uint totalIssued) {
(totalIssued, ) = issuer().totalIssuedPynths(currencyKey, true);
}
// function availableCurrencyKeys() external view returns (bytes32[] memory) {
// return issuer().availableCurrencyKeys();
// }
// function availablePynthCount() external view returns (uint) {
// return issuer().availablePynthCount();
// }
// function availablePynths(uint index) external view returns (IPynth) {
// return issuer().availablePynths(index);
// }
// function pynths(bytes32 currencyKey) external view returns (IPynth) {
// return issuer().pynths(currencyKey);
// }
// function pynthsByAddress(address pynthAddress) external view returns (bytes32) {
// return issuer().pynthsByAddress(pynthAddress);
// }
function isWaitingPeriod(bytes32 currencyKey) external view returns (bool) {
return exchanger().maxSecsLeftInWaitingPeriod(messageSender, currencyKey) > 0;
}
// function anyPynthOrPERIRateIsInvalid() external view returns (bool anyRateInvalid) {
// return issuer().anyPynthOrPERIRateIsInvalid();
// }
function maxIssuablePynths(address account) external view returns (uint maxIssuable) {
(maxIssuable, , ) = issuer().maxIssuablePynths(account);
}
function remainingIssuablePynths(address account)
external
view
returns (
uint maxIssuable,
uint alreadyIssued,
uint totalSystemDebt
)
{
return issuer().remainingIssuablePynths(account);
}
function collateralisationRatio(address _issuer) external view returns (uint) {
return issuer().collateralisationRatio(_issuer);
}
function collateral(address account) external view returns (uint) {
return issuer().collateral(account);
}
function transferablePeriFinance(address account) external view returns (uint transferable) {
(transferable, ) = issuer().transferablePeriFinanceAndAnyRateIsInvalid(account, tokenState.balanceOf(account));
}
function amountsToFitClaimable(address account) external view returns (uint burnAmount, uint exTokenAmountToUnstake) {
(burnAmount, exTokenAmountToUnstake) = issuer().amountsToFitClaimable(account);
}
function _canTransfer(address account, uint value) internal view returns (bool) {
(uint initialDebtOwnership, ) = periFinanceState().issuanceData(account);
if (initialDebtOwnership > 0) {
(uint transferable, bool anyRateIsInvalid) =
issuer().transferablePeriFinanceAndAnyRateIsInvalid(account, tokenState.balanceOf(account));
require(value <= transferable, "Check Transferable");
require(!anyRateIsInvalid, "Rate invalid");
}
return true;
}
// ========== MUTATIVE FUNCTIONS ==========
function setBlacklistManager(address _blacklistManager) external onlyOwner {
require(_blacklistManager != address(0), "0 address");
blacklistManager = IBlacklistManager(_blacklistManager);
}
function exchange(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
)
external
exchangeActive(sourceCurrencyKey, destinationCurrencyKey)
optionalProxy
blacklisted(messageSender)
returns (uint amountReceived)
{
return exchanger().exchange(messageSender, sourceCurrencyKey, sourceAmount, destinationCurrencyKey, messageSender);
}
function exchangeOnBehalf(
address exchangeForAddress,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
)
external
exchangeActive(sourceCurrencyKey, destinationCurrencyKey)
optionalProxy
blacklisted(messageSender)
blacklisted(exchangeForAddress)
returns (uint amountReceived)
{
return
exchanger().exchangeOnBehalf(
exchangeForAddress,
messageSender,
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey
);
}
function settle(bytes32 currencyKey)
external
optionalProxy
blacklisted(messageSender)
returns (
uint reclaimed,
uint refunded,
uint numEntriesSettled
)
{
return exchanger().settle(messageSender, currencyKey);
}
function exchangeWithTracking(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address originator,
bytes32 trackingCode
)
external
exchangeActive(sourceCurrencyKey, destinationCurrencyKey)
optionalProxy
blacklisted(messageSender)
returns (uint amountReceived)
{
return
exchanger().exchangeWithTracking(
messageSender,
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey,
messageSender,
originator,
trackingCode
);
}
function exchangeOnBehalfWithTracking(
address exchangeForAddress,
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
address originator,
bytes32 trackingCode
)
external
exchangeActive(sourceCurrencyKey, destinationCurrencyKey)
optionalProxy
blacklisted(messageSender)
blacklisted(exchangeForAddress)
returns (uint amountReceived)
{
return
exchanger().exchangeOnBehalfWithTracking(
exchangeForAddress,
messageSender,
sourceCurrencyKey,
sourceAmount,
destinationCurrencyKey,
originator,
trackingCode
);
}
function transfer(address to, uint value) external optionalProxy systemActive blacklisted(messageSender) returns (bool) {
// Ensure they're not trying to exceed their locked amount -- only if they have debt.
_canTransfer(messageSender, value);
// Perform the transfer: if there is a problem an exception will be thrown in this call.
_transferByProxy(messageSender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint value
) external optionalProxy systemActive blacklisted(messageSender) blacklisted(from) returns (bool) {
// Ensure they're not trying to exceed their locked amount -- only if they have debt.
_canTransfer(from, value);
// Perform the transfer: if there is a problem,
// an exception will be thrown in this call.
return _transferFromByProxy(messageSender, from, to, value);
}
function issuePynths(bytes32 _currencyKey, uint _issueAmount)
external
issuanceActive
optionalProxy
blacklisted(messageSender)
{
issuer().issuePynths(messageSender, _currencyKey, _issueAmount);
}
function issueMaxPynths() external issuanceActive optionalProxy blacklisted(messageSender) {
issuer().issueMaxPynths(messageSender);
}
function issuePynthsToMaxQuota(bytes32 _currencyKey) external issuanceActive optionalProxy blacklisted(messageSender) {
issuer().issuePynthsToMaxQuota(messageSender, _currencyKey);
}
function burnPynths(bytes32 _currencyKey, uint _burnAmount)
external
issuanceActive
optionalProxy
blacklisted(messageSender)
{
issuer().burnPynths(messageSender, _currencyKey, _burnAmount);
}
function fitToClaimable() external payable issuanceActive optionalProxy blacklisted(messageSender) {
issuer().fitToClaimable(messageSender);
}
function forceFitToClaimable(address _target) external payable onlyOwner {
issuer().fitToClaimable(_target);
}
function exit() external issuanceActive optionalProxy blacklisted(messageSender) {
issuer().exit(messageSender);
}
function exchangeWithVirtual(
bytes32,
uint,
bytes32,
bytes32
) external returns (uint, IVirtualPynth) {
_notImplemented();
}
function liquidateDelinquentAccount(address, uint) external returns (bool) {
_notImplemented();
}
function mintSecondary(address, uint) external {
_notImplemented();
}
function mintSecondaryRewards(uint) external {
_notImplemented();
}
function burnSecondary(address, uint) external {
_notImplemented();
}
function _notImplemented() internal pure {
revert("Can't run");
}
// ========== MODIFIERS ==========
modifier systemActive() {
_systemActive();
_;
}
function _systemActive() private view {
systemStatus().requireSystemActive();
}
modifier issuanceActive() {
_issuanceActive();
_;
}
function _issuanceActive() private view {
systemStatus().requireIssuanceActive();
}
function _blacklisted(address _account) private view {
require(address(blacklistManager) != address(0), "Contract not setted");
require(!blacklistManager.flagged(_account), "Blacklisted");
}
modifier blacklisted(address _account) {
_blacklisted(_account);
_;
}
modifier exchangeActive(bytes32 src, bytes32 dest) {
_exchangeActive(src, dest);
_;
}
function _exchangeActive(bytes32 src, bytes32 dest) private view {
systemStatus().requireExchangeBetweenPynthsAllowed(src, dest);
}
modifier onlyExchanger() {
_onlyExchanger();
_;
}
function _onlyExchanger() private view {
require(msg.sender == address(exchanger()), "OnlyExchanger");
}
// ========== EVENTS ==========
event PynthExchange(
address indexed account,
bytes32 fromCurrencyKey,
uint256 fromAmount,
bytes32 toCurrencyKey,
uint256 toAmount,
address toAddress
);
bytes32 internal constant PYNTHEXCHANGE_SIG =
keccak256("PynthExchange(address,bytes32,uint256,bytes32,uint256,address)");
function emitPynthExchange(
address account,
bytes32 fromCurrencyKey,
uint256 fromAmount,
bytes32 toCurrencyKey,
uint256 toAmount,
address toAddress
) external onlyExchanger {
proxy._emit(
abi.encode(fromCurrencyKey, fromAmount, toCurrencyKey, toAmount, toAddress),
2,
PYNTHEXCHANGE_SIG,
addressToBytes32(account),
0,
0
);
}
event ExchangeTracking(bytes32 indexed trackingCode, bytes32 toCurrencyKey, uint256 toAmount);
bytes32 internal constant EXCHANGE_TRACKING_SIG = keccak256("ExchangeTracking(bytes32,bytes32,uint256)");
function emitExchangeTracking(
bytes32 trackingCode,
bytes32 toCurrencyKey,
uint256 toAmount
) external onlyExchanger {
proxy._emit(abi.encode(toCurrencyKey, toAmount), 2, EXCHANGE_TRACKING_SIG, trackingCode, 0, 0);
}
event ExchangeReclaim(address indexed account, bytes32 currencyKey, uint amount);
bytes32 internal constant EXCHANGERECLAIM_SIG = keccak256("ExchangeReclaim(address,bytes32,uint256)");
function emitExchangeReclaim(
address account,
bytes32 currencyKey,
uint256 amount
) external onlyExchanger {
proxy._emit(abi.encode(currencyKey, amount), 2, EXCHANGERECLAIM_SIG, addressToBytes32(account), 0, 0);
}
event ExchangeRebate(address indexed account, bytes32 currencyKey, uint amount);
bytes32 internal constant EXCHANGEREBATE_SIG = keccak256("ExchangeRebate(address,bytes32,uint256)");
function emitExchangeRebate(
address account,
bytes32 currencyKey,
uint256 amount
) external onlyExchanger {
proxy._emit(abi.encode(currencyKey, amount), 2, EXCHANGEREBATE_SIG, addressToBytes32(account), 0, 0);
}
}
pragma experimental ABIEncoderV2;
library VestingEntries {
struct VestingEntry {
uint64 endTime;
uint256 escrowAmount;
}
struct VestingEntryWithID {
uint64 endTime;
uint256 escrowAmount;
uint256 entryID;
}
}
interface IRewardEscrowV2 {
// Views
function balanceOf(address account) external view returns (uint);
function numVestingEntries(address account) external view returns (uint);
function totalEscrowedAccountBalance(address account) external view returns (uint);
function totalVestedAccountBalance(address account) external view returns (uint);
function totalEscrowedBalance() external view returns (uint);
function getVestingQuantity(address account, uint256[] calldata entryIDs) external view returns (uint);
function getVestingSchedules(
address account,
uint256 index,
uint256 pageSize
) external view returns (VestingEntries.VestingEntryWithID[] memory);
function getAccountVestingEntryIDs(
address account,
uint256 index,
uint256 pageSize
) external view returns (uint256[] memory);
function getVestingEntryClaimable(address account, uint256 entryID) external view returns (uint);
function getVestingEntry(address account, uint256 entryID) external view returns (uint64, uint256);
// Mutative functions
function vest(uint256[] calldata entryIDs) external;
function createEscrowEntry(
address beneficiary,
uint256 deposit,
uint256 duration
) external;
function appendVestingEntry(
address account,
uint256 quantity,
uint256 duration
) external;
function migrateVestingSchedule(address _addressToMigrate) external;
function migrateAccountEscrowBalances(
address[] calldata accounts,
uint256[] calldata escrowBalances,
uint256[] calldata vestedBalances
) external;
// Account Merging
function startMergingWindow() external;
function mergeAccount(address accountToMerge, uint256[] calldata entryIDs) external;
function nominateAccountToMerge(address account) external;
function accountMergingIsOpen() external view returns (bool);
// L2 Migration
function importVestingEntries(
address account,
uint256 escrowedAmount,
VestingEntries.VestingEntry[] calldata vestingEntries
) external;
// Return amount of PERI transfered to PeriFinanceBridgeToOptimism deposit contract
function burnForMigration(address account, uint256[] calldata entryIDs)
external
returns (uint256 escrowedAccountBalance, VestingEntries.VestingEntry[] memory vestingEntries);
}
// https://docs.peri.finance/contracts/source/interfaces/isupplyschedule
interface ISupplySchedule {
// Views
function mintableSupply() external view returns (uint);
function isMintable() external view returns (bool);
function minterReward() external view returns (uint);
// Mutative functions
function recordMintEvent(uint supplyMinted) external returns (bool);
}
interface IBridgeState {
// ----VIEWS
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
}
function networkOpened(uint chainId) external view returns (bool);
function accountOutboundings(
address account,
uint periodId,
uint index
) external view returns (uint);
function accountInboundings(address account, uint index) external view returns (uint);
function inboundings(uint index)
external
view
returns (
address,
uint,
uint,
uint,
bool,
Signature memory
);
function outboundings(uint index)
external
view
returns (
address,
uint,
uint,
uint,
Signature memory
);
function outboundPeriods(uint index)
external
view
returns (
uint,
uint,
uint[] memory,
bool
);
function srcOutboundingIdRegistered(uint chainId, uint srcOutboundingId) external view returns (bool isRegistered);
function numberOfOutboundPerPeriod() external view returns (uint);
function periodDuration() external view returns (uint);
function outboundingsLength() external view returns (uint);
function getTotalOutboundAmount() external view returns (uint);
function inboundingsLength() external view returns (uint);
function getTotalInboundAmount() external view returns (uint);
function outboundIdsInPeriod(uint outboundPeriodId) external view returns (uint[] memory);
function isOnRole(bytes32 roleKey, address account) external view returns (bool);
function accountOutboundingsInPeriod(address _account, uint _period) external view returns (uint[] memory);
function applicableInboundIds(address account) external view returns (uint[] memory);
function outboundRequestIdsInPeriod(address account, uint periodId) external view returns (uint[] memory);
function periodIdsToProcess() external view returns (uint[] memory);
function getMovedAmount(uint _inboundOutbound, uint targetNetworkId) external view returns (uint);
// ----MUTATIVES
function appendOutboundingRequest(
address account,
uint amount,
uint destChainIds,
Signature calldata sign
) external;
function appendMultipleInboundingRequests(
address[] calldata accounts,
uint[] calldata amounts,
uint[] calldata srcChainIds,
uint[] calldata srcOutboundingIds,
Signature[] calldata sign
) external;
function appendInboundingRequest(
address account,
uint amount,
uint srcChainId,
uint srcOutboundingId,
bytes32 r,
bytes32 s,
uint8 v
) external;
function claimInbound(uint index, uint _amount) external;
}
// Inheritance
// Internal references
interface ICrossChainManager {
function mintableSupply() external view returns (uint);
function minterReward() external view returns (uint);
}
// https://docs.peri.finance/contracts/source/contracts/periFinance
contract PeriFinance is BasePeriFinance {
// ========== ADDRESS RESOLVER CONFIGURATION ==========
bytes32 private constant CONTRACT_REWARDESCROW_V2 = "RewardEscrowV2";
bytes32 private constant CONTRACT_SUPPLYSCHEDULE = "SupplySchedule";
bytes32 private constant CONTRACT_CROSSCHAINMANAGER = "CrossChainManager";
bytes32 private constant CONTRACT_BRIDGESTATE = "BridgeState";
address public minterRole;
address public inflationMinter;
address payable public bridgeValidator;
// IBridgeState public bridgeState;
// ========== CONSTRUCTOR ==========
constructor(
address payable _proxy,
TokenState _tokenState,
address _owner,
uint _totalSupply,
address _resolver,
address _minterRole,
address _blacklistManager,
address payable _bridgeValidator
) public BasePeriFinance(_proxy, _tokenState, _owner, _totalSupply, _resolver, _blacklistManager) {
minterRole = _minterRole;
bridgeValidator = _bridgeValidator;
}
function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {
bytes32[] memory existingAddresses = BasePeriFinance.resolverAddressesRequired();
bytes32[] memory newAddresses = new bytes32[](4);
newAddresses[0] = CONTRACT_REWARDESCROW_V2;
newAddresses[1] = CONTRACT_SUPPLYSCHEDULE;
newAddresses[2] = CONTRACT_CROSSCHAINMANAGER;
newAddresses[3] = CONTRACT_BRIDGESTATE;
return combineArrays(existingAddresses, newAddresses);
}
// ========== VIEWS ==========
function rewardEscrowV2() internal view returns (IRewardEscrowV2) {
return IRewardEscrowV2(requireAndGetAddress(CONTRACT_REWARDESCROW_V2));
}
function supplySchedule() internal view returns (ISupplySchedule) {
return ISupplySchedule(requireAndGetAddress(CONTRACT_SUPPLYSCHEDULE));
}
function crossChainManager() internal view returns (ICrossChainManager) {
return ICrossChainManager(requireAndGetAddress(CONTRACT_CROSSCHAINMANAGER));
}
function bridgeState() internal view returns (IBridgeState) {
return IBridgeState(requireAndGetAddress(CONTRACT_BRIDGESTATE));
}
// ========== OVERRIDDEN FUNCTIONS ==========
function settle(bytes32 currencyKey)
external
optionalProxy
blacklisted(messageSender)
returns (
uint reclaimed,
uint refunded,
uint numEntriesSettled
)
{
return exchanger().settle(messageSender, currencyKey);
}
function inflationalMint() external issuanceActive returns (bool) {
require(msg.sender == inflationMinter, "onlyMinter");
require(address(rewardsDistribution()) != address(0), "No RewardsDistribution");
// those commented linse are now moved to crossChainManager same logic but different place
// so PeriFinance contract will not be deployed for this change.
// ISupplySchedule _supplySchedule = supplySchedule();
IRewardsDistribution _rewardsDistribution = rewardsDistribution();
// require(crossChainManager().syncStale() == false, 'Cross-chain debt is stale');
// uint _currRate = crossChainManager().currentNetworkDebtPercentage();
// require(SafeDecimalMath.preciseUnit() >= _currRate, "Network rate invalid");
// uint supplyToMint = _supplySchedule.mintableSupply();
// supplyToMint = supplyToMint
// .decimalToPreciseDecimal()
// .multiplyDecimalRoundPrecise(_currRate)
// .preciseDecimalToDecimal();
// require(supplyToMint > 0, "No mintable supply");
uint supplyToMint = crossChainManager().mintableSupply();
// record minting event before mutation to token supply
// _supplySchedule.recordMintEvent(supplyToMint);
supplySchedule().recordMintEvent(supplyToMint);
// Set minted PERI balance to RewardEscrow's balance
// Minus the minterReward and set balance of minter to add reward
uint minterReward = supplySchedule().minterReward();
// uint minterReward = _supplySchedule.minterReward();
// uint minterReward = crossChainManager().minterReward();
// Get the remainder
uint amountToDistribute = supplyToMint.sub(minterReward);
// Set the token balance to the RewardsDistribution contract
tokenState.setBalanceOf(
address(_rewardsDistribution),
tokenState.balanceOf(address(_rewardsDistribution)).add(amountToDistribute)
);
emitTransfer(address(this), address(_rewardsDistribution), amountToDistribute);
// Kick off the distribution of rewards
_rewardsDistribution.distributeRewards(amountToDistribute);
// Assign the minters reward.
tokenState.setBalanceOf(msg.sender, tokenState.balanceOf(msg.sender).add(minterReward));
emitTransfer(address(this), msg.sender, minterReward);
totalSupply = totalSupply.add(supplyToMint);
return true;
}
function mint(address _user, uint _amount) external optionalProxy returns (bool) {
require(minterRole != address(0), "0 address");
require(minterRole == messageSender, "onlyMinter");
// It won't change totalsupply since it is only for bridge purpose.
tokenState.setBalanceOf(_user, tokenState.balanceOf(_user).add(_amount));
emitTransfer(address(0), _user, _amount);
return true;
}
function liquidateDelinquentAccount(address account, uint pusdAmount)
external
systemActive
optionalProxy
blacklisted(messageSender)
returns (bool)
{
(uint totalRedeemed, uint amountLiquidated) =
issuer().liquidateDelinquentAccount(account, pusdAmount, messageSender);
emitAccountLiquidated(account, totalRedeemed, amountLiquidated, messageSender);
// Transfer PERI redeemed to messageSender
// Reverts if amount to redeem is more than balanceOf account, ie due to escrowed balance
return _transferByProxy(account, messageSender, totalRedeemed);
}
// ------------- Bridge Experiment
function overchainTransfer(
uint _amount,
uint _destChainId,
IBridgeState.Signature calldata _sign
) external payable optionalProxy blacklisted(messageSender) {
require(_amount > 0, "0 amount");
(uint transferable, ) =
issuer().transferablePeriFinanceAndAnyRateIsInvalid(messageSender, tokenState.balanceOf(messageSender));
require(transferable >= _amount, "CheckAmount");
require(msg.value >= systemSettings().bridgeTransferGasCost(), "NoFee");
bridgeValidator.transfer(msg.value);
require(_burnByProxy(messageSender, _amount), "BurnFail");
bridgeState().appendOutboundingRequest(messageSender, _amount, _destChainId, _sign);
}
function claimAllBridgedAmounts() external payable optionalProxy {
uint[] memory applicableIds = bridgeState().applicableInboundIds(messageSender);
require(applicableIds.length > 0, "NoClaimable");
require(msg.value >= systemSettings().bridgeClaimGasCost(), "NoFee");
bridgeValidator.transfer(msg.value);
for (uint i; i < applicableIds.length; i++) {
_claimBridgedAmount(applicableIds[i]);
}
}
function _claimBridgedAmount(uint _index) internal returns (bool) {
// Validations are checked from bridge state
(address account, uint amount, , , , ) = bridgeState().inboundings(_index);
require(account == messageSender, "CheckAddress");
bridgeState().claimInbound(_index, amount);
require(_mintByProxy(account, amount), "MintFail");
return true;
}
function setMinterRole(address _newMinter) external onlyOwner {
// If address is set to zero address, mint is not prohibited
minterRole = _newMinter;
}
function setBridgeValidator(address payable _bridgeValidator) external onlyOwner {
bridgeValidator = _bridgeValidator;
}
function setInflationMinter(address _newInflationMinter) external onlyOwner {
inflationMinter = _newInflationMinter;
}
// function setBridgeState(address _newBridgeState) external onlyOwner {
// bridgeState = IBridgeState(_newBridgeState);
// }
// ========== EVENTS ==========
event AccountLiquidated(address indexed account, uint periRedeemed, uint amountLiquidated, address liquidator);
bytes32 internal constant ACCOUNTLIQUIDATED_SIG = keccak256("AccountLiquidated(address,uint256,uint256,address)");
function emitAccountLiquidated(
address account,
uint256 periRedeemed,
uint256 amountLiquidated,
address liquidator
) internal {
proxy._emit(
abi.encode(periRedeemed, amountLiquidated, liquidator),
2,
ACCOUNTLIQUIDATED_SIG,
addressToBytes32(account),
0,
0
);
}
}
contract PeriFinanceToEthereum is PeriFinance {
constructor(
address payable _proxy,
TokenState _tokenState,
address _owner,
uint _totalSupply,
address _resolver,
address _minterRole,
address _blacklistManager,
address payable _bridgeValidator
)
public
PeriFinance(_proxy, _tokenState, _owner, _totalSupply, _resolver, _minterRole, _blacklistManager, _bridgeValidator)
{}
}
{
"compilationTarget": {
"PeriFinanceToEthereum.sol": "PeriFinanceToEthereum"
},
"evmVersion": "istanbul",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address payable","name":"_proxy","type":"address"},{"internalType":"contract TokenState","name":"_tokenState","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"},{"internalType":"address","name":"_resolver","type":"address"},{"internalType":"address","name":"_minterRole","type":"address"},{"internalType":"address","name":"_blacklistManager","type":"address"},{"internalType":"address payable","name":"_bridgeValidator","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"periRedeemed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLiquidated","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"}],"name":"AccountLiquidated","type":"event"},{"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":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExchangeRebate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExchangeReclaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"trackingCode","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"}],"name":"ExchangeTracking","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxyAddress","type":"address"}],"name":"ProxyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bytes32","name":"fromCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"toAddress","type":"address"}],"name":"PynthExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTokenState","type":"address"}],"name":"TokenStateUpdated","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"},{"constant":true,"inputs":[],"name":"DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TOKEN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TOKEN_SYMBOL","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"amountsToFitClaimable","outputs":[{"internalType":"uint256","name":"burnAmount","type":"uint256"},{"internalType":"uint256","name":"exTokenAmountToUnstake","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"blacklistManager","outputs":[{"internalType":"contract IBlacklistManager","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bridgeValidator","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"},{"internalType":"uint256","name":"_burnAmount","type":"uint256"}],"name":"burnPynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"burnSecondary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimAllBridgedAmounts","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"collateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_issuer","type":"address"}],"name":"collateralisationRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"debtBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emitExchangeRebate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"currencyKey","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emitExchangeReclaim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"trackingCode","type":"bytes32"},{"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"toAmount","type":"uint256"}],"name":"emitExchangeTracking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"fromCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"bytes32","name":"toCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"toAmount","type":"uint256"},{"internalType":"address","name":"toAddress","type":"address"}],"name":"emitPynthExchange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"exchange","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"exchangeForAddress","type":"address"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"}],"name":"exchangeOnBehalf","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"exchangeForAddress","type":"address"},{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"},{"internalType":"address","name":"originator","type":"address"},{"internalType":"bytes32","name":"trackingCode","type":"bytes32"}],"name":"exchangeOnBehalfWithTracking","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"sourceCurrencyKey","type":"bytes32"},{"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"internalType":"bytes32","name":"destinationCurrencyKey","type":"bytes32"},{"internalType":"address","name":"originator","type":"address"},{"internalType":"bytes32","name":"trackingCode","type":"bytes32"}],"name":"exchangeWithTracking","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"exchangeWithVirtual","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"contract IVirtualPynth","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"exit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"fitToClaimable","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_target","type":"address"}],"name":"forceFitToClaimable","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_contractName","type":"bytes32"}],"name":"getRequiredAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"inflationMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"inflationalMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"integrationProxy","outputs":[{"internalType":"contract Proxy","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"isWaitingPeriod","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"issueMaxPynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"},{"internalType":"uint256","name":"_issueAmount","type":"uint256"}],"name":"issuePynths","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"}],"name":"issuePynthsToMaxQuota","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"pusdAmount","type":"uint256"}],"name":"liquidateDelinquentAccount","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"maxIssuablePynths","outputs":[{"internalType":"uint256","name":"maxIssuable","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"messageSender","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintSecondary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintSecondaryRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"minterRole","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_destChainId","type":"uint256"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct IBridgeState.Signature","name":"_sign","type":"tuple"}],"name":"overchainTransfer","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pUSD","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proxy","outputs":[{"internalType":"contract Proxy","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"remainingIssuablePynths","outputs":[{"internalType":"uint256","name":"maxIssuable","type":"uint256"},{"internalType":"uint256","name":"alreadyIssued","type":"uint256"},{"internalType":"uint256","name":"totalSystemDebt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_blacklistManager","type":"address"}],"name":"setBlacklistManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bool","name":"_set","type":"bool"}],"name":"setBlockedAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_bridgeValidator","type":"address"}],"name":"setBridgeValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newInflationMinter","type":"address"}],"name":"setInflationMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_integrationProxy","type":"address"}],"name":"setIntegrationProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"setMessageSender","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newMinter","type":"address"}],"name":"setMinterRole","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_proxy","type":"address"}],"name":"setProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract TokenState","name":"_tokenState","type":"address"}],"name":"setTokenState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"settle","outputs":[{"internalType":"uint256","name":"reclaimed","type":"uint256"},{"internalType":"uint256","name":"refunded","type":"uint256"},{"internalType":"uint256","name":"numEntriesSettled","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenState","outputs":[{"internalType":"contract TokenState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"totalIssuedPynths","outputs":[{"internalType":"uint256","name":"totalIssued","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"currencyKey","type":"bytes32"}],"name":"totalIssuedPynthsExcludeEtherCollateral","outputs":[{"internalType":"uint256","name":"totalIssued","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"transferablePeriFinance","outputs":[{"internalType":"uint256","name":"transferable","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]