Transaction Hash:
Block:
14255753 at Feb-22-2022 12:02:02 PM +UTC
Transaction Fee:
0.00261539176783841 ETH
$5.43
Gas Used:
61,030 Gas / 42.854199047 Gwei
Emitted Events:
| 357 |
TransparentUpgradeableProxy.0xc87dac464bd9964598d47d6e7f7cbe0b76cad55b33430228240e72c18da0edf6( 0xc87dac464bd9964598d47d6e7f7cbe0b76cad55b33430228240e72c18da0edf6, 0x00000000000000000000000070cc0875ef229b781e6b1dc0867925c017179d17, 0x0000000000000000000000000000000000000000000000000000000000000007, 0x00000000000000000000000000000000000000000000000000000000000017c7 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x1aD91ee0...dA6B45836
Miner
| (Hiveon Pool) | 9,574.191997436642755205 Eth | 9,574.192057687391270155 Eth | 0.00006025074851495 | |
| 0x70Cc0875...017179d17 |
0.839164734641863744 Eth
Nonce: 361
|
0.836549342874025334 Eth
Nonce: 362
| 0.00261539176783841 | ||
| 0xA351B769...ec05C1E75 |
Execution Trace
TransparentUpgradeableProxy.bddb95c1( )
-
EthernalElvesV4.heal( healer=6087, target=343 )
File 1 of 2: TransparentUpgradeableProxy
File 2 of 2: EthernalElvesV4
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
// Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_changeAdmin(admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external ifAdmin returns (address admin_) {
admin_ = _getAdmin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external ifAdmin returns (address implementation_) {
implementation_ = _implementation();
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
*/
function changeAdmin(address newAdmin) external virtual ifAdmin {
_changeAdmin(newAdmin);
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeToAndCall(newImplementation, bytes(""), false);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./TransparentUpgradeableProxy.sol";
import "../../access/Ownable.sol";
/**
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
*/
contract ProxyAdmin is Ownable {
/**
* @dev Returns the current implementation of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("implementation()")) == 0x5c60da1b
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
require(success);
return abi.decode(returndata, (address));
}
/**
* @dev Returns the current admin of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("admin()")) == 0xf851a440
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
require(success);
return abi.decode(returndata, (address));
}
/**
* @dev Changes the admin of `proxy` to `newAdmin`.
*
* Requirements:
*
* - This contract must be the current admin of `proxy`.
*/
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
proxy.changeAdmin(newAdmin);
}
/**
* @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
proxy.upgradeTo(implementation);
}
/**
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
* {TransparentUpgradeableProxy-upgradeToAndCall}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
// solhint-disable-next-line no-inline-assembly
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback () external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive () external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.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 ERC1967Upgrade {
// 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 StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.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 {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
address oldImplementation = _getImplementation();
// Initial upgrade and setup call
_setImplementation(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
// Perform rollback test if not already in progress
StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
if (!rollbackTesting.value) {
// Trigger rollback using upgradeTo from the new implementation
rollbackTesting.value = true;
Address.functionDelegateCall(
newImplementation,
abi.encodeWithSignature(
"upgradeTo(address)",
oldImplementation
)
);
rollbackTesting.value = false;
// Check rollback was effective
require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
// Finally reset to the new implementation and log the upgrade
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
}
/**
* @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) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
/**
* @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 StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.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 StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(
Address.isContract(newBeacon),
"ERC1967: new beacon is not a contract"
);
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @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
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 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 {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// 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
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
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 StorageSlot {
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) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Context.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 Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @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 {
emit OwnershipTransferred(_owner, address(0));
_owner = 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
* publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
* continuation of the upgradability.
*
* The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is ERC1967Upgrade {
function upgradeTo(address newImplementation) external virtual {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallSecure(newImplementation, bytes(""), false);
}
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallSecure(newImplementation, data, true);
}
function _authorizeUpgrade(address newImplementation) internal virtual;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
abstract contract Proxiable is UUPSUpgradeable {
function _authorizeUpgrade(address newImplementation) internal override {
_beforeUpgrade(newImplementation);
}
function _beforeUpgrade(address newImplementation) internal virtual;
}
contract ChildOfProxiable is Proxiable {
function _beforeUpgrade(address newImplementation) internal virtual override {}
}
File 2 of 2: EthernalElvesV4
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.7;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./ERC721.sol";
import "./DataStructures.sol";
import "./Interfaces.sol";
//import "hardhat/console.sol";
// We are the Ethernal. The Ethernal Elves
// Written by 0xHusky & Beff Jezos. Everything is on-chain for all time to come.
// Version 2.0.0
// Release notes: Export Sentinel / Polygon
contract EthernalElvesV4 is ERC721 {
function name() external pure returns (string memory) { return "Ethernal Elves"; }
function symbol() external pure returns (string memory) { return "ELV"; }
using DataStructures for DataStructures.ActionVariables;
using DataStructures for DataStructures.Elf;
using DataStructures for DataStructures.Token;
IElfMetaDataHandler elfmetaDataHandler;
ICampaigns campaigns;
IERC20Lite public ren;
using ECDSA for bytes32;
//STATE
bool public isGameActive;
bool public isMintOpen;
bool public isWlOpen;
bool private initialized;
address dev1Address;
address dev2Address;
address terminus;
address public validator;
uint256 public INIT_SUPPLY;
uint256 public price;
bytes32 internal ketchup;
uint256[] public _remaining;
mapping(uint256 => uint256) public sentinels; //memory slot for Elfs
mapping(address => uint256) public bankBalances; //memory slot for bank balances
mapping(address => bool) public auth;
mapping(address => uint16) public whitelist;
/////NEW STORAGE FROM THIS LINE V3///////////////////////////////////////////////////////
bool public isTerminalOpen;
/////NEW STORAGE FROM THIS LINE V4///////////////////////////////////////////////////////
mapping(bytes => uint16) public usedRenSignatures;
function initialize(address _dev1Address, address _dev2Address) public {
require(!initialized, "Already initialized");
admin = msg.sender;
dev1Address = _dev1Address;
dev2Address = _dev2Address;
maxSupply = 6666;
INIT_SUPPLY = 3300;
initialized = true;
price = .088 ether;
_remaining = [250,660,2500]; //[200, 600, 2500]; //this is the supply of each whitelist role
validator = 0x80861814a8775de20F9506CF41932E95f80f7035;
}
function setAddresses(address _ren, address _inventory, address _campaigns, address _validator) public {
onlyOwner();
ren = IERC20Lite(_ren);
elfmetaDataHandler = IElfMetaDataHandler(_inventory);
campaigns = ICampaigns(_campaigns);
validator = _validator;
}
function setAuth(address[] calldata adds_, bool status) public {
onlyOwner();
for (uint256 index = 0; index < adds_.length; index++) {
auth[adds_[index]] = status;
}
}
//EVENTS
event Action(address indexed from, uint256 indexed action, uint256 indexed tokenId);
event BalanceChanged(address indexed owner, uint256 indexed amount, bool indexed subtract);
event Campaigns(address indexed owner, uint256 amount, uint256 indexed campaign, uint256 sector, uint256 indexed tokenId);
event CheckIn(address indexed from, uint256 timestamp, uint256 indexed tokenId, uint256 indexed sentinel);
event CheckOut(address indexed to, uint256 timestamp, uint256 indexed tokenId);
event RenTransferOut(address indexed from, uint256 timestamp, uint256 indexed renAmount);
//////////////EXPORT TO OTHER CHAINS/////////////////
function checkIn(uint256[] calldata ids, uint256 renAmount) public returns (bool) {
isPlayer();
require(isTerminalOpen, "Terminal is closed");
uint256 travelers = ids.length;
if (travelers > 0) {
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 8, msg.sender, 0, 0, false, false, false, 0);
emit CheckIn(msg.sender, block.timestamp, ids[index], sentinels[ids[index]]);
}
}
if (renAmount > 0) {
bankBalances[msg.sender] >= renAmount ? _setAccountBalance(msg.sender, renAmount, true) : ren.burn(msg.sender, renAmount);
emit RenTransferOut(msg.sender,block.timestamp,renAmount);
}
}
function checkOut(uint256[] calldata ids, uint256[] calldata sentinel, bytes[] memory signatures) public returns (bool) {
isPlayer();
require(isTerminalOpen, "Terminal is closed");
//Add this to
///All checks to happen in polygon
uint256 travelers = ids.length;
if (travelers > 0) {
for (uint256 index = 0; index < ids.length; index++) {
require(_isSignedByValidator(encodeSentinelForSignature(ids[index], msg.sender, sentinel[index]),signatures[index]), "incorrect signature");
sentinels[ids[index]] = sentinel[index];
_actions(ids[index], 0, msg.sender, 0, 0, false, false, false, 0);
emit CheckOut(msg.sender, block.timestamp, ids[index]);
}
}
}
function checkOutRen(uint256 renAmount, bytes memory renSignatures, uint256 timestamp) public returns (bool) {
isPlayer();
require(isTerminalOpen, "Terminal is closed");
require(usedRenSignatures[renSignatures] == 0, "Signature already used");
if(renAmount > 0){
require(_isSignedByValidator(encodeRenForSignature(renAmount, msg.sender, timestamp),renSignatures), "incorrect signature");
usedRenSignatures[renSignatures] = 1;
ren.mint(msg.sender, renAmount);
}
}
//CheckOut Permissions
function encodeSentinelForSignature(uint256 id, address owner, uint256 sentinel) public pure returns (bytes32) {
return keccak256(
abi.encodePacked("\\x19Ethereum Signed Message:\
32",
keccak256(
abi.encodePacked(id, owner, sentinel))
)
);
}
function encodeRenForSignature(uint256 renAmount, address owner, uint256 timestamp) public pure returns (bytes32) {
return keccak256(
abi.encodePacked("\\x19Ethereum Signed Message:\
32",
keccak256(
abi.encodePacked(renAmount, owner, timestamp))
)
);
}
function _isSignedByValidator(bytes32 _hash, bytes memory _signature) private view returns (bool) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(_signature, 0x20))
s := mload(add(_signature, 0x40))
v := byte(0, mload(add(_signature, 0x60)))
}
address signer = ecrecover(_hash, v, r, s);
return signer == validator;
}
/////////////////////////////////////////////////////////////////
function mint() external payable returns (uint256 id) {
isPlayer();
require(isMintOpen, "Minting is closed");
uint256 cost;
(cost,) = getMintPriceLevel();
if (totalSupply <= INIT_SUPPLY) {
require(msg.value >= cost, "NotEnoughEther");
}else{
bankBalances[msg.sender] >= cost ? _setAccountBalance(msg.sender, cost, true) : ren.burn(msg.sender, cost);
}
return _mintElf(msg.sender);
}
//GAMEPLAY//
function unStake(uint256[] calldata ids) external {
isPlayer();
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 0, msg.sender, 0, 0, false, false, false, 0);
}
}
function sendCampaign(uint256[] calldata ids, uint256 campaign_, uint256 sector_, bool rollWeapons_, bool rollItems_, bool useitem_) external {
isPlayer();
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 2, msg.sender, campaign_, sector_, rollWeapons_, rollItems_, useitem_, 1);
}
}
function passive(uint256[] calldata ids) external {
isPlayer();
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 3, msg.sender, 0, 0, false, false, false, 0);
}
}
function returnPassive(uint256[] calldata ids) external {
isPlayer();
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 4, msg.sender, 0, 0, false, false, false, 0);
}
}
function forging(uint256[] calldata ids) external payable {
isPlayer();
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 5, msg.sender, 0, 0, false, false, false, 0);
}
}
function merchant(uint256[] calldata ids) external payable {
isPlayer();
for (uint256 index = 0; index < ids.length; index++) {
_actions(ids[index], 6, msg.sender, 0, 0, false, false, false, 0);
}
}
function heal(uint256 healer, uint256 target) external {
isPlayer();
_actions(healer, 7, msg.sender, target, 0, false, false, false, 0);
}
function withdrawTokenBalance() external {
require(bankBalances[msg.sender] > 0, "NoBalance");
ren.mint(msg.sender, bankBalances[msg.sender]);
bankBalances[msg.sender] = 0;
}
function withdrawSomeTokenBalance(uint256 amount) external {
require(bankBalances[msg.sender] > 0, "NoBalance");
require(bankBalances[msg.sender] - amount >= 0,"Overdraft Not permitted");
bankBalances[msg.sender] = bankBalances[msg.sender] - amount; //update ledger first
ren.mint(msg.sender, amount);
}
//INTERNALS
function _mintElf(address _to) private returns (uint16 id) {
uint256 rand = _rand();
{
DataStructures.Elf memory elf;
id = uint16(totalSupply + 1);
elf.owner = address(0);
elf.timestamp = block.timestamp;
elf.action = elf.weaponTier = elf.inventory = 0;
elf.primaryWeapon = 69; //69 is the default weapon - fists.
(,elf.level) = getMintPriceLevel();
elf.sentinelClass = uint16(_randomize(rand, "Class", id)) % 3;
elf.race = rand % 100 > 97 ? 3 : uint16(_randomize(rand, "Race", id)) % 3;
elf.hair = elf.race == 3 ? 0 : uint16(_randomize(rand, "Hair", id)) % 3;
elf.accessories = elf.sentinelClass == 0 ? (uint16(_randomize(rand, "Accessories", id)) % 2) + 3 : uint16(_randomize(rand, "Accessories", id)) % 2; //2 accessories MAX 7
uint256 _traits = DataStructures.packAttributes(elf.hair, elf.race, elf.accessories);
uint256 _class = DataStructures.packAttributes(elf.sentinelClass, elf.weaponTier, elf.inventory);
elf.healthPoints = DataStructures.calcHealthPoints(elf.sentinelClass, elf.level);
elf.attackPoints = DataStructures.calcAttackPoints(elf.sentinelClass, elf.weaponTier);
sentinels[id] = DataStructures._setElf(elf.owner, elf.timestamp, elf.action, elf.healthPoints, elf.attackPoints, elf.primaryWeapon, elf.level, _traits, _class);
}
_mint(_to, id);
}
function _actions(
uint256 id_,
uint action,
address elfOwner,
uint256 campaign_,
uint256 sector_,
bool rollWeapons,
bool rollItems,
bool useItem,
uint256 gameMode_)
private {
DataStructures.Elf memory elf = DataStructures.getElf(sentinels[id_]);
DataStructures.ActionVariables memory actions;
require(isGameActive);
require(ownerOf[id_] == msg.sender || elf.owner == msg.sender, "NotYourElf");
require(elf.action != 8, "elf in Polygon");
uint256 rand = _rand();
if(action == 0){//Unstake if currently staked
require(ownerOf[id_] == address(this));
require(elf.timestamp < block.timestamp, "elf busy");
if(elf.action == 3){
actions.timeDiff = (block.timestamp - elf.timestamp) / 1 days; //amount of time spent in camp CHANGE TO 1 DAYS!
elf.level = _exitPassive(actions.timeDiff, elf.level);
}
_transfer(address(this), elfOwner, id_);
elf.owner = address(0);
}else if(action == 2){//campaign loop - bloodthirst and rampage mode loop.
require(elf.timestamp < block.timestamp, "elf busy");
require(elf.action != 3, "exit passive mode first");
if(ownerOf[id_] != address(this)){
_transfer(elfOwner, address(this), id_);
elf.owner = elfOwner;
}
(elf.level, actions.reward, elf.timestamp, elf.inventory) = campaigns.gameEngine(campaign_, sector_, elf.level, elf.attackPoints, elf.healthPoints, elf.inventory, useItem);
uint256 options;
if(rollWeapons && rollItems){
options = 3;
}else if(rollWeapons){
options = 1;
}else if(rollItems){
options = 2;
}else{
options = 0;
}
if(options > 0){
(elf.weaponTier, elf.primaryWeapon, elf.inventory)
= DataStructures.roll(id_, elf.level, _rand(), options, elf.weaponTier, elf.primaryWeapon, elf.inventory);
}
if(gameMode_ == 1 || gameMode_ == 2) _setAccountBalance(msg.sender, actions.reward, false);
if(gameMode_ == 3) elf.level = elf.level + 1;
emit Campaigns(msg.sender, actions.reward, campaign_, sector_, id_);
}else if(action == 3){//passive campaign
require(elf.timestamp < block.timestamp, "elf busy");
if(ownerOf[id_] != address(this)){
_transfer(elfOwner, address(this), id_);
elf.owner = elfOwner;
}
elf.timestamp = block.timestamp; //set timestamp to current block time
}else if(action == 4){///return from passive mode
require(elf.action == 3);
actions.timeDiff = (block.timestamp - elf.timestamp) / 1 days; //amount of time spent in camp CHANGE TO 1 DAYS!
elf.level = _exitPassive(actions.timeDiff, elf.level);
/* if(actions.timeDiff >= 7){
actions.reward = 140 ether;
}
if(actions.timeDiff >= 14 && actions.timeDiff < 30){
actions.reward = 420 ether;
}
if(actions.timeDiff >= 30){
actions.reward = 1200 ether;
}
elf.level = elf.level + (actions.timeDiff * 1); //one level per day
elf.level = elf.level > 100 ? 100 : elf.level;
_setAccountBalance(msg.sender, actions.reward, false);
*/
}else if(action == 5){//forge loop for weapons
require(msg.value >= .01 ether);
require(elf.action != 3); //Cant roll in passve mode
//
// (elf.weaponTier, elf.primaryWeapon, elf.inventory) = DataStructures.roll(id_, elf.level, rand, 1, elf.weaponTier, elf.primaryWeapon, elf.inventory);
(elf.primaryWeapon, elf.weaponTier) = _rollWeapon(elf.level, id_, rand);
}else if(action == 6){//item or merchant loop
require(msg.value >= .01 ether);
require(elf.action != 3); //Cant roll in passve mode
(elf.weaponTier, elf.primaryWeapon, elf.inventory) = DataStructures.roll(id_, elf.level, rand, 2, elf.weaponTier, elf.primaryWeapon, elf.inventory);
}else if(action == 7){//healing loop
require(elf.sentinelClass == 0, "not a healer");
require(elf.action != 3, "cant heal while passive"); //Cant heal in passve mode
require(elf.timestamp < block.timestamp, "elf busy");
if(ownerOf[id_] != address(this)){
_transfer(elfOwner, address(this), id_);
elf.owner = elfOwner;
}
elf.timestamp = block.timestamp + (12 hours);
elf.level = elf.level + 1;
{
DataStructures.Elf memory hElf = DataStructures.getElf(sentinels[campaign_]);//using the campaign varialbe for elfId here.
require(ownerOf[campaign_] == msg.sender || hElf.owner == msg.sender, "NotYourElf");
if(block.timestamp < hElf.timestamp){
actions.timeDiff = hElf.timestamp - block.timestamp;
actions.timeDiff = actions.timeDiff > 0 ?
hElf.sentinelClass == 0 ? 0 :
hElf.sentinelClass == 1 ? actions.timeDiff * 1/4 :
actions.timeDiff * 1/2
: actions.timeDiff;
hElf.timestamp = hElf.timestamp - actions.timeDiff;
}
actions.traits = DataStructures.packAttributes(hElf.hair, hElf.race, hElf.accessories);
actions.class = DataStructures.packAttributes(hElf.sentinelClass, hElf.weaponTier, hElf.inventory);
sentinels[campaign_] = DataStructures._setElf(hElf.owner, hElf.timestamp, hElf.action, hElf.healthPoints, hElf.attackPoints, hElf.primaryWeapon, hElf.level, actions.traits, actions.class);
}
}else if (action == 8){//checkIn loop Do not remove
if(ownerOf[id_] != address(this)){
_transfer(elfOwner, address(this), id_);
elf.owner = elfOwner;
}
}
actions.traits = DataStructures.packAttributes(elf.hair, elf.race, elf.accessories);
actions.class = DataStructures.packAttributes(elf.sentinelClass, elf.weaponTier, elf.inventory);
elf.healthPoints = DataStructures.calcHealthPoints(elf.sentinelClass, elf.level);
elf.attackPoints = DataStructures.calcAttackPoints(elf.sentinelClass, elf.weaponTier);
elf.level = elf.level > 100 ? 100 : elf.level;
elf.action = action;
sentinels[id_] = DataStructures._setElf(elf.owner, elf.timestamp, elf.action, elf.healthPoints, elf.attackPoints, elf.primaryWeapon, elf.level, actions.traits, actions.class);
emit Action(msg.sender, action, id_);
}
function _exitPassive(uint256 timeDiff, uint256 _level) private returns (uint256 level) {
uint256 rewards;
if(timeDiff >= 7){
rewards = 140 ether;
}
if(timeDiff >= 14 && timeDiff < 30){
rewards = 420 ether;
}
if(timeDiff >= 30){
rewards = 1200 ether;
}
level = _level + (timeDiff * 1); //one level per day
if(level >= 100){
level = 100;
}
_setAccountBalance(msg.sender, rewards, false);
}
function _rollWeapon(uint256 level, uint256 id, uint256 rand) internal pure returns (uint256 newWeapon, uint256 newWeaponTier) {
uint256 levelTier = level == 100 ? 5 : uint256((level/20) + 1);
uint256 chance = _randomize(rand, "Weapon", id) % 100;
if(chance > 10 && chance < 80){
newWeaponTier = levelTier;
}else if (chance > 80 ){
newWeaponTier = levelTier + 1 > 4 ? 4 : levelTier + 1;
}else{
newWeaponTier = levelTier - 1 < 1 ? 1 : levelTier - 1;
}
newWeapon = ((newWeaponTier - 1) * 3) + (rand % 3);
}
function _setAccountBalance(address _owner, uint256 _amount, bool _subtract) private {
_subtract ? bankBalances[_owner] -= _amount : bankBalances[_owner] += _amount;
emit BalanceChanged(_owner, _amount, _subtract);
}
//NOTE BEFF WE NEED TO CHANGE THIS
function getMintPriceLevel() public view returns (uint256 mintCost, uint256 mintLevel) {
if (totalSupply <= INIT_SUPPLY) return (price, 1);
if (totalSupply < 4000) return ( 60 ether, 3);
if (totalSupply < 4500) return ( 180 ether, 5);
if (totalSupply < 5000) return ( 360 ether, 15);
if (totalSupply < 5500) return ( 600 ether, 25);
if (totalSupply < 6000) return ( 900 ether, 35);
if (totalSupply < 6333) return ( 1800 ether, 45);
if (totalSupply < 6666) return ( 2700 ether, 60);
}
function _randomize(uint256 ran, string memory dom, uint256 ness) internal pure returns (uint256) {
return uint256(keccak256(abi.encode(ran,dom,ness)));}
function _rand() internal view returns (uint256) {
return uint256(keccak256(abi.encodePacked(msg.sender, block.difficulty, block.timestamp, block.basefee, ketchup)));}
//PUBLIC VIEWS
function tokenURI(uint256 _id) external view returns(string memory) {
return elfmetaDataHandler.getTokenURI(uint16(_id), sentinels[_id]);
}
function attributes(uint256 _id) external view returns(uint hair, uint race, uint accessories, uint sentinelClass, uint weaponTier, uint inventory){
uint256 character = sentinels[_id];
uint _traits = uint256(uint8(character>>240));
uint _class = uint256(uint8(character>>248));
hair = (_traits / 100) % 10;
race = (_traits / 10) % 10;
accessories = (_traits) % 10;
sentinelClass = (_class / 100) % 10;
weaponTier = (_class / 10) % 10;
inventory = (_class) % 10;
}
function getSentinel(uint256 _id) external view returns(uint256 sentinel){
return sentinel = sentinels[_id];
}
function getToken(uint256 _id) external view returns(DataStructures.Token memory token){
return DataStructures.getToken(sentinels[_id]);
}
function elves(uint256 _id) external view returns(address owner, uint timestamp, uint action, uint healthPoints, uint attackPoints, uint primaryWeapon, uint level) {
uint256 character = sentinels[_id];
owner = address(uint160(uint256(character)));
timestamp = uint(uint40(character>>160));
action = uint(uint8(character>>200));
healthPoints = uint(uint8(character>>208));
attackPoints = uint(uint8(character>>216));
primaryWeapon = uint(uint8(character>>224));
level = uint(uint8(character>>232));
}
//Modifiers but as functions. Less Gas
function isPlayer() internal {
uint256 size = 0;
address acc = msg.sender;
assembly { size := extcodesize(acc)}
require((msg.sender == tx.origin && size == 0));
ketchup = keccak256(abi.encodePacked(acc, block.coinbase));
}
function onlyOwner() internal view {
require(admin == msg.sender || auth[msg.sender] == true || dev1Address == msg.sender || dev2Address == msg.sender);
}
//Bridge and Tunnel Stuff
function modifyElfDNA(uint256 id, uint256 sentinel) external {
require (msg.sender == terminus || admin == msg.sender, "not terminus");
sentinels[id] = sentinel;
}
/* function pull(address owner_, uint256[] calldata ids) external {
require (msg.sender == terminus, "not terminus");
for (uint256 index = 0; index < ids.length; index++) {
_transfer(owner_, msg.sender, ids[index]);
}
ITerminus(msg.sender).pullCallback(owner_, ids);
}
*/
//ADMIN Only
function withdrawAll() public {
onlyOwner();
uint256 balance = address(this).balance;
uint256 devShare = balance/2;
require(balance > 0);
_withdraw(dev1Address, devShare);
_withdraw(dev2Address, devShare);
}
//Internal withdraw
function _withdraw(address _address, uint256 _amount) private {
(bool success, ) = _address.call{value: _amount}("");
require(success);
}
function flipActiveStatus() external {
onlyOwner();
isGameActive = !isGameActive;
}
function flipMint() external {
onlyOwner();
isMintOpen = !isMintOpen;
}
/*function flipWhitelist() external {
onlyOwner();
isWlOpen = !isWlOpen;
}*/
function flipTerminal() external {
onlyOwner();
isTerminalOpen = !isTerminalOpen;
}
function setAccountBalance(address _owner, uint256 _amount) public {
onlyOwner();
bankBalances[_owner] += _amount;
}
function reserve(uint256 _reserveAmount, address _to) public {
onlyOwner();
for (uint i = 0; i < _reserveAmount; i++) {
_mintElf(_to);
}
}
function setElfManually(uint id, uint8 _primaryWeapon, uint8 _weaponTier, uint8 _attackPoints, uint8 _healthPoints, uint8 _level, uint8 _inventory, uint8 _race, uint8 _class, uint8 _accessories) external {
onlyOwner();
DataStructures.Elf memory elf = DataStructures.getElf(sentinels[id]);
DataStructures.ActionVariables memory actions;
elf.owner = elf.owner;
elf.timestamp = elf.timestamp;
elf.action = elf.action;
elf.healthPoints = _healthPoints;
elf.attackPoints = _attackPoints;
elf.primaryWeapon = _primaryWeapon;
elf.level = _level;
elf.weaponTier = _weaponTier;
elf.inventory = _inventory;
elf.race = _race;
elf.sentinelClass = _class;
elf.accessories = _accessories;
actions.traits = DataStructures.packAttributes(elf.hair, elf.race, elf.accessories);
actions.class = DataStructures.packAttributes(elf.sentinelClass, elf.weaponTier, elf.inventory);
sentinels[id] = DataStructures._setElf(elf.owner, elf.timestamp, elf.action, elf.healthPoints, elf.attackPoints, elf.primaryWeapon, elf.level, actions.traits, actions.class);
}
/* function addManyToWhitelist(address[] calldata _addr, uint256 _whitelistRole) public {
onlyOwner();
for (uint256 index = 0; index < _addr.length; index++) {
whitelist[_addr[index]] = uint16(_whitelistRole);
}
}
*/
/*
function whitelistMint(uint256 qty, address to, uint256 roleIndex, bytes memory signature) public payable {
isPlayer();
require(_isSignedByValidator(encodeForSignature(to, roleIndex),signature), "incorrect signature"); /////Francesco Sullo Thanks for showing me how to do this. Follow @sullof
require(isWlOpen, "Whitelist is closed");
require(whitelist[to] != 1,"Wallet used already"); //not on whitelist
require(_remaining[roleIndex] > 0, "noneLeft");
require(qty > 0 && qty <= 2, "max 2"); //max 2
//Role:0 SOG 2 free Role:1 OG 1 free 1 paid Role:2 2 WL paid
// bytes32 messageHash = encodeForSignature(to, roleIndex);
// bool isValid = _isSignedByValidator(messageHash, signature);
// if(isValid){
// console.log("valid");
// }
uint256 amount = msg.value;
_remaining[roleIndex] = _remaining[roleIndex] - qty;
whitelist[to] = 1; //indicate that address is used
if(roleIndex == 0){
for (uint i = 0; i < qty; i++) {
_mintElf(to);
}
}else if(roleIndex == 1){
require(amount >= price * qty/2, "NotEnoughEther");
for (uint i = 0; i < qty; i++) {
_mintElf(to);
}
}else if(roleIndex == 2){
require(amount >= price * qty, "NotEnoughEther");
for (uint i = 0; i < qty; i++) {
_mintElf(to);
}
}
}
*/
/* function setTerminus(address _terminus) public {
onlyOwner();
terminus = _terminus;
}
function setInitialSupply(uint256 _initialSupply) public {
onlyOwner();
INIT_SUPPLY = _initialSupply;
}
*/
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
}
}
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.7;
/// @notice Modern and gas efficient ERC-721 + ERC-20/EIP-2612-like implementation,
/// including the MetaData, and partially, Enumerable extensions.
contract ERC721 {
/*///////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Approval(
address indexed owner,
address indexed spender,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
/*///////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
address implementation_;
address public admin;
/*///////////////////////////////////////////////////////////////
ERC-721 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
uint256 public maxSupply;
mapping(address => uint256) public balanceOf;
mapping(uint256 => address) public ownerOf;
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*///////////////////////////////////////////////////////////////
VIEW FUNCTION
//////////////////////////////////////////////////////////////*/
function owner() external view returns (address) {
return admin;
}
/*///////////////////////////////////////////////////////////////
ERC-20-LIKE LOGIC
//////////////////////////////////////////////////////////////*/
function transfer(address to, uint256 tokenId) external {
require(msg.sender == ownerOf[tokenId], "NOT_OWNER");
_transfer(msg.sender, to, tokenId);
}
/*///////////////////////////////////////////////////////////////
ERC-721 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId)
external
pure
returns (bool supported)
{
supported = interfaceId == 0x80ac58cd || interfaceId == 0x5b5e139f;
}
function approve(address spender, uint256 tokenId) external {
address owner_ = ownerOf[tokenId];
require(
msg.sender == owner_ || isApprovedForAll[owner_][msg.sender],
"NOT_APPROVED"
);
getApproved[tokenId] = spender;
emit Approval(owner_, spender, tokenId);
}
function setApprovalForAll(address operator, bool approved) external {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function transferFrom(address from, address to, uint256 tokenId) public {
address owner_ = ownerOf[tokenId];
require(
msg.sender == owner_ ||
msg.sender == getApproved[tokenId] ||
isApprovedForAll[owner_][msg.sender],
"NOT_APPROVED"
);
_transfer(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) external {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public {
transferFrom(from, to, tokenId);
if (to.code.length != 0) {
// selector = `onERC721Received(address,address,uint,bytes)`
(, bytes memory returned) = to.staticcall(
abi.encodeWithSelector(
0x150b7a02,
msg.sender,
from,
tokenId,
data
)
);
bytes4 selector = abi.decode(returned, (bytes4));
require(selector == 0x150b7a02, "NOT_ERC721_RECEIVER");
}
}
/*///////////////////////////////////////////////////////////////
INTERNAL UTILS
//////////////////////////////////////////////////////////////*/
function _transfer(address from, address to, uint256 tokenId) internal {
require(ownerOf[tokenId] == from);
balanceOf[from]--;
balanceOf[to]++;
delete getApproved[tokenId];
ownerOf[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _mint(address to, uint256 tokenId) internal {
require(ownerOf[tokenId] == address(0), "ALREADY_MINTED");
require(totalSupply++ <= maxSupply, "MAX SUPPLY REACHED");
// This is safe because the sum of all user
// balances can't exceed type(uint256).max!
unchecked {
balanceOf[to]++;
}
ownerOf[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal {
address owner_ = ownerOf[tokenId];
require(ownerOf[tokenId] != address(0), "NOT_MINTED");
totalSupply--;
balanceOf[owner_]--;
delete ownerOf[tokenId];
emit Transfer(owner_, address(0), tokenId);
}
}
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.7;
//import "hardhat/console.sol"; ///REMOVE BEFORE DEPLOYMENT
//v 1.0.3
library DataStructures {
/////////////DATA STRUCTURES///////////////////////////////
struct Elf {
address owner;
uint256 timestamp;
uint256 action;
uint256 healthPoints;
uint256 attackPoints;
uint256 primaryWeapon;
uint256 level;
uint256 hair;
uint256 race;
uint256 accessories;
uint256 sentinelClass;
uint256 weaponTier;
uint256 inventory;
}
struct Token {
address owner;
uint256 timestamp;
uint8 action;
uint8 healthPoints;
uint8 attackPoints;
uint8 primaryWeapon;
uint8 level;
uint8 hair;
uint8 race;
uint8 accessories;
uint8 sentinelClass;
uint8 weaponTier;
uint8 inventory;
}
struct ActionVariables {
uint256 reward;
uint256 timeDiff;
uint256 traits;
uint256 class;
}
struct Camps {
uint32 baseRewards;
uint32 creatureCount;
uint32 creatureHealth;
uint32 expPoints;
uint32 minLevel;
uint32 itemDrop;
uint32 weaponDrop;
uint32 spare;
}
/*Dont Delete, just keep it for reference
struct Attributes {
uint256 hair; //MAX 3 3 hair traits
uint256 race; //MAX 6 Body 4 for body
uint256 accessories; //MAX 7 4
uint256 sentinelClass; //MAX 3 3 in class
uint256 weaponTier; //MAX 6 5 tiers
uint256 inventory; //MAX 7 6 items
}
*/
/////////////////////////////////////////////////////
function getElf(uint256 character) internal pure returns(Elf memory _elf) {
_elf.owner = address(uint160(uint256(character)));
_elf.timestamp = uint256(uint40(character>>160));
_elf.action = uint256(uint8(character>>200));
_elf.healthPoints = uint256(uint8(character>>208));
_elf.attackPoints = uint256(uint8(character>>216));
_elf.primaryWeapon = uint256(uint8(character>>224));
_elf.level = uint256(uint8(character>>232));
_elf.hair = (uint256(uint8(character>>240)) / 100) % 10;
_elf.race = (uint256(uint8(character>>240)) / 10) % 10;
_elf.accessories = (uint256(uint8(character>>240))) % 10;
_elf.sentinelClass = (uint256(uint8(character>>248)) / 100) % 10;
_elf.weaponTier = (uint256(uint8(character>>248)) / 10) % 10;
_elf.inventory = (uint256(uint8(character>>248))) % 10;
}
function getToken(uint256 character) internal pure returns(Token memory token) {
token.owner = address(uint160(uint256(character)));
token.timestamp = uint256(uint40(character>>160));
token.action = (uint8(character>>200));
token.healthPoints = (uint8(character>>208));
token.attackPoints = (uint8(character>>216));
token.primaryWeapon = (uint8(character>>224));
token.level = (uint8(character>>232));
token.hair = ((uint8(character>>240)) / 100) % 10; //MAX 3
token.race = ((uint8(character>>240)) / 10) % 10; //Max6
token.accessories = ((uint8(character>>240))) % 10; //Max7
token.sentinelClass = ((uint8(character>>248)) / 100) % 10; //MAX 3
token.weaponTier = ((uint8(character>>248)) / 10) % 10; //MAX 6
token.inventory = ((uint8(character>>248))) % 10; //MAX 7
token.hair = (token.sentinelClass * 3) + (token.hair + 1);
token.race = (token.sentinelClass * 4) + (token.race + 1);
token.primaryWeapon = token.primaryWeapon == 69 ? 69 : (token.sentinelClass * 15) + (token.primaryWeapon + 1);
token.accessories = (token.sentinelClass * 7) + (token.accessories + 1);
}
function _setElf(
address owner, uint256 timestamp, uint256 action, uint256 healthPoints,
uint256 attackPoints, uint256 primaryWeapon,
uint256 level, uint256 traits, uint256 class )
internal pure returns (uint256 sentinel) {
uint256 character = uint256(uint160(address(owner)));
character |= timestamp<<160;
character |= action<<200;
character |= healthPoints<<208;
character |= attackPoints<<216;
character |= primaryWeapon<<224;
character |= level<<232;
character |= traits<<240;
character |= class<<248;
return character;
}
//////////////////////////////HELPERS/////////////////
function packAttributes(uint hundreds, uint tens, uint ones) internal pure returns (uint256 packedAttributes) {
packedAttributes = uint256(hundreds*100 + tens*10 + ones);
return packedAttributes;
}
function calcAttackPoints(uint256 sentinelClass, uint256 weaponTier) internal pure returns (uint256 attackPoints) {
attackPoints = ((sentinelClass + 1) * 2) + (weaponTier * 2);
return attackPoints;
}
function calcHealthPoints(uint256 sentinelClass, uint256 level) internal pure returns (uint256 healthPoints) {
healthPoints = (level/(3) +2) + (20 - (sentinelClass * 4));
return healthPoints;
}
function calcCreatureHealth(uint256 sector, uint256 baseCreatureHealth) internal pure returns (uint256 creatureHealth) {
creatureHealth = ((sector - 1) * 12) + baseCreatureHealth;
return creatureHealth;
}
function roll(uint256 id_, uint256 level_, uint256 rand, uint256 rollOption_, uint256 weaponTier_, uint256 primaryWeapon_, uint256 inventory_)
internal pure
returns (uint256 newWeaponTier, uint256 newWeapon, uint256 newInventory) {
uint256 levelTier = level_ == 100 ? 5 : uint256((level_/20) + 1);
newWeaponTier = weaponTier_;
newWeapon = primaryWeapon_;
newInventory = inventory_;
if(rollOption_ == 1 || rollOption_ == 3){
//Weapons
uint16 chance = uint16(_randomize(rand, "Weapon", id_)) % 100;
// console.log("chance: ", chance);
if(chance > 10 && chance < 80){
newWeaponTier = levelTier;
}else if (chance > 80 ){
newWeaponTier = levelTier + 1 > 5 ? 5 : levelTier + 1;
}else{
newWeaponTier = levelTier - 1 < 1 ? 1 : levelTier - 1;
}
newWeapon = newWeaponTier == 0 ? 0 : ((newWeaponTier - 1) * 3) + (rand % 3);
}
if(rollOption_ == 2 || rollOption_ == 3){//Items Loop
uint16 morerand = uint16(_randomize(rand, "Inventory", id_));
uint16 diceRoll = uint16(_randomize(rand, "Dice", id_));
diceRoll = (diceRoll % 100);
if(diceRoll <= 20){
newInventory = levelTier > 3 ? morerand % 3 + 3: morerand % 6 + 1;
//console.log("Token#: ", id_);
//console.log("newITEM: ", newInventory);
}
}
}
function _randomize(uint256 ran, string memory dom, uint256 ness) internal pure returns (uint256) {
return uint256(keccak256(abi.encode(ran,dom,ness)));}
}
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.7;
interface IERC20Lite {
function transfer(address to, uint256 value) external returns (bool);
function burn(address from, uint256 value) external;
function mint(address to, uint256 value) external;
}
interface IElfMetaDataHandler {
function getTokenURI(uint16 id_, uint256 sentinel) external view returns (string memory);
}
interface ICampaigns {
function gameEngine(uint256 _campId, uint256 _sector, uint256 _level, uint256 _attackPoints, uint256 _healthPoints, uint256 _inventory, bool _useItem) external
returns(uint256 level, uint256 rewards, uint256 timestamp, uint256 inventory);
}
interface ITunnel {
function sendMessage(bytes calldata message_) external;
}
interface ITerminus {
function pullCallback(address owner, uint256[] calldata ids) external;
}
interface IElves {
function getSentinel(uint256 _id) external view returns(uint256 sentinel);
function modifyElfDNA(uint256 id, uint256 sentinel) external;
function pull(address owner_, uint256[] calldata ids) external;
function transfer(address to, uint256 id) external;
}
interface IERC721Lite {
function transferFrom(address from, address to, uint256 id) external;
function transfer(address to, uint256 id) external;
function ownerOf(uint256 id) external returns (address owner);
function mint(address to, uint256 tokenid) external;
}
interface IEthernalElves {
function presale(uint256 _reserveAmount, address _whitelister) external payable returns (uint256 id);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}