ETH Price: $3,091.34 (-1.91%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
1075261662023-07-29 17:18:29841 days ago1690651109
0x194ed7D6...299ad37cD
0 ETH
1074739052023-07-28 12:16:27842 days ago1690546587
0x194ed7D6...299ad37cD
0 ETH
1074738462023-07-28 12:14:29842 days ago1690546469
0x194ed7D6...299ad37cD
0 ETH
1074737892023-07-28 12:12:35842 days ago1690546355
0x194ed7D6...299ad37cD
0 ETH
1074737292023-07-28 12:10:35842 days ago1690546235
0x194ed7D6...299ad37cD
0 ETH
1074736682023-07-28 12:08:33842 days ago1690546113
0x194ed7D6...299ad37cD
0 ETH
1074735592023-07-28 12:04:55842 days ago1690545895
0x194ed7D6...299ad37cD
0 ETH
1074734742023-07-28 12:02:05842 days ago1690545725
0x194ed7D6...299ad37cD
0 ETH
1074734212023-07-28 12:00:19842 days ago1690545619
0x194ed7D6...299ad37cD
0 ETH
1074733482023-07-28 11:57:53842 days ago1690545473
0x194ed7D6...299ad37cD
0 ETH
1074732702023-07-28 11:55:17842 days ago1690545317
0x194ed7D6...299ad37cD
0 ETH
1074730642023-07-28 11:48:25842 days ago1690544905
0x194ed7D6...299ad37cD
0 ETH
1074730362023-07-28 11:47:29842 days ago1690544849
0x194ed7D6...299ad37cD
0 ETH
1074730202023-07-28 11:46:57842 days ago1690544817
0x194ed7D6...299ad37cD
0 ETH
1074730052023-07-28 11:46:27842 days ago1690544787
0x194ed7D6...299ad37cD
0 ETH
1074729822023-07-28 11:45:41842 days ago1690544741
0x194ed7D6...299ad37cD
0 ETH
1074214922023-07-27 7:09:21843 days ago1690441761
0x194ed7D6...299ad37cD
0 ETH
1074214742023-07-27 7:08:45843 days ago1690441725
0x194ed7D6...299ad37cD
0 ETH
1073439442023-07-25 12:04:25845 days ago1690286665
0x194ed7D6...299ad37cD
0 ETH
1073436902023-07-25 11:55:57845 days ago1690286157
0x194ed7D6...299ad37cD
0 ETH
1073400422023-07-25 9:54:21845 days ago1690278861
0x194ed7D6...299ad37cD
0 ETH
1073398922023-07-25 9:49:21845 days ago1690278561
0x194ed7D6...299ad37cD
0 ETH
1072483642023-07-23 6:58:25847 days ago1690095505
0x194ed7D6...299ad37cD
0 ETH
1071757022023-07-21 14:36:21849 days ago1689950181
0x194ed7D6...299ad37cD
0 ETH
1071755652023-07-21 14:31:47849 days ago1689949907
0x194ed7D6...299ad37cD
0 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SablierV2ProxyTarget

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IPRBProxy } from "@prb/proxy/interfaces/IPRBProxy.sol";
import { ISablierV2Lockup } from "@sablier/v2-core/interfaces/ISablierV2Lockup.sol";
import { ISablierV2LockupLinear } from "@sablier/v2-core/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2LockupDynamic } from "@sablier/v2-core/interfaces/ISablierV2LockupDynamic.sol";
import { LockupDynamic, LockupLinear } from "@sablier/v2-core/types/DataTypes.sol";
import { IAllowanceTransfer } from "permit2/interfaces/IAllowanceTransfer.sol";

import { OnlyDelegateCall } from "./abstracts/OnlyDelegateCall.sol";
import { ISablierV2ProxyTarget } from "./interfaces/ISablierV2ProxyTarget.sol";
import { IWrappedNativeAsset } from "./interfaces/IWrappedNativeAsset.sol";
import { Errors } from "./libraries/Errors.sol";
import { Batch, Permit2Params } from "./types/DataTypes.sol";

/*

███████╗ █████╗ ██████╗ ██╗     ██╗███████╗██████╗     ██╗   ██╗██████╗
██╔════╝██╔══██╗██╔══██╗██║     ██║██╔════╝██╔══██╗    ██║   ██║╚════██╗
███████╗███████║██████╔╝██║     ██║█████╗  ██████╔╝    ██║   ██║ █████╔╝
╚════██║██╔══██║██╔══██╗██║     ██║██╔══╝  ██╔══██╗    ╚██╗ ██╔╝██╔═══╝
███████║██║  ██║██████╔╝███████╗██║███████╗██║  ██║     ╚████╔╝ ███████╗
╚══════╝╚═╝  ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝  ╚═╝      ╚═══╝  ╚══════╝

██████╗ ██████╗  ██████╗ ██╗  ██╗██╗   ██╗    ████████╗ █████╗ ██████╗  ██████╗ ███████╗████████╗
██╔══██╗██╔══██╗██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝    ╚══██╔══╝██╔══██╗██╔══██╗██╔════╝ ██╔════╝╚══██╔══╝
██████╔╝██████╔╝██║   ██║ ╚███╔╝  ╚████╔╝        ██║   ███████║██████╔╝██║  ███╗█████╗     ██║
██╔═══╝ ██╔══██╗██║   ██║ ██╔██╗   ╚██╔╝         ██║   ██╔══██║██╔══██╗██║   ██║██╔══╝     ██║
██║     ██║  ██║╚██████╔╝██╔╝ ██╗   ██║          ██║   ██║  ██║██║  ██║╚██████╔╝███████╗   ██║
╚═╝     ╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═╝   ╚═╝          ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚══════╝   ╚═╝

*/

