PayPool

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "PayPool.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
\r
pragma solidity 0.8.12;\r
import "./interfaces/IPayPool.sol";\r
contract PayPool is IPayPool {\r
\r
    ILendingPool public constant aaveLendingPool=ILendingPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);\r
    ILendingPool public constant lidoLendingPool=ILendingPool(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);\r
    ILendingPool public constant ethenaLendingPool=ILendingPool(0x9D39A5DE30e57443BfF2A8307A4256c8797A3497);\r
    ILidoWithdrawalQueueERC721 public constant lidoWithrawPool=ILidoWithdrawalQueueERC721(0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1);\r
\r
    ICommonConfigs public constant commonConfigs=ICommonConfigs(0x3E428648C8549eC5a50b12156f42BB08182545d5);\r
\r
    address public constant usdeToken=0x4c9EDD5852cd905f086C759E8383e09bff1E68B3;\r
    address public constant susdeToken=0x9D39A5DE30e57443BfF2A8307A4256c8797A3497;\r
    mapping(uint => mapping(address => uint)) public lendingAmount;\r
    mapping(uint => uint) public lidoRequestAmount;\r
    mapping(address => uint) public lidoTotalAmount;\r
    mapping(address => uint) public lidoRemainAmount;\r
    address private _owner;\r
\r
    modifier onlyOwner() {\r
        if (_owner !=msg.sender) {\r
            revert OwnableUnauthorizedAccount(msg.sender);\r
        }\r
        _;\r
    }\r
    uint initStatus;\r
    function initOwner()external{\r
        if(initStatus==0){\r
            initStatus=1;\r
            _owner=msg.sender;\r
        }\r
    }\r
    constructor() {\r
        initStatus=1;\r
        _owner=msg.sender;\r
    }\r
    receive() external payable {}\r
    fallback() external payable {}\r
\r
    function getAssetBlance(address token) internal view returns (uint112 tokenBal) {\r
        assembly {\r
            let emptyPointer := mload(0x40)\r
            mstore(emptyPointer, 0x70a0823100000000000000000000000000000000000000000000000000000000)\r
            mstore(add(emptyPointer, 0x04), address())\r
            let success := staticcall(gas(), token, emptyPointer, 0x24, emptyPointer, 0x40)\r
            if success {\r
                tokenBal := mload(emptyPointer)\r
            }\r
        }\r
    }\r
    function _transfer(address token,address to,uint256 amount) internal  {\r
        assembly {\r
            let emptyPointer := mload(0x40)\r
            mstore(\r
                emptyPointer,\r
                0xa9059cbb00000000000000000000000000000000000000000000000000000000\r
            )\r
            mstore(add(emptyPointer, 0x04),to)\r
            mstore(add(emptyPointer, 0x24), amount)\r
            let failed := iszero(\r
                call(gas(), token, 0, emptyPointer, 0x44, 0, 0)\r
            )\r
            if failed {\r
                returndatacopy(0, 0, returndatasize())\r
                revert(0, returndatasize())\r
            }\r
        }\r
    }\r
