Source Code
Overview
xDAI Balance
xDAI Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 30885244 | 737 days ago | Contract Creation | 0 xDAI |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SablierV2ProxyTargetApprove
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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 { SablierV2ProxyTarget } from "./abstracts/SablierV2ProxyTarget.sol";
/// @title SablierV2ProxyTargetApprove
/// @notice Proxy target contract that implements the transfer logic using standard ERC-20 approvals.
contract SablierV2ProxyTargetApprove is SablierV2ProxyTarget {
using SafeERC20 for IERC20;
/// @notice Transfers the given `amount` of `asset` to the Sablier contract using standard the ERC-20
/// approve and transfer flow, and then approves Sablier to spend the funds.
/// @dev The `transferData` data is ignored in this implementation.
function _handleTransfer(
address sablierContract,
IERC20 asset,
uint160 amount,
bytes calldata /* transferData */
)
internal
override
{
// Retrieve the proxy owner.
address owner = _getOwner();
// Transfer funds from the proxy owner to the proxy.
asset.safeTransferFrom({ from: owner, to: address(this), value: amount });
// 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: 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/src/interfaces/IPRBProxy.sol";
import { ISablierV2Lockup } from "@sablier/v2-core/src/interfaces/ISablierV2Lockup.sol";
import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2LockupDynamic } from "@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol";
import { LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol";
import { OnlyDelegateCall } from "./OnlyDelegateCall.sol";
import { ISablierV2ProxyTarget } from "../interfaces/ISablierV2ProxyTarget.sol";
import { IWrappedNativeAsset } from "../interfaces/IWrappedNativeAsset.sol";
import { Errors } from "../libraries/Errors.sol";
import { Batch } from "../types/DataTypes.sol";
/*
███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗
██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗
███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝
╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝
███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗
╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝
██████╗ ██████╗ ██████╗ ██╗ ██╗██╗ ██╗ ████████╗ █████╗ ██████╗ ██████╗ ███████╗████████╗
██╔══██╗██╔══██╗██╔═══██╗╚██╗██╔╝╚██╗ ██╔╝ ╚══██╔══╝██╔══██╗██╔══██╗██╔════╝ ██╔════╝╚══██╔══╝
██████╔╝██████╔╝██║ ██║ ╚███╔╝ ╚████╔╝ ██║ ███████║██████╔╝██║ ███╗█████╗ ██║
██╔═══╝ ██╔══██╗██║ ██║ ██╔██╗ ╚██╔╝ ██║ ██╔══██║██╔══██╗██║ ██║██╔══╝ ██║
██║ ██║ ██║╚██████╔╝██╔╝ ██╗ ██║ ██║ ██║ ██║██║ ██║╚██████╔╝███████╗ ██║
╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝
*/
/// @title SablierV2ProxyTarget
/// @notice See the documentation in {ISablierV2ProxyTarget}.
abstract contract SablierV2ProxyTarget is
ISablierV2ProxyTarget, // 0 inherited components
OnlyDelegateCall // 0 inherited components
{
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////////////////
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);
}
/// @inheritdoc ISablierV2ProxyTarget
function withdrawMultiple(
ISablierV2Lockup lockup,
uint256[] calldata streamIds,
address to,
uint128[] calldata amounts
)
external
onlyDelegateCall
{
lockup.withdrawMultiple(streamIds, to, amounts);
}
/*//////////////////////////////////////////////////////////////////////////
SABLIER-V2-LOCKUP-LINEAR
//////////////////////////////////////////////////////////////////////////*/
/// @inheritdoc ISablierV2ProxyTarget
function batchCreateWithDurations(
ISablierV2LockupLinear lockupLinear,
IERC20 asset,
Batch.CreateWithDurations[] calldata batch,
bytes calldata transferData
)
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 approves the Sablier contract to spend them.
_handleTransfer(address(lockupLinear), asset, transferAmount, transferData);
// 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,
bytes calldata transferData
)
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.
_handleTransfer(address(lockupLinear), asset, transferAmount, transferData);
// 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,
bytes calldata transferData
)
external
override
onlyDelegateCall
returns (uint256 newStreamId)
{
cancel(lockup, streamId);
newStreamId = createWithDurations(lockupLinear, createParams, transferData);
}
/// @inheritdoc ISablierV2ProxyTarget
function cancelAndCreateWithRange(
ISablierV2Lockup lockup,
uint256 streamId,
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithRange calldata createParams,
bytes calldata transferData
)
external
override
onlyDelegateCall
returns (uint256 newStreamId)
{
cancel(lockup, streamId);
newStreamId = createWithRange(lockupLinear, createParams, transferData);
}
/// @inheritdoc ISablierV2ProxyTarget
function createWithDurations(
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithDurations calldata createParams,
bytes calldata transferData
)
public
override
onlyDelegateCall
returns (uint256 streamId)
{
_handleTransfer(address(lockupLinear), createParams.asset, createParams.totalAmount, transferData);
streamId = lockupLinear.createWithDurations(createParams);
}
/// @inheritdoc ISablierV2ProxyTarget
function createWithRange(
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithRange calldata createParams,
bytes calldata transferData
)
public
override
onlyDelegateCall
returns (uint256 streamId)
{
_handleTransfer(address(lockupLinear), createParams.asset, createParams.totalAmount, transferData);
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,
bytes calldata transferData
)
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.
_handleTransfer(address(dynamic), asset, transferAmount, transferData);
// 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,
bytes calldata transferData
)
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.
_handleTransfer(address(dynamic), asset, transferAmount, transferData);
// 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,
bytes calldata transferData
)
external
override
onlyDelegateCall
returns (uint256 newStreamId)
{
cancel(lockup, streamId);
newStreamId = createWithDeltas(dynamic, createParams, transferData);
}
/// @inheritdoc ISablierV2ProxyTarget
function cancelAndCreateWithMilestones(
ISablierV2Lockup lockup,
uint256 streamId,
ISablierV2LockupDynamic dynamic,
LockupDynamic.CreateWithMilestones calldata createParams,
bytes calldata transferData
)
external
override
onlyDelegateCall
returns (uint256 newStreamId)
{
cancel(lockup, streamId);
newStreamId = createWithMilestones(dynamic, createParams, transferData);
}
/// @inheritdoc ISablierV2ProxyTarget
function createWithDeltas(
ISablierV2LockupDynamic dynamic,
LockupDynamic.CreateWithDeltas calldata createParams,
bytes calldata transferData
)
public
override
onlyDelegateCall
returns (uint256 streamId)
{
_handleTransfer(address(dynamic), createParams.asset, createParams.totalAmount, transferData);
streamId = dynamic.createWithDeltas(createParams);
}
/// @inheritdoc ISablierV2ProxyTarget
function createWithMilestones(
ISablierV2LockupDynamic dynamic,
LockupDynamic.CreateWithMilestones calldata createParams,
bytes calldata transferData
)
public
override
onlyDelegateCall
returns (uint256 streamId)
{
_handleTransfer(address(dynamic), createParams.asset, createParams.totalAmount, transferData);
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 Handler function meant to be inherited by child contracts that implement the transfer logic. This function
/// may also approve the Sablier contract to spend to spend funds from the proxy if the allowance is insufficient.
function _handleTransfer(
address sablierContract,
IERC20 asset,
uint160 amount,
bytes calldata transferData
)
internal
virtual;
/// @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 });
}
}
}// 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);
}
}
}// 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 a target contract reverts without a specified reason.
error PRBProxy_ExecutionReverted();
/// @notice Thrown when an unauthorized account tries to execute a delegate call.
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);
/*//////////////////////////////////////////////////////////////////////////
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, if any.
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/src/UD2x18.sol";
import { UD60x18 } from "@prb/math/src/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: 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/src/interfaces/ISablierV2Lockup.sol";
import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2LockupDynamic } from "@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol";
import { LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol";
import { Batch } 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 only the 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 Notes:
/// - All refunded assets are forwarded to the proxy owner.
///
/// Requirements:
/// - 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 only the 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;
/// @notice Mirror for {ISablierV2Lockup.withdrawMultiple}.
/// @dev Must be delegate called.
function withdrawMultiple(
ISablierV2Lockup lockup,
uint256[] calldata streamIds,
address to,
uint128[] calldata amounts
)
external;
/*//////////////////////////////////////////////////////////////////////////
SABLIER-V2-LOCKUP-LINEAR
//////////////////////////////////////////////////////////////////////////*/
/// @notice Creates a batch of Lockup Linear streams using `createWithDurations`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamIds The ids of the newly created streams.
function batchCreateWithDurations(
ISablierV2LockupLinear lockupLinear,
IERC20 asset,
Batch.CreateWithDurations[] calldata batch,
bytes calldata transferData
)
external
returns (uint256[] memory streamIds);
/// @notice Creates a batch of Lockup Linear streams using `createWithRange`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamIds The ids of the newly created streams.
function batchCreateWithRange(
ISablierV2LockupLinear lockupLinear,
IERC20 asset,
Batch.CreateWithRange[] calldata batch,
bytes calldata transferData
)
external
returns (uint256[] memory streamIds);
/// @notice Cancels a Lockup stream and creates a new Lockup Linear stream using `createWithDurations`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return newStreamId The id of the newly created stream.
function cancelAndCreateWithDurations(
ISablierV2Lockup lockup,
uint256 streamId,
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithDurations calldata createParams,
bytes calldata transferData
)
external
returns (uint256 newStreamId);
/// @notice Cancels a Lockup stream and creates a new Lockup Linear stream using `createWithRange`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return newStreamId The id of the newly created stream.
function cancelAndCreateWithRange(
ISablierV2Lockup lockup,
uint256 streamId,
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithRange calldata createParams,
bytes calldata transferData
)
external
returns (uint256 newStreamId);
/// @notice Mirror for {SablierV2LockupLinear.createWithDurations}.
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamId The id of the newly created stream.
function createWithDurations(
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithDurations calldata createParams,
bytes calldata transferData
)
external
returns (uint256 streamId);
/// @notice Mirror for {SablierV2LockupLinear.createWithRange}.
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamId The id of the newly created stream.
function createWithRange(
ISablierV2LockupLinear lockupLinear,
LockupLinear.CreateWithRange calldata createParams,
bytes calldata transferData
)
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`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamIds The ids of the newly created streams.
function batchCreateWithDeltas(
ISablierV2LockupDynamic lockupDynamic,
IERC20 asset,
Batch.CreateWithDeltas[] calldata batch,
bytes calldata transferData
)
external
returns (uint256[] memory streamIds);
/// @notice Creates a batch of Lockup Dynamic streams using `createWithMilestones`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamIds The ids of the newly created streams.
function batchCreateWithMilestones(
ISablierV2LockupDynamic lockupDynamic,
IERC20 asset,
Batch.CreateWithMilestones[] calldata batch,
bytes calldata transferData
)
external
returns (uint256[] memory streamIds);
/// @notice Cancels a Lockup stream and creates a new Lockup Dynamic stream using `createWithDeltas`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return newStreamId The id of the newly created stream.
function cancelAndCreateWithDeltas(
ISablierV2Lockup lockup,
uint256 streamId,
ISablierV2LockupDynamic lockupDynamic,
LockupDynamic.CreateWithDeltas calldata createParams,
bytes calldata transferData
)
external
returns (uint256 newStreamId);
/// @notice Cancels a Lockup stream and creates a new Lockup Dynamic stream using `createWithMilestones`.
///
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return newStreamId The id of the newly created stream.
function cancelAndCreateWithMilestones(
ISablierV2Lockup lockup,
uint256 streamId,
ISablierV2LockupDynamic lockupDynamic,
LockupDynamic.CreateWithMilestones calldata createParams,
bytes calldata transferData
)
external
returns (uint256 newStreamId);
/// @notice Mirror for {SablierV2LockupDynamic.createWithDeltas}.
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamId The id of the newly created stream.
function createWithDeltas(
ISablierV2LockupDynamic lockupDynamic,
LockupDynamic.CreateWithDeltas calldata createParams,
bytes calldata transferData
)
external
returns (uint256 streamId);
/// @notice Mirror for {SablierV2LockupDynamic.createWithMilestones}.
/// @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 transferData Bytes used for additional information, specific to the implementation, it may contain the
/// parameters needed for Permit2 in one implementation and may be ignored in another.
/// @return streamId The id of the newly created stream.
function createWithMilestones(
ISablierV2LockupDynamic lockupDynamic,
LockupDynamic.CreateWithMilestones calldata createParams,
bytes calldata transferData
)
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;
}// 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-BATCH
//////////////////////////////////////////////////////////////////////////*/
error SablierV2Batch_BatchSizeZero();
/*//////////////////////////////////////////////////////////////////////////
SABLIER-V2-MERKLE-STREAMER
//////////////////////////////////////////////////////////////////////////*/
/// @notice Thrown when trying to claim the same stream more than once.
error SablierV2MerkleStreamer_StreamClaimed(uint256 index);
/// @notice Thrown when trying to claim after the campaign has expired.
error SablierV2MerkleStreamer_CampaignExpired(uint256 currentTime, uint40 expiration);
/// @notice Thrown when trying to claim when Merkle streamer has not expired.
error SablierV2MerkleStreamer_CampaignNotExpired(uint256 currentTime, uint40 expiration);
/// @notice Thrown when trying to claim with an invalid Merkle proof.
error SablierV2MerkleStreamer_InvalidProof();
/*//////////////////////////////////////////////////////////////////////////
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);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19;
import { ISablierV2Lockup } from "@sablier/v2-core/src/interfaces/ISablierV2Lockup.sol";
import { Broker, LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.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;
}
}// 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 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);
/// @notice Thrown when a function requires the user to have a proxy.
error PRBProxyRegistry_UserDoesNotHaveProxy(address user);
/// @notice Thrown when a function requires the user to not have a proxy.
error PRBProxyRegistry_UserHasProxy(address user, IPRBProxy proxy);
/*//////////////////////////////////////////////////////////////////////////
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's permission is updated.
event SetPermission(
address indexed owner, IPRBProxy indexed proxy, address indexed envoy, address target, bool newPermission
);
/// @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 call data to be passed 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 checked for 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 checked for 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 selector 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 selector for the query.
function getPluginByProxy(IPRBProxy proxy, bytes4 method) external view returns (IPRBProxyPlugin plugin);
/// @notice Retrieves the proxy for the provided user.
/// @param user The user address for the query.
function getProxy(address user) 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 {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}, {Execute}, and {InstallPlugin} event.
///
/// Requirements:
/// - The caller must not have a proxy.
/// - See the requirements in `installPlugin`.
/// - See the requirements in `execute`.
///
/// @param target The address of the target.
/// @param data Function selector plus ABI-encoded data.
/// @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 {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 user.
///
/// @dev Emits a {DeployProxy} event.
///
/// Requirements:
/// - The user must not have a proxy already.
///
/// @param user The address that will own the proxy.
/// @return proxy The address of the newly deployed proxy.
function deployFor(address user) 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 selectors as {IPRBProxy.execute}, {IPRBProxy.owner}, and
/// {IPRBProxy.registry} 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 plugin installed by the caller.
///
/// @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 the caller is giving or taking permission from.
/// @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/src/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);
}// 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";
// 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
// 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/src/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;
}// 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);
}// 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);// 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);// 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;// 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);
}// 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);// 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);
}
}// 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);// 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());
}// 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));
}
}// 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);
}// 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;
}
}
}// 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;// 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;// 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;// 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);// 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);
}// 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);
}// 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());
}// 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));
}
}// 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);// 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);{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@prb/proxy/=lib/prb-proxy/",
"@prb/proxy-test/=lib/prb-proxy/test/",
"@prb/test/=lib/prb-test/src/",
"@sablier/v2-core/=lib/v2-core/",
"@sablier/v2-core-script/=lib/v2-core/script/",
"@sablier/v2-core-test/=lib/v2-core/test/",
"@uniswap/permit2/=lib/permit2/src/",
"@uniswap/permit2-test/=lib/permit2/test/",
"murky/=lib/murky/src/",
"forge-std/=lib/forge-std/src/",
"solady/=lib/solady/src/",
"@prb/math/=lib/v2-core/lib/prb-math/",
"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/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/",
"permit2/=lib/permit2/",
"prb-math/=lib/v2-core/lib/prb-math/src/",
"prb-proxy/=lib/prb-proxy/",
"prb-test/=lib/prb-test/src/",
"solarray/=lib/v2-core/lib/solarray/src/",
"solmate/=lib/permit2/lib/solmate/",
"v2-core/=lib/v2-core/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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[]"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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[]"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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[]"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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[]"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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"},{"internalType":"bytes","name":"transferData","type":"bytes"}],"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 ISablierV2Lockup","name":"lockup","type":"address"},{"internalType":"uint256[]","name":"streamIds","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"}],"name":"withdrawMultiple","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"}]Contract Creation Code
60a0806040523461002357306080526144a090816100298239608051816132470152f35b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c80630cbbef7f14612bab57806310fad8c8146129b257806313b55f011461294a57806314296d161461258b5780631d165efc1461244b57806345188c01146121165780634c4bfa7714611ec85780636a09d49a14611ddb5780636a9c21b714611b205780636f0995f31461188b578063825976161461169957806386f2891e1461162157806387d23ff1146111fa5780638e80029914610fa157806390e2cd7914610de457806398590ef914610bc85780639dc29fac14610b4d578063a3143b7614610ad4578063aa02171414610a64578063ad26c0fb146109d9578063b956b45f1461092e578063e6a64e02146105fe578063ec5b900f14610439578063f16306121461028a5763f2bf799e1461013057600080fd5b3461023c576003199060808236011261023c5761014b612d80565b9167ffffffffffffffff6024358181116102865761016d9036906004016130be565b929091610178612d96565b90606435908111610282576101919036906004016130be565b92909661019c61323d565b6001600160a01b0380911694853b1561027e576101ef9060409995949951977fa2ffb897000000000000000000000000000000000000000000000000000000008952606060048a01526064890191613200565b9716602486015284870301604485015280865260208096019195855b82811061024a57868087818180890381838c5af1801561023f5761022c5750f35b61023590612e25565b61023c5780f35b80fd5b6040513d84823e3d90fd5b90919282806001926fffffffffffffffffffffffffffffffff61026c8c612f34565b1681520198019101969291909661020b565b8780fd5b8580fd5b8380fd5b503461023c57604060031936011261023c5767ffffffffffffffff600435818111610435576102bd9036906004016130be565b916024918235828111610282576102d89036906004016130be565b9390926102e361323d565b851561040b5786906102f586866140df565b93825b88811061030e578361030b89898961422c565b80f35b610319818a84613191565b356001600160a01b03811680910361040757610336828b85613191565b60209081810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561027e570180359086821161027e578201928160051b3603841361027e57803b1561027e57888880946103cc604051978896879586947f8659c2700000000000000000000000000000000000000000000000000000000086526004860152840191613200565b03925af19081156103fc5785916103e8575b50506001016102f8565b6103f190612e25565b6102865783386103de565b6040513d87823e3d90fd5b8480fd5b60046040517f71594532000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b506003199060408236011261023c57610450612d80565b916024359067ffffffffffffffff9081831161028657610100908336030112610435576040519061048082612dda565b61048c83600401612f01565b825261049a60248401612f76565b94602095868401526104ae60448501612f01565b60408401526104bf60648501612f34565b91606084019283526104d360848601612f01565b94608085019586526104e83660a48301612f95565b60a086015260e48101359182116105fa570136602382011215610282579261056d6105a2938796936105258a973690602460048201359101612ff1565b60c085015261053261323d565b6fffffffffffffffffffffffffffffffff9081341683526001600160a01b03809161055f8289511661430b565b169551169151169084613efd565b6040519485809481937fbf061d0a00000000000000000000000000000000000000000000000000000000835260048301613890565b03925af19182156105ee57916105bc575b50604051908152f35b90508181813d83116105e7575b6105d38183612eaa565b810103126105e25751386105b3565b600080fd5b503d6105c9565b604051903d90823e3d90fd5b8680fd5b503461023c5760808060031936011261092a57610619612d80565b90610622612eeb565b906044359067ffffffffffffffff938483116102825736602384011215610282578260040135948086116105fa576024840193602436918860081b0101116105fa576064359081116105fa5761067c903690600401612dac565b505061068661323d565b841561040b578591865b8681106108ed57506001600160a01b0380921661070c836106af6141ad565b9516610705604051866020987f23b872dd000000000000000000000000000000000000000000000000000000008a840152166024820152306044820152826064820152606481526106ff81612e8e565b89613349565b8783613efd565b61071587613609565b9683899716965b81811061073557604051806107318b82613083565b0390f35b60c0908161074482858b6135dc565b0183606093818c8c86886107598286856135dc565b0161076390613658565b9361076d926135dc565b968d8d8d8161077d8b8a866135dc565b0161078790613665565b928a610794818b846135dc565b61079d90613665565b996107a7926135dc565b6040016107b3906135ec565b9281604051996107c28b612dda565b16895216908701526fffffffffffffffffffffffffffffffff1660408601528401521515888301528436037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80016040136105e2576108548a9361088d966040519061082c82612e72565b6108378c8201612f83565b825261084660a0809201612f83565b878301528501523690612f95565b908201528c60405180809681947f1b4103a900000000000000000000000000000000000000000000000000000000835260048301613679565b0391885af180156108e2578b906108b4575b600192506108ad828c613712565b520161071c565b508682813d83116108db575b6108ca8183612eaa565b810103126105e2576001915161089f565b503d6108c0565b6040513d8d823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff610920604061091a898d8c6135dc565b016135ec565b1601169301610690565b5080fd5b503461023c57608060031936011261023c5780610949612d80565b610951612d96565b610959612f15565b9161096261323d565b6001600160a01b03809116803b15610407578492836064926fffffffffffffffffffffffffffffffff60405197889687957ffdd46d6000000000000000000000000000000000000000000000000000000000875260243560048801521660248601521660448401525af1801561023f5761022c5750f35b503461023c57806001600160a01b036109f13661315d565b9290916109fc61323d565b1691823b15610a5f576040517fc156a11d00000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b031660248201529082908290818381604481015b03925af1801561023f5761022c5750f35b505050fd5b503461023c576003199060608236011261023c57610a80612d80565b916024359167ffffffffffffffff9182841161092a5761010090843603011261023c5760443591821161023c576020610acc8585610ac13660048801612dac565b505060040190613aed565b604051908152f35b503461023c57806001600160a01b03610aec3661315d565b929091610af761323d565b1691823b15610a5f576040517fea5ead1900000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03166024820152908290829081838160448101610a4e565b503461023c57604060031936011261023c57806001600160a01b03610b70612d80565b610b7861323d565b16803b15610bc5578180916024604051809481937f42966c68000000000000000000000000000000000000000000000000000000008352833560048401525af1801561023f5761022c5750f35b50fd5b503461023c57604060031936011261023c57610be2612d80565b602435610bed61323d565b6001600160a01b0380921691604051917feac8f5b8000000000000000000000000000000000000000000000000000000008352806004840152846020928385602481895afa94851561023f578295610dac575b50841691604051957f70a0823100000000000000000000000000000000000000000000000000000000918288523060048901528588602481885afa978815610da1578498610d6e575b50813b156102865783916024839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610d61578593610d48575b505060246040518094819382523060048301525afa9182156103fc578592610d18575b505061030b92610d0991613299565b90610d126141ad565b906132d5565b90809250813d8311610d41575b610d2f8183612eaa565b810103126105e2575182610d09610cfa565b503d610d25565b610d5491929350612e25565b6102825782908638610cd7565b50604051903d90823e3d90fd5b86809299508195503d8311610d9a575b610d888183612eaa565b810103126105e2578792519638610c89565b503d610d7e565b6040513d86823e3d90fd5b9094508381813d8311610ddd575b610dc48183612eaa565b8101031261092a5751848116810361092a579338610c40565b503d610dba565b5061014060031936011261023c57610dfa612d80565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c5760405191610e3383612dda565b610e3b612eeb565b8352610e45612d96565b9260209384820152610e55612f15565b9060408101918252610e65612f51565b60608201908152610e74612f67565b608083015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c3601126105e257604051610eaf81612e72565b64ffffffffff60c43581811681036105e257825260e43590811681036105e2578782015260a083015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc3601126105e25760405191610f0f83612e72565b610104356001600160a01b039485821682036105e2578796899686610f6c946105a29852610124358982015260c0860152610f4861323d565b806fffffffffffffffffffffffffffffffff92833416855261055f8289511661430b565b6040519485809481937f1b4103a900000000000000000000000000000000000000000000000000000000835260048301613679565b503461023c5760031960a08136011261092a57610fbc612d80565b9160243591610fc9612d96565b916064359167ffffffffffffffff908184116104355761012090843603011261092a5760843590811161092a57611004903690600401612dac565b505061100e61323d565b61101661323d565b6001600160a01b0380951690604051947feac8f5b80000000000000000000000000000000000000000000000000000000086528060048701526020968787602481875afa9687156111ef5783976111b7575b50861690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528986602481875afa9586156103fc578596611188575b50813b156104075784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af18015610da157899291859161116f575b505060246040518094819382523060048301525afa9182156105ee579161113e575b5093610d0961113592610acc96613299565b60040190613d70565b9490508585813d8311611168575b6111568183612eaa565b810103126105e2579351610d09611123565b503d61114c565b61117b91929350612e25565b6104355787908338611101565b9095508981813d83116111b0575b6111a08183612eaa565b810103126105e2575194386110b1565b503d611196565b9096508781813d83116111e8575b6111cf8183612eaa565b8101031261043557518681168103610435579538611068565b503d6111c5565b6040513d85823e3d90fd5b503461023c576101c060031936011261023c57611215612d80565b6024803591611222612d96565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c360112610407576101a43567ffffffffffffffff81116102825761126e903690600401612dac565b505061127861323d565b61128061323d565b6001600160a01b03809216604051907feac8f5b800000000000000000000000000000000000000000000000000000000825285600483015260209586838781855afa92831561158e5788936115e9575b508785841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a868b81885afa958615610da15784966115b6575b50813b156102865783918a839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610d61578a93611599575b5050876040518094819382523060048301525afa90811561158e578596979891611556575b5061139b9291610d0991613299565b6113a361323d565b169060c435818116908181036105e25760a435906fffffffffffffffffffffffffffffffff82168092036105e257816114359161142f6113e16141ad565b87604051917f23b872dd000000000000000000000000000000000000000000000000000000008d840152168a8201523060448201528360648201526064815261142981612e8e565b82613349565b86613efd565b604051947f4bc78b730000000000000000000000000000000000000000000000000000000086526064358481168091036105e2576004870152608435908482168092036105e2578601526044850152606484015260e4358015158091036105e25760848401526101049081359064ffffffffff918281168091036105e25760a48601526101249283358381168091036105e25760c48701526101449283359081168091036105e25760e4870152610164359182168092036105e25786948694859360009385015261018435908401525af190811561154a5760009161151d5750604051908152f35b908282813d8311611543575b6115338183612eaa565b8101031261023c575051386105b3565b503d611529565b6040513d6000823e3d90fd5b9450909190508684813d8111611587575b6115718183612eaa565b810103126105e25792518493919061139b61138c565b503d611567565b6040513d8a823e3d90fd5b6115a591929350612e25565b6115b25787908938611367565b8880fd5b8b809297508195503d83116115e2575b6115d08183612eaa565b810103126105e2578a9251943861131a565b503d6115c6565b9092508681813d831161161a575b6116018183612eaa565b8101031261027e5751848116810361027e5791386112d0565b503d6115f7565b503461023c57604060031936011261023c57806001600160a01b03611644612d80565b61164c61323d565b16803b15610bc5578180916024604051809481937f7de6b1db000000000000000000000000000000000000000000000000000000008352833560048401525af1801561023f5761022c5750f35b503461023c5761018060031936011261023c576116b4612d80565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c57610164359067ffffffffffffffff821161023c5750611703903690600401612dac565b505061170d61323d565b608435906001600160a01b038281169181168284036105e257606435926fffffffffffffffffffffffffffffffff84168094036105e2576117a5846117506141ad565b9661179f6040518760209a7f23b872dd000000000000000000000000000000000000000000000000000000008c8401521660248201523060448201528360648201526064815261142981612e8e565b84613efd565b604051937f4bc78b730000000000000000000000000000000000000000000000000000000085526024358481168091036105e25760048601526044358481168091036105e25760248601526044850152606484015260a4358015158091036105e257608484015260c4359164ffffffffff928381168091036105e25760a485015260e4358381168091036105e25760c48501526101049283359081168091036105e25760e48501526101249081359081168091036105e2576000859384928896840152610144938435908401525af190811561154a5760009161151d5750604051908152f35b503461023c5761189a366130ef565b505090926118a661323d565b811561040b578490855b838110611ae957506001600160a01b0361193a9116916119336001600160a01b036118d96141ad565b9216916001600160a01b03604051917f23b872dd0000000000000000000000000000000000000000000000000000000060208401521660248201523060448201528260648201526064815261192d81612e8e565b86613349565b8483613efd565b61194382613609565b93855b83811061195b57604051806107318882613083565b6119668185846137fc565b608001906119758186856137fc565b60200161198190613658565b61198c8287866137fc565b60400161199890613665565b926119a48388876137fc565b60c081016119b19161383c565b9190926119bf858a896137fc565b6119c890613665565b956119d4868b8a6137fc565b6060016119e0906135ec565b91604051976119ee89612dda565b6001600160a01b03168852151560208801526001600160a01b031660408701526fffffffffffffffffffffffffffffffff1660608601526001600160a01b038916608086015236611a3e91612f95565b60a08501523690611a4e92612ff1565b60c0830152836040518080947fbf061d0a0000000000000000000000000000000000000000000000000000000082526004820190611a8b91613890565b03818b5a94602095f1801561158e578890611ab6575b60019250611aaf8289613712565b5201611946565b506020823d602011611ae1575b81611ad060209383612eaa565b810103126105e25760019151611aa1565b3d9150611ac3565b916001600160a01b036001916fffffffffffffffffffffffffffffffff611b16606061091a888a8d6137fc565b16011692016118b0565b503461023c57611b2f366130ef565b5050909192611b3c61323d565b811561040b5784805b838210611da457611bce9150611bbe6001600160a01b03611b646141ad565b9216916001600160a01b03604051917f23b872dd00000000000000000000000000000000000000000000000000000000602084015216602482015230604482015282606482015260648152611bb881612e8e565b87613349565b856001600160a01b038416613efd565b611bd782613609565b93855b838110611bef57604051806107318882613083565b60a0611bfc828688613996565b0190611c146040611c0e83888a613996565b01613658565b86611c2b6060611c25858a85613996565b01613665565b91611c44611c3a858a85613996565b60e081019061383c565b6020611c64878c611c5e611c5983838b613996565b613665565b97613996565b01359464ffffffffff86168603611da057611d3c976fffffffffffffffffffffffffffffffff611cc7966001600160a01b038f948f9864ffffffffff60209c848f608061091a611d049f92611cbc93611cf89e613996565b966040519e8f612e39565b168d52168c8c0152151560408b01521660608901521660808701526001600160a01b038a1660a08701523690612f95565b60c08501523691612ff1565b60e0820152604051809481927f21714be1000000000000000000000000000000000000000000000000000000008352600483016139d6565b03818b6001600160a01b0389165af1801561158e578890611d6d575b60019250611d668289613712565b5201611bda565b506020823d602011611d98575b81611d8760209383612eaa565b810103126105e25760019151611d58565b3d9150611d7a565b8d80fd5b6001600160a01b036001916fffffffffffffffffffffffffffffffff611dd0608061091a878a8c613996565b160116910190611b45565b503461023c57606060031936011261023c57611df5612d80565b8167ffffffffffffffff60243581811161043557611e179036906004016130be565b92909160443590811161092a57611e329036906004016130be565b611e3a61323d565b6001600160a01b03611e4c86866140df565b961691823b1561028657611e9a928492836040518096819582947f8659c270000000000000000000000000000000000000000000000000000000008452602060048501526024840191613200565b03925af1801561023f57611eb4575b505061030b9261422c565b611ebd90612e25565b610286578338611ea9565b503461023c5760031960a08136011261092a57611ee3612d80565b9160243591611ef0612d96565b916064359167ffffffffffffffff908184116104355761010090843603011261092a5760843590811161092a57611f2b903690600401612dac565b5050611f3561323d565b611f3d61323d565b6001600160a01b0380951690604051947feac8f5b80000000000000000000000000000000000000000000000000000000086528060048701526020968787602481875afa9687156111ef5783976120de575b50861690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528986602481875afa9586156103fc5785966120af575b50813b156104075784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af18015610da1578992918591612096575b505060246040518094819382523060048301525afa9182156105ee5791612065575b5093610d0961205c92610acc96613299565b60040190613aed565b9490508585813d831161208f575b61207d8183612eaa565b810103126105e2579351610d0961204a565b503d612073565b6120a291929350612e25565b6104355787908338612028565b9095508981813d83116120d7575b6120c78183612eaa565b810103126105e257519438611fd8565b503d6120bd565b9096508781813d831161210f575b6120f68183612eaa565b8101031261043557518681168103610435579538611f8f565b503d6120ec565b503461023c5760808060031936011261092a57612131612d80565b9161213a612eeb565b60443567ffffffffffffffff938482116102865736602383011215610286578160040135948086116104075760248301926024369161012089020101116104075760643590811161040757612193903690600401612dac565b505061219d61323d565b841561040b579091839190825b86811061240f57506001600160a01b03809716612226886121c96141ad565b951661221f6040518b6020987f23b872dd000000000000000000000000000000000000000000000000000000008a8401521660248201523060448201528260648201526064815261221981612e8e565b85613349565b8383613efd565b61222f87613609565b9688879316925b81811061224b57604051806107318b82613083565b806122588392838a613726565b60e0018260608d8161226b86858f613726565b0161227590613658565b908b8d87612284818884613726565b9961228e92613726565b0161229890613665565b908d876122a6818884613726565b6122af90613665565b966122b992613726565b6040016122c5906135ec565b9181604051966122d488612dda565b168652168c8501526fffffffffffffffffffffffffffffffff16604084015288828401521515898301528436037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001126105e2576123ae936123778a9360405161233d81612e56565b6123488c8501612f83565b815260a0612357818601612f83565b8783015261236860c0809601612f83565b60408301528501523690612f95565b90820152604051809481927f4bc78b7300000000000000000000000000000000000000000000000000000000835260048301613737565b03818c885af180156124045789906123d6575b600192506123cf828c613712565b5201612236565b508682813d83116123fd575b6123ec8183612eaa565b810103126105e257600191516123c1565b503d6123e2565b6040513d8b823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff61243e604061091a898d8c999c613726565b16011693019390936121aa565b506003199060408236011261023c57612462612d80565b916024359067ffffffffffffffff9081831161028657610120908336030112610435576040519061249282612e39565b61249e83600401612f01565b82526124ac60248401612f83565b94602095868401526124c060448501612f76565b60408401526124d160648501612f01565b60608401526124e260848501612f34565b91608084019283526124f660a48601612f01565b9460a0850195865261250b3660c48301612f95565b60c08601526101048101359182116105fa57013660238201121561028257926125566105a2938796936125498a973690602460048201359101612ff1565b60e085015261053261323d565b6040519485809481937f21714be1000000000000000000000000000000000000000000000000000000008352600483016139d6565b503461023c576101a060031936011261023c576125a6612d80565b60248035916125b3612d96565b6101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c360112610407576101843567ffffffffffffffff8111610282576125ff903690600401612dac565b505061260961323d565b61261161323d565b6040517feac8f5b8000000000000000000000000000000000000000000000000000000008152600481018590526020946001600160a01b0393841686838781845afa92831561158e578893612912575b508483169088604051937f70a0823100000000000000000000000000000000000000000000000000000000928386523060048701528a868b81885afa9586156111ef5783966128e3575b50803b156104355789839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af180156128d8576128c5575b508790876040518094819382523060048301525afa90811561158e57859697989161288d575b506127289291610d0991613299565b61273061323d565b1660c435828116908181036105e25760a435906fffffffffffffffffffffffffffffffff82168092036105e257816127bb916127b561276d6141ad565b88604051917f23b872dd000000000000000000000000000000000000000000000000000000008d840152168a8201523060448201528360648201526064815261142981612e8e565b85613efd565b604051947f1b4103a90000000000000000000000000000000000000000000000000000000086526064358581168091036105e2576004870152608435908582168092036105e2578601526044850152606484015260e4358015158091036105e257608484015264ffffffffff6101048035828116908190036105e25760a48601526101249182359081168091036105e25760c4860152610144359384168094036105e257600085938492889660e485015261016435908401525af190811561154a5760009161151d5750604051908152f35b9450909190508684813d81116128be575b6128a88183612eaa565b810103126105e257925184939190612728612719565b503d61289e565b986128d189929a612e25565b98906126f3565b6040513d8c823e3d90fd5b9095508a81813d831161290b575b6128fb8183612eaa565b81010312610435575194386126ab565b503d6128f1565b9092508681813d8311612943575b61292a8183612eaa565b8101031261027e5751848116810361027e579138612661565b503d612920565b503461023c576003199060608236011261023c57612966612d80565b916024359167ffffffffffffffff9182841161092a5761012090843603011261023c5760443591821161023c576020610acc85856129a73660048801612dac565b505060040190613d70565b5061016060031936011261023c576129c8612d80565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c5760405191612a0183612dda565b612a09612eeb565b8352612a13612d96565b9260209384820152612a23612f15565b60408201908152612a32612f51565b9260608301938452612a42612f67565b608084015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c36011261040757604051612a7d81612e56565b64ffffffffff60c435818116810361027e57825260e435818116810361027e57888301526101043590811681036105fa57604082015260a084015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc36011261040757604051612aee81612e72565b6001600160a01b039061012435828116810361027e579387969389969383612b5f97612b2a9552610144358982015260c0860152610f4861323d565b6040519485809481937f4bc78b7300000000000000000000000000000000000000000000000000000000835260048301613737565b03925af19182156105ee578092612b7b575b5050604051908152f35b9091508282813d8311612ba4575b612b938183612eaa565b8101031261023c5750513880612b71565b503d612b89565b503461023c5761016060031936011261023c57612bc6612d80565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c576101443567ffffffffffffffff811161092a57612c13903690600401612dac565b5050612c1d61323d565b608435916001600160a01b0383811691811682850361028657606435926fffffffffffffffffffffffffffffffff841680940361040757612caf84612c606141ad565b9761179f6040518760209b7f23b872dd000000000000000000000000000000000000000000000000000000008d8401521660248201523060448201528360648201526064815261142981612e8e565b604051937f1b4103a90000000000000000000000000000000000000000000000000000000085526024358481168091036105fa5760048601526044358481168091036105fa5760248601526044850152606484015260a43580151580910361040757608484015260c43564ffffffffff908181168091036102825760a485015260e4359081168091036104075760c4840152610104918235908116809103610407579183858193889560e4840152610124938435908401525af19182156105ee578092612b7b575050604051908152f35b600435906001600160a01b03821682036105e257565b604435906001600160a01b03821682036105e257565b9181601f840112156105e25782359167ffffffffffffffff83116105e257602083818601950101116105e257565b60e0810190811067ffffffffffffffff821117612df657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111612df657604052565b610100810190811067ffffffffffffffff821117612df657604052565b6060810190811067ffffffffffffffff821117612df657604052565b6040810190811067ffffffffffffffff821117612df657604052565b60a0810190811067ffffffffffffffff821117612df657604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612df657604052565b602435906001600160a01b03821682036105e257565b35906001600160a01b03821682036105e257565b606435906fffffffffffffffffffffffffffffffff821682036105e257565b35906fffffffffffffffffffffffffffffffff821682036105e257565b608435906001600160a01b03821682036105e257565b60a4359081151582036105e257565b359081151582036105e257565b359064ffffffffff821682036105e257565b91908260409103126105e257604051612fad81612e72565b6020808294612fbb81612f01565b84520135910152565b67ffffffffffffffff8111612df65760051b60200190565b359067ffffffffffffffff821682036105e257565b929192612ffd82612fc4565b60409461300c86519283612eaa565b819584835260208093019160608096028501948186116105e257925b8584106130385750505050505050565b86848303126105e257848791845161304f81612e56565b61305887612f34565b8152613065838801612fdc565b83820152613074868801612f83565b86820152815201930192613028565b6020908160408183019282815285518094520193019160005b8281106130aa575050505090565b83518552938101939281019260010161309c565b9181601f840112156105e25782359167ffffffffffffffff83116105e2576020808501948460051b0101116105e257565b60806003198201126105e2576001600160a01b039160043583811681036105e2579260243590811681036105e2579167ffffffffffffffff916044358381116105e2578261313f916004016130be565b939093926064359182116105e25761315991600401612dac565b9091565b60031960609101126105e2576001600160a01b0360043581811681036105e257916024359160443590811681036105e25790565b91908110156131d15760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1813603018212156105e2570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116105e25760209260051b809284830137010190565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016301461326f57565b60046040517fbbff6135000000000000000000000000000000000000000000000000000000008152fd5b919082039182116132a657565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261332f9161332a606483612eaa565b613349565b565b908160209103126105e2575180151581036105e25790565b6040516133a7916001600160a01b031661336282612e72565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16133a161345c565b916134ba565b805190828215928315613444575b505050156133c05750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6134549350820181019101613331565b3882816133b5565b3d156134b5573d9067ffffffffffffffff8211612df657604051916134a960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184612eaa565b82523d6000602084013e565b606090565b9192901561353557508151156134ce575090565b3b156134d75790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156135485750805190602001fd5b604051907f08c379a000000000000000000000000000000000000000000000000000000000825281602080600483015282519283602484015260005b8481106135c5575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201613584565b91908110156131d15760081b0190565b356fffffffffffffffffffffffffffffffff811681036105e25790565b9061361382612fc4565b6136206040519182612eaa565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061364e8294612fc4565b0190602036910137565b3580151581036105e25790565b356001600160a01b03811681036105e25790565b61332f9092919260e060c06101208301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151602064ffffffffff918281511660a0880152015116828501520151910190602080916001600160a01b0381511684520151910152565b80518210156131d15760209160051b010190565b91908110156131d157610120020190565b61332f9092919261010060c06101408301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151604064ffffffffff918281511660a0880152826020820151168588015201511660e08501520151910190602080916001600160a01b0381511684520151910152565b602080916001600160a01b036137f282612f01565b1684520135910152565b91908110156131d15760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21813603018212156105e2570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156105e2570180359067ffffffffffffffff82116105e2576020019160608202360383136105e257565b9060208083526101208301908061014060c06001600160a01b0395868151168489015283810151151560408901526040810151968060609816888a01526fffffffffffffffffffffffffffffffff888301511660808a015260808201511660a089015261391760a0820151838a0190602080916001600160a01b0381511684520151910152565b015195610100808201528651809552019401926000905b83821061393d57505050505090565b90919293948382826139896001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019601949392019061392e565b91908110156131d15760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01813603018212156105e2570190565b9060208083526101408301908061016060e06001600160a01b0395868151168489015264ffffffffff848201511660408901526040810151966060971515888a015280888301511660808a01526fffffffffffffffffffffffffffffffff60808301511660a08a015260a08201511660c0890152613a6e60c0820151838a0190602080916001600160a01b0381511684520151910152565b015195610120808201528651809552019401926000905b838210613a9457505050505090565b9091929394838282613ae06001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b0196019493920190613a85565b90613af661323d565b7f23b872dd000000000000000000000000000000000000000000000000000000006001600160a01b03809316926080830193613b3185613665565b936060613c39818301926fffffffffffffffffffffffffffffffff95613b9987613b5a876135ec565b16613b636141ad565b9a613b936040518560209e8f9e8f8401521660248201523060448201528360648201526064815261142981612e8e565b88613efd565b613c196040519a8b987fbf061d0a000000000000000000000000000000000000000000000000000000008a528a60048b0152613c0e6101248b019885613bde88612f01565b1660248d0152613bef8d8801612f76565b151560448d015285613c0360408901612f01565b1660648d0152612f34565b1660848a0152612f01565b1660a4870152613c2f60c4870160a083016137dd565b60e0810190613ccc565b809193610100610104880152526101448501929160005b828110613ca55750505050600083809203925af190811561154a57600091613c79575b50905090565b82813d8311613c9e575b613c8d8183612eaa565b8101031261023c5750518038613c73565b503d613c83565b9295506001919496508084613cbb829689613d1f565b019501910192879492879694613c50565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156105e257016020813591019167ffffffffffffffff82116105e25760608202360383136105e257565b64ffffffffff613d6a604080936fffffffffffffffffffffffffffffffff613d4682612f34565b16865267ffffffffffffffff613d5e60208301612fdc565b16602087015201612f83565b16910152565b907f23b872dd00000000000000000000000000000000000000000000000000000000613e7692613d9e61323d565b6001600160a01b0380911660a0840191613db783613665565b94613e9760808201916fffffffffffffffffffffffffffffffff93613ddf85613b5a866135ec565b604051998a977f21714be10000000000000000000000000000000000000000000000000000000089528960048a015261014489019683613e1e86612f01565b1660248b015264ffffffffff613e358c8701612f83565b1660448b0152613e4760408601612f76565b151560648b0152613e6b60609785613e608a8901612f01565b1660848d0152612f34565b1660a48a0152612f01565b1660c4870152613e8c60e4870160c083016137dd565b610100810190613ccc565b809193610120610124880152526101648501929160005b828110613ed65750505050600083809203925af190811561154a57600091613c795750905090565b9295506001919496508084613eec829689613d1f565b019501910192879492879694613eae565b91906001600160a01b039283821690604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701528116918260248701526020958681604481855afa801561154a57869160009161409f575b5010613f6c575b505050505050565b60008060405196613fee88613fc28b8201937f095ea7b3000000000000000000000000000000000000000000000000000000009889865260248401602090939291936001600160a01b0360408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018a5289612eaa565b87519082855af190613ffe61345c565b8261406c575b5081614061575b5015614018575b80613f64565b60405194850152602484015260006044840152604483526080830183811067ffffffffffffffff821117612df6576140579361332a9160405282613349565b3880808080614012565b90503b15153861400b565b809192505190878215928315614087575b5050509038614004565b6140979350820181019101613331565b38878161407d565b91508782813d83116140c8575b6140b68183612eaa565b8101031261023c575085905138613f5d565b503d6140ac565b91908110156131d15760051b0190565b9190916140eb83613609565b9260005b8181106140fb57505050565b6001600160a01b03614111611c598385876140cf565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa9182156141a35750600091614172575b506001925061416b8288613712565b52016140ef565b919282813d831161419c575b6141888183612eaa565b8101031261023c575090600191513861415c565b503d61417e565b513d6000823e3d90fd5b6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481305afa90811561154a576000916141ee575090565b6020813d8211614224575b8161420660209383612eaa565b8101031261092a5751906001600160a01b038216820361023c575090565b3d91506141f9565b909160005b81811061423e5750505050565b6001600160a01b03614254611c598385886140cf565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa9182156141a357506000916142d8575b50600192506142bc6142d2916142b58488613712565b5190613299565b6142ca611c5984878a6140cf565b610d126141ad565b01614231565b919282813d8311614304575b6142ee8183612eaa565b8101031261023c575051600191906142bc61429f565b503d6142e4565b6001600160a01b031660409081517f70a08231000000000000000000000000000000000000000000000000000000008082526000903060048401526020908184602481885afa938415614496578394614467575b50843b156104355785517fd0e30db00000000000000000000000000000000000000000000000000000000081528381600481348a5af1801561445d5761444a575b508190602487518097819382523060048301525afa91821561443f579161440f575b506143cd9250613299565b903482036143d9575050565b6044925051907fe5f762580000000000000000000000000000000000000000000000000000000082523460048301526024820152fd5b905082813d8311614438575b6144258183612eaa565b810103126105e2576143cd9151386143c2565b503d61441b565b8551903d90823e3d90fd5b92614456839294612e25565b92906143a0565b87513d86823e3d90fd5b9093508181813d831161448f575b61447f8183612eaa565b810103126104355751923861435f565b503d614475565b86513d85823e3d90fd
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c80630cbbef7f14612bab57806310fad8c8146129b257806313b55f011461294a57806314296d161461258b5780631d165efc1461244b57806345188c01146121165780634c4bfa7714611ec85780636a09d49a14611ddb5780636a9c21b714611b205780636f0995f31461188b578063825976161461169957806386f2891e1461162157806387d23ff1146111fa5780638e80029914610fa157806390e2cd7914610de457806398590ef914610bc85780639dc29fac14610b4d578063a3143b7614610ad4578063aa02171414610a64578063ad26c0fb146109d9578063b956b45f1461092e578063e6a64e02146105fe578063ec5b900f14610439578063f16306121461028a5763f2bf799e1461013057600080fd5b3461023c576003199060808236011261023c5761014b612d80565b9167ffffffffffffffff6024358181116102865761016d9036906004016130be565b929091610178612d96565b90606435908111610282576101919036906004016130be565b92909661019c61323d565b6001600160a01b0380911694853b1561027e576101ef9060409995949951977fa2ffb897000000000000000000000000000000000000000000000000000000008952606060048a01526064890191613200565b9716602486015284870301604485015280865260208096019195855b82811061024a57868087818180890381838c5af1801561023f5761022c5750f35b61023590612e25565b61023c5780f35b80fd5b6040513d84823e3d90fd5b90919282806001926fffffffffffffffffffffffffffffffff61026c8c612f34565b1681520198019101969291909661020b565b8780fd5b8580fd5b8380fd5b503461023c57604060031936011261023c5767ffffffffffffffff600435818111610435576102bd9036906004016130be565b916024918235828111610282576102d89036906004016130be565b9390926102e361323d565b851561040b5786906102f586866140df565b93825b88811061030e578361030b89898961422c565b80f35b610319818a84613191565b356001600160a01b03811680910361040757610336828b85613191565b60209081810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561027e570180359086821161027e578201928160051b3603841361027e57803b1561027e57888880946103cc604051978896879586947f8659c2700000000000000000000000000000000000000000000000000000000086526004860152840191613200565b03925af19081156103fc5785916103e8575b50506001016102f8565b6103f190612e25565b6102865783386103de565b6040513d87823e3d90fd5b8480fd5b60046040517f71594532000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b506003199060408236011261023c57610450612d80565b916024359067ffffffffffffffff9081831161028657610100908336030112610435576040519061048082612dda565b61048c83600401612f01565b825261049a60248401612f76565b94602095868401526104ae60448501612f01565b60408401526104bf60648501612f34565b91606084019283526104d360848601612f01565b94608085019586526104e83660a48301612f95565b60a086015260e48101359182116105fa570136602382011215610282579261056d6105a2938796936105258a973690602460048201359101612ff1565b60c085015261053261323d565b6fffffffffffffffffffffffffffffffff9081341683526001600160a01b03809161055f8289511661430b565b169551169151169084613efd565b6040519485809481937fbf061d0a00000000000000000000000000000000000000000000000000000000835260048301613890565b03925af19182156105ee57916105bc575b50604051908152f35b90508181813d83116105e7575b6105d38183612eaa565b810103126105e25751386105b3565b600080fd5b503d6105c9565b604051903d90823e3d90fd5b8680fd5b503461023c5760808060031936011261092a57610619612d80565b90610622612eeb565b906044359067ffffffffffffffff938483116102825736602384011215610282578260040135948086116105fa576024840193602436918860081b0101116105fa576064359081116105fa5761067c903690600401612dac565b505061068661323d565b841561040b578591865b8681106108ed57506001600160a01b0380921661070c836106af6141ad565b9516610705604051866020987f23b872dd000000000000000000000000000000000000000000000000000000008a840152166024820152306044820152826064820152606481526106ff81612e8e565b89613349565b8783613efd565b61071587613609565b9683899716965b81811061073557604051806107318b82613083565b0390f35b60c0908161074482858b6135dc565b0183606093818c8c86886107598286856135dc565b0161076390613658565b9361076d926135dc565b968d8d8d8161077d8b8a866135dc565b0161078790613665565b928a610794818b846135dc565b61079d90613665565b996107a7926135dc565b6040016107b3906135ec565b9281604051996107c28b612dda565b16895216908701526fffffffffffffffffffffffffffffffff1660408601528401521515888301528436037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80016040136105e2576108548a9361088d966040519061082c82612e72565b6108378c8201612f83565b825261084660a0809201612f83565b878301528501523690612f95565b908201528c60405180809681947f1b4103a900000000000000000000000000000000000000000000000000000000835260048301613679565b0391885af180156108e2578b906108b4575b600192506108ad828c613712565b520161071c565b508682813d83116108db575b6108ca8183612eaa565b810103126105e2576001915161089f565b503d6108c0565b6040513d8d823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff610920604061091a898d8c6135dc565b016135ec565b1601169301610690565b5080fd5b503461023c57608060031936011261023c5780610949612d80565b610951612d96565b610959612f15565b9161096261323d565b6001600160a01b03809116803b15610407578492836064926fffffffffffffffffffffffffffffffff60405197889687957ffdd46d6000000000000000000000000000000000000000000000000000000000875260243560048801521660248601521660448401525af1801561023f5761022c5750f35b503461023c57806001600160a01b036109f13661315d565b9290916109fc61323d565b1691823b15610a5f576040517fc156a11d00000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b031660248201529082908290818381604481015b03925af1801561023f5761022c5750f35b505050fd5b503461023c576003199060608236011261023c57610a80612d80565b916024359167ffffffffffffffff9182841161092a5761010090843603011261023c5760443591821161023c576020610acc8585610ac13660048801612dac565b505060040190613aed565b604051908152f35b503461023c57806001600160a01b03610aec3661315d565b929091610af761323d565b1691823b15610a5f576040517fea5ead1900000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03166024820152908290829081838160448101610a4e565b503461023c57604060031936011261023c57806001600160a01b03610b70612d80565b610b7861323d565b16803b15610bc5578180916024604051809481937f42966c68000000000000000000000000000000000000000000000000000000008352833560048401525af1801561023f5761022c5750f35b50fd5b503461023c57604060031936011261023c57610be2612d80565b602435610bed61323d565b6001600160a01b0380921691604051917feac8f5b8000000000000000000000000000000000000000000000000000000008352806004840152846020928385602481895afa94851561023f578295610dac575b50841691604051957f70a0823100000000000000000000000000000000000000000000000000000000918288523060048901528588602481885afa978815610da1578498610d6e575b50813b156102865783916024839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610d61578593610d48575b505060246040518094819382523060048301525afa9182156103fc578592610d18575b505061030b92610d0991613299565b90610d126141ad565b906132d5565b90809250813d8311610d41575b610d2f8183612eaa565b810103126105e2575182610d09610cfa565b503d610d25565b610d5491929350612e25565b6102825782908638610cd7565b50604051903d90823e3d90fd5b86809299508195503d8311610d9a575b610d888183612eaa565b810103126105e2578792519638610c89565b503d610d7e565b6040513d86823e3d90fd5b9094508381813d8311610ddd575b610dc48183612eaa565b8101031261092a5751848116810361092a579338610c40565b503d610dba565b5061014060031936011261023c57610dfa612d80565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c5760405191610e3383612dda565b610e3b612eeb565b8352610e45612d96565b9260209384820152610e55612f15565b9060408101918252610e65612f51565b60608201908152610e74612f67565b608083015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c3601126105e257604051610eaf81612e72565b64ffffffffff60c43581811681036105e257825260e43590811681036105e2578782015260a083015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc3601126105e25760405191610f0f83612e72565b610104356001600160a01b039485821682036105e2578796899686610f6c946105a29852610124358982015260c0860152610f4861323d565b806fffffffffffffffffffffffffffffffff92833416855261055f8289511661430b565b6040519485809481937f1b4103a900000000000000000000000000000000000000000000000000000000835260048301613679565b503461023c5760031960a08136011261092a57610fbc612d80565b9160243591610fc9612d96565b916064359167ffffffffffffffff908184116104355761012090843603011261092a5760843590811161092a57611004903690600401612dac565b505061100e61323d565b61101661323d565b6001600160a01b0380951690604051947feac8f5b80000000000000000000000000000000000000000000000000000000086528060048701526020968787602481875afa9687156111ef5783976111b7575b50861690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528986602481875afa9586156103fc578596611188575b50813b156104075784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af18015610da157899291859161116f575b505060246040518094819382523060048301525afa9182156105ee579161113e575b5093610d0961113592610acc96613299565b60040190613d70565b9490508585813d8311611168575b6111568183612eaa565b810103126105e2579351610d09611123565b503d61114c565b61117b91929350612e25565b6104355787908338611101565b9095508981813d83116111b0575b6111a08183612eaa565b810103126105e2575194386110b1565b503d611196565b9096508781813d83116111e8575b6111cf8183612eaa565b8101031261043557518681168103610435579538611068565b503d6111c5565b6040513d85823e3d90fd5b503461023c576101c060031936011261023c57611215612d80565b6024803591611222612d96565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c360112610407576101a43567ffffffffffffffff81116102825761126e903690600401612dac565b505061127861323d565b61128061323d565b6001600160a01b03809216604051907feac8f5b800000000000000000000000000000000000000000000000000000000825285600483015260209586838781855afa92831561158e5788936115e9575b508785841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a868b81885afa958615610da15784966115b6575b50813b156102865783918a839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610d61578a93611599575b5050876040518094819382523060048301525afa90811561158e578596979891611556575b5061139b9291610d0991613299565b6113a361323d565b169060c435818116908181036105e25760a435906fffffffffffffffffffffffffffffffff82168092036105e257816114359161142f6113e16141ad565b87604051917f23b872dd000000000000000000000000000000000000000000000000000000008d840152168a8201523060448201528360648201526064815261142981612e8e565b82613349565b86613efd565b604051947f4bc78b730000000000000000000000000000000000000000000000000000000086526064358481168091036105e2576004870152608435908482168092036105e2578601526044850152606484015260e4358015158091036105e25760848401526101049081359064ffffffffff918281168091036105e25760a48601526101249283358381168091036105e25760c48701526101449283359081168091036105e25760e4870152610164359182168092036105e25786948694859360009385015261018435908401525af190811561154a5760009161151d5750604051908152f35b908282813d8311611543575b6115338183612eaa565b8101031261023c575051386105b3565b503d611529565b6040513d6000823e3d90fd5b9450909190508684813d8111611587575b6115718183612eaa565b810103126105e25792518493919061139b61138c565b503d611567565b6040513d8a823e3d90fd5b6115a591929350612e25565b6115b25787908938611367565b8880fd5b8b809297508195503d83116115e2575b6115d08183612eaa565b810103126105e2578a9251943861131a565b503d6115c6565b9092508681813d831161161a575b6116018183612eaa565b8101031261027e5751848116810361027e5791386112d0565b503d6115f7565b503461023c57604060031936011261023c57806001600160a01b03611644612d80565b61164c61323d565b16803b15610bc5578180916024604051809481937f7de6b1db000000000000000000000000000000000000000000000000000000008352833560048401525af1801561023f5761022c5750f35b503461023c5761018060031936011261023c576116b4612d80565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c57610164359067ffffffffffffffff821161023c5750611703903690600401612dac565b505061170d61323d565b608435906001600160a01b038281169181168284036105e257606435926fffffffffffffffffffffffffffffffff84168094036105e2576117a5846117506141ad565b9661179f6040518760209a7f23b872dd000000000000000000000000000000000000000000000000000000008c8401521660248201523060448201528360648201526064815261142981612e8e565b84613efd565b604051937f4bc78b730000000000000000000000000000000000000000000000000000000085526024358481168091036105e25760048601526044358481168091036105e25760248601526044850152606484015260a4358015158091036105e257608484015260c4359164ffffffffff928381168091036105e25760a485015260e4358381168091036105e25760c48501526101049283359081168091036105e25760e48501526101249081359081168091036105e2576000859384928896840152610144938435908401525af190811561154a5760009161151d5750604051908152f35b503461023c5761189a366130ef565b505090926118a661323d565b811561040b578490855b838110611ae957506001600160a01b0361193a9116916119336001600160a01b036118d96141ad565b9216916001600160a01b03604051917f23b872dd0000000000000000000000000000000000000000000000000000000060208401521660248201523060448201528260648201526064815261192d81612e8e565b86613349565b8483613efd565b61194382613609565b93855b83811061195b57604051806107318882613083565b6119668185846137fc565b608001906119758186856137fc565b60200161198190613658565b61198c8287866137fc565b60400161199890613665565b926119a48388876137fc565b60c081016119b19161383c565b9190926119bf858a896137fc565b6119c890613665565b956119d4868b8a6137fc565b6060016119e0906135ec565b91604051976119ee89612dda565b6001600160a01b03168852151560208801526001600160a01b031660408701526fffffffffffffffffffffffffffffffff1660608601526001600160a01b038916608086015236611a3e91612f95565b60a08501523690611a4e92612ff1565b60c0830152836040518080947fbf061d0a0000000000000000000000000000000000000000000000000000000082526004820190611a8b91613890565b03818b5a94602095f1801561158e578890611ab6575b60019250611aaf8289613712565b5201611946565b506020823d602011611ae1575b81611ad060209383612eaa565b810103126105e25760019151611aa1565b3d9150611ac3565b916001600160a01b036001916fffffffffffffffffffffffffffffffff611b16606061091a888a8d6137fc565b16011692016118b0565b503461023c57611b2f366130ef565b5050909192611b3c61323d565b811561040b5784805b838210611da457611bce9150611bbe6001600160a01b03611b646141ad565b9216916001600160a01b03604051917f23b872dd00000000000000000000000000000000000000000000000000000000602084015216602482015230604482015282606482015260648152611bb881612e8e565b87613349565b856001600160a01b038416613efd565b611bd782613609565b93855b838110611bef57604051806107318882613083565b60a0611bfc828688613996565b0190611c146040611c0e83888a613996565b01613658565b86611c2b6060611c25858a85613996565b01613665565b91611c44611c3a858a85613996565b60e081019061383c565b6020611c64878c611c5e611c5983838b613996565b613665565b97613996565b01359464ffffffffff86168603611da057611d3c976fffffffffffffffffffffffffffffffff611cc7966001600160a01b038f948f9864ffffffffff60209c848f608061091a611d049f92611cbc93611cf89e613996565b966040519e8f612e39565b168d52168c8c0152151560408b01521660608901521660808701526001600160a01b038a1660a08701523690612f95565b60c08501523691612ff1565b60e0820152604051809481927f21714be1000000000000000000000000000000000000000000000000000000008352600483016139d6565b03818b6001600160a01b0389165af1801561158e578890611d6d575b60019250611d668289613712565b5201611bda565b506020823d602011611d98575b81611d8760209383612eaa565b810103126105e25760019151611d58565b3d9150611d7a565b8d80fd5b6001600160a01b036001916fffffffffffffffffffffffffffffffff611dd0608061091a878a8c613996565b160116910190611b45565b503461023c57606060031936011261023c57611df5612d80565b8167ffffffffffffffff60243581811161043557611e179036906004016130be565b92909160443590811161092a57611e329036906004016130be565b611e3a61323d565b6001600160a01b03611e4c86866140df565b961691823b1561028657611e9a928492836040518096819582947f8659c270000000000000000000000000000000000000000000000000000000008452602060048501526024840191613200565b03925af1801561023f57611eb4575b505061030b9261422c565b611ebd90612e25565b610286578338611ea9565b503461023c5760031960a08136011261092a57611ee3612d80565b9160243591611ef0612d96565b916064359167ffffffffffffffff908184116104355761010090843603011261092a5760843590811161092a57611f2b903690600401612dac565b5050611f3561323d565b611f3d61323d565b6001600160a01b0380951690604051947feac8f5b80000000000000000000000000000000000000000000000000000000086528060048701526020968787602481875afa9687156111ef5783976120de575b50861690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528986602481875afa9586156103fc5785966120af575b50813b156104075784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af18015610da1578992918591612096575b505060246040518094819382523060048301525afa9182156105ee5791612065575b5093610d0961205c92610acc96613299565b60040190613aed565b9490508585813d831161208f575b61207d8183612eaa565b810103126105e2579351610d0961204a565b503d612073565b6120a291929350612e25565b6104355787908338612028565b9095508981813d83116120d7575b6120c78183612eaa565b810103126105e257519438611fd8565b503d6120bd565b9096508781813d831161210f575b6120f68183612eaa565b8101031261043557518681168103610435579538611f8f565b503d6120ec565b503461023c5760808060031936011261092a57612131612d80565b9161213a612eeb565b60443567ffffffffffffffff938482116102865736602383011215610286578160040135948086116104075760248301926024369161012089020101116104075760643590811161040757612193903690600401612dac565b505061219d61323d565b841561040b579091839190825b86811061240f57506001600160a01b03809716612226886121c96141ad565b951661221f6040518b6020987f23b872dd000000000000000000000000000000000000000000000000000000008a8401521660248201523060448201528260648201526064815261221981612e8e565b85613349565b8383613efd565b61222f87613609565b9688879316925b81811061224b57604051806107318b82613083565b806122588392838a613726565b60e0018260608d8161226b86858f613726565b0161227590613658565b908b8d87612284818884613726565b9961228e92613726565b0161229890613665565b908d876122a6818884613726565b6122af90613665565b966122b992613726565b6040016122c5906135ec565b9181604051966122d488612dda565b168652168c8501526fffffffffffffffffffffffffffffffff16604084015288828401521515898301528436037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001126105e2576123ae936123778a9360405161233d81612e56565b6123488c8501612f83565b815260a0612357818601612f83565b8783015261236860c0809601612f83565b60408301528501523690612f95565b90820152604051809481927f4bc78b7300000000000000000000000000000000000000000000000000000000835260048301613737565b03818c885af180156124045789906123d6575b600192506123cf828c613712565b5201612236565b508682813d83116123fd575b6123ec8183612eaa565b810103126105e257600191516123c1565b503d6123e2565b6040513d8b823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff61243e604061091a898d8c999c613726565b16011693019390936121aa565b506003199060408236011261023c57612462612d80565b916024359067ffffffffffffffff9081831161028657610120908336030112610435576040519061249282612e39565b61249e83600401612f01565b82526124ac60248401612f83565b94602095868401526124c060448501612f76565b60408401526124d160648501612f01565b60608401526124e260848501612f34565b91608084019283526124f660a48601612f01565b9460a0850195865261250b3660c48301612f95565b60c08601526101048101359182116105fa57013660238201121561028257926125566105a2938796936125498a973690602460048201359101612ff1565b60e085015261053261323d565b6040519485809481937f21714be1000000000000000000000000000000000000000000000000000000008352600483016139d6565b503461023c576101a060031936011261023c576125a6612d80565b60248035916125b3612d96565b6101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c360112610407576101843567ffffffffffffffff8111610282576125ff903690600401612dac565b505061260961323d565b61261161323d565b6040517feac8f5b8000000000000000000000000000000000000000000000000000000008152600481018590526020946001600160a01b0393841686838781845afa92831561158e578893612912575b508483169088604051937f70a0823100000000000000000000000000000000000000000000000000000000928386523060048701528a868b81885afa9586156111ef5783966128e3575b50803b156104355789839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af180156128d8576128c5575b508790876040518094819382523060048301525afa90811561158e57859697989161288d575b506127289291610d0991613299565b61273061323d565b1660c435828116908181036105e25760a435906fffffffffffffffffffffffffffffffff82168092036105e257816127bb916127b561276d6141ad565b88604051917f23b872dd000000000000000000000000000000000000000000000000000000008d840152168a8201523060448201528360648201526064815261142981612e8e565b85613efd565b604051947f1b4103a90000000000000000000000000000000000000000000000000000000086526064358581168091036105e2576004870152608435908582168092036105e2578601526044850152606484015260e4358015158091036105e257608484015264ffffffffff6101048035828116908190036105e25760a48601526101249182359081168091036105e25760c4860152610144359384168094036105e257600085938492889660e485015261016435908401525af190811561154a5760009161151d5750604051908152f35b9450909190508684813d81116128be575b6128a88183612eaa565b810103126105e257925184939190612728612719565b503d61289e565b986128d189929a612e25565b98906126f3565b6040513d8c823e3d90fd5b9095508a81813d831161290b575b6128fb8183612eaa565b81010312610435575194386126ab565b503d6128f1565b9092508681813d8311612943575b61292a8183612eaa565b8101031261027e5751848116810361027e579138612661565b503d612920565b503461023c576003199060608236011261023c57612966612d80565b916024359167ffffffffffffffff9182841161092a5761012090843603011261023c5760443591821161023c576020610acc85856129a73660048801612dac565b505060040190613d70565b5061016060031936011261023c576129c8612d80565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c5760405191612a0183612dda565b612a09612eeb565b8352612a13612d96565b9260209384820152612a23612f15565b60408201908152612a32612f51565b9260608301938452612a42612f67565b608084015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c36011261040757604051612a7d81612e56565b64ffffffffff60c435818116810361027e57825260e435818116810361027e57888301526101043590811681036105fa57604082015260a084015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc36011261040757604051612aee81612e72565b6001600160a01b039061012435828116810361027e579387969389969383612b5f97612b2a9552610144358982015260c0860152610f4861323d565b6040519485809481937f4bc78b7300000000000000000000000000000000000000000000000000000000835260048301613737565b03925af19182156105ee578092612b7b575b5050604051908152f35b9091508282813d8311612ba4575b612b938183612eaa565b8101031261023c5750513880612b71565b503d612b89565b503461023c5761016060031936011261023c57612bc6612d80565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261023c576101443567ffffffffffffffff811161092a57612c13903690600401612dac565b5050612c1d61323d565b608435916001600160a01b0383811691811682850361028657606435926fffffffffffffffffffffffffffffffff841680940361040757612caf84612c606141ad565b9761179f6040518760209b7f23b872dd000000000000000000000000000000000000000000000000000000008d8401521660248201523060448201528360648201526064815261142981612e8e565b604051937f1b4103a90000000000000000000000000000000000000000000000000000000085526024358481168091036105fa5760048601526044358481168091036105fa5760248601526044850152606484015260a43580151580910361040757608484015260c43564ffffffffff908181168091036102825760a485015260e4359081168091036104075760c4840152610104918235908116809103610407579183858193889560e4840152610124938435908401525af19182156105ee578092612b7b575050604051908152f35b600435906001600160a01b03821682036105e257565b604435906001600160a01b03821682036105e257565b9181601f840112156105e25782359167ffffffffffffffff83116105e257602083818601950101116105e257565b60e0810190811067ffffffffffffffff821117612df657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111612df657604052565b610100810190811067ffffffffffffffff821117612df657604052565b6060810190811067ffffffffffffffff821117612df657604052565b6040810190811067ffffffffffffffff821117612df657604052565b60a0810190811067ffffffffffffffff821117612df657604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612df657604052565b602435906001600160a01b03821682036105e257565b35906001600160a01b03821682036105e257565b606435906fffffffffffffffffffffffffffffffff821682036105e257565b35906fffffffffffffffffffffffffffffffff821682036105e257565b608435906001600160a01b03821682036105e257565b60a4359081151582036105e257565b359081151582036105e257565b359064ffffffffff821682036105e257565b91908260409103126105e257604051612fad81612e72565b6020808294612fbb81612f01565b84520135910152565b67ffffffffffffffff8111612df65760051b60200190565b359067ffffffffffffffff821682036105e257565b929192612ffd82612fc4565b60409461300c86519283612eaa565b819584835260208093019160608096028501948186116105e257925b8584106130385750505050505050565b86848303126105e257848791845161304f81612e56565b61305887612f34565b8152613065838801612fdc565b83820152613074868801612f83565b86820152815201930192613028565b6020908160408183019282815285518094520193019160005b8281106130aa575050505090565b83518552938101939281019260010161309c565b9181601f840112156105e25782359167ffffffffffffffff83116105e2576020808501948460051b0101116105e257565b60806003198201126105e2576001600160a01b039160043583811681036105e2579260243590811681036105e2579167ffffffffffffffff916044358381116105e2578261313f916004016130be565b939093926064359182116105e25761315991600401612dac565b9091565b60031960609101126105e2576001600160a01b0360043581811681036105e257916024359160443590811681036105e25790565b91908110156131d15760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1813603018212156105e2570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116105e25760209260051b809284830137010190565b6001600160a01b037f00000000000000000000000089afe038714e547c29fa881029dd4b5cfb00845416301461326f57565b60046040517fbbff6135000000000000000000000000000000000000000000000000000000008152fd5b919082039182116132a657565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261332f9161332a606483612eaa565b613349565b565b908160209103126105e2575180151581036105e25790565b6040516133a7916001600160a01b031661336282612e72565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16133a161345c565b916134ba565b805190828215928315613444575b505050156133c05750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6134549350820181019101613331565b3882816133b5565b3d156134b5573d9067ffffffffffffffff8211612df657604051916134a960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184612eaa565b82523d6000602084013e565b606090565b9192901561353557508151156134ce575090565b3b156134d75790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156135485750805190602001fd5b604051907f08c379a000000000000000000000000000000000000000000000000000000000825281602080600483015282519283602484015260005b8481106135c5575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201613584565b91908110156131d15760081b0190565b356fffffffffffffffffffffffffffffffff811681036105e25790565b9061361382612fc4565b6136206040519182612eaa565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061364e8294612fc4565b0190602036910137565b3580151581036105e25790565b356001600160a01b03811681036105e25790565b61332f9092919260e060c06101208301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151602064ffffffffff918281511660a0880152015116828501520151910190602080916001600160a01b0381511684520151910152565b80518210156131d15760209160051b010190565b91908110156131d157610120020190565b61332f9092919261010060c06101408301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151604064ffffffffff918281511660a0880152826020820151168588015201511660e08501520151910190602080916001600160a01b0381511684520151910152565b602080916001600160a01b036137f282612f01565b1684520135910152565b91908110156131d15760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21813603018212156105e2570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156105e2570180359067ffffffffffffffff82116105e2576020019160608202360383136105e257565b9060208083526101208301908061014060c06001600160a01b0395868151168489015283810151151560408901526040810151968060609816888a01526fffffffffffffffffffffffffffffffff888301511660808a015260808201511660a089015261391760a0820151838a0190602080916001600160a01b0381511684520151910152565b015195610100808201528651809552019401926000905b83821061393d57505050505090565b90919293948382826139896001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019601949392019061392e565b91908110156131d15760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01813603018212156105e2570190565b9060208083526101408301908061016060e06001600160a01b0395868151168489015264ffffffffff848201511660408901526040810151966060971515888a015280888301511660808a01526fffffffffffffffffffffffffffffffff60808301511660a08a015260a08201511660c0890152613a6e60c0820151838a0190602080916001600160a01b0381511684520151910152565b015195610120808201528651809552019401926000905b838210613a9457505050505090565b9091929394838282613ae06001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b0196019493920190613a85565b90613af661323d565b7f23b872dd000000000000000000000000000000000000000000000000000000006001600160a01b03809316926080830193613b3185613665565b936060613c39818301926fffffffffffffffffffffffffffffffff95613b9987613b5a876135ec565b16613b636141ad565b9a613b936040518560209e8f9e8f8401521660248201523060448201528360648201526064815261142981612e8e565b88613efd565b613c196040519a8b987fbf061d0a000000000000000000000000000000000000000000000000000000008a528a60048b0152613c0e6101248b019885613bde88612f01565b1660248d0152613bef8d8801612f76565b151560448d015285613c0360408901612f01565b1660648d0152612f34565b1660848a0152612f01565b1660a4870152613c2f60c4870160a083016137dd565b60e0810190613ccc565b809193610100610104880152526101448501929160005b828110613ca55750505050600083809203925af190811561154a57600091613c79575b50905090565b82813d8311613c9e575b613c8d8183612eaa565b8101031261023c5750518038613c73565b503d613c83565b9295506001919496508084613cbb829689613d1f565b019501910192879492879694613c50565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156105e257016020813591019167ffffffffffffffff82116105e25760608202360383136105e257565b64ffffffffff613d6a604080936fffffffffffffffffffffffffffffffff613d4682612f34565b16865267ffffffffffffffff613d5e60208301612fdc565b16602087015201612f83565b16910152565b907f23b872dd00000000000000000000000000000000000000000000000000000000613e7692613d9e61323d565b6001600160a01b0380911660a0840191613db783613665565b94613e9760808201916fffffffffffffffffffffffffffffffff93613ddf85613b5a866135ec565b604051998a977f21714be10000000000000000000000000000000000000000000000000000000089528960048a015261014489019683613e1e86612f01565b1660248b015264ffffffffff613e358c8701612f83565b1660448b0152613e4760408601612f76565b151560648b0152613e6b60609785613e608a8901612f01565b1660848d0152612f34565b1660a48a0152612f01565b1660c4870152613e8c60e4870160c083016137dd565b610100810190613ccc565b809193610120610124880152526101648501929160005b828110613ed65750505050600083809203925af190811561154a57600091613c795750905090565b9295506001919496508084613eec829689613d1f565b019501910192879492879694613eae565b91906001600160a01b039283821690604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701528116918260248701526020958681604481855afa801561154a57869160009161409f575b5010613f6c575b505050505050565b60008060405196613fee88613fc28b8201937f095ea7b3000000000000000000000000000000000000000000000000000000009889865260248401602090939291936001600160a01b0360408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018a5289612eaa565b87519082855af190613ffe61345c565b8261406c575b5081614061575b5015614018575b80613f64565b60405194850152602484015260006044840152604483526080830183811067ffffffffffffffff821117612df6576140579361332a9160405282613349565b3880808080614012565b90503b15153861400b565b809192505190878215928315614087575b5050509038614004565b6140979350820181019101613331565b38878161407d565b91508782813d83116140c8575b6140b68183612eaa565b8101031261023c575085905138613f5d565b503d6140ac565b91908110156131d15760051b0190565b9190916140eb83613609565b9260005b8181106140fb57505050565b6001600160a01b03614111611c598385876140cf565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa9182156141a35750600091614172575b506001925061416b8288613712565b52016140ef565b919282813d831161419c575b6141888183612eaa565b8101031261023c575090600191513861415c565b503d61417e565b513d6000823e3d90fd5b6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481305afa90811561154a576000916141ee575090565b6020813d8211614224575b8161420660209383612eaa565b8101031261092a5751906001600160a01b038216820361023c575090565b3d91506141f9565b909160005b81811061423e5750505050565b6001600160a01b03614254611c598385886140cf565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa9182156141a357506000916142d8575b50600192506142bc6142d2916142b58488613712565b5190613299565b6142ca611c5984878a6140cf565b610d126141ad565b01614231565b919282813d8311614304575b6142ee8183612eaa565b8101031261023c575051600191906142bc61429f565b503d6142e4565b6001600160a01b031660409081517f70a08231000000000000000000000000000000000000000000000000000000008082526000903060048401526020908184602481885afa938415614496578394614467575b50843b156104355785517fd0e30db00000000000000000000000000000000000000000000000000000000081528381600481348a5af1801561445d5761444a575b508190602487518097819382523060048301525afa91821561443f579161440f575b506143cd9250613299565b903482036143d9575050565b6044925051907fe5f762580000000000000000000000000000000000000000000000000000000082523460048301526024820152fd5b905082813d8311614438575b6144258183612eaa565b810103126105e2576143cd9151386143c2565b503d61441b565b8551903d90823e3d90fd5b92614456839294612e25565b92906143a0565b87513d86823e3d90fd5b9093508181813d831161448f575b61447f8183612eaa565b810103126104355751923861435f565b503d614475565b86513d85823e3d90fd
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.