/// @title SablierV2ProxyTarget
/// @notice See the documentation in {ISablierV2ProxyTarget}.
contract SablierV2ProxyTarget is
    ISablierV2ProxyTarget, // 0 inherited components
    OnlyDelegateCall // 0 inherited components
{
    using SafeERC20 for IERC20;

    /*//////////////////////////////////////////////////////////////////////////
                                     CONSTANTS
    //////////////////////////////////////////////////////////////////////////*/

    IAllowanceTransfer internal immutable PERMIT2;

    /*//////////////////////////////////////////////////////////////////////////
                                    CONSTRUCTOR
    //////////////////////////////////////////////////////////////////////////*/

    constructor(IAllowanceTransfer permit2) {
        PERMIT2 = permit2;
    }

    /*//////////////////////////////////////////////////////////////////////////
                                 SABLIER-V2-LOCKUP
    //////////////////////////////////////////////////////////////////////////*/

    /// @inheritdoc ISablierV2ProxyTarget
    function batchCancelMultiple(
        Batch.CancelMultiple[] calldata batch,
        IERC20[] calldata assets
    )
        external
        onlyDelegateCall
    {
        // Check that the batch size is not zero.
        uint256 batchSize = batch.length;
        if (batchSize == 0) {
            revert Errors.SablierV2ProxyTarget_BatchSizeZero();
        }

        // Load the balances before the cancellations.
        uint256[] memory initialBalances = _getBalances(assets);

        for (uint256 i = 0; i < batchSize;) {
            // Cancel the streams.
            batch[i].lockup.cancelMultiple(batch[i].streamIds);

            // Increment the for loop iterator.
            unchecked {
                i += 1;
            }
        }

        // Transfer the balance differences to the proxy owner.
        _postMultipleCancellations(initialBalances, assets);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function burn(ISablierV2Lockup lockup, uint256 streamId) external onlyDelegateCall {
        lockup.burn(streamId);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function cancel(ISablierV2Lockup lockup, uint256 streamId) public onlyDelegateCall {
        // Retrieve the asset used for streaming.
        IERC20 asset = lockup.getAsset(streamId);

        // Load the balance before the cancellation.
        uint256 initialBalance = asset.balanceOf(address(this));

        // Cancel the stream.
        lockup.cancel(streamId);

        // Calculate the difference between the final and the initial balance.
        uint256 finalBalance = asset.balanceOf(address(this));
        uint256 deltaBalance = finalBalance - initialBalance;

        // Forward the delta to the proxy owner. This cannot be zero because settled streams cannot be canceled.
        asset.safeTransfer({ to: _getOwner(), value: deltaBalance });
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function cancelMultiple(
        ISablierV2Lockup lockup,
        IERC20[] calldata assets,
        uint256[] calldata streamIds
    )
        external
        onlyDelegateCall
    {
        // Load the balances before the cancellations.
        uint256[] memory initialBalances = _getBalances(assets);

        // Cancel the streams.
        lockup.cancelMultiple(streamIds);

        // Transfer the balance differences to the proxy owner.
        _postMultipleCancellations(initialBalances, assets);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function renounce(ISablierV2Lockup lockup, uint256 streamId) external onlyDelegateCall {
        lockup.renounce(streamId);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function withdraw(
        ISablierV2Lockup lockup,
        uint256 streamId,
        address to,
        uint128 amount
    )
        external
        onlyDelegateCall
    {
        lockup.withdraw(streamId, to, amount);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function withdrawMax(ISablierV2Lockup lockup, uint256 streamId, address to) external onlyDelegateCall {
        lockup.withdrawMax(streamId, to);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function withdrawMaxAndTransfer(
        ISablierV2Lockup lockup,
        uint256 streamId,
        address newRecipient
    )
        external
        onlyDelegateCall
    {
        lockup.withdrawMaxAndTransfer(streamId, newRecipient);
    }

    /*//////////////////////////////////////////////////////////////////////////
                              SABLIER-V2-LOCKUP-LINEAR
    //////////////////////////////////////////////////////////////////////////*/

    /// @inheritdoc ISablierV2ProxyTarget
    function batchCreateWithDurations(
        ISablierV2LockupLinear lockupLinear,
        IERC20 asset,
        Batch.CreateWithDurations[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256[] memory streamIds)
    {
        // Check that the batch size is not zero.
        uint256 batchSize = batch.length;
        if (batchSize == 0) {
            revert Errors.SablierV2ProxyTarget_BatchSizeZero();
        }

        // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create
        // transactions will revert if there is overflow.
        uint256 i;
        uint160 transferAmount;
        for (i = 0; i < batchSize;) {
            unchecked {
                transferAmount += batch[i].totalAmount;
                i += 1;
            }
        }

        // Transfers the assets to the proxy and approve the Sablier contract to spend them.
        _transferAndApprove(address(lockupLinear), asset, transferAmount, permit2Params);

        // Create a stream for each element in the parameter array.
        streamIds = new uint256[](batchSize);
        for (i = 0; i < batchSize;) {
            // Create the stream.
            streamIds[i] = lockupLinear.createWithDurations(
                LockupLinear.CreateWithDurations({
                    asset: asset,
                    broker: batch[i].broker,
                    cancelable: batch[i].cancelable,
                    durations: batch[i].durations,
                    recipient: batch[i].recipient,
                    sender: batch[i].sender,
                    totalAmount: batch[i].totalAmount
                })
            );

            // Increment the for loop iterator.
            unchecked {
                i += 1;
            }
        }
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function batchCreateWithRange(
        ISablierV2LockupLinear lockupLinear,
        IERC20 asset,
        Batch.CreateWithRange[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256[] memory streamIds)
    {
        // Check that the batch is not empty.
        uint256 batchSize = batch.length;
        if (batchSize == 0) {
            revert Errors.SablierV2ProxyTarget_BatchSizeZero();
        }

        // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create
        // transactions will revert if there is overflow.
        uint256 i;
        uint160 transferAmount;
        for (i = 0; i < batchSize;) {
            unchecked {
                transferAmount += batch[i].totalAmount;
                i += 1;
            }
        }

        // Transfers the assets to the proxy and approve the Sablier contract to spend them.
        _transferAndApprove(address(lockupLinear), asset, transferAmount, permit2Params);

        // Create a stream for each element in the parameter array.
        streamIds = new uint256[](batchSize);
        for (i = 0; i < batchSize;) {
            // Create the stream.
            streamIds[i] = lockupLinear.createWithRange(
                LockupLinear.CreateWithRange({
                    asset: asset,
                    broker: batch[i].broker,
                    cancelable: batch[i].cancelable,
                    range: batch[i].range,
                    recipient: batch[i].recipient,
                    sender: batch[i].sender,
                    totalAmount: batch[i].totalAmount
                })
            );

            // Increment the for loop iterator.
            unchecked {
                i += 1;
            }
        }
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function cancelAndCreateWithDurations(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithDurations calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256 newStreamId)
    {
        cancel(lockup, streamId);
        newStreamId = createWithDurations(lockupLinear, createParams, permit2Params);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function cancelAndCreateWithRange(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithRange calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256 newStreamId)
    {
        cancel(lockup, streamId);
        newStreamId = createWithRange(lockupLinear, createParams, permit2Params);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function createWithDurations(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithDurations calldata createParams,
        Permit2Params calldata permit2Params
    )
        public
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        _transferAndApprove(address(lockupLinear), createParams.asset, createParams.totalAmount, permit2Params);
        streamId = lockupLinear.createWithDurations(createParams);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function createWithRange(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithRange calldata createParams,
        Permit2Params calldata permit2Params
    )
        public
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        _transferAndApprove(address(lockupLinear), createParams.asset, createParams.totalAmount, permit2Params);
        streamId = lockupLinear.createWithRange(createParams);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function wrapAndCreateWithDurations(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithDurations memory createParams
    )
        external
        payable
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        // All production chains have a native asset with a circulating supply much smaller than 2^128.
        createParams.totalAmount = uint128(msg.value);

        // Safely wrap the native asset payment in ERC-20 form.
        _safeWrap(createParams.asset);

        // Approve the Sablier contract to spend funds.
        _approve(address(lockupLinear), createParams.asset, createParams.totalAmount);

        // Create the stream.
        streamId = lockupLinear.createWithDurations(createParams);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function wrapAndCreateWithRange(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithRange memory createParams
    )
        external
        payable
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        // All production chains have a native asset with a circulating supply much smaller than 2^128.
        createParams.totalAmount = uint128(msg.value);

        // Safely wrap the native asset payment in ERC-20 form.
        _safeWrap(createParams.asset);

        // Approve the Sablier contract to spend funds.
        _approve(address(lockupLinear), createParams.asset, createParams.totalAmount);

        // Create the stream.
        streamId = lockupLinear.createWithRange(createParams);
    }

    /*//////////////////////////////////////////////////////////////////////////
                             SABLIER-V2-LOCKUP-DYNAMIC
    //////////////////////////////////////////////////////////////////////////*/

    /// @inheritdoc ISablierV2ProxyTarget
    function batchCreateWithDeltas(
        ISablierV2LockupDynamic dynamic,
        IERC20 asset,
        Batch.CreateWithDeltas[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256[] memory streamIds)
    {
        // Check that the batch size is not zero.
        uint256 batchSize = batch.length;
        if (batchSize == 0) {
            revert Errors.SablierV2ProxyTarget_BatchSizeZero();
        }

        // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create
        // transactions will revert if there is overflow.
        uint256 i;
        uint160 transferAmount;
        for (i = 0; i < batchSize;) {
            unchecked {
                transferAmount += batch[i].totalAmount;
                i += 1;
            }
        }

        // Perform the ERC-20 transfer and approve {SablierV2LockupDynamic} to spend the amount of assets.
        _transferAndApprove(address(dynamic), asset, transferAmount, permit2Params);

        // Create a stream for each element in the parameter array.
        streamIds = new uint256[](batchSize);
        for (i = 0; i < batchSize;) {
            // Create the stream.
            streamIds[i] = dynamic.createWithDeltas(
                LockupDynamic.CreateWithDeltas({
                    asset: asset,
                    broker: batch[i].broker,
                    cancelable: batch[i].cancelable,
                    recipient: batch[i].recipient,
                    segments: batch[i].segments,
                    sender: batch[i].sender,
                    totalAmount: batch[i].totalAmount
                })
            );

            // Increment the for loop iterator.
            unchecked {
                i += 1;
            }
        }
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function batchCreateWithMilestones(
        ISablierV2LockupDynamic dynamic,
        IERC20 asset,
        Batch.CreateWithMilestones[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256[] memory streamIds)
    {
        // Check that the batch size is not zero.
        uint256 batchSize = batch.length;
        if (batchSize == 0) {
            revert Errors.SablierV2ProxyTarget_BatchSizeZero();
        }

        // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create
        // transactions will revert if there is overflow.
        uint256 i;
        uint160 transferAmount;
        for (i = 0; i < batchSize;) {
            unchecked {
                transferAmount += batch[i].totalAmount;
                i += 1;
            }
        }

        // Perform the ERC-20 transfer and approve {SablierV2LockupDynamic} to spend the amount of assets.
        _transferAndApprove(address(dynamic), asset, transferAmount, permit2Params);

        // Create a stream for each element in the parameter array.
        streamIds = new uint256[](batchSize);
        for (i = 0; i < batchSize;) {
            // Create the stream.
            streamIds[i] = dynamic.createWithMilestones(
                LockupDynamic.CreateWithMilestones({
                    asset: asset,
                    broker: batch[i].broker,
                    cancelable: batch[i].cancelable,
                    recipient: batch[i].recipient,
                    segments: batch[i].segments,
                    sender: batch[i].sender,
                    startTime: batch[i].startTime,
                    totalAmount: batch[i].totalAmount
                })
            );

            // Increment the for loop iterator.
            unchecked {
                i += 1;
            }
        }
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function cancelAndCreateWithDeltas(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupDynamic dynamic,
        LockupDynamic.CreateWithDeltas calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256 newStreamId)
    {
        cancel(lockup, streamId);
        newStreamId = createWithDeltas(dynamic, createParams, permit2Params);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function cancelAndCreateWithMilestones(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupDynamic dynamic,
        LockupDynamic.CreateWithMilestones calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        override
        onlyDelegateCall
        returns (uint256 newStreamId)
    {
        cancel(lockup, streamId);
        newStreamId = createWithMilestones(dynamic, createParams, permit2Params);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function createWithDeltas(
        ISablierV2LockupDynamic dynamic,
        LockupDynamic.CreateWithDeltas calldata createParams,
        Permit2Params calldata permit2Params
    )
        public
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        _transferAndApprove(address(dynamic), createParams.asset, createParams.totalAmount, permit2Params);
        streamId = dynamic.createWithDeltas(createParams);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function createWithMilestones(
        ISablierV2LockupDynamic dynamic,
        LockupDynamic.CreateWithMilestones calldata createParams,
        Permit2Params calldata permit2Params
    )
        public
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        _transferAndApprove(address(dynamic), createParams.asset, createParams.totalAmount, permit2Params);
        streamId = dynamic.createWithMilestones(createParams);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function wrapAndCreateWithDeltas(
        ISablierV2LockupDynamic dynamic,
        LockupDynamic.CreateWithDeltas memory createParams
    )
        external
        payable
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        // All production chains have a native asset with a circulating supply much smaller than 2^128.
        createParams.totalAmount = uint128(msg.value);

        // Safely wrap the native asset payment in ERC-20 form.
        _safeWrap(createParams.asset);

        // Approve the Sablier contract to spend funds.
        _approve(address(dynamic), createParams.asset, createParams.totalAmount);

        // Create the stream.
        streamId = dynamic.createWithDeltas(createParams);
    }

    /// @inheritdoc ISablierV2ProxyTarget
    function wrapAndCreateWithMilestones(
        ISablierV2LockupDynamic dynamic,
        LockupDynamic.CreateWithMilestones memory createParams
    )
        external
        payable
        override
        onlyDelegateCall
        returns (uint256 streamId)
    {
        // All production chains have a native asset with a circulating supply much smaller than 2^128.
        createParams.totalAmount = uint128(msg.value);

        // Safely wrap the native asset payment in ERC-20 form.
        _safeWrap(createParams.asset);

        // Approve the Sablier contract to spend funds.
        _approve(address(dynamic), createParams.asset, createParams.totalAmount);

        // Create the stream.
        streamId = dynamic.createWithMilestones(createParams);
    }

    /*//////////////////////////////////////////////////////////////////////////
                                  HELPER FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @dev Helper function to approve a Sablier contract to spend funds from the proxy. If the current allowance
    /// is insufficient, this function approves Sablier to spend the exact `amount`.
    /// The {SafeERC20.forceApprove} function is used to handle special ERC-20 assets (e.g. USDT) that require the
    /// current allowance to be zero before setting it to a non-zero value.
    function _approve(address sablierContract, IERC20 asset, uint256 amount) internal {
        uint256 allowance = asset.allowance({ owner: address(this), spender: sablierContract });
        if (allowance < amount) {
            asset.forceApprove({ spender: sablierContract, value: amount });
        }
    }

    /// @dev Helper function to retrieve the proxy's balance for the provided assets.
    function _getBalances(IERC20[] calldata assets) internal view returns (uint256[] memory initialBalances) {
        uint256 assetCount = assets.length;
        initialBalances = new uint256[](assetCount);
        for (uint256 i = 0; i < assetCount;) {
            initialBalances[i] = assets[i].balanceOf(address(this));
            unchecked {
                i += 1;
            }
        }
    }

    /// @dev Helper function to retrieve the proxy's owner, which is stored as an immutable variable in the proxy.
    function _getOwner() internal view returns (address) {
        return IPRBProxy(address(this)).owner();
    }

    /// @dev Shared logic between {cancelMultiple} and {batchCancelMultiple}.
    function _postMultipleCancellations(uint256[] memory initialBalances, IERC20[] calldata assets) internal {
        uint256 assetCount = assets.length;
        uint256 finalBalance;
        uint256 deltaBalance;
        for (uint256 i = 0; i < assetCount;) {
            // Calculate the difference between the final and initial balances.
            finalBalance = assets[i].balanceOf(address(this));
            deltaBalance = finalBalance - initialBalances[i];

            // Forward the delta to the proxy owner. This cannot be zero because settled streams cannot be canceled.
            assets[i].safeTransfer({ to: _getOwner(), value: deltaBalance });

            // Increment the for loop iterator.
            unchecked {
                i += 1;
            }
        }
    }

    /// @dev Safely wraps the native asset payment in ERC-20 form, checking that the credit amount is greater than or
    /// equal to `msg.value`.
    function _safeWrap(IERC20 asset) internal {
        // Load the balance before the wrap.
        uint256 initialBalance = asset.balanceOf(address(this));

        // Wrap the native asset payment in ERC-20 form.
        IWrappedNativeAsset(address(asset)).deposit{ value: msg.value }();

        // Calculate the credit amount.
        uint256 finalBalance = asset.balanceOf(address(this));
        uint256 creditAmount = finalBalance - initialBalance;

        // Check that the credit amount is equal to `msg.value`.
        if (creditAmount != msg.value) {
            revert Errors.SablierV2ProxyTarget_CreditAmountMismatch({ msgValue: msg.value, creditAmount: creditAmount });
        }
    }

    /// @dev Helper function to transfer funds from the proxy owner to the proxy using Permit2 and, if needed, approve
    /// the Sablier contract to spend funds from the proxy.
    function _transferAndApprove(
        address sablierContract,
        IERC20 asset,
        uint160 amount,
        Permit2Params calldata permit2Params
    )
        internal
    {
        // Retrieve the proxy owner.
        address owner = _getOwner();

        // Permit the proxy to spend funds from the proxy owner.
        PERMIT2.permit({ owner: owner, permitSingle: permit2Params.permitSingle, signature: permit2Params.signature });

        // Transfer funds from the proxy owner to the proxy.
        PERMIT2.transferFrom({ from: owner, to: address(this), amount: amount, token: address(asset) });

        // Approve the Sablier contract to spend funds.
        _approve(sablierContract, asset, amount);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        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));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
     * 0 before setting it to a non-zero value.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

import { IPRBProxyPlugin } from "./IPRBProxyPlugin.sol";
import { IPRBProxyRegistry } from "./IPRBProxyRegistry.sol";

/// @title IPRBProxy
/// @notice Proxy contract to compose transactions on behalf of the owner.
interface IPRBProxy {
    /*//////////////////////////////////////////////////////////////////////////
                                       ERRORS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when the transfer ownership function is called directly (not via the registry).
    error PRBProxy_CallerNotRegistry(IPRBProxyRegistry registry, address caller);

    /// @notice Thrown when a target contract reverts without a specified reason.
    error PRBProxy_ExecutionReverted();

    /// @notice Thrown when the caller to be the owner.
    error PRBProxy_ExecutionUnauthorized(address owner, address caller, address target);

    /// @notice Thrown when the fallback function fails to find an installed plugin for the method selector.
    error PRBProxy_PluginNotInstalledForMethod(address caller, address owner, bytes4 method);

    /// @notice Thrown when a plugin execution reverts without a specified reason.
    error PRBProxy_PluginReverted(IPRBProxyPlugin plugin);

    /// @notice Thrown when a non-contract address is passed as the target.
    error PRBProxy_TargetNotContract(address target);

    /// @notice Thrown when the registry is passed as the target.
    error PRBProxy_TargetRegistry();

    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when a target contract is delegate called.
    event Execute(address indexed target, bytes data, bytes response);

    /// @notice Emitted when a plugin is run for a provided method.
    event RunPlugin(IPRBProxyPlugin indexed plugin, bytes data, bytes response);

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice The address of the owner account or contract, which controls the proxy.
    function owner() external view returns (address);

    /// @notice The address of the registry that has deployed this proxy.
    function registry() external view returns (IPRBProxyRegistry);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Delegate calls to the provided target contract by forwarding the data. It returns the data it
    /// gets back, and bubbles up any potential revert.
    ///
    /// @dev Emits an {Execute} event.
    ///
    /// Requirements:
    /// - The caller must be either the owner or an envoy with permission.
    /// - `target` must be a contract.
    ///
    /// @param target The address of the target contract.
    /// @param data Function selector plus ABI encoded data.
    /// @return response The response received from the target contract.
    function execute(address target, bytes calldata data) external payable returns (bytes memory response);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

import { Lockup } from "../types/DataTypes.sol";
import { ISablierV2Base } from "./ISablierV2Base.sol";
import { ISablierV2NFTDescriptor } from "./ISablierV2NFTDescriptor.sol";

/// @title ISablierV2Lockup
/// @notice Common logic between all Sablier V2 lockup streaming contracts.
interface ISablierV2Lockup is
    ISablierV2Base, // 1 inherited component
    IERC721Metadata // 2 inherited components
{
    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when a stream is canceled.
    /// @param streamId The id of the stream.
    /// @param sender The address of the stream's sender.
    /// @param recipient The address of the stream's recipient.
    /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's
    /// decimals.
    /// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of the
    /// asset's decimals.
    event CancelLockupStream(
        uint256 indexed streamId,
        address indexed sender,
        address indexed recipient,
        uint128 senderAmount,
        uint128 recipientAmount
    );

    /// @notice Emitted when a sender gives up the right to cancel a stream.
    /// @param streamId The id of the stream.
    event RenounceLockupStream(uint256 indexed streamId);

    /// @notice Emitted when the admin sets a new NFT descriptor contract.
    /// @param admin The address of the current contract admin.
    /// @param oldNFTDescriptor The address of the old NFT descriptor contract.
    /// @param newNFTDescriptor The address of the new NFT descriptor contract.
    event SetNFTDescriptor(
        address indexed admin, ISablierV2NFTDescriptor oldNFTDescriptor, ISablierV2NFTDescriptor newNFTDescriptor
    );

    /// @notice Emitted when assets are withdrawn from a stream.
    /// @param streamId The id of the stream.
    /// @param to The address that has received the withdrawn assets.
    /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals.
    event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, uint128 amount);

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Retrieves the address of the ERC-20 asset used for streaming.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getAsset(uint256 streamId) external view returns (IERC20 asset);

    /// @notice Retrieves the amount deposited in the stream, denoted in units of the asset's decimals.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount);

    /// @notice Retrieves the stream's end time, which is a Unix timestamp.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getEndTime(uint256 streamId) external view returns (uint40 endTime);

    /// @notice Retrieves the stream's recipient.
    /// @dev Reverts if the NFT has been burned.
    /// @param streamId The stream id for the query.
    function getRecipient(uint256 streamId) external view returns (address recipient);

    /// @notice Retrieves the amount refunded to the sender after a cancellation, denoted in units of the asset's
    /// decimals. This amount is always zero unless the stream was canceled.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getRefundedAmount(uint256 streamId) external view returns (uint128 refundedAmount);

    /// @notice Retrieves the stream's sender.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getSender(uint256 streamId) external view returns (address sender);

    /// @notice Retrieves the stream's start time, which is a Unix timestamp.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getStartTime(uint256 streamId) external view returns (uint40 startTime);

    /// @notice Retrieves the amount withdrawn from the stream, denoted in units of the asset's decimals.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getWithdrawnAmount(uint256 streamId) external view returns (uint128 withdrawnAmount);

    /// @notice Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this
    /// flag is always `false`.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function isCancelable(uint256 streamId) external view returns (bool result);

    /// @notice Retrieves a flag indicating whether the stream is cold, i.e. settled, canceled, or depleted.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function isCold(uint256 streamId) external view returns (bool result);

    /// @notice Retrieves a flag indicating whether the stream is depleted.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function isDepleted(uint256 streamId) external view returns (bool result);

    /// @notice Retrieves a flag indicating whether the stream exists.
    /// @dev Does not revert if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function isStream(uint256 streamId) external view returns (bool result);

    /// @notice Retrieves a flag indicating whether the stream is warm, i.e. either pending or streaming.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function isWarm(uint256 streamId) external view returns (bool result);

    /// @notice Counter for stream ids, used in the create functions.
    function nextStreamId() external view returns (uint256);

    /// @notice Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units
    /// of the asset's decimals.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount);

    /// @notice Retrieves the stream's status.
    /// @param streamId The stream id for the query.
    function statusOf(uint256 streamId) external view returns (Lockup.Status status);

    /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount);

    /// @notice Retrieves a flag indicating whether the stream was canceled.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function wasCanceled(uint256 streamId) external view returns (bool result);

    /// @notice Calculates the amount that the recipient can withdraw from the stream, denoted in units of the asset's
    /// decimals.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function withdrawableAmountOf(uint256 streamId) external view returns (uint128 withdrawableAmount);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Burns the NFT associated with the stream.
    ///
    /// @dev Emits a {Transfer} event.
    ///
    /// Requirements:
    /// - Must not be delegate called.
    /// - `streamId` must reference a depleted stream.
    /// - The NFT must exist.
    /// - `msg.sender` must be either the NFT owner or an approved third party.
    ///
    /// @param streamId The id of the stream NFT to burn.
    function burn(uint256 streamId) external;

    /// @notice Cancels the stream and refunds any remaining assets to the sender.
    ///
    /// @dev Emits a {Transfer}, {CancelLockupStream}, and {MetadataUpdate} event.
    ///
    /// Notes:
    /// - If there any assets left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the
    /// stream is marked as depleted.
    /// - This function attempts to invoke a hook on either the sender or the recipient, depending on who `msg.sender`
    /// is, and if the resolved address is a contract.
    ///
    /// Requirements:
    /// - Must not be delegate called.
    /// - The stream must be warm and cancelable.
    /// - `msg.sender` must be either the stream's sender or the stream's recipient (i.e. the NFT owner).
    ///
    /// @param streamId The id of the stream to cancel.
    function cancel(uint256 streamId) external;

    /// @notice Cancels multiple streams and refunds any remaining assets to the sender.
    ///
    /// @dev Emits multiple {Transfer}, {CancelLockupStream}, and {MetadataUpdate} events.
    ///
    /// Notes:
    /// - Refer to the notes in {cancel}.
    ///
    /// Requirements:
    /// - All requirements from {cancel} must be met for each stream.
    ///
    /// @param streamIds The ids of the streams to cancel.
    function cancelMultiple(uint256[] calldata streamIds) external;

    /// @notice Removes the right of the stream's sender to cancel the stream.
    ///
    /// @dev Emits a {RenounceLockupStream} and {MetadataUpdate} event.
    ///
    /// Notes:
    /// - This is an irreversible operation.
    /// - This function attempts to invoke a hook on the stream's recipient, provided that the recipient is a contract.
    ///
    /// Requirements:
    /// - Must not be delegate called.
    /// - `streamId` must reference a warm stream.
    /// - `msg.sender` must be the stream's sender.
    /// - The stream must be cancelable.
    ///
    /// @param streamId The id of the stream to renounce.
    function renounce(uint256 streamId) external;

    /// @notice Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs.
    ///
    /// @dev Emits a {SetNFTDescriptor} and {BatchMetadataUpdate} event.
    ///
    /// Notes:
    /// - Does not revert if the NFT descriptor is the same.
    ///
    /// Requirements:
    /// - `msg.sender` must be the contract admin.
    ///
    /// @param newNFTDescriptor The address of the new NFT descriptor contract.
    function setNFTDescriptor(ISablierV2NFTDescriptor newNFTDescriptor) external;

    /// @notice Withdraws the provided amount of assets from the stream to the `to` address.
    ///
    /// @dev Emits a {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} event.
    ///
    /// Notes:
    /// - This function attempts to invoke a hook on the stream's recipient, provided that the recipient is a contract
    /// and `msg.sender` is either the sender or an approved operator.
    ///
    /// Requirements:
    /// - Must not be delegate called.
    /// - `streamId` must not reference a null or depleted stream.
    /// - `msg.sender` must be the stream's sender, the stream's recipient or an approved third party.
    /// - `to` must be the recipient if `msg.sender` is the stream's sender.
    /// - `to` must not be the zero address.
    /// - `amount` must be greater than zero and must not exceed the withdrawable amount.
    ///
    /// @param streamId The id of the stream to withdraw from.
    /// @param to The address receiving the withdrawn assets.
    /// @param amount The amount to withdraw, denoted in units of the asset's decimals.
    function withdraw(uint256 streamId, address to, uint128 amount) external;

    /// @notice Withdraws the maximum withdrawable amount from the stream to the provided address `to`.
    ///
    /// @dev Emits a {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} event.
    ///
    /// Notes:
    /// - Refer to the notes in {withdraw}.
    ///
    /// Requirements:
    /// - Refer to the requirements in {withdraw}.
    ///
    /// @param streamId The id of the stream to withdraw from.
    /// @param to The address receiving the withdrawn assets.
    function withdrawMax(uint256 streamId, address to) external;

    /// @notice Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the
    /// NFT to `newRecipient`.
    ///
    /// @dev Emits a {WithdrawFromLockupStream} and a {Transfer} event.
    ///
    /// Notes:
    /// - If the withdrawable amount is zero, the withdrawal is skipped.
    /// - Refer to the notes in {withdraw}.
    ///
    /// Requirements:
    /// - `msg.sender` must be the stream's recipient.
    /// - Refer to the requirements in {withdraw}.
    /// - Refer to the requirements in {IERC721.transferFrom}.
    ///
    /// @param streamId The id of the stream NFT to transfer.
    /// @param newRecipient The address of the new owner of the stream NFT.
    function withdrawMaxAndTransfer(uint256 streamId, address newRecipient) external;

    /// @notice Withdraws assets from streams to the provided address `to`.
    ///
    /// @dev Emits multiple {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} events.
    ///
    /// Notes:
    /// - This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient.
    ///
    /// Requirements:
    /// - All requirements from {withdraw} must be met for each stream.
    /// - There must be an equal number of `streamIds` and `amounts`.
    ///
    /// @param streamIds The ids of the streams to withdraw from.
    /// @param to The address receiving the withdrawn assets.
    /// @param amounts The amounts to withdraw, denoted in units of the asset's decimals.
    function withdrawMultiple(uint256[] calldata streamIds, address to, uint128[] calldata amounts) external;
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { Lockup, LockupLinear } from "../types/DataTypes.sol";
import { ISablierV2Lockup } from "./ISablierV2Lockup.sol";

/// @title ISablierV2LockupLinear
/// @notice Creates and manages lockup streams with a linear streaming function.
interface ISablierV2LockupLinear is ISablierV2Lockup {
    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when a stream is created.
    /// @param streamId The id of the newly created stream.
    /// @param funder The address which funded the stream.
    /// @param sender The address streaming the assets, with the ability to cancel the stream.
    /// @param recipient The address receiving the assets.
    /// @param amounts Struct containing (i) the deposit amount, (ii) the protocol fee amount, and (iii) the
    /// broker fee amount, all denoted in units of the asset's decimals.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param cancelable Boolean indicating whether the stream will be cancelable or not.
    /// @param range Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as Unix
    /// timestamps.
    /// @param broker The address of the broker who has helped create the stream, e.g. a front-end website.
    event CreateLockupLinearStream(
        uint256 streamId,
        address funder,
        address indexed sender,
        address indexed recipient,
        Lockup.CreateAmounts amounts,
        IERC20 indexed asset,
        bool cancelable,
        LockupLinear.Range range,
        address broker
    );

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Retrieves the stream's cliff time, which is a Unix timestamp.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime);

    /// @notice Retrieves the stream's range, which is a struct containing (i) the stream's start time, (ii) cliff
    /// time, and (iii) end time, all as Unix timestamps.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getRange(uint256 streamId) external view returns (LockupLinear.Range memory range);

    /// @notice Retrieves the stream entity.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getStream(uint256 streamId) external view returns (LockupLinear.Stream memory stream);

    /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals.
    ///
    /// When the stream is warm, the streaming function is:
    ///
    /// $$
    /// f(x) = x * d + c
    /// $$
    ///
    /// Where:
    ///
    /// - $x$ is the elapsed time divided by the stream's total duration.
    /// - $d$ is the deposited amount.
    /// - $c$ is the cliff amount.
    ///
    /// Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited
    /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent
    /// to the total amount withdrawn.
    ///
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Creates a stream by setting the start time to `block.timestamp`, and the end time to
    /// the sum of `block.timestamp` and `params.durations.total. The stream is funded by `msg.sender` and is wrapped
    /// in an ERC-721 NFT.
    ///
    /// @dev Emits a {Transfer} and {CreateLockupLinearStream} event.
    ///
    /// Requirements:
    /// - All requirements in {createWithRange} must be met for the calculated parameters.
    ///
    /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
    /// @return streamId The id of the newly created stream.
    function createWithDurations(LockupLinear.CreateWithDurations calldata params)
        external
        returns (uint256 streamId);

    /// @notice Creates a stream with the provided start time and end time as the range. The stream is
    /// funded by `msg.sender` and is wrapped in an ERC-721 NFT.
    ///
    /// @dev Emits a {Transfer} and {CreateLockupLinearStream} event.
    ///
    /// Notes:
    /// - As long as the times are ordered, it is not an error for the start or the cliff time to be in the past.
    ///
    /// Requirements:
    /// - Must not be delegate called.
    /// - `params.totalAmount` must be greater than zero.
    /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`.
    /// - `params.range.start` must be less than or equal to `params.range.cliff`.
    /// - `params.range.cliff` must be less than `params.range.end`.
    /// - `params.range.end` must be in the future.
    /// - `params.recipient` must not be the zero address.
    /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets.
    ///
    /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
    /// @return streamId The id of the newly created stream.
    function createWithRange(LockupLinear.CreateWithRange calldata params) external returns (uint256 streamId);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { Lockup, LockupDynamic } from "../types/DataTypes.sol";
import { ISablierV2Lockup } from "./ISablierV2Lockup.sol";

/// @title ISablierV2LockupDynamic
/// @notice Creates and manages lockup streams with dynamic streaming functions.
interface ISablierV2LockupDynamic is ISablierV2Lockup {
    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when a stream is created.
    /// @param streamId The id of the newly created stream.
    /// @param funder The address which has funded the stream.
    /// @param sender The address from which to stream the assets, who will have the ability to cancel the stream.
    /// @param recipient The address toward which to stream the assets.
    /// @param amounts Struct containing (i) the deposit amount, (ii) the protocol fee amount, and (iii) the
    /// broker fee amount, all denoted in units of the asset's decimals.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param cancelable Boolean indicating whether the stream will be cancelable or not.
    /// @param segments The segments the protocol uses to compose the custom streaming curve.
    /// @param range Struct containing (i) the stream's start time and (ii) end time, both as Unix timestamps.
    /// @param broker The address of the broker who has helped create the stream, e.g. a front-end website.
    event CreateLockupDynamicStream(
        uint256 streamId,
        address funder,
        address indexed sender,
        address indexed recipient,
        Lockup.CreateAmounts amounts,
        IERC20 indexed asset,
        bool cancelable,
        LockupDynamic.Segment[] segments,
        LockupDynamic.Range range,
        address broker
    );

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice The maximum number of segments allowed in a stream.
    /// @dev This is initialized at construction time and cannot be changed later.
    function MAX_SEGMENT_COUNT() external view returns (uint256);

    /// @notice Retrieves the stream's range, which is a struct containing (i) the stream's start time and (ii) end
    /// time, both as Unix timestamps.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getRange(uint256 streamId) external view returns (LockupDynamic.Range memory range);

    /// @notice Retrieves the segments the protocol uses to compose the custom streaming curve.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getSegments(uint256 streamId) external view returns (LockupDynamic.Segment[] memory segments);

    /// @notice Retrieves the stream entity.
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function getStream(uint256 streamId) external view returns (LockupDynamic.Stream memory stream);

    /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals.
    ///
    /// When the stream is warm, the streaming function is:
    ///
    /// $$
    /// f(x) = x^{exp} * csa + \Sigma(esa)
    /// $$
    ///
    /// Where:
    ///
    /// - $x$ is the elapsed time divided by the total time in the current segment.
    /// - $exp$ is the current segment exponent.
    /// - $csa$ is the current segment amount.
    /// - $\Sigma(esa)$ is the sum of all elapsed segments' amounts.
    ///
    /// Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited
    /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent
    /// to the total amount withdrawn.
    ///
    /// @dev Reverts if `streamId` references a null stream.
    /// @param streamId The stream id for the query.
    function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of
    /// `block.timestamp` and all specified time deltas. The segment milestones are derived from these
    /// deltas. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT.
    ///
    /// @dev Emits a {Transfer} and {CreateLockupDynamicStream} event.
    ///
    /// Requirements:
    /// - All requirements in {createWithMilestones} must be met for the calculated parameters.
    ///
    /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
    /// @return streamId The id of the newly created stream.
    function createWithDeltas(LockupDynamic.CreateWithDeltas calldata params) external returns (uint256 streamId);

    /// @notice Creates a stream with the provided segment milestones, implying the end time from the last milestone.
    /// The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT.
    ///
    /// @dev Emits a {Transfer} and {CreateLockupDynamicStream} event.
    ///
    /// Notes:
    /// - As long as the segment milestones are arranged in ascending order, it is not an error for some
    /// of them to be in the past.
    ///
    /// Requirements:
    /// - Must not be delegate called.
    /// - `params.totalAmount` must be greater than zero.
    /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`.
    /// - `params.segments` must have at least one segment, but not more than `MAX_SEGMENT_COUNT`.
    /// - `params.startTime` must be less than the first segment's milestone.
    /// - The segment milestones must be arranged in ascending order.
    /// - The last segment milestone (i.e. the stream's end time) must be in the future.
    /// - The sum of the segment amounts must equal the deposit amount.
    /// - `params.recipient` must not be the zero address.
    /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets.
    ///
    /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
    /// @return streamId The id of the newly created stream.
    function createWithMilestones(LockupDynamic.CreateWithMilestones calldata params)
        external
        returns (uint256 streamId);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { UD2x18 } from "@prb/math/UD2x18.sol";
import { UD60x18 } from "@prb/math/UD60x18.sol";

// DataTypes.sol
//
// This file defines all structs used in V2 Core, most of which are organized under three namespaces:
//
// - Lockup
// - LockupDynamic
// - LockupLinear
//
// You will notice that some structs contain "slot" annotations - they are used to indicate the
// storage layout of the struct. It is more gas efficient to group small data types together so
// that they fit in a single 32-byte slot.

/// @notice Struct encapsulating the broker parameters passed to the create functions. Both can be set to zero.
/// @param account The address receiving the broker's fee.
/// @param fee The broker's percentage fee from the total amount, denoted as a fixed-point number where 1e18 is 100%.
struct Broker {
    address account;
    UD60x18 fee;
}

/// @notice Namespace for the structs used in both {SablierV2LockupLinear} and {SablierV2LockupDynamic}.
library Lockup {
    /// @notice Struct encapsulating the deposit, withdrawn, and refunded amounts, all denoted in units
    /// of the asset's decimals.
    /// @dev Because the deposited and the withdrawn amount are often read together, declaring them in
    /// the same slot saves gas.
    /// @param deposited The initial amount deposited in the stream, net of fees.
    /// @param withdrawn The cumulative amount withdrawn from the stream.
    /// @param refunded The amount refunded to the sender. Unless the stream was canceled, this is always zero.
    struct Amounts {
        // slot 0
        uint128 deposited;
        uint128 withdrawn;
        // slot 1
        uint128 refunded;
    }

    /// @notice Struct encapsulating the deposit amount, the protocol fee amount, and the broker fee amount,
    /// all denoted in units of the asset's decimals.
    /// @param deposit The amount to deposit in the stream.
    /// @param protocolFee The protocol fee amount.
    /// @param brokerFee The broker fee amount.
    struct CreateAmounts {
        uint128 deposit;
        uint128 protocolFee;
        uint128 brokerFee;
    }

    /// @notice Enum representing the different statuses of a stream.
    /// @custom:value PENDING Stream created but not started; assets are in a pending state.
    /// @custom:value STREAMING Active stream where assets are currently being streamed.
    /// @custom:value SETTLED All assets have been streamed; recipient is due to withdraw them.
    /// @custom:value CANCELED Canceled stream; remaining assets await recipient's withdrawal.
    /// @custom:value DEPLETED Depleted stream; all assets have been withdrawn and/or refunded.
    enum Status {
        PENDING, // value 0
        STREAMING, // value 1
        SETTLED, // value 2
        CANCELED, // value 3
        DEPLETED // value 4
    }
}

/// @notice Namespace for the structs used in {SablierV2LockupDynamic}.
library LockupDynamic {
    /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithDeltas} function.
    /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the
    /// same as `msg.sender`.
    /// @param recipient The address receiving the assets.
    /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential
    /// fees, all denoted in units of the asset's decimals.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param cancelable Indicates if the stream is cancelable.
    /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the
    /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero.
    /// @param segments Segments with deltas used to compose the custom streaming curve. Milestones are calculated by
    /// starting from `block.timestamp` and adding each delta to the previous milestone.
    struct CreateWithDeltas {
        address sender;
        bool cancelable;
        address recipient;
        uint128 totalAmount;
        IERC20 asset;
        Broker broker;
        SegmentWithDelta[] segments;
    }

    /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithMilestones}
    /// function.
    /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the
    /// same as `msg.sender`.
    /// @param startTime The Unix timestamp indicating the stream's start.
    /// @param cancelable Indicates if the stream is cancelable.
    /// @param recipient The address receiving the assets.
    /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential
    /// fees, all denoted in units of the asset's decimals.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the
    /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero.
    /// @param segments Segments used to compose the custom streaming curve.
    struct CreateWithMilestones {
        address sender;
        uint40 startTime;
        bool cancelable;
        address recipient;
        uint128 totalAmount;
        IERC20 asset;
        Broker broker;
        Segment[] segments;
    }

    /// @notice Struct encapsulating the time range.
    /// @param start The Unix timestamp indicating the stream's start.
    /// @param end The Unix timestamp indicating the stream's end.
    struct Range {
        uint40 start;
        uint40 end;
    }

    /// @notice Segment struct used in the Lockup Dynamic stream.
    /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals.
    /// @param exponent The exponent of this segment, denoted as a fixed-point number.
    /// @param milestone The Unix timestamp indicating this segment's end.
    struct Segment {
        // slot 0
        uint128 amount;
        UD2x18 exponent;
        uint40 milestone;
    }

    /// @notice Segment struct used at runtime in {SablierV2LockupDynamic.createWithDeltas}.
    /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals.
    /// @param exponent The exponent of this segment, denoted as a fixed-point number.
    /// @param delta The time difference in seconds between this segment and the previous one.
    struct SegmentWithDelta {
        uint128 amount;
        UD2x18 exponent;
        uint40 delta;
    }

    /// @notice Lockup Dynamic stream.
    /// @dev The fields are arranged like this to save gas via tight variable packing.
    /// @param sender The address streaming the assets, with the ability to cancel the stream.
    /// @param startTime The Unix timestamp indicating the stream's start.
    /// @param endTime The Unix timestamp indicating the stream's end.
    /// @param isCancelable Boolean indicating if the stream is cancelable.
    /// @param wasCanceled Boolean indicating if the stream was canceled.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param isDepleted Boolean indicating if the stream is depleted.
    /// @param isStream Boolean indicating if the struct entity exists.
    /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, all denoted in units of the
    /// asset's decimals.
    /// @param segments Segments used to compose the custom streaming curve.
    struct Stream {
        // slot 0
        address sender;
        uint40 startTime;
        uint40 endTime;
        bool isCancelable;
        bool wasCanceled;
        // slot 1
        IERC20 asset;
        bool isDepleted;
        bool isStream;
        // slot 2 and 3
        Lockup.Amounts amounts;
        // slots [4..n]
        Segment[] segments;
    }
}

/// @notice Namespace for the structs used in {SablierV2LockupLinear}.
library LockupLinear {
    /// @notice Struct encapsulating the parameters for the {SablierV2LockupLinear.createWithDurations} function.
    /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the
    /// same as `msg.sender`.
    /// @param recipient The address receiving the assets.
    /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential
    /// fees, all denoted in units of the asset's decimals.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param cancelable Indicates if the stream is cancelable.
    /// @param durations Struct containing (i) cliff period duration and (ii) total stream duration, both in seconds.
    /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the
    /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero.
    struct CreateWithDurations {
        address sender;
        address recipient;
        uint128 totalAmount;
        IERC20 asset;
        bool cancelable;
        Durations durations;
        Broker broker;
    }

    /// @notice Struct encapsulating the parameters for the {SablierV2LockupLinear.createWithRange} function.
    /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the
    /// same as `msg.sender`.
    /// @param recipient The address receiving the assets.
    /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential
    /// fees, all denoted in units of the asset's decimals.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param cancelable Indicates if the stream is cancelable.
    /// @param range Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as Unix
    /// timestamps.
    /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the
    /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero.
    struct CreateWithRange {
        address sender;
        address recipient;
        uint128 totalAmount;
        IERC20 asset;
        bool cancelable;
        Range range;
        Broker broker;
    }

    /// @notice Struct encapsulating the cliff duration and the total duration.
    /// @param cliff The cliff duration in seconds.
    /// @param total The total duration in seconds.
    struct Durations {
        uint40 cliff;
        uint40 total;
    }

    /// @notice Struct encapsulating the time range.
    /// @param start The Unix timestamp for the stream's start.
    /// @param cliff The Unix timestamp for the cliff period's end.
    /// @param end The Unix timestamp for the stream's end.
    struct Range {
        uint40 start;
        uint40 cliff;
        uint40 end;
    }

    /// @notice Lockup Linear stream.
    /// @dev The fields are arranged like this to save gas via tight variable packing.
    /// @param sender The address streaming the assets, with the ability to cancel the stream.
    /// @param startTime The Unix timestamp indicating the stream's start.
    /// @param cliffTime The Unix timestamp indicating the cliff period's end.
    /// @param isCancelable Boolean indicating if the stream is cancelable.
    /// @param wasCanceled Boolean indicating if the stream was canceled.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param endTime The Unix timestamp indicating the stream's end.
    /// @param isDepleted Boolean indicating if the stream is depleted.
    /// @param isStream Boolean indicating if the struct entity exists.
    /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, all denoted in units of the
    /// asset's decimals.
    struct Stream {
        // slot 0
        address sender;
        uint40 startTime;
        uint40 cliffTime;
        bool isCancelable;
        bool wasCanceled;
        // slot 1
        IERC20 asset;
        uint40 endTime;
        bool isDepleted;
        bool isStream;
        // slot 2 and 3
        Lockup.Amounts amounts;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {IEIP712} from "./IEIP712.sol";

/// @title AllowanceTransfer
/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts
/// @dev Requires user's token approval on the Permit2 contract
interface IAllowanceTransfer is IEIP712 {
    /// @notice Thrown when an allowance on a token has expired.
    /// @param deadline The timestamp at which the allowed amount is no longer valid
    error AllowanceExpired(uint256 deadline);

    /// @notice Thrown when an allowance on a token has been depleted.
    /// @param amount The maximum amount allowed
    error InsufficientAllowance(uint256 amount);

    /// @notice Thrown when too many nonces are invalidated.
    error ExcessiveInvalidation();

    /// @notice Emits an event when the owner successfully invalidates an ordered nonce.
    event NonceInvalidation(
        address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce
    );

    /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.
    event Approval(
        address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration
    );

    /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.
    event Permit(
        address indexed owner,
        address indexed token,
        address indexed spender,
        uint160 amount,
        uint48 expiration,
        uint48 nonce
    );

    /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.
    event Lockdown(address indexed owner, address token, address spender);

    /// @notice The permit data for a token
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice The permit message signed for a single token allownce
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The permit message signed for multiple token allowances
    struct PermitBatch {
        // the permit data for multiple token allowances
        PermitDetails[] details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The saved permissions
    /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    struct PackedAllowance {
        // amount allowed
        uint160 amount;
        // permission expiry
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice A token spender pair.
    struct TokenSpenderPair {
        // the token the spender is approved
        address token;
        // the spender address
        address spender;
    }

    /// @notice Details for a token transfer.
    struct AllowanceTransferDetails {
        // the owner of the token
        address from;
        // the recipient of the token
        address to;
        // the amount of the token
        uint160 amount;
        // the token to be transferred
        address token;
    }

    /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.
    /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]
    /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.
    function allowance(address user, address token, address spender)
        external
        view
        returns (uint160 amount, uint48 expiration, uint48 nonce);

    /// @notice Approves the spender to use up to amount of the specified token up until the expiration
    /// @param token The token to approve
    /// @param spender The spender address to approve
    /// @param amount The approved amount of the token
    /// @param expiration The timestamp at which the approval is no longer valid
    /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    function approve(address token, address spender, uint160 amount, uint48 expiration) external;

    /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitSingle Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitBatch Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;

    /// @notice Transfer approved tokens from one address to another
    /// @param from The address to transfer from
    /// @param to The address of the recipient
    /// @param amount The amount of the token to transfer
    /// @param token The token address to transfer
    /// @dev Requires the from address to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(address from, address to, uint160 amount, address token) external;

    /// @notice Transfer approved tokens in a batch
    /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers
    /// @dev Requires the from addresses to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;

    /// @notice Enables performing a "lockdown" of the sender's Permit2 identity
    /// by batch revoking approvals
    /// @param approvals Array of approvals to revoke.
    function lockdown(TokenSpenderPair[] calldata approvals) external;

    /// @notice Invalidate nonces for a given (token, spender) pair
    /// @param token The token to invalidate nonces for
    /// @param spender The spender to invalidate nonces for
    /// @param newNonce The new nonce to set. Invalidates all nonces less than it.
    /// @dev Can't invalidate more than 2**16 nonces per transaction.
    function invalidateNonces(address token, address spender, uint48 newNonce) external;
}

File 10 of 50 : OnlyDelegateCall.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { Errors } from "../libraries/Errors.sol";

/// @title OnlyDelegateCall
/// @notice This contract implements logic to allow only delegate calls.
abstract contract OnlyDelegateCall {
    /// @dev The address of the original contract that was deployed.
    address private immutable _original;

    /// @dev Sets the original contract address.
    constructor() {
        _original = address(this);
    }

    /// @notice Allows only delegate calls.
    modifier onlyDelegateCall() {
        _allowOnlyDelegateCall();
        _;
    }

    /// @dev This function checks whether the current call is a delegate call, and reverts if it is not.
    ///
    /// - A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into
    /// every function that uses them. The `_original` address would get copied in every place the modifier is used,
    /// which would increase the contract size. By using a function instead, we can avoid this duplication of code
    /// and reduce the overall size of the contract.
    function _allowOnlyDelegateCall() private view {
        if (address(this) == _original) {
            revert Errors.CallNotDelegateCall();
        }
    }
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISablierV2Lockup } from "@sablier/v2-core/interfaces/ISablierV2Lockup.sol";
import { ISablierV2LockupLinear } from "@sablier/v2-core/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2LockupDynamic } from "@sablier/v2-core/interfaces/ISablierV2LockupDynamic.sol";
import { LockupDynamic, LockupLinear } from "@sablier/v2-core/types/DataTypes.sol";

import { Batch, Permit2Params } from "../types/DataTypes.sol";

/// @title ISablierV2ProxyTarget
/// @notice Proxy target with stateless scripts for interacting with Sablier V2, designed to be used by
/// stream senders.
/// @dev Intended for use with an instance of PRBProxy through delegate calls. Any standard calls will be reverted.
interface ISablierV2ProxyTarget {
    /*//////////////////////////////////////////////////////////////////////////
                                 SABLIER-V2-LOCKUP
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Cancels multiple streams across different lockup contracts.
    ///
    /// @dev Notes:
    /// - All refunded assets are forwarded to the proxy owner.
    /// - It is assumed that `assets` includes all assets associated with the stream ids in `batch`. If any asset
    /// is missing, the refunded amount will be left in the proxy.
    ///
    /// Requirements:
    /// - Must be delegate called.
    /// - There must be at least one element in `batch`.
    ///
    /// @param batch An array of structs, each encapsulating the lockup contract's address and the stream id to cancel.
    /// @param assets The contract addresses of the ERC-20 assets used for streaming.
    function batchCancelMultiple(Batch.CancelMultiple[] calldata batch, IERC20[] calldata assets) external;

    /// @notice Mirror for {ISablierV2Lockup.burn}.
    /// @dev Must be delegate called.
    function burn(ISablierV2Lockup lockup, uint256 streamId) external;

    /// @notice Mirror for {ISablierV2Lockup.cancel}.
    /// @dev Must be delegate called.
    function cancel(ISablierV2Lockup lockup, uint256 streamId) external;

    /// @notice Mirror for {ISablierV2Lockup.cancelMultiple}.
    ///
    /// @dev Notes:
    /// - All refunded assets are forwarded to the proxy owner.
    /// - It is assumed that `assets` includes all assets associated with `streamIds`. If any asset is missing, the
    /// refunded amount will be left in the proxy.
    ///
    /// Requirements:
    /// - Must be delegate called.
    ///
    /// @param lockup The address of the lockup streaming contract.
    /// @param assets The contract addresses of the ERC-20 assets used for streaming.
    /// @param streamIds The stream ids to cancel.
    function cancelMultiple(ISablierV2Lockup lockup, IERC20[] calldata assets, uint256[] calldata streamIds) external;

    /// @notice Mirror for {ISablierV2Lockup.renounce}.
    /// @dev Must be delegate called.
    function renounce(ISablierV2Lockup lockup, uint256 streamId) external;

    /// @notice Mirror for {ISablierV2Lockup.withdraw}.
    /// @dev Must be delegate called.
    function withdraw(ISablierV2Lockup lockup, uint256 streamId, address to, uint128 amount) external;

    /// @notice Mirror for {ISablierV2Lockup.withdrawMax}.
    /// @dev Must be delegate called.
    function withdrawMax(ISablierV2Lockup lockup, uint256 streamId, address to) external;

    /// @notice Mirror for {ISablierV2Lockup.withdrawMaxAndTransfer}.
    /// @dev Must be delegate called.
    function withdrawMaxAndTransfer(ISablierV2Lockup lockup, uint256 streamId, address newRecipient) external;

    /*//////////////////////////////////////////////////////////////////////////
                              SABLIER-V2-LOCKUP-LINEAR
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Creates a batch of Lockup Linear streams using `createWithDurations`. Assets are transferred to the
    /// proxy via Permit2.
    ///
    /// @dev Requirements:
    /// - Must be delegate called.
    /// - There must be at least one element in `batch`.
    /// - All requirements from {ISablierV2LockupLinear.createWithDurations} must be met for each stream.
    ///
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param batch An array of structs, each encapsulating a subset of the parameters of
    /// {SablierV2LockupLinear.createWithDurations}.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamIds The ids of the newly created streams.
    function batchCreateWithDurations(
        ISablierV2LockupLinear lockupLinear,
        IERC20 asset,
        Batch.CreateWithDurations[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256[] memory streamIds);

    /// @notice Creates a batch of Lockup Linear streams using `createWithRange`. Assets are transferred to the proxy
    /// via Permit2.
    ///
    /// @dev Requirements:
    /// - Must be delegate called.
    /// - There must be at least one element in `batch`.
    /// - All requirements from {ISablierV2LockupLinear.createWithRange} must be met for each stream.
    ///
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param batch An array of structs, each encapsulating a subset of the parameters of
    /// {SablierV2LockupLinear.createWithRange}.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamIds The ids of the newly created streams.
    function batchCreateWithRange(
        ISablierV2LockupLinear lockupLinear,
        IERC20 asset,
        Batch.CreateWithRange[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256[] memory streamIds);

    /// @notice Cancels a Lockup stream and creates a new Lockup Linear stream using `createWithDurations`. Assets are
    /// transferred to the proxy via Permit2.
    ///
    /// @dev Notes:
    /// - `streamId` can reference either a Lockup Linear or a Lockup Dynamic stream.
    /// - See {ISablierV2Lockup.cancel} and {ISablierV2LockupLinear.createWithDurations} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    ///
    /// @param lockup The address of the lockup streaming contract where the stream to cancel is.
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract to use for creating the new stream.
    /// @param streamId The id of the stream to cancel.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return newStreamId The id of the newly created stream.
    function cancelAndCreateWithDurations(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithDurations calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 newStreamId);

    /// @notice Cancels a Lockup stream and creates a new Lockup Linear stream using `createWithRange`. Assets are
    /// transferred to the proxy via Permit2.
    ///
    /// @dev Notes:
    /// - `streamId` can reference either a Lockup Linear or a Lockup Dynamic stream.
    /// - See {ISablierV2Lockup.cancel} and {ISablierV2LockupLinear.createWithRange} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    ///
    /// @param lockup The address of the lockup streaming contract where the stream to cancel is.
    /// @param streamId The id of the stream to cancel.
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract to use for creating the new stream.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return newStreamId The id of the newly created stream.
    function cancelAndCreateWithRange(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithRange calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 newStreamId);

    /// @notice Mirror for {SablierV2LockupLinear.createWithDurations}. Assets are transferred to the proxy via Permit2.
    /// @dev Must be delegate called.
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamId The id of the newly created stream.
    function createWithDurations(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithDurations calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 streamId);

    /// @notice Mirror for {SablierV2LockupLinear.createWithRange}. Assets are transferred to the proxy via Permit2.
    /// @dev Must be delegate called.
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamId The id of the newly created stream.
    function createWithRange(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithRange calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 streamId);

    /// @notice Wraps the native asset payment in ERC-20 form and creates a Lockup Linear stream using
    /// `createWithDurations`.
    ///
    /// @dev Notes:
    /// - `createParams.totalAmount` is overwritten with `msg.value`.
    /// - See {ISablierV2LockupLinear.createWithDurations} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    /// - The ERC-20 amount credited by the wrapper contract must be equal to `msg.value`.
    ///
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    function wrapAndCreateWithDurations(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithDurations memory createParams
    )
        external
        payable
        returns (uint256 streamId);

    /// @notice Wraps the native asset payment in ERC-20 form and creates a Lockup Linear stream using
    /// `createWithRange`.
    ///
    /// @dev Notes:
    /// - `createParams.totalAmount` is overwritten with `msg.value`.
    /// - See {ISablierV2LockupLinear.createWithRange} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    /// - The ERC-20 amount credited by the wrapper contract must be equal to `msg.value`.
    ///
    /// @param lockupLinear The address of the {SablierV2LockupLinear} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    function wrapAndCreateWithRange(
        ISablierV2LockupLinear lockupLinear,
        LockupLinear.CreateWithRange memory createParams
    )
        external
        payable
        returns (uint256 streamId);

    /*//////////////////////////////////////////////////////////////////////////
                             SABLIER-V2-LOCKUP-DYNAMIC
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Creates a batch of Lockup Dynamic streams using `createWithDeltas`. Assets are transferred to the proxy
    /// via Permit2.
    ///
    /// @dev Requirements:
    /// - Must be delegate called.
    /// - There must be at least one element in `batch`.
    /// - All requirements from {ISablierV2LockupDynamic.createWithDeltas} must be met for each stream.
    ///
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param batch An array of structs, each encapsulating a subset of the parameters of
    /// {SablierV2LockupDynamic.createWithDeltas}.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamIds The ids of the newly created streams.
    function batchCreateWithDeltas(
        ISablierV2LockupDynamic lockupDynamic,
        IERC20 asset,
        Batch.CreateWithDeltas[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256[] memory streamIds);

    /// @notice Creates a batch of Lockup Dynamic streams using `createWithMilestones`. Assets are transferred to the
    /// proxy via Permit2.
    ///
    /// @dev Requirements:
    /// - Must be delegate called.
    /// - There must be at least one element in `batch`.
    /// - All requirements from {ISablierV2LockupDynamic.createWithMilestones} must be met for each stream.
    ///
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract.
    /// @param asset The contract address of the ERC-20 asset used for streaming.
    /// @param batch An array of structs, each encapsulating a subset of the parameters of
    /// {SablierV2LockupDynamic.createWithMilestones}.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamIds The ids of the newly created streams.
    function batchCreateWithMilestones(
        ISablierV2LockupDynamic lockupDynamic,
        IERC20 asset,
        Batch.CreateWithMilestones[] calldata batch,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256[] memory streamIds);

    /// @notice Cancels a Lockup stream and creates a new Lockup Dynamic stream using `createWithDeltas`. Assets are
    /// transferred to the proxy via Permit2.
    ///
    /// @dev Notes:
    /// - `streamId` can reference either a Lockup Linear or a Lockup Dynamic stream.
    /// - See {ISablierV2Lockup.cancel} and {ISablierV2LockupDynamic.createWithDeltas} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    ///
    /// @param lockup The address of the lockup streaming contract where the stream to cancel is.
    /// @param streamId The id of the stream to cancel.
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract to use for creating the new stream.
    /// @param createParams A struct encapsulating the create function parameters, which are documented in V2 Core.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return newStreamId The id of the newly created stream.
    function cancelAndCreateWithDeltas(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupDynamic lockupDynamic,
        LockupDynamic.CreateWithDeltas calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 newStreamId);

    /// @notice Cancels a Lockup stream and creates a new Lockup Dynamic stream using `createWithMilestones`. Assets are
    /// transferred to the proxy via Permit2.
    ///
    /// @dev Notes:
    /// - `streamId` can reference either a Lockup Linear or a Lockup Dynamic stream.
    /// - See {ISablierV2Lockup.cancel} and {ISablierV2LockupDynamic.createWithMilestones} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    ///
    /// @param lockup The address of the lockup streaming contract where the stream to cancel is.
    /// @param streamId The id of the stream to cancel.
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract to use for creating the new stream.
    /// @param createParams A struct encapsulating the create function parameters, which are documented in V2 Core.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return newStreamId The id of the newly created stream.
    function cancelAndCreateWithMilestones(
        ISablierV2Lockup lockup,
        uint256 streamId,
        ISablierV2LockupDynamic lockupDynamic,
        LockupDynamic.CreateWithMilestones calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 newStreamId);

    /// @notice Mirror for {SablierV2LockupDynamic.createWithDeltas}. Assets are transferred to the proxy via Permit2.
    /// @dev Must be delegate called.
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract.
    /// @param createParams A struct encapsulating the create function parameters, which are documented in V2 Core.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamId The id of the newly created stream.
    function createWithDeltas(
        ISablierV2LockupDynamic lockupDynamic,
        LockupDynamic.CreateWithDeltas calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 streamId);

    /// @notice Mirror for {SablierV2LockupDynamic.createWithMilestones}. Assets are transferred to the proxy via
    /// Permit2.
    /// @dev Must be delegate called.
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    /// @param permit2Params A struct encapsulating the parameters needed for Permit2, most importantly the signature.
    /// @return streamId The id of the newly created stream.
    function createWithMilestones(
        ISablierV2LockupDynamic lockupDynamic,
        LockupDynamic.CreateWithMilestones calldata createParams,
        Permit2Params calldata permit2Params
    )
        external
        returns (uint256 streamId);

    /// @notice Wraps the native asset payment in ERC-20 form and creates a Lockup Dynamic stream using
    /// `createWithDeltas`.
    ///
    /// @dev Notes:
    /// - `createParams.totalAmount` is overwritten with `msg.value`.
    /// - See {ISablierV2LockupDynamic.createWithDeltas} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    /// - The ERC-20 amount credited by the wrapper contract must be equal to `msg.value`.
    ///
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    /// @return streamId The id of the newly created stream.
    function wrapAndCreateWithDeltas(
        ISablierV2LockupDynamic lockupDynamic,
        LockupDynamic.CreateWithDeltas memory createParams
    )
        external
        payable
        returns (uint256 streamId);

    /// @notice Wraps the native asset payment in ERC-20 form and creates a Lockup Dynamic stream using
    /// `createWithMilestones`.
    ///
    /// @dev Notes:
    /// - `createParams.totalAmount` is overwritten with `msg.value`.
    /// - See {ISablierV2LockupDynamic.createWithMilestones} for full documentation.
    ///
    /// Requirements:
    /// - Must be delegate called.
    /// - The ERC-20 amount credited by the wrapper contract must be equal to `msg.value`.
    ///
    /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract.
    /// @param createParams Struct encapsulating the function parameters, which are documented in V2 Core.
    /// @return streamId The id of the newly created stream.
    function wrapAndCreateWithMilestones(
        ISablierV2LockupDynamic lockupDynamic,
        LockupDynamic.CreateWithMilestones memory createParams
    )
        external
        payable
        returns (uint256 streamId);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title IWrappedNativeAsset
/// @notice An interface for contracts that wrap native assets in ERC-20 form, such as WETH.
/// @dev A generic name is used instead of "WETH" to accommodate chains with different native assets.
interface IWrappedNativeAsset is IERC20 {
    /// @notice Deposits native assets to receive ERC-20 wrapped assets.
    function deposit() external payable;

    /// @notice Withdraws ERC-20 wrapped assets to obtain native assets.
    /// @param amount The amount of ERC-20 wrapped assets to withdraw.
    function withdraw(uint256 amount) external;
}

File 13 of 50 : Errors.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

/// @title Errors
/// @notice Library containing all custom errors the protocol may revert with.
library Errors {
    /*//////////////////////////////////////////////////////////////////////////
                                      GENERICS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when trying to perform a standard call to a function that allows only delegate calls.
    error CallNotDelegateCall();

    /*//////////////////////////////////////////////////////////////////////////
                              SABLIER-V2-PROXY-PLUGIN
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when the caller is an unknown address, which is not listed in the archive.
    error SablierV2ProxyPlugin_UnknownCaller(address caller);

    /*//////////////////////////////////////////////////////////////////////////
                              SABLIER-V2-PROXY-TARGET
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when trying to perform an action that requires the batch size to not be zero.
    error SablierV2ProxyTarget_BatchSizeZero();

    /// @notice Thrown when trying to wrap and create a stream and the credit amount is not equal to `msg.value`.
    error SablierV2ProxyTarget_CreditAmountMismatch(uint256 msgValue, uint256 creditAmount);
}

File 14 of 50 : DataTypes.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { ISablierV2Lockup } from "@sablier/v2-core/interfaces/ISablierV2Lockup.sol";
import { Broker, LockupDynamic, LockupLinear } from "@sablier/v2-core/types/DataTypes.sol";
import { IAllowanceTransfer } from "permit2/interfaces/IAllowanceTransfer.sol";

library Batch {
    /// @notice A struct encapsulating the lockup contract's address and the stream ids to cancel.
    struct CancelMultiple {
        ISablierV2Lockup lockup;
        uint256[] streamIds;
    }

    /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithDelta} except for the asset.
    struct CreateWithDeltas {
        address sender;
        bool cancelable;
        address recipient;
        uint128 totalAmount;
        Broker broker;
        LockupDynamic.SegmentWithDelta[] segments;
    }

    /// @notice A struct encapsulating all parameters of {SablierV2LockupLinear.createWithDurations} except for the
    /// asset.
    struct CreateWithDurations {
        address sender;
        address recipient;
        uint128 totalAmount;
        bool cancelable;
        LockupLinear.Durations durations;
        Broker broker;
    }

    /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithMilestones} except for the
    /// asset.
    struct CreateWithMilestones {
        address sender;
        uint40 startTime;
        bool cancelable;
        address recipient;
        uint128 totalAmount;
        Broker broker;
        LockupDynamic.Segment[] segments;
    }

    /// @notice A struct encapsulating all parameters of {SablierV2LockupLinear.createWithRange} except for the asset.
    struct CreateWithRange {
        address sender;
        address recipient;
        uint128 totalAmount;
        bool cancelable;
        LockupLinear.Range range;
        Broker broker;
    }
}

/// @notice A struct encapsulating the parameters needed for Permit2.
/// @dev See the full documentation at https://github.com/Uniswap/permit2.
/// @param permitSingle The permit message signed for a single token allowance.
/// @param signature The ECDSA signature of the permit, which contains the three parameters (r,s,v).
struct Permit2Params {
    IAllowanceTransfer.PermitSingle permitSingle;
    bytes signature;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    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");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    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");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 17 of 50 : IPRBProxyPlugin.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

/// @title IPRBProxyPlugin
/// @notice Interface for plugin contracts that can be installed on a proxy.
/// @dev Plugins are contracts that enable the proxy to interact with and respond to calls from other contracts. These
/// plugins are run via the proxy's fallback function.
///
/// This interface is meant to be directly inherited by plugin implementations.
interface IPRBProxyPlugin {
    /// @notice Retrieves the methods implemented by the plugin.
    /// @dev The registry pulls these methods when installing the plugin.
    ///
    /// Requirements:
    /// - The plugin must implement at least one method.
    ///
    /// @return methods The array of the methods implemented by the plugin.
    function getMethods() external returns (bytes4[] memory methods);
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

import { IPRBProxy } from "./IPRBProxy.sol";
import { IPRBProxyPlugin } from "./IPRBProxyPlugin.sol";

/// @title IPRBProxyRegistry
/// @notice Deploys new proxies via CREATE2 and keeps a registry of owners to proxies. Proxies can only be deployed
/// once per owner, and they cannot be transferred. The registry also supports installing plugins, which are used
/// for extending the functionality of the proxy.
interface IPRBProxyRegistry {
    /*//////////////////////////////////////////////////////////////////////////
                                       ERRORS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Thrown when an action requires the caller to have a proxy.
    error PRBProxyRegistry_CallerDoesNotHaveProxy(address caller);

    /// @notice Thrown when an action requires the owner to not have a proxy.
    error PRBProxyRegistry_OwnerHasProxy(address owner, IPRBProxy proxy);

    /// @notice Thrown when trying to install a plugin that implements a method already implemented by another
    /// installed plugin.
    error PRBProxyRegistry_PluginMethodCollision(
        IPRBProxyPlugin currentPlugin, IPRBProxyPlugin newPlugin, bytes4 method
    );

    /// @notice Thrown when trying to uninstall an unknown plugin.
    error PRBProxyRegistry_PluginUnknown(IPRBProxyPlugin plugin);

    /// @notice Thrown when trying to install a plugin that doesn't implement any method.
    error PRBProxyRegistry_PluginWithZeroMethods(IPRBProxyPlugin plugin);

    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when a new proxy is deployed.
    event DeployProxy(address indexed operator, address indexed owner, IPRBProxy proxy);

    /// @notice Emitted when a plugin is installed.
    event InstallPlugin(
        address indexed owner, IPRBProxy indexed proxy, IPRBProxyPlugin indexed plugin, bytes4[] methods
    );

    /// @notice Emitted when an envoy permission is updated.
    event SetPermission(
        address indexed owner, IPRBProxy indexed proxy, address indexed envoy, address target, bool permission
    );

    /// @notice Emitted when a plugin is uninstalled.
    event UninstallPlugin(
        address indexed owner, IPRBProxy indexed proxy, IPRBProxyPlugin indexed plugin, bytes4[] methods
    );

    /*//////////////////////////////////////////////////////////////////////////
                                      STRUCTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @param owner The address of the user who will own the proxy.
    /// @param target The address of the target to delegate call to. Can be set to zero.
    /// @param data The address of the call data to pass to the target. Can be set to zero.
    struct ConstructorParams {
        address owner;
        address target;
        bytes data;
    }

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice The release version of the proxy system, which applies to both the registry and deployed proxies.
    /// @dev This is stored in the registry rather than the proxy to save gas for end users.
    function VERSION() external view returns (string memory);

    /// @notice The parameters used in constructing the proxy, which the registry sets transiently during proxy
    /// deployment.
    /// @dev The proxy constructor fetches these parameters.
    function constructorParams() external view returns (address owner, address target, bytes memory data);

    /// @notice Retrieves the list of installed methods for the provided plugin.
    /// @dev An empty array is returned if the plugin is unknown.
    /// @param owner The proxy owner for the query.
    /// @param plugin The plugin for the query.
    function getMethodsByOwner(address owner, IPRBProxyPlugin plugin) external view returns (bytes4[] memory methods);

    /// @notice Retrieves the list of installed methods for the provided plugin.
    /// @dev An empty array is returned if the plugin is unknown.
    /// @param proxy The proxy for the query.
    /// @param plugin The plugin for the query.
    function getMethodsByProxy(
        IPRBProxy proxy,
        IPRBProxyPlugin plugin
    )
        external
        view
        returns (bytes4[] memory methods);

    /// @notice Retrieves a boolean flag that indicates whether the provided envoy has permission to call the provided
    /// target.
    /// @param owner The proxy owner for the query.
    /// @param envoy The address with permission to call the target.
    /// @param target The address of the target.
    function getPermissionByOwner(
        address owner,
        address envoy,
        address target
    )
        external
        view
        returns (bool permission);

    /// @notice Retrieves a boolean flag that indicates whether the provided envoy has permission to call the provided
    /// target.
    /// @param proxy The proxy for the query.
    /// @param envoy The address with permission to call the target.
    /// @param target The address of the target.
    function getPermissionByProxy(
        IPRBProxy proxy,
        address envoy,
        address target
    )
        external
        view
        returns (bool permission);

    /// @notice Retrieves the address of the plugin installed for the provided method selector.
    /// @dev The zero address is returned if no plugin is installed.
    /// @param owner The proxy owner for the query.
    /// @param method The method signature for the query.
    function getPluginByOwner(address owner, bytes4 method) external view returns (IPRBProxyPlugin plugin);

    /// @notice Retrieves the address of the plugin installed for the provided method selector.
    /// @dev The zero address is returned if no plugin is installed.
    /// @param proxy The proxy for the query.
    /// @param method The method signature for the query.
    function getPluginByProxy(IPRBProxy proxy, bytes4 method) external view returns (IPRBProxyPlugin plugin);

    /// @notice Retrieves the proxy for the provided owner.
    /// @param owner The user address for the query.
    function getProxy(address owner) external view returns (IPRBProxy proxy);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Deploys a new proxy for the caller.
    ///
    /// @dev Emits a {DeployProxy} event.
    ///
    /// Requirements:
    /// - The caller must not have a proxy.
    ///
    /// @return proxy The address of the newly deployed proxy.
    function deploy() external returns (IPRBProxy proxy);

    /// @notice This function performs two actions:
    /// 1. Deploys a new proxy for the caller
    /// 2. Delegate calls to the provided target, returning the data it gets back, and bubbling up any potential revert.
    ///
    /// @dev Emits a {DeployProxy} and an {Execute} event.
    ///
    /// Requirements:
    /// - The caller must not have a proxy.
    /// - `target` must be a contract.
    ///
    /// @param target The address of the target.
    /// @param data Function selector plus ABI encoded data.
    /// @return proxy The address of the newly deployed proxy.
    function deployAndExecute(address target, bytes calldata data) external returns (IPRBProxy proxy);

    /// @notice This function performs three actions:
    /// 1. Deploys a new proxy for the caller
    /// 2. Delegate calls to the provided target, returning the data it gets back, and bubbling up any potential revert.
    /// 3. Installs the provided plugin on the newly deployed proxy.
    ///
    /// @dev Emits a {DeployProxy} and an {InstallPlugin} event.
    ///
    /// Requirements:
    /// - The caller must not have a proxy.
    /// - See the requirements in `installPlugin`.
    /// - See the requirements in `execute`.
    ///
    /// @param plugin The address of the plugin to install.
    /// @return proxy The address of the newly deployed proxy.
    function deployAndExecuteAndInstallPlugin(
        address target,
        bytes calldata data,
        IPRBProxyPlugin plugin
    )
        external
        returns (IPRBProxy proxy);

    /// @notice This function performs two actions:
    /// 1. Deploys a new proxy for the caller.
    /// 2. Installs the provided plugin on the newly deployed proxy.
    ///
    /// @dev Emits a {DeployProxy} and an {InstallPlugin} event.
    ///
    /// Requirements:
    /// - The caller must not have a proxy.
    /// - See the requirements in `installPlugin`.
    ///
    /// @param plugin The address of the plugin to install.
    /// @return proxy The address of the newly deployed proxy.
    function deployAndInstallPlugin(IPRBProxyPlugin plugin) external returns (IPRBProxy proxy);

    /// @notice Deploys a new proxy for the provided owner.
    ///
    /// @dev Emits a {DeployProxy} event.
    ///
    /// Requirements:
    /// - The owner must not have a proxy.
    ///
    /// @param owner The owner of the proxy.
    /// @return proxy The address of the newly deployed proxy.
    function deployFor(address owner) external returns (IPRBProxy proxy);

    /// @notice Installs the provided plugin on the caller's proxy, and saves the list of methods implemented by the
    /// plugin so that they can be referenced later.
    ///
    /// @dev Emits an {InstallPlugin} event.
    ///
    /// Notes:
    /// - Installing a plugin is a potentially dangerous operation, because anyone can run the plugin.
    /// - Plugin methods that have the same selector as {PRBProxy.execute} can be installed, but they can never be run.
    ///
    /// Requirements:
    /// - The caller must have a proxy.
    /// - The plugin must have at least one implemented method.
    /// - There must be no method collision with any other installed plugin.
    ///
    /// @param plugin The address of the plugin to install.
    function installPlugin(IPRBProxyPlugin plugin) external;

    /// @notice Gives or takes a permission from an envoy to call the provided target and function selector
    /// on behalf of the caller's proxy.
    ///
    /// @dev Emits a {SetPermission} event.
    ///
    /// Notes:
    /// - It is not an error to set the same permission.
    ///
    /// Requirements:
    /// - The caller must have a proxy.
    ///
    /// @param envoy The address of the account given permission to call the target.
    /// @param target The address of the target.
    /// @param permission The boolean permission to set.
    function setPermission(address envoy, address target, bool permission) external;

    /// @notice Uninstalls the plugin from the caller's proxy, and removes the list of methods originally implemented by
    /// the plugin.
    ///
    /// @dev Emits an {UninstallPlugin} event.
    ///
    /// Requirements:
    /// - The caller must have a proxy.
    /// - The plugin must be a known, previously installed plugin.
    ///
    /// @param plugin The address of the plugin to uninstall.
    function uninstallPlugin(IPRBProxyPlugin plugin) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { UD60x18 } from "@prb/math/UD60x18.sol";

import { IAdminable } from "./IAdminable.sol";
import { ISablierV2Comptroller } from "./ISablierV2Comptroller.sol";

/// @title ISablierV2Base
/// @notice Base logic for all Sablier V2 streaming contracts.
interface ISablierV2Base is IAdminable {
    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when the admin claims all protocol revenues accrued for a particular ERC-20 asset.
    /// @param admin The address of the contract admin.
    /// @param asset The contract address of the ERC-20 asset the protocol revenues have been claimed for.
    /// @param protocolRevenues The amount of protocol revenues claimed, denoted in units of the asset's decimals.
    event ClaimProtocolRevenues(address indexed admin, IERC20 indexed asset, uint128 protocolRevenues);

    /// @notice Emitted when the admin sets a new comptroller contract.
    /// @param admin The address of the contract admin.
    /// @param oldComptroller The address of the old comptroller contract.
    /// @param newComptroller The address of the new comptroller contract.
    event SetComptroller(
        address indexed admin, ISablierV2Comptroller oldComptroller, ISablierV2Comptroller newComptroller
    );

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Retrieves the maximum fee that can be charged by the protocol or a broker, denoted as a fixed-point
    /// number where 1e18 is 100%.
    /// @dev This value is hard coded as a constant.
    function MAX_FEE() external view returns (UD60x18);

    /// @notice Retrieves the address of the comptroller contract, responsible for the Sablier V2 protocol
    /// configuration.
    function comptroller() external view returns (ISablierV2Comptroller);

    /// @notice Retrieves the protocol revenues accrued for the provided ERC-20 asset, in units of the asset's
    /// decimals.
    /// @param asset The contract address of the ERC-20 asset to query.
    function protocolRevenues(IERC20 asset) external view returns (uint128 revenues);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Claims all accumulated protocol revenues for the provided ERC-20 asset.
    ///
    /// @dev Emits a {ClaimProtocolRevenues} event.
    ///
    /// Requirements:
    /// - `msg.sender` must be the contract admin.
    ///
    /// @param asset The contract address of the ERC-20 asset for which to claim protocol revenues.
    function claimProtocolRevenues(IERC20 asset) external;

    /// @notice Assigns a new comptroller contract responsible for the protocol configuration.
    ///
    /// @dev Emits a {SetComptroller} event.
    ///
    /// Notes:
    /// - Does not revert if the comptroller is the same.
    ///
    /// Requirements:
    /// - `msg.sender` must be the contract admin.
    ///
    /// @param newComptroller The address of the new comptroller contract.
    function setComptroller(ISablierV2Comptroller newComptroller) external;
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

/// @title ISablierV2NFTDescriptor
/// @notice This contract generates the URI describing the Sablier V2 stream NFTs.
/// @dev Inspired by Uniswap V3 Positions NFTs.
interface ISablierV2NFTDescriptor {
    /// @notice Produces the URI describing a particular stream NFT.
    /// @dev This is a data URI with the JSON contents directly inlined.
    /// @param sablier The address of the Sablier contract the stream was created in.
    /// @param streamId The id of the stream for which to produce a description.
    /// @return uri The URI of the ERC721-compliant metadata.
    function tokenURI(IERC721Metadata sablier, uint256 streamId) external view returns (string memory uri);
}

File 22 of 50 : UD2x18.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

/*

██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗
██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║
██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║
██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║
██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║
╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝

██╗   ██╗██████╗ ██████╗ ██╗  ██╗ ██╗ █████╗
██║   ██║██╔══██╗╚════██╗╚██╗██╔╝███║██╔══██╗
██║   ██║██║  ██║ █████╔╝ ╚███╔╝ ╚██║╚█████╔╝
██║   ██║██║  ██║██╔═══╝  ██╔██╗  ██║██╔══██╗
╚██████╔╝██████╔╝███████╗██╔╝ ██╗ ██║╚█████╔╝
 ╚═════╝ ╚═════╝ ╚══════╝╚═╝  ╚═╝ ╚═╝ ╚════╝

*/

import "./ud2x18/Casting.sol";
import "./ud2x18/Constants.sol";
import "./ud2x18/Errors.sol";
import "./ud2x18/ValueType.sol";

File 23 of 50 : UD60x18.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

/*

██████╗ ██████╗ ██████╗ ███╗   ███╗ █████╗ ████████╗██╗  ██╗
██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║  ██║
██████╔╝██████╔╝██████╔╝██╔████╔██║███████║   ██║   ███████║
██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║   ██║   ██╔══██║
██║     ██║  ██║██████╔╝██║ ╚═╝ ██║██║  ██║   ██║   ██║  ██║
╚═╝     ╚═╝  ╚═╝╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝

██╗   ██╗██████╗  ██████╗  ██████╗ ██╗  ██╗ ██╗ █████╗
██║   ██║██╔══██╗██╔════╝ ██╔═████╗╚██╗██╔╝███║██╔══██╗
██║   ██║██║  ██║███████╗ ██║██╔██║ ╚███╔╝ ╚██║╚█████╔╝
██║   ██║██║  ██║██╔═══██╗████╔╝██║ ██╔██╗  ██║██╔══██╗
╚██████╔╝██████╔╝╚██████╔╝╚██████╔╝██╔╝ ██╗ ██║╚█████╔╝
 ╚═════╝ ╚═════╝  ╚═════╝  ╚═════╝ ╚═╝  ╚═╝ ╚═╝ ╚════╝

*/

import "./ud60x18/Casting.sol";
import "./ud60x18/Constants.sol";
import "./ud60x18/Conversions.sol";
import "./ud60x18/Errors.sol";
import "./ud60x18/Helpers.sol";
import "./ud60x18/Math.sol";
import "./ud60x18/ValueType.sol";

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

/// @title IAdminable
/// @notice Contract module that provides a basic access control mechanism, with an admin that can be
/// granted exclusive access to specific functions. The inheriting contract must set the initial admin
/// in the constructor.
interface IAdminable {
    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when the admin is transferred.
    /// @param oldAdmin The address of the old admin.
    /// @param newAdmin The address of the new admin.
    event TransferAdmin(address indexed oldAdmin, address indexed newAdmin);

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice The address of the admin account or contract.
    function admin() external view returns (address);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Transfers the contract admin to a new address.
    ///
    /// @dev Notes:
    /// - Does not revert if the admin is the same.
    /// - This function can potentially leave the contract without an admin, thereby removing any
    /// functionality that is only available to the admin.
    ///
    /// Requirements:
    /// - `msg.sender` must be the contract admin.
    ///
    /// @param newAdmin The address of the new admin.
    function transferAdmin(address newAdmin) external;
}

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { UD60x18 } from "@prb/math/UD60x18.sol";

import { IAdminable } from "./IAdminable.sol";

/// @title ISablierV2Controller
/// @notice This contract is in charge of the Sablier V2 protocol configuration, handling such values as the
/// protocol fees.
interface ISablierV2Comptroller is IAdminable {
    /*//////////////////////////////////////////////////////////////////////////
                                       EVENTS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Emitted when the admin sets a new flash fee.
    /// @param admin The address of the contract admin.
    /// @param oldFlashFee The old flash fee, denoted as a fixed-point number.
    /// @param newFlashFee The new flash fee, denoted as a fixed-point number.
    event SetFlashFee(address indexed admin, UD60x18 oldFlashFee, UD60x18 newFlashFee);

    /// @notice Emitted when the admin sets a new protocol fee for the provided ERC-20 asset.
    /// @param admin The address of the contract admin.
    /// @param asset The contract address of the ERC-20 asset the new protocol fee has been set for.
    /// @param oldProtocolFee The old protocol fee, denoted as a fixed-point number.
    /// @param newProtocolFee The new protocol fee, denoted as a fixed-point number.
    event SetProtocolFee(address indexed admin, IERC20 indexed asset, UD60x18 oldProtocolFee, UD60x18 newProtocolFee);

    /// @notice Emitted when the admin enables or disables an ERC-20 asset for flash loaning.
    /// @param admin The address of the contract admin.
    /// @param asset The contract address of the ERC-20 asset to toggle.
    /// @param newFlag Whether the ERC-20 asset can be flash loaned.
    event ToggleFlashAsset(address indexed admin, IERC20 indexed asset, bool newFlag);

    /*//////////////////////////////////////////////////////////////////////////
                                 CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Retrieves the global flash fee, denoted as a fixed-point number where 1e18 is 100%.
    ///
    /// @dev Notes:
    /// - This fee represents a percentage, not an amount. Do not confuse it with {IERC3156FlashLender.flashFee},
    /// which calculates the fee amount for a specified flash loan amount.
    /// - Unlike the protocol fee, this is a global fee applied to all flash loans, not a per-asset fee.
    function flashFee() external view returns (UD60x18 fee);

    /// @notice Retrieves a flag indicating whether the provided ERC-20 asset can be flash loaned.
    /// @param token The contract address of the ERC-20 asset to check.
    function isFlashAsset(IERC20 token) external view returns (bool result);

    /// @notice Retrieves the protocol fee for all streams created with the provided ERC-20 asset.
    /// @param asset The contract address of the ERC-20 asset to query.
    /// @return fee The protocol fee denoted as a fixed-point number where 1e18 is 100%.
    function protocolFees(IERC20 asset) external view returns (UD60x18 fee);

    /*//////////////////////////////////////////////////////////////////////////
                               NON-CONSTANT FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /// @notice Updates the flash fee charged on all flash loans made with any ERC-20 asset.
    ///
    /// @dev Emits a {SetFlashFee} event.
    ///
    /// Notes:
    /// - Does not revert if the fee is the same.
    ///
    /// Requirements:
    /// - `msg.sender` must be the contract admin.
    ///
    /// @param newFlashFee The new flash fee to set, denoted as a fixed-point number where 1e18 is 100%.
    function setFlashFee(UD60x18 newFlashFee) external;

    /// @notice Sets a new protocol fee that will be charged on all streams created with the provided ERC-20 asset.
    ///
    /// @dev Emits a {SetProtocolFee} event.
    ///
    /// Notes:
    /// - The fee is not denoted in units of the asset's decimals; it is a fixed-point number. Refer to the
    /// PRBMath documentation for more detail on the logic of UD60x18.
    /// - Does not revert if the fee is the same.
    ///
    /// Requirements:
    /// - `msg.sender` must be the contract admin.
    ///
    /// @param asset The contract address of the ERC-20 asset to update the fee for.
    /// @param newProtocolFee The new protocol fee, denoted as a fixed-point number where 1e18 is 100%.
    function setProtocolFee(IERC20 asset, UD60x18 newProtocolFee) external;

    /// @notice Toggles the flash loanability of an ERC-20 asset.
    ///
    /// @dev Emits a {ToggleFlashAsset} event.
    ///
    /// Requirements:
    /// - `msg.sender` must be the admin.
    ///
    /// @param asset The address of the ERC-20 asset to toggle.
    function toggleFlashAsset(IERC20 asset) external;
}

File 28 of 50 : Casting.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import { uMAX_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { UD2x18 } from "./ValueType.sol";

/// @notice Casts a UD2x18 number into SD1x18.
/// - x must be less than or equal to `uMAX_SD1x18`.
function intoSD1x18(UD2x18 x) pure returns (SD1x18 result) {
    uint64 xUint = UD2x18.unwrap(x);
    if (xUint > uint64(uMAX_SD1x18)) {
        revert Errors.PRBMath_UD2x18_IntoSD1x18_Overflow(x);
    }
    result = SD1x18.wrap(int64(xUint));
}

/// @notice Casts a UD2x18 number into SD59x18.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of SD59x18.
function intoSD59x18(UD2x18 x) pure returns (SD59x18 result) {
    result = SD59x18.wrap(int256(uint256(UD2x18.unwrap(x))));
}

/// @notice Casts a UD2x18 number into UD60x18.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of UD60x18.
function intoUD60x18(UD2x18 x) pure returns (UD60x18 result) {
    result = UD60x18.wrap(UD2x18.unwrap(x));
}

/// @notice Casts a UD2x18 number into uint128.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of uint128.
function intoUint128(UD2x18 x) pure returns (uint128 result) {
    result = uint128(UD2x18.unwrap(x));
}

/// @notice Casts a UD2x18 number into uint256.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of uint256.
function intoUint256(UD2x18 x) pure returns (uint256 result) {
    result = uint256(UD2x18.unwrap(x));
}

/// @notice Casts a UD2x18 number into uint40.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_UINT40`.
function intoUint40(UD2x18 x) pure returns (uint40 result) {
    uint64 xUint = UD2x18.unwrap(x);
    if (xUint > uint64(Common.MAX_UINT40)) {
        revert Errors.PRBMath_UD2x18_IntoUint40_Overflow(x);
    }
    result = uint40(xUint);
}

/// @notice Alias for {wrap}.
function ud2x18(uint64 x) pure returns (UD2x18 result) {
    result = UD2x18.wrap(x);
}

/// @notice Unwrap a UD2x18 number into uint64.
function unwrap(UD2x18 x) pure returns (uint64 result) {
    result = UD2x18.unwrap(x);
}

/// @notice Wraps a uint64 number into UD2x18.
function wrap(uint64 x) pure returns (UD2x18 result) {
    result = UD2x18.wrap(x);
}

File 29 of 50 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { UD2x18 } from "./ValueType.sol";

/// @dev Euler's number as a UD2x18 number.
UD2x18 constant E = UD2x18.wrap(2_718281828459045235);

/// @dev The maximum value a UD2x18 number can have.
uint64 constant uMAX_UD2x18 = 18_446744073709551615;
UD2x18 constant MAX_UD2x18 = UD2x18.wrap(uMAX_UD2x18);

/// @dev PI as a UD2x18 number.
UD2x18 constant PI = UD2x18.wrap(3_141592653589793238);

/// @dev The unit number, which gives the decimal precision of UD2x18.
uint256 constant uUNIT = 1e18;
UD2x18 constant UNIT = UD2x18.wrap(1e18);

File 30 of 50 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { UD2x18 } from "./ValueType.sol";

/// @notice Thrown when trying to cast a UD2x18 number that doesn't fit in SD1x18.
error PRBMath_UD2x18_IntoSD1x18_Overflow(UD2x18 x);

/// @notice Thrown when trying to cast a UD2x18 number that doesn't fit in uint40.
error PRBMath_UD2x18_IntoUint40_Overflow(UD2x18 x);

File 31 of 50 : ValueType.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "./Casting.sol" as Casting;

/// @notice The unsigned 2.18-decimal fixed-point number representation, which can have up to 2 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type uint64. This is useful when end users want to use uint64 to save gas, e.g. with tight variable packing in contract
/// storage.
type UD2x18 is uint64;

/*//////////////////////////////////////////////////////////////////////////
                                    CASTING
//////////////////////////////////////////////////////////////////////////*/

using {
    Casting.intoSD1x18,
    Casting.intoSD59x18,
    Casting.intoUD60x18,
    Casting.intoUint256,
    Casting.intoUint128,
    Casting.intoUint40,
    Casting.unwrap
} for UD2x18 global;

File 32 of 50 : Casting.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "./Errors.sol" as CastingErrors;
import { MAX_UINT128, MAX_UINT40 } from "../Common.sol";
import { uMAX_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { uMAX_SD59x18 } from "../sd59x18/Constants.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { uMAX_UD2x18 } from "../ud2x18/Constants.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD60x18 } from "./ValueType.sol";

/// @notice Casts a UD60x18 number into SD1x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_SD1x18`.
function intoSD1x18(UD60x18 x) pure returns (SD1x18 result) {
    uint256 xUint = UD60x18.unwrap(x);
    if (xUint > uint256(int256(uMAX_SD1x18))) {
        revert CastingErrors.PRBMath_UD60x18_IntoSD1x18_Overflow(x);
    }
    result = SD1x18.wrap(int64(uint64(xUint)));
}

/// @notice Casts a UD60x18 number into UD2x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_UD2x18`.
function intoUD2x18(UD60x18 x) pure returns (UD2x18 result) {
    uint256 xUint = UD60x18.unwrap(x);
    if (xUint > uMAX_UD2x18) {
        revert CastingErrors.PRBMath_UD60x18_IntoUD2x18_Overflow(x);
    }
    result = UD2x18.wrap(uint64(xUint));
}

/// @notice Casts a UD60x18 number into SD59x18.
/// @dev Requirements:
/// - x must be less than or equal to `uMAX_SD59x18`.
function intoSD59x18(UD60x18 x) pure returns (SD59x18 result) {
    uint256 xUint = UD60x18.unwrap(x);
    if (xUint > uint256(uMAX_SD59x18)) {
        revert CastingErrors.PRBMath_UD60x18_IntoSD59x18_Overflow(x);
    }
    result = SD59x18.wrap(int256(xUint));
}

/// @notice Casts a UD60x18 number into uint128.
/// @dev This is basically an alias for {unwrap}.
function intoUint256(UD60x18 x) pure returns (uint256 result) {
    result = UD60x18.unwrap(x);
}

/// @notice Casts a UD60x18 number into uint128.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_UINT128`.
function intoUint128(UD60x18 x) pure returns (uint128 result) {
    uint256 xUint = UD60x18.unwrap(x);
    if (xUint > MAX_UINT128) {
        revert CastingErrors.PRBMath_UD60x18_IntoUint128_Overflow(x);
    }
    result = uint128(xUint);
}

/// @notice Casts a UD60x18 number into uint40.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_UINT40`.
function intoUint40(UD60x18 x) pure returns (uint40 result) {
    uint256 xUint = UD60x18.unwrap(x);
    if (xUint > MAX_UINT40) {
        revert CastingErrors.PRBMath_UD60x18_IntoUint40_Overflow(x);
    }
    result = uint40(xUint);
}

/// @notice Alias for {wrap}.
function ud(uint256 x) pure returns (UD60x18 result) {
    result = UD60x18.wrap(x);
}

/// @notice Alias for {wrap}.
function ud60x18(uint256 x) pure returns (UD60x18 result) {
    result = UD60x18.wrap(x);
}

/// @notice Unwraps a UD60x18 number into uint256.
function unwrap(UD60x18 x) pure returns (uint256 result) {
    result = UD60x18.unwrap(x);
}

/// @notice Wraps a uint256 number into the UD60x18 value type.
function wrap(uint256 x) pure returns (UD60x18 result) {
    result = UD60x18.wrap(x);
}

File 33 of 50 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { UD60x18 } from "./ValueType.sol";

// NOTICE: the "u" prefix stands for "unwrapped".

/// @dev Euler's number as a UD60x18 number.
UD60x18 constant E = UD60x18.wrap(2_718281828459045235);

/// @dev The maximum input permitted in {exp}.
uint256 constant uEXP_MAX_INPUT = 133_084258667509499440;
UD60x18 constant EXP_MAX_INPUT = UD60x18.wrap(uEXP_MAX_INPUT);

/// @dev The maximum input permitted in {exp2}.
uint256 constant uEXP2_MAX_INPUT = 192e18 - 1;
UD60x18 constant EXP2_MAX_INPUT = UD60x18.wrap(uEXP2_MAX_INPUT);

/// @dev Half the UNIT number.
uint256 constant uHALF_UNIT = 0.5e18;
UD60x18 constant HALF_UNIT = UD60x18.wrap(uHALF_UNIT);

/// @dev $log_2(10)$ as a UD60x18 number.
uint256 constant uLOG2_10 = 3_321928094887362347;
UD60x18 constant LOG2_10 = UD60x18.wrap(uLOG2_10);

/// @dev $log_2(e)$ as a UD60x18 number.
uint256 constant uLOG2_E = 1_442695040888963407;
UD60x18 constant LOG2_E = UD60x18.wrap(uLOG2_E);

/// @dev The maximum value a UD60x18 number can have.
uint256 constant uMAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935;
UD60x18 constant MAX_UD60x18 = UD60x18.wrap(uMAX_UD60x18);

/// @dev The maximum whole value a UD60x18 number can have.
uint256 constant uMAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000;
UD60x18 constant MAX_WHOLE_UD60x18 = UD60x18.wrap(uMAX_WHOLE_UD60x18);

/// @dev PI as a UD60x18 number.
UD60x18 constant PI = UD60x18.wrap(3_141592653589793238);

/// @dev The unit number, which gives the decimal precision of UD60x18.
uint256 constant uUNIT = 1e18;
UD60x18 constant UNIT = UD60x18.wrap(uUNIT);

/// @dev The unit number squared.
uint256 constant uUNIT_SQUARED = 1e36;
UD60x18 constant UNIT_SQUARED = UD60x18.wrap(uUNIT_SQUARED);

/// @dev Zero as a UD60x18 number.
UD60x18 constant ZERO = UD60x18.wrap(0);

File 34 of 50 : Conversions.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { uMAX_UD60x18, uUNIT } from "./Constants.sol";
import { PRBMath_UD60x18_Convert_Overflow } from "./Errors.sol";
import { UD60x18 } from "./ValueType.sol";

/// @notice Converts a UD60x18 number to a simple integer by dividing it by `UNIT`.
/// @dev The result is rounded toward zero.
/// @param x The UD60x18 number to convert.
/// @return result The same number in basic integer form.
function convert(UD60x18 x) pure returns (uint256 result) {
    result = UD60x18.unwrap(x) / uUNIT;
}

/// @notice Converts a simple integer to UD60x18 by multiplying it by `UNIT`.
///
/// @dev Requirements:
/// - x must be less than or equal to `MAX_UD60x18 / UNIT`.
///
/// @param x The basic integer to convert.
/// @param result The same number converted to UD60x18.
function convert(uint256 x) pure returns (UD60x18 result) {
    if (x > uMAX_UD60x18 / uUNIT) {
        revert PRBMath_UD60x18_Convert_Overflow(x);
    }
    unchecked {
        result = UD60x18.wrap(x * uUNIT);
    }
}

File 35 of 50 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { UD60x18 } from "./ValueType.sol";

/// @notice Thrown when ceiling a number overflows UD60x18.
error PRBMath_UD60x18_Ceil_Overflow(UD60x18 x);

/// @notice Thrown when converting a basic integer to the fixed-point format overflows UD60x18.
error PRBMath_UD60x18_Convert_Overflow(uint256 x);

/// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441.
error PRBMath_UD60x18_Exp_InputTooBig(UD60x18 x);

/// @notice Thrown when taking the binary exponent of a base greater than 192e18.
error PRBMath_UD60x18_Exp2_InputTooBig(UD60x18 x);

/// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows UD60x18.
error PRBMath_UD60x18_Gm_Overflow(UD60x18 x, UD60x18 y);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD1x18.
error PRBMath_UD60x18_IntoSD1x18_Overflow(UD60x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD59x18.
error PRBMath_UD60x18_IntoSD59x18_Overflow(UD60x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD2x18.
error PRBMath_UD60x18_IntoUD2x18_Overflow(UD60x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint128.
error PRBMath_UD60x18_IntoUint128_Overflow(UD60x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint40.
error PRBMath_UD60x18_IntoUint40_Overflow(UD60x18 x);

/// @notice Thrown when taking the logarithm of a number less than 1.
error PRBMath_UD60x18_Log_InputTooSmall(UD60x18 x);

/// @notice Thrown when calculating the square root overflows UD60x18.
error PRBMath_UD60x18_Sqrt_Overflow(UD60x18 x);

File 36 of 50 : Helpers.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { wrap } from "./Casting.sol";
import { UD60x18 } from "./ValueType.sol";

/// @notice Implements the checked addition operation (+) in the UD60x18 type.
function add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() + y.unwrap());
}

/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.
function and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() & bits);
}

/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.
function and2(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() & y.unwrap());
}

/// @notice Implements the equal operation (==) in the UD60x18 type.
function eq(UD60x18 x, UD60x18 y) pure returns (bool result) {
    result = x.unwrap() == y.unwrap();
}

/// @notice Implements the greater than operation (>) in the UD60x18 type.
function gt(UD60x18 x, UD60x18 y) pure returns (bool result) {
    result = x.unwrap() > y.unwrap();
}

/// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type.
function gte(UD60x18 x, UD60x18 y) pure returns (bool result) {
    result = x.unwrap() >= y.unwrap();
}

/// @notice Implements a zero comparison check function in the UD60x18 type.
function isZero(UD60x18 x) pure returns (bool result) {
    // This wouldn't work if x could be negative.
    result = x.unwrap() == 0;
}

/// @notice Implements the left shift operation (<<) in the UD60x18 type.
function lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() << bits);
}

/// @notice Implements the lower than operation (<) in the UD60x18 type.
function lt(UD60x18 x, UD60x18 y) pure returns (bool result) {
    result = x.unwrap() < y.unwrap();
}

/// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type.
function lte(UD60x18 x, UD60x18 y) pure returns (bool result) {
    result = x.unwrap() <= y.unwrap();
}

/// @notice Implements the checked modulo operation (%) in the UD60x18 type.
function mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() % y.unwrap());
}

/// @notice Implements the not equal operation (!=) in the UD60x18 type.
function neq(UD60x18 x, UD60x18 y) pure returns (bool result) {
    result = x.unwrap() != y.unwrap();
}

/// @notice Implements the NOT (~) bitwise operation in the UD60x18 type.
function not(UD60x18 x) pure returns (UD60x18 result) {
    result = wrap(~x.unwrap());
}

/// @notice Implements the OR (|) bitwise operation in the UD60x18 type.
function or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() | y.unwrap());
}

/// @notice Implements the right shift operation (>>) in the UD60x18 type.
function rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() >> bits);
}

/// @notice Implements the checked subtraction operation (-) in the UD60x18 type.
function sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() - y.unwrap());
}

/// @notice Implements the unchecked addition operation (+) in the UD60x18 type.
function uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    unchecked {
        result = wrap(x.unwrap() + y.unwrap());
    }
}

/// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type.
function uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    unchecked {
        result = wrap(x.unwrap() - y.unwrap());
    }
}

/// @notice Implements the XOR (^) bitwise operation in the UD60x18 type.
function xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(x.unwrap() ^ y.unwrap());
}

File 37 of 50 : Math.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import { wrap } from "./Casting.sol";
import {
    uEXP_MAX_INPUT,
    uEXP2_MAX_INPUT,
    uHALF_UNIT,
    uLOG2_10,
    uLOG2_E,
    uMAX_UD60x18,
    uMAX_WHOLE_UD60x18,
    UNIT,
    uUNIT,
    uUNIT_SQUARED,
    ZERO
} from "./Constants.sol";
import { UD60x18 } from "./ValueType.sol";

/*//////////////////////////////////////////////////////////////////////////
                            MATHEMATICAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Calculates the arithmetic average of x and y using the following formula:
///
/// $$
/// avg(x, y) = (x & y) + ((xUint ^ yUint) / 2)
/// $$
//
/// In English, this is what this formula does:
///
/// 1. AND x and y.
/// 2. Calculate half of XOR x and y.
/// 3. Add the two results together.
///
/// This technique is known as SWAR, which stands for "SIMD within a register". You can read more about it here:
/// https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// @param x The first operand as a UD60x18 number.
/// @param y The second operand as a UD60x18 number.
/// @return result The arithmetic average as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function avg(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();
    uint256 yUint = y.unwrap();
    unchecked {
        result = wrap((xUint & yUint) + ((xUint ^ yUint) >> 1));
    }
}

/// @notice Yields the smallest whole number greater than or equal to x.
///
/// @dev This is optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional
/// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x must be less than or equal to `MAX_WHOLE_UD60x18`.
///
/// @param x The UD60x18 number to ceil.
/// @param result The smallest whole number greater than or equal to x, as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function ceil(UD60x18 x) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();
    if (xUint > uMAX_WHOLE_UD60x18) {
        revert Errors.PRBMath_UD60x18_Ceil_Overflow(x);
    }

    assembly ("memory-safe") {
        // Equivalent to `x % UNIT`.
        let remainder := mod(x, uUNIT)

        // Equivalent to `UNIT - remainder`.
        let delta := sub(uUNIT, remainder)

        // Equivalent to `x + remainder > 0 ? delta : 0`.
        result := add(x, mul(delta, gt(remainder, 0)))
    }
}

/// @notice Divides two UD60x18 numbers, returning a new UD60x18 number.
///
/// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv}.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv}.
///
/// @param x The numerator as a UD60x18 number.
/// @param y The denominator as a UD60x18 number.
/// @param result The quotient as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(Common.mulDiv(x.unwrap(), uUNIT, y.unwrap()));
}

/// @notice Calculates the natural exponent of x using the following formula:
///
/// $$
/// e^x = 2^{x * log_2{e}}
/// $$
///
/// @dev Requirements:
/// - x must be less than 133_084258667509499441.
///
/// @param x The exponent as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp(UD60x18 x) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();

    // This check prevents values greater than 192e18 from being passed to {exp2}.
    if (xUint > uEXP_MAX_INPUT) {
        revert Errors.PRBMath_UD60x18_Exp_InputTooBig(x);
    }

    unchecked {
        // Inline the fixed-point multiplication to save gas.
        uint256 doubleUnitProduct = xUint * uLOG2_E;
        result = exp2(wrap(doubleUnitProduct / uUNIT));
    }
}

/// @notice Calculates the binary exponent of x using the binary fraction method.
///
/// @dev See https://ethereum.stackexchange.com/q/79903/24693
///
/// Requirements:
/// - x must be less than 192e18.
/// - The result must fit in UD60x18.
///
/// @param x The exponent as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp2(UD60x18 x) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();

    // Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format.
    if (xUint > uEXP2_MAX_INPUT) {
        revert Errors.PRBMath_UD60x18_Exp2_InputTooBig(x);
    }

    // Convert x to the 192.64-bit fixed-point format.
    uint256 x_192x64 = (xUint << 64) / uUNIT;

    // Pass x to the {Common.exp2} function, which uses the 192.64-bit fixed-point number representation.
    result = wrap(Common.exp2(x_192x64));
}

/// @notice Yields the greatest whole number less than or equal to x.
/// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
/// @param x The UD60x18 number to floor.
/// @param result The greatest whole number less than or equal to x, as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function floor(UD60x18 x) pure returns (UD60x18 result) {
    assembly ("memory-safe") {
        // Equivalent to `x % UNIT`.
        let remainder := mod(x, uUNIT)

        // Equivalent to `x - remainder > 0 ? remainder : 0)`.
        result := sub(x, mul(remainder, gt(remainder, 0)))
    }
}

/// @notice Yields the excess beyond the floor of x using the odd function definition.
/// @dev See https://en.wikipedia.org/wiki/Fractional_part.
/// @param x The UD60x18 number to get the fractional part of.
/// @param result The fractional part of x as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function frac(UD60x18 x) pure returns (UD60x18 result) {
    assembly ("memory-safe") {
        result := mod(x, uUNIT)
    }
}

/// @notice Calculates the geometric mean of x and y, i.e. $\sqrt{x * y}$, rounding down.
///
/// @dev Requirements:
/// - x * y must fit in UD60x18.
///
/// @param x The first operand as a UD60x18 number.
/// @param y The second operand as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function gm(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();
    uint256 yUint = y.unwrap();
    if (xUint == 0 || yUint == 0) {
        return ZERO;
    }

    unchecked {
        // Checking for overflow this way is faster than letting Solidity do it.
        uint256 xyUint = xUint * yUint;
        if (xyUint / xUint != yUint) {
            revert Errors.PRBMath_UD60x18_Gm_Overflow(x, y);
        }

        // We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT`
        // during multiplication. See the comments in {Common.sqrt}.
        result = wrap(Common.sqrt(xyUint));
    }
}

/// @notice Calculates the inverse of x.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x must not be zero.
///
/// @param x The UD60x18 number for which to calculate the inverse.
/// @return result The inverse as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function inv(UD60x18 x) pure returns (UD60x18 result) {
    unchecked {
        result = wrap(uUNIT_SQUARED / x.unwrap());
    }
}

/// @notice Calculates the natural logarithm of x using the following formula:
///
/// $$
/// ln{x} = log_2{x} / log_2{e}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
/// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The UD60x18 number for which to calculate the natural logarithm.
/// @return result The natural logarithm as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function ln(UD60x18 x) pure returns (UD60x18 result) {
    unchecked {
        // Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that
        // {log2} can return is ~196_205294292027477728.
        result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);
    }
}

/// @notice Calculates the common logarithm of x using the following formula:
///
/// $$
/// log_{10}{x} = log_2{x} / log_2{10}
/// $$
///
/// However, if x is an exact power of ten, a hard coded value is returned.
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The UD60x18 number for which to calculate the common logarithm.
/// @return result The common logarithm as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function log10(UD60x18 x) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();
    if (xUint < uUNIT) {
        revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);
    }

    // Note that the `mul` in this assembly block is the standard multiplication operation, not {UD60x18.mul}.
    // prettier-ignore
    assembly ("memory-safe") {
        switch x
        case 1 { result := mul(uUNIT, sub(0, 18)) }
        case 10 { result := mul(uUNIT, sub(1, 18)) }
        case 100 { result := mul(uUNIT, sub(2, 18)) }
        case 1000 { result := mul(uUNIT, sub(3, 18)) }
        case 10000 { result := mul(uUNIT, sub(4, 18)) }
        case 100000 { result := mul(uUNIT, sub(5, 18)) }
        case 1000000 { result := mul(uUNIT, sub(6, 18)) }
        case 10000000 { result := mul(uUNIT, sub(7, 18)) }
        case 100000000 { result := mul(uUNIT, sub(8, 18)) }
        case 1000000000 { result := mul(uUNIT, sub(9, 18)) }
        case 10000000000 { result := mul(uUNIT, sub(10, 18)) }
        case 100000000000 { result := mul(uUNIT, sub(11, 18)) }
        case 1000000000000 { result := mul(uUNIT, sub(12, 18)) }
        case 10000000000000 { result := mul(uUNIT, sub(13, 18)) }
        case 100000000000000 { result := mul(uUNIT, sub(14, 18)) }
        case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) }
        case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) }
        case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) }
        case 1000000000000000000 { result := 0 }
        case 10000000000000000000 { result := uUNIT }
        case 100000000000000000000 { result := mul(uUNIT, 2) }
        case 1000000000000000000000 { result := mul(uUNIT, 3) }
        case 10000000000000000000000 { result := mul(uUNIT, 4) }
        case 100000000000000000000000 { result := mul(uUNIT, 5) }
        case 1000000000000000000000000 { result := mul(uUNIT, 6) }
        case 10000000000000000000000000 { result := mul(uUNIT, 7) }
        case 100000000000000000000000000 { result := mul(uUNIT, 8) }
        case 1000000000000000000000000000 { result := mul(uUNIT, 9) }
        case 10000000000000000000000000000 { result := mul(uUNIT, 10) }
        case 100000000000000000000000000000 { result := mul(uUNIT, 11) }
        case 1000000000000000000000000000000 { result := mul(uUNIT, 12) }
        case 10000000000000000000000000000000 { result := mul(uUNIT, 13) }
        case 100000000000000000000000000000000 { result := mul(uUNIT, 14) }
        case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) }
        case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) }
        case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) }
        case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) }
        case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) }
        case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) }
        case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) }
        case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) }
        case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) }
        case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) }
        case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) }
        case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) }
        case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) }
        case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) }
        case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) }
        case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) }
        case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) }
        case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) }
        case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) }
        case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) }
        case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) }
        case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) }
        case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) }
        case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) }
        case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) }
        case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) }
        case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) }
        case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) }
        case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) }
        case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) }
        case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) }
        case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) }
        case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) }
        case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) }
        case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) }
        case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) }
        case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) }
        case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) }
        case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) }
        case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) }
        case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) }
        case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) }
        case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) }
        case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) }
        case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 59) }
        default { result := uMAX_UD60x18 }
    }

    if (result.unwrap() == uMAX_UD60x18) {
        unchecked {
            // Inline the fixed-point division to save gas.
            result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);
        }
    }
}

/// @notice Calculates the binary logarithm of x using the iterative approximation algorithm:
///
/// $$
/// log_2{x} = n + log_2{y}, \text{ where } y = x*2^{-n}, \ y \in [1, 2)
/// $$
///
/// For $0 \leq x \lt 1$, the input is inverted:
///
/// $$
/// log_2{x} = -log_2{\frac{1}{x}}
/// $$
///
/// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
///
/// Notes:
/// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal.
///
/// Requirements:
/// - x must be greater than zero.
///
/// @param x The UD60x18 number for which to calculate the binary logarithm.
/// @return result The binary logarithm as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function log2(UD60x18 x) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();

    if (xUint < uUNIT) {
        revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x);
    }

    unchecked {
        // Calculate the integer part of the logarithm.
        uint256 n = Common.msb(xUint / uUNIT);

        // This is the integer part of the logarithm as a UD60x18 number. The operation can't overflow because n
        // n is at most 255 and UNIT is 1e18.
        uint256 resultUint = n * uUNIT;

        // Calculate $y = x * 2^{-n}$.
        uint256 y = xUint >> n;

        // If y is the unit number, the fractional part is zero.
        if (y == uUNIT) {
            return wrap(resultUint);
        }

        // Calculate the fractional part via the iterative approximation.
        // The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient.
        uint256 DOUBLE_UNIT = 2e18;
        for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {
            y = (y * y) / uUNIT;

            // Is y^2 >= 2e18 and so in the range [2e18, 4e18)?
            if (y >= DOUBLE_UNIT) {
                // Add the 2^{-m} factor to the logarithm.
                resultUint += delta;

                // Halve y, which corresponds to z/2 in the Wikipedia article.
                y >>= 1;
            }
        }
        result = wrap(resultUint);
    }
}

/// @notice Multiplies two UD60x18 numbers together, returning a new UD60x18 number.
///
/// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv}.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv}.
///
/// @dev See the documentation in {Common.mulDiv18}.
/// @param x The multiplicand as a UD60x18 number.
/// @param y The multiplier as a UD60x18 number.
/// @return result The product as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    result = wrap(Common.mulDiv18(x.unwrap(), y.unwrap()));
}

/// @notice Raises x to the power of y.
///
/// For $1 \leq x \leq \infty$, the following standard formula is used:
///
/// $$
/// x^y = 2^{log_2{x} * y}
/// $$
///
/// For $0 \leq x \lt 1$, since the unsigned {log2} is undefined, an equivalent formula is used:
///
/// $$
/// i = \frac{1}{x}
/// w = 2^{log_2{i} * y}
/// x^y = \frac{1}{w}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {log2} and {mul}.
/// - Returns `UNIT` for 0^0.
/// - It may not perform well with very small values of x. Consider using SD59x18 as an alternative.
///
/// Requirements:
/// - Refer to the requirements in {exp2}, {log2}, and {mul}.
///
/// @param x The base as a UD60x18 number.
/// @param y The exponent as a UD60x18 number.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();
    uint256 yUint = y.unwrap();

    // If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero.
    if (xUint == 0) {
        return yUint == 0 ? UNIT : ZERO;
    }
    // If x is `UNIT`, the result is always `UNIT`.
    else if (xUint == uUNIT) {
        return UNIT;
    }

    // If y is zero, the result is always `UNIT`.
    if (yUint == 0) {
        return UNIT;
    }
    // If y is `UNIT`, the result is always x.
    else if (yUint == uUNIT) {
        return x;
    }

    // If x is greater than `UNIT`, use the standard formula.
    if (xUint > uUNIT) {
        result = exp2(mul(log2(x), y));
    }
    // Conversely, if x is less than `UNIT`, use the equivalent formula.
    else {
        UD60x18 i = wrap(uUNIT_SQUARED / xUint);
        UD60x18 w = exp2(mul(log2(i), y));
        result = wrap(uUNIT_SQUARED / w.unwrap());
    }
}

/// @notice Raises x (a UD60x18 number) to the power y (an unsigned basic integer) using the well-known
/// algorithm "exponentiation by squaring".
///
/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv18}.
/// - Returns `UNIT` for 0^0.
///
/// Requirements:
/// - The result must fit in UD60x18.
///
/// @param x The base as a UD60x18 number.
/// @param y The exponent as a uint256.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) {
    // Calculate the first iteration of the loop in advance.
    uint256 xUint = x.unwrap();
    uint256 resultUint = y & 1 > 0 ? xUint : uUNIT;

    // Equivalent to `for(y /= 2; y > 0; y /= 2)`.
    for (y >>= 1; y > 0; y >>= 1) {
        xUint = Common.mulDiv18(xUint, xUint);

        // Equivalent to `y % 2 == 1`.
        if (y & 1 > 0) {
            resultUint = Common.mulDiv18(resultUint, xUint);
        }
    }
    result = wrap(resultUint);
}

/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x must be less than `MAX_UD60x18 / UNIT`.
///
/// @param x The UD60x18 number for which to calculate the square root.
/// @return result The result as a UD60x18 number.
/// @custom:smtchecker abstract-function-nondet
function sqrt(UD60x18 x) pure returns (UD60x18 result) {
    uint256 xUint = x.unwrap();

    unchecked {
        if (xUint > uMAX_UD60x18 / uUNIT) {
            revert Errors.PRBMath_UD60x18_Sqrt_Overflow(x);
        }
        // Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two UD60x18 numbers.
        // In this case, the two numbers are both the square root.
        result = wrap(Common.sqrt(xUint * uUNIT));
    }
}

File 38 of 50 : ValueType.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "./Casting.sol" as Casting;
import "./Helpers.sol" as Helpers;
import "./Math.sol" as Math;

/// @notice The unsigned 60.18-decimal fixed-point number representation, which can have up to 60 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the Solidity type uint256.
/// @dev The value type is defined here so it can be imported in all other files.
type UD60x18 is uint256;

/*//////////////////////////////////////////////////////////////////////////
                                    CASTING
//////////////////////////////////////////////////////////////////////////*/

using {
    Casting.intoSD1x18,
    Casting.intoUD2x18,
    Casting.intoSD59x18,
    Casting.intoUint128,
    Casting.intoUint256,
    Casting.intoUint40,
    Casting.unwrap
} for UD60x18 global;

/*//////////////////////////////////////////////////////////////////////////
                            MATHEMATICAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

// The global "using for" directive makes the functions in this library callable on the UD60x18 type.
using {
    Math.avg,
    Math.ceil,
    Math.div,
    Math.exp,
    Math.exp2,
    Math.floor,
    Math.frac,
    Math.gm,
    Math.inv,
    Math.ln,
    Math.log10,
    Math.log2,
    Math.mul,
    Math.pow,
    Math.powu,
    Math.sqrt
} for UD60x18 global;

/*//////////////////////////////////////////////////////////////////////////
                                HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

// The global "using for" directive makes the functions in this library callable on the UD60x18 type.
using {
    Helpers.add,
    Helpers.and,
    Helpers.eq,
    Helpers.gt,
    Helpers.gte,
    Helpers.isZero,
    Helpers.lshift,
    Helpers.lt,
    Helpers.lte,
    Helpers.mod,
    Helpers.neq,
    Helpers.not,
    Helpers.or,
    Helpers.rshift,
    Helpers.sub,
    Helpers.uncheckedAdd,
    Helpers.uncheckedSub,
    Helpers.xor
} for UD60x18 global;

/*//////////////////////////////////////////////////////////////////////////
                                    OPERATORS
//////////////////////////////////////////////////////////////////////////*/

// The global "using for" directive makes it possible to use these operators on the UD60x18 type.
using {
    Helpers.add as +,
    Helpers.and2 as &,
    Math.div as /,
    Helpers.eq as ==,
    Helpers.gt as >,
    Helpers.gte as >=,
    Helpers.lt as <,
    Helpers.lte as <=,
    Helpers.or as |,
    Helpers.mod as %,
    Math.mul as *,
    Helpers.neq as !=,
    Helpers.not as ~,
    Helpers.sub as -,
    Helpers.xor as ^
} for UD60x18 global;

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 40 of 50 : Common.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

// Common.sol
//
// Common mathematical functions needed by both SD59x18 and UD60x18. Note that these global functions do not
// always operate with SD59x18 and UD60x18 numbers.

/*//////////////////////////////////////////////////////////////////////////
                                CUSTOM ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);

/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);

/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.
error PRBMath_MulDivSigned_InputTooSmall();

/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);

/*//////////////////////////////////////////////////////////////////////////
                                    CONSTANTS
//////////////////////////////////////////////////////////////////////////*/

/// @dev The maximum value a uint128 number can have.
uint128 constant MAX_UINT128 = type(uint128).max;

/// @dev The maximum value a uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;

/// @dev The unit number, which the decimal precision of the fixed-point types.
uint256 constant UNIT = 1e18;

/// @dev The unit number inverted mod 2^256.
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;

/// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant
/// bit in the binary representation of `UNIT`.
uint256 constant UNIT_LPOTD = 262144;

/*//////////////////////////////////////////////////////////////////////////
                                    FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.
/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function exp2(uint256 x) pure returns (uint256 result) {
    unchecked {
        // Start from 0.5 in the 192.64-bit fixed-point format.
        result = 0x800000000000000000000000000000000000000000000000;

        // The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:
        //
        // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.
        // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing
        // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,
        // we know that `x & 0xFF` is also 1.
        if (x & 0xFF00000000000000 > 0) {
            if (x & 0x8000000000000000 > 0) {
                result = (result * 0x16A09E667F3BCC909) >> 64;
            }
            if (x & 0x4000000000000000 > 0) {
                result = (result * 0x1306FE0A31B7152DF) >> 64;
            }
            if (x & 0x2000000000000000 > 0) {
                result = (result * 0x1172B83C7D517ADCE) >> 64;
            }
            if (x & 0x1000000000000000 > 0) {
                result = (result * 0x10B5586CF9890F62A) >> 64;
            }
            if (x & 0x800000000000000 > 0) {
                result = (result * 0x1059B0D31585743AE) >> 64;
            }
            if (x & 0x400000000000000 > 0) {
                result = (result * 0x102C9A3E778060EE7) >> 64;
            }
            if (x & 0x200000000000000 > 0) {
                result = (result * 0x10163DA9FB33356D8) >> 64;
            }
            if (x & 0x100000000000000 > 0) {
                result = (result * 0x100B1AFA5ABCBED61) >> 64;
            }
        }

        if (x & 0xFF000000000000 > 0) {
            if (x & 0x80000000000000 > 0) {
                result = (result * 0x10058C86DA1C09EA2) >> 64;
            }
            if (x & 0x40000000000000 > 0) {
                result = (result * 0x1002C605E2E8CEC50) >> 64;
            }
            if (x & 0x20000000000000 > 0) {
                result = (result * 0x100162F3904051FA1) >> 64;
            }
            if (x & 0x10000000000000 > 0) {
                result = (result * 0x1000B175EFFDC76BA) >> 64;
            }
            if (x & 0x8000000000000 > 0) {
                result = (result * 0x100058BA01FB9F96D) >> 64;
            }
            if (x & 0x4000000000000 > 0) {
                result = (result * 0x10002C5CC37DA9492) >> 64;
            }
            if (x & 0x2000000000000 > 0) {
                result = (result * 0x1000162E525EE0547) >> 64;
            }
            if (x & 0x1000000000000 > 0) {
                result = (result * 0x10000B17255775C04) >> 64;
            }
        }

        if (x & 0xFF0000000000 > 0) {
            if (x & 0x800000000000 > 0) {
                result = (result * 0x1000058B91B5BC9AE) >> 64;
            }
            if (x & 0x400000000000 > 0) {
                result = (result * 0x100002C5C89D5EC6D) >> 64;
            }
            if (x & 0x200000000000 > 0) {
                result = (result * 0x10000162E43F4F831) >> 64;
            }
            if (x & 0x100000000000 > 0) {
                result = (result * 0x100000B1721BCFC9A) >> 64;
            }
            if (x & 0x80000000000 > 0) {
                result = (result * 0x10000058B90CF1E6E) >> 64;
            }
            if (x & 0x40000000000 > 0) {
                result = (result * 0x1000002C5C863B73F) >> 64;
            }
            if (x & 0x20000000000 > 0) {
                result = (result * 0x100000162E430E5A2) >> 64;
            }
            if (x & 0x10000000000 > 0) {
                result = (result * 0x1000000B172183551) >> 64;
            }
        }

        if (x & 0xFF00000000 > 0) {
            if (x & 0x8000000000 > 0) {
                result = (result * 0x100000058B90C0B49) >> 64;
            }
            if (x & 0x4000000000 > 0) {
                result = (result * 0x10000002C5C8601CC) >> 64;
            }
            if (x & 0x2000000000 > 0) {
                result = (result * 0x1000000162E42FFF0) >> 64;
            }
            if (x & 0x1000000000 > 0) {
                result = (result * 0x10000000B17217FBB) >> 64;
            }
            if (x & 0x800000000 > 0) {
                result = (result * 0x1000000058B90BFCE) >> 64;
            }
            if (x & 0x400000000 > 0) {
                result = (result * 0x100000002C5C85FE3) >> 64;
            }
            if (x & 0x200000000 > 0) {
                result = (result * 0x10000000162E42FF1) >> 64;
            }
            if (x & 0x100000000 > 0) {
                result = (result * 0x100000000B17217F8) >> 64;
            }
        }

        if (x & 0xFF000000 > 0) {
            if (x & 0x80000000 > 0) {
                result = (result * 0x10000000058B90BFC) >> 64;
            }
            if (x & 0x40000000 > 0) {
                result = (result * 0x1000000002C5C85FE) >> 64;
            }
            if (x & 0x20000000 > 0) {
                result = (result * 0x100000000162E42FF) >> 64;
            }
            if (x & 0x10000000 > 0) {
                result = (result * 0x1000000000B17217F) >> 64;
            }
            if (x & 0x8000000 > 0) {
                result = (result * 0x100000000058B90C0) >> 64;
            }
            if (x & 0x4000000 > 0) {
                result = (result * 0x10000000002C5C860) >> 64;
            }
            if (x & 0x2000000 > 0) {
                result = (result * 0x1000000000162E430) >> 64;
            }
            if (x & 0x1000000 > 0) {
                result = (result * 0x10000000000B17218) >> 64;
            }
        }

        if (x & 0xFF0000 > 0) {
            if (x & 0x800000 > 0) {
                result = (result * 0x1000000000058B90C) >> 64;
            }
            if (x & 0x400000 > 0) {
                result = (result * 0x100000000002C5C86) >> 64;
            }
            if (x & 0x200000 > 0) {
                result = (result * 0x10000000000162E43) >> 64;
            }
            if (x & 0x100000 > 0) {
                result = (result * 0x100000000000B1721) >> 64;
            }
            if (x & 0x80000 > 0) {
                result = (result * 0x10000000000058B91) >> 64;
            }
            if (x & 0x40000 > 0) {
                result = (result * 0x1000000000002C5C8) >> 64;
            }
            if (x & 0x20000 > 0) {
                result = (result * 0x100000000000162E4) >> 64;
            }
            if (x & 0x10000 > 0) {
                result = (result * 0x1000000000000B172) >> 64;
            }
        }

        if (x & 0xFF00 > 0) {
            if (x & 0x8000 > 0) {
                result = (result * 0x100000000000058B9) >> 64;
            }
            if (x & 0x4000 > 0) {
                result = (result * 0x10000000000002C5D) >> 64;
            }
            if (x & 0x2000 > 0) {
                result = (result * 0x1000000000000162E) >> 64;
            }
            if (x & 0x1000 > 0) {
                result = (result * 0x10000000000000B17) >> 64;
            }
            if (x & 0x800 > 0) {
                result = (result * 0x1000000000000058C) >> 64;
            }
            if (x & 0x400 > 0) {
                result = (result * 0x100000000000002C6) >> 64;
            }
            if (x & 0x200 > 0) {
                result = (result * 0x10000000000000163) >> 64;
            }
            if (x & 0x100 > 0) {
                result = (result * 0x100000000000000B1) >> 64;
            }
        }

        if (x & 0xFF > 0) {
            if (x & 0x80 > 0) {
                result = (result * 0x10000000000000059) >> 64;
            }
            if (x & 0x40 > 0) {
                result = (result * 0x1000000000000002C) >> 64;
            }
            if (x & 0x20 > 0) {
                result = (result * 0x10000000000000016) >> 64;
            }
            if (x & 0x10 > 0) {
                result = (result * 0x1000000000000000B) >> 64;
            }
            if (x & 0x8 > 0) {
                result = (result * 0x10000000000000006) >> 64;
            }
            if (x & 0x4 > 0) {
                result = (result * 0x10000000000000003) >> 64;
            }
            if (x & 0x2 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }
            if (x & 0x1 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }
        }

        // In the code snippet below, two operations are executed simultaneously:
        //
        // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1
        // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.
        // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.
        //
        // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,
        // integer part, $2^n$.
        result *= UNIT;
        result >>= (191 - (x >> 64));
    }
}

/// @notice Finds the zero-based index of the first 1 in the binary representation of x.
///
/// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set
///
/// Each step in this implementation is equivalent to this high-level code:
///
/// ```solidity
/// if (x >= 2 ** 128) {
///     x >>= 128;
///     result += 128;
/// }
/// ```
///
/// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:
/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
///
/// The Yul instructions used below are:
///
/// - "gt" is "greater than"
/// - "or" is the OR bitwise operator
/// - "shl" is "shift left"
/// - "shr" is "shift right"
///
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return result The index of the most significant bit as a uint256.
/// @custom:smtchecker abstract-function-nondet
function msb(uint256 x) pure returns (uint256 result) {
    // 2^128
    assembly ("memory-safe") {
        let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^64
    assembly ("memory-safe") {
        let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^32
    assembly ("memory-safe") {
        let factor := shl(5, gt(x, 0xFFFFFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^16
    assembly ("memory-safe") {
        let factor := shl(4, gt(x, 0xFFFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^8
    assembly ("memory-safe") {
        let factor := shl(3, gt(x, 0xFF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^4
    assembly ("memory-safe") {
        let factor := shl(2, gt(x, 0xF))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^2
    assembly ("memory-safe") {
        let factor := shl(1, gt(x, 0x3))
        x := shr(factor, x)
        result := or(result, factor)
    }
    // 2^1
    // No need to shift x any more.
    assembly ("memory-safe") {
        let factor := gt(x, 0x1)
        result := or(result, factor)
    }
}

/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - The denominator must not be zero.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as a uint256.
/// @param y The multiplier as a uint256.
/// @param denominator The divisor as a uint256.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
    // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256
    // variables such that product = prod1 * 2^256 + prod0.
    uint256 prod0; // Least significant 256 bits of the product
    uint256 prod1; // Most significant 256 bits of the product
    assembly ("memory-safe") {
        let mm := mulmod(x, y, not(0))
        prod0 := mul(x, y)
        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
    }

    // Handle non-overflow cases, 256 by 256 division.
    if (prod1 == 0) {
        unchecked {
            return prod0 / denominator;
        }
    }

    // Make sure the result is less than 2^256. Also prevents denominator == 0.
    if (prod1 >= denominator) {
        revert PRBMath_MulDiv_Overflow(x, y, denominator);
    }

    ////////////////////////////////////////////////////////////////////////////
    // 512 by 256 division
    ////////////////////////////////////////////////////////////////////////////

    // Make division exact by subtracting the remainder from [prod1 prod0].
    uint256 remainder;
    assembly ("memory-safe") {
        // Compute remainder using the mulmod Yul instruction.
        remainder := mulmod(x, y, denominator)

        // Subtract 256 bit number from 512-bit number.
        prod1 := sub(prod1, gt(remainder, prod0))
        prod0 := sub(prod0, remainder)
    }

    unchecked {
        // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
        // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
        // For more detail, see https://cs.stackexchange.com/q/138556/92363.
        uint256 lpotdod = denominator & (~denominator + 1);
        uint256 flippedLpotdod;

        assembly ("memory-safe") {
            // Factor powers of two out of denominator.
            denominator := div(denominator, lpotdod)

            // Divide [prod1 prod0] by lpotdod.
            prod0 := div(prod0, lpotdod)

            // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
            // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
            // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
            flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
        }

        // Shift in bits from prod1 into prod0.
        prod0 |= prod1 * flippedLpotdod;

        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
        // four bits. That is, denominator * inv = 1 mod 2^4.
        uint256 inverse = (3 * denominator) ^ 2;

        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
        // in modular arithmetic, doubling the correct bits in each step.
        inverse *= 2 - denominator * inverse; // inverse mod 2^8
        inverse *= 2 - denominator * inverse; // inverse mod 2^16
        inverse *= 2 - denominator * inverse; // inverse mod 2^32
        inverse *= 2 - denominator * inverse; // inverse mod 2^64
        inverse *= 2 - denominator * inverse; // inverse mod 2^128
        inverse *= 2 - denominator * inverse; // inverse mod 2^256

        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
        // is no longer required.
        result = prod0 * inverse;
    }
}

/// @notice Calculates x*y÷1e18 with 512-bit precision.
///
/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.
///
/// Notes:
/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.
/// - The result is rounded toward zero.
/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:
///
/// $$
/// \begin{cases}
///     x * y = MAX\_UINT256 * UNIT \\
///     (x * y) \% UNIT \geq \frac{UNIT}{2}
/// \end{cases}
/// $$
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
    uint256 prod0;
    uint256 prod1;
    assembly ("memory-safe") {
        let mm := mulmod(x, y, not(0))
        prod0 := mul(x, y)
        prod1 := sub(sub(mm, prod0), lt(mm, prod0))
    }

    if (prod1 == 0) {
        unchecked {
            return prod0 / UNIT;
        }
    }

    if (prod1 >= UNIT) {
        revert PRBMath_MulDiv18_Overflow(x, y);
    }

    uint256 remainder;
    assembly ("memory-safe") {
        remainder := mulmod(x, y, UNIT)
        result :=
            mul(
                or(
                    div(sub(prod0, remainder), UNIT_LPOTD),
                    mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
                ),
                UNIT_INVERSE
            )
    }
}

/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - None of the inputs can be `type(int256).min`.
/// - The result must fit in int256.
///
/// @param x The multiplicand as an int256.
/// @param y The multiplier as an int256.
/// @param denominator The divisor as an int256.
/// @return result The result as an int256.
/// @custom:smtchecker abstract-function-nondet
function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
    if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
        revert PRBMath_MulDivSigned_InputTooSmall();
    }

    // Get hold of the absolute values of x, y and the denominator.
    uint256 xAbs;
    uint256 yAbs;
    uint256 dAbs;
    unchecked {
        xAbs = x < 0 ? uint256(-x) : uint256(x);
        yAbs = y < 0 ? uint256(-y) : uint256(y);
        dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);
    }

    // Compute the absolute value of x*y÷denominator. The result must fit in int256.
    uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
    if (resultAbs > uint256(type(int256).max)) {
        revert PRBMath_MulDivSigned_Overflow(x, y);
    }

    // Get the signs of x, y and the denominator.
    uint256 sx;
    uint256 sy;
    uint256 sd;
    assembly ("memory-safe") {
        // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement.
        sx := sgt(x, sub(0, 1))
        sy := sgt(y, sub(0, 1))
        sd := sgt(denominator, sub(0, 1))
    }

    // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
    // If there are, the result should be negative. Otherwise, it should be positive.
    unchecked {
        result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
    }
}

/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - If x is not a perfect square, the result is rounded down.
/// - Credits to OpenZeppelin for the explanations in comments below.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function sqrt(uint256 x) pure returns (uint256 result) {
    if (x == 0) {
        return 0;
    }

    // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.
    //
    // We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
    //
    // $$
    // msb(x) <= x <= 2*msb(x)$
    // $$
    //
    // We write $msb(x)$ as $2^k$, and we get:
    //
    // $$
    // k = log_2(x)
    // $$
    //
    // Thus, we can write the initial inequality as:
    //
    // $$
    // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\
    // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\
    // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
    // $$
    //
    // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.
    uint256 xAux = uint256(x);
    result = 1;
    if (xAux >= 2 ** 128) {
        xAux >>= 128;
        result <<= 64;
    }
    if (xAux >= 2 ** 64) {
        xAux >>= 64;
        result <<= 32;
    }
    if (xAux >= 2 ** 32) {
        xAux >>= 32;
        result <<= 16;
    }
    if (xAux >= 2 ** 16) {
        xAux >>= 16;
        result <<= 8;
    }
    if (xAux >= 2 ** 8) {
        xAux >>= 8;
        result <<= 4;
    }
    if (xAux >= 2 ** 4) {
        xAux >>= 4;
        result <<= 2;
    }
    if (xAux >= 2 ** 2) {
        result <<= 1;
    }

    // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at
    // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision
    // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of
    // precision into the expected uint128 result.
    unchecked {
        result = (result + x / result) >> 1;
        result = (result + x / result) >> 1;
        result = (result + x / result) >> 1;
        result = (result + x / result) >> 1;
        result = (result + x / result) >> 1;
        result = (result + x / result) >> 1;
        result = (result + x / result) >> 1;

        // If x is not a perfect square, round the result toward zero.
        uint256 roundedResult = x / result;
        if (result >= roundedResult) {
            result = roundedResult;
        }
    }
}

File 41 of 50 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { SD1x18 } from "./ValueType.sol";

/// @dev Euler's number as an SD1x18 number.
SD1x18 constant E = SD1x18.wrap(2_718281828459045235);

/// @dev The maximum value an SD1x18 number can have.
int64 constant uMAX_SD1x18 = 9_223372036854775807;
SD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18);

/// @dev The maximum value an SD1x18 number can have.
int64 constant uMIN_SD1x18 = -9_223372036854775808;
SD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18);

/// @dev PI as an SD1x18 number.
SD1x18 constant PI = SD1x18.wrap(3_141592653589793238);

/// @dev The unit number, which gives the decimal precision of SD1x18.
SD1x18 constant UNIT = SD1x18.wrap(1e18);
int256 constant uUNIT = 1e18;

File 42 of 50 : ValueType.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "./Casting.sol" as Casting;

/// @notice The signed 1.18-decimal fixed-point number representation, which can have up to 1 digit and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type int64. This is useful when end users want to use int64 to save gas, e.g. with tight variable packing in contract
/// storage.
type SD1x18 is int64;

/*//////////////////////////////////////////////////////////////////////////
                                    CASTING
//////////////////////////////////////////////////////////////////////////*/

using {
    Casting.intoSD59x18,
    Casting.intoUD2x18,
    Casting.intoUD60x18,
    Casting.intoUint256,
    Casting.intoUint128,
    Casting.intoUint40,
    Casting.unwrap
} for SD1x18 global;

File 43 of 50 : ValueType.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "./Casting.sol" as Casting;
import "./Helpers.sol" as Helpers;
import "./Math.sol" as Math;

/// @notice The signed 59.18-decimal fixed-point number representation, which can have up to 59 digits and up to 18
/// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity
/// type int256.
type SD59x18 is int256;

/*//////////////////////////////////////////////////////////////////////////
                                    CASTING
//////////////////////////////////////////////////////////////////////////*/

using {
    Casting.intoInt256,
    Casting.intoSD1x18,
    Casting.intoUD2x18,
    Casting.intoUD60x18,
    Casting.intoUint256,
    Casting.intoUint128,
    Casting.intoUint40,
    Casting.unwrap
} for SD59x18 global;

/*//////////////////////////////////////////////////////////////////////////
                            MATHEMATICAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

using {
    Math.abs,
    Math.avg,
    Math.ceil,
    Math.div,
    Math.exp,
    Math.exp2,
    Math.floor,
    Math.frac,
    Math.gm,
    Math.inv,
    Math.log10,
    Math.log2,
    Math.ln,
    Math.mul,
    Math.pow,
    Math.powu,
    Math.sqrt
} for SD59x18 global;

/*//////////////////////////////////////////////////////////////////////////
                                HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

using {
    Helpers.add,
    Helpers.and,
    Helpers.eq,
    Helpers.gt,
    Helpers.gte,
    Helpers.isZero,
    Helpers.lshift,
    Helpers.lt,
    Helpers.lte,
    Helpers.mod,
    Helpers.neq,
    Helpers.not,
    Helpers.or,
    Helpers.rshift,
    Helpers.sub,
    Helpers.uncheckedAdd,
    Helpers.uncheckedSub,
    Helpers.uncheckedUnary,
    Helpers.xor
} for SD59x18 global;

/*//////////////////////////////////////////////////////////////////////////
                                    OPERATORS
//////////////////////////////////////////////////////////////////////////*/

// The global "using for" directive makes it possible to use these operators on the SD59x18 type.
using {
    Helpers.add as +,
    Helpers.and2 as &,
    Math.div as /,
    Helpers.eq as ==,
    Helpers.gt as >,
    Helpers.gte as >=,
    Helpers.lt as <,
    Helpers.lte as <=,
    Helpers.mod as %,
    Math.mul as *,
    Helpers.neq as !=,
    Helpers.not as ~,
    Helpers.or as |,
    Helpers.sub as -,
    Helpers.unary as -,
    Helpers.xor as ^
} for SD59x18 global;

File 44 of 50 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { SD59x18 } from "./ValueType.sol";

// NOTICE: the "u" prefix stands for "unwrapped".

/// @dev Euler's number as an SD59x18 number.
SD59x18 constant E = SD59x18.wrap(2_718281828459045235);

/// @dev The maximum input permitted in {exp}.
int256 constant uEXP_MAX_INPUT = 133_084258667509499440;
SD59x18 constant EXP_MAX_INPUT = SD59x18.wrap(uEXP_MAX_INPUT);

/// @dev The maximum input permitted in {exp2}.
int256 constant uEXP2_MAX_INPUT = 192e18 - 1;
SD59x18 constant EXP2_MAX_INPUT = SD59x18.wrap(uEXP2_MAX_INPUT);

/// @dev Half the UNIT number.
int256 constant uHALF_UNIT = 0.5e18;
SD59x18 constant HALF_UNIT = SD59x18.wrap(uHALF_UNIT);

/// @dev $log_2(10)$ as an SD59x18 number.
int256 constant uLOG2_10 = 3_321928094887362347;
SD59x18 constant LOG2_10 = SD59x18.wrap(uLOG2_10);

/// @dev $log_2(e)$ as an SD59x18 number.
int256 constant uLOG2_E = 1_442695040888963407;
SD59x18 constant LOG2_E = SD59x18.wrap(uLOG2_E);

/// @dev The maximum value an SD59x18 number can have.
int256 constant uMAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967;
SD59x18 constant MAX_SD59x18 = SD59x18.wrap(uMAX_SD59x18);

/// @dev The maximum whole value an SD59x18 number can have.
int256 constant uMAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000;
SD59x18 constant MAX_WHOLE_SD59x18 = SD59x18.wrap(uMAX_WHOLE_SD59x18);

/// @dev The minimum value an SD59x18 number can have.
int256 constant uMIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968;
SD59x18 constant MIN_SD59x18 = SD59x18.wrap(uMIN_SD59x18);

/// @dev The minimum whole value an SD59x18 number can have.
int256 constant uMIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000;
SD59x18 constant MIN_WHOLE_SD59x18 = SD59x18.wrap(uMIN_WHOLE_SD59x18);

/// @dev PI as an SD59x18 number.
SD59x18 constant PI = SD59x18.wrap(3_141592653589793238);

/// @dev The unit number, which gives the decimal precision of SD59x18.
int256 constant uUNIT = 1e18;
SD59x18 constant UNIT = SD59x18.wrap(1e18);

/// @dev The unit number squared.
int256 constant uUNIT_SQUARED = 1e36;
SD59x18 constant UNIT_SQUARED = SD59x18.wrap(uUNIT_SQUARED);

/// @dev Zero as an SD59x18 number.
SD59x18 constant ZERO = SD59x18.wrap(0);

File 45 of 50 : Casting.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "../Common.sol" as Common;
import "./Errors.sol" as CastingErrors;
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD1x18 } from "./ValueType.sol";

/// @notice Casts an SD1x18 number into SD59x18.
/// @dev There is no overflow check because the domain of SD1x18 is a subset of SD59x18.
function intoSD59x18(SD1x18 x) pure returns (SD59x18 result) {
    result = SD59x18.wrap(int256(SD1x18.unwrap(x)));
}

/// @notice Casts an SD1x18 number into UD2x18.
/// - x must be positive.
function intoUD2x18(SD1x18 x) pure returns (UD2x18 result) {
    int64 xInt = SD1x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD1x18_ToUD2x18_Underflow(x);
    }
    result = UD2x18.wrap(uint64(xInt));
}

/// @notice Casts an SD1x18 number into UD60x18.
/// @dev Requirements:
/// - x must be positive.
function intoUD60x18(SD1x18 x) pure returns (UD60x18 result) {
    int64 xInt = SD1x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD1x18_ToUD60x18_Underflow(x);
    }
    result = UD60x18.wrap(uint64(xInt));
}

/// @notice Casts an SD1x18 number into uint256.
/// @dev Requirements:
/// - x must be positive.
function intoUint256(SD1x18 x) pure returns (uint256 result) {
    int64 xInt = SD1x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD1x18_ToUint256_Underflow(x);
    }
    result = uint256(uint64(xInt));
}

/// @notice Casts an SD1x18 number into uint128.
/// @dev Requirements:
/// - x must be positive.
function intoUint128(SD1x18 x) pure returns (uint128 result) {
    int64 xInt = SD1x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD1x18_ToUint128_Underflow(x);
    }
    result = uint128(uint64(xInt));
}

/// @notice Casts an SD1x18 number into uint40.
/// @dev Requirements:
/// - x must be positive.
/// - x must be less than or equal to `MAX_UINT40`.
function intoUint40(SD1x18 x) pure returns (uint40 result) {
    int64 xInt = SD1x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD1x18_ToUint40_Underflow(x);
    }
    if (xInt > int64(uint64(Common.MAX_UINT40))) {
        revert CastingErrors.PRBMath_SD1x18_ToUint40_Overflow(x);
    }
    result = uint40(uint64(xInt));
}

/// @notice Alias for {wrap}.
function sd1x18(int64 x) pure returns (SD1x18 result) {
    result = SD1x18.wrap(x);
}

/// @notice Unwraps an SD1x18 number into int64.
function unwrap(SD1x18 x) pure returns (int64 result) {
    result = SD1x18.unwrap(x);
}

/// @notice Wraps an int64 number into SD1x18.
function wrap(int64 x) pure returns (SD1x18 result) {
    result = SD1x18.wrap(x);
}

File 46 of 50 : Casting.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "./Errors.sol" as CastingErrors;
import { MAX_UINT128, MAX_UINT40 } from "../Common.sol";
import { uMAX_SD1x18, uMIN_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { uMAX_UD2x18 } from "../ud2x18/Constants.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { SD59x18 } from "./ValueType.sol";

/// @notice Casts an SD59x18 number into int256.
/// @dev This is basically a functional alias for {unwrap}.
function intoInt256(SD59x18 x) pure returns (int256 result) {
    result = SD59x18.unwrap(x);
}

/// @notice Casts an SD59x18 number into SD1x18.
/// @dev Requirements:
/// - x must be greater than or equal to `uMIN_SD1x18`.
/// - x must be less than or equal to `uMAX_SD1x18`.
function intoSD1x18(SD59x18 x) pure returns (SD1x18 result) {
    int256 xInt = SD59x18.unwrap(x);
    if (xInt < uMIN_SD1x18) {
        revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Underflow(x);
    }
    if (xInt > uMAX_SD1x18) {
        revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Overflow(x);
    }
    result = SD1x18.wrap(int64(xInt));
}

/// @notice Casts an SD59x18 number into UD2x18.
/// @dev Requirements:
/// - x must be positive.
/// - x must be less than or equal to `uMAX_UD2x18`.
function intoUD2x18(SD59x18 x) pure returns (UD2x18 result) {
    int256 xInt = SD59x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Underflow(x);
    }
    if (xInt > int256(uint256(uMAX_UD2x18))) {
        revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Overflow(x);
    }
    result = UD2x18.wrap(uint64(uint256(xInt)));
}

/// @notice Casts an SD59x18 number into UD60x18.
/// @dev Requirements:
/// - x must be positive.
function intoUD60x18(SD59x18 x) pure returns (UD60x18 result) {
    int256 xInt = SD59x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD59x18_IntoUD60x18_Underflow(x);
    }
    result = UD60x18.wrap(uint256(xInt));
}

/// @notice Casts an SD59x18 number into uint256.
/// @dev Requirements:
/// - x must be positive.
function intoUint256(SD59x18 x) pure returns (uint256 result) {
    int256 xInt = SD59x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD59x18_IntoUint256_Underflow(x);
    }
    result = uint256(xInt);
}

/// @notice Casts an SD59x18 number into uint128.
/// @dev Requirements:
/// - x must be positive.
/// - x must be less than or equal to `uMAX_UINT128`.
function intoUint128(SD59x18 x) pure returns (uint128 result) {
    int256 xInt = SD59x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD59x18_IntoUint128_Underflow(x);
    }
    if (xInt > int256(uint256(MAX_UINT128))) {
        revert CastingErrors.PRBMath_SD59x18_IntoUint128_Overflow(x);
    }
    result = uint128(uint256(xInt));
}