\r
    function tokenApprove(address token,address spender, uint256 amount) internal {\r
        assembly {\r
            let emptyPointer := mload(0x40)\r
            mstore(\r
                emptyPointer,\r
                0x095ea7b300000000000000000000000000000000000000000000000000000000\r
            )\r
            mstore(add(emptyPointer, 0x04), spender)\r
            mstore(add(emptyPointer, 0x24), amount)\r
            if iszero(call(gas(), token, 0, emptyPointer, 0x44, 0, 0)) {\r
                returndatacopy(0, 0, returndatasize())\r
                revert(0, returndatasize())\r
            }\r
        }\r
    }\r
    function getFee(uint256 _amount,uint rewardFeeRate)internal pure returns(uint fee){\r
        fee=_amount*rewardFeeRate/1e4;\r
    }\r
    function getColdPool() internal view returns(address coldPool)  {\r
        (bool success, bytes memory data) = msg.sender.staticcall(\r
            abi.encodeWithSelector(0xb5e1e3bf)//abi.encodeWithSelector(getColdPool.selector)\r
        );\r
        if(success){\r
            coldPool=abi.decode(data, (address));\r
        }\r
    }\r
    function depositByAave(address token) external onlyOwner returns (uint assets){\r
        assets=getAssetBlance(token);\r
        tokenApprove(token,address(aaveLendingPool), assets);\r
        aaveLendingPool.supply(token, assets, address(this), 0);\r
        tokenApprove(token,address(aaveLendingPool), 0);\r
        lendingAmount[1][token]+=assets;\r
        emit DepositByAave(token,assets);\r
    }\r
    function withdrawByAave(address token,uint assets) external onlyOwner returns(uint amount,uint256 reward){\r
        uint totalLendingAmount=lendingAmount[1][token];\r
        if(totalLendingAmount>0){\r
            aaveLendingPool.withdraw(token, type(uint256).max, address(this));\r
            (uint rewardFeeRate,address feeTo)=commonConfigs.getFeeInfo(IMultiSigCold(msg.sender));\r
            amount=getAssetBlance(token);\r
            uint fee;\r
            if(amount>totalLendingAmount+1000){\r
                reward=amount-totalLendingAmount;\r
                fee=getFee(reward,rewardFeeRate);\r
                _transfer(token,feeTo,fee);\r
            }\r
            if(assets>=amount-fee){\r
                lendingAmount[1][token]=0;\r
                assets=getAssetBlance(token);\r
                _transfer(token,getColdPool(),assets);\r
            }else{\r
                _transfer(token,getColdPool(),assets);\r
                totalLendingAmount=getAssetBlance(token);\r
                tokenApprove(token,address(aaveLendingPool), totalLendingAmount);\r
                aaveLendingPool.supply(token, totalLendingAmount, address(this), 0);\r
                tokenApprove(token,address(aaveLendingPool), 0);\r
                lendingAmount[1][token]=totalLendingAmount;\r
            }\r
            emit WithdrawByAave(token,assets,amount,reward);\r
        }\r
    }\r
    function depositByLido(address token) external onlyOwner returns (uint assets){\r
        if(token==address(0)){\r
            assets=address(this).balance;\r
        }else{\r
            assets=getAssetBlance(token);\r
            IWETH(token).withdraw(assets);\r
        }\r
        (,address feeTo)=commonConfigs.getFeeInfo(IMultiSigCold(msg.sender));\r
        uint amount=lidoLendingPool.submit{value: assets}(feeTo);\r
        lidoTotalAmount[token]+=amount;\r
        lidoRemainAmount[token]+=amount;\r
        lendingAmount[2][token]+=assets;\r
        emit DepositByLido(token,assets);\r
        if(address(lidoLendingPool)==address(0)){\r
            revert();\r
        }\r
    }\r
