Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
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].
*
* CAUTION: See Security Considerations above.
*/
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);
}
"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// 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);
}
"
},
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (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. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
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));
}
}
"
},
"@openzeppelin/contracts/utils/Address.sol": {
"content": "// 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);
}
}
}
"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
"
},
"@openzeppelin/contracts/utils/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 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 {
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) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// 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;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// 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 + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
"
},
"contracts/diamond/DiamondLib.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;
import { IAccessControl } from "../interfaces/IAccessControl.sol";
import { IDiamondCut } from "../interfaces/diamond/IDiamondCut.sol";
/**
* @title DiamondLib
*
* @notice Provides Diamond storage slot and supported interface checks.
*
* @notice Based on Nick Mudge's gas-optimized diamond-2 reference,
* with modifications to support role-based access and management of
* supported interfaces. Also added copious code comments throughout.
*
* Reference Implementation : https://github.com/mudgen/diamond-2-hardhat
* EIP-2535 Diamond Standard : https://eips.ethereum.org/EIPS/eip-2535
*
* N.B. Facet management functions from original `DiamondLib` were refactored/extracted
* to JewelerLib, since business facets also use this library for access control and
* managing supported interfaces.
*
* @author Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
* @author Cliff Hall <cliff@futurescale.com> (https://twitter.com/seaofarrows)
*/
library DiamondLib {
bytes32 internal constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
struct DiamondStorage {
// Maps function selectors to the facets that execute the functions
// and maps the selectors to their position in the selectorSlots array.
// func selector => address facet, selector position
mapping(bytes4 => bytes32) facets;
// Array of slots of function selectors.
// Each slot holds 8 function selectors.
mapping(uint256 => bytes32) selectorSlots;
// The number of function selectors in selectorSlots
uint16 selectorCount;
// Used to query if a contract implement is an interface.
// Used to implement ERC-165.
mapping(bytes4 => bool) supportedInterfaces;
// The Boson Protocol AccessController
IAccessControl accessController;
}
/**
* @notice Gets the Diamond storage slot.
*
* @return ds - Diamond storage slot cast to DiamondStorage
*/
function diamondStorage() internal pure returns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot := position
}
}
/**
* @notice Adds a supported interface to the Diamond.
*
* @param _interfaceId - the interface to add
*/
function addSupportedInterface(bytes4 _interfaceId) internal {
// Get the DiamondStorage struct
DiamondStorage storage ds = diamondStorage();
// Flag the interfaces as supported
ds.supportedInterfaces[_interfaceId] = true;
}
/**
* @notice Removes a supported interface from the Diamond.
*
* @param _interfaceId - the interface to remove
*/
function removeSupportedInterface(bytes4 _interfaceId) internal {
// Get the DiamondStorage struct
DiamondStorage storage ds = diamondStorage();
// Flag the interfaces as unsupported
ds.supportedInterfaces[_interfaceId] = false;
}
/**
* @notice Checks if a specific interface is supported.
* Implementation of ERC-165 interface detection standard.
*
* @param _interfaceId - the sighash of the given interface
* @return - whether or not the interface is supported
*/
function supportsInterface(bytes4 _interfaceId) internal view returns (bool) {
// Get the DiamondStorage struct
DiamondStorage storage ds = diamondStorage();
// Return the value
return ds.supportedInterfaces[_interfaceId];
}
}
"
},
"contracts/domain/BosonConstants.sol": {
"content": "import "./BosonTypes.sol";
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
// Access Control Roles
bytes32 constant ADMIN = keccak256("ADMIN"); // Role Admin
bytes32 constant PAUSER = keccak256("PAUSER"); // Role for pausing the protocol
bytes32 constant PROTOCOL = keccak256("PROTOCOL"); // Role for facets of the ProtocolDiamond
bytes32 constant CLIENT = keccak256("CLIENT"); // Role for clients of the ProtocolDiamond
bytes32 constant UPGRADER = keccak256("UPGRADER"); // Role for performing contract and config upgrades
bytes32 constant FEE_COLLECTOR = keccak256("FEE_COLLECTOR"); // Role for collecting fees from the protocol
// Generic
uint256 constant HUNDRED_PERCENT = 10000; // 100% in basis points
uint256 constant PROTOCOL_ENTITY_ID = 0; // Entity ID for the protocol itself
uint256 constant VOIDED_OFFER_ID = type(uint256).max; // Offer ID for voided non-listed offers
// Pause Handler
uint256 constant ALL_REGIONS_MASK = (1 << (uint256(type(BosonTypes.PausableRegion).max) + 1)) - 1;
// Reentrancy guard
uint256 constant NOT_ENTERED = 1;
uint256 constant ENTERED = 2;
// Twin handler
uint256 constant SINGLE_TWIN_RESERVED_GAS = 160000;
uint256 constant MINIMAL_RESIDUAL_GAS = 230000;
// Config related
bytes32 constant VOUCHER_PROXY_SALT = keccak256(abi.encodePacked("BosonVoucherProxy"));
// Funds related
string constant NATIVE_CURRENCY = "Native currency";
string constant TOKEN_NAME_UNSPECIFIED = "Token name unavailable";
// EIP712Lib
string constant PROTOCOL_NAME = "Boson Protocol";
string constant PROTOCOL_VERSION = "V2";
bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256(
bytes("EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)")
);
uint256 constant SLOT_SIZE = 32; // Size of a slot in bytes, used for encoding and decoding
// BosonVoucher
string constant VOUCHER_NAME = "Boson Voucher (rNFT)";
string constant VOUCHER_SYMBOL = "BOSON_VOUCHER_RNFT";
// Meta Transactions - Error
string constant FUNCTION_CALL_NOT_SUCCESSFUL = "Function call not successful";
// External contracts errors
string constant OWNABLE_ZERO_ADDRESS = "Ownable: new owner is the zero address"; // exception message from OpenZeppelin Ownable
string constant ERC721_INVALID_TOKEN_ID = "ERC721: invalid token ID"; // exception message from OpenZeppelin ERC721
// Meta Transactions - Structs
bytes32 constant META_TRANSACTION_TYPEHASH = keccak256(
bytes(
"MetaTransaction(uint256 nonce,address from,address contractAddress,string functionName,bytes functionSignature)"
)
);
bytes32 constant OFFER_DETAILS_TYPEHASH = keccak256("MetaTxOfferDetails(address buyer,uint256 offerId)");
bytes32 constant META_TX_COMMIT_TO_OFFER_TYPEHASH = keccak256(
"MetaTxCommitToOffer(uint256 nonce,address from,address contractAddress,string functionName,MetaTxOfferDetails offerDetails)MetaTxOfferDetails(address buyer,uint256 offerId)"
);
bytes32 constant CONDITIONAL_OFFER_DETAILS_TYPEHASH = keccak256(
"MetaTxConditionalOfferDetails(address buyer,uint256 offerId,uint256 tokenId)"
);
bytes32 constant META_TX_COMMIT_TO_CONDITIONAL_OFFER_TYPEHASH = keccak256(
"MetaTxCommitToConditionalOffer(uint256 nonce,address from,address contractAddress,string functionName,MetaTxConditionalOfferDetails offerDetails)MetaTxConditionalOfferDetails(address buyer,uint256 offerId,uint256 tokenId)"
);
bytes32 constant EXCHANGE_DETAILS_TYPEHASH = keccak256("MetaTxExchangeDetails(uint256 exchangeId)");
bytes32 constant META_TX_EXCHANGE_TYPEHASH = keccak256(
"MetaTxExchange(uint256 nonce,address from,address contractAddress,string functionName,MetaTxExchangeDetails exchangeDetails)MetaTxExchangeDetails(uint256 exchangeId)"
);
bytes32 constant FUND_DETAILS_TYPEHASH = keccak256(
"MetaTxFundDetails(uint256 entityId,address[] tokenList,uint256[] tokenAmounts)"
);
bytes32 constant META_TX_FUNDS_TYPEHASH = keccak256(
"MetaTxFund(uint256 nonce,address from,address contractAddress,string functionName,MetaTxFundDetails fundDetails)MetaTxFundDetails(uint256 entityId,address[] tokenList,uint256[] tokenAmounts)"
);
bytes32 constant DISPUTE_RESOLUTION_DETAILS_TYPEHASH = keccak256(
"MetaTxDisputeResolutionDetails(uint256 exchangeId,uint256 buyerPercentBasisPoints,bytes signature)"
);
bytes32 constant META_TX_DISPUTE_RESOLUTIONS_TYPEHASH = keccak256(
"MetaTxDisputeResolution(uint256 nonce,address from,address contractAddress,string functionName,MetaTxDisputeResolutionDetails disputeResolutionDetails)MetaTxDisputeResolutionDetails(uint256 exchangeId,uint256 buyerPercentBasisPoints,bytes signature)"
);
// Function names
string constant COMMIT_TO_OFFER = "commitToOffer(address,uint256)";
string constant COMMIT_TO_CONDITIONAL_OFFER = "commitToConditionalOffer(address,uint256,uint256)";
string constant CANCEL_VOUCHER = "cancelVoucher(uint256)";
string constant REDEEM_VOUCHER = "redeemVoucher(uint256)";
string constant COMPLETE_EXCHANGE = "completeExchange(uint256)";
string constant WITHDRAW_FUNDS = "withdrawFunds(uint256,address[],uint256[])";
string constant RETRACT_DISPUTE = "retractDispute(uint256)";
string constant RAISE_DISPUTE = "raiseDispute(uint256)";
string constant ESCALATE_DISPUTE = "escalateDispute(uint256)";
string constant RESOLVE_DISPUTE = "resolveDispute(uint256,uint256,bytes)";
"
},
"contracts/domain/BosonErrors.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
import { BosonTypes } from "./BosonTypes.sol";
interface BosonErrors {
// Pause related
// Trying to unpause a protocol when it's not paused
error NotPaused();
// Whenever a region is paused, and a method from that region is called
error RegionPaused(BosonTypes.PausableRegion region);
// General
// Input parameter of type address is zero address
error InvalidAddress();
// Exchange or dispute is in different state than expected when certain action is called
error InvalidState();
// Two or more array parameters with different lengths
error ArrayLengthMismatch();
// Array elements that are not in ascending order (i.e arr[i-1] > arr[i])
error NonAscendingOrder();
// Called contract returned an unexpected value
error UnexpectedDataReturned(bytes data);
// Reentrancy guard
// Reentrancy guard is active and second call to protocol is made
error ReentrancyGuard();
// Protocol initialization related
// Trying to initialize the facet when it's already initialized
error AlreadyInitialized(); // ToDo consider adding the facet to the error message
// Initialization of some facet failed
error ProtocolInitializationFailed(); // ToDo consider adding the facet to the error message
// Trying to initialize the protocol with empty version
error VersionMustBeSet();
// Length of _addresses and _calldata arrays do not match
error AddressesAndCalldataLengthMismatch(); // ToDo consider reusing ArrayLengthMismatch
// The new protocol version is not subsequent to the current one
error WrongCurrentVersion();
// Initialization can be done only through proxy
error DirectInitializationNotAllowed();
// Initialization of v2.3.0 can be done only if not twin exists
error TwinsAlreadyExist();
// Access related
// ToDo consider having a single error, with a parameter for the role
// Caller is not authorized to call the method
error AccessDenied();
// Caller is not entitiy's assistant
error NotAssistant();
// Caller is not entitiy's admin
error NotAdmin();
// Caller is not entitiy's admin and assistant
error NotAdminAndAssistant();
// Caller is neither the buyer or the seller involved in the exchange
error NotBuyerOrSeller();
// Caller is not the owner of the voucher
error NotVoucherHolder();
// Caller is not the buyer
error NotBuyerWallet();
// Caller is not the agent
error NotAgentWallet();
// Caller is not dispute resolver assistant
error NotDisputeResolverAssistant();
// Caller is not the creator of the offer
error NotOfferCreator();
// Supplied clerk is not zero address
error ClerkDeprecated();
// Account-related
// Entity must be active
error MustBeActive();
// Seller's address cannot be already used in another seller
error SellerAddressMustBeUnique();
// Buyer's address cannot be already used in another buyer
error BuyerAddressMustBeUnique();
// DR's address cannot be already used in another DR
error DisputeResolverAddressMustBeUnique();
// Agent's address cannot be already used in another agent
error AgentAddressMustBeUnique();
// Seller does not exist
error NoSuchSeller();
// Buyer does not exist
error NoSuchBuyer();
// Dispute resolver does not exist
error NoSuchDisputeResolver();
// Agent does not exist
error NoSuchAgent();
// Entity does not exist
error NoSuchEntity();
// Buyer is involved in an non-finalized exchange
error WalletOwnsVouchers();
// Escalation period is not greater than zero or is more than the max allowed
error InvalidEscalationPeriod();
// Action would remove the last supported fee from the DR (must always have at least one)
error InexistentDisputeResolverFees();
// Trying to add a fee that already exists
error DuplicateDisputeResolverFees();
// Trying to remove a fee that does not exist
error DisputeResolverFeeNotFound();
// Trying to approve a seller that is already approved (list of sellers that DR will handle disputes for)
error SellerAlreadyApproved();
// Trying to assing a DR that had not approved the seller
error SellerNotApproved();
// Trying to add or removed 0 sellers
error InexistentAllowedSellersList();
// Custom auth token is not yet supported
error InvalidAuthTokenType();
// Seller must use either and address or auth token for authentication, but not both
error AdminOrAuthToken();
// A single auth token can only be used by one seller
error AuthTokenMustBeUnique();
// Sum of protocol and agent fee exceed the max allowed fee
error InvalidAgentFeePercentage();
// Trying to finalize the update, while it's not even started
error NoPendingUpdateForAccount();
// Only the account itself can finalize the update
error UnauthorizedCallerUpdate();
// Trying to update the account with the same values
error NoUpdateApplied();
// Creating a seller's collection failed
error CloneCreationFailed();
// Seller's salt is already used by another seller
error SellerSaltNotUnique();
// Offer related
// Offer does not exist
error NoSuchOffer();
// Offer parameters are invalid
error InvalidOffer();
// Collection index is invalid for the context
error InvalidCollectionIndex();
// Offer finishes in the past or it starts after it finishes
error InvalidOfferPeriod();
// Buyer cancellation penalty is higher than the item price
error InvalidOfferPenalty();
// New offer must be actiove
error OfferMustBeActive();
// Offer can be added to same group only once
error OfferMustBeUnique();
// Offer has been voided
error OfferHasBeenVoided();
// Current timestamp is higher than offer's expiry timestamp
error OfferHasExpired();
// Current timestamp is lower than offer's start timestamp
error OfferNotAvailable();
// Offer's quantity available is zero
error OfferSoldOut();
// Buyer is not allowed to commit to the offer (does not meet the token gating requirements)
error CannotCommit();
// Bundle cannot be created since exchganes for offer exist already
error ExchangeForOfferExists();
// Buyer-initiated offer cannot have seller-specific fields (sellerId, collectionIndex, royaltyInfo)
error InvalidBuyerOfferFields();
// Seller-initiated offer cannot have buyer-specific fields (buyerId, quantityAvailable)
error InvalidSellerOfferFields();
// Buyer cannot provide seller parameters when committing to an offer
error SellerParametersNotAllowed();
// Invalid offer creator value specified
error InvalidOfferCreator();
// Voucher must have either a fixed expiry or a fixed redeemable period, not both
error AmbiguousVoucherExpiry();
// Redemption period starts after it ends or it ends before offer itself expires
error InvalidRedemptionPeriod();
// Dispute period is less than minimal dispute period allowed
error InvalidDisputePeriod();
// Resolution period is not within the allowed range or it's being misconfigured (minimal > maximal)
error InvalidResolutionPeriod();
// Dispute resolver does not exist or is not active
error InvalidDisputeResolver();
// Quantity available is zero
error InvalidQuantityAvailable();
// Chose DR does not support the fees in the chosen exchange token
error DRUnsupportedFee();
// Sum of protocol and agent fee exceeds the max allowed fee
error AgentFeeAmountTooHigh();
// Sum of protocol and agent fee exceeds the seller defined max fee
error TotalFeeExceedsLimit();
// Collection does not exist
error NoSuchCollection();
// Royalty recipient is not allow listed for the seller
error InvalidRoyaltyRecipient();
// Total royality fee exceeds the max allowed
error InvalidRoyaltyPercentage();
// Specified royalty recipient already added
error RecipientNotUnique();
// Trying to access an out of bounds royalty recipient
error InvalidRoyaltyRecipientId();
// Array of royalty recipients is not sorted by id
error RoyaltyRecipientIdsNotSorted();
// Trying to remove the default recipient (treasury)
error CannotRemoveDefaultRecipient();
// Supplying too many Royalty info structs
error InvalidRoyaltyInfo();
// Trying to change the default recipient address (treasury)
error WrongDefaultRecipient();
// Price discovery offer has non zero price
error InvalidPriceDiscoveryPrice();
// Trying to set the same mutualizer as the existing one
error SameMutualizerAddress();
// Group related
// Group does not exist
error NoSuchGroup();
// Offer is not in a group
error OfferNotInGroup();
// Group remains the same
error NothingUpdated();
// There is a logical error in the group's condition parameters or it's not supported yet
error InvalidConditionParameters();
// Group does not have a condition
error GroupHasNoCondition();
// Group has a condition
error GroupHasCondition();
// User exhaused the number of commits allowed for the group
error MaxCommitsReached();
// The supplied token id is outside the condition's range
error TokenIdNotInConditionRange();
// ERC20 and ERC721 require zero token id
error InvalidTokenId();
// Exchange related
// Exchange does not exist
error NoSuchExchange();
// Exchange cannot be completed yet
error DisputePeriodNotElapsed();
// Current timestamp is outside the voucher's redeemable period
error VoucherNotRedeemable();
// New expiration date is earlier than existing expiration date
error VoucherExtensionNotValid();
// Voucher cannot be expired yet
error VoucherStillValid();
// Voucher has expired and cannot be transferred anymore
error VoucherHasExpired();
// Exchange has not been finalized yet
error ExchangeIsNotInAFinalState();
// Exchange with the same id already exists
error ExchangeAlreadyExists();
// Range length is 0, is more than quantity available or it would cause an overflow
error InvalidRangeLength();
// Exchange is being finalized into an invalid state
error InvalidTargeExchangeState();
// Twin related
// Twin does not exist
error NoSuchTwin();
// Seller did not approve the twin transfer
error NoTransferApproved();
// Twin transfer failed
error TwinTransferUnsuccessful();
// Token address is 0 or it does not implement the required interface
error UnsupportedToken();
// Twin cannot be removed if it's in a bundle
error BundleForTwinExists();
// Supply available is zero
error InvalidSupplyAvailable();
// Twin is Fungible or Multitoken and amount was set
error InvalidAmount();
// Twin is NonFungible and amount was not set
error InvalidTwinProperty(); // ToDo consider replacing with InvalidAmount
// Token range overlap with another, starting token id is too high or end of range would overflow
error InvalidTwinTokenRange();
// Token does not support IERC721 interface
error InvalidTokenAddress();
// Bundle related
// Bundle does not exist
error NoSuchBundle();
// Twin is not in a bundle
error TwinNotInBundle();
// Offer is not in a bundle
error OfferNotInBundle();
// Offer can appear in a bundle only once
error BundleOfferMustBeUnique();
// Twin can appear in a bundle only once
error BundleTwinMustBeUnique();
// Twin supply does not covver all offers in the bundle
error InsufficientTwinSupplyToCoverBundleOffers();
// Bundle cannot be created without an offer or a twin
error BundleRequiresAtLeastOneTwinAndOneOffer();
// Funds related
// Native token must be represented with zero address
error NativeWrongAddress();
// Amount sent along (msg.value) does not match the expected amount
error NativeWrongAmount();
// Token list lenght does not match the amount list length
error TokenAmountMismatch(); // ToDo consider replacing with ArrayLengthMismatch
// Token list is empty
error NothingToWithdraw();
// Call is not allowed to transfer the funds
error NotAuthorized();
// Token transfer failed
error TokenTransferFailed();
// Received amount does not match the expected amount
error InsufficientValueReceived();
// Seller's pool does not have enough funds to encumber
error InsufficientAvailableFunds();
// Native token was sent when ERC20 was expected
error NativeNotAllowed();
// Trying to deposit zero amount
error ZeroDepositNotAllowed();
// DR Fee related
// DR fee mutualizer cannot provide coverage for the fee
error DRFeeMutualizerCannotProvideCoverage();
// Meta-Transactions related
// Meta-transaction nonce is invalid
error NonceUsedAlready();
// Function signature does not match it's name
error InvalidFunctionName();
// Signature has invalid parameters
error InvalidSignature();
// Function is not allowed to be executed as a meta-transaction
error FunctionNotAllowlisted();
// Signer does not match the expected one or ERC1271 signature is not valid
error SignatureValidationFailed();
// Dispute related
// Dispute cannot be raised since the period to do it has elapsed
error DisputePeriodHasElapsed();
// Mutualizer address does not implement the required interface
error UnsupportedMutualizer();
// Dispute cannot be resolved anymore and must be finalized with expireDispute
error DisputeHasExpired();
// Buyer gets more than 100% of the total pot
error InvalidBuyerPercent();
// Dispute is still valid and cannot be expired yet
error DisputeStillValid();
// New dispute timeout is earlier than existing dispute timeout
error InvalidDisputeTimeout();
// Absolute zero offers cannot be escalated
error EscalationNotAllowed();
// Dispute is being finalized into an invalid state
error InvalidTargeDisputeState();
// Config related
// Percentage exceeds 100%
error InvalidFeePercentage();
// Zero config value is not allowed
error ValueZeroNotAllowed();
// BosonVoucher
// Trying to issue an voucher that is in a reseverd range
error ExchangeIdInReservedRange();
// Trying to premint vouchers for an offer that does not have a reserved range
error NoReservedRangeForOffer();
// Trying to reserve a range that is already reserved
error OfferRangeAlreadyReserved();
// Range start at 0 is not allowed
error InvalidRangeStart();
// Amount to premint exceeds the range length
error InvalidAmountToMint();
// Trying to silent mint vouchers not belonging to the range owner
error NoSilentMintAllowed();
// Trying to premint the voucher of already expired offer
error OfferExpiredOrVoided();
// Trying to burn preminted vouchers of still valid offer
error OfferStillValid();
// Trying to burn more vouchers than available
error AmountExceedsRangeOrNothingToBurn();
// Royalty fee exceeds the max allowed
error InvalidRoyaltyFee();
// Trying to assign the premined vouchers to the address that is neither the contract owner nor the contract itself
error InvalidToAddress();
// Call to an external contract was not successful
error ExternalCallFailed();
// Trying to interact with external contract in a way that could result in transferring assets from the contract
error InteractionNotAllowed();
// Price discovery related
// Price discovery returned a price that does not match the expected one
error PriceMismatch();
// Token id is mandatory for bid orders and wrappers
error TokenIdMandatory();
// Incoming token id does not match the expected one
error TokenIdMismatch();
// Using price discovery for non-price discovery offer or using ordinary commit for price discovery offer
error InvalidPriceType();
// Missing price discovery contract address or data
error InvalidPriceDiscovery();
// Trying to set incoming voucher when it's already set, indicating reentrancy
error IncomingVoucherAlreadySet();
// Conduit address must be zero ()
error InvalidConduitAddress();
// Protocol does not know what token id to use
error TokenIdNotSet();
// Transferring a preminted voucher to wrong recipient
error VoucherTransferNotAllowed();
// Price discovery contract returned a negative price
error NegativePriceNotAllowed();
// Price discovery did not send the voucher to the protocol
error VoucherNotReceived();
// Price discovery did not send the voucher from the protocol
error VoucherNotTransferred();
// Either token with wrong id received or wrong voucher contract made the transfer
error UnexpectedERC721Received();
// Royalty fee exceeds the price
error FeeAmountTooHigh();
// Price does not cover the cancellation penalty
error PriceDoesNotCoverPenalty();
// Fee Table related
// Thrown if asset is not supported in feeTable feature.
error FeeTableAssetNotSupported();
}
"
},
"contracts/domain/BosonTypes.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;
/**
* @title BosonTypes
*
* @notice Enums and structs used by the B
Submitted on: 2025-10-23 19:22:39
Comments
Log in to comment.
No comments yet.