/// @notice Casts an SD59x18 number into uint40.
/// @dev Requirements:
/// - x must be positive.
/// - x must be less than or equal to `MAX_UINT40`.
function intoUint40(SD59x18 x) pure returns (uint40 result) {
    int256 xInt = SD59x18.unwrap(x);
    if (xInt < 0) {
        revert CastingErrors.PRBMath_SD59x18_IntoUint40_Underflow(x);
    }
    if (xInt > int256(uint256(MAX_UINT40))) {
        revert CastingErrors.PRBMath_SD59x18_IntoUint40_Overflow(x);
    }
    result = uint40(uint256(xInt));
}

/// @notice Alias for {wrap}.
function sd(int256 x) pure returns (SD59x18 result) {
    result = SD59x18.wrap(x);
}

/// @notice Alias for {wrap}.
function sd59x18(int256 x) pure returns (SD59x18 result) {
    result = SD59x18.wrap(x);
}

/// @notice Unwraps an SD59x18 number into int256.
function unwrap(SD59x18 x) pure returns (int256 result) {
    result = SD59x18.unwrap(x);
}

/// @notice Wraps an int256 number into SD59x18.
function wrap(int256 x) pure returns (SD59x18 result) {
    result = SD59x18.wrap(x);
}

File 47 of 50 : Helpers.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { wrap } from "./Casting.sol";
import { SD59x18 } from "./ValueType.sol";