\r
    // 请求提现\r
    function lidoRequestWithdrawals(address token,uint256[] calldata _amounts)external onlyOwner returns (uint256[] memory requestIds){\r
        uint assets;\r
        for (uint256 i; i < _amounts.length; ++i) {\r
            assets += _amounts[i];\r
        }\r
        lidoRemainAmount[token]-=assets;\r
        tokenApprove(address(lidoLendingPool),address(lidoWithrawPool), assets);\r
\r
        requestIds=lidoWithrawPool.requestWithdrawals(_amounts, address(this));\r
        tokenApprove(address(lidoLendingPool),address(lidoWithrawPool), 0);\r
        for (uint256 i; i < _amounts.length; ++i) {\r
            lidoRequestAmount[requestIds[i]] = _amounts[i];\r
        }\r
    }\r
    function withdrawByLido(uint256[] memory requestIds,address token,uint assets) external onlyOwner returns(uint amount,uint256 reward){\r
        uint totalLendingAmount=lendingAmount[2][token];\r
        if(totalLendingAmount>0){\r
            uint totalEAmount;\r
            for (uint256 i; i < requestIds.length; ++i) {\r
                totalEAmount+= lidoRequestAmount[requestIds[i]];\r
                delete lidoRequestAmount[requestIds[i]];\r
            }\r
            totalLendingAmount=totalLendingAmount*totalEAmount/lidoTotalAmount[token]+1;\r
            lidoTotalAmount[token]-=totalEAmount;\r
            uint256[] memory _hints = lidoWithrawPool.findCheckpointHints(requestIds, 1, lidoWithrawPool.getLastCheckpointIndex());\r
            lidoWithrawPool.claimWithdrawals(requestIds, _hints);\r
            (uint rewardFeeRate,address feeTo)=commonConfigs.getFeeInfo(IMultiSigCold(msg.sender));\r
            amount=address(this).balance;\r
            uint fee;\r
            if(amount>totalLendingAmount+1000){\r
                reward=amount-totalLendingAmount;\r
                fee=getFee(reward,rewardFeeRate);\r
                ethTransfer(feeTo,fee);\r
            }\r
            if(lendingAmount[2][token]>totalLendingAmount){\r
                lendingAmount[2][token]-=totalLendingAmount;\r
            }else{\r
                lendingAmount[2][token]=0;\r
            }\r
            if(assets>=amount-fee){\r
                assets=address(this).balance;\r
                if(token==address(0)){\r
                    ethTransfer(getColdPool(),assets);\r
                }else{\r
                    IWETH(token).deposit{value:assets}();\r
                    _transfer(token,getColdPool(),assets);\r
                }\r
            }else{\r
                if(token==address(0)){\r
                    ethTransfer(getColdPool(),assets);\r
                }else{\r
                    IWETH(token).deposit{value:assets}();\r
                    _transfer(token,getColdPool(),assets);\r
                }\r
                uint bal=address(this).balance;\r
                uint _amount=lidoLendingPool.submit{value: bal}(feeTo);\r
                lidoTotalAmount[token]+=_amount;\r
                lidoRemainAmount[token]+=_amount;\r
                lendingAmount[2][token]+=bal;\r
            }\r
            emit WithdrawByLido(token,assets,amount,reward);\r
        }\r
    }\r
\r
    function depositByEthenaStakeUsde() external onlyOwner returns (uint assets){\r
        assets=getAssetBlance(usdeToken);\r
        tokenApprove(usdeToken,address(ethenaLendingPool), assets);\r
        ethenaLendingPool.deposit(assets, address(this));\r
        tokenApprove(usdeToken,address(ethenaLendingPool), 0);\r
        lendingAmount[4][usdeToken]+=assets;\r
        emit DepositByEthena(usdeToken,assets);\r
    }\r
    function cooldownSharesForEthenaStake() external onlyOwner returns (uint256 assets){\r
        assets=ethenaLendingPool.cooldownShares(getAssetBlance(susdeToken));\r
    }\r
    function withdrawByEthenaStakeUsde(uint assets) external onlyOwner returns (uint amount,uint256 reward){\r
        uint totalLendingAmount=lendingAmount[4][usdeToken];\r
        if(totalLendingAmount>0){\r
            amount=getAssetBlance(usdeToken);\r
            uint24 cooldownDuration=ethenaLendingPool.cooldownDuration();\r
            (uint104 cooldownEnd,uint152 underlyingAmount)=ethenaLendingPool.cooldowns(address(this));\r
            if (underlyingAmount>0) {\r
                if(block.timestamp >= cooldownEnd || cooldownDuration == 0){\r
                    ethenaLendingPool.unstake(address(this));\r
                    (uint rewardFeeRate,address feeTo)=commonConfigs.getFeeInfo(IMultiSigCold(msg.sender));\r
                    amount=getAssetBlance(usdeToken)-amount;\r
                    uint fee;\r
                    if(amount>totalLendingAmount+1000){\r
                        reward=amount-totalLendingAmount;\r
                        fee=getFee(reward,rewardFeeRate);\r
                        _transfer(usdeToken,feeTo,fee);\r
                    }\r
                    if(assets>=amount-fee){\r
                        lendingAmount[4][usdeToken]=0;\r
                        assets=getAssetBlance(usdeToken);\r
                        _transfer(usdeToken,getColdPool(),assets);\r
                    }else{\r
                        _transfer(usdeToken,getColdPool(),assets);\r
                        totalLendingAmount=getAssetBlance(usdeToken);\r
                        tokenApprove(usdeToken,address(ethenaLendingPool), totalLendingAmount);\r
                        ethenaLendingPool.deposit(totalLendingAmount, address(this));\r
                        tokenApprove(usdeToken,address(ethenaLendingPool), 0);\r
                        lendingAmount[4][usdeToken]=totalLendingAmount;\r
                    }\r
                    emit WithdrawByEthena(usdeToken,assets,amount,reward);\r
                }else{\r
                    revert EthenaCooldownNotEnd(msg.sender);\r
                }\r
            }else{\r
                revert EthenaCooldownNotStart(msg.sender);\r
            }\r
        }\r
    }\r
    function ethTransfer(address recipient, uint256 amount) internal {\r
        bool failed=false;\r
        assembly {\r
            failed := iszero(call(gas(), recipient, amount, 0, 0, 0, 0))\r
        }\r
        if (failed) {\r
            revert EthTransfer(recipient, amount);\r
        }\r
    }\r
