文件 1 的 5: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 的 5: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_);
}
文件 3 的 5:ISyrupRouter.sol
pragma solidity 0.8.7;
interface ISyrupRouter {
event DepositData(address indexed owner, uint256 amount, bytes32 depositData);
function asset() external view returns (address asset);
function authorizeAndDeposit(
uint256 bitmap_,
uint256 deadline_,
uint8 auth_v,
bytes32 auth_r,
bytes32 auth_s,
uint256 amount_,
bytes32 depositData_
) external returns (uint256 shares_);
function authorizeAndDepositWithPermit(
uint256 bitmap_,
uint256 auth_deadline_,
uint8 auth_v,
bytes32 auth_r,
bytes32 auth_s,
uint256 amount_,
bytes32 depositData_,
uint256 permit_deadline,
uint8 permit_v_,
bytes32 permit_r_,
bytes32 permit_s_
) external returns (uint256 shares_);
function deposit(uint256 assets, bytes32 depositData) external returns (uint256 shares);
function depositWithPermit(uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s, bytes32 depositData)
external returns (uint256 shares);
function nonces(address owner_) external view returns (uint256 nonce_);
function pool() external view returns (address pool);
function poolManager() external view returns (address poolManager);
function poolPermissionManager() external view returns (address poolPermissionManager);
}
文件 4 的 5:Interfaces.sol
pragma solidity 0.8.7;
interface IERC20Like {
function allowance(address owner, address spender) external view returns (uint256 allowance);
function approve(address spender, uint256 amount) 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);
}
interface IPoolLike is IERC20Like {
function asset() external view returns (address asset);
function convertToExitAssets(uint256 shares) external view returns (uint256);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function manager() external view returns (address manager);
}
interface IPoolManagerLike {
function poolPermissionManager() external view returns (address poolPermissionManager);
}
interface IPoolPermissionManagerLike {
function hasPermission(address poolManager, address lender, bytes32 functionId) external view returns (bool hasPermission);
function permissionAdmins(address account) external view returns (bool isAdmin);
function setLenderBitmaps(address[] calldata lenders, uint256[] calldata bitmaps) external;
}
文件 5 的 5:SyrupRouter.sol
pragma solidity 0.8.7;
import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol";
import { ISyrupRouter } from "./interfaces/ISyrupRouter.sol";
import {
IERC20Like,
IPoolLike,
IPoolManagerLike,
IPoolPermissionManagerLike
} from "./interfaces/Interfaces.sol";
contract SyrupRouter is ISyrupRouter {
address public immutable override asset;
address public immutable override pool;
address public immutable override poolManager;
address public immutable override poolPermissionManager;
mapping(address => uint256) public override nonces;
constructor(address pool_) {
pool = pool_;
address asset_ = asset = IPoolLike(pool_).asset();
address poolManager_ = poolManager = IPoolLike(pool_).manager();
poolPermissionManager = IPoolManagerLike(poolManager_).poolPermissionManager();
require(ERC20Helper.approve(asset_, pool_, type(uint256).max), "SR:C:APPROVE_FAIL");
}
function authorizeAndDeposit(
uint256 bitmap_,
uint256 deadline_,
uint8 auth_v,
bytes32 auth_r,
bytes32 auth_s,
uint256 amount_,
bytes32 depositData_
)
external override returns (uint256 shares_)
{
_authorize(deadline_, bitmap_, auth_v, auth_r, auth_s);
shares_ = _deposit(msg.sender, amount_, depositData_);
}
function authorizeAndDepositWithPermit(
uint256 bitmap_,
uint256 auth_deadline_,
uint8 auth_v,
bytes32 auth_r,
bytes32 auth_s,
uint256 amount_,
bytes32 depositData_,
uint256 permit_deadline,
uint8 permit_v_,
bytes32 permit_r_,
bytes32 permit_s_
)
external override returns (uint256 shares_)
{
_authorize(auth_deadline_, bitmap_, auth_v, auth_r, auth_s);
_permit(asset, permit_deadline, amount_, permit_v_, permit_r_, permit_s_);
shares_ = _deposit(msg.sender, amount_, depositData_);
}
function deposit(uint256 amount_, bytes32 depositData_) external override returns (uint256 shares_) {
shares_ = _deposit(msg.sender, amount_, depositData_);
}
function depositWithPermit(
uint256 amount_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_,
bytes32 depositData_
)
external override returns (uint256 shares_)
{
_permit(asset, deadline_, amount_, v_, r_, s_);
shares_ = _deposit(msg.sender, amount_, depositData_);
}
function _authorize(uint256 deadline_, uint256 bitmap_, uint8 v_, bytes32 r_, bytes32 s_) internal {
require(deadline_ >= block.timestamp, "SR:A:EXPIRED");
require(
uint256(s_) <= uint256(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) &&
(v_ == 27 || v_ == 28),
"SR:A:MALLEABLE"
);
bytes32 digest_ = keccak256(abi.encodePacked(
"\x19\x01",
block.chainid,
address(this),
msg.sender,
nonces[msg.sender]++,
bitmap_,
deadline_
));
address recoveredAddress_ = ecrecover(digest_, v_, r_, s_);
IPoolPermissionManagerLike ppm_ = IPoolPermissionManagerLike(poolPermissionManager);
require(recoveredAddress_ != address(0) && ppm_.permissionAdmins(recoveredAddress_), "SR:A:NOT_PERMISSION_ADMIN");
address[] memory lender = new address[](1);
uint256[] memory bitmap = new uint256[](1);
lender[0] = msg.sender;
bitmap[0] = bitmap_;
ppm_.setLenderBitmaps(lender, bitmap);
}
function _deposit(address owner_, uint256 amount_, bytes32 depositData_) internal returns (uint256 shares_) {
require(
IPoolPermissionManagerLike(poolPermissionManager).hasPermission(poolManager, owner_, "P:deposit"),
"SR:D:NOT_AUTHORIZED"
);
require(ERC20Helper.transferFrom(asset, owner_, address(this), amount_), "SR:D:TRANSFER_FROM_FAIL");
address pool_ = pool;
shares_ = IPoolLike(pool_).deposit(amount_, address(this));
require(ERC20Helper.transfer(pool_, owner_, shares_), "SR:D:TRANSFER_FAIL");
emit DepositData(owner_, amount_, depositData_);
}
function _permit(address asset_, uint256 deadline_, uint256 amount_, uint8 v_, bytes32 r_, bytes32 s_) internal {
uint256 allowance_ = IERC20Like(asset_).allowance(msg.sender, address(this));
if (allowance_ < amount_) {
IERC20Like(asset_).permit(msg.sender, address(this), amount_, deadline_, v_, r_, s_);
}
}
}
{
"compilationTarget": {
"modules/syrup-router/contracts/SyrupRouter.sol": "SyrupRouter"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":address-registry/=modules/address-registry/src/",
":contract-test-utils/=modules/erc20/modules/contract-test-utils/contracts/",
":ds-test/=modules/forge-std/lib/ds-test/src/",
":erc20-helper/=modules/erc20-helper/src/",
":erc20/=modules/erc20/",
":fixed-term-loan-manager/=modules/fixed-term-loan-manager/contracts/",
":fixed-term-loan/=modules/fixed-term-loan/contracts/",
":forge-std/=modules/forge-std/src/",
":globals/=modules/globals/contracts/",
":liquidations/=modules/liquidations/contracts/",
":maple-proxy-factory/=modules/open-term-loan/modules/maple-proxy-factory/",
":non-transparent-proxy/=modules/globals/modules/non-transparent-proxy/",
":ntp/=modules/pool-permission-manager/modules/ntp/",
":open-term-loan-manager/=modules/open-term-loan-manager/contracts/",
":open-term-loan/=modules/open-term-loan/contracts/",
":pool-permission-manager/=modules/pool-permission-manager/contracts/",
":pool/=modules/pool/contracts/",
":proxy-factory/=modules/open-term-loan/modules/maple-proxy-factory/modules/proxy-factory/",
":syrup-router/=modules/syrup-router/",
":withdrawal-manager-cyclical/=modules/withdrawal-manager-cyclical/contracts/",
":withdrawal-manager-queue/=modules/withdrawal-manager-queue/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"pool_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"depositData","type":"bytes32"}],"name":"DepositData","type":"event"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"auth_v","type":"uint8"},{"internalType":"bytes32","name":"auth_r","type":"bytes32"},{"internalType":"bytes32","name":"auth_s","type":"bytes32"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes32","name":"depositData_","type":"bytes32"}],"name":"authorizeAndDeposit","outputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bitmap_","type":"uint256"},{"internalType":"uint256","name":"auth_deadline_","type":"uint256"},{"internalType":"uint8","name":"auth_v","type":"uint8"},{"internalType":"bytes32","name":"auth_r","type":"bytes32"},{"internalType":"bytes32","name":"auth_s","type":"bytes32"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes32","name":"depositData_","type":"bytes32"},{"internalType":"uint256","name":"permit_deadline","type":"uint256"},{"internalType":"uint8","name":"permit_v_","type":"uint8"},{"internalType":"bytes32","name":"permit_r_","type":"bytes32"},{"internalType":"bytes32","name":"permit_s_","type":"bytes32"}],"name":"authorizeAndDepositWithPermit","outputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes32","name":"depositData_","type":"bytes32"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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":"bytes32","name":"depositData_","type":"bytes32"}],"name":"depositWithPermit","outputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolPermissionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]