/// @notice Implements the checked addition operation (+) in the SD59x18 type.
function add(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    return wrap(x.unwrap() + y.unwrap());
}

/// @notice Implements the AND (&) bitwise operation in the SD59x18 type.
function and(SD59x18 x, int256 bits) pure returns (SD59x18 result) {
    return wrap(x.unwrap() & bits);
}

/// @notice Implements the AND (&) bitwise operation in the SD59x18 type.
function and2(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    return wrap(x.unwrap() & y.unwrap());
}

/// @notice Implements the equal (=) operation in the SD59x18 type.
function eq(SD59x18 x, SD59x18 y) pure returns (bool result) {
    result = x.unwrap() == y.unwrap();
}

/// @notice Implements the greater than operation (>) in the SD59x18 type.
function gt(SD59x18 x, SD59x18 y) pure returns (bool result) {
    result = x.unwrap() > y.unwrap();
}

/// @notice Implements the greater than or equal to operation (>=) in the SD59x18 type.
function gte(SD59x18 x, SD59x18 y) pure returns (bool result) {
    result = x.unwrap() >= y.unwrap();
}

/// @notice Implements a zero comparison check function in the SD59x18 type.
function isZero(SD59x18 x) pure returns (bool result) {
    result = x.unwrap() == 0;
}

