文件 1 的 12:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 12:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function totalSupply() external view returns (uint256);
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}
文件 3 的 12:IERC20Permit.sol
pragma solidity 0.8.0;
interface IERC20Permit {
function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 4 的 12:IOracle.sol
pragma solidity ^0.8.0;
interface IOracle {
function getPriceUSD(address _asset) external view returns (uint256 price);
function getPricesUSD(address[] calldata _assets) external view returns (uint256[] memory prices);
function updateFeedETH(address _asset, address _feed) external;
function updateFeedUSD(address _asset, address _feed) external;
function setSushiKeeperOracle(address _sushiOracle) external;
function setUniKeeperOracle(address _uniOracle) external;
}
文件 5 的 12:IRERC20.sol
pragma solidity ^0.8.0;
import "../ERC20/IERC20.sol";
interface IRERC20 is IERC20 {
function mint(address _account, uint256 _amount) external returns (bool);
function burnByRuler(address _account, uint256 _amount) external returns (bool);
}
文件 6 的 12:IRouter.sol
pragma solidity ^0.8.0;
interface IRouter {
function getAmountsOut(uint256 amountIn, address[] memory path) external view returns (uint256[] memory amounts);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
external
returns (uint256[] memory amounts);
}
文件 7 的 12:IRulerCore.sol
pragma solidity ^0.8.0;
import "./IRERC20.sol";
import "./IOracle.sol";
interface IRulerCore {
event RTokenCreated(address);
event CollateralUpdated(address col, uint256 old, uint256 _new);
event PairAdded(address indexed collateral, address indexed paired, uint48 expiry, uint256 mintRatio);
event MarketMakeDeposit(address indexed user, address indexed collateral, address indexed paired, uint48 expiry, uint256 mintRatio, uint256 amount);
event Deposit(address indexed user, address indexed collateral, address indexed paired, uint48 expiry, uint256 mintRatio, uint256 amount);
event Repay(address indexed user, address indexed collateral, address indexed paired, uint48 expiry, uint256 mintRatio, uint256 amount);
event Redeem(address indexed user, address indexed collateral, address indexed paired, uint48 expiry, uint256 mintRatio, uint256 amount);
event Collect(address indexed user, address indexed collateral, address indexed paired, uint48 expiry, uint256 mintRatio, uint256 amount);
event AddressUpdated(string _type, address old, address _new);
event PausedStatusUpdated(bool old, bool _new);
event RERC20ImplUpdated(address rERC20Impl, address newImpl);
event FlashLoanRateUpdated(uint256 old, uint256 _new);
struct Pair {
bool active;
uint48 expiry;
address pairedToken;
IRERC20 rcToken;
IRERC20 rrToken;
uint256 mintRatio;
uint256 feeRate;
uint256 colTotal;
}
struct Permit {
address owner;
address spender;
uint256 amount;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
function oracle() external view returns (IOracle);
function version() external pure returns (string memory);
function flashLoanRate() external view returns (uint256);
function paused() external view returns (bool);
function responder() external view returns (address);
function feeReceiver() external view returns (address);
function rERC20Impl() external view returns (address);
function collaterals(uint256 _index) external view returns (address);
function minColRatioMap(address _col) external view returns (uint256);
function feesMap(address _token) external view returns (uint256);
function pairs(address _col, address _paired, uint48 _expiry, uint256 _mintRatio) external view returns (
bool active,
uint48 expiry,
address pairedToken,
IRERC20 rcToken,
IRERC20 rrToken,
uint256 mintRatio,
uint256 feeRate,
uint256 colTotal
);
function getCollaterals() external view returns (address[] memory);
function getPairList(address _col) external view returns (Pair[] memory);
function viewCollectible(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenAmt
) external view returns (uint256 colAmtToCollect, uint256 pairedAmtToCollect);
function mmDeposit(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenAmt
) external;
function mmDepositWithPermit(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenAmt,
Permit calldata _pairedPermit
) external;
function deposit(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt
) external;
function depositWithPermit(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
Permit calldata _colPermit
) external;
function redeem(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rTokenAmt
) external;
function repay(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rrTokenAmt
) external;
function repayWithPermit(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rrTokenAmt,
Permit calldata _pairedPermit
) external;
function collect(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenAmt
) external;
function collectFees(IERC20[] calldata _tokens) external;
function setPaused(bool _paused) external;
function addPair(
address _col,
address _paired,
uint48 _expiry,
string calldata _expiryStr,
uint256 _mintRatio,
string calldata _mintRatioStr,
uint256 _feeRate
) external;
function setPairActive(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
bool _active
) external;
function updateCollateral(address _col, uint256 _minColRatio) external;
function setFeeReceiver(address _addr) external;
function setResponder(address _addr) external;
function setRERC20Impl(address _addr) external;
function setOracle(address _addr) external;
function setFlashLoanRate(uint256 _newRate) external;
}
文件 8 的 12:IRulerZap.sol
pragma solidity ^0.8.0;
import "./IRulerCore.sol";
import "./IRouter.sol";
import "../ERC20/IERC20.sol";
interface IRulerZap {
struct Permit {
address owner;
address spender;
uint256 amount;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
function core() external view returns (IRulerCore);
function router() external view returns (IRouter);
function getAmountOut(uint256 _tokenInAmt, address[] calldata _path) external view returns (uint256);
function depositAndSwapToPaired(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _minPairedOut,
address[] calldata _path,
uint256 _deadline
) external;
function depositWithPermitAndSwapToPaired(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _minPairedOut,
address[] calldata _path,
uint256 _deadline,
Permit calldata _colPermit
) external;
function depositAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline
) external;
function depositWithColPermitAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _colPermit
) external;
function depositWithPairedPermitAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _pairedPermit
) external;
function depositWithBothPermitsAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _colPermit,
Permit calldata _pairedPermit
) external;
function mmDepositAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline
) external;
function mmDepositWithPermitAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _pairedPermit
) external;
function collect(IERC20 _token) external;
function updateCore(IRulerCore _core) external;
function updateRouter(IRouter _router) external;
}
文件 9 的 12:Initializable.sol
pragma solidity ^0.8.0;
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
function _isConstructor() private view returns (bool) {
address self = address(this);
uint256 cs;
assembly { cs := extcodesize(self) }
return cs == 0;
}
}
文件 10 的 12:Ownable.sol
pragma solidity ^0.8.0;
import "./Initializable.sol";
contract Ownable is Initializable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function initializeOwner() internal initializer {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == msg.sender, "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 11 的 12:RulerZap.sol
pragma solidity ^0.8.0;
import "./ERC20/IERC20.sol";
import "./ERC20/IERC20Permit.sol";
import "./ERC20/SafeERC20.sol";
import "./interfaces/IRERC20.sol";
import "./interfaces/IRulerCore.sol";
import "./interfaces/IRouter.sol";
import "./interfaces/IRulerZap.sol";
import "./utils/Ownable.sol";
contract RulerZap is Ownable, IRulerZap {
using SafeERC20 for IERC20;
IRulerCore public override core;
IRouter public override router;
constructor (IRulerCore _core, IRouter _router) {
require(address(_core) != address(0), "RulerZap: _core is 0");
require(address(_router) != address(0), "RulerZap: _router is 0");
core = _core;
router = _router;
initializeOwner();
}
function depositAndSwapToPaired(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _minPairedOut,
address[] calldata _path,
uint256 _deadline
) external override {
_depositAndSwapToPaired(
_col,
_paired,
_expiry,
_mintRatio,
_colAmt,
_minPairedOut,
_path,
_deadline
);
}
function depositWithPermitAndSwapToPaired(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _minPairedOut,
address[] calldata _path,
uint256 _deadline,
Permit calldata _colPermit
) external override {
_permit(IERC20Permit(_col), _colPermit);
_depositAndSwapToPaired(
_col,
_paired,
_expiry,
_mintRatio,
_colAmt,
_minPairedOut,
_path,
_deadline
);
}
function depositAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline
) external override {
_depositAndAddLiquidity(
_col,
_paired,
_expiry,
_mintRatio,
_colAmt,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
_deadline
);
}
function depositWithColPermitAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _colPermit
) external override {
_permit(IERC20Permit(_col), _colPermit);
_depositAndAddLiquidity(
_col,
_paired,
_expiry,
_mintRatio,
_colAmt,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
_deadline
);
}
function depositWithPairedPermitAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _pairedPermit
) external override {
_permit(IERC20Permit(_paired), _pairedPermit);
_depositAndAddLiquidity(
_col,
_paired,
_expiry,
_mintRatio,
_colAmt,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
_deadline
);
}
function depositWithBothPermitsAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _colPermit,
Permit calldata _pairedPermit
) external override {
_permit(IERC20Permit(_col), _colPermit);
_permit(IERC20Permit(_paired), _pairedPermit);
_depositAndAddLiquidity(
_col,
_paired,
_expiry,
_mintRatio,
_colAmt,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
_deadline
);
}
function mmDepositAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline
) external override {
_mmDepositAndAddLiquidity(
_col,
_paired,
_expiry,
_mintRatio,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
_deadline
);
}
function mmDepositWithPermitAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline,
Permit calldata _pairedPermit
) external override {
_permit(IERC20Permit(_paired), _pairedPermit);
_mmDepositAndAddLiquidity(
_col,
_paired,
_expiry,
_mintRatio,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
_deadline
);
}
function collect(IERC20 _token) external override onlyOwner {
uint256 balance = _token.balanceOf(address(this));
require(balance > 0, "RulerZap: balance is 0");
_token.safeTransfer(msg.sender, balance);
}
function updateCore(IRulerCore _core) external override onlyOwner {
require(address(_core) != address(0), "RulerZap: _core is 0");
core = _core;
}
function updateRouter(IRouter _router) external override onlyOwner {
require(address(_router) != address(0), "RulerZap: _router is 0");
router = _router;
}
function getAmountOut(
uint256 _tokenInAmt,
address[] calldata _path
) external view override returns (uint256) {
return router.getAmountsOut(_tokenInAmt, _path)[_path.length - 1];
}
function _depositAndSwapToPaired(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _minPairedOut,
address[] calldata _path,
uint256 _deadline
) private {
require(_colAmt > 0, "RulerZap: _colAmt is 0");
require(_path.length >= 2, "RulerZap: _path length < 2");
require(_path[_path.length - 1] == _paired, "RulerZap: output != _paired");
require(_deadline >= block.timestamp, "RulerZap: _deadline in past");
(address _rcToken, uint256 _rcTokensReceived, ) = _deposit(_col, _paired, _expiry, _mintRatio, _colAmt);
require(_path[0] == _rcToken, "RulerZap: input != rcToken");
_approve(IERC20(_rcToken), address(router), _rcTokensReceived);
router.swapExactTokensForTokens(_rcTokensReceived, _minPairedOut, _path, msg.sender, _deadline);
}
function _depositAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline
) private {
require(_colAmt > 0, "RulerZap: _colAmt is 0");
require(_deadline >= block.timestamp, "RulerZap: _deadline in past");
require(_rcTokenDepositAmt > 0, "RulerZap: 0 rcTokenDepositAmt");
require(_rcTokenDepositAmt >= _rcTokenDepositMin, "RulerZap: rcToken Amt < min");
require(_pairedDepositAmt > 0, "RulerZap: 0 pairedDepositAmt");
require(_pairedDepositAmt >= _pairedDepositMin, "RulerZap: paired Amt < min");
IERC20 rcToken;
uint256 rcTokensBalBefore;
{
(address _rcToken, uint256 _rcTokensReceived, uint256 _rcTokensBalBefore) = _deposit(_col, _paired, _expiry, _mintRatio, _colAmt);
require(_rcTokenDepositAmt <= _rcTokensReceived, "RulerZap: rcToken Amt > minted");
rcToken = IERC20(_rcToken);
rcTokensBalBefore = _rcTokensBalBefore;
}
IERC20 paired = IERC20(_paired);
uint256 pairedBalBefore = paired.balanceOf(address(this));
paired.safeTransferFrom(msg.sender, address(this), _pairedDepositAmt);
uint256 receivedPaired = paired.balanceOf(address(this)) - pairedBalBefore;
require(receivedPaired > 0, "RulerZap: paired transfer failed");
_approve(rcToken, address(router), _rcTokenDepositAmt);
_approve(paired, address(router), _pairedDepositAmt);
router.addLiquidity(
address(rcToken),
address(paired),
_rcTokenDepositAmt,
receivedPaired,
_rcTokenDepositMin,
_pairedDepositMin,
msg.sender,
_deadline
);
uint256 rcTokensLeftover = rcToken.balanceOf(address(this)) - rcTokensBalBefore;
if (rcTokensLeftover > 0) {
rcToken.safeTransfer(msg.sender, rcTokensLeftover);
}
uint256 pairedTokensLeftover = paired.balanceOf(address(this)) - pairedBalBefore;
if (pairedTokensLeftover > 0) {
paired.safeTransfer(msg.sender, pairedTokensLeftover);
}
}
function _mmDepositAndAddLiquidity(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _rcTokenDepositAmt,
uint256 _pairedDepositAmt,
uint256 _rcTokenDepositMin,
uint256 _pairedDepositMin,
uint256 _deadline
) private {
require(_deadline >= block.timestamp, "RulerZap: _deadline in past");
require(_rcTokenDepositAmt > 0, "RulerZap: 0 rcTokenDepositAmt");
require(_rcTokenDepositAmt >= _rcTokenDepositMin, "RulerZap: rcToken Amt < min");
require(_pairedDepositAmt > 0, "RulerZap: 0 pairedDepositAmt");
require(_pairedDepositAmt >= _pairedDepositMin, "RulerZap: paired Amt < min");
IERC20 paired = IERC20(_paired);
uint256 pairedBalBefore = paired.balanceOf(address(this));
paired.safeTransferFrom(msg.sender, address(this), _rcTokenDepositAmt + _pairedDepositAmt);
require(paired.balanceOf(address(this)) - pairedBalBefore == _rcTokenDepositAmt + _pairedDepositAmt, "RulerZap: paired transfer failed");
( , , , IRERC20 rcToken, , , , ) = core.pairs(_col, _paired, _expiry, _mintRatio);
require(address(rcToken) != address(0), "RulerZap: pair not exist");
uint256 rcTokenBalBefore = rcToken.balanceOf(address(this));
_approve(paired, address(core), _rcTokenDepositAmt);
core.mmDeposit(_col, _paired, _expiry, _mintRatio, _rcTokenDepositAmt);
uint256 rcTokenReceived = rcToken.balanceOf(address(this)) - rcTokenBalBefore;
require(_rcTokenDepositAmt <= rcTokenReceived, "RulerZap: rcToken Amt > minted");
_approve(rcToken, address(router), _rcTokenDepositAmt);
_approve(paired, address(router), _pairedDepositAmt);
router.addLiquidity(
address(rcToken),
_paired,
_rcTokenDepositAmt,
_pairedDepositAmt,
_rcTokenDepositMin,
_pairedDepositMin,
msg.sender,
_deadline
);
_transferRem(rcToken, rcTokenBalBefore);
_transferRem(paired, pairedBalBefore);
}
function _deposit(
address _col,
address _paired,
uint48 _expiry,
uint256 _mintRatio,
uint256 _colAmt
) private returns (address rcTokenAddr, uint256 rcTokenReceived, uint256 rcTokenBalBefore) {
( , , , IRERC20 rcToken, IRERC20 rrToken, , , ) = core.pairs(_col, _paired, _expiry, _mintRatio);
require(address(rcToken) != address(0) && address(rrToken) != address(0), "RulerZap: pair not exist");
IERC20 collateral = IERC20(_col);
uint256 colBalBefore = collateral.balanceOf(address(this));
collateral.safeTransferFrom(msg.sender, address(this), _colAmt);
uint256 received = collateral.balanceOf(address(this)) - colBalBefore;
require(received > 0, "RulerZap: col transfer failed");
rcTokenBalBefore = rcToken.balanceOf(address(this));
uint256 rrTokenBalBefore = rrToken.balanceOf(address(this));
_approve(collateral, address(core), received);
core.deposit(_col, _paired, _expiry, _mintRatio, received);
_transferRem(rrToken, rrTokenBalBefore);
rcTokenReceived = rcToken.balanceOf(address(this)) - rcTokenBalBefore;
rcTokenAddr = address(rcToken);
}
function _approve(IERC20 _token, address _spender, uint256 _amount) private {
uint256 allowance = _token.allowance(address(this), _spender);
if (allowance < _amount) {
if (allowance != 0) {
_token.safeApprove(_spender, 0);
}
_token.safeApprove(_spender, type(uint256).max);
}
}
function _permit(IERC20Permit _token, Permit calldata permit) private {
_token.permit(
permit.owner,
permit.spender,
permit.amount,
permit.deadline,
permit.v,
permit.r,
permit.s
);
}
function _transferRem(IERC20 _token, uint256 _balBefore) private {
uint256 tokensLeftover = _token.balanceOf(address(this)) - _balBefore;
if (tokensLeftover > 0) {
_token.safeTransfer(msg.sender, tokensLeftover);
}
}
}
文件 12 的 12:SafeERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
{
"compilationTarget": {
"contracts/RulerZap.sol": "RulerZap"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IRulerCore","name":"_core","type":"address"},{"internalType":"contract IRouter","name":"_router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"collect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract IRulerCore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_colAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositMin","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositMin","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"depositAndAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_colAmt","type":"uint256"},{"internalType":"uint256","name":"_minPairedOut","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"depositAndSwapToPaired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_colAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositMin","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositMin","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRulerZap.Permit","name":"_colPermit","type":"tuple"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRulerZap.Permit","name":"_pairedPermit","type":"tuple"}],"name":"depositWithBothPermitsAndAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_colAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositMin","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositMin","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRulerZap.Permit","name":"_colPermit","type":"tuple"}],"name":"depositWithColPermitAndAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_colAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositMin","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositMin","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRulerZap.Permit","name":"_pairedPermit","type":"tuple"}],"name":"depositWithPairedPermitAndAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_colAmt","type":"uint256"},{"internalType":"uint256","name":"_minPairedOut","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRulerZap.Permit","name":"_colPermit","type":"tuple"}],"name":"depositWithPermitAndSwapToPaired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenInAmt","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositMin","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositMin","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"mmDepositAndAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_col","type":"address"},{"internalType":"address","name":"_paired","type":"address"},{"internalType":"uint48","name":"_expiry","type":"uint48"},{"internalType":"uint256","name":"_mintRatio","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositAmt","type":"uint256"},{"internalType":"uint256","name":"_rcTokenDepositMin","type":"uint256"},{"internalType":"uint256","name":"_pairedDepositMin","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IRulerZap.Permit","name":"_pairedPermit","type":"tuple"}],"name":"mmDepositWithPermitAndAddLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRulerCore","name":"_core","type":"address"}],"name":"updateCore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRouter","name":"_router","type":"address"}],"name":"updateRouter","outputs":[],"stateMutability":"nonpayable","type":"function"}]