\r
    function EmergencyCall(\r
        bytes calldata data,\r
        uint callType,\r
        address callAddr\r
    ) external onlyOwner returns(bool success,bytes memory returnData){\r
        commonConfigs.checkEmergencyCall(data,callType,callAddr);\r
        if(callType==100){\r
            (success,returnData)=callAddr.call(data);\r
        }else if(callType==200){\r
            (success,returnData)=callAddr.delegatecall(data);\r
        }\r
    }\r
}"
    },
    "interfaces/IPayPool.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
import "./ILendingPool.sol";\r
import "./ICommonConfigs.sol";\r
import "./IWETH.sol";\r
interface IPayPool{\r
    event DepositByAave(address token,uint assets);\r
    event WithdrawByAave(address token,uint assets,uint amount,uint256 reward);\r
\r
    event DepositByLido(address token,uint assets);\r
    event WithdrawByLido(address token,uint assets,uint amount,uint256 reward);\r
\r
    event DepositByEthena(address token,uint assets);\r
    event WithdrawByEthena(address token,uint assets,uint amount,uint256 reward);\r
    function aaveLendingPool() external pure returns (ILendingPool);\r
    function lidoLendingPool() external pure returns (ILendingPool);\r
    function ethenaLendingPool() external pure returns (ILendingPool);\r
    function commonConfigs() external pure returns (ICommonConfigs);\r
    function usdeToken() external pure returns (address);\r
    function lendingAmount(uint _type,address _user) external view returns (uint);\r
\r
    error OwnableUnauthorizedAccount(address account);\r
    error EthTransfer(address recipient, uint256 amount);\r
    error EthenaCooldownNotStart(address account);\r
    error EthenaCooldownNotEnd(address account);\r
    function initOwner()external;\r
\r
    function depositByAave(address token) external returns (uint assets);\r
    function withdrawByAave(address token,uint assets) external returns(uint amount,uint256 reward);\r
\r
    function depositByLido(address token) external returns (uint assets);\r
    function withdrawByLido(uint256[] memory requestIds,address token,uint assets)external returns(uint amount,uint256 reward);\r
    // 请求提现\r
    function lidoRequestWithdrawals(address token,uint256[] calldata _amounts)external returns (uint256[] memory requestIds);\r
\r
    function depositByEthenaStakeUsde() external returns (uint assets);\r
    function cooldownSharesForEthenaStake() external returns (uint256 assets);\r
    function withdrawByEthenaStakeUsde(uint assets) external returns (uint amount,uint256 reward);\r
\r
    function EmergencyCall(\r
        bytes calldata data,\r
        uint callType,\r
        address callAddr\r
    ) external returns(bool success,bytes memory returnData);\r
\r
}\r
"
    },
    "interfaces/IWETH.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
interface IWETH {\r
    function deposit() external payable;\r
    function withdraw(uint256) external;\r
}"
    },
    "interfaces/ICommonConfigs.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