/// @notice Implements the left shift operation (<<) in the SD59x18 type.
function lshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() << bits);
}

/// @notice Implements the lower than operation (<) in the SD59x18 type.
function lt(SD59x18 x, SD59x18 y) pure returns (bool result) {
    result = x.unwrap() < y.unwrap();
}

/// @notice Implements the lower than or equal to operation (<=) in the SD59x18 type.
function lte(SD59x18 x, SD59x18 y) pure returns (bool result) {
    result = x.unwrap() <= y.unwrap();
}

/// @notice Implements the unchecked modulo operation (%) in the SD59x18 type.
function mod(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() % y.unwrap());
}

/// @notice Implements the not equal operation (!=) in the SD59x18 type.
function neq(SD59x18 x, SD59x18 y) pure returns (bool result) {
    result = x.unwrap() != y.unwrap();
}

/// @notice Implements the NOT (~) bitwise operation in the SD59x18 type.
function not(SD59x18 x) pure returns (SD59x18 result) {
    result = wrap(~x.unwrap());
}

/// @notice Implements the OR (|) bitwise operation in the SD59x18 type.
function or(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() | y.unwrap());
}

/// @notice Implements the right shift operation (>>) in the SD59x18 type.
function rshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() >> bits);
}

/// @notice Implements the checked subtraction operation (-) in the SD59x18 type.
function sub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() - y.unwrap());
}

