Accounts
0x75...f461
0x75...F461

0x75...F461

$500
This contract's source code is verified!
Contract Metadata
Compiler
0.8.20+commit.a1b79de6
Language
Solidity
Contract Source Code
File 1 of 1: MplUserActions.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20 ^0.8.0 ^0.8.7;

// contracts/interfaces/IMplUserActions.sol

interface IMplUserActions {

    /**************************************************************************************************************************************/
    /*** Events                                                                                                                         ***/
    /**************************************************************************************************************************************/

    event MigratedAndStaked(
        address indexed sender,
        address assetSent,
        uint256 amountSent,
        address indexed receiver,
        address assetReceived,
        uint256 amountReceived
    );

    event RedeemedAndMigrated(
        address indexed sender,
        address assetSent,
        uint256 amountSent,
        address indexed receiver,
        address assetReceived,
        uint256 amountReceived
    );

    event RedeemedAndMigratedAndStaked(
        address indexed sender,
        address assetSent,
        uint256 amountSent,
        address indexed receiver,
        address assetReceived,
        uint256 amountReceived
    );

    /**************************************************************************************************************************************/
    /*** State Variables                                                                                                                ***/
    /**************************************************************************************************************************************/

    /**
     *  @dev    Returns the address of the MPL migrator contract.
     *  @return migrator Address of the migrator contract.
     */
    function migrator() external returns (address migrator);

    /**
     *  @dev    Returns the address of the MPL contract.
     *  @return mpl Address of the MPL contract.
     */
    function mpl() external returns (address mpl);

    /**
     *  @dev    Returns the address of the stSYRUP contract.
     *  @return stsyrup Address of the stSYRUP contract.
     */
    function stsyrup() external returns (address stsyrup);

    /**
     *  @dev    Returns the address of the SYRUP contract.
     *  @return syrup Address of the SYRUP contract.
     */
    function syrup() external returns (address syrup);

    /**
     *  @dev    Returns the address of the xMPL contract.
     *  @return xmpl Address of the xMPL contract.
     */
    function xmpl() external returns (address xmpl);

    /**************************************************************************************************************************************/
    /*** User Actions                                                                                                                   ***/
    /**************************************************************************************************************************************/

    /**
     *  @dev    Migrates MPL to SYRUP and then stakes it.
     *  @param  receiver   Address that will receive stSYRUP.
     *  @param  mplIn      Amount of MPL to migrate.
     *  @return stsyrupOut Amount of stSYRUP received.
     */
    function migrateAndStake(address receiver, uint256 mplIn) external returns (uint256 stsyrupOut);

    /**
     *  @dev    Migrates MPL to SYRUP and then stakes it.
     *          Approves the transfer of MPL with the use of a permit signature.
     *  @param  receiver   Address that will receive stSYRUP.
     *  @param  mplIn      Amount of MPL to migrate.
     *  @param  deadline   The deadline of the permit.
     *  @param  v          The v value of the permit signature.
     *  @param  r          The r value of the permit signature.
     *  @param  s          The s value of the permit signature.
     *  @return stsyrupOut Amount of stSYRUP received.
     */
    function migrateAndStakeWithPermit(
        address receiver,
        uint256 mplIn,
        uint256 deadline,
        uint8   v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 stsyrupOut);

    /**
     *  @dev    Redeems xMPL into MPL and then migrates it to SYRUP.
     *  @param  receiver Address that will receive SYRUP.
     *  @param  xmplIn   Amount of xMPL to redeem.
     *  @return syrupOut Amount of SYRUP received.
     */
    function redeemAndMigrate(address receiver, uint256 xmplIn) external returns (uint256 syrupOut);

    /**
     *  @dev    Redeems xMPL into MPL and then migrates it to SYRUP.
     *          Approves the transfer of xMPL with the use of a permit signature.
     *  @param  receiver Address that will receive SYRUP.
     *  @param  xmplIn   Amount of xMPL to redeem.
     *  @param  deadline The deadline of the permit.
     *  @param  v        The v value of the permit signature.
     *  @param  r        The r value of the permit signature.
     *  @param  s        The s value of the permit signature.
     *  @return syrupOut Amount of SYRUP received.
     */
    function redeemAndMigrateWithPermit(
        address receiver,
        uint256 xmplIn,
        uint256 deadline,
        uint8   v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 syrupOut);

