Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {UnsafeMath} from '../UnsafeMath.sol';
using UnsafeMath for int256;
type I256 is int256;
using {
add as +,
sub as -,
mul as *,
div as /,
mod as %,
neq as !=,
eq as ==,
lt as <,
lte as <=,
gt as >,
gte as >=,
and as &,
or as |,
xor as ^,
not as ~
} for I256 global;
function add(I256 _i256, I256 _addend) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256).add(I256.unwrap(_addend)));
}
function sub(I256 _i256, I256 _subtrahend) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256).sub(I256.unwrap(_subtrahend)));
}
function mul(I256 _i256, I256 _multiplier) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256).mul(I256.unwrap(_multiplier)));
}
function div(I256 _i256, I256 _divisor) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256).div(I256.unwrap(_divisor)));
}
function mod(I256 _i256, I256 _divisor) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256).mod(I256.unwrap(_divisor)));
}
function and(I256 _i256, I256 _mask) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256) & I256.unwrap(_mask));
}
function or(I256 _i256, I256 _mask) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256) | I256.unwrap(_mask));
}
function xor(I256 _i256, I256 _mask) pure returns (I256) {
return I256.wrap(I256.unwrap(_i256) ^ I256.unwrap(_mask));
}
function not(I256 _i256) pure returns (I256) {
return I256.wrap(~I256.unwrap(_i256));
}
function neq(I256 _i256, I256 _bounds) pure returns (bool) {
return I256.unwrap(_i256) != I256.unwrap(_bounds);
}
function eq(I256 _i256, I256 _bounds) pure returns (bool) {
return I256.unwrap(_i256) == I256.unwrap(_bounds);
}
function lt(I256 _i256, I256 _bounds) pure returns (bool) {
return I256.unwrap(_i256) < I256.unwrap(_bounds);
}
function lte(I256 _i256, I256 _bounds) pure returns (bool) {
return I256.unwrap(_i256) <= I256.unwrap(_bounds);
}
function gt(I256 _i256, I256 _bounds) pure returns (bool) {
return I256.unwrap(_i256) > I256.unwrap(_bounds);
}
function gte(I256 _i256, I256 _bounds) pure returns (bool) {
return I256.unwrap(_i256) >= I256.unwrap(_bounds);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {UnsafeMath} from '../UnsafeMath.sol';
using UnsafeMath for uint256;
type U256 is uint256;
using {
add as +,
sub as -,
mul as *,
div as /,
mod as %,
neq as !=,
eq as ==,
lt as <,
lte as <=,
gt as >,
gte as >=,
and as &,
or as |,
xor as ^,
not as ~
} for U256 global;
function add(U256 _u256, U256 _addend) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256).add(U256.unwrap(_addend)));
}
function sub(U256 _u256, U256 _subtrahend) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256).sub(U256.unwrap(_subtrahend)));
}
function mul(U256 _u256, U256 _multiplier) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256).mul(U256.unwrap(_multiplier)));
}
function div(U256 _u256, U256 _divisor) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256).div(U256.unwrap(_divisor)));
}
function mod(U256 _u256, U256 _divisor) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256).mod(U256.unwrap(_divisor)));
}
function and(U256 _u256, U256 _mask) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256) & U256.unwrap(_mask));
}
function or(U256 _u256, U256 _mask) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256) | U256.unwrap(_mask));
}
function xor(U256 _u256, U256 _mask) pure returns (U256) {
return U256.wrap(U256.unwrap(_u256) ^ U256.unwrap(_mask));
}
function not(U256 _u256) pure returns (U256) {
return U256.wrap(~U256.unwrap(_u256));
}
function neq(U256 _u256, U256 _bounds) pure returns (bool) {
return U256.unwrap(_u256) != U256.unwrap(_bounds);
}
function eq(U256 _u256, U256 _bounds) pure returns (bool) {
return U256.unwrap(_u256) == U256.unwrap(_bounds);
}
function lt(U256 _u256, U256 _bounds) pure returns (bool) {
return U256.unwrap(_u256) < U256.unwrap(_bounds);
}
function lte(U256 _u256, U256 _bounds) pure returns (bool) {
return U256.unwrap(_u256) <= U256.unwrap(_bounds);
}
function gt(U256 _u256, U256 _bounds) pure returns (bool) {
return U256.unwrap(_u256) > U256.unwrap(_bounds);
}
function gte(U256 _u256, U256 _bounds) pure returns (bool) {
return U256.unwrap(_u256) >= U256.unwrap(_bounds);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// solhint-disable func-name-mixedcase
import {I256} from './types/I256.sol';
import {U256} from './types/U256.sol';
library UnsafeMath {
/*********************
* uint256 ->
*********************/
/// @dev Returns the addition of two unsigned integers
/// @param _uint256 The first unsigned integer
/// @param _addend The second unsigned integer
/// @return The addition of the two unsigned integers
function add(uint256 _uint256, uint256 _addend) internal pure returns (uint256) {
unchecked {
return _uint256 + _addend;
}
}
/// @dev Returns the subtraction of two unsigned integers
/// @param _uint256 The first unsigned integer
/// @param _subtrahend The second unsigned integer
/// @return The subtraction of the two unsigned integers
function sub(uint256 _uint256, uint256 _subtrahend) internal pure returns (uint256) {
unchecked {
return _uint256 - _subtrahend;
}
}
/// @dev Increments an unsigned integer by one
/// @param _uint256 The unsigned integer
/// @return The incremented unsigned integer
function inc(uint256 _uint256) internal pure returns (uint256) {
unchecked {
return ++_uint256;
}
}
/// @dev Decrements an unsigned integer by one
/// @param _uint256 The unsigned integer
/// @return The decremented unsigned integer
function dec(uint256 _uint256) internal pure returns (uint256) {
unchecked {
return --_uint256;
}
}
/// @dev Returns the multiplication of two unsigned integers
/// @param _uint256 The first unsigned integer
/// @param _multiplier The second unsigned integer
/// @return The multiplication of the two unsigned integers
function mul(uint256 _uint256, uint256 _multiplier) internal pure returns (uint256) {
unchecked {
return _uint256 * _multiplier;
}
}
/// @dev Returns the exponentiation of two unsigned integers
/// @param _uint256 The first unsigned integer
/// @param _exponent The second unsigned integer
/// @return The exponentiation of the two unsigned integers
function exp(uint256 _uint256, uint256 _exponent) internal pure returns (uint256) {
uint256 result;
// solhint-disable-next-line no-inline-assembly
assembly {
result := exp(_uint256, _exponent)
}
return result;
}
/// @dev Returns the division of two unsigned integers
/// @param _uint256 The first unsigned integer
/// @param _divisor The second unsigned integer
/// @return The division of the two unsigned integers
function div(uint256 _uint256, uint256 _divisor) internal pure returns (uint256) {
uint256 result;
// solhint-disable-next-line no-inline-assembly
assembly {
result := div(_uint256, _divisor)
}
return result;
}
/// @dev Returns the remainder of the division of two unsigned integers
/// @param _uint256 The first unsigned integer
/// @param _divisor The second unsigned integer
/// @return The remainder of the division of the two unsigned integers
function mod(uint256 _uint256, uint256 _divisor) internal pure returns (uint256) {
uint256 result;
// solhint-disable-next-line no-inline-assembly
assembly {
result := mod(_uint256, _divisor)
}
return result;
}
/*********************
* int256 ->
*********************/
/// @dev Returns the addition of two signed integers
/// @param _int256 The first signed integer
/// @param _addend The second signed integer
/// @return The addition of the two signed integers
function add(int256 _int256, int256 _addend) internal pure returns (int256) {
unchecked {
return _int256 + _addend;
}
}
/// @dev Returns the subtraction of two signed integers
/// @param _int256 The first signed integer
/// @param _subtrahend The second signed integer
/// @return The subtraction of the two signed integers
function sub(int256 _int256, int256 _subtrahend) internal pure returns (int256) {
unchecked {
return _int256 - _subtrahend;
}
}
/// @dev Increments a signed integer by one
/// @param _int256 The signed integer
/// @return The incremented signed integer
function inc(int256 _int256) internal pure returns (int256) {
unchecked {
return ++_int256;
}
}
/// @dev Decrements a signed integer by one
/// @param _int256 The signed integer
/// @return The decremented signed integer
function dec(int256 _int256) internal pure returns (int256) {
unchecked {
return --_int256;
}
}
/// @dev Returns the multiplication of two signed integers
/// @param _int256 The first signed integer
/// @param _multiplier The second signed integer
/// @return The multiplication of the two signed integers
function mul(int256 _int256, int256 _multiplier) internal pure returns (int256) {
unchecked {
return _int256 * _multiplier;
}
}
/// @dev Returns the division of two signed integers
/// @param _int256 The first signed integer
/// @param _divisor The second signed integer
/// @return The division of the two signed integers
function div(int256 _int256, int256 _divisor) internal pure returns (int256) {
int256 result;
// solhint-disable-next-line no-inline-assembly
assembly {
result := sdiv(_int256, _divisor)
}
return result;
}
/// @dev Returns the remainder of the division of two signed integers
/// @param _int256 The first signed integer
/// @param _divisor The second signed integer
/// @return The remainder of the division of the two signed integers
function mod(int256 _int256, int256 _divisor) internal pure returns (int256) {
int256 result;
// solhint-disable-next-line no-inline-assembly
assembly {
result := smod(_int256, _divisor)
}
return result;
}
/*********************
* I256 ->
*********************/
/// @dev Wraps an int256 into an I256
/// @param _i256 The int256 to wrap
/// @return i256 The wrapped I256
function asI256(int256 _i256) internal pure returns (I256 i256) {
return I256.wrap(_i256);
}
/// @dev Wraps a uint256 into an I256
/// @param _i256 The uint256 to wrap
/// @return i256 The wrapped I256
function asI256(uint256 _i256) internal pure returns (I256 i256) {
return I256.wrap(int256(_i256));
}
/// @dev Converts an I256 to a signed int256
/// @param _i256 The I256 to convert
/// @return signed The signed int256
function asInt256(I256 _i256) internal pure returns (int256 signed) {
return I256.unwrap(_i256);
}
/// @dev Converts an I256 to a signed int248
/// @param _i256 The I256 to convert
/// @return signed The signed int248
function asInt248(I256 _i256) internal pure returns (int248 signed) {
return int248(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int240
/// @param _i256 The I256 to convert
/// @return signed The signed int240
function asInt240(I256 _i256) internal pure returns (int240 signed) {
return int240(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int232
/// @param _i256 The I256 to convert
/// @return signed The signed int232
function asInt232(I256 _i256) internal pure returns (int232 signed) {
return int232(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int224
/// @param _i256 The I256 to convert
/// @return signed The signed int224
function asInt224(I256 _i256) internal pure returns (int224 signed) {
return int224(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int216
/// @param _i256 The I256 to convert
/// @return signed The signed int216
function asInt216(I256 _i256) internal pure returns (int216 signed) {
return int216(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int208
/// @param _i256 The I256 to convert
/// @return signed The signed int208
function asInt208(I256 _i256) internal pure returns (int208 signed) {
return int208(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int200
/// @param _i256 The I256 to convert
/// @return signed The signed int200
function asInt200(I256 _i256) internal pure returns (int200 signed) {
return int200(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int192
/// @param _i256 The I256 to convert
/// @return signed The signed int192
function asInt192(I256 _i256) internal pure returns (int192 signed) {
return int192(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int184
/// @param _i256 The I256 to convert
/// @return signed The signed int184
function asInt184(I256 _i256) internal pure returns (int184 signed) {
return int184(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int176
/// @param _i256 The I256 to convert
/// @return signed The signed int176
function asInt176(I256 _i256) internal pure returns (int176 signed) {
return int176(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int168
/// @param _i256 The I256 to convert
/// @return signed The signed int168
function asInt168(I256 _i256) internal pure returns (int168 signed) {
return int168(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int160
/// @param _i256 The I256 to convert
/// @return signed The signed int160
function asInt160(I256 _i256) internal pure returns (int160 signed) {
return int160(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int152
/// @param _i256 The I256 to convert
/// @return signed The signed int152
function asInt152(I256 _i256) internal pure returns (int152 signed) {
return int152(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int144
/// @param _i256 The I256 to convert
/// @return signed The signed int144
function asInt144(I256 _i256) internal pure returns (int144 signed) {
return int144(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int136
/// @param _i256 The I256 to convert
/// @return signed The signed int136
function asInt136(I256 _i256) internal pure returns (int136 signed) {
return int136(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int128
/// @param _i256 The I256 to convert
/// @return signed The signed int128
function asInt128(I256 _i256) internal pure returns (int128 signed) {
return int128(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int120
/// @param _i256 The I256 to convert
/// @return signed The signed int120
function asInt120(I256 _i256) internal pure returns (int120 signed) {
return int120(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int112
/// @param _i256 The I256 to convert
/// @return signed The signed int112
function asInt112(I256 _i256) internal pure returns (int112 signed) {
return int112(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int104
/// @param _i256 The I256 to convert
/// @return signed The signed int104
function asInt104(I256 _i256) internal pure returns (int104 signed) {
return int104(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int96
/// @param _i256 The I256 to convert
/// @return signed The signed int96
function asInt96(I256 _i256) internal pure returns (int96 signed) {
return int96(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int88
/// @param _i256 The I256 to convert
/// @return signed The signed int88
function asInt88(I256 _i256) internal pure returns (int88 signed) {
return int88(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int80
/// @param _i256 The I256 to convert
/// @return signed The signed int80
function asInt80(I256 _i256) internal pure returns (int80 signed) {
return int80(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int72
/// @param _i256 The I256 to convert
/// @return signed The signed int72
function asInt72(I256 _i256) internal pure returns (int72 signed) {
return int72(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int64
/// @param _i256 The I256 to convert
/// @return signed The signed int64
function asInt64(I256 _i256) internal pure returns (int64 signed) {
return int64(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int56
/// @param _i256 The I256 to convert
/// @return signed The signed int56
function asInt56(I256 _i256) internal pure returns (int56 signed) {
return int56(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int48
/// @param _i256 The I256 to convert
/// @return signed The signed int48
function asInt48(I256 _i256) internal pure returns (int48 signed) {
return int48(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int40
/// @param _i256 The I256 to convert
/// @return signed The signed int40
function asInt40(I256 _i256) internal pure returns (int40 signed) {
return int40(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int32
/// @param _i256 The I256 to convert
/// @return signed The signed int32
function asInt32(I256 _i256) internal pure returns (int32 signed) {
return int32(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int24
/// @param _i256 The I256 to convert
/// @return signed The signed int24
function asInt24(I256 _i256) internal pure returns (int24 signed) {
return int24(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int16
/// @param _i256 The I256 to convert
/// @return signed The signed int16
function asInt16(I256 _i256) internal pure returns (int16 signed) {
return int16(I256.unwrap(_i256));
}
/// @dev Converts an I256 to a signed int8
/// @param _i256 The I256 to convert
/// @return signed The signed int8
function asInt8(I256 _i256) internal pure returns (int8 signed) {
return int8(I256.unwrap(_i256));
}
/// @dev Converts an I256 to an unsigned uint256
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint256
function asUint256(I256 _i256) internal pure returns (uint256 unsigned) {
return uint256(I256.unwrap(_i256));
}
/// @dev Converts an I256 to an unsigned uint248
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint248
function asUint248(I256 _i256) internal pure returns (uint248 unsigned) {
return uint248(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint240
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint240
function asUint240(I256 _i256) internal pure returns (uint240 unsigned) {
return uint240(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint232
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint232
function asUint232(I256 _i256) internal pure returns (uint232 unsigned) {
return uint232(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint224
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint224
function asUint224(I256 _i256) internal pure returns (uint224 unsigned) {
return uint224(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint216
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint216
function asUint216(I256 _i256) internal pure returns (uint216 unsigned) {
return uint216(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint208
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint208
function asUint208(I256 _i256) internal pure returns (uint208 unsigned) {
return uint208(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint200
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint200
function asUint200(I256 _i256) internal pure returns (uint200 unsigned) {
return uint200(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint192
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint192
function asUint192(I256 _i256) internal pure returns (uint192 unsigned) {
return uint192(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint184
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint184
function asUint184(I256 _i256) internal pure returns (uint184 unsigned) {
return uint184(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint176
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint176
function asUint176(I256 _i256) internal pure returns (uint176 unsigned) {
return uint176(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint168
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint168
function asUint168(I256 _i256) internal pure returns (uint168 unsigned) {
return uint168(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint160
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint160
function asUint160(I256 _i256) internal pure returns (uint160 unsigned) {
return uint160(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint152
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint152
function asUint152(I256 _i256) internal pure returns (uint152 unsigned) {
return uint152(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint144
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint144
function asUint144(I256 _i256) internal pure returns (uint144 unsigned) {
return uint144(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint136
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint136
function asUint136(I256 _i256) internal pure returns (uint136 unsigned) {
return uint136(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint128
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint128
function asUint128(I256 _i256) internal pure returns (uint128 unsigned) {
return uint128(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint120
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint120
function asUint120(I256 _i256) internal pure returns (uint120 unsigned) {
return uint120(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint112
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint112
function asUint112(I256 _i256) internal pure returns (uint112 unsigned) {
return uint112(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint104
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint104
function asUint104(I256 _i256) internal pure returns (uint104 unsigned) {
return uint104(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint96
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint96
function asUint96(I256 _i256) internal pure returns (uint96 unsigned) {
return uint96(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint88
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint88
function asUint88(I256 _i256) internal pure returns (uint88 unsigned) {
return uint88(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint80
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint80
function asUint80(I256 _i256) internal pure returns (uint80 unsigned) {
return uint80(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint72
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint72
function asUint72(I256 _i256) internal pure returns (uint72 unsigned) {
return uint72(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint64
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint64
function asUint64(I256 _i256) internal pure returns (uint64 unsigned) {
return uint64(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint56
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint56
function asUint56(I256 _i256) internal pure returns (uint56 unsigned) {
return uint56(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint48
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint48
function asUint48(I256 _i256) internal pure returns (uint48 unsigned) {
return uint48(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint40
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint40
function asUint40(I256 _i256) internal pure returns (uint40 unsigned) {
return uint40(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint32
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint32
function asUint32(I256 _i256) internal pure returns (uint32 unsigned) {
return uint32(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint24
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint24
function asUint24(I256 _i256) internal pure returns (uint24 unsigned) {
return uint24(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint16
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint16
function asUint16(I256 _i256) internal pure returns (uint16 unsigned) {
return uint16(uint256(I256.unwrap(_i256)));
}
/// @dev Converts an I256 to an unsigned uint8
/// @param _i256 The I256 to convert
/// @return unsigned The unsigned uint8
function asUint8(I256 _i256) internal pure returns (uint8 unsigned) {
return uint8(uint256(I256.unwrap(_i256)));
}
/// @dev Adds an int256 to an I256
/// @param _i256 The I256 to add to
/// @param _addend The int256 to add
/// @return i256 The result of the addition
function add(I256 _i256, int256 _addend) internal pure returns (I256 i256) {
return I256.wrap(add(I256.unwrap(_i256), _addend));
}
/// @dev Subtracts an int256 from an I256
/// @param _i256 The I256 to subtract from
/// @param _subtrahend The int256 to subtract
/// @return i256 The result of the subtraction
function sub(I256 _i256, int256 _subtrahend) internal pure returns (I256 i256) {
return I256.wrap(sub(I256.unwrap(_i256), _subtrahend));
}
/// @dev Increments an I256
/// @param _i256 The I256 to increment
/// @return i256 The result of the increment
function inc(I256 _i256) internal pure returns (I256 i256) {
return I256.wrap(inc(I256.unwrap(_i256)));
}
/// @dev Decrements an I256
/// @param _i256 The I256 to decrement
/// @return i256 The result of the decrement
function dec(I256 _i256) internal pure returns (I256 i256) {
return I256.wrap(dec(I256.unwrap(_i256)));
}
/// @dev Multiplies an I256 by an int256
/// @param _i256 The I256 to multiply
/// @param _multiplier The int256 to multiply by
/// @return i256 The result of the multiplication
function mul(I256 _i256, int256 _multiplier) internal pure returns (I256 i256) {
return I256.wrap(mul(I256.unwrap(_i256), _multiplier));
}
/// @dev Divides an I256 by an int256
/// @param _i256 The I256 to divide
/// @param _divisor The int256 to divide by
/// @return i256 The result of the division
function div(I256 _i256, int256 _divisor) internal pure returns (I256 i256) {
return I256.wrap(div(I256.unwrap(_i256), _divisor));
}
/// @dev Divides an I256 by an int256 and returns the remainder
/// @param _i256 The I256 to divide
/// @param _divisor The int256 to divide by
/// @return i256 The remainder of the division
function mod(I256 _i256, int256 _divisor) internal pure returns (I256 i256) {
return I256.wrap(mod(I256.unwrap(_i256), _divisor));
}
/// @dev Logical and of an I256 and an int256
/// @param _i256 The I256 to and
/// @param _value The int256 to and with
/// @return i256 The result of the and
function and(I256 _i256, int256 _value) internal pure returns (I256 i256) {
return I256.wrap(I256.unwrap(_i256) & _value);
}
/// @dev Logical or of an I256 and an int256
/// @param _i256 The I256 to or
/// @param _value The int256 to or with
/// @return i256 The result of the or
function or(I256 _i256, int256 _value) internal pure returns (I256 i256) {
return I256.wrap(I256.unwrap(_i256) | _value);
}
/// @dev Logical xor of an I256 and an int256
/// @param _i256 The I256 to xor
/// @param _value The int256 to xor with
/// @return i256 The result of the xor
function xor(I256 _i256, int256 _value) internal pure returns (I256 i256) {
return I256.wrap(I256.unwrap(_i256) ^ _value);
}
/// @dev Logical not of an I256
/// @param _i256 The I256 to not
/// @return i256 The result of the not
function not(I256 _i256) internal pure returns (I256 i256) {
return I256.wrap(~I256.unwrap(_i256));
}
/// @dev Compares an I256 to an int256 for equality
/// @param _i256 The I256 to compare
/// @param _value The int256 to compare to
/// @return equal True if the I256 and int256 are equal
function eq(I256 _i256, int256 _value) internal pure returns (bool) {
return I256.unwrap(_i256) == _value;
}
/// @dev Compares an I256 to an int256 for inequality
/// @param _i256 The I256 to compare
/// @param _value The int256 to compare to
/// @return equal True if the I256 and int256 are not equal
function neq(I256 _i256, int256 _value) internal pure returns (bool) {
return I256.unwrap(_i256) != _value;
}
/// @dev Compares an I256 to an int256 for greater than
/// @param _i256 The I256 to compare
/// @param _value The int256 to compare to
/// @return equal True if the I256 is greater than the int256
function gt(I256 _i256, int256 _value) internal pure returns (bool) {
return I256.unwrap(_i256) > _value;
}
/// @dev Compares an I256 to an int256 for greater than or equal to
/// @param _i256 The I256 to compare
/// @param _value The int256 to compare to
/// @return equal True if the I256 is greater than or equal to the int256
function gte(I256 _i256, int256 _value) internal pure returns (bool) {
return I256.unwrap(_i256) >= _value;
}
/// @dev Compares an I256 to an int256 for less than
/// @param _i256 The I256 to compare
/// @param _value The int256 to compare to
/// @return equal True if the I256 is less than the int256
function lt(I256 _i256, int256 _value) internal pure returns (bool) {
return I256.unwrap(_i256) < _value;
}
/// @dev Compares an I256 to an int256 for less than or equal to
/// @param _i256 The I256 to compare
/// @param _value The int256 to compare to
/// @return equal True if the I256 is less than or equal to the int256
function lte(I256 _i256, int256 _value) internal pure returns (bool) {
return I256.unwrap(_i256) <= _value;
}
/*********************
* U256 ->
*********************/
/// @dev Wraps an int256 into a U256.
/// @param _i256 The int256 to wrap.
/// @return u256 The wrapped U256.
function asU256(int256 _i256) internal pure returns (U256 u256) {
u256 = U256.wrap(uint256(_i256));
}
/// @dev Wraps a uint256 into a U256.
/// @param _u256 The uint256 to wrap.
/// @return u256 The wrapped U256.
function asU256(uint256 _u256) internal pure returns (U256 u256) {
u256 = U256.wrap(_u256);
}
/// @dev Converts a U256 to a uint256.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint256 representation of the U256.
function asUint256(U256 _u256) internal pure returns (uint256 unsigned) {
return U256.unwrap(_u256);
}
/// @dev Converts a U256 to a uint224.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint224 representation of the U256.
function asUint224(U256 _u256) internal pure returns (uint224 unsigned) {
return uint224(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint216.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint216 representation of the U256.
function asUint216(U256 _u256) internal pure returns (uint216 unsigned) {
return uint216(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint208.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint208 representation of the U256.
function asUint208(U256 _u256) internal pure returns (uint208 unsigned) {
return uint208(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint200.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint200 representation of the U256.
function asUint200(U256 _u256) internal pure returns (uint200 unsigned) {
return uint200(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint192.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint192 representation of the U256.
function asUint192(U256 _u256) internal pure returns (uint192 unsigned) {
return uint192(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint184.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint184 representation of the U256.
function asUint184(U256 _u256) internal pure returns (uint184 unsigned) {
return uint184(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint176.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint176 representation of the U256.
function asUint176(U256 _u256) internal pure returns (uint176 unsigned) {
return uint176(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint168.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint168 representation of the U256.
function asUint168(U256 _u256) internal pure returns (uint168 unsigned) {
return uint168(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint160.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint160 representation of the U256.
function asUint160(U256 _u256) internal pure returns (uint160 unsigned) {
return uint160(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint152.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint152 representation of the U256.
function asUint152(U256 _u256) internal pure returns (uint152 unsigned) {
return uint152(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint144.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint144 representation of the U256.
function asUint144(U256 _u256) internal pure returns (uint144 unsigned) {
return uint144(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint136.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint136 representation of the U256.
function asUint136(U256 _u256) internal pure returns (uint136 unsigned) {
return uint136(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint128.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint128 representation of the U256.
function asUint128(U256 _u256) internal pure returns (uint128 unsigned) {
return uint128(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint120.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint120 representation of the U256.
function asUint120(U256 _u256) internal pure returns (uint120 unsigned) {
return uint120(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint112.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint112 representation of the U256.
function asUint112(U256 _u256) internal pure returns (uint112 unsigned) {
return uint112(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint104.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint104 representation of the U256.
function asUint104(U256 _u256) internal pure returns (uint104 unsigned) {
return uint104(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint96.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint96 representation of the U256.
function asUint96(U256 _u256) internal pure returns (uint96 unsigned) {
return uint96(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint88.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint88 representation of the U256.
function asUint88(U256 _u256) internal pure returns (uint88 unsigned) {
return uint88(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint80.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint80 representation of the U256.
function asUint80(U256 _u256) internal pure returns (uint80 unsigned) {
return uint80(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint72.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint72 representation of the U256.
function asUint72(U256 _u256) internal pure returns (uint72 unsigned) {
return uint72(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint64.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint64 representation of the U256.
function asUint64(U256 _u256) internal pure returns (uint64 unsigned) {
return uint64(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint56.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint56 representation of the U256.
function asUint56(U256 _u256) internal pure returns (uint56 unsigned) {
return uint56(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint48.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint48 representation of the U256.
function asUint48(U256 _u256) internal pure returns (uint48 unsigned) {
return uint48(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint40.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint40 representation of the U256.
function asUint40(U256 _u256) internal pure returns (uint40 unsigned) {
return uint40(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint32.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint32 representation of the U256.
function asUint32(U256 _u256) internal pure returns (uint32 unsigned) {
return uint32(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint24.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint24 representation of the U256.
function asUint24(U256 _u256) internal pure returns (uint24 unsigned) {
return uint24(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint16.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint16 representation of the U256.
function asUint16(U256 _u256) internal pure returns (uint16 unsigned) {
return uint16(U256.unwrap(_u256));
}
/// @dev Converts a U256 to a uint8.
/// @param _u256 The U256 to unwrap.
/// @return unsigned The uint8 representation of the U256.
function asUint8(U256 _u256) internal pure returns (uint8 unsigned) {
return uint8(U256.unwrap(_u256));
}
/// @dev Converts a U256 to an int256.
/// @param _u256 The U256 to convert.
/// @return signed The int256 representation of the U256.
function asInt256(U256 _u256) internal pure returns (int256 signed) {
return int256(U256.unwrap(_u256));
}
/// @dev Converts a U256 to an int248.
/// @param _u256 The U256 to convert.
/// @return signed The int248 representation of the U256.
function asInt248(U256 _u256) internal pure returns (int248 signed) {
return int248(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int240.
/// @param _u256 The U256 to convert.
/// @return signed The int240 representation of the U256.
function asInt240(U256 _u256) internal pure returns (int240 signed) {
return int240(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int232.
/// @param _u256 The U256 to convert.
/// @return signed The int232 representation of the U256.
function asInt232(U256 _u256) internal pure returns (int232 signed) {
return int232(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int224.
/// @param _u256 The U256 to convert.
/// @return signed The int224 representation of the U256.
function asInt224(U256 _u256) internal pure returns (int224 signed) {
return int224(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int216.
/// @param _u256 The U256 to convert.
/// @return signed The int216 representation of the U256.
function asInt216(U256 _u256) internal pure returns (int216 signed) {
return int216(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int208.
/// @param _u256 The U256 to convert.
/// @return signed The int208 representation of the U256.
function asInt208(U256 _u256) internal pure returns (int208 signed) {
return int208(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int200.
/// @param _u256 The U256 to convert.
/// @return signed The int200 representation of the U256.
function asInt200(U256 _u256) internal pure returns (int200 signed) {
return int200(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int192.
/// @param _u256 The U256 to convert.
/// @return signed The int192 representation of the U256.
function asInt192(U256 _u256) internal pure returns (int192 signed) {
return int192(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int184.
/// @param _u256 The U256 to convert.
/// @return signed The int184 representation of the U256.
function asInt184(U256 _u256) internal pure returns (int184 signed) {
return int184(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int176.
/// @param _u256 The U256 to convert.
/// @return signed The int176 representation of the U256.
function asInt176(U256 _u256) internal pure returns (int176 signed) {
return int176(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int168.
/// @param _u256 The U256 to convert.
/// @return signed The int168 representation of the U256.
function asInt168(U256 _u256) internal pure returns (int168 signed) {
return int168(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int160.
/// @param _u256 The U256 to convert.
/// @return signed The int160 representation of the U256.
function asInt160(U256 _u256) internal pure returns (int160 signed) {
return int160(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int152.
/// @param _u256 The U256 to convert.
/// @return signed The int152 representation of the U256.
function asInt152(U256 _u256) internal pure returns (int152 signed) {
return int152(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int144.
/// @param _u256 The U256 to convert.
/// @return signed The int144 representation of the U256.
function asInt144(U256 _u256) internal pure returns (int144 signed) {
return int144(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int136.
/// @param _u256 The U256 to convert.
/// @return signed The int136 representation of the U256.
function asInt136(U256 _u256) internal pure returns (int136 signed) {
return int136(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int128.
/// @param _u256 The U256 to convert.
/// @return signed The int128 representation of the U256.
function asInt128(U256 _u256) internal pure returns (int128 signed) {
return int128(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int120.
/// @param _u256 The U256 to convert.
/// @return signed The int120 representation of the U256.
function asInt120(U256 _u256) internal pure returns (int120 signed) {
return int120(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int112.
/// @param _u256 The U256 to convert.
/// @return signed The int112 representation of the U256.
function asInt112(U256 _u256) internal pure returns (int112 signed) {
return int112(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int104.
/// @param _u256 The U256 to convert.
/// @return signed The int104 representation of the U256.
function asInt104(U256 _u256) internal pure returns (int104 signed) {
return int104(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int96.
/// @param _u256 The U256 to convert.
/// @return signed The int96 representation of the U256.
function asInt96(U256 _u256) internal pure returns (int96 signed) {
return int96(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int88.
/// @param _u256 The U256 to convert.
/// @return signed The int88 representation of the U256.
function asInt88(U256 _u256) internal pure returns (int88 signed) {
return int88(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int80.
/// @param _u256 The U256 to convert.
/// @return signed The int80 representation of the U256.
function asInt80(U256 _u256) internal pure returns (int80 signed) {
return int80(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int72.
/// @param _u256 The U256 to convert.
/// @return signed The int72 representation of the U256.
function asInt72(U256 _u256) internal pure returns (int72 signed) {
return int72(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int64.
/// @param _u256 The U256 to convert.
/// @return signed The int64 representation of the U256.
function asInt64(U256 _u256) internal pure returns (int64 signed) {
return int64(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int56.
/// @param _u256 The U256 to convert.
/// @return signed The int56 representation of the U256.
function asInt56(U256 _u256) internal pure returns (int56 signed) {
return int56(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int48.
/// @param _u256 The U256 to convert.
/// @return signed The int48 representation of the U256.
function asInt48(U256 _u256) internal pure returns (int48 signed) {
return int48(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int40.
/// @param _u256 The U256 to convert.
/// @return signed The int40 representation of the U256.
function asInt40(U256 _u256) internal pure returns (int40 signed) {
return int40(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int32.
/// @param _u256 The U256 to convert.
/// @return signed The int32 representation of the U256.
function asInt32(U256 _u256) internal pure returns (int32 signed) {
return int32(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int24.
/// @param _u256 The U256 to convert.
/// @return signed The int24 representation of the U256.
function asInt24(U256 _u256) internal pure returns (int24 signed) {
return int24(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int16.
/// @param _u256 The U256 to convert.
/// @return signed The int16 representation of the U256.
function asInt16(U256 _u256) internal pure returns (int16 signed) {
return int16(int256(U256.unwrap(_u256)));
}
/// @dev Converts a U256 to an int8.
/// @param _u256 The U256 to convert.
/// @return signed The int8 representation of the U256.
function asInt8(U256 _u256) internal pure returns (int8 signed) {
return int8(int256(U256.unwrap(_u256)));
}
/// @dev Adds a uint256 to a U256.
/// @param _u256 The U256 to add to.
/// @param _addend The uint256 to add.
/// @return u256 The U256 result of the addition.
function add(U256 _u256, uint256 _addend) internal pure returns (U256 u256) {
u256 = U256.wrap(add(U256.unwrap(_u256), _addend));
}
/// @dev Subtracts a uint256 from a U256.
/// @param _u256 The U256 to subtract from.
/// @param _subtrahend The uint256 to subtract.
/// @return u256 The U256 result of the subtraction.
function sub(U256 _u256, uint256 _subtrahend) internal pure returns (U256 u256) {
return U256.wrap(sub(U256.unwrap(_u256), _subtrahend));
}
/// @dev Increments a U256.
/// @param _u256 The U256 to increment.
/// @return u256 The U256 result of the increment.
function inc(U256 _u256) internal pure returns (U256 u256) {
return U256.wrap(inc(U256.unwrap(_u256)));
}
/// @dev Decrements a U256.
/// @param _u256 The U256 to decrement.
/// @return u256 The U256 result of the decrement.
function dec(U256 _u256) internal pure returns (U256 u256) {
return U256.wrap(dec(U256.unwrap(_u256)));
}
/// @notice Calculate the product of a U256 and a uint256
/// @param _u256 The U256
/// @param _multiplier The uint256
/// @return u256 The product of _u256 and _multiplier
function mul(U256 _u256, uint256 _multiplier) internal pure returns (U256 u256) {
return U256.wrap(mul(U256.unwrap(_u256), _multiplier));
}
/**
* @dev Divide a U256 number by a uint256 number.
* @param _u256 The U256 number to divide.
* @param _divisor The uint256 number to divide by.
* @return u256 The result of dividing _u256 by _divisor.
*/
function div(U256 _u256, uint256 _divisor) internal pure returns (U256 u256) {
return U256.wrap(div(U256.unwrap(_u256), _divisor));
}
/// @dev Get the modulus of a U256 and a uint256
/// @param _u256 The U256 to be divided
/// @param _divisor The divisor
/// @return u256 The result of the modulo operation
function mod(U256 _u256, uint256 _divisor) internal pure returns (U256 u256) {
return U256.wrap(mod(U256.unwrap(_u256), _divisor));
}
/// @notice Raise a U256 to the power of a uint256
/// @param _u256 The base
/// @param _exponent The exponent
/// @return u256 The result of raising `_u256` to the power of `_exponent`
function exp(U256 _u256, uint256 _exponent) internal pure returns (U256 u256) {
return U256.wrap(exp(U256.unwrap(_u256), _exponent));
}
/// @dev Right shift a uint256 by a uint256.
/// @param _u256 uint256 to right shift
/// @param _shift uint256 to shift by
/// @return u256 uint256 result of right shift
function rshift(U256 _u256, U256 _shift) internal pure returns (U256 u256) {
return U256.wrap(U256.unwrap(_u256) >> U256.unwrap(_shift));
}
/// @dev Left shift a U256 by a U256.
/// @param _u256 U256 to left shift
/// @param _shift U256 to shift by
/// @return u256 U256 result of left shift
function lshift(U256 _u256, U256 _shift) internal pure returns (U256 u256) {
return U256.wrap(U256.unwrap(_u256) << U256.unwrap(_shift));
}
/// @dev Right shift a U256 by a uint256.
/// @param _u256 U256 to right shift
/// @param _shift uint256 to shift by
/// @return u256 U256 result of right shift
function rshift(U256 _u256, uint256 _shift) internal pure returns (U256 u256) {
return U256.wrap(U256.unwrap(_u256) >> _shift);
}
/// @dev Left shift a U256 by a uint256.
/// @param _u256 U256 to left shift
/// @param _shift uint256 to shift by
/// @return u256 U256 result of left shift
function lshift(U256 _u256, uint256 _shift) internal pure returns (U256 u256) {
return U256.wrap(U256.unwrap(_u256) << _shift);
}
/// @dev logical and between the input and the value
/// @param _u256 input
/// @param _value value
/// @return u256 the result of the logical and
function and(U256 _u256, uint256 _value) internal pure returns (U256 u256) {
return _u256 & U256.wrap(_value);
}
/// @dev logical or between the input and the value
/// @param _u256 input
/// @param _value value
/// @return u256 the result of the logical or
function or(U256 _u256, uint256 _value) internal pure returns (U256 u256) {
return _u256 | U256.wrap(_value);
}
/// @dev logical xor between the input and the value
/// @param _u256 input
/// @param _value value
/// @return u256 the result of the logical xor
function xor(U256 _u256, uint256 _value) internal pure returns (U256 u256) {
return _u256 ^ U256.wrap(_value);
}
/// @dev logical not of the input
/// @param _u256 input
/// @return u256 the result of the logical not
function not(U256 _u256) internal pure returns (U256 u256) {
return ~_u256;
}
/// @dev Compare a U256 to a uint256 for equality
/// @param _u256 The U256 to compare
/// @param _value The uint256 to compare
/// @return result True if the U256 is equal to the uint256
function eq(U256 _u256, uint256 _value) internal pure returns (bool result) {
return U256.unwrap(_u256) == _value;
}
/// @dev Compare a U256 to a uint256 for inequality
/// @param _u256 The U256 to compare
/// @param _value The uint256 to compare
/// @return result True if the U256 is not equal to the uint256
function neq(U256 _u256, uint256 _value) internal pure returns (bool result) {
return U256.unwrap(_u256) != _value;
}
/// @dev Compare a U256 to a uint256 for greater than
/// @param _u256 The U256 to compare
/// @param _value The uint256 to compare
/// @return result True if the U256 is greater than the uint256
function gt(U256 _u256, uint256 _value) internal pure returns (bool result) {
return U256.unwrap(_u256) > _value;
}
/// @dev Compare a U256 to a uint256 for greater than or equal to
/// @param _u256 The U256 to compare
/// @param _value The uint256 to compare
/// @return result True if the U256 is greater than or equal to the uint256
function gte(U256 _u256, uint256 _value) internal pure returns (bool result) {
return U256.unwrap(_u256) >= _value;
}
/// @dev Compare a U256 to a uint256 for less than
/// @param _u256 The U256 to compare
/// @param _value The uint256 to compare
/// @return result True if the U256 is less than the uint256
function lt(U256 _u256, uint256 _value) internal pure returns (bool result) {
return U256.unwrap(_u256) < _value;
}
/// @dev Compare a U256 to a uint256 for less than or equal to
/// @param _u256 The U256 to compare
/// @param _value The uint256 to compare
/// @return result True if the U256 is less than or equal to the uint256
function lte(U256 _u256, uint256 _value) internal pure returns (bool result) {
return U256.unwrap(_u256) <= _value;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Skill, Attire, CombatStyle, CombatStats} from "./misc.sol";
import {GuaranteedReward, RandomReward} from "./rewards.sol";
enum ActionQueueStatus {
NONE,
APPEND,
KEEP_LAST_IN_PROGRESS
}
struct QueuedActionInputV2 {
Attire attire;
uint16 actionId;
uint16 regenerateId; // Food (combat), maybe something for non-combat later
uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
uint16 leftHandEquipmentTokenId; // Shield, can be empty
uint24 timespan; // How long to queue the action for
CombatStyle combatStyle; // specific style of combat
uint40 petId; // id of the pet (can be empty)
}
struct QueuedActionInput {
Attire attire;
uint16 actionId;
uint16 regenerateId; // Food (combat), maybe something for non-combat later
uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
uint16 leftHandEquipmentTokenId; // Shield, can be empty
uint24 timespan; // How long to queue the action for
CombatStyle combatStyle; // specific style of combat
}
struct QueuedActionExtra {
uint40 petId; // id of the pet (can be empty)
}
// Can't extend this due to the actionQueue variable in Player struct
struct QueuedAction {
uint16 actionId;
uint16 regenerateId; // Food (combat), maybe something for non-combat later
uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
uint16 leftHandEquipmentTokenId; // Shield, can be empty
uint24 timespan; // How long to queue the action for
CombatStyle combatStyle; // specific style of combat
uint24 prevProcessedTime; // How long the action has been processed for previously
uint24 prevProcessedXPTime; // How much XP has been gained for this action so far
uint64 queueId; // id of this queued action
bytes1 packed; // isValid first bit (not used yet) and hasPet 2nd bit
uint24 reserved;
}
struct QueuedActionV1 {
uint16 actionId;
uint16 regenerateId; // Food (combat), maybe something for non-combat later
uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
uint16 leftHandEquipmentTokenId; // Shield, can be empty
uint24 timespan; // How long to queue the action for
CombatStyle combatStyle; // specific style of combat
uint24 prevProcessedTime; // How long the action has been processed for previously
uint24 prevProcessedXPTime; // How much XP has been gained for this action so far
uint64 queueId; // id of this queued action
bool isValid; // If we still have the item, TODO: Not used yet
}
// This is only used as an input arg (and events)
struct Action {
uint16 actionId;
ActionInfo info;
GuaranteedReward[] guaranteedRewards;
RandomReward[] randomRewards;
CombatStats combatStats;
}
struct ActionV1 {
uint16 actionId;
ActionInfoV1 info;
GuaranteedReward[] guaranteedRewards;
RandomReward[] randomRewards;
CombatStats combatStats;
}
struct ActionInfo {
Skill skill;
bool isAvailable;
bool isDynamic;
bool actionChoiceRequired; // If true, then the user must choose an action choice
uint24 xpPerHour;
uint32 minXP;
uint24 numSpawned; // Mostly for combat, capped respawn rate for xp/drops. Per hour, base 10000
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
uint8 successPercent; // 0-100
uint8 worldLocation; // 0 is the main starting world
bool isFullModeOnly;
}
struct ActionInfoV1 {
Skill skill;
bool isAvailable;
bool isDynamic;
bool actionChoiceRequired; // If true, then the user must choose an action choice
uint24 xpPerHour;
uint32 minXP;
uint24 numSpawned; // Mostly for combat, capped respawn rate for xp/drops. Per hour, base 10000
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
uint8 successPercent; // 0-100
}
// Allows for 2, 4 or 8 hour respawn time
uint constant SPAWN_MUL = 1000;
uint constant RATE_MUL = 1000;
uint constant GUAR_MUL = 10; // Guaranteeded reward multiplier (1 decimal, allows for 2 hour respawn time)
uint constant ACTION_CHOICE_USE_NEW_MIN_SKILL_SECOND_STORAGE_SLOT_BIT = 6;
uint constant ACTION_CHOICE_USE_ALTERNATE_INPUTS_SECOND_STORAGE_SLOT = 5;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Types and constants, no external dependencies
import "./actions.sol";
import "./items.sol";
import "./misc.sol";
import "./players.sol";
import "./rewards.sol";
import "./quests.sol";
import "./promotions.sol";
import "./clans.sol";
import "./pets.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IBank} from "../interfaces/IBank.sol";
enum ClanRank {
NONE, // Not in a clan
COMMONER, // Member of the clan
SCOUT, // Invite and kick commoners
TREASURER, // Can withdraw from bank
LEADER, // Can edit clan details
OWNER // Can do everything and transfer ownership
}
enum BattleResultEnum {
DRAW,
WIN,
LOSE
}
struct ClanBattleInfo {
uint40 lastClanIdAttackOtherClanIdCooldownTimestamp;
uint8 numReattacks;
uint40 lastOtherClanIdAttackClanIdCooldownTimestamp;
uint8 numReattacksOtherClan;
}
// Packed for gas efficiency
struct Vault {
bool claimed; // Only applies to the first one, if it's claimed without the second one being claimed
uint40 timestamp;
uint80 amount;
uint40 timestamp1;
uint80 amount1;
}
struct VaultClanInfo {
IBank bank;
uint96 totalBrushLocked;
// New storage slot
uint40 attackingCooldownTimestamp;
uint40 assignCombatantsCooldownTimestamp;
bool currentlyAttacking;
uint88 gasPaid; // TODO remove in migration
uint24 defendingVaultsOffset;
uint40 blockAttacksTimestamp;
uint8 blockAttacksCooldownHours;
bool isInMMRArray;
uint48[] playerIds;
Vault[] defendingVaults; // Append only, and use defendingVaultsOffset to decide where the real start is
uint40 superAttackCooldownTimestamp;
}
uint constant MAX_CLAN_COMBATANTS = 20;
uint constant CLAN_WARS_GAS_PRICE_WINDOW_SIZE = 4;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
uint16 constant NONE = 0;
uint16 constant COMBAT_BASE = 2048;
// Melee
uint16 constant SWORD_BASE = COMBAT_BASE;
uint16 constant BRONZE_SWORD = SWORD_BASE;
// Woodcutting (2816 - 3071)
uint16 constant WOODCUTTING_BASE = 2816;
uint16 constant BRONZE_AXE = WOODCUTTING_BASE;
// Firemaking (3328 - 3583)
uint16 constant FIRE_BASE = 3328;
uint16 constant MAGIC_FIRE_STARTER = FIRE_BASE;
uint16 constant FIRE_MAX = FIRE_BASE + 255;
// Fishing (3072 - 3327)
uint16 constant FISHING_BASE = 3072;
uint16 constant NET_STICK = FISHING_BASE;
// Mining (2560 - 2815)
uint16 constant MINING_BASE = 2560;
uint16 constant BRONZE_PICKAXE = MINING_BASE;
// Magic
uint16 constant STAFF_BASE = COMBAT_BASE + 50;
uint16 constant TOTEM_STAFF = STAFF_BASE;
// Ranged
uint16 constant BOW_BASE = COMBAT_BASE + 100;
uint16 constant BASIC_BOW = BOW_BASE;
// Cooked fish
uint16 constant COOKED_FISH_BASE = 11008;
uint16 constant COOKED_FEOLA = COOKED_FISH_BASE + 3;
// Scrolls
uint16 constant SCROLL_BASE = 12032;
uint16 constant SHADOW_SCROLL = SCROLL_BASE;
// Boosts
uint16 constant BOOST_BASE = 12800;
uint16 constant COMBAT_BOOST = BOOST_BASE;
uint16 constant XP_BOOST = BOOST_BASE + 1;
uint16 constant GATHERING_BOOST = BOOST_BASE + 2;
uint16 constant SKILL_BOOST = BOOST_BASE + 3;
uint16 constant ABSENCE_BOOST = BOOST_BASE + 4;
uint16 constant LUCKY_POTION = BOOST_BASE + 5;
uint16 constant LUCK_OF_THE_DRAW = BOOST_BASE + 6;
uint16 constant PRAY_TO_THE_BEARDIE = BOOST_BASE + 7;
uint16 constant PRAY_TO_THE_BEARDIE_2 = BOOST_BASE + 8;
uint16 constant PRAY_TO_THE_BEARDIE_3 = BOOST_BASE + 9;
uint16 constant BOOST_RESERVED_1 = BOOST_BASE + 10;
uint16 constant BOOST_RESERVED_2 = BOOST_BASE + 11;
uint16 constant BOOST_RESERVED_3 = BOOST_BASE + 12;
uint16 constant GO_OUTSIDE = BOOST_BASE + 13;
uint16 constant RAINING_RARES = BOOST_BASE + 14;
uint16 constant CLAN_BOOSTER = BOOST_BASE + 15;
uint16 constant CLAN_BOOSTER_2 = BOOST_BASE + 16;
uint16 constant CLAN_BOOSTER_3 = BOOST_BASE + 17;
uint16 constant BOOST_RESERVED_4 = BOOST_BASE + 18;
uint16 constant BOOST_RESERVED_5 = BOOST_BASE + 19;
uint16 constant BOOST_RESERVED_6 = BOOST_BASE + 20;
uint16 constant BOOST_MAX = 13055;
// Eggs
uint16 constant EGG_BASE = 12544;
uint16 constant SECRET_EGG_1_TIER1 = EGG_BASE;
uint16 constant SECRET_EGG_2_TIER1 = EGG_BASE + 1;
uint16 constant EGG_MAX = 12799;
struct BulkTransferInfo {
uint[] tokenIds;
uint[] amounts;
address to;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
enum BoostType {
NONE,
ANY_XP,
COMBAT_XP,
NON_COMBAT_XP,
GATHERING,
ABSENCE,
PASSIVE_SKIP_CHANCE,
// Clan wars
PVP_BLOCK,
PVP_REATTACK,
PVP_SUPER_ATTACK
}
struct Equipment {
uint16 itemTokenId;
uint24 amount;
}
enum Skill {
NONE,
COMBAT, // This is a helper which incorporates all combat skills, attack <-> magic, defence, health etc
MELEE,
RANGED,
MAGIC,
DEFENCE,
HEALTH,
RESERVED_COMBAT,
MINING,
WOODCUTTING,
FISHING,
SMITHING,
THIEVING,
CRAFTING,
COOKING,
FIREMAKING,
AGILITY,
ALCHEMY,
FLETCHING,
FORGING,
RESERVED2,
RESERVED3,
RESERVED4,
RESERVED5,
RESERVED6,
RESERVED7,
RESERVED8,
RESERVED9,
RESERVED10,
RESERVED11,
RESERVED12,
RESERVED13,
RESERVED14,
RESERVED15,
RESERVED16,
RESERVED17,
RESERVED18,
RESERVED19,
RESERVED20,
TRAVELING // Helper Skill for travelling
}
struct Attire {
uint16 head;
uint16 neck;
uint16 body;
uint16 arms;
uint16 legs;
uint16 feet;
uint16 ring;
uint16 reserved1;
}
struct CombatStats {
// From skill points
int16 melee;
int16 magic;
int16 ranged;
int16 health;
// These include equipment
int16 meleeDefence;
int16 magicDefence;
int16 rangedDefence;
}
enum CombatStyle {
NONE,
ATTACK,
DEFENCE
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Skill} from "./misc.sol";
enum PetSkin {
NONE,
DEFAULT,
OG,
ONEKIN,
FROST,
CRYSTAL,
ANNIV1,
KRAGSTYR
}
enum PetEnhancementType {
NONE,
MELEE,
MAGIC,
RANGED,
DEFENCE,
HEALTH,
MELEE_AND_DEFENCE,
MAGIC_AND_DEFENCE,
RANGED_AND_DEFENCE
}
struct Pet {
Skill skillEnhancement1;
uint8 skillFixedEnhancement1;
uint8 skillPercentageEnhancement1;
Skill skillEnhancement2;
uint8 skillFixedEnhancement2;
uint8 skillPercentageEnhancement2;
uint40 lastAssignmentTimestamp;
address owner; // Will be used as an optimzation to avoid having to look up the owner of the pet in another storage slot
// 1 byte left in this storage slot
uint24 baseId;
}
struct BasePetMetadata {
string description;
uint8 tier;
PetSkin skin;
PetEnhancementType enhancementType;
Skill skillEnhancement1;
uint8 skillFixedMin1;
uint8 skillFixedMax1;
uint8 skillFixedIncrement1;
uint8 skillPercentageMin1;
uint8 skillPercentageMax1;
uint8 skillPercentageIncrement1;
uint8 skillMinLevel1;
Skill skillEnhancement2;
uint8 skillFixedMin2;
uint8 skillFixedMax2;
uint8 skillFixedIncrement2;
uint8 skillPercentageMin2;
uint8 skillPercentageMax2;
uint8 skillPercentageIncrement2;
uint8 skillMinLevel2;
uint16 fixedStarThreshold;
uint16 percentageStarThreshold;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {QueuedAction} from "./actions.sol";
import {Skill, BoostType, CombatStats, Equipment} from "./misc.sol";
import {PlayerQuest} from "./quests.sol";
// 4 bytes for each level. 0x00000000 is the first level, 0x00000054 is the second, etc.
bytes constant XP_BYTES = hex"0000000000000054000000AE0000010E00000176000001E60000025E000002DE00000368000003FD0000049B00000546000005FC000006C000000792000008730000096400000A6600000B7B00000CA400000DE100000F36000010A200001229000013CB0000158B0000176B0000196E00001B9400001DE20000205A000022FF000025D5000028DD00002C1E00002F99000033540000375200003B9A000040300000451900004A5C00004FFF0000560900005C810000637000006ADD000072D100007B570000847900008E42000098BE0000A3F90000B0020000BCE70000CAB80000D9860000E9630000FA6200010C990001201D0001350600014B6F0001637300017D2E000198C10001B64E0001D5F80001F7E600021C430002433B00026CFD000299BE0002C9B30002FD180003342B00036F320003AE730003F23D00043AE3000488BE0004DC2F0005359B000595700005FC2400066A360006E02D00075E990007E6160008774C000912EB0009B9B4000A6C74000B2C06000BF956000CD561000DC134000EBDF3000FCCD40010EF24";
enum EquipPosition {
NONE,
HEAD,
NECK,
BODY,
ARMS,
LEGS,
FEET,
RING,
SPARE2,
LEFT_HAND,
RIGHT_HAND,
BOTH_HANDS,
QUIVER,
MAGIC_BAG,
FOOD,
AUX, // wood, seeds etc..
BOOST_VIAL,
EXTRA_BOOST_VIAL,
GLOBAL_BOOST_VIAL,
CLAN_BOOST_VIAL,
PASSIVE_BOOST_VIAL,
LOCKED_VAULT,
TERRITORY
}
struct Player {
uint40 currentActionStartTime; // The start time of the first queued action
Skill currentActionProcessedSkill1; // The skill that the queued action has already gained XP in
uint24 currentActionProcessedXPGained1; // The amount of XP that the queued action has already gained
Skill currentActionProcessedSkill2;
uint24 currentActionProcessedXPGained2;
uint16 currentActionProcessedFoodConsumed;
uint16 currentActionProcessedBaseInputItemsConsumedNum; // e.g scrolls, crafting materials etc
Skill skillBoosted1; // The skill that is boosted
Skill skillBoosted2; // The second skill that is boosted
uint56 totalXP;
Skill currentActionProcessedSkill3;
uint24 currentActionProcessedXPGained3;
bytes1 packedData; // Contains worldLocation in first 6 bits (0 is the main starting world), and full mode unlocked in the upper most bit
// TODO: Can be up to 7
QueuedAction[] actionQueue;
string name; // Raw name
}
struct Item {
EquipPosition equipPosition;
bytes1 packedData; // 0x1 exists, upper most bit is full mode
// Can it be transferred?
bool isTransferable;
// Food
uint16 healthRestored;
// Boost vial
BoostType boostType;
uint16 boostValue; // Varies, could be the % increase
uint24 boostDuration; // How long the effect of the boost last
// Combat stats
int16 melee;
int16 magic;
int16 ranged;
int16 meleeDefence;
int16 magicDefence;
int16 rangedDefence;
int16 health;
// Minimum requirements in this skill to use this item (can be NONE)
Skill skill;
uint32 minXP;
}
struct ItemV1 {
EquipPosition equipPosition;
bool exists;
bool isTransferable;
uint16 healthRestored;
BoostType boostType;
uint16 boostValue;
uint24 boostDuration;
int16 melee;
int16 magic;
int16 ranged;
int16 meleeDefence;
int16 magicDefence;
int16 rangedDefence;
int16 health;
Skill skill;
uint32 minXP;
}
struct ItemOutput {
EquipPosition equipPosition;
bool isFullModeOnly;
bool isTransferable;
uint16 healthRestored;
BoostType boostType;
uint16 boostValue;
uint24 boostDuration;
int16 melee;
int16 magic;
int16 ranged;
int16 meleeDefence;
int16 magicDefence;
int16 rangedDefence;
int16 health;
Skill skill;
uint32 minXP;
}
// Used for events
struct BoostInfo {
uint40 startTime;
uint24 duration;
uint16 value;
uint16 itemTokenId; // Get the effect of it
BoostType boostType;
}
struct PlayerBoostInfo {
uint40 startTime;
uint24 duration;
uint16 value;
uint16 itemTokenId; // Get the effect of it
BoostType boostType;
// Another boost slot (for global/clan boosts this is the "last", for users it is the "extra")
uint40 extraOrLastStartTime;
uint24 extraOrLastDuration;
uint16 extraOrLastValue;
uint16 extraOrLastItemTokenId;
BoostType extraOrLastBoostType;
uint40 cooldown; // Just put here for packing
}
// This is effectively a ratio to produce 1 of outputTokenId.
// Available choices that can be undertaken for an action
struct ActionChoiceInput {
Skill skill; // Skill that this action choice is related to
int16 skillDiff; // How much the skill is increased/decreased by this action choice
uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
uint24 xpPerHour;
uint16[] inputTokenIds;
uint24[] inputAmounts;
uint16 outputTokenId;
uint8 outputAmount;
uint8 successPercent; // 0-100
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
bool isFullModeOnly;
Skill[] minSkills; // Skills required to do this action choice
uint32[] minXPs; // Min XP in the corresponding skills to be able to do this action choice
}
struct ActionChoiceInputV3 {
Skill skill; // Skill that this action choice is related to
int16 skillDiff; // How much the skill is increased/decreased by this action choice
uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
uint24 xpPerHour;
uint16[] inputTokenIds;
uint8[] inputAmounts;
uint16 outputTokenId;
uint8 outputAmount;
uint8 successPercent; // 0-100
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
bool isFullModeOnly;
Skill[] minSkills; // Skills required to do this action choice
uint32[] minXPs; // Min XP in the corresponding skills to be able to do this action choice
}
struct ActionChoiceInputV2 {
Skill skill; // Skill that this action choice is related to
uint32 minXP; // Min XP in the skill to be able to do this action choice
int16 skillDiff; // How much the skill is increased/decreased by this action choice
uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
uint24 xpPerHour;
uint16 inputTokenId1;
uint8 inputAmount1;
uint16 inputTokenId2;
uint8 inputAmount2;
uint16 inputTokenId3;
uint8 inputAmount3;
uint16 outputTokenId;
uint8 outputAmount;
uint8 successPercent; // 0-100
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
bool isFullModeOnly;
}
struct ActionChoice {
Skill skill; // Skill that this action choice is related to
uint32 minXP; // Min XP in the skill to be able to do this action choice
int16 skillDiff; // How much the skill is increased/decreased by this action choice
uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
uint24 xpPerHour;
uint16 inputTokenId1;
uint8 inputAmount1;
uint16 inputTokenId2;
uint8 inputAmount2;
uint16 inputTokenId3;
uint8 inputAmount3;
uint16 outputTokenId;
uint8 outputAmount;
uint8 successPercent; // 0-100
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
// FullMode is last bit, first 6 bits is worldLocation,
// 2nd last bit is if there are other skills in next storage slot to check,
// 3rd last bit if the input amounts should be used
bytes1 packedData;
bytes1 reserved;
// Second storage slot
Skill minSkill2;
uint32 minXP2;
Skill minSkill3;
uint32 minXP3;
uint24 newInputAmount1; // alternative inputAmount1 which is larger
uint24 newInputAmount2; // alternative inputAmount2 which is larger
uint24 newInputAmount3; // alternative inputAmount3 which is larger
}
struct ActionChoiceV2 {
Skill skill; // Skill that this action choice is related to
uint32 minXP; // Min XP in the skill to be able to do this action choice
int16 skillDiff; // How much the skill is increased/decreased by this action choice
uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
uint24 xpPerHour;
uint16 inputTokenId1;
uint8 inputAmount1;
uint16 inputTokenId2;
uint8 inputAmount2;
uint16 inputTokenId3;
uint8 inputAmount3;
uint16 outputTokenId;
uint8 outputAmount;
uint8 successPercent; // 0-100
uint16 handItemTokenIdRangeMin; // Inclusive
uint16 handItemTokenIdRangeMax; // Inclusive
bytes1 packedData; // FullMode is last bit
}
struct ActionChoiceV1 {
Skill skill;
uint32 minXP;
int16 skillDiff;
uint24 rate;
uint24 xpPerHour;
uint16 inputTokenId1;
uint8 inputAmount1;
uint16 inputTokenId2;
uint8 inputAmount2;
uint16 inputTokenId3;
uint8 inputAmount3;
uint16 outputTokenId;
uint8 outputAmount;
uint8 successPercent; // 0-100
}
// Must be in the same order as Skill enum
struct PackedXP {
uint40 melee;
uint40 ranged;
uint40 magic;
uint40 defence;
uint40 health;
uint40 reservedCombat;
bytes2 packedDataIsMaxed; // 2 bits per skill, 1 = first maxed level
// Next slot
uint40 mining;
uint40 woodcutting;
uint40 fishing;
uint40 smithing;
uint40 thieving;
uint40 crafting;
bytes2 packedDataIsMaxed1; // 2 bits per skill, 1 = first maxed level
// Next slot
uint40 cooking;
uint40 firemaking;
uint40 agility;
uint40 alchemy;
uint40 fletching;
uint40 forging;
bytes2 packedDataIsMaxed2; // 2 bits per skill, 1 = first maxed level
}
struct AvatarInfo {
string name;
string description;
string imageURI;
Skill[2] startSkills; // Can be NONE
}
struct PastRandomRewardInfo {
uint64 queueId;
uint16 itemTokenId;
uint24 amount;
}
struct PendingQueuedActionEquipmentState {
uint[] consumedItemTokenIds;
uint[] consumedAmounts;
uint[] producedItemTokenIds;
uint[] producedAmounts;
}
struct PendingQueuedActionMetadata {
uint32 xpGained; // total xp gained
uint32 rolls;
bool died;
uint16 actionId;
uint64 queueId;
uint24 elapsedTime;
uint24 xpElapsedTime;
}
struct PendingQueuedActionData {
// The amount of XP that the queued action has already gained
Skill skill1;
uint24 xpGained1;
Skill skill2; // Most likely health
uint24 xpGained2;
Skill skill3; // Could come
uint24 xpGained3;
// How much food is consumed in the current action so far
uint16 foodConsumed;
// How many base consumables are consumed in the current action so far
uint16 baseInputItemsConsumedNum;
}
struct PendingQueuedActionProcessed {
// XP gained during this session
Skill[] skills;
uint32[] xpGainedSkills;
// Data for the current action which has been previously processed, this is used to store on the Player
PendingQueuedActionData currentAction;
}
struct QuestState {
uint[] consumedItemTokenIds;
uint[] consumedAmounts;
uint[] rewardItemTokenIds;
uint[] rewardAmounts;
PlayerQuest[] activeQuestInfo;
uint[] questsCompleted;
Skill[] skills; // Skills gained XP in
uint32[] xpGainedSkills; // XP gained in these skills
}
struct LotteryWinnerInfo {
uint16 lotteryId;
uint24 raffleId;
uint16 itemTokenId;
uint16 amount;
bool instantConsume;
uint40 playerId;
}
struct PendingQueuedActionState {
// These 2 are in sync. Separated to reduce gas/deployment costs as these are passed down many layers.
PendingQueuedActionEquipmentState[] equipmentStates;
PendingQueuedActionMetadata[] actionMetadatas;
QueuedAction[] remainingQueuedActions;
PastRandomRewardInfo[] producedPastRandomRewards;
uint[] xpRewardItemTokenIds;
uint[] xpRewardAmounts;
uint[] dailyRewardItemTokenIds;
uint[] dailyRewardAmounts;
PendingQueuedActionProcessed processedData;
bytes32 dailyRewardMask;
QuestState quests;
uint numPastRandomRewardInstancesToRemove;
uint8 worldLocation;
LotteryWinnerInfo lotteryWinner;
}
struct FullAttireBonusInput {
Skill skill;
uint8 bonusXPPercent;
uint8 bonusRewardsPercent; // 3 = 3%
uint16[5] itemTokenIds; // 0 = head, 1 = body, 2 arms, 3 body, 4 = feet
}
// Contains everything you need to create an item
struct ItemInput {
CombatStats combatStats;
uint16 tokenId;
EquipPosition equipPosition;
bool isTransferable;
bool isFullModeOnly;
// Minimum requirements in this skill
Skill skill;
uint32 minXP;
// Food
uint16 healthRestored;
// Boost
BoostType boostType;
uint16 boostValue; // Varies, could be the % increase
uint24 boostDuration; // How long the effect of the boost vial last
// uri
string metadataURI;
string name;
}
uint constant MAX_UNIQUE_TICKETS_ = 64;
uint constant IS_FULL_MODE_BIT = 7;
// Passive/InstantVRF action
uint constant IS_AVAILABLE_BIT = 1;
// Queued action
uint constant HAS_PET_BIT = 1;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
enum Promotion {
NONE,
STARTER,
HALLOWEEN_2023,
XMAS_2023,
HALLOWEEN_2024,
HOLIDAY4, // Just have placeholders for now
HOLIDAY5,
HOLIDAY6,
HOLIDAY7,
HOLIDAY8,
HOLIDAY9,
HOLIDAY10
}
enum PromotionMintStatus {
NONE,
SUCCESS,
PROMOTION_ALREADY_CLAIMED,
ORACLE_NOT_CALLED,
MINTING_OUTSIDE_AVAILABLE_DATE,
PLAYER_DOES_NOT_QUALIFY,
PLAYER_NOT_HIT_ENOUGH_CLAIMS_FOR_STREAK_BONUS
}
struct PromotionInfoInput {
Promotion promotion;
uint40 startTime;
uint40 endTime; // Exclusive
uint8 numDailyRandomItemsToPick; // Number of items to pick
uint40 minTotalXP; // Minimum xp required to claim
uint brushCost; // Cost in brush to start the promotion, max 16mil
// Special promotion specific (like 1kin)
uint8 redeemCodeLength; // Length of the redeem code
bool adminOnly; // Only admins can mint the promotion, like for 1kin (Not used yet)
bool promotionTiedToUser; // If the promotion is tied to a user
bool promotionTiedToPlayer; // If the promotion is tied to the player
bool promotionMustOwnPlayer; // Must own the player to get the promotion
// Evolution specific
bool evolvedHeroOnly; // Only allow evolved heroes to claim
// Multiday specific
bool isMultiday; // The promotion is multi-day
uint brushCostMissedDay; // Cost in brush to mint the promotion if they miss a day (in ether), max 25.6 (base 100)
uint8 numDaysHitNeededForStreakBonus; // How many days to hit for the streak bonus
uint8 numDaysClaimablePeriodStreakBonus; // If there is a streak bonus, how many days to claim it after the promotion ends. If no final day bonus, set to 0
uint8 numRandomStreakBonusItemsToPick1; // Number of items to pick for the streak bonus
uint8 numRandomStreakBonusItemsToPick2; // Number of random items to pick for the streak bonus
uint16[] randomStreakBonusItemTokenIds1;
uint32[] randomStreakBonusAmounts1;
uint16[] randomStreakBonusItemTokenIds2;
uint32[] randomStreakBonusAmounts2;
uint16[] guaranteedStreakBonusItemTokenIds;
uint16[] guaranteedStreakBonusAmounts;
// Single and multiday
uint16[] guaranteedItemTokenIds; // Guaranteed items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
uint32[] guaranteedAmounts; // Corresponding amounts to the itemTokenIds
uint16[] randomItemTokenIds; // Possible items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
uint32[] randomAmounts; // Corresponding amounts to the randomItemTokenIds
}
struct PromotionInfo {
Promotion promotion;
uint40 startTime;
uint8 numDays;
uint8 numDailyRandomItemsToPick; // Number of items to pick
uint40 minTotalXP; // Minimum xp required to claim
uint24 brushCost; // Cost in brush to mint the promotion (in ether), max 16mil
// Special promotion specific (like 1kin), could pack these these later
uint8 redeemCodeLength; // Length of the redeem code
bool adminOnly; // Only admins can mint the promotion, like for 1kin
bool promotionTiedToUser; // If the promotion is tied to a user
bool promotionTiedToPlayer; // If the promotion is tied to the player
bool promotionMustOwnPlayer; // Must own the player to get the promotion
// Evolution specific
bool evolvedHeroOnly; // Only allow evolved heroes to claim
// Multiday specific
bool isMultiday; // The promotion is multi-day
uint8 brushCostMissedDay; // Cost in brush to mint the promotion if they miss a day (in ether), max 25.5, base 100
uint8 numDaysHitNeededForStreakBonus; // How many days to hit for the streak bonus
uint8 numDaysClaimablePeriodStreakBonus; // If there is a streak bonus, how many days to claim it after the promotion ends. If no final day bonus, set to 0
uint8 numRandomStreakBonusItemsToPick1; // Number of items to pick for the streak bonus
uint8 numRandomStreakBonusItemsToPick2; // Number of random items to pick for the streak bonus
// Misc
uint16[] randomStreakBonusItemTokenIds1;
uint32[] randomStreakBonusAmounts1;
uint16[] randomStreakBonusItemTokenIds2; // Not used yet
uint32[] randomStreakBonusAmounts2; // Not used yet
uint16[] guaranteedStreakBonusItemTokenIds; // Not used yet
uint16[] guaranteedStreakBonusAmounts; // Not used yet
// Single and multiday
uint16[] guaranteedItemTokenIds; // Guaranteed items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
uint32[] guaranteedAmounts; // Corresponding amounts to the itemTokenIds
uint16[] randomItemTokenIds; // Possible items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
uint32[] randomAmounts; // Corresponding amounts to the randomItemTokenIds
}
uint constant BRUSH_COST_MISSED_DAY_MUL = 10;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Skill} from "./misc.sol";
struct QuestInput {
uint16 dependentQuestId; // The quest that must be completed before this one can be started
uint16 actionId1; // action to do
uint16 actionNum1; // how many (up to 65535)
uint16 actionId2; // another action to do
uint16 actionNum2; // how many (up to 65535)
uint16 actionChoiceId; // actionChoice to perform
uint16 actionChoiceNum; // how many to do (base number), (up to 65535)
Skill skillReward; // The skill to reward XP to
uint16 skillXPGained; // The amount of XP to give (up to 65535)
uint16 rewardItemTokenId1; // Reward an item
uint16 rewardAmount1; // amount of the reward (up to 65535)
uint16 rewardItemTokenId2; // Reward another item
uint16 rewardAmount2; // amount of the reward (up to 65535)
uint16 burnItemTokenId; // Burn an item
uint16 burnAmount; // amount of the burn (up to 65535)
uint16 questId; // Unique id for this quest
bool isFullModeOnly; // If true this quest requires the user be evolved
uint8 worldLocation; // 0 is the main starting world
}
struct Quest {
uint16 dependentQuestId; // The quest that must be completed before this one can be started
uint16 actionId1; // action to do
uint16 actionNum1; // how many (up to 65535)
uint16 actionId2; // another action to do
uint16 actionNum2; // how many (up to 65535)
uint16 actionChoiceId; // actionChoice to perform
uint16 actionChoiceNum; // how many to do (base number), (up to 65535)
Skill skillReward; // The skill to reward XP to
uint16 skillXPGained; // The amount of XP to give (up to 65535)
uint16 rewardItemTokenId1; // Reward an item
uint16 rewardAmount1; // amount of the reward (up to 65535)
uint16 rewardItemTokenId2; // Reward another item
uint16 rewardAmount2; // amount of the reward (up to 65535)
uint16 burnItemTokenId; // Burn an item
uint16 burnAmount; // amount of the burn (up to 65535)
uint16 reserved; // Reserved for future use (previously was questId and cleared)
bytes1 packedData; // FullMode is last bit, first 6 bits is worldLocation
}
struct QuestV1 {
uint16 dependentQuestId; // The quest that must be completed before this one can be started
uint16 actionId1; // action to do
uint16 actionNum1; // how many (up to 65535)
uint16 actionId2; // another action to do
uint16 actionNum2; // how many (up to 65535)
uint16 actionChoiceId; // actionChoice to perform
uint16 actionChoiceNum; // how many to do (base number), (up to 65535)
Skill skillReward; // The skill to reward XP to
uint16 skillXPGained; // The amount of XP to give (up to 65535)
uint16 rewardItemTokenId1; // Reward an item
uint16 rewardAmount1; // amount of the reward (up to 65535)
uint16 rewardItemTokenId2; // Reward another item
uint16 rewardAmount2; // amount of the reward (up to 65535)
uint16 burnItemTokenId; // Burn an item
uint16 burnAmount; // amount of the burn (up to 65535)
uint16 questId; // Unique id for this quest
bool isFullModeOnly; // Was requireActionsCompletedBeforeBurning before
}
struct PlayerQuest {
uint32 questId;
uint16 actionCompletedNum1;
uint16 actionCompletedNum2;
uint16 actionChoiceCompletedNum;
uint16 burnCompletedAmount;
bool isFixed;
}
uint constant QUEST_PURSE_STRINGS = 5; // MAKE SURE THIS MATCHES definitions
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {BoostType, Equipment} from "./misc.sol";
struct GuaranteedReward {
uint16 itemTokenId;
uint16 rate; // num per hour (base 10, 1 decimal) for actions and num per duration for passive actions
}
struct RandomReward {
uint16 itemTokenId;
uint16 chance; // out of 65535
uint8 amount; // out of 255
}
struct PendingRandomReward {
uint16 actionId;
uint40 startTime;
uint24 xpElapsedTime;
uint64 queueId;
uint16 boostItemTokenId;
uint24 elapsedTime;
uint24 sentinelElapsedTime;
uint40 boostStartTime; // When the boost was started
// Full equipment at the time this was generated
uint8 fullAttireBonusRewardsPercent;
}
struct ActionRewards {
uint16 guaranteedRewardTokenId1;
uint16 guaranteedRewardRate1; // Num per hour base 10 (1 decimal) for actions (Max 6553.5 per hour), num per duration for passive actions
uint16 guaranteedRewardTokenId2;
uint16 guaranteedRewardRate2;
uint16 guaranteedRewardTokenId3;
uint16 guaranteedRewardRate3;
// Random chance rewards
uint16 randomRewardTokenId1;
uint16 randomRewardChance1; // out of 65535
uint8 randomRewardAmount1; // out of 255
uint16 randomRewardTokenId2;
uint16 randomRewardChance2;
uint8 randomRewardAmount2;
uint16 randomRewardTokenId3;
uint16 randomRewardChance3;
uint8 randomRewardAmount3;
uint16 randomRewardTokenId4;
uint16 randomRewardChance4;
uint8 randomRewardAmount4;
// No more room!
}
struct XPThresholdReward {
uint32 xpThreshold;
Equipment[] rewards;
}
enum InstantVRFActionType {
NONE,
GENERIC,
FORGING,
EGG
}
struct InstantVRFActionInput {
uint16 actionId;
uint16[] inputTokenIds;
uint24[] inputAmounts;
bytes data;
InstantVRFActionType actionType;
bool isFullModeOnly;
}
struct InstantVRFRandomReward {
uint16 itemTokenId;
uint16 chance; // out of 65535
uint16 amount; // out of 65535
}
uint constant MAX_GUARANTEED_REWARDS_PER_ACTION = 3;
uint constant MAX_RANDOM_REWARDS_PER_ACTION = 4;
uint constant MAX_REWARDS_PER_ACTION = MAX_GUARANTEED_REWARDS_PER_ACTION + MAX_RANDOM_REWARDS_PER_ACTION;
uint constant MAX_CONSUMED_PER_ACTION = 3;
uint constant MAX_QUEST_REWARDS = 2;
uint constant TIER_1_DAILY_REWARD_START_XP = 0;
uint constant TIER_2_DAILY_REWARD_START_XP = 7_650;
uint constant TIER_3_DAILY_REWARD_START_XP = 33_913;
uint constant TIER_4_DAILY_REWARD_START_XP = 195_864;
uint constant TIER_5_DAILY_REWARD_START_XP = 784_726;
uint constant TIER_6_DAILY_REWARD_START_XP = 2_219_451;
// 4 bytes for each threshold, starts at 500 xp in decimal
bytes constant xpRewardBytes = hex"00000000000001F4000003E8000009C40000138800002710000075300000C350000186A00001D4C0000493E0000557300007A120000927C0000B71B0000DBBA0000F424000124F800016E360001B7740001E8480002625A0002932E0002DC6C0";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IBank {
function initialize(uint clanId, address bankRegistry) external;
function depositToken(address from, uint playerId, address token, uint amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IOracleRewardCB {
function newOracleRandomWords(uint randomWord) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface ISamWitchVRF {
function requestRandomWords(uint numWords, uint callbackGasLimit) external returns (bytes32 requestId);
function fulfillRandomWords(
bytes32 requestId,
address oracle,
address fulfillAddress,
uint256 callbackGasLimit,
uint256 numWords,
uint256[2] calldata publicKey,
uint256[4] calldata proof,
uint256[2] calldata uPoint,
uint256[4] calldata vComponents
) external returns (bool callSuccess);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
error CallerIsNotOwner();
error NewOwnerIsZeroAddress();
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert CallerIsNotOwner();
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert NewOwnerIsZeroAddress();
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable {
error NewImplementationIsNotAContract();
error NewImplementationNotUUPS();
error UnsupportedProxiableUUID();
error NewAdminIsZeroAddress();
error NewBeaconIsNotAContract();
error BeaconImplementationIsNotAContract();
error AddressIsNotContract();
function __ERC1967Upgrade_init() internal onlyInitializing {}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {}
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (!AddressUpgradeable.isContract(newImplementation)) {
revert NewImplementationIsNotAContract();
}
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
_functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != _IMPLEMENTATION_SLOT) {
revert UnsupportedProxiableUUID();
}
} catch {
revert NewImplementationNotUUPS();
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert NewAdminIsZeroAddress();
}
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (!AddressUpgradeable.isContract(newBeacon)) {
revert NewBeaconIsNotAContract();
}
if (!AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation())) {
revert BeaconImplementationIsNotAContract();
}
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
_functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @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) private returns (bytes memory) {
if (!AddressUpgradeable.isContract(target)) {
revert AddressIsNotContract();
}
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
error NotInitializing();
error IsInitializing();
error AlreadyInitialized();
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
if (
!((isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1))
) {
revert AlreadyInitialized();
}
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
if (!(!_initializing && _initialized < version)) {
revert AlreadyInitialized();
}
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
if (!_initializing) {
revert NotInitializing();
}
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
if (_initializing) {
revert IsInitializing();
}
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822ProxiableUpgradeable} from "@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol";
import {ERC1967UpgradeUpgradeable} from "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
error FunctionMustBeCalledThroughDelegateCall();
error FunctionMustBeCalledThroughActiveProxy();
error FunctionMustNotBeCalledThroughDelegateCall();
function __UUPSUpgradeable_init() internal onlyInitializing {}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
if (address(this) == __self) {
revert FunctionMustBeCalledThroughDelegateCall();
}
if (_getImplementation() != __self) {
revert FunctionMustBeCalledThroughActiveProxy();
}
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
if (address(this) != __self) {
revert FunctionMustNotBeCalledThroughDelegateCall();
}
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
error RecipientMayHaveReverted();
error CallToNonContract();
error InsufficientAllowance();
error InsufficientBalance();
/**
* @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
* ====
*
* [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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert InsufficientBalance();
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert RecipientMayHaveReverted();
}
}
/**
* @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) {
if (address(this).balance < value) {
revert InsufficientAllowance();
}
(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 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
if (!isContract(target)) {
revert CallToNonContract();
}
}
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
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.20;
import "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {}
function __Context_init_unchained() internal onlyInitializing {}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Initializable} from "./ozUpgradeable/proxy/utils/Initializable.sol";
import {ISamWitchVRF} from "./interfaces/ISamWitchVRF.sol";
// This is useful as a drop in replacement for the VRFConsumerBaseV2Upgradeable from Chainlink keeping storage compatibility
abstract contract SamWitchVRFConsumerUpgradeable is Initializable {
ISamWitchVRF internal samWitchVRF;
error CallerNotSamWitchVRF();
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
// solhint-disable-next-line func-name-mixedcase
function __SamWitchVRFConsumerUpgradeable_init(ISamWitchVRF _samWitchVRF) internal onlyInitializing {
samWitchVRF = _samWitchVRF;
}
/// @dev Reverts if the caller is not the SamWitchVRF contract.
modifier onlySamWitchVRF() {
if (msg.sender != address(samWitchVRF)) {
revert CallerNotSamWitchVRF();
}
_;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {UUPSUpgradeable} from "./ozUpgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "./ozUpgradeable/access/OwnableUpgradeable.sol";
import {UnsafeMath, U256} from "@0xdoublesharp/unsafe-math/contracts/UnsafeMath.sol";
// TODO: Find alternate VRF provider
import {SamWitchVRFConsumerUpgradeable} from "./SamWitchVRFConsumerUpgradeable.sol";
import {ISamWitchVRF} from "./interfaces/ISamWitchVRF.sol";
import {IOracleRewardCB} from "./interfaces/IOracleRewardCB.sol";
import {WorldLibrary} from "./WorldLibrary.sol";
// solhint-disable-next-line no-global-import
import "./globals/all.sol";
contract World is SamWitchVRFConsumerUpgradeable, UUPSUpgradeable, OwnableUpgradeable {
using UnsafeMath for U256;
using UnsafeMath for uint;
event RequestSent(uint requestId, uint32 numWords, uint lastRandomWordsUpdatedTime);
event RequestFulfilled(uint requestId, uint randomWord);
event AddActions(Action[] actions);
event EditActions(Action[] actions);
event AddActionChoices(uint16 actionId, uint16[] actionChoiceIds, ActionChoiceInput[] choices);
event EditActionChoices(uint16 actionId, uint16[] actionChoiceIds, ActionChoiceInput[] choices);
event RemoveActionChoices(uint16 actionId, uint16[] actionChoiceIds);
error RandomWordsCannotBeUpdatedYet();
error CanOnlyRequestAfterTheNextCheckpoint(uint currentTime, uint checkpoint);
error RequestAlreadyFulfilled();
error NoValidRandomWord();
error CanOnlyRequestAfter1DayHasPassed();
error ActionIdZeroNotAllowed();
error MinCannotBeGreaterThanMax();
error DynamicActionsCannotBeAdded();
error ActionAlreadyExists(uint16 actionId);
error ActionDoesNotExist();
error ActionChoiceIdZeroNotAllowed();
error DynamicActionsCannotBeSet();
error LengthMismatch();
error NoActionChoices();
error ActionChoiceAlreadyExists();
error ActionChoiceDoesNotExist();
error NotAFactorOf3600();
error NonCombatWithActionChoicesCannotHaveBothGuaranteedAndRandomRewards();
error InvalidReward();
error TooManyRewardsInPool();
error CallbackGasLimitTooHigh();
// Past request ids
uint[] public requestIds; // Each one is a set of random words for 1 day
mapping(uint requestId => uint randomWord) public randomWords;
uint40 public lastRandomWordsUpdatedTime;
uint40 private startTime;
uint40 private weeklyRewardCheckpoint;
bytes8 public thisWeeksRandomWordSegment; // Every 8 bits is a random segment for the day
uint24 private callbackGasLimit;
uint32 private constant NUM_WORDS = 1;
uint32 public constant MIN_RANDOM_WORDS_UPDATE_TIME = 1 days;
uint32 private constant MIN_DYNAMIC_ACTION_UPDATE_TIME = 1 days;
uint32 public constant NUM_DAYS_RANDOM_WORDS_INITIALIZED = 3;
mapping(uint actionId => ActionInfo actionInfo) public actions;
uint16[] private lastAddedDynamicActions;
uint private lastDynamicUpdatedTime;
/// @custom:oz-renamed-from dailyRewards
bytes32 dummy; // Not clean
mapping(uint actionId => mapping(uint16 choiceId => ActionChoice actionChoice)) private actionChoices;
mapping(uint actionId => CombatStats combatStats) private actionCombatStats;
mapping(uint actionId => ActionRewards actionRewards) private actionRewards;
IOracleRewardCB private quests;
mapping(uint tier => Equipment[]) public dailyRewardPool;
mapping(uint tier => Equipment[]) public weeklyRewardPool;
IOracleRewardCB private wishingWell;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address _vrf) external initializer {
__SamWitchVRFConsumerUpgradeable_init(ISamWitchVRF(_vrf));
__UUPSUpgradeable_init();
__Ownable_init();
startTime = uint40(
(block.timestamp / MIN_RANDOM_WORDS_UPDATE_TIME) *
MIN_RANDOM_WORDS_UPDATE_TIME -
(NUM_DAYS_RANDOM_WORDS_INITIALIZED + 1) *
1 days
); // Floor to the nearest day 00:00 UTC
lastRandomWordsUpdatedTime = uint40(startTime + NUM_DAYS_RANDOM_WORDS_INITIALIZED * 1 days);
weeklyRewardCheckpoint = uint40((block.timestamp - 4 days) / 1 weeks) * 1 weeks + 4 days + 1 weeks;
callbackGasLimit = 600_000;
// Initialize a few days worth of random words so that we have enough data to fetch the first day
for (U256 iter; iter.lt(NUM_DAYS_RANDOM_WORDS_INITIALIZED); iter = iter.inc()) {
uint i = iter.asUint256();
uint requestId = 200 + i;
requestIds.push(requestId);
emit RequestSent(requestId, NUM_WORDS, startTime + (i * 1 days) + 1 days);
uint[] memory _randomWords = new uint[](1);
_randomWords[0] = uint(
blockhash(block.number - NUM_DAYS_RANDOM_WORDS_INITIALIZED + i) ^
0x3632d8eba811d69784e6904a58de6e0ab55f32638189623b309895beaa6920c4
);
_fulfillRandomWords(requestId, _randomWords);
}
thisWeeksRandomWordSegment = bytes8(uint64(randomWords[0]));
}
function requestRandomWords() external returns (uint requestId) {
// Last one has not been fulfilled yet
if (requestIds.length != 0 && randomWords[requestIds[requestIds.length - 1]] == 0) {
revert RandomWordsCannotBeUpdatedYet();
}
uint40 newLastRandomWordsUpdatedTime = lastRandomWordsUpdatedTime + MIN_RANDOM_WORDS_UPDATE_TIME;
if (newLastRandomWordsUpdatedTime > block.timestamp) {
revert CanOnlyRequestAfterTheNextCheckpoint(block.timestamp, newLastRandomWordsUpdatedTime);
}
requestId = uint256(samWitchVRF.requestRandomWords(NUM_WORDS, callbackGasLimit));
requestIds.push(requestId);
lastRandomWordsUpdatedTime = newLastRandomWordsUpdatedTime;
emit RequestSent(requestId, NUM_WORDS, newLastRandomWordsUpdatedTime);
return requestId;
}
function fulfillRandomWords(bytes32 _requestId, uint[] memory _randomWords) external onlySamWitchVRF {
_fulfillRandomWords(uint(_requestId), _randomWords);
}
function getWeeklyReward(uint _tier, uint _playerId) public view returns (uint16 itemTokenId, uint24 amount) {
uint day = 7;
uint index = _getRewardIndex(_playerId, day, uint64(thisWeeksRandomWordSegment), weeklyRewardPool[_tier].length);
Equipment storage equipment = weeklyRewardPool[_tier][index];
return (equipment.itemTokenId, equipment.amount);
}
function getSpecificDailyReward(
uint _tier,
uint _playerId,
uint _day,
uint _randomWord
) public view returns (uint16 itemTokenId, uint24 amount) {
uint index = _getRewardIndex(_playerId, _day, _randomWord, dailyRewardPool[_tier].length);
Equipment storage equipment = dailyRewardPool[_tier][index];
return (equipment.itemTokenId, equipment.amount);
}
function getDailyReward(uint _tier, uint _playerId) external view returns (uint itemTokenId, uint amount) {
uint checkpoint = ((block.timestamp - 4 days) / 1 weeks) * 1 weeks + 4 days;
uint day = ((block.timestamp / 1 days) * 1 days - checkpoint) / 1 days;
return getSpecificDailyReward(_tier, _playerId, day, uint64(thisWeeksRandomWordSegment));
}
function getActiveDailyAndWeeklyRewards(
uint _tier,
uint _playerId
) external view returns (Equipment[8] memory rewards) {
for (uint i; i < 7; ++i) {
(rewards[i].itemTokenId, rewards[i].amount) = getSpecificDailyReward(
_tier,
_playerId,
i,
uint64(thisWeeksRandomWordSegment)
);
}
(rewards[7].itemTokenId, rewards[7].amount) = getWeeklyReward(_tier, _playerId);
}
function _getRandomWordOffset(uint _timestamp) private view returns (int) {
if (_timestamp < startTime) {
return -1;
}
return int((_timestamp - startTime) / MIN_RANDOM_WORDS_UPDATE_TIME);
}
function _getRandomWord(uint _timestamp) private view returns (uint) {
int offset = _getRandomWordOffset(_timestamp);
if (offset < 0 || requestIds.length <= uint(offset)) {
return 0;
}
return randomWords[requestIds[uint(offset)]];
}
function hasRandomWord(uint _timestamp) external view returns (bool) {
return _getRandomWord(_timestamp) != 0;
}
function getRandomWord(uint _timestamp) public view returns (uint randomWord) {
randomWord = _getRandomWord(_timestamp);
if (randomWord == 0) {
revert NoValidRandomWord();
}
}
function getMultipleWords(uint _timestamp) public view returns (uint[4] memory words) {
for (U256 iter; iter.lt(4); iter = iter.inc()) {
uint i = iter.asUint256();
words[i] = getRandomWord(_timestamp - (i * 1 days));
}
}
function getSkill(uint _actionId) external view returns (Skill) {
return actions[_actionId].skill;
}
function getActionRewards(uint _actionId) external view returns (ActionRewards memory) {
return actionRewards[_actionId];
}
function getActionInfo(uint _actionId) external view returns (ActionInfo memory info) {
return actions[_actionId];
}
function getXPPerHour(uint16 _actionId, uint16 _actionChoiceId) external view returns (uint24 xpPerHour) {
return _actionChoiceId != 0 ? actionChoices[_actionId][_actionChoiceId].xpPerHour : actions[_actionId].xpPerHour;
}
function getNumSpawn(uint16 _actionId) external view returns (uint numSpawned) {
return actions[_actionId].numSpawned;
}
function getCombatStats(uint16 _actionId) external view returns (CombatStats memory stats) {
stats = actionCombatStats[_actionId];
}
function getActionChoice(uint16 _actionId, uint16 _choiceId) external view returns (ActionChoice memory choice) {
ActionChoice storage actionChoice = actionChoices[_actionId][_choiceId];
choice.skill = actionChoice.skill;
choice.minXP = actionChoice.minXP;
choice.skillDiff = actionChoice.skillDiff;
choice.rate = actionChoice.rate;
choice.xpPerHour = actionChoice.xpPerHour;
choice.inputTokenId1 = actionChoice.inputTokenId1;
choice.inputAmount1 = actionChoice.inputAmount1;
choice.inputTokenId2 = actionChoice.inputTokenId2;
choice.inputAmount2 = actionChoice.inputAmount2;
choice.inputTokenId3 = actionChoice.inputTokenId3;
choice.inputAmount3 = actionChoice.inputAmount3;
choice.outputTokenId = actionChoice.outputTokenId;
choice.outputAmount = actionChoice.outputAmount;
choice.successPercent = actionChoice.successPercent;
choice.handItemTokenIdRangeMin = actionChoice.handItemTokenIdRangeMin;
choice.handItemTokenIdRangeMax = actionChoice.handItemTokenIdRangeMax;
choice.packedData = actionChoice.packedData;
// Only read second storage when needed
if (
(uint8(choice.packedData >> ACTION_CHOICE_USE_NEW_MIN_SKILL_SECOND_STORAGE_SLOT_BIT) & 1 == 1) ||
(uint8(choice.packedData >> ACTION_CHOICE_USE_ALTERNATE_INPUTS_SECOND_STORAGE_SLOT) & 1 == 1)
) {
choice.minSkill2 = actionChoice.minSkill2;
choice.minXP2 = actionChoice.minXP2;
choice.minSkill3 = actionChoice.minSkill3;
choice.minXP3 = actionChoice.minXP3;
choice.newInputAmount1 = actionChoice.newInputAmount1;
choice.newInputAmount2 = actionChoice.newInputAmount2;
choice.newInputAmount3 = actionChoice.newInputAmount3;
}
}
function getActionSuccessPercentAndMinXP(
uint16 _actionId
) external view returns (uint8 successPercent, uint32 minXP) {
return (actions[_actionId].successPercent, actions[_actionId].minXP);
}
function getRewardsHelper(
uint16 _actionId
) external view returns (ActionRewards memory, Skill skill, uint numSpanwed, uint8 worldLocation) {
return (
actionRewards[_actionId],
actions[_actionId].skill,
actions[_actionId].numSpawned,
actions[_actionId].worldLocation
);
}
function getRandomBytes(
uint _numTickets,
uint _startTimestamp,
uint _endTimestamp,
uint _playerId
) external view returns (bytes memory b) {
if (_numTickets <= 16) {
// 32 bytes
bytes32 word = bytes32(getRandomWord(_endTimestamp));
b = abi.encodePacked(_getRandomComponent(word, _startTimestamp, _endTimestamp, _playerId));
} else if (_numTickets <= MAX_UNIQUE_TICKETS_) {
// 4 * 32 bytes
uint[4] memory multipleWords = getMultipleWords(_endTimestamp);
for (U256 iter; iter.lt(4); iter = iter.inc()) {
uint i = iter.asUint256();
multipleWords[i] = uint(
_getRandomComponent(bytes32(multipleWords[i]), _startTimestamp, _endTimestamp, _playerId)
);
// XOR all the words with the first fresh random number to give more randomness to the existing random words
if (i != 0) {
multipleWords[i] = uint(keccak256(abi.encodePacked(multipleWords[i] ^ multipleWords[0])));
}
}
b = abi.encodePacked(multipleWords);
} else {
assert(false);
}
}
function _addAction(Action calldata _action) private {
if (_action.info.isDynamic) {
revert DynamicActionsCannotBeAdded();
}
if (actions[_action.actionId].skill != Skill.NONE) {
revert ActionAlreadyExists(_action.actionId);
}
_setAction(_action);
}
function _getRewardIndex(uint _playerId, uint _day, uint _randomWord, uint _length) private pure returns (uint) {
return uint(keccak256(abi.encodePacked(_randomWord, _playerId)) >> (_day * 8)) % _length;
}
function _setAction(Action calldata _action) private {
if (_action.actionId == 0) {
revert ActionIdZeroNotAllowed();
}
if (_action.info.handItemTokenIdRangeMin > _action.info.handItemTokenIdRangeMax) {
revert MinCannotBeGreaterThanMax();
}
if (_action.info.numSpawned != 0) {
// Combat
if ((3600 * SPAWN_MUL) % _action.info.numSpawned != 0) {
revert NotAFactorOf3600();
}
} else if (_action.guaranteedRewards.length != 0) {
// Non-combat guaranteed rewards. Only care about the first one as it's used for correctly taking into account partial loots.
if ((3600 * GUAR_MUL) % _action.guaranteedRewards[0].rate != 0) {
revert NotAFactorOf3600();
}
}
actions[_action.actionId] = _action.info;
// Set the rewards
ActionRewards storage actionReward = actionRewards[_action.actionId];
delete actionRewards[_action.actionId];
WorldLibrary.setActionGuaranteedRewards(_action.guaranteedRewards, actionReward);
WorldLibrary.setActionRandomRewards(_action.randomRewards, actionReward);
if (_action.info.skill == Skill.COMBAT) {
actionCombatStats[_action.actionId] = _action.combatStats;
} else {
bool actionHasGuaranteedRewards = _action.guaranteedRewards.length != 0;
bool actionHasRandomRewards = _action.randomRewards.length != 0;
if (actionHasGuaranteedRewards && actionHasRandomRewards && _action.info.actionChoiceRequired) {
revert NonCombatWithActionChoicesCannotHaveBothGuaranteedAndRandomRewards();
}
}
}
function _addActionChoice(
uint16 _actionId,
uint16 _actionChoiceId,
ActionChoiceInput calldata _actionChoiceInput
) private view {
if (_actionChoiceId == 0) {
revert ActionChoiceIdZeroNotAllowed();
}
if (actionChoices[_actionId][_actionChoiceId].skill != Skill.NONE) {
revert ActionChoiceAlreadyExists();
}
WorldLibrary.checkActionChoice(_actionChoiceInput);
}
function _editActionChoice(
uint16 _actionId,
uint16 _actionChoiceId,
ActionChoiceInput calldata _actionChoiceInput
) private view {
if (actionChoices[_actionId][_actionChoiceId].skill == Skill.NONE) {
revert ActionChoiceDoesNotExist();
}
WorldLibrary.checkActionChoice(_actionChoiceInput);
}
function _getRandomComponent(
bytes32 _word,
uint _startTimestamp,
uint _endTimestamp,
uint _playerId
) private pure returns (bytes32) {
return keccak256(abi.encodePacked(_word, _startTimestamp, _endTimestamp, _playerId));
}
function _packActionChoice(
ActionChoiceInput calldata _actionChoiceInput
) private pure returns (ActionChoice memory actionChoice) {
bytes1 packedData = bytes1(uint8(_actionChoiceInput.isFullModeOnly ? 1 << IS_FULL_MODE_BIT : 0));
if (_actionChoiceInput.minSkills.length > 1) {
packedData |= bytes1(uint8(1)) << ACTION_CHOICE_USE_NEW_MIN_SKILL_SECOND_STORAGE_SLOT_BIT;
}
bool anyInputExceedsStandardAmount = (_actionChoiceInput.inputAmounts.length > 0 &&
_actionChoiceInput.inputAmounts[0] > 255) ||
(_actionChoiceInput.inputAmounts.length > 1 && _actionChoiceInput.inputAmounts[1] > 255) ||
(_actionChoiceInput.inputAmounts.length > 2 && _actionChoiceInput.inputAmounts[2] > 255);
if (anyInputExceedsStandardAmount) {
packedData |= bytes1(uint8(1)) << ACTION_CHOICE_USE_ALTERNATE_INPUTS_SECOND_STORAGE_SLOT;
}
actionChoice = ActionChoice({
skill: _actionChoiceInput.skill,
minXP: _actionChoiceInput.minXPs.length != 0 ? _actionChoiceInput.minXPs[0] : 0,
skillDiff: _actionChoiceInput.skillDiff,
rate: _actionChoiceInput.rate,
xpPerHour: _actionChoiceInput.xpPerHour,
inputTokenId1: _actionChoiceInput.inputTokenIds.length > 0 ? _actionChoiceInput.inputTokenIds[0] : NONE,
inputAmount1: _actionChoiceInput.inputAmounts.length > 0 && !anyInputExceedsStandardAmount
? uint8(_actionChoiceInput.inputAmounts[0])
: 0,
inputTokenId2: _actionChoiceInput.inputTokenIds.length > 1 ? _actionChoiceInput.inputTokenIds[1] : NONE,
inputAmount2: _actionChoiceInput.inputAmounts.length > 1 && !anyInputExceedsStandardAmount
? uint8(_actionChoiceInput.inputAmounts[1])
: 0,
inputTokenId3: _actionChoiceInput.inputTokenIds.length > 2 ? _actionChoiceInput.inputTokenIds[2] : NONE,
inputAmount3: _actionChoiceInput.inputAmounts.length > 2 && !anyInputExceedsStandardAmount
? uint8(_actionChoiceInput.inputAmounts[2])
: 0,
outputTokenId: _actionChoiceInput.outputTokenId,
outputAmount: _actionChoiceInput.outputAmount,
successPercent: _actionChoiceInput.successPercent,
handItemTokenIdRangeMin: _actionChoiceInput.handItemTokenIdRangeMin,
handItemTokenIdRangeMax: _actionChoiceInput.handItemTokenIdRangeMax,
packedData: packedData,
reserved: bytes1(uint8(0)),
// Second storage slot
minSkill2: _actionChoiceInput.minSkills.length > 1 ? _actionChoiceInput.minSkills[1] : Skill.NONE,
minXP2: _actionChoiceInput.minXPs.length > 1 ? _actionChoiceInput.minXPs[1] : 0,
minSkill3: _actionChoiceInput.minSkills.length > 2 ? _actionChoiceInput.minSkills[2] : Skill.NONE,
minXP3: _actionChoiceInput.minXPs.length > 2 ? _actionChoiceInput.minXPs[2] : 0,
newInputAmount1: _actionChoiceInput.inputAmounts.length > 0 && anyInputExceedsStandardAmount
? _actionChoiceInput.inputAmounts[0]
: 0,
newInputAmount2: _actionChoiceInput.inputAmounts.length > 1 && anyInputExceedsStandardAmount
? _actionChoiceInput.inputAmounts[1]
: 0,
newInputAmount3: _actionChoiceInput.inputAmounts.length > 2 && anyInputExceedsStandardAmount
? _actionChoiceInput.inputAmounts[2]
: 0
});
}
function _fulfillRandomWords(uint _requestId, uint[] memory _randomWords) internal {
if (randomWords[_requestId] != 0) {
revert RequestAlreadyFulfilled();
}
if (_randomWords.length != NUM_WORDS) {
revert LengthMismatch();
}
uint randomWord = _randomWords[0];
if (randomWord == 0) {
// Not sure if 0 can be selected, but in case use previous block hash as pseudo random number
randomWord = uint(blockhash(block.number - 1));
}
randomWords[_requestId] = randomWord;
if (address(quests) != address(0)) {
quests.newOracleRandomWords(randomWord);
}
if (address(wishingWell) != address(0)) {
wishingWell.newOracleRandomWords(randomWord);
}
emit RequestFulfilled(_requestId, randomWord);
// Are we at the threshold for a new week
if (weeklyRewardCheckpoint <= ((block.timestamp) / 1 days) * 1 days) {
// Issue new daily rewards for each tier based on the new random words
thisWeeksRandomWordSegment = bytes8(uint64(randomWord));
weeklyRewardCheckpoint = uint40((block.timestamp - 4 days) / 1 weeks) * 1 weeks + 4 days + 1 weeks;
}
}
function addActions(Action[] calldata _actions) external onlyOwner {
U256 iter = _actions.length.asU256();
while (iter.neq(0)) {
iter = iter.dec();
uint16 i = iter.asUint16();
_addAction(_actions[i]);
}
emit AddActions(_actions);
}
function editActions(Action[] calldata _actions) external onlyOwner {
for (uint i = 0; i < _actions.length; ++i) {
if (actions[_actions[i].actionId].skill == Skill.NONE) {
revert ActionDoesNotExist();
}
_setAction(_actions[i]);
}
emit EditActions(_actions);
}
function addActionChoices(
uint16 _actionId,
uint16[] calldata _actionChoiceIds,
ActionChoiceInput[] calldata _actionChoices
) public onlyOwner {
emit AddActionChoices(_actionId, _actionChoiceIds, _actionChoices);
U256 actionChoiceLength = _actionChoices.length.asU256();
if (actionChoiceLength.neq(_actionChoiceIds.length)) {
revert LengthMismatch();
}
if (_actionChoiceIds.length == 0) {
revert NoActionChoices();
}
for (U256 iter; iter < actionChoiceLength; iter = iter.inc()) {
uint16 i = iter.asUint16();
_addActionChoice(_actionId, _actionChoiceIds[i], _actionChoices[i]);
// TODO: Could set the first storage slot only in cases where appropriate (same as editing)
actionChoices[_actionId][_actionChoiceIds[i]] = _packActionChoice(_actionChoices[i]);
}
}
// actionId of 0 means it is not tied to a specific action (combat)
function addBulkActionChoices(
uint16[] calldata _actionIds,
uint16[][] calldata _actionChoiceIds,
ActionChoiceInput[][] calldata _actionChoices
) external onlyOwner {
if (_actionIds.length != _actionChoices.length) {
revert LengthMismatch();
}
if (_actionIds.length == 0) {
revert NoActionChoices();
}
U256 actionIdsLength = _actionIds.length.asU256();
for (U256 iter; iter < actionIdsLength; iter = iter.inc()) {
uint16 i = iter.asUint16();
uint16 actionId = _actionIds[i];
addActionChoices(actionId, _actionChoiceIds[i], _actionChoices[i]);
}
}
function editActionChoices(
uint16 _actionId,
uint16[] calldata _actionChoiceIds,
ActionChoiceInput[] calldata _actionChoices
) external onlyOwner {
if (_actionChoiceIds.length == 0) {
revert NoActionChoices();
}
if (_actionChoiceIds.length != _actionChoices.length) {
revert LengthMismatch();
}
U256 actionIdsLength = _actionChoiceIds.length.asU256();
for (U256 iter; iter < actionIdsLength; iter = iter.inc()) {
uint16 i = iter.asUint16();
_editActionChoice(_actionId, _actionChoiceIds[i], _actionChoices[i]);
actionChoices[_actionId][_actionChoiceIds[i]] = _packActionChoice(_actionChoices[i]);
}
emit EditActionChoices(_actionId, _actionChoiceIds, _actionChoices);
}
function removeActionChoices(uint16 _actionId, uint16[] calldata _actionChoiceIds) external onlyOwner {
if (_actionChoiceIds.length == 0) {
revert NoActionChoices();
}
U256 length = _actionChoiceIds.length.asU256();
for (U256 iter; iter < length; iter = iter.inc()) {
uint16 i = iter.asUint16();
delete actionChoices[_actionId][_actionChoiceIds[i]];
}
emit RemoveActionChoices(_actionId, _actionChoiceIds);
}
function setQuests(IOracleRewardCB _quests) external onlyOwner {
quests = _quests;
}
function setWishingWell(IOracleRewardCB _wishingWell) external onlyOwner {
wishingWell = _wishingWell;
}
function setDailyRewardPool(uint _tier, Equipment[] calldata _dailyRewards) external onlyOwner {
if (_dailyRewards.length > 255) {
revert TooManyRewardsInPool();
}
delete dailyRewardPool[_tier];
for (uint i = 0; i < _dailyRewards.length; ++i) {
// Amount should be divisible by 10 to allow percentage increases to be applied (like clan bonuses)
if (_dailyRewards[i].itemTokenId == 0 || _dailyRewards[i].amount == 0 || _dailyRewards[i].amount % 10 != 0) {
revert InvalidReward();
}
dailyRewardPool[_tier].push(_dailyRewards[i]);
}
}
function setWeeklyRewardPool(uint _tier, Equipment[] calldata _weeklyRewards) external onlyOwner {
if (_weeklyRewards.length > 255) {
revert TooManyRewardsInPool();
}
delete weeklyRewardPool[_tier];
for (uint i = 0; i < _weeklyRewards.length; ++i) {
if (_weeklyRewards[i].itemTokenId == NONE || _weeklyRewards[i].amount == 0) {
revert InvalidReward();
}
weeklyRewardPool[_tier].push(_weeklyRewards[i]);
}
}
function setCallbackGasLimit(uint _gasLimit) external onlyOwner {
if (_gasLimit > 3_000_000) {
revert CallbackGasLimitTooHigh();
}
callbackGasLimit = uint24(_gasLimit);
}
function setVRF(address _vrf) external onlyOwner {
samWitchVRF = ISamWitchVRF(_vrf);
}
// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {UnsafeMath, U256} from "@0xdoublesharp/unsafe-math/contracts/UnsafeMath.sol";
// solhint-disable-next-line no-global-import
import "./globals/all.sol";
// This file contains methods for interacting with the World, used to decrease implementation deployment bytecode code.
library WorldLibrary {
using UnsafeMath for U256;
using UnsafeMath for uint;
error InputSpecifiedWithoutAmount();
error InputAmountsMustBeInOrder();
error TooManyInputItems();
error InvalidInputTokenId();
error LengthMismatch();
error InputItemNoDuplicates();
error InvalidSkill();
error MinimumSkillsNoDuplicates();
error TooManyMinSkills();
error OutputAmountCannotBeZero();
error OutputSpecifiedWithoutAmount();
error OutputTokenIdCannotBeEmpty();
error RandomRewardsMustBeInOrder(uint16 chance1, uint16 chance2);
error RandomRewardNoDuplicates();
error GuaranteedRewardsNoDuplicates();
error NotAFactorOf3600();
error TooManyGuaranteedRewards();
error TooManyRandomRewards();
error FirstMinSkillMustBeActionChoiceSkill();
function checkActionChoice(ActionChoiceInput calldata _actionChoiceInput) external pure {
uint16[] calldata inputTokenIds = _actionChoiceInput.inputTokenIds;
uint24[] calldata amounts = _actionChoiceInput.inputAmounts;
if (inputTokenIds.length > 3) {
revert TooManyInputItems();
}
if (inputTokenIds.length != amounts.length) {
revert LengthMismatch();
}
if (_actionChoiceInput.outputTokenId != NONE && _actionChoiceInput.outputAmount == 0) {
revert OutputAmountCannotBeZero();
}
if (_actionChoiceInput.outputTokenId == NONE && _actionChoiceInput.outputAmount != 0) {
revert OutputTokenIdCannotBeEmpty();
}
for (uint i; i < inputTokenIds.length; ++i) {
if (inputTokenIds[i] == 0) {
revert InvalidInputTokenId();
}
if (amounts[i] == 0) {
revert InputSpecifiedWithoutAmount();
}
if (i != inputTokenIds.length - 1) {
if (amounts[i] > amounts[i + 1]) {
revert InputAmountsMustBeInOrder();
}
for (uint j; j < inputTokenIds.length; ++j) {
if (j != i && inputTokenIds[i] == inputTokenIds[j]) {
revert InputItemNoDuplicates();
}
}
}
}
// Check minimum xp
Skill[] calldata minSkills = _actionChoiceInput.minSkills;
uint32[] calldata minXPs = _actionChoiceInput.minXPs;
// First minSkill must be the same as the action choice skill
if (minSkills.length > 0 && minSkills[0] != _actionChoiceInput.skill) {
revert FirstMinSkillMustBeActionChoiceSkill();
}
if (minSkills.length > 3) {
revert TooManyMinSkills();
}
if (minSkills.length != minXPs.length) {
revert LengthMismatch();
}
for (uint i; i < minSkills.length; ++i) {
if (minSkills[i] == Skill.NONE) {
revert InvalidSkill();
}
// Can only be 0 if it's the first one and there is more than one
if (minXPs[i] == 0 && (i != 0 || minSkills.length == 1)) {
revert InputSpecifiedWithoutAmount();
}
if (i != minSkills.length - 1) {
for (uint j; j < minSkills.length; ++j) {
if (j != i && minSkills[i] == minSkills[j]) {
revert MinimumSkillsNoDuplicates();
}
}
}
}
if (_actionChoiceInput.rate != 0) {
// Check that it is a factor of 3600
if ((3600 * RATE_MUL) % _actionChoiceInput.rate != 0) {
revert NotAFactorOf3600();
}
}
}
function setActionGuaranteedRewards(
GuaranteedReward[] calldata _guaranteedRewards,
ActionRewards storage _actionRewards
) external {
uint guaranteedRewardsLength = _guaranteedRewards.length;
if (guaranteedRewardsLength != 0) {
_actionRewards.guaranteedRewardTokenId1 = _guaranteedRewards[0].itemTokenId;
_actionRewards.guaranteedRewardRate1 = _guaranteedRewards[0].rate;
}
if (guaranteedRewardsLength > 1) {
_actionRewards.guaranteedRewardTokenId2 = _guaranteedRewards[1].itemTokenId;
_actionRewards.guaranteedRewardRate2 = _guaranteedRewards[1].rate;
if (_actionRewards.guaranteedRewardTokenId1 == _actionRewards.guaranteedRewardTokenId2) {
revert GuaranteedRewardsNoDuplicates();
}
}
if (guaranteedRewardsLength > 2) {
_actionRewards.guaranteedRewardTokenId3 = _guaranteedRewards[2].itemTokenId;
_actionRewards.guaranteedRewardRate3 = _guaranteedRewards[2].rate;
U256 bounds = guaranteedRewardsLength.dec().asU256();
for (U256 iter; iter < bounds; iter = iter.inc()) {
uint i = iter.asUint256();
if (_guaranteedRewards[i].itemTokenId == _guaranteedRewards[guaranteedRewardsLength.dec()].itemTokenId) {
revert GuaranteedRewardsNoDuplicates();
}
}
}
if (guaranteedRewardsLength > 3) {
revert TooManyGuaranteedRewards();
}
}
// Random rewards have most common one first
function setActionRandomRewards(RandomReward[] calldata _randomRewards, ActionRewards storage actionReward) external {
uint randomRewardsLength = _randomRewards.length;
if (randomRewardsLength != 0) {
actionReward.randomRewardTokenId1 = _randomRewards[0].itemTokenId;
actionReward.randomRewardChance1 = _randomRewards[0].chance;
actionReward.randomRewardAmount1 = _randomRewards[0].amount;
}
if (randomRewardsLength > 1) {
actionReward.randomRewardTokenId2 = _randomRewards[1].itemTokenId;
actionReward.randomRewardChance2 = _randomRewards[1].chance;
actionReward.randomRewardAmount2 = _randomRewards[1].amount;
if (actionReward.randomRewardChance2 > actionReward.randomRewardChance1) {
revert RandomRewardsMustBeInOrder(_randomRewards[0].chance, _randomRewards[1].chance);
}
if (actionReward.randomRewardTokenId1 == actionReward.randomRewardTokenId2) {
revert RandomRewardNoDuplicates();
}
}
if (randomRewardsLength > 2) {
actionReward.randomRewardTokenId3 = _randomRewards[2].itemTokenId;
actionReward.randomRewardChance3 = _randomRewards[2].chance;
actionReward.randomRewardAmount3 = _randomRewards[2].amount;
if (actionReward.randomRewardChance3 > actionReward.randomRewardChance2) {
revert RandomRewardsMustBeInOrder(_randomRewards[1].chance, _randomRewards[2].chance);
}
U256 bounds = randomRewardsLength.dec().asU256();
for (U256 iter; iter < bounds; iter = iter.inc()) {
uint i = iter.asUint256();
if (_randomRewards[i].itemTokenId == _randomRewards[randomRewardsLength.dec()].itemTokenId) {
revert RandomRewardNoDuplicates();
}
}
}
if (_randomRewards.length > 3) {
actionReward.randomRewardTokenId4 = _randomRewards[3].itemTokenId;
actionReward.randomRewardChance4 = _randomRewards[3].chance;
actionReward.randomRewardAmount4 = _randomRewards[3].amount;
if (actionReward.randomRewardChance4 > actionReward.randomRewardChance3) {
revert RandomRewardsMustBeInOrder(_randomRewards[2].chance, _randomRewards[3].chance);
}
U256 bounds = _randomRewards.length.dec().asU256();
for (U256 iter; iter < bounds; iter = iter.inc()) {
uint i = iter.asUint256();
if (_randomRewards[i].itemTokenId == _randomRewards[_randomRewards.length - 1].itemTokenId) {
revert RandomRewardNoDuplicates();
}
}
}
if (_randomRewards.length > 4) {
revert TooManyRandomRewards();
}
}
}