/// @notice Implements the checked unary minus operation (-) in the SD59x18 type.
function unary(SD59x18 x) pure returns (SD59x18 result) {
    result = wrap(-x.unwrap());
}

/// @notice Implements the unchecked addition operation (+) in the SD59x18 type.
function uncheckedAdd(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    unchecked {
        result = wrap(x.unwrap() + y.unwrap());
    }
}

/// @notice Implements the unchecked subtraction operation (-) in the SD59x18 type.
function uncheckedSub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    unchecked {
        result = wrap(x.unwrap() - y.unwrap());
    }
}

/// @notice Implements the unchecked unary minus operation (-) in the SD59x18 type.
function uncheckedUnary(SD59x18 x) pure returns (SD59x18 result) {
    unchecked {
        result = wrap(-x.unwrap());
    }
}

/// @notice Implements the XOR (^) bitwise operation in the SD59x18 type.
function xor(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() ^ y.unwrap());
}

File 48 of 50 : Math.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import "../Common.sol" as Common;
import "./Errors.sol" as Errors;
import {
    uEXP_MAX_INPUT,
    uEXP2_MAX_INPUT,
    uHALF_UNIT,
    uLOG2_10,
    uLOG2_E,
    uMAX_SD59x18,
    uMAX_WHOLE_SD59x18,
    uMIN_SD59x18,
    uMIN_WHOLE_SD59x18,
    UNIT,
    uUNIT,
    uUNIT_SQUARED,
    ZERO
} from "./Constants.sol";
import { wrap } from "./Helpers.sol";
import { SD59x18 } from "./ValueType.sol";

/// @notice Calculates the absolute value of x.
///
/// @dev Requirements:
/// - x must be greater than `MIN_SD59x18`.
///
/// @param x The SD59x18 number for which to calculate the absolute value.
/// @param result The absolute value of x as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function abs(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt == uMIN_SD59x18) {
        revert Errors.PRBMath_SD59x18_Abs_MinSD59x18();
    }
    result = xInt < 0 ? wrap(-xInt) : x;
}

/// @notice Calculates the arithmetic average of x and y.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// @param x The first operand as an SD59x18 number.
/// @param y The second operand as an SD59x18 number.
/// @return result The arithmetic average as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function avg(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    int256 yInt = y.unwrap();

    unchecked {
        // This operation is equivalent to `x / 2 +  y / 2`, and it can never overflow.
        int256 sum = (xInt >> 1) + (yInt >> 1);

        if (sum < 0) {
            // If at least one of x and y is odd, add 1 to the result, because shifting negative numbers to the right
            // rounds toward negative infinity. The right part is equivalent to `sum + (x % 2 == 1 || y % 2 == 1)`.
            assembly ("memory-safe") {
                result := add(sum, and(or(xInt, yInt), 1))
            }
        } else {
            // Add 1 if both x and y are odd to account for the double 0.5 remainder truncated after shifting.
            result = wrap(sum + (xInt & yInt & 1));
        }
    }
}

/// @notice Yields the smallest whole number greater than or equal to x.
///
/// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x must be less than or equal to `MAX_WHOLE_SD59x18`.
///
/// @param x The SD59x18 number to ceil.
/// @param result The smallest whole number greater than or equal to x, as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function ceil(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt > uMAX_WHOLE_SD59x18) {
        revert Errors.PRBMath_SD59x18_Ceil_Overflow(x);
    }

    int256 remainder = xInt % uUNIT;
    if (remainder == 0) {
        result = x;
    } else {
        unchecked {
            // Solidity uses C fmod style, which returns a modulus with the same sign as x.
            int256 resultInt = xInt - remainder;
            if (xInt > 0) {
                resultInt += uUNIT;
            }
            result = wrap(resultInt);
        }
    }
}

/// @notice Divides two SD59x18 numbers, returning a new SD59x18 number.
///
/// @dev This is an extension of {Common.mulDiv} for signed numbers, which works by computing the signs and the absolute
/// values separately.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv}.
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv}.
/// - None of the inputs can be `MIN_SD59x18`.
/// - The denominator must not be zero.
/// - The result must fit in SD59x18.
///
/// @param x The numerator as an SD59x18 number.
/// @param y The denominator as an SD59x18 number.
/// @param result The quotient as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    int256 yInt = y.unwrap();
    if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {
        revert Errors.PRBMath_SD59x18_Div_InputTooSmall();
    }

    // Get hold of the absolute values of x and y.
    uint256 xAbs;
    uint256 yAbs;
    unchecked {
        xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);
        yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);
    }

    // Compute the absolute value (x*UNIT÷y). The resulting value must fit in SD59x18.
    uint256 resultAbs = Common.mulDiv(xAbs, uint256(uUNIT), yAbs);
    if (resultAbs > uint256(uMAX_SD59x18)) {
        revert Errors.PRBMath_SD59x18_Div_Overflow(x, y);
    }

    // Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for
    // negative, 0 for positive or zero).
    bool sameSign = (xInt ^ yInt) > -1;

    // If the inputs have the same sign, the result should be positive. Otherwise, it should be negative.
    unchecked {
        result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));
    }
}

/// @notice Calculates the natural exponent of x using the following formula:
///
/// $$
/// e^x = 2^{x * log_2{e}}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {exp2}.
///
/// Requirements:
/// - Refer to the requirements in {exp2}.
/// - x must be less than 133_084258667509499441.
///
/// @param x The exponent as an SD59x18 number.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();

    // This check prevents values greater than 192e18 from being passed to {exp2}.
    if (xInt > uEXP_MAX_INPUT) {
        revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x);
    }

    unchecked {
        // Inline the fixed-point multiplication to save gas.
        int256 doubleUnitProduct = xInt * uLOG2_E;
        result = exp2(wrap(doubleUnitProduct / uUNIT));
    }
}

/// @notice Calculates the binary exponent of x using the binary fraction method using the following formula:
///
/// $$
/// 2^{-x} = \frac{1}{2^x}
/// $$
///
/// @dev See https://ethereum.stackexchange.com/q/79903/24693.
///
/// Notes:
/// - If x is less than -59_794705707972522261, the result is zero.
///
/// Requirements:
/// - x must be less than 192e18.
/// - The result must fit in SD59x18.
///
/// @param x The exponent as an SD59x18 number.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function exp2(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt < 0) {
        // The inverse of any number less than this is truncated to zero.
        if (xInt < -59_794705707972522261) {
            return ZERO;
        }

        unchecked {
            // Inline the fixed-point inversion to save gas.
            result = wrap(uUNIT_SQUARED / exp2(wrap(-xInt)).unwrap());
        }
    } else {
        // Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format.
        if (xInt > uEXP2_MAX_INPUT) {
            revert Errors.PRBMath_SD59x18_Exp2_InputTooBig(x);
        }

        unchecked {
            // Convert x to the 192.64-bit fixed-point format.
            uint256 x_192x64 = uint256((xInt << 64) / uUNIT);

            // It is safe to cast the result to int256 due to the checks above.
            result = wrap(int256(Common.exp2(x_192x64)));
        }
    }
}

/// @notice Yields the greatest whole number less than or equal to x.
///
/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional
/// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x must be greater than or equal to `MIN_WHOLE_SD59x18`.
///
/// @param x The SD59x18 number to floor.
/// @param result The greatest whole number less than or equal to x, as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function floor(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt < uMIN_WHOLE_SD59x18) {
        revert Errors.PRBMath_SD59x18_Floor_Underflow(x);
    }

    int256 remainder = xInt % uUNIT;
    if (remainder == 0) {
        result = x;
    } else {
        unchecked {
            // Solidity uses C fmod style, which returns a modulus with the same sign as x.
            int256 resultInt = xInt - remainder;
            if (xInt < 0) {
                resultInt -= uUNIT;
            }
            result = wrap(resultInt);
        }
    }
}

/// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right.
/// of the radix point for negative numbers.
/// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part
/// @param x The SD59x18 number to get the fractional part of.
/// @param result The fractional part of x as an SD59x18 number.
function frac(SD59x18 x) pure returns (SD59x18 result) {
    result = wrap(x.unwrap() % uUNIT);
}

/// @notice Calculates the geometric mean of x and y, i.e. $\sqrt{x * y}$.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x * y must fit in SD59x18.
/// - x * y must not be negative, since complex numbers are not supported.
///
/// @param x The first operand as an SD59x18 number.
/// @param y The second operand as an SD59x18 number.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function gm(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    int256 yInt = y.unwrap();
    if (xInt == 0 || yInt == 0) {
        return ZERO;
    }

    unchecked {
        // Equivalent to `xy / x != y`. Checking for overflow this way is faster than letting Solidity do it.
        int256 xyInt = xInt * yInt;
        if (xyInt / xInt != yInt) {
            revert Errors.PRBMath_SD59x18_Gm_Overflow(x, y);
        }

        // The product must not be negative, since complex numbers are not supported.
        if (xyInt < 0) {
            revert Errors.PRBMath_SD59x18_Gm_NegativeProduct(x, y);
        }

        // We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT`
        // during multiplication. See the comments in {Common.sqrt}.
        uint256 resultUint = Common.sqrt(uint256(xyInt));
        result = wrap(int256(resultUint));
    }
}

/// @notice Calculates the inverse of x.
///
/// @dev Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x must not be zero.
///
/// @param x The SD59x18 number for which to calculate the inverse.
/// @return result The inverse as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function inv(SD59x18 x) pure returns (SD59x18 result) {
    result = wrap(uUNIT_SQUARED / x.unwrap());
}

/// @notice Calculates the natural logarithm of x using the following formula:
///
/// $$
/// ln{x} = log_2{x} / log_2{e}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
/// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The SD59x18 number for which to calculate the natural logarithm.
/// @return result The natural logarithm as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function ln(SD59x18 x) pure returns (SD59x18 result) {
    // Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that
    // {log2} can return is ~195_205294292027477728.
    result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E);
}

/// @notice Calculates the common logarithm of x using the following formula:
///
/// $$
/// log_{10}{x} = log_2{x} / log_2{10}
/// $$
///
/// However, if x is an exact power of ten, a hard coded value is returned.
///
/// @dev Notes:
/// - Refer to the notes in {log2}.
///
/// Requirements:
/// - Refer to the requirements in {log2}.
///
/// @param x The SD59x18 number for which to calculate the common logarithm.
/// @return result The common logarithm as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function log10(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt < 0) {
        revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x);
    }

    // Note that the `mul` in this block is the standard multiplication operation, not {SD59x18.mul}.
    // prettier-ignore
    assembly ("memory-safe") {
        switch x
        case 1 { result := mul(uUNIT, sub(0, 18)) }
        case 10 { result := mul(uUNIT, sub(1, 18)) }
        case 100 { result := mul(uUNIT, sub(2, 18)) }
        case 1000 { result := mul(uUNIT, sub(3, 18)) }
        case 10000 { result := mul(uUNIT, sub(4, 18)) }
        case 100000 { result := mul(uUNIT, sub(5, 18)) }
        case 1000000 { result := mul(uUNIT, sub(6, 18)) }
        case 10000000 { result := mul(uUNIT, sub(7, 18)) }
        case 100000000 { result := mul(uUNIT, sub(8, 18)) }
        case 1000000000 { result := mul(uUNIT, sub(9, 18)) }
        case 10000000000 { result := mul(uUNIT, sub(10, 18)) }
        case 100000000000 { result := mul(uUNIT, sub(11, 18)) }
        case 1000000000000 { result := mul(uUNIT, sub(12, 18)) }
        case 10000000000000 { result := mul(uUNIT, sub(13, 18)) }
        case 100000000000000 { result := mul(uUNIT, sub(14, 18)) }
        case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) }
        case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) }
        case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) }
        case 1000000000000000000 { result := 0 }
        case 10000000000000000000 { result := uUNIT }
        case 100000000000000000000 { result := mul(uUNIT, 2) }
        case 1000000000000000000000 { result := mul(uUNIT, 3) }
        case 10000000000000000000000 { result := mul(uUNIT, 4) }
        case 100000000000000000000000 { result := mul(uUNIT, 5) }
        case 1000000000000000000000000 { result := mul(uUNIT, 6) }
        case 10000000000000000000000000 { result := mul(uUNIT, 7) }
        case 100000000000000000000000000 { result := mul(uUNIT, 8) }
        case 1000000000000000000000000000 { result := mul(uUNIT, 9) }
        case 10000000000000000000000000000 { result := mul(uUNIT, 10) }
        case 100000000000000000000000000000 { result := mul(uUNIT, 11) }
        case 1000000000000000000000000000000 { result := mul(uUNIT, 12) }
        case 10000000000000000000000000000000 { result := mul(uUNIT, 13) }
        case 100000000000000000000000000000000 { result := mul(uUNIT, 14) }
        case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) }
        case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) }
        case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) }
        case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) }
        case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) }
        case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) }
        case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) }
        case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) }
        case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) }
        case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) }
        case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) }
        case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) }
        case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) }
        case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) }
        case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) }
        case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) }
        case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) }
        case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) }
        case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) }
        case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) }
        case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) }
        case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) }
        case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) }
        case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) }
        case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) }
        case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) }
        case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) }
        case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) }
        case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) }
        case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) }
        case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) }
        case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) }
        case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) }
        case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) }
        case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) }
        case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) }
        case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) }
        case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) }
        case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) }
        case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) }
        case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) }
        case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) }
        case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) }
        case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) }
        default { result := uMAX_SD59x18 }
    }

    if (result.unwrap() == uMAX_SD59x18) {
        unchecked {
            // Inline the fixed-point division to save gas.
            result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10);
        }
    }
}

/// @notice Calculates the binary logarithm of x using the iterative approximation algorithm:
///
/// $$
/// log_2{x} = n + log_2{y}, \text{ where } y = x*2^{-n}, \ y \in [1, 2)
/// $$
///
/// For $0 \leq x \lt 1$, the input is inverted:
///
/// $$
/// log_2{x} = -log_2{\frac{1}{x}}
/// $$
///
/// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation.
///
/// Notes:
/// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal.
///
/// Requirements:
/// - x must be greater than zero.
///
/// @param x The SD59x18 number for which to calculate the binary logarithm.
/// @return result The binary logarithm as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function log2(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt <= 0) {
        revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x);
    }

    unchecked {
        int256 sign;
        if (xInt >= uUNIT) {
            sign = 1;
        } else {
            sign = -1;
            // Inline the fixed-point inversion to save gas.
            xInt = uUNIT_SQUARED / xInt;
        }

        // Calculate the integer part of the logarithm.
        uint256 n = Common.msb(uint256(xInt / uUNIT));

        // This is the integer part of the logarithm as an SD59x18 number. The operation can't overflow
        // because n is at most 255, `UNIT` is 1e18, and the sign is either 1 or -1.
        int256 resultInt = int256(n) * uUNIT;

        // Calculate $y = x * 2^{-n}$.
        int256 y = xInt >> n;

        // If y is the unit number, the fractional part is zero.
        if (y == uUNIT) {
            return wrap(resultInt * sign);
        }

        // Calculate the fractional part via the iterative approximation.
        // The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient.
        int256 DOUBLE_UNIT = 2e18;
        for (int256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {
            y = (y * y) / uUNIT;

            // Is y^2 >= 2e18 and so in the range [2e18, 4e18)?
            if (y >= DOUBLE_UNIT) {
                // Add the 2^{-m} factor to the logarithm.
                resultInt = resultInt + delta;

                // Halve y, which corresponds to z/2 in the Wikipedia article.
                y >>= 1;
            }
        }
        resultInt *= sign;
        result = wrap(resultInt);
    }
}

/// @notice Multiplies two SD59x18 numbers together, returning a new SD59x18 number.
///
/// @dev Notes:
/// - Refer to the notes in {Common.mulDiv18}.
///
/// Requirements:
/// - Refer to the requirements in {Common.mulDiv18}.
/// - None of the inputs can be `MIN_SD59x18`.
/// - The result must fit in SD59x18.
///
/// @param x The multiplicand as an SD59x18 number.
/// @param y The multiplier as an SD59x18 number.
/// @return result The product as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function mul(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    int256 yInt = y.unwrap();
    if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {
        revert Errors.PRBMath_SD59x18_Mul_InputTooSmall();
    }

    // Get hold of the absolute values of x and y.
    uint256 xAbs;
    uint256 yAbs;
    unchecked {
        xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);
        yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);
    }

    // Compute the absolute value (x*y÷UNIT). The resulting value must fit in SD59x18.
    uint256 resultAbs = Common.mulDiv18(xAbs, yAbs);
    if (resultAbs > uint256(uMAX_SD59x18)) {
        revert Errors.PRBMath_SD59x18_Mul_Overflow(x, y);
    }

    // Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for
    // negative, 0 for positive or zero).
    bool sameSign = (xInt ^ yInt) > -1;

    // If the inputs have the same sign, the result should be positive. Otherwise, it should be negative.
    unchecked {
        result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));
    }
}

/// @notice Raises x to the power of y using the following formula:
///
/// $$
/// x^y = 2^{log_2{x} * y}
/// $$
///
/// @dev Notes:
/// - Refer to the notes in {exp2}, {log2}, and {mul}.
/// - Returns `UNIT` for 0^0.
///
/// Requirements:
/// - Refer to the requirements in {exp2}, {log2}, and {mul}.
///
/// @param x The base as an SD59x18 number.
/// @param y Exponent to raise x to, as an SD59x18 number
/// @return result x raised to power y, as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    int256 yInt = y.unwrap();

    // If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero.
    if (xInt == 0) {
        return yInt == 0 ? UNIT : ZERO;
    }
    // If x is `UNIT`, the result is always `UNIT`.
    else if (xInt == uUNIT) {
        return UNIT;
    }

    // If y is zero, the result is always `UNIT`.
    if (yInt == 0) {
        return UNIT;
    }
    // If y is `UNIT`, the result is always x.
    else if (yInt == uUNIT) {
        return x;
    }

    // Calculate the result using the formula.
    result = exp2(mul(log2(x), y));
}

/// @notice Raises x (an SD59x18 number) to the power y (an unsigned basic integer) using the well-known
/// algorithm "exponentiation by squaring".
///
/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring.
///
/// Notes:
/// - Refer to the notes in {Common.mulDiv18}.
/// - Returns `UNIT` for 0^0.
///
/// Requirements:
/// - Refer to the requirements in {abs} and {Common.mulDiv18}.
/// - The result must fit in SD59x18.
///
/// @param x The base as an SD59x18 number.
/// @param y The exponent as a uint256.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function powu(SD59x18 x, uint256 y) pure returns (SD59x18 result) {
    uint256 xAbs = uint256(abs(x).unwrap());

    // Calculate the first iteration of the loop in advance.
    uint256 resultAbs = y & 1 > 0 ? xAbs : uint256(uUNIT);

    // Equivalent to `for(y /= 2; y > 0; y /= 2)`.
    uint256 yAux = y;
    for (yAux >>= 1; yAux > 0; yAux >>= 1) {
        xAbs = Common.mulDiv18(xAbs, xAbs);

        // Equivalent to `y % 2 == 1`.
        if (yAux & 1 > 0) {
            resultAbs = Common.mulDiv18(resultAbs, xAbs);
        }
    }

    // The result must fit in SD59x18.
    if (resultAbs > uint256(uMAX_SD59x18)) {
        revert Errors.PRBMath_SD59x18_Powu_Overflow(x, y);
    }

    unchecked {
        // Is the base negative and the exponent odd? If yes, the result should be negative.
        int256 resultInt = int256(resultAbs);
        bool isNegative = x.unwrap() < 0 && y & 1 == 1;
        if (isNegative) {
            resultInt = -resultInt;
        }
        result = wrap(resultInt);
    }
}

/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - Only the positive root is returned.
/// - The result is rounded toward zero.
///
/// Requirements:
/// - x cannot be negative, since complex numbers are not supported.
/// - x must be less than `MAX_SD59x18 / UNIT`.
///
/// @param x The SD59x18 number for which to calculate the square root.
/// @return result The result as an SD59x18 number.
/// @custom:smtchecker abstract-function-nondet
function sqrt(SD59x18 x) pure returns (SD59x18 result) {
    int256 xInt = x.unwrap();
    if (xInt < 0) {
        revert Errors.PRBMath_SD59x18_Sqrt_NegativeInput(x);
    }
    if (xInt > uMAX_SD59x18 / uUNIT) {
        revert Errors.PRBMath_SD59x18_Sqrt_Overflow(x);
    }

    unchecked {
        // Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two SD59x18 numbers.
        // In this case, the two numbers are both the square root.
        uint256 resultUint = Common.sqrt(uint256(xInt * uUNIT));
        result = wrap(int256(resultUint));
    }
}

File 49 of 50 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { SD1x18 } from "./ValueType.sol";

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in UD2x18.
error PRBMath_SD1x18_ToUD2x18_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in UD60x18.
error PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint128.
error PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint256.
error PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x);

/// @notice Thrown when trying to cast a SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);

File 50 of 50 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;

import { SD59x18 } from "./ValueType.sol";

/// @notice Thrown when taking the absolute value of `MIN_SD59x18`.
error PRBMath_SD59x18_Abs_MinSD59x18();

/// @notice Thrown when ceiling a number overflows SD59x18.
error PRBMath_SD59x18_Ceil_Overflow(SD59x18 x);

/// @notice Thrown when converting a basic integer to the fixed-point format overflows SD59x18.
error PRBMath_SD59x18_Convert_Overflow(int256 x);

/// @notice Thrown when converting a basic integer to the fixed-point format underflows SD59x18.
error PRBMath_SD59x18_Convert_Underflow(int256 x);

/// @notice Thrown when dividing two numbers and one of them is `MIN_SD59x18`.
error PRBMath_SD59x18_Div_InputTooSmall();

/// @notice Thrown when dividing two numbers and one of the intermediary unsigned results overflows SD59x18.
error PRBMath_SD59x18_Div_Overflow(SD59x18 x, SD59x18 y);

/// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441.
error PRBMath_SD59x18_Exp_InputTooBig(SD59x18 x);

/// @notice Thrown when taking the binary exponent of a base greater than 192e18.
error PRBMath_SD59x18_Exp2_InputTooBig(SD59x18 x);

/// @notice Thrown when flooring a number underflows SD59x18.
error PRBMath_SD59x18_Floor_Underflow(SD59x18 x);

/// @notice Thrown when taking the geometric mean of two numbers and their product is negative.
error PRBMath_SD59x18_Gm_NegativeProduct(SD59x18 x, SD59x18 y);

/// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows SD59x18.
error PRBMath_SD59x18_Gm_Overflow(SD59x18 x, SD59x18 y);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD1x18.
error PRBMath_SD59x18_IntoSD1x18_Overflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD1x18.
error PRBMath_SD59x18_IntoSD1x18_Underflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD2x18.
error PRBMath_SD59x18_IntoUD2x18_Overflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD2x18.
error PRBMath_SD59x18_IntoUD2x18_Underflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD60x18.
error PRBMath_SD59x18_IntoUD60x18_Underflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint128.
error PRBMath_SD59x18_IntoUint128_Overflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint128.
error PRBMath_SD59x18_IntoUint128_Underflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint256.
error PRBMath_SD59x18_IntoUint256_Underflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint40.
error PRBMath_SD59x18_IntoUint40_Overflow(SD59x18 x);

/// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint40.
error PRBMath_SD59x18_IntoUint40_Underflow(SD59x18 x);

/// @notice Thrown when taking the logarithm of a number less than or equal to zero.
error PRBMath_SD59x18_Log_InputTooSmall(SD59x18 x);

/// @notice Thrown when multiplying two numbers and one of the inputs is `MIN_SD59x18`.
error PRBMath_SD59x18_Mul_InputTooSmall();

/// @notice Thrown when multiplying two numbers and the intermediary absolute result overflows SD59x18.
error PRBMath_SD59x18_Mul_Overflow(SD59x18 x, SD59x18 y);

/// @notice Thrown when raising a number to a power and hte intermediary absolute result overflows SD59x18.
error PRBMath_SD59x18_Powu_Overflow(SD59x18 x, uint256 y);

/// @notice Thrown when taking the square root of a negative number.
error PRBMath_SD59x18_Sqrt_NegativeInput(SD59x18 x);

/// @notice Thrown when the calculating the square root overflows SD59x18.
error PRBMath_SD59x18_Sqrt_Overflow(SD59x18 x);

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@prb/math/=lib/v2-core/lib/prb-math/src/",
    "@prb/proxy-test/=lib/prb-proxy/test/",
    "@prb/proxy/=lib/prb-proxy/src/",
    "@prb/test/=lib/prb-test/src/",
    "@sablier/v2-core-script/=lib/v2-core/script/",
    "@sablier/v2-core-test/=lib/v2-core/test/",
    "@sablier/v2-core/=lib/v2-core/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "permit2-test/=lib/permit2/test/",
    "permit2/=lib/permit2/src/",
    "prb-math/=lib/v2-core/lib/prb-math/src/",
    "prb-proxy/=lib/prb-proxy/",
    "prb-test/=lib/prb-test/src/",
    "solady/=lib/solady/src/",
    "solarray/=lib/v2-core/lib/solarray/src/",
    "solmate/=lib/permit2/lib/solmate/",
    "v2-core/=lib/v2-core/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IAllowanceTransfer","name":"permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallNotDelegateCall","type":"error"},{"inputs":[],"name":"SablierV2ProxyTarget_BatchSizeZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"},{"internalType":"uint256","name":"creditAmount","type":"uint256"}],"name":"SablierV2ProxyTarget_CreditAmountMismatch","type":"error"},{"inputs":[{"components":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"}],"internalType":"struct Batch.CancelMultiple[]","name":"batch","type":"tuple[]"},{"internalType":"contract IERC20[]","name":"assets","type":"address[]"}],"name":"batchCancelMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"delta","type":"uint40"}],"internalType":"struct LockupDynamic.SegmentWithDelta[]","name":"segments","type":"tuple[]"}],"internalType":"struct Batch.CreateWithDeltas[]","name":"batch","type":"tuple[]"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"batchCreateWithDeltas","outputs":[{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"total","type":"uint40"}],"internalType":"struct LockupLinear.Durations","name":"durations","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct Batch.CreateWithDurations[]","name":"batch","type":"tuple[]"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"batchCreateWithDurations","outputs":[{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"milestone","type":"uint40"}],"internalType":"struct LockupDynamic.Segment[]","name":"segments","type":"tuple[]"}],"internalType":"struct Batch.CreateWithMilestones[]","name":"batch","type":"tuple[]"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"batchCreateWithMilestones","outputs":[{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"start","type":"uint40"},{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"end","type":"uint40"}],"internalType":"struct LockupLinear.Range","name":"range","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct Batch.CreateWithRange[]","name":"batch","type":"tuple[]"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"batchCreateWithRange","outputs":[{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"delta","type":"uint40"}],"internalType":"struct LockupDynamic.SegmentWithDelta[]","name":"segments","type":"tuple[]"}],"internalType":"struct LockupDynamic.CreateWithDeltas","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"cancelAndCreateWithDeltas","outputs":[{"internalType":"uint256","name":"newStreamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"total","type":"uint40"}],"internalType":"struct LockupLinear.Durations","name":"durations","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct LockupLinear.CreateWithDurations","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"cancelAndCreateWithDurations","outputs":[{"internalType":"uint256","name":"newStreamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"milestone","type":"uint40"}],"internalType":"struct LockupDynamic.Segment[]","name":"segments","type":"tuple[]"}],"internalType":"struct LockupDynamic.CreateWithMilestones","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"cancelAndCreateWithMilestones","outputs":[{"internalType":"uint256","name":"newStreamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"start","type":"uint40"},{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"end","type":"uint40"}],"internalType":"struct LockupLinear.Range","name":"range","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct LockupLinear.CreateWithRange","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"cancelAndCreateWithRange","outputs":[{"internalType":"uint256","name":"newStreamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"contract IERC20[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"}],"name":"cancelMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"delta","type":"uint40"}],"internalType":"struct LockupDynamic.SegmentWithDelta[]","name":"segments","type":"tuple[]"}],"internalType":"struct LockupDynamic.CreateWithDeltas","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"createWithDeltas","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"total","type":"uint40"}],"internalType":"struct LockupLinear.Durations","name":"durations","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct LockupLinear.CreateWithDurations","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"createWithDurations","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"milestone","type":"uint40"}],"internalType":"struct LockupDynamic.Segment[]","name":"segments","type":"tuple[]"}],"internalType":"struct LockupDynamic.CreateWithMilestones","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"createWithMilestones","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"start","type":"uint40"},{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"end","type":"uint40"}],"internalType":"struct LockupLinear.Range","name":"range","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct LockupLinear.CreateWithRange","name":"createParams","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Permit2Params","name":"permit2Params","type":"tuple"}],"name":"createWithRange","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"renounce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"address","name":"newRecipient","type":"address"}],"name":"withdrawMaxAndTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"delta","type":"uint40"}],"internalType":"struct LockupDynamic.SegmentWithDelta[]","name":"segments","type":"tuple[]"}],"internalType":"struct LockupDynamic.CreateWithDeltas","name":"createParams","type":"tuple"}],"name":"wrapAndCreateWithDeltas","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"total","type":"uint40"}],"internalType":"struct LockupLinear.Durations","name":"durations","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct LockupLinear.CreateWithDurations","name":"createParams","type":"tuple"}],"name":"wrapAndCreateWithDurations","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupDynamic","name":"dynamic","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint40","name":"startTime","type":"uint40"},{"internalType":"bool","name":"cancelable","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"UD2x18","name":"exponent","type":"uint64"},{"internalType":"uint40","name":"milestone","type":"uint40"}],"internalType":"struct LockupDynamic.Segment[]","name":"segments","type":"tuple[]"}],"internalType":"struct LockupDynamic.CreateWithMilestones","name":"createParams","type":"tuple"}],"name":"wrapAndCreateWithMilestones","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ISablierV2LockupLinear","name":"lockupLinear","type":"address"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"totalAmount","type":"uint128"},{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"bool","name":"cancelable","type":"bool"},{"components":[{"internalType":"uint40","name":"start","type":"uint40"},{"internalType":"uint40","name":"cliff","type":"uint40"},{"internalType":"uint40","name":"end","type":"uint40"}],"internalType":"struct LockupLinear.Range","name":"range","type":"tuple"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"UD60x18","name":"fee","type":"uint256"}],"internalType":"struct Broker","name":"broker","type":"tuple"}],"internalType":"struct LockupLinear.CreateWithRange","name":"createParams","type":"tuple"}],"name":"wrapAndCreateWithRange","outputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"stateMutability":"payable","type":"function"}]