    /**
     *  @dev    Redeems xMPL into MPL, migrates it to SYRUP, and then stakes it.
     *  @param  receiver   Address that will receive stSYRUP.
     *  @param  xmplIn     Amount of xMPL to redeem.
     *  @return stsyrupOut Amount of stSYRUP received.
     */
    function redeemAndMigrateAndStake(address receiver, uint256 xmplIn) external returns (uint256 stsyrupOut);

    /**
     *  @dev    Redeems xMPL into MPL, migrates it to SYRUP, and then stakes it.
     *          Approves the transfer of xMPL with the use of a permit signature.
     *  @param  receiver   sAddress that will receive stSYRUP.
     *  @param  xmplIn     Amount of xMPL to redeem.
     *  @param  deadline   The deadline of the permit.
     *  @param  v          The v value of the permit signature.
     *  @param  r          The r value of the permit signature.
     *  @param  s          The s value of the permit signature.
     *  @return stsyrupOut Amount of stSYRUP received.
     */
    function redeemAndMigrateAndStakeWithPermit(
        address receiver,
        uint256 xmplIn,
        uint256 deadline,
        uint8   v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 stsyrupOut);

}

// contracts/interfaces/Interfaces.sol

interface IBalancerVaultLike {

    enum SwapKind { GIVEN_IN, GIVEN_OUT }

    struct FundManagement {
        address sender;
        bool fromInternalBalance;
        address recipient;
        bool toInternalBalance;
    }

    struct SingleSwap {
        bytes32 poolId;
        SwapKind kind;
        address assetIn;
        address assetOut;
        uint256 amount;
        bytes userData;
    }

    function swap(
        SingleSwap calldata singleSwap,
        FundManagement calldata funds,
        uint256 limit,
        uint256 deadline
    ) external returns (uint256 assetDelta);

}

interface IERC20Like_0 {

    function allowance(address owner, address spender) external view returns (uint256 allowance);

    function balanceOf(address account) external view returns (uint256 balance);

    function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator);

    function PERMIT_TYPEHASH() external view returns (bytes32 permitTypehash);

    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 IGlobalsLike {

    function governor() external view returns (address governor);

    function operationalAdmin() external view returns (address operationalAdmin);

}

interface IMigratorLike {

    function migrate(address receiver, uint256 mplAmount) external returns (uint256 syrupAmount);

}

interface IPoolLike is IERC20Like_0 {

    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;

}

interface IPSMLike {

    function buyGem(address account, uint256 daiAmount) external;

    function tout() external view returns (uint256 tout);  // This is the fee charged for conversion

}

interface ISDaiLike {

    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);

}

interface IRDTLike {

    function asset() external view returns (address asset);

    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);

}

interface IStakedSyrupLike {

    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

}

// modules/erc20-helper/src/interfaces/IERC20Like.sol

/// @title Interface of the ERC20 standard as needed by ERC20Helper.
interface IERC20Like_1 {

    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_);

}

// modules/erc20-helper/src/ERC20Helper.sol

/**
 * @title Small Library to standardize erc20 token interactions.
 */
library ERC20Helper {

    /**************************************************************************************************************************************/
    /*** Internal Functions                                                                                                             ***/
    /**************************************************************************************************************************************/

    function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) {
        return _call(token_, abi.encodeWithSelector(IERC20Like_1.transfer.selector, to_, amount_));
    }

    function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) {
        return _call(token_, abi.encodeWithSelector(IERC20Like_1.transferFrom.selector, from_, to_, amount_));
    }

    function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) {
        // If setting approval to zero fails, return false.
        if (!_call(token_, abi.encodeWithSelector(IERC20Like_1.approve.selector, spender_, uint256(0)))) return false;

        // If `amount_` is zero, return true as the previous step already did this.
        if (amount_ == uint256(0)) return true;

        // Return the result of setting the approval to `amount_`.
        return _call(token_, abi.encodeWithSelector(IERC20Like_1.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)));
    }

}

// contracts/MplUserActions.sol

