文件 1 的 6:ERC20Helper.sol
pragma solidity ^0.8.7;
import { IERC20Like } from "./interfaces/IERC20Like.sol";
library ERC20Helper {
function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) {
return _call(token_, abi.encodeWithSelector(IERC20Like.transfer.selector, to_, amount_));
}
function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) {
return _call(token_, abi.encodeWithSelector(IERC20Like.transferFrom.selector, from_, to_, amount_));
}
function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) {
if (!_call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, uint256(0)))) return false;
if (amount_ == uint256(0)) return true;
return _call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, amount_));
}
function _call(address token_, bytes memory data_) private returns (bool success_) {
if (token_.code.length == uint256(0)) return false;
bytes memory returnData;
( success_, returnData ) = token_.call(data_);
return success_ && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
}
}
文件 2 的 6:IERC20.sol
pragma solidity ^0.8.7;
interface IERC20 {
event Approval(address indexed owner_, address indexed spender_, uint256 amount_);
event Transfer(address indexed owner_, address indexed recipient_, uint256 amount_);
function approve(address spender_, uint256 amount_) external returns (bool success_);
function decreaseAllowance(address spender_, uint256 subtractedAmount_) external returns (bool success_);
function increaseAllowance(address spender_, uint256 addedAmount_) external returns (bool success_);
function permit(address owner_, address spender_, uint amount_, uint deadline_, uint8 v_, bytes32 r_, bytes32 s_) external;
function transfer(address recipient_, uint256 amount_) external returns (bool success_);
function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
function allowance(address owner_, address spender_) external view returns (uint256 allowance_);
function balanceOf(address account_) external view returns (uint256 balance_);
function decimals() external view returns (uint8 decimals_);
function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator_);
function name() external view returns (string memory name_);
function nonces(address owner_) external view returns (uint256 nonce_);
function PERMIT_TYPEHASH() external view returns (bytes32 permitTypehash_);
function symbol() external view returns (string memory symbol_);
function totalSupply() external view returns (uint256 totalSupply_);
}
文件 3 的 6:IERC20Like.sol
pragma solidity ^0.8.7;
interface IERC20Like {
function approve(address spender_, uint256 amount_) external returns (bool success_);
function transfer(address recipient_, uint256 amount_) external returns (bool success_);
function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
}
文件 4 的 6:IMapleLoanFeeManager.sol
pragma solidity 0.8.7;
interface IMapleLoanFeeManager {
event FeeTermsUpdated(address loan_, uint256 delegateOriginationFee_, uint256 delegateServiceFee_);
event OriginationFeesPaid(address loan_, uint256 delegateOriginationFee_, uint256 platformOriginationFee_);
event PlatformServiceFeeUpdated(address loan_, uint256 platformServiceFee_);
event PartialRefinanceServiceFeesUpdated(address loan_, uint256 partialPlatformServiceFee_, uint256 partialDelegateServiceFee_);
event ServiceFeesPaid(address loan_, uint256 delegateServiceFee_, uint256 partialRefinanceDelegateServiceFee_, uint256 platformServiceFee_, uint256 partialRefinancePlatformServiceFee_);
function payServiceFees(address asset_, uint256 numberOfPayments_) external returns (uint256 feePaid_);
function payOriginationFees(address asset_, uint256 principalRequested_) external returns (uint256 feePaid_);
function updateDelegateFeeTerms(uint256 delegateOriginationFee_, uint256 delegateServiceFee_) external;
function updateRefinanceServiceFees(uint256 principalRequested_, uint256 timeSinceLastDueDate_) external;
function updatePlatformServiceFee(uint256 principalRequested_, uint256 paymentInterval_) external;
function delegateOriginationFee(address loan_) external view returns (uint256 delegateOriginationFee_);
function delegateServiceFee(address loan_) external view returns (uint256 delegateServiceFee_);
function delegateRefinanceServiceFee(address loan_) external view returns (uint256 delegateRefinanceServiceFee_);
function getDelegateServiceFeesForPeriod(address loan_, uint256 interval_) external view returns (uint256 delegateServiceFee_);
function getOriginationFees(address loan_, uint256 principalRequested_) external view returns (uint256 originationFees_);
function getPlatformOriginationFee(address loan_, uint256 principalRequested_) external view returns (uint256 platformOriginationFee_);
function getPlatformServiceFeeForPeriod(address loan_, uint256 principalRequested_, uint256 interval_) external view returns (uint256 platformServiceFee_);
function getServiceFeeBreakdown(address loan_, uint256 numberOfPayments_) external view returns (
uint256 delegateServiceFee_,
uint256 delegateRefinanceFee_,
uint256 platformServiceFee_,
uint256 platformRefinanceFee_
);
function getServiceFees(address loan_, uint256 numberOfPayments_) external view returns (uint256 serviceFees_);
function getServiceFeesForPeriod(address loan_, uint256 interval_) external view returns (uint256 serviceFees_);
function globals() external view returns (address globals_);
function platformRefinanceServiceFee(address loan_) external view returns (uint256 platformRefinanceServiceFee_);
function platformServiceFee(address loan_) external view returns (uint256 platformServiceFee);
}
文件 5 的 6:Interfaces.sol
pragma solidity 0.8.7;
interface IMapleGlobalsLike {
function governor() external view returns (address governor_);
function isBorrower(address account_) external view returns (bool isBorrower_);
function isCollateralAsset(address collateralAsset_) external view returns (bool isCollateralAsset_);
function isFactory(bytes32 factoryId_, address factory_) external view returns (bool isValid_);
function isPoolAsset(address poolAsset_) external view returns (bool isValid_);
function mapleTreasury() external view returns (address governor_);
function platformOriginationFeeRate(address pool_) external view returns (uint256 platformOriginationFeeRate_);
function platformServiceFeeRate(address pool_) external view returns (uint256 platformFee_);
function protocolPaused() external view returns (bool protocolPaused_);
function securityAdmin() external view returns (address securityAdmin_);
}
interface ILenderLike {
function claim(uint256 principal_, uint256 interest_, uint256 previousPaymentDueDate_, uint256 nextPaymentDueDate_) external;
function factory() external view returns (address factory_);
}
interface ILoanLike {
function factory() external view returns (address factory_);
function fundsAsset() external view returns (address asset_);
function lender() external view returns (address lender_);
function paymentInterval() external view returns (uint256 paymentInterval_);
function paymentsRemaining() external view returns (uint256 paymentsRemaining_);
function principal() external view returns (uint256 principal_);
function principalRequested() external view returns (uint256 principalRequested_);
}
interface ILoanManagerLike {
function owner() external view returns (address owner_);
function poolManager() external view returns (address poolManager_);
}
interface IMapleFeeManagerLike {
function updateDelegateFeeTerms(uint256 delegateOriginationFee_, uint256 delegateServiceFee_) external;
function updatePlatformServiceFee(uint256 principalRequested_, uint256 paymentInterval_) external;
}
interface IMapleProxyFactoryLike {
function isInstance(address instance_) external view returns (bool isInstance_);
function mapleGlobals() external view returns (address mapleGlobals_);
}
interface IPoolManagerLike {
function poolDelegate() external view returns (address poolDelegate_);
}
文件 6 的 6:MapleLoanFeeManager.sol
pragma solidity 0.8.7;
import { IERC20 } from "../modules/erc20/contracts/interfaces/IERC20.sol";
import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol";
import {
IMapleGlobalsLike,
ILoanLike,
ILoanManagerLike,
IPoolManagerLike
} from "./interfaces/Interfaces.sol";
import { IMapleLoanFeeManager } from "./interfaces/IMapleLoanFeeManager.sol";
contract MapleLoanFeeManager is IMapleLoanFeeManager {
uint256 internal constant HUNDRED_PERCENT = 100_0000;
address public override globals;
mapping(address => uint256) public override delegateOriginationFee;
mapping(address => uint256) public override delegateRefinanceServiceFee;
mapping(address => uint256) public override delegateServiceFee;
mapping(address => uint256) public override platformServiceFee;
mapping(address => uint256) public override platformRefinanceServiceFee;
constructor(address globals_) {
globals = globals_;
}
function payOriginationFees(address asset_, uint256 principalRequested_) external override returns (uint256 feePaid_) {
uint256 delegateOriginationFee_ = delegateOriginationFee[msg.sender];
uint256 platformOriginationFee_ = _getPlatformOriginationFee(msg.sender, principalRequested_);
_transferTo(asset_, _getPoolDelegate(msg.sender), delegateOriginationFee_, "MLFM:POF:PD_TRANSFER");
_transferTo(asset_, _getTreasury(), platformOriginationFee_, "MLFM:POF:TREASURY_TRANSFER");
feePaid_ = delegateOriginationFee_ + platformOriginationFee_;
emit OriginationFeesPaid(msg.sender, delegateOriginationFee_, platformOriginationFee_);
}
function payServiceFees(address asset_, uint256 numberOfPayments_) external override returns (uint256 feePaid_) {
(
uint256 delegateServiceFee_,
uint256 delegateRefinanceServiceFee_,
uint256 platformServiceFee_,
uint256 platformRefinanceServiceFee_
) = getServiceFeeBreakdown(msg.sender, numberOfPayments_);
feePaid_ = delegateServiceFee_ + delegateRefinanceServiceFee_ + platformServiceFee_ + platformRefinanceServiceFee_;
_transferTo(asset_, _getPoolDelegate(msg.sender), delegateServiceFee_ + delegateRefinanceServiceFee_, "MLFM:PSF:PD_TRANSFER");
_transferTo(asset_, _getTreasury(), platformServiceFee_ + platformRefinanceServiceFee_, "MLFM:PSF:TREASURY_TRANSFER");
delete delegateRefinanceServiceFee[msg.sender];
delete platformRefinanceServiceFee[msg.sender];
emit ServiceFeesPaid(msg.sender, delegateServiceFee_, delegateRefinanceServiceFee_, platformServiceFee_, platformRefinanceServiceFee_);
}
function updateDelegateFeeTerms(uint256 delegateOriginationFee_, uint256 delegateServiceFee_) external override {
delegateOriginationFee[msg.sender] = delegateOriginationFee_;
delegateServiceFee[msg.sender] = delegateServiceFee_;
emit FeeTermsUpdated(msg.sender, delegateOriginationFee_, delegateServiceFee_);
}
function updateRefinanceServiceFees(uint256 principalRequested_, uint256 timeSinceLastDueDate_) external override {
uint256 platformRefinanceServiceFee_ = getPlatformServiceFeeForPeriod(msg.sender, principalRequested_, timeSinceLastDueDate_);
uint256 delegateRefinanceServiceFee_ = getDelegateServiceFeesForPeriod(msg.sender, timeSinceLastDueDate_);
platformRefinanceServiceFee[msg.sender] += platformRefinanceServiceFee_;
delegateRefinanceServiceFee[msg.sender] += delegateRefinanceServiceFee_;
emit PartialRefinanceServiceFeesUpdated(msg.sender, platformRefinanceServiceFee_, delegateRefinanceServiceFee_);
}
function updatePlatformServiceFee(uint256 principalRequested_, uint256 paymentInterval_) external override {
uint256 platformServiceFee_ = getPlatformServiceFeeForPeriod(msg.sender, principalRequested_, paymentInterval_);
platformServiceFee[msg.sender] = platformServiceFee_;
emit PlatformServiceFeeUpdated(msg.sender, platformServiceFee_);
}
function getDelegateServiceFeesForPeriod(address loan_, uint256 interval_) public view override returns (uint256 delegateServiceFee_) {
uint256 paymentInterval = ILoanLike(loan_).paymentInterval();
delegateServiceFee_ = delegateServiceFee[loan_] * interval_ / paymentInterval;
}
function getPlatformOriginationFee(address loan_, uint256 principalRequested_) external view override returns (uint256 platformOriginationFee_) {
platformOriginationFee_ = _getPlatformOriginationFee(loan_, principalRequested_);
}
function getPlatformServiceFeeForPeriod(address loan_, uint256 principalRequested_, uint256 interval_) public view override returns (uint256 platformServiceFee_) {
uint256 platformServiceFeeRate_ = IMapleGlobalsLike(globals).platformServiceFeeRate(_getPoolManager(loan_));
platformServiceFee_ = principalRequested_ * platformServiceFeeRate_ * interval_ / 365 days / HUNDRED_PERCENT;
}
function getServiceFees(address loan_, uint256 numberOfPayments_) external view override returns (uint256 serviceFees_) {
(
uint256 delegateServiceFee_,
uint256 delegateRefinanceServiceFee_,
uint256 platformServiceFee_,
uint256 platformRefinanceServiceFee_
) = getServiceFeeBreakdown(loan_, numberOfPayments_);
serviceFees_ = delegateServiceFee_ + delegateRefinanceServiceFee_ + platformServiceFee_ + platformRefinanceServiceFee_;
}
function getServiceFeeBreakdown(address loan_, uint256 numberOfPayments_) public view override
returns (
uint256 delegateServiceFee_,
uint256 delegateRefinanceFee_,
uint256 platformServiceFee_,
uint256 platformRefinanceFee_
)
{
delegateServiceFee_ = delegateServiceFee[loan_] * numberOfPayments_;
platformServiceFee_ = platformServiceFee[loan_] * numberOfPayments_;
delegateRefinanceFee_ = delegateRefinanceServiceFee[loan_];
platformRefinanceFee_ = platformRefinanceServiceFee[loan_];
}
function getServiceFeesForPeriod(address loan_, uint256 interval_) external view override returns (uint256 serviceFee_) {
uint256 principalRequested = ILoanLike(loan_).principalRequested();
serviceFee_ = getDelegateServiceFeesForPeriod(loan_, interval_) + getPlatformServiceFeeForPeriod(loan_, principalRequested, interval_);
}
function getOriginationFees(address loan_, uint256 principalRequested_) external view override returns (uint256 originationFees_) {
originationFees_ = _getPlatformOriginationFee(loan_, principalRequested_) + delegateOriginationFee[loan_];
}
function _getAsset(address loan_) internal view returns (address asset_) {
return ILoanLike(loan_).fundsAsset();
}
function _getPlatformOriginationFee(address loan_, uint256 principalRequested_) internal view returns (uint256 platformOriginationFee_) {
uint256 platformOriginationFeeRate_ = IMapleGlobalsLike(globals).platformOriginationFeeRate(_getPoolManager(loan_));
uint256 loanTermLength_ = ILoanLike(loan_).paymentInterval() * ILoanLike(loan_).paymentsRemaining();
platformOriginationFee_ = platformOriginationFeeRate_ * principalRequested_ * loanTermLength_ / 365 days / HUNDRED_PERCENT;
}
function _getPoolManager(address loan_) internal view returns (address pool_) {
return ILoanManagerLike(ILoanLike(loan_).lender()).poolManager();
}
function _getPoolDelegate(address loan_) internal view returns (address poolDelegate_) {
return IPoolManagerLike(_getPoolManager(loan_)).poolDelegate();
}
function _getTreasury() internal view returns (address mapleTreasury_) {
return IMapleGlobalsLike(globals).mapleTreasury();
}
function _transferTo(address asset_, address destination_, uint256 amount_, string memory errorMessage_) internal {
require(destination_ != address(0), "MLFM:TT:ZERO_DESTINATION");
require(ERC20Helper.transferFrom(asset_, msg.sender, destination_, amount_), errorMessage_);
}
}
{
"compilationTarget": {
"modules/loan-v401/contracts/MapleLoanFeeManager.sol": "MapleLoanFeeManager"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":contract-test-utils/=modules/contract-test-utils/contracts/",
":debt-locker-v4/=modules/debt-locker-v4/contracts/",
":erc20-helper/=modules/withdrawal-manager/modules/erc20-helper/src/",
":erc20/=modules/erc20/",
":globals-v2/=modules/globals-v2/",
":liquidations/=modules/liquidations/contracts/",
":loan-v301/=modules/loan-v301/contracts/",
":loan-v302/=modules/loan-v302/contracts/",
":loan-v400/=modules/loan-v400/contracts/",
":loan-v401/=modules/loan-v401/contracts/",
":loan/=modules/debt-locker-v4/modules/loan/contracts/",
":maple-proxy-factory/=modules/withdrawal-manager/modules/maple-proxy-factory/",
":migration-helpers/=modules/migration-helpers/contracts/",
":non-transparent-proxy/=modules/migration-helpers/modules/non-transparent-proxy/",
":pool-v2/=modules/pool-v2/contracts/",
":proxy-factory/=modules/withdrawal-manager/modules/maple-proxy-factory/modules/proxy-factory/",
":withdrawal-manager/=modules/withdrawal-manager/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"globals_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loan_","type":"address"},{"indexed":false,"internalType":"uint256","name":"delegateOriginationFee_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delegateServiceFee_","type":"uint256"}],"name":"FeeTermsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loan_","type":"address"},{"indexed":false,"internalType":"uint256","name":"delegateOriginationFee_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"platformOriginationFee_","type":"uint256"}],"name":"OriginationFeesPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loan_","type":"address"},{"indexed":false,"internalType":"uint256","name":"partialPlatformServiceFee_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"partialDelegateServiceFee_","type":"uint256"}],"name":"PartialRefinanceServiceFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loan_","type":"address"},{"indexed":false,"internalType":"uint256","name":"platformServiceFee_","type":"uint256"}],"name":"PlatformServiceFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"loan_","type":"address"},{"indexed":false,"internalType":"uint256","name":"delegateServiceFee_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"partialRefinanceDelegateServiceFee_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"platformServiceFee_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"partialRefinancePlatformServiceFee_","type":"uint256"}],"name":"ServiceFeesPaid","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegateOriginationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegateRefinanceServiceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegateServiceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"interval_","type":"uint256"}],"name":"getDelegateServiceFeesForPeriod","outputs":[{"internalType":"uint256","name":"delegateServiceFee_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"principalRequested_","type":"uint256"}],"name":"getOriginationFees","outputs":[{"internalType":"uint256","name":"originationFees_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"principalRequested_","type":"uint256"}],"name":"getPlatformOriginationFee","outputs":[{"internalType":"uint256","name":"platformOriginationFee_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"principalRequested_","type":"uint256"},{"internalType":"uint256","name":"interval_","type":"uint256"}],"name":"getPlatformServiceFeeForPeriod","outputs":[{"internalType":"uint256","name":"platformServiceFee_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"numberOfPayments_","type":"uint256"}],"name":"getServiceFeeBreakdown","outputs":[{"internalType":"uint256","name":"delegateServiceFee_","type":"uint256"},{"internalType":"uint256","name":"delegateRefinanceFee_","type":"uint256"},{"internalType":"uint256","name":"platformServiceFee_","type":"uint256"},{"internalType":"uint256","name":"platformRefinanceFee_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"numberOfPayments_","type":"uint256"}],"name":"getServiceFees","outputs":[{"internalType":"uint256","name":"serviceFees_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"loan_","type":"address"},{"internalType":"uint256","name":"interval_","type":"uint256"}],"name":"getServiceFeesForPeriod","outputs":[{"internalType":"uint256","name":"serviceFee_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globals","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_","type":"address"},{"internalType":"uint256","name":"principalRequested_","type":"uint256"}],"name":"payOriginationFees","outputs":[{"internalType":"uint256","name":"feePaid_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset_","type":"address"},{"internalType":"uint256","name":"numberOfPayments_","type":"uint256"}],"name":"payServiceFees","outputs":[{"internalType":"uint256","name":"feePaid_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"platformRefinanceServiceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"platformServiceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"delegateOriginationFee_","type":"uint256"},{"internalType":"uint256","name":"delegateServiceFee_","type":"uint256"}],"name":"updateDelegateFeeTerms","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"principalRequested_","type":"uint256"},{"internalType":"uint256","name":"paymentInterval_","type":"uint256"}],"name":"updatePlatformServiceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"principalRequested_","type":"uint256"},{"internalType":"uint256","name":"timeSinceLastDueDate_","type":"uint256"}],"name":"updateRefinanceServiceFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]