60c0346200007d57601f620042a838819003918201601f19168301916001600160401b0383118484101762000082578084926020946040528339810103126200007d57516001600160a01b03811681036200007d573060805260a05260405161420f9081620000998239608051816141bd015260a05181613fb70152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816310fad8c81461281b575080631d165efc1461268f57806339532c191461244057806351c9b6f1146123d957806361ea5802146120fe5780636a09d49a1461201a578063868699c514611e8d57806386f2891e14611e155780638922211914611dae5780638ad7937414611b7357806390e2cd79146119b657806398590ef9146117c15780639dc29fac14611746578063a3143b76146116cd578063a4af60d214611357578063ad26c0fb146112cc578063b956b45f14611206578063c00b86a514610f26578063c0cb6a4014610d51578063c426f89c14610b03578063ec5b900f14610954578063f1630612146107bf578063f65e5d66146103ce5763fe5cacde1461012957600080fd5b346103c75760031960a0813601126103ca57610143612a0e565b9160243591610150612a24565b906064359267ffffffffffffffff918285116103ca576101008186360301126103ca576084359283116103ca5760e09083360301126103c7576101916141b3565b6101996141b3565b6001600160a01b0380961690604051957feac8f5b80000000000000000000000000000000000000000000000000000000087528060048801526020978888602481875afa9788156103bc578398610384575b50871690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a86602481875afa95861561037957859661034a575b50813b156103465784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1801561033b578a9291859161031e575b505060246040518094819382523060048301525afa91821561031257916102dc575b50946102b86102c7926102d497612e6b565b906102c1613c99565b90612ea7565b6004019160040190613665565b604051908152f35b9590508686813d831161030b575b6102f48183612aee565b810103126103065794516102b86102a6565b600080fd5b503d6102ea565b604051903d90823e3d90fd5b61032a91929350612aa2565b6103375788908338610284565b8280fd5b6040513d86823e3d90fd5b8480fd5b9095508a81813d8311610372575b6103628183612aee565b8101031261030657519438610234565b503d610358565b6040513d87823e3d90fd5b9097508881813d83116103b5575b61039c8183612aee565b81010312610337575187811681036103375796386101eb565b503d610392565b6040513d85823e3d90fd5b80fd5b5080fd5b50346103c7576003196101c0813601126103ca576103ea612a0e565b906024908135926103f9612a24565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126107b7576101a4359267ffffffffffffffff84116107bb5760e09084360301126107b75761044c6141b3565b6104546141b3565b6001600160a01b03809216604051907feac8f5b800000000000000000000000000000000000000000000000000000000825286600483015260209687838881855afa92831561070f57899361077b575b508885841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528b868c81885afa95861561033b578496610748575b50813b156107445783918b839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578b9361071a575b5050886040518094819382523060048301525afa90811561070f578596979899916106d7575b5061057092916102b891612e6b565b6105786141b3565b169160c435828116918282036103065760a435916fffffffffffffffffffffffffffffffff831680930361030657826105b5926004019187613f9f565b604051947f4bc78b7300000000000000000000000000000000000000000000000000000000865260643584811680910361030657600487015260843590848216809203610306578601526044850152606484015260e4358015158091036103065760848401526101049081359064ffffffffff918281168091036103065760a48601526101249283358381168091036103065760c48701526101449283359081168091036103065760e4870152610164359182168092036103065786948694859360009385015261018435908401525af19081156106cb5760009161069e575b50604051908152f35b908282813d83116106c4575b6106b48183612aee565b810103126103c757505138610695565b503d6106aa565b6040513d6000823e3d90fd5b9450909190508784813d8111610708575b6106f28183612aee565b8101031261030657925184939190610570610561565b503d6106e8565b6040513d8b823e3d90fd5b61072691929350612aa2565b6107335788908a3861053b565b8980fd5b50604051903d90823e3d90fd5b8380fd5b8c809297508195503d8311610774575b6107628183612aee565b81010312610306578b925194386104ee565b503d610758565b9092508781813d83116107b0575b6107938183612aee565b810103126107ac575184811681036107ac5791386104a4565b8880fd5b503d610789565b8580fd5b8680fd5b50346103c75760406003193601126103c75767ffffffffffffffff600435818111610337576107f2903690600401612ca9565b91906024358281116103465761080c903690600401612ca9565b9290916108176141b3565b841561092a57856108288585613bcb565b92815b878110610841578261083e888888613d18565b80f35b61084c818986612dba565b356001600160a01b03811680910361074457610869828a87612dba565b60209081810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156107bb5701908135918583116107bb5701908060051b360382136107b757823b156107b7576108fa928692836040518096819582947f8659c27000000000000000000000000000000000000000000000000000000000845260048401612e29565b03925af190811561033b578491610916575b505060010161082b565b61091f90612aa2565b61033757823861090c565b60046040517f71594532000000000000000000000000000000000000000000000000000000008152fd5b50600319906040823601126103c75761096b612a0e565b916024359067ffffffffffffffff9081831161074457610100908336030112610337576040519061099b82612a3a565b6109a783600401612b27565b82526109b560248401612b9c565b94602095868401526109c960448501612b27565b60408401526109da60648501612b5a565b91606084019283526109ee60848601612b27565b9460808501958652610a033660a48301612bbb565b60a086015260e48101359182116107bb5701366023820112156107b75792610a88610abd93879693610a408a973690602460048201359101612c17565b60c0850152610a4d6141b3565b6fffffffffffffffffffffffffffffffff9081341683526001600160a01b038091610a7a82895116613df7565b169551169151169084613a07565b6040519485809481937fbf061d0a00000000000000000000000000000000000000000000000000000000835260048301613408565b03925af19182156103125791610ad65750604051908152f35b90508181813d8311610afc575b610aed8183612aee565b81010312610306575138610695565b503d610ae3565b50346103c75760031960a0813601126103ca57610b1e612a0e565b9160243591610b2b612a24565b906064359267ffffffffffffffff918285116103ca576101208186360301126103ca576084359283116103ca5760e09083360301126103c757610b6c6141b3565b610b746141b3565b6001600160a01b0380961690604051957feac8f5b80000000000000000000000000000000000000000000000000000000087528060048801526020978888602481875afa9788156103bc578398610d19575b50871690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a86602481875afa958615610379578596610cea575b50813b156103465784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1801561033b578a92918591610cd1575b505060246040518094819382523060048301525afa9182156103125791610ca0575b50946102b8610c93926102d497612e6b565b6004019160040190613895565b9590508686813d8311610cca575b610cb88183612aee565b810103126103065794516102b8610c81565b503d610cae565b610cdd91929350612aa2565b6103375788908338610c5f565b9095508a81813d8311610d12575b610d028183612aee565b8101031261030657519438610c0f565b503d610cf8565b9097508881813d8311610d4a575b610d318183612aee565b8101031261033757518781168103610337579638610bc6565b503d610d27565b50346103c75760031990610180823601126103c757610d6e612a0e565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c757610164359267ffffffffffffffff84116103ca5760e09084360301126103c75750610dc36141b3565b6001600160a01b03809116608435928284169081850361030657606435946fffffffffffffffffffffffffffffffff86168096036103065785610e0a926004019185613f9f565b604051937f4bc78b730000000000000000000000000000000000000000000000000000000085526024358481168091036103065760048601526044358481168091036103065760248601526044850152606484015260a43580151580910361030657608484015260c4359164ffffffffff928381168091036103065760a485015260e4358381168091036103065760c48501526101049283359081168091036103065760e485015261012490813590811680910361030657600085938492602096840152610144938435908401525af19081156106cb57600091610ef4575b602082604051908152f35b6020813d8211610f1e575b81610f0c60209383612aee565b810103126103ca575190506020610ee9565b3d9150610eff565b50346103c7576080600319818136011261033757610f42612a0e565b610f4a612b11565b916044359067ffffffffffffffff948583116107bb57366023840112156107bb57826004013591868311611202576024840193602436918560081b010111611202576064359687116112025760e09087360301126107bb57610faa6141b3565b811561092a5790939086805b8681106111bf5750610fd9906001600160a01b0380961697600401908489613f9f565b610fe28561319f565b9584889316925b8681106110025760405180610ffe8a82612d4b565b0390f35b60c0908682611012838b8a613172565b018960609481898b8789611027828685613172565b01611031906131d0565b9361103b92613172565b978c6020978861104c8b8985613172565b01611056906131dd565b918a611063818a84613172565b61106c906131dd565b9861107692613172565b60400161108290613182565b9181604051986110918a612a3a565b16885216888701526fffffffffffffffffffffffffffffffff1660408601528401521515888301528536037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160401361030657611123849361115c97604051906110fb82612ad2565b6111068c8201612ba9565b825261111560a0809201612ba9565b878301528501523690612bbb565b908201528c60405180809781947f1b4103a9000000000000000000000000000000000000000000000000000000008352600483016131f1565b0391885af19081156111b4578b91611185575b506001925061117e828b61328a565b5201610fe9565b905082813d83116111ad575b61119b8183612aee565b8101031261030657600191513861116f565b503d611191565b6040513d8d823e3d90fd5b906001600160a01b036001916fffffffffffffffffffffffffffffffff6111f560406111ef878d8c9e9b9e613172565b01613182565b1601169101959295610fb6565b8780fd5b50346103c75760806003193601126103c75780611221612a0e565b611229612a24565b611231612b3b565b9161123a6141b3565b6001600160a01b03809116803b15610346578492836064926fffffffffffffffffffffffffffffffff60405197889687957ffdd46d6000000000000000000000000000000000000000000000000000000000875260243560048801521660248601521660448401525af180156112c1576112b15750f35b6112ba90612aa2565b6103c75780f35b6040513d84823e3d90fd5b50346103c757806001600160a01b036112e436612d86565b9290916112ef6141b3565b1691823b15611352576040517fc156a11d00000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b031660248201529082908290818381604481015b03925af180156112c1576112b15750f35b505050fd5b50346103c7576003196101a0813601126103ca57611373612a0e565b602490813592611381612a24565b6101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126107b757610184359167ffffffffffffffff83116107bb5760e09083360301126107b7576113d46141b3565b6113dc6141b3565b6001600160a01b03809316604051907feac8f5b800000000000000000000000000000000000000000000000000000000825286600483015260209687838881855afa92831561070f578993611695575b508886841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528b868c81885afa95861561033b578496611662575b50813b156107445783918b839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578b93611649575b5050886040518094819382523060048301525afa90811561070f578697989996959691611611575b506114fa92916102b891612e6b565b6115026141b3565b169060c435838116918282036103065760a435916fffffffffffffffffffffffffffffffff8316809303610306578261153f926004019186613f9f565b604051947f1b4103a900000000000000000000000000000000000000000000000000000000865260643585811680910361030657600487015260843590858216809203610306578601526044850152606484015260e43580151580910361030657608484015264ffffffffff6101048035828116908190036103065760a48601526101249182359081168091036103065760c48601526101443593841680940361030657600085938492889660e485015261016435908401525af19081156106cb5760009161069e5750604051908152f35b9450909190508784813d8111611642575b61162c8183612aee565b81010312610306579251859391906114fa6114eb565b503d611622565b61165591929350612aa2565b6107335788908a386114c3565b8c809297508195503d831161168e575b61167c8183612aee565b81010312610306578b92519438611476565b503d611672565b9092508781813d83116116c6575b6116ad8183612aee565b810103126107ac575185811681036107ac57913861142c565b503d6116a3565b50346103c757806001600160a01b036116e536612d86565b9290916116f06141b3565b1691823b15611352576040517fea5ead1900000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03166024820152908290829081838160448101611341565b50346103c75760406003193601126103c757806001600160a01b03611769612a0e565b6117716141b3565b16803b156117be578180916024604051809481937f42966c68000000000000000000000000000000000000000000000000000000008352833560048401525af180156112c1576112b15750f35b50fd5b50346103c75760406003193601126103c7576117db612a0e565b6024356117e66141b3565b6001600160a01b0380921691604051917feac8f5b8000000000000000000000000000000000000000000000000000000008352806004840152846020928385602481895afa9485156112c157829561197e575b50841691604051957f70a0823100000000000000000000000000000000000000000000000000000000918288523060048901528588602481885afa97881561033b57849861194b575b50813b156107445783916024839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578593611932575b505060246040518094819382523060048301525afa918215610379578592611902575b505061083e926102b891612e6b565b90809250813d831161192b575b6119198183612aee565b810103126103065751826102b86118f3565b503d61190f565b61193e91929350612aa2565b6107b757829086386118d0565b86809299508195503d8311611977575b6119658183612aee565b81010312610306578792519638611882565b503d61195b565b9094508381813d83116119af575b6119968183612aee565b810103126103ca575184811681036103ca579338611839565b503d61198c565b506101406003193601126103c7576119cc612a0e565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c75760405191611a0583612a3a565b611a0d612b11565b8352611a17612a24565b9260209384820152611a27612b3b565b9060408101918252611a37612b77565b60608201908152611a46612b8d565b608083015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c36011261030657604051611a8181612ad2565b64ffffffffff60c435818116810361030657825260e4359081168103610306578782015260a083015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc3601126103065760405191611ae183612ad2565b610104356001600160a01b03948582168203610306578796899686611b3e94610abd9852610124358982015260c0860152611b1a6141b3565b806fffffffffffffffffffffffffffffffff928334168552610a7a82895116613df7565b6040519485809481937f1b4103a9000000000000000000000000000000000000000000000000000000008352600483016131f1565b50346103c757611b8236612cda565b611b8e949193946141b3565b831561092a578591865b858110611d775750906001600160a01b03611bb69216928684613f9f565b611bbf8361319f565b93855b848110611bd75760405180610ffe8882612d4b565b60809081611be6828888613374565b018587611bf4848284613374565b602001611c00906131d0565b92611c0c858385613374565b604001611c18906131dd565b9585611c25818587613374565b958160c097888101611c36916133b4565b96611c42929198613374565b611c4b906131dd565b988d8d6060948592611c5c92613374565b01611c6690613182565b916040519a611c748c612a3a565b6001600160a01b03168b52151560208b01526001600160a01b031660408a01526fffffffffffffffffffffffffffffffff16908801526001600160a01b0388169087015236611cc291612bbb565b60a08601523690611cd292612c17565b90830152836040518080947fbf061d0a0000000000000000000000000000000000000000000000000000000082526004820190611d0e91613408565b03818b5a94602095f18015611d6c578890611d39575b60019250611d32828961328a565b5201611bc2565b506020823d602011611d64575b81611d5360209383612aee565b810103126103065760019151611d24565b3d9150611d46565b6040513d8a823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff611da460606111ef898c8c613374565b1601169301611b98565b50346103c7576003196060813601126103ca57611dc9612a0e565b906024359267ffffffffffffffff918285116103ca576101008186360301126103ca576044359283116103ca5760e09083360301126103c75760206102d4600480850190870186613665565b50346103c75760406003193601126103c757806001600160a01b03611e38612a0e565b611e406141b3565b16803b156117be578180916024604051809481937f7de6b1db000000000000000000000000000000000000000000000000000000008352833560048401525af180156112c1576112b15750f35b50346103c75760031990610160823601126103c757611eaa612a0e565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c757610144359267ffffffffffffffff84116103ca5760e09084360301126103c75750611eff6141b3565b6001600160a01b0380911690608435928184169081850361030657606435946fffffffffffffffffffffffffffffffff86168096036103065785611f47926004019186613f9f565b604051937f1b4103a90000000000000000000000000000000000000000000000000000000085526024358381168091036103065760048601526044358381168091036103065760248601526044850152606484015260a43580151580910361030657608484015260c43564ffffffffff908181168091036103065760a485015260e4359081168091036103065760c4840152610104803591821680920361030657836000602094829460e4840152610124938435908401525af19081156106cb57600091610ef457602082604051908152f35b50346103c75760606003193601126103c757612034612a0e565b9067ffffffffffffffff60243581811161033757612056903690600401612ca9565b916044359081116107445761206f903690600401612ca9565b906120786141b3565b6001600160a01b0361208a8585613bcb565b961690813b156107b7579185916120d193836040518096819582947f8659c27000000000000000000000000000000000000000000000000000000000845260048401612e29565b03925af1801561033b576120eb575b5061083e9293613d18565b926120f861083e94612aa2565b926120e0565b50346103c7576080906003199082823601126103c75761211c612a0e565b90612125612b11565b916044359367ffffffffffffffff91828611610744573660238701121561074457856004013591838311610346576024870196602436916101208602010111610346576064359384116103465760e0908436030112610744576121866141b3565b811561092a5793959383805b83811061239c57506121b5906001600160a01b0380931694600401908986613f9f565b6121be8261319f565b9581859816975b8381106121da5760405180610ffe8a82612d4b565b88816121e781878661329e565b60e001606090816121f9848a8961329e565b01612203906131d0565b9161220f848a8961329e565b926020958a8a818b898b61222482858561329e565b0161222e906131dd565b946122389261329e565b612241906131dd565b9861224c918d61329e565b60400161225890613182565b9181604051996122678b612a3a565b16895216888801526fffffffffffffffffffffffffffffffff1660408701528286015215158c8501528236037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001126107335791839161230b612342948d6122dc604051916122d583612ab6565b8501612ba9565b815260a06122eb818601612ba9565b878301526122fc60c0809601612ba9565b60408301528501523690612bbb565b90820152604051809381927f4bc78b73000000000000000000000000000000000000000000000000000000008352600483016132af565b03818b8b5af1918215611d6c57889261236d575b505090600191612366828b61328a565b52016121c5565b90809250813d8311612395575b6123848183612aee565b810103126107bb5751600138612356565b503d61237a565b906001600160a01b036001916fffffffffffffffffffffffffffffffff6123cc60406111ef879c9e9c8a8f61329e565b1601169101979597612192565b50346103c7576003196060813601126103ca576123f4612a0e565b906024359267ffffffffffffffff918285116103ca576101208186360301126103ca576044359283116103ca5760e09083360301126103c75760206102d4600480850190870186613895565b50346103c75761244f36612cda565b61245c94919293946141b3565b821561092a5785865b84811061265857509061248291866001600160a01b038516613f9f565b61248b8261319f565b93855b8381106124a35760405180610ffe8882612d4b565b60a06124b082868861350e565b01906124c860406124c283888a61350e565b016131d0565b866124df60606124d9858a8561350e565b016131dd565b916124f86124ee858a8561350e565b60e08101906133b4565b6020612518878c61251261250d83838b61350e565b6131dd565b9761350e565b01359464ffffffffff86168603612654576125f0976fffffffffffffffffffffffffffffffff61257b966001600160a01b038f948f9864ffffffffff60209c848f60806111ef6125b89f92612570936125ac9e61350e565b966040519e8f612a85565b168d52168c8c0152151560408b01521660608901521660808701526001600160a01b038a1660a08701523690612bbb565b60c08501523691612c17565b60e0820152604051809481927f21714be10000000000000000000000000000000000000000000000000000000083526004830161354e565b03818b6001600160a01b0389165af18015611d6c578890612621575b6001925061261a828961328a565b520161248e565b506020823d60201161264c575b8161263b60209383612aee565b81010312611202576001915161260c565b3d915061262e565b8d80fd5b906001600160a01b036001916fffffffffffffffffffffffffffffffff61268560806111ef878b8d61350e565b1601169101612465565b50600319906040823601126103c7576126a6612a0e565b916024359067ffffffffffffffff908183116107445761012090833603011261033757604051906126d682612a85565b6126e283600401612b27565b82526126f060248401612ba9565b946020958684015261270460448501612b9c565b604084015261271560648501612b27565b606084015261272660848501612b5a565b916080840192835261273a60a48601612b27565b9460a0850195865261274f3660c48301612bbb565b60c08601526101048101359182116107bb5701366023820112156107b7579261279a6127cf9387969361278d8a973690602460048201359101612c17565b60e0850152610a4d6141b3565b6040519485809481937f21714be10000000000000000000000000000000000000000000000000000000083526004830161354e565b03925af19182156103125780926127eb575b5050604051908152f35b9091508282813d8311612814575b6128038183612aee565b810103126103c757505138806127e1565b503d6127f9565b826101606003193601126103c757612831612a0e565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103ca5761286583612a3a565b61286d612b11565b8352612877612a24565b9260209384820152612887612b3b565b60408201908152612896612b77565b92606083019384526128a6612b8d565b608084015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c360112610346576040516128e181612ab6565b64ffffffffff60c435818116810361120257825260e435818116810361120257888301526101043590811681036107bb57604082015260a084015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc3601126103465760405161295281612ad2565b6001600160a01b03906101243582811681036112025793879693899693836129c39761298e9552610144358982015260c0860152611b1a6141b3565b6040519485809481937f4bc78b73000000000000000000000000000000000000000000000000000000008352600483016132af565b03925af19182156103125780926129de575050604051908152f35b9091508282813d8311612a07575b6129f68183612aee565b810103126103c757505182806127e1565b503d6129ec565b600435906001600160a01b038216820361030657565b604435906001600160a01b038216820361030657565b60e0810190811067ffffffffffffffff821117612a5657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610100810190811067ffffffffffffffff821117612a5657604052565b67ffffffffffffffff8111612a5657604052565b6060810190811067ffffffffffffffff821117612a5657604052565b6040810190811067ffffffffffffffff821117612a5657604052565b90601f601f19910116810190811067ffffffffffffffff821117612a5657604052565b602435906001600160a01b038216820361030657565b35906001600160a01b038216820361030657565b606435906fffffffffffffffffffffffffffffffff8216820361030657565b35906fffffffffffffffffffffffffffffffff8216820361030657565b608435906001600160a01b038216820361030657565b60a43590811515820361030657565b3590811515820361030657565b359064ffffffffff8216820361030657565b919082604091031261030657604051612bd381612ad2565b6020808294612be181612b27565b84520135910152565b67ffffffffffffffff8111612a565760051b60200190565b359067ffffffffffffffff8216820361030657565b929192612c2382612bea565b604094612c3286519283612aee565b8195848352602080930191606080960285019481861161030657925b858410612c5e5750505050505050565b8684830312610306578487918451612c7581612ab6565b612c7e87612b5a565b8152612c8b838801612c02565b83820152612c9a868801612ba9565b86820152815201930192612c4e565b9181601f840112156103065782359167ffffffffffffffff8311610306576020808501948460051b01011161030657565b9060031991608083820112610306576001600160a01b0392600435848116810361030657936024359081168103610306579267ffffffffffffffff6044358181116103065784612d2c91600401612ca9565b94909493606435928311610306578260e0920301126103065760040190565b6020908160408183019282815285518094520193019160005b828110612d72575050505090565b835185529381019392810192600101612d64565b6003196060910112610306576001600160a01b03600435818116810361030657916024359160443590811681036103065790565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610306570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081528260208201527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103065760409260051b809284830137010190565b91908203918211612e7857565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152612f0191612efc606483612aee565b612f1b565b565b90816020910312610306575180151581036103065790565b604051612f79916001600160a01b0316612f3482612ad2565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1612f7361302e565b9161306e565b805190828215928315613016575b50505015612f925750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6130269350820181019101612f03565b388281612f87565b3d15613069573d9067ffffffffffffffff8211612a56576040519161305d6020601f19601f8401160184612aee565b82523d6000602084013e565b606090565b919290156130e95750815115613082575090565b3b1561308b5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156130fc5750805190602001fd5b604051907f08c379a000000000000000000000000000000000000000000000000000000000825281602080600483015282519283602484015260005b84811061315b57505050601f19601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201613138565b9190811015612dfa5760081b0190565b356fffffffffffffffffffffffffffffffff811681036103065790565b906131a982612bea565b6131b66040519182612aee565b828152601f196131c68294612bea565b0190602036910137565b3580151581036103065790565b356001600160a01b03811681036103065790565b612f019092919260e060c06101208301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151602064ffffffffff918281511660a0880152015116828501520151910190602080916001600160a01b0381511684520151910152565b8051821015612dfa5760209160051b010190565b9190811015612dfa57610120020190565b612f019092919261010060c06101408301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151604064ffffffffff918281511660a0880152826020820151168588015201511660e08501520151910190602080916001600160a01b0381511684520151910152565b602080916001600160a01b0361336a82612b27565b1684520135910152565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2181360301821215610306570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610306570180359067ffffffffffffffff82116103065760200191606082023603831361030657565b9060208083526101208301908061014060c06001600160a01b0395868151168489015283810151151560408901528660408201511696606097888a01526fffffffffffffffffffffffffffffffff888301511660808a015260808201511660a089015261348f60a0820151838a0190602080916001600160a01b0381511684520151910152565b015195610100808201528651809552019401926000905b8382106134b557505050505090565b90919293948382826135016001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01960194939201906134a6565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0181360301821215610306570190565b9060208083526101408301908061016060e06001600160a01b0395868151168489015264ffffffffff848201511660408901526040810151151596606097888a015280888301511660808a01526fffffffffffffffffffffffffffffffff60808301511660a08a015260a08201511660c08901526135e660c0820151838a0190602080916001600160a01b0381511684520151910152565b015195610120808201528651809552019401926000905b83821061360c57505050505090565b90919293948382826136586001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01960194939201906135fd565b909161366f6141b3565b60808301916001600160a01b03908116613688846131dd565b9260606136b6818801926fffffffffffffffffffffffffffffffff96876136ae86613182565b169086613f9f565b61375e6040519788957fbf061d0a00000000000000000000000000000000000000000000000000000000875261373e6020998a998a60048b01526137336101248b01988561370388612b27565b1660248d01526137148d8801612b9c565b151560448d01528561372860408901612b27565b1660648d0152612b5a565b1660848a0152612b27565b1660a487015261375460c4870160a08301613355565b60e08101906137f1565b809193610100610104880152526101448501929160005b8281106137ca5750505050600083809203925af19081156106cb5760009161379e575b50905090565b82813d83116137c3575b6137b28183612aee565b810103126103c75750518038613798565b503d6137a8565b92955060019194965080846137e0829689613844565b019501910192879492879694613775565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561030657016020813591019167ffffffffffffffff821161030657606082023603831361030657565b64ffffffffff61388f604080936fffffffffffffffffffffffffffffffff61386b82612b5a565b16865267ffffffffffffffff61388360208301612c02565b16602087015201612ba9565b16910152565b9161398091926138a36141b3565b6001600160a01b0380911660a08501926138bc846131dd565b906138e160808801916fffffffffffffffffffffffffffffffff93846136ae85613182565b6139a16040519788957f21714be100000000000000000000000000000000000000000000000000000000875260209889988960048a01526101448901968361392886612b27565b1660248b015264ffffffffff61393f8c8701612ba9565b1660448b015261395160408601612b9c565b151560648b01526139756060978561396a8a8901612b27565b1660848d0152612b5a565b1660a48a0152612b27565b1660c487015261399660e4870160c08301613355565b6101008101906137f1565b809193610120610124880152526101648501929160005b8281106139e05750505050600083809203925af19081156106cb5760009161379e5750905090565b92955060019194965080846139f6829689613844565b0195019101928794928796946139b8565b91906001600160a01b039283821690604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701528116918260248701526020958681604481855afa80156106cb578691600091613b8b575b5010613a76575b505050505050565b60008060405196613ada88613acc8b8201937f095ea7b3000000000000000000000000000000000000000000000000000000009889865260248401602090939291936001600160a01b0360408201951681520152565b03601f1981018a5289612aee565b87519082855af190613aea61302e565b82613b58575b5081613b4d575b5015613b04575b80613a6e565b60405194850152602484015260006044840152604483526080830183811067ffffffffffffffff821117612a5657613b4393612efc9160405282612f1b565b3880808080613afe565b90503b151538613af7565b809192505190878215928315613b73575b5050509038613af0565b613b839350820181019101612f03565b388781613b69565b91508782813d8311613bb4575b613ba28183612aee565b810103126103c7575085905138613a67565b503d613b98565b9190811015612dfa5760051b0190565b919091613bd78361319f565b9260005b818110613be757505050565b6001600160a01b03613bfd61250d838587613bbb565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa918215613c8f5750600091613c5e575b5060019250613c57828861328a565b5201613bdb565b919282813d8311613c88575b613c748183612aee565b810103126103c75750906001915138613c48565b503d613c6a565b513d6000823e3d90fd5b6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481305afa9081156106cb57600091613cda575090565b6020813d8211613d10575b81613cf260209383612aee565b810103126103ca5751906001600160a01b03821682036103c7575090565b3d9150613ce5565b909160005b818110613d2a5750505050565b6001600160a01b03613d4061250d838588613bbb565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa918215613c8f5750600091613dc4575b5060019250613da8613dbe91613da1848861328a565b5190612e6b565b613db661250d84878a613bbb565b6102c1613c99565b01613d1d565b919282813d8311613df0575b613dda8183612aee565b810103126103c757505160019190613da8613d8b565b503d613dd0565b6001600160a01b031660409081517f70a08231000000000000000000000000000000000000000000000000000000008082526000903060048401526020908184602481885afa938415613f82578394613f53575b50843b156103375785517fd0e30db00000000000000000000000000000000000000000000000000000000081528381600481348a5af18015613f4957613f36575b508190602487518097819382523060048301525afa918215613f2b5791613efb575b50613eb99250612e6b565b90348203613ec5575050565b6044925051907fe5f762580000000000000000000000000000000000000000000000000000000082523460048301526024820152fd5b905082813d8311613f24575b613f118183612aee565b8101031261030657613eb9915138613eae565b503d613f07565b8551903d90823e3d90fd5b92613f42839294612aa2565b9290613e8c565b87513d86823e3d90fd5b9093508181813d8311613f7b575b613f6b8183612aee565b8101031261033757519238613e4b565b503d613f61565b86513d85823e3d90fd5b359065ffffffffffff8216820361030657565b939293613faa613c99565b946001600160a01b0393847f0000000000000000000000000000000000000000000000000000000000000000166000978860c08501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112156103ca5785019485359567ffffffffffffffff871161033757602001863603811361033757843b156103375789604051947f2b67b57000000000000000000000000000000000000000000000000000000000865216968760048601528a61406e84612b27565b16602486015260208301358b811680910361034657601f86949260a086948f601f1995604488015265ffffffffffff806140aa60408501613f8c565b1660648901526140bc60608401613f8c565b1660848801526140ce60808301612b27565b1660a4870152013560c485015261010060e485015280610104850152806101249586860137868582860101520116810103018183865af1801561070f5761419e575b50908188923b156103375786938360849260405196879586947f36c78516000000000000000000000000000000000000000000000000000000008652600486015230602486015216998a6044850152891660648401525af180156141935761417f575b50612f01939450613a07565b6141898691612aa2565b6103465784614173565b6040513d88823e3d90fd5b6141ab9098919298612aa2565b969038614110565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630146141e557565b60046040517fbbff6135000000000000000000000000000000000000000000000000000000008152fd000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