import "./IMultiSigCold.sol";\r
interface ICommonConfigs{\r
     struct FeeInfo{\r
          address feeTo;\r
          uint16 feeRate;\r
     }\r
     function getFeeInfo(IMultiSigCold user)external view returns(uint,address);\r
\r
     function setSupportEmergencyCalls(uint callType,address callAddr,bytes4 methodId,bytes memory signatures) external ;\r
     function setFeeRate(uint16 _feeRate,IMultiSigCold user,bytes memory signatures) external ;\r
     function setFreeFeeRate(IMultiSigCold user,bytes memory signatures) external ;\r
     function checkEmergencyCall(bytes memory data,uint callType,address callAddr)external view;\r
}"
    },
    "interfaces/ILendingPool.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
import "./ILidoWithdrawalQueueERC721.sol";\r
\r
interface ILendingPool {\r
     function withdraw(\r
          address asset,\r
          uint256 amount,\r
          address to\r
     ) external returns (uint256);\r
     function supply(\r
          address asset,\r
          uint256 amount,\r
          address onBehalfOf,\r
          uint16 referralCode\r
     ) external;\r
\r
     //ethena---start\r
     function cooldownShares(uint256 shares) external returns (uint256 assets);\r
     function unstake(address receiver) external;\r
     function deposit(uint256 assets, address receiver) external returns (uint256 shares);\r
     function cooldowns(address receiver) external view returns(uint104 cooldownEnd,uint152 underlyingAmount);\r
     function cooldownDuration() external view returns(uint24);\r
     //ethena---end\r
     // 质押到指定模块\r
\r
     function submit(address _referral) external payable returns (uint256);//ldo\r
\r
}\r
"
    },
    "interfaces/ILidoWithdrawalQueueERC721.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
interface ILidoWithdrawalQueueERC721{\r
    // 请求提现\r
    function requestWithdrawals(uint256[] calldata _amounts, address _owner)external returns (uint256[] memory requestIds);\r
    // 领取提现\r
    function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external;\r
    //获取提款请求\r
    function getWithdrawalRequests(address _owner)external view returns (uint256[] memory requestsIds);\r
\r
    function findCheckpointHints(uint256[] calldata _requestIds,uint256 _firstIndex,uint256 _lastIndex) external view returns (uint256[] memory hintIds);\r
    function getLastCheckpointIndex() external view returns (uint256);\r
\r
}"
    },
    "interfaces/IMultiSigCold.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
\r
import "./IMultiSigUtc.sol";\r
struct Merchant {\r
    /// Set the storage balance ratio of each merchant's hot contract\r
    uint256 hotCoinMaxRatio;\r
    /// Fee payment ratio for each merchant\r
    uint256 feeRate;\r
    /// Each merchant balance funds limit time\r
    uint256 balancedTime;\r
    /// The minimum voting ratio for multiple signatures for each merchant is at least 50 and the maximum is 100\r
    uint256 primAgentProfitPerc;\r
    /// Hot contract storage pool address\r
    address payable hotPool;\r
    /// Cold contract storage pool address\r
    address payable coldPool;\r
    /// Agent’s multi-signature address\r
    address multiSigAgentAddr;\r
}\r
\r
interface IMultiSigCold{\r
    function initManagers(Merchant memory data,IMultiSigUtc _multiSigUtc,uint ratio,uint expirationTime,address[] memory _managers) external;\r
    function initOwner() external;\r
    event TransferCommissionLogs(address indexed token, uint256 indexed totalCommission,uint256 indexed primCommission,uint256 web3PayCommission,uint256 transBalHot);\r
}"
    },
    "interfaces/IMultiSigUtc.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\r
pragma solidity 0.8.12;\r
\r
interface IMultiSigUtc{\r
    function getManagerInfo()external view returns(uint managerNumber,uint expirationTime,address[] memory managers);\r
    function getUtcFeeAddr() external view returns(address);\r
}\r
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
Proxy, Upgradeable, Factory|addr:0x58833317b38d33f6f27dd56f4c132e42ac14d82b|verified:true|block:23744344|tx:0x565eb72d7ea179107073702e35124e5d521999f503e85e5ea4522668e92d9b0d|first_check:1762513655

Submitted on: 2025-11-07 12:07:36

Comments

Log in to comment.

No comments yet.