Contract Overview
Balance:
0 DEV
My Name Tag:
Not Available
Txn Hash | Method |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0xace6b04e4e2c38935be77d7ed278349179edb6ae664f57a9d3adc0558be711be | 0x60806040 | 2777820 | 266 days 15 hrs ago | 0xb6010d7ac4a8e9fa3e88b25f287fe725f2215208 | IN | Contract Creation | 0 DEV | 0.000662185 |
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0xc58d3032f51972A621545fdD2b9eCf60FC21805c
Contract Name:
TradingEmissionsQontroller
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: NONE pragma solidity ^0.8.9; import "./interfaces/IQAdmin.sol"; import "./interfaces/ITradingEmissionsQontroller.sol"; import "./interfaces/IQodaERC20.sol"; contract TradingEmissionsQontroller is ITradingEmissionsQontroller { struct EmissionsPhase { /// @notice Token reward per $1 USD in txn fees uint rewardRate; ///@ notice Current amount of tokens accrued in the current phase uint tokensAccrued; /// @notice Total amount of tokens reserved for the current phase uint tokensTotal; } /// @notice Contract storing all global Qoda parameters IQAdmin private _qAdmin; /// @notice Address of underlying QODA token IQodaERC20 private _qodaERC20; /// @notice Number of emissions phases uint private _numPhases; /// @notice Current phase for emissions uint private _currentPhase; /// @notice Total tokens allocated to reward for `TradingEmissionsQontroller` uint private _totalAllocation; /// @notice Track unclaimed rewards mapping(address => uint) private _claimableEmissions; /// @notice Map defining the emissions phase and associated configurations mapping(uint => EmissionsPhase) private _emissionsPhase; /// @notice Emitted when user claims emissions event ClaimEmissions(address account, uint amount); constructor( address qodaERC20Address, address qAdminAddress, uint[] memory rewardRate_, uint[] memory tokensTotal_, uint numPhases_, uint totalAllocation_ ) { require( rewardRate_.length == numPhases_ && tokensTotal_.length == numPhases_, "TEQ2 length mismatch" ); // Initialize values _qodaERC20 = IQodaERC20(qodaERC20Address); _qAdmin = IQAdmin(qAdminAddress); _numPhases = numPhases_; _currentPhase = 0; _totalAllocation = totalAllocation_; // Initialize emissions phases and rewards config for (uint i = 0; i < numPhases_; i++){ _emissionsPhase[i] = EmissionsPhase({ rewardRate: rewardRate_[i], tokensTotal: tokensTotal_[i], tokensAccrued: 0 }); } // Sanity check on rewards uint totalRewards = 0; for(uint i=0; i<_numPhases; i++){ totalRewards += _emissionsPhase[i].tokensTotal; } require(_totalAllocation == totalRewards, "TEQ0 incorrect rewards"); } modifier onlyMarket() { require(_qAdmin.hasRole(_qAdmin.MARKET_ROLE(), msg.sender), "TEQ1 only market"); _; } /** ACCESS CONTROLLED FUNCTIONS **/ /// @notice Use the fees generated (in USD) as basis to calculate how much /// token reward to disburse for trading volumes. Only `FixedRateMarket` /// contracts may call this function. /// @param borrower Address of the borrower /// @param lender Address of the lender /// @param feeUSD Fees generated (in USD, scaled to 1e6) function updateRewards( address borrower, address lender, uint feeUSD ) external onlyMarket { _updateRewards(borrower, feeUSD); _updateRewards(lender, feeUSD); } /** USER INTERFACE **/ /// @notice Mint the unclaimed rewards to user and reset their claimable emissions function claimEmissions() external { // Get the emissions accrued for the user uint reward = _claimableEmissions[msg.sender]; require(reward > 0, "TEQ3 reward must be positive"); // Reset user's claimable emissions _claimableEmissions[msg.sender] = 0; // Transfer the rewards directly from `TradingEmissionsQontroller` contract // to user. The assumption is that total supply of reward tokens have been // pre-minted to this contract address. This limits the maximum damage of // a potential hack to just tokens within the contract (compared to an // infinite mint of tokens if this contract were allowed to mint on a // callable function _qodaERC20.transfer(msg.sender, reward); // Emit the event emit ClaimEmissions(msg.sender, reward); } /** VIEW FUNCTIONS **/ /// @notice Checks the amount of unclaimed trading rewards that the user can claim /// @param account Address of the user /// @return uint Amount of QODA token rewards the user may claim function claimableEmissions(address account) external view returns(uint){ return _claimableEmissions[account]; } function qAdmin() external view returns(address) { return address(_qAdmin); } function qodaERC20() external view returns(address) { return address(_qodaERC20); } function numPhases() external view returns(uint) { return _numPhases; } function currentPhase() external view returns(uint) { return _currentPhase; } function totalAllocation() external view returns(uint) { return _totalAllocation; } function emissionsPhase(uint phase) external view returns(uint, uint, uint) { uint rewardRate = _emissionsPhase[phase].rewardRate; uint tokensAccrued = _emissionsPhase[phase].tokensAccrued; uint tokensTotal = _emissionsPhase[phase].tokensTotal; return (rewardRate, tokensAccrued, tokensTotal); } /** INTERNAL FUNCTIONS **/ /// @notice Use the fees generated (in USD) as basis to calculate how much /// token reward to disburse for trading volumes. /// @param account Address of the user /// @param feeUSD Fees generated (in USD, scaled to 1e6) function _updateRewards(address account, uint feeUSD) internal { if(_currentPhase == _numPhases){ // All trading rewards have already been distributed return; } uint tokensTotal = _emissionsPhase[_currentPhase].tokensTotal; uint tokensAccrued = _emissionsPhase[_currentPhase].tokensAccrued; // One USD is 1000000 by convention (see QPriceOracle) uint proposedReward = _emissionsPhase[_currentPhase].rewardRate * feeUSD / 1000000; // Check if the `proposedReward` will push the emission schedule into the next phase if(proposedReward + tokensAccrued > tokensTotal) { // Total reward under old phase can't be more than the remaining reserved tokens in the phase uint rewardOldPhase = tokensTotal - tokensAccrued; // The reward is enough to move us to the next emissions phase // First, set `tokensAccrued` = `tokensTotal` in the current phase _emissionsPhase[_currentPhase].tokensAccrued = tokensTotal; // Move to next phase _currentPhase++; // Accrue the remaining amount of reward in `tokensAccrued` of next phase uint rewardNewPhase = proposedReward - rewardOldPhase; // Scale the remaining reward by the reward rate of the new phase rewardNewPhase = rewardNewPhase * _emissionsPhase[_currentPhase].rewardRate / _emissionsPhase[_currentPhase-1].rewardRate; _emissionsPhase[_currentPhase].tokensAccrued = rewardNewPhase; // Store the amount of claimable emissions for the user _claimableEmissions[account] += rewardOldPhase + rewardNewPhase; }else { // Accrue the full amount of reward in `tokensAccrued` of the current phase _emissionsPhase[_currentPhase].tokensAccrued += proposedReward; // Store the amount of claimable emissions for the user _claimableEmissions[account] += proposedReward; } } }
//SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IFixedRateMarket.sol"; import "../libraries/QTypes.sol"; interface IQAdmin is IAccessControlUpgradeable { /// @notice Emitted when a new FixedRateMarket is deployed event CreateFixedRateMarket(address indexed marketAddress, address indexed tokenAddress, uint maturity); /// @notice Emitted when a new `Asset` is added event AddAsset( address indexed tokenAddress, bool isYieldBearing, address oracleFeed, uint collateralFactor, uint marketFactor); /// @notice Emitted when setting `_qollateralManager` event SetQollateralManager(address qollateralManagerAddress); /// @notice Emitted when setting `_stakingEmissionsQontroller` event SetStakingEmissionsQontroller(address stakingEmissionsQontrollerAddress); /// @notice Emitted when setting `_tradingEmissionsQontroller` event SetTradingEmissionsQontroller(address tradingEmissionsQontrollerAddress); /// @notice Emitted when setting `_feeEmissionsQontroller` event SetFeeEmissionsQontroller(address feeEmissionsQontrollerAddress); /// @notice Emitted when setting `_veQoda` event SetVeQoda(address veQodaAddress); /// @notice Emitted when setting `collateralFactor` event SetCollateralFactor(address indexed tokenAddress, uint oldValue, uint newValue); /// @notice Emitted when setting `marketFactor` event SetMarketFactor(address indexed tokenAddress, uint oldValue, uint newValue); /// @notice Emitted when setting `minQuoteSize` event SetMinQuoteSize(address indexed tokenAddress, uint oldValue, uint newValue); /// @notice Emitted when `_initCollateralRatio` gets updated event SetInitCollateralRatio(uint oldValue, uint newValue); /// @notice Emitted when `_closeFactor` gets updated event SetCloseFactor(uint oldValue, uint newValue); /// @notice Emitted when `_repaymentGracePeriod` gets updated event SetRepaymentGracePeriod(uint oldValue, uint newValue); /// @notice Emitted when `_maturityGracePeriod` gets updated event SetMaturityGracePeriod(uint oldValue, uint newValue); /// @notice Emitted when `_liquidationIncentive` gets updated event SetLiquidationIncentive(uint oldValue, uint newValue); /// @notice Emitted when `_protocolFee` gets updated event SetProtocolFee(uint oldValue, uint newValue); /// @notice Emitted when `creditLimit` gets updated event SetCreditLimit(address accountAddress, uint oldValue, uint newValue); /** ADMIN FUNCTIONS **/ /// @notice Call upon initialization after deploying `QollateralManager` contract /// @param qollateralManagerAddress Address of `QollateralManager` deployment function _setQollateralManager(address qollateralManagerAddress) external; /// @notice Call upon initialization after deploying `StakingEmissionsQontroller` contract /// @param stakingEmissionsQontrollerAddress Address of `StakingEmissionsQontroller` deployment function _setStakingEmissionsQontroller(address stakingEmissionsQontrollerAddress) external; /// @notice Call upon initialization after deploying `TradingEmissionsQontroller` contract /// @param tradingEmissionsQontrollerAddress Address of `TradingEmissionsQontroller` deployment function _setTradingEmissionsQontroller(address tradingEmissionsQontrollerAddress) external; /// @notice Call upon initialization after deploying `FeeEmissionsQontroller` contract /// @param feeEmissionsQontroller Address of `FeeEmissionsQontroller` deployment function _setFeeEmissionsQontroller(address feeEmissionsQontroller) external; /// @notice Call upon initialization after deploying `veQoda` contract /// @param veQodaAddress Address of `veQoda` deployment function _setVeQoda(address veQodaAddress) external; /// @notice Call to adjust allowed limit in USD for given address to do uncollateralized borrow /// Note that if credit limit is lowered, there might be chance where user's loan is subjected to /// instant liquidations. So it's crucial to notify the user in advance before attempting the action. /// @param accountAddress accoutn for credit limit adjustment /// @param creditLimit_ new credit limit in USD, scaled by 1e6 function _setCreditLimit(address accountAddress, uint creditLimit_) external; /// @notice Admin function for adding new Assets. An Asset must be added before it /// can be used as collateral or borrowed. Note: We can create functionality for /// allowing borrows of a token but not using it as collateral by setting /// `collateralFactor` to zero. /// @param token ERC20 token corresponding to the Asset /// @param isYieldBearing True if token bears interest (eg aToken, cToken, mToken, etc) /// @param underlying Address of the underlying token /// @param oracleFeed Chainlink price feed address /// @param collateralFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets /// @param marketFactor 0.0 to 1.0 (scaled to 1e8) for premium on risky borrows function _addAsset( IERC20 token, bool isYieldBearing, address underlying, address oracleFeed, uint collateralFactor, uint marketFactor ) external; /// @notice Adds a new `FixedRateMarket` contract into the internal mapping of /// whitelisted market addresses /// @param market New `FixedRateMarket` contract function _addFixedRateMarket(IFixedRateMarket market) external; /// @notice Update the `collateralFactor` for a given `Asset` /// @param token ERC20 token corresponding to the Asset /// @param collateralFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets function _setCollateralFactor(IERC20 token, uint collateralFactor) external; /// @notice Update the `marketFactor` for a given `Asset` /// @param token Address of the token corresponding to the Asset /// @param marketFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets function _setMarketFactor(IERC20 token, uint marketFactor) external; /// @notice Set the minimum quote size for a particular `FixedRateMarket` /// @param market Address of the `FixedRateMarket` contract /// @param minQuoteSize_ Size in PV terms, local currency function _setMinQuoteSize(IFixedRateMarket market, uint minQuoteSize_) external; /// @notice Set the global initial collateral ratio /// @param initCollateralRatio_ New collateral ratio value function _setInitCollateralRatio(uint initCollateralRatio_) external; /// @notice Set the global close factor /// @param closeFactor_ New close factor value function _setCloseFactor(uint closeFactor_) external; /// @notice Set the global repayment grace period /// @param repaymentGracePeriod_ New repayment grace period function _setRepaymentGracePeriod(uint repaymentGracePeriod_) external; /// @notice Set the global maturity grace period /// @param maturityGracePeriod_ New maturity grace period function _setMaturityGracePeriod(uint maturityGracePeriod_) external; /// @notice Set the global liquidation incetive /// @param liquidationIncentive_ New liquidation incentive value function _setLiquidationIncentive(uint liquidationIncentive_) external; /// @notice Set the global annualized protocol fees for each market in basis points /// @param market Address of the `FixedRateMarket` contract /// @param protocolFee_ New protocol fee value (scaled to 1e4) function _setProtocolFee(IFixedRateMarket market, uint protocolFee_) external; /// @notice Set the global threshold in USD for protocol fee transfer /// @param thresholdUSD_ New threshold USD value (scaled by 1e6) function _setThresholdUSD(uint thresholdUSD_) external; /** VIEW FUNCTIONS **/ function ADMIN_ROLE() external view returns(bytes32); function MARKET_ROLE() external view returns(bytes32); function MINTER_ROLE() external view returns(bytes32); function VETOKEN_ROLE() external view returns(bytes32); /// @notice Get the address of the `QollateralManager` contract function qollateralManager() external view returns(address); /// @notice Get the address of the `QPriceOracle` contract function qPriceOracle() external view returns(address); /// @notice Get the address of the `StakingEmissionsQontroller` contract function stakingEmissionsQontroller() external view returns(address); /// @notice Get the address of the `TradingEmissionsQontroller` contract function tradingEmissionsQontroller() external view returns(address); /// @notice Get the address of the `FeeEmissionsQontroller` contract function feeEmissionsQontroller() external view returns(address); /// @notice Get the address of the `veQoda` contract function veQoda() external view returns(address); /// @notice Get the credit limit with associated address, scaled by 1e6 function creditLimit(address accountAddress) external view returns(uint); /// @notice Gets the `Asset` mapped to the address of a ERC20 token /// @param token ERC20 token /// @return QTypes.Asset Associated `Asset` function assets(IERC20 token) external view returns(QTypes.Asset memory); /// @notice Get all enabled `Asset`s /// @return address[] iterable list of enabled `Asset`s function allAssets() external view returns(address[] memory); /// @notice Gets the `CollateralFactor` associated with a ERC20 token /// @param token ERC20 token /// @return uint Collateral Factor, scaled by 1e8 function collateralFactor(IERC20 token) external view returns(uint); /// @notice Gets the `MarketFactor` associated with a ERC20 token /// @param token ERC20 token /// @return uint Market Factor, scaled by 1e8 function marketFactor(IERC20 token) external view returns(uint); /// @notice Gets the `maturities` associated with a ERC20 token /// @param token ERC20 token /// @return uint[] array of UNIX timestamps (in seconds) of the maturity dates function maturities(IERC20 token) external view returns(uint[] memory); /// @notice Get the MToken market corresponding to any underlying ERC20 /// tokenAddress => mTokenAddress function underlyingToMToken(IERC20 token) external view returns(address); /// @notice Gets the address of the `FixedRateMarket` contract /// @param token ERC20 token /// @param maturity UNIX timestamp of the maturity date /// @return IFixedRateMarket Address of `FixedRateMarket` contract function fixedRateMarkets(IERC20 token, uint maturity) external view returns(IFixedRateMarket); /// @notice Check whether an address is a valid FixedRateMarket address. /// Can be used for checks for inter-contract admin/restricted function call. /// @param market `FixedRateMarket` contract /// @return bool True if valid false otherwise function isMarketEnabled(IFixedRateMarket market) external view returns(bool); function minQuoteSize(IFixedRateMarket market) external view returns(uint); function minCollateralRatio() external view returns(uint); function initCollateralRatio() external view returns(uint); function closeFactor() external view returns(uint); function repaymentGracePeriod() external view returns(uint); function maturityGracePeriod() external view returns(uint); function liquidationIncentive() external view returns(uint); /// @notice Annualized protocol fee in basis points, scaled by 1e4 function protocolFee(IFixedRateMarket market) external view returns(uint); /// @notice threshold in USD where protocol fee from each market will be transferred into `FeeEmissionsQontroller` /// once this amount is reached, scaled by 1e6 function thresholdUSD() external view returns(uint); /// @notice 2**256 - 1 function UINT_MAX() external pure returns(uint); /// @notice Generic mantissa corresponding to ETH decimals function MANTISSA_DEFAULT() external pure returns(uint); /// @notice Mantissa for stablecoins function MANTISSA_STABLECOIN() external pure returns(uint); /// @notice Mantissa for collateral ratio function MANTISSA_COLLATERAL_RATIO() external pure returns(uint); /// @notice `assetFactor` and `marketFactor` have up to 8 decimal places precision function MANTISSA_FACTORS() external pure returns(uint); /// @notice Basis points have 4 decimal place precision function MANTISSA_BPS() external pure returns(uint); /// @notice Staked Qoda has 6 decimal place precision function MANTISSA_STAKING() external pure returns(uint); /// @notice `collateralFactor` cannot be above 1.0 function MAX_COLLATERAL_FACTOR() external pure returns(uint); /// @notice `marketFactor` cannot be above 1.0 function MAX_MARKET_FACTOR() external pure returns(uint); /// @notice version number of this contract, will be bumped upon contractual change function VERSION_NUMBER() external pure returns(string memory); }
//SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; interface ITradingEmissionsQontroller { /** ACCESS CONTROLLED FUNCTIONS **/ /// @notice Use the fees generated (in USD) as basis to calculate how much /// token reward to disburse for trading volumes. Only `FixedRateMarket` /// contracts may call this function. /// @param borrower Address of the borrower /// @param lender Address of the lender /// @param feeUSD Fees generated (in USD, scaled to 1e6) function updateRewards(address borrower, address lender, uint feeUSD) external; /** USER INTERFACE **/ /// @notice Mint the unclaimed rewards to user and reset their claimable emissions function claimEmissions() external; /** VIEW FUNCTIONS **/ /// @notice Checks the amount of unclaimed trading rewards that the user can claim /// @param account Address of the user /// @return uint Amount of QODA token rewards the user may claim function claimableEmissions(address account) external view returns(uint); function qAdmin() external view returns(address); function qodaERC20() external view returns(address); function numPhases() external view returns(uint); function currentPhase() external view returns(uint); function totalAllocation() external view returns(uint); function emissionsPhase(uint phase) external view returns(uint, uint, uint); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IQodaERC20 is IERC20 { /// @notice Mints tokens to a recipient, as long as it is under the /// supply cap. Reverts if the caller does not have the minter role. /// @param recipient Account to mint tokens to /// @param amount Amount of tokens to mint function mint(address recipient, uint amount) external returns(bool); function supplyCap() external view returns(uint); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
//SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IFixedRateMarket is IERC20Upgradeable, IERC20MetadataUpgradeable { /// @notice Emitted when a borrower repays borrow. /// Boolean flag `withQTokens`= true if repaid via qTokens, false otherwise. event RepayBorrow(address indexed borrower, uint amount, bool withQTokens); /// @notice Emitted when a borrower is liquidated event LiquidateBorrow( address indexed borrower, address indexed liquidator, uint amount, address collateralTokenAddress, uint reward ); /// @notice Emitted when a borrower and lender are matched for a fixed rate loan event FixedRateLoan( bytes32 indexed quoteId, address indexed borrower, address indexed lender, uint amountPV, uint amountFV, uint feeIncurred); /// @notice Emitted when an account cancels their Quote event CancelQuote(address indexed account, uint nonce); /// @notice Emitted when an account redeems their qTokens event RedeemQTokens(address indexed account, uint amount); /** USER INTERFACE **/ /// @notice Execute against Quote as a borrower. /// @param amountPV Amount that the borrower wants to execute as PV /// @param lender Account of the lender /// @param quoteType *Lender's* type preference, 0 for PV+APR, 1 for FV+APR /// @param quoteExpiryTime Timestamp after which the quote is no longer valid /// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052) /// @param cashflow Can be PV or FV depending on `quoteType` /// @param nonce For uniqueness of signature /// @param signature signed hash of the Quote message /// @return uint, uint Loan amount (`amountPV`) and repayment amount (`amountFV`) function borrow( uint amountPV, address lender, uint8 quoteType, uint64 quoteExpiryTime, uint64 APR, uint cashflow, uint nonce, bytes memory signature ) external returns(uint, uint); /// @notice Execute against Quote as a lender. /// @param amountPV Amount that the lender wants to execute as PV /// @param borrower Account of the borrower /// @param quoteType *Borrower's* type preference, 0 for PV+APR, 1 for FV+APR /// @param quoteExpiryTime Timestamp after which the quote is no longer valid /// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052) /// @param cashflow Can be PV or FV depending on `quoteType` /// @param nonce For uniqueness of signature /// @param signature signed hash of the Quote message /// @return uint, uint Loan amount (`amountPV`) and repayment amount (`amountFV`) function lend( uint amountPV, address borrower, uint8 quoteType, uint64 quoteExpiryTime, uint64 APR, uint cashflow, uint nonce, bytes memory signature ) external returns(uint, uint); /// @notice Borrower will make repayments to the smart contract, which /// holds the value in escrow until maturity to release to lenders. /// @param amount Amount to repay /// @return uint Remaining account borrow amount function repayBorrow(uint amount) external returns(uint); /// @notice By setting the nonce in `_voidNonces` to true, this is equivalent to /// invalidating the Quote (i.e. cancelling the quote) /// param nonce Nonce of the Quote to be cancelled function cancelQuote(uint nonce) external; /// @notice This function allows net lenders to redeem qTokens for the /// underlying token. Redemptions may only be permitted after loan maturity /// plus `_maturityGracePeriod`. The public interface redeems specified amount /// of qToken from existing balance. /// @param amount Amount of qTokens to redeem /// @return uint Amount of qTokens redeemed function redeemQTokens(uint amount) external returns(uint); /// @notice This function allows net lenders to redeem qTokens for the /// underlying token. Redemptions may only be permitted after loan maturity /// plus `_maturityGracePeriod`. The public interface redeems the entire qToken /// balance. /// @return uint Amount of qTokens redeemed function redeemAvailableQTokens() external returns(uint); /// @notice Get amount of qTokens user can redeem based on current loan repayment ratio /// @return uint amount of qTokens user can redeem function redeemableQTokens() external view returns(uint); /// @notice If an account is in danger of being undercollateralized (i.e. /// collateralRatio < 1.0) or has not repaid past maturity plus `_repaymentGracePeriod`, /// any user may liquidate that account by paying back the loan on behalf of the account. /// In return, the liquidator receives collateral belonging to the account equal in value to /// the repayment amount in USD plus the liquidation incentive amount as a bonus. /// @param borrower Address of account that is undercollateralized /// @param amount Amount to repay on behalf of account /// @param collateralToken Liquidator's choice of which currency to be paid in function liquidateBorrow( address borrower, uint amount, IERC20 collateralToken ) external; /** VIEW FUNCTIONS **/ /// @notice Get the address of the `QollateralManager` /// @return address function qollateralManager() external view returns(address); /// @notice Get the address of the ERC20 token which the loan will be denominated /// @return IERC20 function underlyingToken() external view returns(IERC20); /// @notice Get the UNIX timestamp (in seconds) when the market matures /// @return uint function maturity() external view returns(uint); /// @notice Get the minimum quote size for this market /// @return uint Minimum quote size, in PV terms, local currency function minQuoteSize() external view returns(uint); /// @notice True if a nonce for a Quote is voided, false otherwise. /// Used for checking if a Quote is a duplicated. /// @param account Account to query /// @param nonce Nonce to query /// @return bool True if used, false otherwise function isNonceVoid(address account, uint nonce) external view returns(bool); /// @notice Get the total balance of borrows by user /// @param account Account to query /// @return uint Borrows function accountBorrows(address account) external view returns(uint); /// @notice Get the current total partial fill for a Quote /// @param quoteId ID of the Quote - this is the keccak256 hash of the signature /// @return uint Partial fill function quoteFill(bytes32 quoteId) external view returns(uint); /// @notice Get the `protocolFee` associated with this market /// @return uint annualized protocol fee, scaled by 1e4 function protocolFee() external view returns(uint); /// @notice Get the `protocolFee` associated with this market, prorated by time till maturity /// @param amount loan amount /// @param timeNow block timestamp for calculating time till maturity /// @return uint prorated protocol fee, scaled by 1e4 function proratedProtocolFee(uint amount, uint timeNow) external view returns(uint); /// @notice Get the `protocolFee` associated with this market, prorated by time till maturity from now /// @param amount loan amount /// @return uint prorated protocol fee, scaled by 1e4 function proratedProtocolFeeNow(uint amount) external view returns(uint); /// @notice Gets the current `redemptionRatio` where owned qTokens can be redeemed up to /// @return uint redemption ratio, scaled by 1e18 function redemptionRatio() external view returns(uint); /// @notice Tokens redeemed across all users so far /// @return uint redeemed amount of qToken function tokensRedeemedTotal() external view returns(uint); /// @notice Get total protocol fee accrued in this market so far, in local currency /// @return uint accrued fee function totalAccruedFees() external view returns(uint); }
//SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; library QTypes { /// @notice Contains all the details of an Asset. Assets must be defined /// before they can be used as collateral. /// @member isEnabled True if an asset is defined, false otherwise /// @member isYieldBearing True if token bears interest (eg aToken, cToken, mToken, etc) /// @member underlying Address of the underlying token /// @member oracleFeed Address of the corresponding chainlink oracle feed /// @member collateralFactor 0.0 to 1.0 (scaled to 1e8) for discounting risky assets /// @member marketFactor 0.0 1.0 for premium on risky borrows /// @member maturities Iterable storage for all enabled maturities struct Asset { bool isEnabled; bool isYieldBearing; address underlying; address oracleFeed; uint collateralFactor; uint marketFactor; uint[] maturities; } /// @notice Contains all the fields of a published Quote /// @notice quoteId ID of the quote - this is the keccak256 hash of signature /// @param marketAddress Address of `FixedRateLoanMarket` contract /// @param quoter Account of the Quoter /// @param quoteType 0 for PV+APR, 1 for FV+APR /// @param side 0 if Quoter is borrowing, 1 if Quoter is lending /// @param quoteExpiryTime Timestamp after which the quote is no longer valid /// @param APR In decimal form scaled by 1e4 (ex. 10.52% = 1052) /// @param cashflow Can be PV or FV depending on `quoteType` /// @param nonce For uniqueness of signature /// @param signature Signed hash of the Quote message struct Quote { bytes32 quoteId; address marketAddress; address quoter; uint8 quoteType; uint8 side; uint64 quoteExpiryTime; //if 0, then quote never expires uint64 APR; uint cashflow; uint nonce; bytes signature; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"qodaERC20Address","type":"address"},{"internalType":"address","name":"qAdminAddress","type":"address"},{"internalType":"uint256[]","name":"rewardRate_","type":"uint256[]"},{"internalType":"uint256[]","name":"tokensTotal_","type":"uint256[]"},{"internalType":"uint256","name":"numPhases_","type":"uint256"},{"internalType":"uint256","name":"totalAllocation_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimEmissions","type":"event"},{"inputs":[],"name":"claimEmissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"claimableEmissions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPhase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"phase","type":"uint256"}],"name":"emissionsPhase","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numPhases","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"qAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"qodaERC20","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"uint256","name":"feeUSD","type":"uint256"}],"name":"updateRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162000b5a38038062000b5a8339810160408190526200003491620002f1565b818451148015620000455750818351145b620000975760405162461bcd60e51b815260206004820152601460248201527f54455132206c656e677468206d69736d6174636800000000000000000000000060448201526064015b60405180910390fd5b600180546001600160a01b038089166001600160a01b03199283161790925560008054928816929091169190911781556002839055600381905560048290555b828110156200017457604051806060016040528086838151811062000100576200010062000393565b602002602001015181526020016000815260200185838151811062000129576200012962000393565b602090810291909101810151909152600083815260068252604090819020835181559183015160018301559190910151600290910155806200016b81620003bf565b915050620000d7565b506000805b600254811015620001b957600081815260066020526040902060020154620001a29083620003dd565b915080620001b081620003bf565b91505062000179565b5080600454146200020d5760405162461bcd60e51b815260206004820152601660248201527f5445513020696e636f727265637420726577617264730000000000000000000060448201526064016200008e565b50505050505050620003f8565b80516001600160a01b03811681146200023257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200025f57600080fd5b815160206001600160401b03808311156200027e576200027e62000237565b8260051b604051601f19603f83011681018181108482111715620002a657620002a662000237565b604052938452858101830193838101925087851115620002c557600080fd5b83870191505b84821015620002e657815183529183019190830190620002cb565b979650505050505050565b60008060008060008060c087890312156200030b57600080fd5b62000316876200021a565b955062000326602088016200021a565b60408801519095506001600160401b03808211156200034457600080fd5b620003528a838b016200024d565b955060608901519150808211156200036957600080fd5b506200037889828a016200024d565b9350506080870151915060a087015190509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415620003d657620003d6620003a9565b5060010190565b60008219821115620003f357620003f3620003a9565b500190565b61075280620004086000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063a591a6f411610066578063a591a6f414610107578063bf5d433214610111578063c0cb9acf14610136578063ce4013081461015f578063fd4368311461017057600080fd5b8063055ad42e146100985780630e101b1e146100af57806379203dc4146100f75780638b5a6d7e146100ff575b600080fd5b6003545b6040519081526020015b60405180910390f35b6100dc6100bd3660046105ad565b6000908152600660205260409020805460018201546002909201549092565b604080519384526020840192909252908201526060016100a6565b60045461009c565b60025461009c565b61010f610183565b005b6001546001600160a01b03165b6040516001600160a01b0390911681526020016100a6565b61009c6101443660046105e2565b6001600160a01b031660009081526005602052604090205490565b6000546001600160a01b031661011e565b61010f61017e366004610604565b6102b9565b33600090815260056020526040902054806101e55760405162461bcd60e51b815260206004820152601c60248201527f5445513320726577617264206d75737420626520706f7369746976650000000060448201526064015b60405180910390fd5b3360008181526005602052604080822091909155600154905163a9059cbb60e01b81526004810192909252602482018390526001600160a01b03169063a9059cbb90604401602060405180830381600087803b15801561024457600080fd5b505af1158015610258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027c9190610640565b5060408051338152602081018390527f0d962b580b08e94b6cd0d0ed9da8371103adfad40f998c68bda1f58c7a97ffa4910160405180910390a150565b60005460408051633e27ec9b60e01b815290516001600160a01b03909216916391d14854918391633e27ec9b91600480820192602092909190829003018186803b15801561030657600080fd5b505afa15801561031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033e9190610662565b6040516001600160e01b031960e084901b168152600481019190915233602482015260440160206040518083038186803b15801561037b57600080fd5b505afa15801561038f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b39190610640565b6103f25760405162461bcd60e51b815260206004820152601060248201526f1511544c481bdb9b1e481b585c9ad95d60821b60448201526064016101dc565b6103fc838261040b565b610406828261040b565b505050565b600254600354141561041b575050565b6003546000908152600660205260408120600281015460018201549154909290620f42409061044b908690610691565b61045591906106b0565b90508261046283836106d2565b111561054f57600061047483856106ea565b600380546000908152600660205260408120600101879055815492935061049a83610701565b90915550600090506104ac82846106ea565b90506006600060016003546104c191906106ea565b815260208082019290925260409081016000908120546003548252600690935220546104ed9083610691565b6104f791906106b0565b6003546000908152600660205260409020600101819055905061051a81836106d2565b6001600160a01b038816600090815260056020526040812080549091906105429084906106d2565b909155506105a692505050565b600354600090815260066020526040812060010180548392906105739084906106d2565b90915550506001600160a01b038516600090815260056020526040812080548392906105a09084906106d2565b90915550505b5050505050565b6000602082840312156105bf57600080fd5b5035919050565b80356001600160a01b03811681146105dd57600080fd5b919050565b6000602082840312156105f457600080fd5b6105fd826105c6565b9392505050565b60008060006060848603121561061957600080fd5b610622846105c6565b9250610630602085016105c6565b9150604084013590509250925092565b60006020828403121561065257600080fd5b815180151581146105fd57600080fd5b60006020828403121561067457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156106ab576106ab61067b565b500290565b6000826106cd57634e487b7160e01b600052601260045260246000fd5b500490565b600082198211156106e5576106e561067b565b500190565b6000828210156106fc576106fc61067b565b500390565b60006000198214156107155761071561067b565b506001019056fea264697066735822122079ce79efe074fb8b227d4710b7f8a5eb70a325a73f2ece1030754bd2eeb0951164736f6c63430008090033000000000000000000000000329602da21a8d686fa192e13e00af0bd23c74f730000000000000000000000002dedeb6310d209f9a89ab3b0941ae2c6a424e2c100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000001851b1318cbc171700000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000120d4da7b0bd14000000000000000000000000000000000000000000000000000d8d726b7177a8000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000c28d898c65e0b8b8000000000000000000000000000000000000000000000000c28d898c65e0b8b800000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|