Deployed Bytecode

0x608080604052600436101561001357600080fd5b600090813560e01c90816310fad8c81461281b575080631d165efc1461268f57806339532c191461244057806351c9b6f1146123d957806361ea5802146120fe5780636a09d49a1461201a578063868699c514611e8d57806386f2891e14611e155780638922211914611dae5780638ad7937414611b7357806390e2cd79146119b657806398590ef9146117c15780639dc29fac14611746578063a3143b76146116cd578063a4af60d214611357578063ad26c0fb146112cc578063b956b45f14611206578063c00b86a514610f26578063c0cb6a4014610d51578063c426f89c14610b03578063ec5b900f14610954578063f1630612146107bf578063f65e5d66146103ce5763fe5cacde1461012957600080fd5b346103c75760031960a0813601126103ca57610143612a0e565b9160243591610150612a24565b906064359267ffffffffffffffff918285116103ca576101008186360301126103ca576084359283116103ca5760e09083360301126103c7576101916141b3565b6101996141b3565b6001600160a01b0380961690604051957feac8f5b80000000000000000000000000000000000000000000000000000000087528060048801526020978888602481875afa9788156103bc578398610384575b50871690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a86602481875afa95861561037957859661034a575b50813b156103465784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1801561033b578a9291859161031e575b505060246040518094819382523060048301525afa91821561031257916102dc575b50946102b86102c7926102d497612e6b565b906102c1613c99565b90612ea7565b6004019160040190613665565b604051908152f35b9590508686813d831161030b575b6102f48183612aee565b810103126103065794516102b86102a6565b600080fd5b503d6102ea565b604051903d90823e3d90fd5b61032a91929350612aa2565b6103375788908338610284565b8280fd5b6040513d86823e3d90fd5b8480fd5b9095508a81813d8311610372575b6103628183612aee565b8101031261030657519438610234565b503d610358565b6040513d87823e3d90fd5b9097508881813d83116103b5575b61039c8183612aee565b81010312610337575187811681036103375796386101eb565b503d610392565b6040513d85823e3d90fd5b80fd5b5080fd5b50346103c7576003196101c0813601126103ca576103ea612a0e565b906024908135926103f9612a24565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126107b7576101a4359267ffffffffffffffff84116107bb5760e09084360301126107b75761044c6141b3565b6104546141b3565b6001600160a01b03809216604051907feac8f5b800000000000000000000000000000000000000000000000000000000825286600483015260209687838881855afa92831561070f57899361077b575b508885841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528b868c81885afa95861561033b578496610748575b50813b156107445783918b839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578b9361071a575b5050886040518094819382523060048301525afa90811561070f578596979899916106d7575b5061057092916102b891612e6b565b6105786141b3565b169160c435828116918282036103065760a435916fffffffffffffffffffffffffffffffff831680930361030657826105b5926004019187613f9f565b604051947f4bc78b7300000000000000000000000000000000000000000000000000000000865260643584811680910361030657600487015260843590848216809203610306578601526044850152606484015260e4358015158091036103065760848401526101049081359064ffffffffff918281168091036103065760a48601526101249283358381168091036103065760c48701526101449283359081168091036103065760e4870152610164359182168092036103065786948694859360009385015261018435908401525af19081156106cb5760009161069e575b50604051908152f35b908282813d83116106c4575b6106b48183612aee565b810103126103c757505138610695565b503d6106aa565b6040513d6000823e3d90fd5b9450909190508784813d8111610708575b6106f28183612aee565b8101031261030657925184939190610570610561565b503d6106e8565b6040513d8b823e3d90fd5b61072691929350612aa2565b6107335788908a3861053b565b8980fd5b50604051903d90823e3d90fd5b8380fd5b8c809297508195503d8311610774575b6107628183612aee565b81010312610306578b925194386104ee565b503d610758565b9092508781813d83116107b0575b6107938183612aee565b810103126107ac575184811681036107ac5791386104a4565b8880fd5b503d610789565b8580fd5b8680fd5b50346103c75760406003193601126103c75767ffffffffffffffff600435818111610337576107f2903690600401612ca9565b91906024358281116103465761080c903690600401612ca9565b9290916108176141b3565b841561092a57856108288585613bcb565b92815b878110610841578261083e888888613d18565b80f35b61084c818986612dba565b356001600160a01b03811680910361074457610869828a87612dba565b60209081810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156107bb5701908135918583116107bb5701908060051b360382136107b757823b156107b7576108fa928692836040518096819582947f8659c27000000000000000000000000000000000000000000000000000000000845260048401612e29565b03925af190811561033b578491610916575b505060010161082b565b61091f90612aa2565b61033757823861090c565b60046040517f71594532000000000000000000000000000000000000000000000000000000008152fd5b50600319906040823601126103c75761096b612a0e565b916024359067ffffffffffffffff9081831161074457610100908336030112610337576040519061099b82612a3a565b6109a783600401612b27565b82526109b560248401612b9c565b94602095868401526109c960448501612b27565b60408401526109da60648501612b5a565b91606084019283526109ee60848601612b27565b9460808501958652610a033660a48301612bbb565b60a086015260e48101359182116107bb5701366023820112156107b75792610a88610abd93879693610a408a973690602460048201359101612c17565b60c0850152610a4d6141b3565b6fffffffffffffffffffffffffffffffff9081341683526001600160a01b038091610a7a82895116613df7565b169551169151169084613a07565b6040519485809481937fbf061d0a00000000000000000000000000000000000000000000000000000000835260048301613408565b03925af19182156103125791610ad65750604051908152f35b90508181813d8311610afc575b610aed8183612aee565b81010312610306575138610695565b503d610ae3565b50346103c75760031960a0813601126103ca57610b1e612a0e565b9160243591610b2b612a24565b906064359267ffffffffffffffff918285116103ca576101208186360301126103ca576084359283116103ca5760e09083360301126103c757610b6c6141b3565b610b746141b3565b6001600160a01b0380961690604051957feac8f5b80000000000000000000000000000000000000000000000000000000087528060048801526020978888602481875afa9788156103bc578398610d19575b50871690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a86602481875afa958615610379578596610cea575b50813b156103465784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1801561033b578a92918591610cd1575b505060246040518094819382523060048301525afa9182156103125791610ca0575b50946102b8610c93926102d497612e6b565b6004019160040190613895565b9590508686813d8311610cca575b610cb88183612aee565b810103126103065794516102b8610c81565b503d610cae565b610cdd91929350612aa2565b6103375788908338610c5f565b9095508a81813d8311610d12575b610d028183612aee565b8101031261030657519438610c0f565b503d610cf8565b9097508881813d8311610d4a575b610d318183612aee565b8101031261033757518781168103610337579638610bc6565b503d610d27565b50346103c75760031990610180823601126103c757610d6e612a0e565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c757610164359267ffffffffffffffff84116103ca5760e09084360301126103c75750610dc36141b3565b6001600160a01b03809116608435928284169081850361030657606435946fffffffffffffffffffffffffffffffff86168096036103065785610e0a926004019185613f9f565b604051937f4bc78b730000000000000000000000000000000000000000000000000000000085526024358481168091036103065760048601526044358481168091036103065760248601526044850152606484015260a43580151580910361030657608484015260c4359164ffffffffff928381168091036103065760a485015260e4358381168091036103065760c48501526101049283359081168091036103065760e485015261012490813590811680910361030657600085938492602096840152610144938435908401525af19081156106cb57600091610ef4575b602082604051908152f35b6020813d8211610f1e575b81610f0c60209383612aee565b810103126103ca575190506020610ee9565b3d9150610eff565b50346103c7576080600319818136011261033757610f42612a0e565b610f4a612b11565b916044359067ffffffffffffffff948583116107bb57366023840112156107bb57826004013591868311611202576024840193602436918560081b010111611202576064359687116112025760e09087360301126107bb57610faa6141b3565b811561092a5790939086805b8681106111bf5750610fd9906001600160a01b0380961697600401908489613f9f565b610fe28561319f565b9584889316925b8681106110025760405180610ffe8a82612d4b565b0390f35b60c0908682611012838b8a613172565b018960609481898b8789611027828685613172565b01611031906131d0565b9361103b92613172565b978c6020978861104c8b8985613172565b01611056906131dd565b918a611063818a84613172565b61106c906131dd565b9861107692613172565b60400161108290613182565b9181604051986110918a612a3a565b16885216888701526fffffffffffffffffffffffffffffffff1660408601528401521515888301528536037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160401361030657611123849361115c97604051906110fb82612ad2565b6111068c8201612ba9565b825261111560a0809201612ba9565b878301528501523690612bbb565b908201528c60405180809781947f1b4103a9000000000000000000000000000000000000000000000000000000008352600483016131f1565b0391885af19081156111b4578b91611185575b506001925061117e828b61328a565b5201610fe9565b905082813d83116111ad575b61119b8183612aee565b8101031261030657600191513861116f565b503d611191565b6040513d8d823e3d90fd5b906001600160a01b036001916fffffffffffffffffffffffffffffffff6111f560406111ef878d8c9e9b9e613172565b01613182565b1601169101959295610fb6565b8780fd5b50346103c75760806003193601126103c75780611221612a0e565b611229612a24565b611231612b3b565b9161123a6141b3565b6001600160a01b03809116803b15610346578492836064926fffffffffffffffffffffffffffffffff60405197889687957ffdd46d6000000000000000000000000000000000000000000000000000000000875260243560048801521660248601521660448401525af180156112c1576112b15750f35b6112ba90612aa2565b6103c75780f35b6040513d84823e3d90fd5b50346103c757806001600160a01b036112e436612d86565b9290916112ef6141b3565b1691823b15611352576040517fc156a11d00000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b031660248201529082908290818381604481015b03925af180156112c1576112b15750f35b505050fd5b50346103c7576003196101a0813601126103ca57611373612a0e565b602490813592611381612a24565b6101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126107b757610184359167ffffffffffffffff83116107bb5760e09083360301126107b7576113d46141b3565b6113dc6141b3565b6001600160a01b03809316604051907feac8f5b800000000000000000000000000000000000000000000000000000000825286600483015260209687838881855afa92831561070f578993611695575b508886841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528b868c81885afa95861561033b578496611662575b50813b156107445783918b839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578b93611649575b5050886040518094819382523060048301525afa90811561070f578697989996959691611611575b506114fa92916102b891612e6b565b6115026141b3565b169060c435838116918282036103065760a435916fffffffffffffffffffffffffffffffff8316809303610306578261153f926004019186613f9f565b604051947f1b4103a900000000000000000000000000000000000000000000000000000000865260643585811680910361030657600487015260843590858216809203610306578601526044850152606484015260e43580151580910361030657608484015264ffffffffff6101048035828116908190036103065760a48601526101249182359081168091036103065760c48601526101443593841680940361030657600085938492889660e485015261016435908401525af19081156106cb5760009161069e5750604051908152f35b9450909190508784813d8111611642575b61162c8183612aee565b81010312610306579251859391906114fa6114eb565b503d611622565b61165591929350612aa2565b6107335788908a386114c3565b8c809297508195503d831161168e575b61167c8183612aee565b81010312610306578b92519438611476565b503d611672565b9092508781813d83116116c6575b6116ad8183612aee565b810103126107ac575185811681036107ac57913861142c565b503d6116a3565b50346103c757806001600160a01b036116e536612d86565b9290916116f06141b3565b1691823b15611352576040517fea5ead1900000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03166024820152908290829081838160448101611341565b50346103c75760406003193601126103c757806001600160a01b03611769612a0e565b6117716141b3565b16803b156117be578180916024604051809481937f42966c68000000000000000000000000000000000000000000000000000000008352833560048401525af180156112c1576112b15750f35b50fd5b50346103c75760406003193601126103c7576117db612a0e565b6024356117e66141b3565b6001600160a01b0380921691604051917feac8f5b8000000000000000000000000000000000000000000000000000000008352806004840152846020928385602481895afa9485156112c157829561197e575b50841691604051957f70a0823100000000000000000000000000000000000000000000000000000000918288523060048901528588602481885afa97881561033b57849861194b575b50813b156107445783916024839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578593611932575b505060246040518094819382523060048301525afa918215610379578592611902575b505061083e926102b891612e6b565b90809250813d831161192b575b6119198183612aee565b810103126103065751826102b86118f3565b503d61190f565b61193e91929350612aa2565b6107b757829086386118d0565b86809299508195503d8311611977575b6119658183612aee565b81010312610306578792519638611882565b503d61195b565b9094508381813d83116119af575b6119968183612aee565b810103126103ca575184811681036103ca579338611839565b503d61198c565b506101406003193601126103c7576119cc612a0e565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c75760405191611a0583612a3a565b611a0d612b11565b8352611a17612a24565b9260209384820152611a27612b3b565b9060408101918252611a37612b77565b60608201908152611a46612b8d565b608083015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c36011261030657604051611a8181612ad2565b64ffffffffff60c435818116810361030657825260e4359081168103610306578782015260a083015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc3601126103065760405191611ae183612ad2565b610104356001600160a01b03948582168203610306578796899686611b3e94610abd9852610124358982015260c0860152611b1a6141b3565b806fffffffffffffffffffffffffffffffff928334168552610a7a82895116613df7565b6040519485809481937f1b4103a9000000000000000000000000000000000000000000000000000000008352600483016131f1565b50346103c757611b8236612cda565b611b8e949193946141b3565b831561092a578591865b858110611d775750906001600160a01b03611bb69216928684613f9f565b611bbf8361319f565b93855b848110611bd75760405180610ffe8882612d4b565b60809081611be6828888613374565b018587611bf4848284613374565b602001611c00906131d0565b92611c0c858385613374565b604001611c18906131dd565b9585611c25818587613374565b958160c097888101611c36916133b4565b96611c42929198613374565b611c4b906131dd565b988d8d6060948592611c5c92613374565b01611c6690613182565b916040519a611c748c612a3a565b6001600160a01b03168b52151560208b01526001600160a01b031660408a01526fffffffffffffffffffffffffffffffff16908801526001600160a01b0388169087015236611cc291612bbb565b60a08601523690611cd292612c17565b90830152836040518080947fbf061d0a0000000000000000000000000000000000000000000000000000000082526004820190611d0e91613408565b03818b5a94602095f18015611d6c578890611d39575b60019250611d32828961328a565b5201611bc2565b506020823d602011611d64575b81611d5360209383612aee565b810103126103065760019151611d24565b3d9150611d46565b6040513d8a823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff611da460606111ef898c8c613374565b1601169301611b98565b50346103c7576003196060813601126103ca57611dc9612a0e565b906024359267ffffffffffffffff918285116103ca576101008186360301126103ca576044359283116103ca5760e09083360301126103c75760206102d4600480850190870186613665565b50346103c75760406003193601126103c757806001600160a01b03611e38612a0e565b611e406141b3565b16803b156117be578180916024604051809481937f7de6b1db000000000000000000000000000000000000000000000000000000008352833560048401525af180156112c1576112b15750f35b50346103c75760031990610160823601126103c757611eaa612a0e565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c757610144359267ffffffffffffffff84116103ca5760e09084360301126103c75750611eff6141b3565b6001600160a01b0380911690608435928184169081850361030657606435946fffffffffffffffffffffffffffffffff86168096036103065785611f47926004019186613f9f565b604051937f1b4103a90000000000000000000000000000000000000000000000000000000085526024358381168091036103065760048601526044358381168091036103065760248601526044850152606484015260a43580151580910361030657608484015260c43564ffffffffff908181168091036103065760a485015260e4359081168091036103065760c4840152610104803591821680920361030657836000602094829460e4840152610124938435908401525af19081156106cb57600091610ef457602082604051908152f35b50346103c75760606003193601126103c757612034612a0e565b9067ffffffffffffffff60243581811161033757612056903690600401612ca9565b916044359081116107445761206f903690600401612ca9565b906120786141b3565b6001600160a01b0361208a8585613bcb565b961690813b156107b7579185916120d193836040518096819582947f8659c27000000000000000000000000000000000000000000000000000000000845260048401612e29565b03925af1801561033b576120eb575b5061083e9293613d18565b926120f861083e94612aa2565b926120e0565b50346103c7576080906003199082823601126103c75761211c612a0e565b90612125612b11565b916044359367ffffffffffffffff91828611610744573660238701121561074457856004013591838311610346576024870196602436916101208602010111610346576064359384116103465760e0908436030112610744576121866141b3565b811561092a5793959383805b83811061239c57506121b5906001600160a01b0380931694600401908986613f9f565b6121be8261319f565b9581859816975b8381106121da5760405180610ffe8a82612d4b565b88816121e781878661329e565b60e001606090816121f9848a8961329e565b01612203906131d0565b9161220f848a8961329e565b926020958a8a818b898b61222482858561329e565b0161222e906131dd565b946122389261329e565b612241906131dd565b9861224c918d61329e565b60400161225890613182565b9181604051996122678b612a3a565b16895216888801526fffffffffffffffffffffffffffffffff1660408701528286015215158c8501528236037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001126107335791839161230b612342948d6122dc604051916122d583612ab6565b8501612ba9565b815260a06122eb818601612ba9565b878301526122fc60c0809601612ba9565b60408301528501523690612bbb565b90820152604051809381927f4bc78b73000000000000000000000000000000000000000000000000000000008352600483016132af565b03818b8b5af1918215611d6c57889261236d575b505090600191612366828b61328a565b52016121c5565b90809250813d8311612395575b6123848183612aee565b810103126107bb5751600138612356565b503d61237a565b906001600160a01b036001916fffffffffffffffffffffffffffffffff6123cc60406111ef879c9e9c8a8f61329e565b1601169101979597612192565b50346103c7576003196060813601126103ca576123f4612a0e565b906024359267ffffffffffffffff918285116103ca576101208186360301126103ca576044359283116103ca5760e09083360301126103c75760206102d4600480850190870186613895565b50346103c75761244f36612cda565b61245c94919293946141b3565b821561092a5785865b84811061265857509061248291866001600160a01b038516613f9f565b61248b8261319f565b93855b8381106124a35760405180610ffe8882612d4b565b60a06124b082868861350e565b01906124c860406124c283888a61350e565b016131d0565b866124df60606124d9858a8561350e565b016131dd565b916124f86124ee858a8561350e565b60e08101906133b4565b6020612518878c61251261250d83838b61350e565b6131dd565b9761350e565b01359464ffffffffff86168603612654576125f0976fffffffffffffffffffffffffffffffff61257b966001600160a01b038f948f9864ffffffffff60209c848f60806111ef6125b89f92612570936125ac9e61350e565b966040519e8f612a85565b168d52168c8c0152151560408b01521660608901521660808701526001600160a01b038a1660a08701523690612bbb565b60c08501523691612c17565b60e0820152604051809481927f21714be10000000000000000000000000000000000000000000000000000000083526004830161354e565b03818b6001600160a01b0389165af18015611d6c578890612621575b6001925061261a828961328a565b520161248e565b506020823d60201161264c575b8161263b60209383612aee565b81010312611202576001915161260c565b3d915061262e565b8d80fd5b906001600160a01b036001916fffffffffffffffffffffffffffffffff61268560806111ef878b8d61350e565b1601169101612465565b50600319906040823601126103c7576126a6612a0e565b916024359067ffffffffffffffff908183116107445761012090833603011261033757604051906126d682612a85565b6126e283600401612b27565b82526126f060248401612ba9565b946020958684015261270460448501612b9c565b604084015261271560648501612b27565b606084015261272660848501612b5a565b916080840192835261273a60a48601612b27565b9460a0850195865261274f3660c48301612bbb565b60c08601526101048101359182116107bb5701366023820112156107b7579261279a6127cf9387969361278d8a973690602460048201359101612c17565b60e0850152610a4d6141b3565b6040519485809481937f21714be10000000000000000000000000000000000000000000000000000000083526004830161354e565b03925af19182156103125780926127eb575b5050604051908152f35b9091508282813d8311612814575b6128038183612aee565b810103126103c757505138806127e1565b503d6127f9565b826101606003193601126103c757612831612a0e565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103ca5761286583612a3a565b61286d612b11565b8352612877612a24565b9260209384820152612887612b3b565b60408201908152612896612b77565b92606083019384526128a6612b8d565b608084015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c360112610346576040516128e181612ab6565b64ffffffffff60c435818116810361120257825260e435818116810361120257888301526101043590811681036107bb57604082015260a084015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc3601126103465760405161295281612ad2565b6001600160a01b03906101243582811681036112025793879693899693836129c39761298e9552610144358982015260c0860152611b1a6141b3565b6040519485809481937f4bc78b73000000000000000000000000000000000000000000000000000000008352600483016132af565b03925af19182156103125780926129de575050604051908152f35b9091508282813d8311612a07575b6129f68183612aee565b810103126103c757505182806127e1565b503d6129ec565b600435906001600160a01b038216820361030657565b604435906001600160a01b038216820361030657565b60e0810190811067ffffffffffffffff821117612a5657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610100810190811067ffffffffffffffff821117612a5657604052565b67ffffffffffffffff8111612a5657604052565b6060810190811067ffffffffffffffff821117612a5657604052565b6040810190811067ffffffffffffffff821117612a5657604052565b90601f601f19910116810190811067ffffffffffffffff821117612a5657604052565b602435906001600160a01b038216820361030657565b35906001600160a01b038216820361030657565b606435906fffffffffffffffffffffffffffffffff8216820361030657565b35906fffffffffffffffffffffffffffffffff8216820361030657565b608435906001600160a01b038216820361030657565b60a43590811515820361030657565b3590811515820361030657565b359064ffffffffff8216820361030657565b919082604091031261030657604051612bd381612ad2565b6020808294612be181612b27565b84520135910152565b67ffffffffffffffff8111612a565760051b60200190565b359067ffffffffffffffff8216820361030657565b929192612c2382612bea565b604094612c3286519283612aee565b8195848352602080930191606080960285019481861161030657925b858410612c5e5750505050505050565b8684830312610306578487918451612c7581612ab6565b612c7e87612b5a565b8152612c8b838801612c02565b83820152612c9a868801612ba9565b86820152815201930192612c4e565b9181601f840112156103065782359167ffffffffffffffff8311610306576020808501948460051b01011161030657565b9060031991608083820112610306576001600160a01b0392600435848116810361030657936024359081168103610306579267ffffffffffffffff6044358181116103065784612d2c91600401612ca9565b94909493606435928311610306578260e0920301126103065760040190565b6020908160408183019282815285518094520193019160005b828110612d72575050505090565b835185529381019392810192600101612d64565b6003196060910112610306576001600160a01b03600435818116810361030657916024359160443590811681036103065790565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610306570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081528260208201527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103065760409260051b809284830137010190565b91908203918211612e7857565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152612f0191612efc606483612aee565b612f1b565b565b90816020910312610306575180151581036103065790565b604051612f79916001600160a01b0316612f3482612ad2565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1612f7361302e565b9161306e565b805190828215928315613016575b50505015612f925750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6130269350820181019101612f03565b388281612f87565b3d15613069573d9067ffffffffffffffff8211612a56576040519161305d6020601f19601f8401160184612aee565b82523d6000602084013e565b606090565b919290156130e95750815115613082575090565b3b1561308b5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156130fc5750805190602001fd5b604051907f08c379a000000000000000000000000000000000000000000000000000000000825281602080600483015282519283602484015260005b84811061315b57505050601f19601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201613138565b9190811015612dfa5760081b0190565b356fffffffffffffffffffffffffffffffff811681036103065790565b906131a982612bea565b6131b66040519182612aee565b828152601f196131c68294612bea565b0190602036910137565b3580151581036103065790565b356001600160a01b03811681036103065790565b612f019092919260e060c06101208301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151602064ffffffffff918281511660a0880152015116828501520151910190602080916001600160a01b0381511684520151910152565b8051821015612dfa5760209160051b010190565b9190811015612dfa57610120020190565b612f019092919261010060c06101408301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151604064ffffffffff918281511660a0880152826020820151168588015201511660e08501520151910190602080916001600160a01b0381511684520151910152565b602080916001600160a01b0361336a82612b27565b1684520135910152565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2181360301821215610306570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610306570180359067ffffffffffffffff82116103065760200191606082023603831361030657565b9060208083526101208301908061014060c06001600160a01b0395868151168489015283810151151560408901528660408201511696606097888a01526fffffffffffffffffffffffffffffffff888301511660808a015260808201511660a089015261348f60a0820151838a0190602080916001600160a01b0381511684520151910152565b015195610100808201528651809552019401926000905b8382106134b557505050505090565b90919293948382826135016001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01960194939201906134a6565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0181360301821215610306570190565b9060208083526101408301908061016060e06001600160a01b0395868151168489015264ffffffffff848201511660408901526040810151151596606097888a015280888301511660808a01526fffffffffffffffffffffffffffffffff60808301511660a08a015260a08201511660c08901526135e660c0820151838a0190602080916001600160a01b0381511684520151910152565b015195610120808201528651809552019401926000905b83821061360c57505050505090565b90919293948382826136586001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01960194939201906135fd565b909161366f6141b3565b60808301916001600160a01b03908116613688846131dd565b9260606136b6818801926fffffffffffffffffffffffffffffffff96876136ae86613182565b169086613f9f565b61375e6040519788957fbf061d0a00000000000000000000000000000000000000000000000000000000875261373e6020998a998a60048b01526137336101248b01988561370388612b27565b1660248d01526137148d8801612b9c565b151560448d01528561372860408901612b27565b1660648d0152612b5a565b1660848a0152612b27565b1660a487015261375460c4870160a08301613355565b60e08101906137f1565b809193610100610104880152526101448501929160005b8281106137ca5750505050600083809203925af19081156106cb5760009161379e575b50905090565b82813d83116137c3575b6137b28183612aee565b810103126103c75750518038613798565b503d6137a8565b92955060019194965080846137e0829689613844565b019501910192879492879694613775565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561030657016020813591019167ffffffffffffffff821161030657606082023603831361030657565b64ffffffffff61388f604080936fffffffffffffffffffffffffffffffff61386b82612b5a565b16865267ffffffffffffffff61388360208301612c02565b16602087015201612ba9565b16910152565b9161398091926138a36141b3565b6001600160a01b0380911660a08501926138bc846131dd565b906138e160808801916fffffffffffffffffffffffffffffffff93846136ae85613182565b6139a16040519788957f21714be100000000000000000000000000000000000000000000000000000000875260209889988960048a01526101448901968361392886612b27565b1660248b015264ffffffffff61393f8c8701612ba9565b1660448b015261395160408601612b9c565b151560648b01526139756060978561396a8a8901612b27565b1660848d0152612b5a565b1660a48a0152612b27565b1660c487015261399660e4870160c08301613355565b6101008101906137f1565b809193610120610124880152526101648501929160005b8281106139e05750505050600083809203925af19081156106cb5760009161379e5750905090565b92955060019194965080846139f6829689613844565b0195019101928794928796946139b8565b91906001600160a01b039283821690604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701528116918260248701526020958681604481855afa80156106cb578691600091613b8b575b5010613a76575b505050505050565b60008060405196613ada88613acc8b8201937f095ea7b3000000000000000000000000000000000000000000000000000000009889865260248401602090939291936001600160a01b0360408201951681520152565b03601f1981018a5289612aee565b87519082855af190613aea61302e565b82613b58575b5081613b4d575b5015613b04575b80613a6e565b60405194850152602484015260006044840152604483526080830183811067ffffffffffffffff821117612a5657613b4393612efc9160405282612f1b565b3880808080613afe565b90503b151538613af7565b809192505190878215928315613b73575b5050509038613af0565b613b839350820181019101612f03565b388781613b69565b91508782813d8311613bb4575b613ba28183612aee565b810103126103c7575085905138613a67565b503d613b98565b9190811015612dfa5760051b0190565b919091613bd78361319f565b9260005b818110613be757505050565b6001600160a01b03613bfd61250d838587613bbb565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa918215613c8f5750600091613c5e575b5060019250613c57828861328a565b5201613bdb565b919282813d8311613c88575b613c748183612aee565b810103126103c75750906001915138613c48565b503d613c6a565b513d6000823e3d90fd5b6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481305afa9081156106cb57600091613cda575090565b6020813d8211613d10575b81613cf260209383612aee565b810103126103ca5751906001600160a01b03821682036103c7575090565b3d9150613ce5565b909160005b818110613d2a5750505050565b6001600160a01b03613d4061250d838588613bbb565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa918215613c8f5750600091613dc4575b5060019250613da8613dbe91613da1848861328a565b5190612e6b565b613db661250d84878a613bbb565b6102c1613c99565b01613d1d565b919282813d8311613df0575b613dda8183612aee565b810103126103c757505160019190613da8613d8b565b503d613dd0565b6001600160a01b031660409081517f70a08231000000000000000000000000000000000000000000000000000000008082526000903060048401526020908184602481885afa938415613f82578394613f53575b50843b156103375785517fd0e30db00000000000000000000000000000000000000000000000000000000081528381600481348a5af18015613f4957613f36575b508190602487518097819382523060048301525afa918215613f2b5791613efb575b50613eb99250612e6b565b90348203613ec5575050565b6044925051907fe5f762580000000000000000000000000000000000000000000000000000000082523460048301526024820152fd5b905082813d8311613f24575b613f118183612aee565b8101031261030657613eb9915138613eae565b503d613f07565b8551903d90823e3d90fd5b92613f42839294612aa2565b9290613e8c565b87513d86823e3d90fd5b9093508181813d8311613f7b575b613f6b8183612aee565b8101031261033757519238613e4b565b503d613f61565b86513d85823e3d90fd5b359065ffffffffffff8216820361030657565b939293613faa613c99565b946001600160a01b0393847f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3166000978860c08501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112156103ca5785019485359567ffffffffffffffff871161033757602001863603811361033757843b156103375789604051947f2b67b57000000000000000000000000000000000000000000000000000000000865216968760048601528a61406e84612b27565b16602486015260208301358b811680910361034657601f86949260a086948f601f1995604488015265ffffffffffff806140aa60408501613f8c565b1660648901526140bc60608401613f8c565b1660848801526140ce60808301612b27565b1660a4870152013560c485015261010060e485015280610104850152806101249586860137868582860101520116810103018183865af1801561070f5761419e575b50908188923b156103375786938360849260405196879586947f36c78516000000000000000000000000000000000000000000000000000000008652600486015230602486015216998a6044850152891660648401525af180156141935761417f575b50612f01939450613a07565b6141898691612aa2565b6103465784614173565b6040513d88823e3d90fd5b6141ab9098919298612aa2565b969038614110565b6001600160a01b037f000000000000000000000000194ed7d6005c8ba4084a948406545df299ad37cd1630146141e557565b60046040517fbbff6135000000000000000000000000000000000000000000000000000000008152fd

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

-----Decoded View---------------
Arg [0] : permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.