contract MplUserActions is IMplUserActions {

    /**************************************************************************************************************************************/
    /*** State Variables                                                                                                                ***/
    /**************************************************************************************************************************************/

    address public immutable override migrator;
    address public immutable override mpl;
    address public immutable override stsyrup;
    address public immutable override syrup;
    address public immutable override xmpl;

    /**************************************************************************************************************************************/
    /*** Constructor                                                                                                                    ***/
    /**************************************************************************************************************************************/

    constructor(address migrator_, address xmpl_, address stsyrup_) {
        address mpl_   = IRDTLike(xmpl_).asset();
        address syrup_ = IRDTLike(stsyrup_).asset();

        migrator = migrator_;
        mpl      = mpl_;
        syrup    = syrup_;
        xmpl     = xmpl_;
        stsyrup  = stsyrup_;

        require(ERC20Helper.approve(mpl_,   migrator_, type(uint256).max), "MUA:C:MPL_APPROVE");
        require(ERC20Helper.approve(syrup_, stsyrup_,  type(uint256).max), "MUA:C:SYRUP_APPROVE");
    }

    /**************************************************************************************************************************************/
    /*** User Actions                                                                                                                   ***/
    /**************************************************************************************************************************************/

    // MPL -> SYRUP -> stSYRUP
    function migrateAndStake(address receiver_, uint256 mplIn_) external override returns (uint256 stsyrupOut_) {
        stsyrupOut_ = _migrateAndStake(receiver_, mplIn_);
    }

    // MPL -> SYRUP -> stSYRUP
    function migrateAndStakeWithPermit(
        address receiver_,
        uint256 mplIn_,
        uint256 deadline_,
        uint8   v_,
        bytes32 r_,
        bytes32 s_
    )
        external override returns (uint256 stsyrupOut_)
    {
        _permit(mpl, deadline_, mplIn_, v_, r_, s_);

        stsyrupOut_ = _migrateAndStake(receiver_, mplIn_);
    }

    // xMPL -> MPL -> SYRUP
    function redeemAndMigrate(address receiver_, uint256 xmplIn_) external override returns (uint256 syrupOut_) {
        syrupOut_ = _redeemAndMigrate(receiver_, xmplIn_);
    }

    // xMPL -> MPL -> SYRUP
    function redeemAndMigrateWithPermit(
        address receiver_,
        uint256 xmplIn_,
        uint256 deadline_,
        uint8   v_,
        bytes32 r_,
        bytes32 s_
    )
        external override returns (uint256 syrupOut_)
    {
        _permit(xmpl, deadline_, xmplIn_, v_, r_, s_);

        syrupOut_ = _redeemAndMigrate(receiver_, xmplIn_);
    }

    // xMPL -> MPL -> SYRUP -> stSYRUP
    function redeemAndMigrateAndStake(address receiver_, uint256 xmplIn_) external override returns (uint256 stsyrupOut_) {
        stsyrupOut_ = _redeemAndMigrateAndStake(receiver_, xmplIn_);
    }

    // xMPL -> MPL -> SYRUP -> stSYRUP
    function redeemAndMigrateAndStakeWithPermit(
        address receiver_,
        uint256 xmplIn_,
        uint256 deadline_,
        uint8   v_,
        bytes32 r_,
        bytes32 s_
    )
        external override returns (uint256 stsyrupOut_)
    {
        _permit(xmpl, deadline_, xmplIn_, v_, r_, s_);

        stsyrupOut_ = _redeemAndMigrateAndStake(receiver_, xmplIn_);
    }

    /**************************************************************************************************************************************/
    /*** Internal Functions                                                                                                             ***/
    /**************************************************************************************************************************************/

    // MPL -> SYRUP -> stSYRUP
    function _migrateAndStake(address receiver_, uint256 mplIn_) internal returns (uint256 stsyrupOut_) {
        require(mplIn_ > 0,                                                       "MUA:MAS:ZERO_AMOUNT");
        require(ERC20Helper.transferFrom(mpl, msg.sender, address(this), mplIn_), "MUA:MAS:TRANSFER_FAIL");

        uint256 syrupAmount_ = _migrate(address(this), mplIn_);
        stsyrupOut_          = _stake(receiver_, syrupAmount_);

        emit MigratedAndStaked(msg.sender, mpl, mplIn_, receiver_, stsyrup, stsyrupOut_);
    }

    // MPL -> SYRUP
    function _migrate(address receiver_, uint256 mplIn_) internal returns (uint256 syrupOut_) {
        syrupOut_ = IMigratorLike(migrator).migrate(receiver_, mplIn_);
    }

    function _permit(address asset_, uint256 deadline_, uint256 amount_, uint8 v_, bytes32 r_, bytes32 s_) internal {
        uint256 allowance_ = IERC20Like_0(asset_).allowance(msg.sender, address(this));

        if (allowance_ < amount_) {
            IERC20Like_0(asset_).permit(msg.sender, address(this), amount_, deadline_, v_, r_, s_);
        }
    }

    // xMPL -> MPL
    function _redeem(address receiver_, uint256 xmplIn_) internal returns (uint256 mplOut_) {
        mplOut_ = IRDTLike(xmpl).redeem(xmplIn_, receiver_, address(this));
    }

    // xMPL -> MPL -> SYRUP
    function _redeemAndMigrate(address receiver_, uint256 xmplIn_) internal returns (uint256 syrupOut_) {
        require(xmplIn_ > 0,                                                        "MUA:RAM:ZERO_AMOUNT");
        require(ERC20Helper.transferFrom(xmpl, msg.sender, address(this), xmplIn_), "MUA:RAM:TRANSFER_FAIL");

        uint256 mplAmount_ = _redeem(address(this), xmplIn_);
        syrupOut_          = _migrate(receiver_, mplAmount_);

        emit RedeemedAndMigrated(msg.sender, xmpl, xmplIn_, receiver_, syrup, syrupOut_);
    }

    // xMPL -> MPL -> SYRUP -> stSYRUP
    function _redeemAndMigrateAndStake(address receiver_, uint256 xmplIn_) internal returns (uint256 stsyrupOut_) {
        require(xmplIn_ > 0,                                                        "MUA:RAMAS:ZERO_AMOUNT");
        require(ERC20Helper.transferFrom(xmpl, msg.sender, address(this), xmplIn_), "MUA:RAMAS:TRANSFER_FAIL");

        uint256 mplAmount_   = _redeem(address(this), xmplIn_);
        uint256 syrupAmount_ = _migrate(address(this), mplAmount_);
        stsyrupOut_          = _stake(receiver_, syrupAmount_);

        emit RedeemedAndMigratedAndStaked(msg.sender, xmpl, xmplIn_, receiver_, stsyrup, stsyrupOut_);
    }

    // SYRUP -> stSYRUP
    function _stake(address receiver_, uint256 syrupIn_) internal returns (uint256 stsyrupOut_) {
        stsyrupOut_ = IRDTLike(stsyrup).deposit(syrupIn_, receiver_);
    }

}
Settings
{
  "compilationTarget": {
    "MplUserActions.sol": "MplUserActions"
  },
  "evmVersion": "shanghai",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"migrator_","type":"address"},{"internalType":"address","name":"xmpl_","type":"address"},{"internalType":"address","name":"stsyrup_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"assetSent","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSent","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"assetReceived","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"MigratedAndStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"assetSent","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSent","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"assetReceived","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"RedeemedAndMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"assetSent","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSent","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"assetReceived","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"RedeemedAndMigratedAndStaked","type":"event"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"mplIn_","type":"uint256"}],"name":"migrateAndStake","outputs":[{"internalType":"uint256","name":"stsyrupOut_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"mplIn_","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"}],"name":"migrateAndStakeWithPermit","outputs":[{"internalType":"uint256","name":"stsyrupOut_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"xmplIn_","type":"uint256"}],"name":"redeemAndMigrate","outputs":[{"internalType":"uint256","name":"syrupOut_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"xmplIn_","type":"uint256"}],"name":"redeemAndMigrateAndStake","outputs":[{"internalType":"uint256","name":"stsyrupOut_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"xmplIn_","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"}],"name":"redeemAndMigrateAndStakeWithPermit","outputs":[{"internalType":"uint256","name":"stsyrupOut_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"xmplIn_","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"}],"name":"redeemAndMigrateWithPermit","outputs":[{"internalType":"uint256","name":"syrupOut_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stsyrup","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"syrup","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xmpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]