Overview
xDAI Balance
xDAI Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
38744889 | 57 days ago | Contract Creation | 0 xDAI |
Loading...
Loading
Contract Name:
OuterSpaceRewardFacet
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; import "./OuterSpaceFacetBase.sol"; contract OuterSpaceRewardFacet is OuterSpaceFacetBase { // solhint-disable-next-line no-empty-blocks constructor(Config memory config) OuterSpaceFacetBase(config) {} function getPrevRewardIds(address sponsor) external view returns (uint256) { return _prevRewardIds[sponsor]; } function addReward(uint256 location) external { _addReward(location, msg.sender); } function getRewardId(uint256 location) external view returns (uint256) { return _rewards[location]; } function hasRewardGoalBeenAchieved(address player, uint256 fullRewardId) external view returns (bool) { return _rewardsToWithdraw[player][fullRewardId]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// 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; 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"); (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"); (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"); (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"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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:\n32", hash)); } /** * @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: MIT pragma solidity ^0.8.0; abstract contract Proxied { /// @notice to be used by initialisation / postUpgrade function so that only the proxy's admin can execute them /// It also allows these functions to be called inside a contructor /// even if the contract is meant to be used without proxy modifier proxied() { address proxyAdminAddress = _proxyAdmin(); // With hardhat-deploy proxies // the proxyAdminAddress is zero only for the implementation contract // if the implementation contract want to be used as a standalone/immutable contract // it simply has to execute the `proxied` function // This ensure the proxyAdminAddress is never zero post deployment // And allow you to keep the same code for both proxied contract and immutable contract if (proxyAdminAddress == address(0)) { // ensure can not be called twice when used outside of proxy : no admin // solhint-disable-next-line security/no-inline-assembly assembly { sstore( 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ) } } else { require(msg.sender == proxyAdminAddress); } _; } modifier onlyProxyAdmin() { require(msg.sender == _proxyAdmin(), "NOT_AUTHORIZED"); _; } function _proxyAdmin() internal view returns (address ownerAddress) { // solhint-disable-next-line security/no-inline-assembly assembly { ownerAddress := sload(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103) } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; function _sendLogPayloadImplementation(bytes memory payload) internal view { address consoleAddress = CONSOLE_ADDRESS; /// @solidity memory-safe-assembly assembly { pop( staticcall( gas(), consoleAddress, add(payload, 32), mload(payload), 0, 0 ) ) } } function _castToPure( function(bytes memory) internal view fnIn ) internal pure returns (function(bytes memory) pure fnOut) { assembly { fnOut := fnIn } } function _sendLogPayload(bytes memory payload) internal pure { _castToPure(_sendLogPayloadImplementation)(payload); } function log() internal pure { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); } function logUint(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function logString(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function log(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint256 p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); } function log(uint256 p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); } function log(uint256 p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); } function log(uint256 p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); } function log(string memory p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); } function log(string memory p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); } function log(bool p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); } function log(address p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint256 p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); } function log(uint256 p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); } function log(uint256 p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); } function log(uint256 p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); } function log(uint256 p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); } function log(uint256 p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); } function log(uint256 p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); } function log(uint256 p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); } function log(uint256 p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); } function log(uint256 p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); } function log(uint256 p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); } function log(uint256 p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); } function log(uint256 p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); } function log(string memory p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); } function log(string memory p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); } function log(string memory p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); } function log(string memory p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); } function log(bool p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); } function log(bool p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); } function log(bool p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); } function log(address p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); } function log(address p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); } function log(address p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; import "hardhat-deploy/solc_0.8/proxy/Proxied.sol"; import "../interfaces/IAlliance.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/utils/Address.sol"; // import "hardhat/console.sol"; contract AllianceRegistry is Proxied { using ECDSA for bytes32; uint8 internal constant MAX_NUM_ALLIANCES = 4; mapping(address => mapping(IAlliance => uint256)) internal _allianceNonces; struct AllianceRow { IAlliance alliance; uint96 joinTime; } struct Alliances { AllianceRow alliance0; AllianceRow alliance1; AllianceRow alliance2; AllianceRow alliance3; } mapping(address => Alliances) internal _alliances; event AllianceLink(IAlliance indexed alliance, address indexed player, bool joining); function getAllianceDataAtSlot(address player, uint8 slot) external view returns ( IAlliance alliance, uint96 joinTime, uint256 nonce ) { Alliances storage alliances = _alliances[player]; if (slot == 0) { alliance = alliances.alliance0.alliance; joinTime = alliances.alliance0.joinTime; } else if (slot == 1) { alliance = alliances.alliance1.alliance; joinTime = alliances.alliance1.joinTime; } else if (slot == 2) { alliance = alliances.alliance2.alliance; joinTime = alliances.alliance2.joinTime; } else if (slot == 3) { alliance = alliances.alliance3.alliance; joinTime = alliances.alliance3.joinTime; } nonce = _allianceNonces[player][alliance]; } function getAllianceData(address player, IAlliance alliance) public view returns (uint96 joinTime, uint256 nonce) { nonce = _allianceNonces[player][alliance]; Alliances storage alliances = _alliances[player]; if (alliances.alliance0.alliance == alliance) { joinTime = alliances.alliance0.joinTime; } else if (alliances.alliance1.alliance == alliance) { joinTime = alliances.alliance1.joinTime; } else if (alliances.alliance2.alliance == alliance) { joinTime = alliances.alliance2.joinTime; } else if (alliances.alliance3.alliance == alliance) { joinTime = alliances.alliance3.joinTime; } } function havePlayersAnAllianceInCommon( address player1, address player2, uint256 timestamp ) external view returns (IAlliance alliance, uint96 joinTime) { Alliances storage p1Alliances = _alliances[player1]; Alliances storage p2Alliances = _alliances[player2]; AllianceRow[4] memory player1Alliances; AllianceRow[4] memory player2Alliances; uint256 num1 = 0; uint256 num2 = 0; for (uint256 i = 0; i < 4; i++) { if (i == num1) { AllianceRow memory allianceRow; if (i == 0) { allianceRow = p1Alliances.alliance0; } else if (i == 1) { allianceRow = p1Alliances.alliance1; } else if (i == 2) { allianceRow = p1Alliances.alliance2; } else if (i == 3) { allianceRow = p1Alliances.alliance3; } if (address(allianceRow.alliance) == address(0)) { // console.log("p1 exhausted"); return (alliance, joinTime); // the alliance leave ensure that there is no gap // TODO } player1Alliances[num1++] = allianceRow; } for (uint256 j = 0; j < 4; j++) { if (j == num2) { AllianceRow memory allianceRow; if (j == 0) { allianceRow = p2Alliances.alliance0; } else if (j == 1) { allianceRow = p2Alliances.alliance1; } else if (j == 2) { allianceRow = p2Alliances.alliance2; } else if (j == 3) { allianceRow = p2Alliances.alliance3; } if (address(allianceRow.alliance) == address(0)) { // console.log("p2 exhausted"); // return (alliance, joinTime); // the alliance leave ensure that there is no gap // TODO break; } player2Alliances[num2++] = allianceRow; } if (player1Alliances[i].alliance == player2Alliances[j].alliance) { if (player1Alliances[i].joinTime >= player2Alliances[j].joinTime) { if (player1Alliances[i].joinTime < timestamp) { return (player1Alliances[i].alliance, player1Alliances[i].joinTime); } else { // TODO check greater ? alliance = player1Alliances[i].alliance; joinTime = player1Alliances[i].joinTime; } } else { if (player2Alliances[j].joinTime < timestamp) { return (player2Alliances[j].alliance, player2Alliances[j].joinTime); } else { // TODO check greater ? alliance = player2Alliances[j].alliance; joinTime = player2Alliances[j].joinTime; } } } } } // console.log(address(alliance)); // console.log(joinTime); } // ----------------------------------------------------------------------------------------------------- // FROM PLAYER // ----------------------------------------------------------------------------------------------------- function joinAlliance(IAlliance alliance, bytes calldata data) external returns (bool joined) { Alliances storage alliances = _alliances[msg.sender]; uint256 slot = 0; if (address(alliances.alliance0.alliance) != address(0)) { slot++; } if (address(alliances.alliance1.alliance) != address(0)) { slot++; } if (address(alliances.alliance2.alliance) != address(0)) { slot++; } require(address(alliances.alliance3.alliance) == address(0), "MAX_NUM_ALLIANCES_REACHED"); joined = alliance.requestToJoin(msg.sender, data); if (joined) { if (slot == 0) { alliances.alliance0.alliance = alliance; alliances.alliance0.joinTime = uint96(block.timestamp); } else if (slot == 1) { alliances.alliance1.alliance = alliance; alliances.alliance1.joinTime = uint96(block.timestamp); } else if (slot == 2) { alliances.alliance2.alliance = alliance; alliances.alliance2.joinTime = uint96(block.timestamp); } else if (slot == 3) { alliances.alliance3.alliance = alliance; alliances.alliance3.joinTime = uint96(block.timestamp); } emit AllianceLink(alliance, msg.sender, true); } } function leaveAlliance(IAlliance alliance) external { _leaveAlliance(msg.sender, alliance); try alliance.playerHasLeft(msg.sender) {} catch {} // TODO ensure callback not failed due to low gas (1/64 rule) } // ----------------------------------------------------------------------------------------------------- // FROM ALLIANCE // ----------------------------------------------------------------------------------------------------- function addPlayerToAlliance( address player, uint32 nonce, bytes calldata signature ) external { _addPlayerToAlliance(player, nonce, signature); } struct PlayerSubmission { address addr; uint32 nonce; bytes signature; } function addMultiplePlayersToAlliance(PlayerSubmission[] calldata playerSubmissions) external { for (uint256 i = 0; i < playerSubmissions.length; i++) { _addPlayerToAlliance(playerSubmissions[i].addr, playerSubmissions[i].nonce, playerSubmissions[i].signature); } } function ejectPlayerFromAlliance(address player) external { _leaveAlliance(player, IAlliance(msg.sender)); } // ----------------------------------------------------------------------------------------------------- // INTERNAL // ----------------------------------------------------------------------------------------------------- function _addPlayerToAlliance( address player, uint32 nonce, bytes calldata signature ) internal { IAlliance alliance = IAlliance(msg.sender); Alliances storage alliances = _alliances[player]; uint256 slot = 0; if (address(alliances.alliance0.alliance) != address(0)) { require(alliances.alliance0.alliance != alliance, "ALREADY_JOINED"); slot++; } if (address(alliances.alliance1.alliance) != address(0)) { require(alliances.alliance1.alliance != alliance, "ALREADY_JOINED"); slot++; } if (address(alliances.alliance2.alliance) != address(0)) { require(alliances.alliance2.alliance != alliance, "ALREADY_JOINED"); slot++; } require(alliances.alliance3.alliance != alliance, "ALREADY_JOINED"); require(address(alliances.alliance3.alliance) == address(0), "MAX_NUM_ALLIANCES_REACHED"); uint256 currentNonce = _allianceNonces[player][alliance]; require(currentNonce == nonce, "INVALID_NONCE"); bytes memory message; if (nonce == 0) { message = abi.encodePacked( "\x19Ethereum Signed Message:\n56", "Join Alliance 0x0000000000000000000000000000000000000000" ); _writeUintAsHex(message, 28 + 55, uint160(msg.sender)); } else { message = abi.encodePacked( "\x19Ethereum Signed Message:\n76", "Join Alliance 0x0000000000000000000000000000000000000000 (nonce: 0)" ); _writeUintAsHex(message, 28 + 55, uint160(msg.sender)); _writeUintAsDecimal(message, 28 + 74, nonce); } // console.log(string(message)); bytes32 digest = keccak256(message); address signer = digest.recover(signature); require(player == signer, "INVALID_SIGNATURE"); if (slot == 0) { alliances.alliance0.alliance = alliance; alliances.alliance0.joinTime = uint96(block.timestamp); } else if (slot == 1) { alliances.alliance1.alliance = alliance; alliances.alliance1.joinTime = uint96(block.timestamp); } else if (slot == 2) { alliances.alliance2.alliance = alliance; alliances.alliance2.joinTime = uint96(block.timestamp); } else if (slot == 3) { alliances.alliance3.alliance = alliance; alliances.alliance3.joinTime = uint96(block.timestamp); } _allianceNonces[player][alliance] = nonce + 1; emit AllianceLink(alliance, player, true); _checkERC1155AndCallSafeTransfer(msg.sender, address(0), player, uint256(uint160(address(alliance))), 1); emit TransferSingle(msg.sender, address(0), player, uint256(uint160(address(alliance))), 1); } bytes internal constant hexAlphabet = "0123456789abcdef"; bytes internal constant decimalAlphabet = "0123456789"; function _writeUintAsHex( bytes memory data, uint256 endPos, uint256 num ) internal pure { while (num != 0) { data[endPos--] = bytes1(hexAlphabet[num % 16]); num /= 16; } } function _writeUintAsDecimal( bytes memory data, uint256 endPos, uint256 num ) internal pure { while (num != 0) { data[endPos--] = bytes1(decimalAlphabet[num % 10]); num /= 10; } } function _leaveAlliance(address player, IAlliance alliance) internal { Alliances storage alliances = _alliances[player]; IAlliance lastSlotAlliance; uint96 lastSlotJoinTime; require(address(alliances.alliance0.alliance) != address(0), "NOT_PART_OF_ANY_ALLIANCE"); if (address(alliances.alliance1.alliance) == address(0)) { lastSlotAlliance = alliances.alliance0.alliance; lastSlotJoinTime = alliances.alliance0.joinTime; alliances.alliance0.alliance = IAlliance(address(0)); alliances.alliance0.joinTime = 0; } else { if (address(alliances.alliance2.alliance) == address(0)) { lastSlotAlliance = alliances.alliance1.alliance; lastSlotJoinTime = alliances.alliance1.joinTime; alliances.alliance1.alliance = IAlliance(address(0)); alliances.alliance1.joinTime = 0; } else { if (address(alliances.alliance3.alliance) == address(0)) { lastSlotAlliance = alliances.alliance2.alliance; lastSlotJoinTime = alliances.alliance2.joinTime; alliances.alliance2.alliance = IAlliance(address(0)); alliances.alliance2.joinTime = 0; } else { lastSlotAlliance = alliances.alliance3.alliance; lastSlotJoinTime = alliances.alliance3.joinTime; alliances.alliance3.alliance = IAlliance(address(0)); alliances.alliance3.joinTime = 0; } } } if (alliance != lastSlotAlliance) { if (alliances.alliance0.alliance == alliance) { alliances.alliance0.alliance = lastSlotAlliance; alliances.alliance0.joinTime = lastSlotJoinTime; } else if (alliances.alliance1.alliance == alliance) { alliances.alliance1.alliance = lastSlotAlliance; alliances.alliance1.joinTime = lastSlotJoinTime; } else if (alliances.alliance2.alliance == alliance) { alliances.alliance2.alliance = lastSlotAlliance; alliances.alliance2.joinTime = lastSlotJoinTime; } else { revert("NOT_PART_OF_THE_ALLIANCE"); } } emit AllianceLink(alliance, player, false); emit TransferSingle(msg.sender, player, address(0), uint256(uint160(address(alliance))), 1); } function _msgSender() internal view returns (address) { return msg.sender; // TODO metatx } // --------------------------------------------------------------------- // Support For ERC-1155 // --------------------------------------------------------------------- event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); function balanceOf(address owner, uint256 id) external view returns (uint256 balance) { require(id == uint160(id), "INVALID_ID"); (uint96 joinTime, ) = getAllianceData(owner, IAlliance(address(uint160(id)))); if (joinTime > 0) { return 1; } else { return 0; } } function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory balances) { balances = new uint256[](owners.length); for (uint256 i = 0; i < owners.length; i++) { require(ids[i] == uint160(ids[i]), "INVALID_ID"); (uint96 joinTime, ) = getAllianceData(owners[i], IAlliance(address(uint160(ids[i])))); if (joinTime > 0) { balances[i] = 1; } else { balances[i] = 0; } } } function isApprovedForAll(address, address) external pure returns (bool) { return false; } function supportsInterface(bytes4 interfaceID) external pure returns (bool) { return interfaceID == 0xd9b67a26 || interfaceID == 0x01ffc9a7; } function _checkERC1155AndCallSafeTransfer( address operator, address from, address to, uint256 id, uint256 value ) internal returns (bool) { if (!Address.isContract(to)) { return true; } return ERC1155TokenReceiver(to).onERC1155Received(operator, from, id, value, "") == 0xf23a6e61; } } interface ERC1155TokenReceiver { function onERC1155Received( address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data ) external returns (bytes4); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IFreePlayToken is IERC20 { function mintViaNativeToken(address to, uint256 amount) external payable; function mintViaNativeTokenPlusSendExtraNativeTokens(address payable to, uint256 amount) external payable; function mintMultipleViaNativeTokenPlusSendExtraNativeTokens( address payable[] calldata tos, uint256[] calldata amounts, uint256[] calldata nativeTokenAmounts ) external payable; function mint( address from, address to, uint256 amount ) external; function burn( address from, address to, uint256 amount ) external; struct BurnFrom { address from; uint256 amount; } function burnMultiple(BurnFrom[] calldata list, address to) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; interface IAlliance { function requestToJoin(address player, bytes calldata data) external returns (bool); function playerHasLeft(address player) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; // TODO remove import "hardhat/console.sol"; library Extraction { function value( bytes32 data, uint8 leastSignificantBit, uint8 size ) internal pure returns (uint256) { return uint256((data >> leastSignificantBit)) % 2**size; } function value8Mod( bytes32 data, uint8 leastSignificantBit, uint8 mod ) internal pure returns (uint8) { return uint8(uint256((data >> leastSignificantBit)) % mod); } function value8(bytes32 data, uint8 leastSignificantBit) internal pure returns (uint8) { return uint8(uint256((data >> leastSignificantBit)) % 2**8); } // 1+1+2+3+4+6+7+8+8+7+6+4+3+2+1+1 // aproximation of normal distribution with mean=7.5 and standard deviation=3 for 16 values bytes32 constant n_m7_5_sd3 = 0x01223334444555555666666677777777888888889999999AAAAAABBBBCCCDDEF; function normal8(bytes32 data, uint8 leastSignificantBit) internal pure returns (uint8) { uint8 index = value8Mod(data, leastSignificantBit, 64); uint8 first = index / 2; uint8 second = index % 2; uint8 slot = uint8(n_m7_5_sd3[first]); if (second == 0) { return slot >> 4; } else { return slot % 16; } } function normal16( bytes32 data, uint8 leastSignificantBit, bytes32 selection ) internal pure returns (uint16) { uint8 index = normal8(data, leastSignificantBit); return uint16(uint8(selection[index * 2])) * 2**8 + uint16(uint8(selection[index * 2 + 1])); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; library Math { function mul( uint256 a, uint256 b, string memory overflowError ) internal pure returns (uint256 c) { require(b == 0 || a == 0 || ((c = a * b) / b) == a, overflowError); } function add( uint256 a, uint256 b, string memory overflowError ) internal pure returns (uint256 c) { require((c = a + b) >= a, overflowError); } function sub( uint256 a, uint256 b, string memory underflowError ) internal pure returns (uint256 c) { require((c = a - b) <= a, underflowError); } function mul18( uint256 a18, uint256 b18, string memory overflowError ) internal pure returns (uint256) { return mul(a18, b18, overflowError) / 10**18; } function div18( uint256 a18, uint256 b18, string memory overflowError ) internal pure returns (uint256) { return mul(a18, 10**18, overflowError) / b18; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a <= b ? a : b; } function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function smin(int256 a, int256 b) internal pure returns (int256) { return a <= b ? a : b; } function smax(int256 a, int256 b) internal pure returns (int256) { return a >= b ? a : b; } function sqrt(uint256 a) internal pure returns (uint256 c) { uint256 tmp = (a + 1) / 2; c = a; while (tmp < c) { c = tmp; tmp = ((a / tmp) + tmp) / 2; } } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; contract ImportingOuterSpaceConstants { uint256 internal constant DECIMALS_18 = 1e18; uint256 internal constant DECIMALS_14 = 1e14; uint32 internal constant ACTIVE_MASK = 2**31; int256 internal constant UINT32_MAX = 2**32 - 1; int256 internal constant UINT32_MIN = -2147483648; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; import "../types/ImportingOuterSpaceTypes.sol"; contract UsingOuterSpaceDataLayout is ImportingOuterSpaceTypes { mapping(uint256 => Planet) internal _planets; mapping(uint256 => Fleet) internal _fleets; mapping(address => uint256) internal _stakeReadyToBeWithdrawn; mapping(address => mapping(address => bool)) internal _operators; // Note: make it namespaces per user, currently it is possible (though unlikely) for 2 users to share a slot if one attack another and quickly send away spaceships mapping(uint256 => mapping(uint256 => InFlight)) internal _inFlight; Discovered internal _discovered; // rewards mapping(address => uint256) internal _prevRewardIds; mapping(uint256 => uint256) internal _rewards; mapping(address => mapping(uint256 => bool)) internal _rewardsToWithdraw; // This adds 20,000 gas to all resolution mapping(uint256 => mapping(address => mapping(uint256 => AccumulatedAttack))) internal _attacks; mapping(address => uint256) internal _freeStakeReadyToBeWithdrawn; mapping(uint256 => uint256) internal _planetFlagged; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; interface ImportingOuterSpaceEvents { event BlockTime(uint256 block, uint256 timestamp); event PlanetStake( address indexed acquirer, uint256 indexed location, uint32 numSpaceships, int40 travelingUpkeep, uint32 overflow, uint256 stake, bool freegift ); event FleetSent( address indexed fleetSender, address indexed fleetOwner, uint256 indexed from, address operator, uint256 fleet, uint32 quantity, uint32 newNumSpaceships, int40 newTravelingUpkeep, uint32 newOverflow ); event FleetRevealed( uint256 indexed fleetId, uint256 indexed from, uint256 indexed to, uint256 arrivalTimeWanted, bool gift, address specific, bytes32 secret, address fleetSender, address operator ); struct ArrivalData { uint32 newNumspaceships; int40 newTravelingUpkeep; uint32 newOverflow; uint32 numSpaceshipsAtArrival; uint32 taxLoss; uint32 fleetLoss; uint32 planetLoss; uint32 inFlightFleetLoss; uint32 inFlightPlanetLoss; uint32 accumulatedDefenseAdded; uint32 accumulatedAttackAdded; } event FleetArrived( uint256 indexed fleet, address indexed fleetOwner, address indexed destinationOwner, uint256 destination, bool gift, bool won, ArrivalData data ); event TravelingUpkeepRefund( uint256 indexed origin, uint256 indexed fleet, uint32 newNumspaceships, int40 newTravelingUpkeep, uint32 newOverflow ); event PlanetTransfer( address indexed previousOwner, address indexed newOwner, uint256 indexed location, uint32 newNumspaceships, int40 newTravelingUpkeep, uint32 newOverflow ); event PlanetReset(uint256 indexed location); event PlanetExit(address indexed owner, uint256 indexed location); event ExitComplete(address indexed owner, uint256 indexed location, uint256 stake); event RewardSetup(uint256 indexed location, address indexed giver, uint256 rewardId); event RewardToWithdraw(address indexed owner, uint256 indexed location, uint256 indexed rewardId); event StakeToWithdraw(address indexed owner, uint256 newStake, bool freegift); event Initialized( bytes32 genesis, uint256 resolveWindow, uint256 timePerDistance, uint256 exitDuration, uint32 acquireNumSpaceships, uint32 productionSpeedUp, uint256 frontrunningDelay, uint256 productionCapAsDuration, uint256 upkeepProductionDecreaseRatePer10000th, uint256 fleetSizeFactor6, uint32 initialSpaceExpansion, uint32 expansionDelta, uint256 giftTaxPer10000 ); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event Transfer(address indexed from, address indexed to, uint256 indexed location); event GeneratorChanged(address newGenerator); event GeneratorAdminChanged(address newGeneratorAdmin); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; import "../types/ImportingOuterSpaceTypes.sol"; import "../base/ImportingOuterSpaceConstants.sol"; import "../events/ImportingOuterSpaceEvents.sol"; import "../base/UsingOuterSpaceDataLayout.sol"; import "../../libraries/Extraction.sol"; import "../../libraries/Math.sol"; import "../../interfaces/IAlliance.sol"; import "../../alliances/AllianceRegistry.sol"; import "../../conquest_token/IFreePlayToken.sol"; interface StakingToken is IERC20 { function mint(address to, uint256 amount) external payable; } contract OuterSpaceFacetBase is ImportingOuterSpaceTypes, ImportingOuterSpaceConstants, ImportingOuterSpaceEvents, UsingOuterSpaceDataLayout { using Extraction for bytes32; StakingToken internal immutable _stakingToken; IFreePlayToken internal immutable _freeStakingToken; AllianceRegistry internal immutable _allianceRegistry; bytes32 internal immutable _genesis; uint256 internal immutable _resolveWindow; uint256 internal immutable _timePerDistance; uint256 internal immutable _exitDuration; uint32 internal immutable _acquireNumSpaceships; // TODO use uint256 uint32 internal immutable _productionSpeedUp; // TODO use uint256 uint256 internal immutable _frontrunningDelay; uint256 internal immutable _productionCapAsDuration; uint256 internal immutable _upkeepProductionDecreaseRatePer10000th; uint256 internal immutable _fleetSizeFactor6; uint32 internal immutable _initialSpaceExpansion; // = 16; uint32 internal immutable _expansionDelta; // = 8; // TODO use uint256 uint256 internal immutable _giftTaxPer10000; // = 2500; // // 4,5,5,10,10,15,15, 20, 20, 30,30,40,40,80,80,100 // bytes32 constant stakeRange = 0x000400050005000A000A000F000F00140014001E001E00280028005000500064; // 6, 8, 10, 12, 14, 16, 18, 20, 20, 22, 24, 32, 40, 48, 56, 72 // bytes32 internal constant stakeRange = 0x00060008000A000C000E00100012001400140016001800200028003000380048; bytes32 internal immutable _stakeRange; uint256 internal immutable _stakeMultiplier10000th; uint256 internal immutable _bootstrapSessionEndTime; uint256 internal immutable _infinityStartTime; struct Config { StakingToken stakingToken; IFreePlayToken freeStakingToken; AllianceRegistry allianceRegistry; bytes32 genesis; uint256 resolveWindow; uint256 timePerDistance; uint256 exitDuration; uint32 acquireNumSpaceships; uint32 productionSpeedUp; uint256 frontrunningDelay; uint256 productionCapAsDuration; uint256 upkeepProductionDecreaseRatePer10000th; uint256 fleetSizeFactor6; uint32 initialSpaceExpansion; uint32 expansionDelta; uint256 giftTaxPer10000; bytes32 stakeRange; uint256 stakeMultiplier10000th; uint256 bootstrapSessionEndTime; uint256 infinityStartTime; } constructor(Config memory config) { uint32 t = uint32(config.timePerDistance) / 4; // the coordinates space is 4 times bigger require(t * 4 == config.timePerDistance, "TIME_PER_DIST_NOT_DIVISIBLE_4"); _stakingToken = config.stakingToken; _freeStakingToken = config.freeStakingToken; _allianceRegistry = config.allianceRegistry; _genesis = config.genesis; _resolveWindow = config.resolveWindow; _timePerDistance = t; _exitDuration = config.exitDuration; _acquireNumSpaceships = config.acquireNumSpaceships; _productionSpeedUp = config.productionSpeedUp; _frontrunningDelay = config.frontrunningDelay; _productionCapAsDuration = config.productionCapAsDuration; _upkeepProductionDecreaseRatePer10000th = config.upkeepProductionDecreaseRatePer10000th; _fleetSizeFactor6 = config.fleetSizeFactor6; _initialSpaceExpansion = config.initialSpaceExpansion; _expansionDelta = config.expansionDelta; _giftTaxPer10000 = config.giftTaxPer10000; _stakeRange = config.stakeRange; _stakeMultiplier10000th = config.stakeMultiplier10000th; _bootstrapSessionEndTime = config.bootstrapSessionEndTime; _infinityStartTime = config.infinityStartTime; } // --------------------------------------------------------------------------------------------------------------- // PLANET STATE // --------------------------------------------------------------------------------------------------------------- struct PlanetUpdateState { uint256 location; uint40 lastUpdated; bool active; // modified uint32 numSpaceships; // modified int40 travelingUpkeep; // modified uint40 exitStartTime; uint40 newExitStartTime; // modified uint32 overflow; // modified address owner; address newOwner; // modified bytes32 data; uint24 futureExtraProduction; } function _createPlanetUpdateState( Planet memory planet, uint256 location ) internal view returns (PlanetUpdateState memory planetUpdate) { (bool active, uint32 currentNumSpaceships) = _activeNumSpaceships(planet.numSpaceships); planetUpdate.location = location; planetUpdate.lastUpdated = planet.lastUpdated; planetUpdate.active = active; planetUpdate.numSpaceships = currentNumSpaceships; planetUpdate.travelingUpkeep = planet.travelingUpkeep; planetUpdate.exitStartTime = planet.exitStartTime; planetUpdate.newExitStartTime = planet.exitStartTime; planetUpdate.overflow = planet.overflow; planetUpdate.owner = planet.owner; planetUpdate.newOwner = planet.owner; planetUpdate.data = _planetData(location); } // solhint-disable-next-line code-complexity function _computePlanetUpdateForTimeElapsed(PlanetUpdateState memory planetUpdate) internal view { if (planetUpdate.exitStartTime != 0) { if (_hasJustExited(planetUpdate.exitStartTime)) { planetUpdate.newExitStartTime = 0; planetUpdate.numSpaceships = 0; planetUpdate.travelingUpkeep = 0; planetUpdate.newOwner = address(0); planetUpdate.overflow = 0; planetUpdate.active = false; // event is emitted at the endof each write function // lastUpdated is set at the end directly on storage return; } } uint256 timePassed = block.timestamp - planetUpdate.lastUpdated; uint16 production = _production(planetUpdate.data); uint256 amountProducedTheWholeTime = (timePassed * uint256(_productionSpeedUp) * uint256(production)) / 1 hours; uint256 newNumSpaceships = planetUpdate.numSpaceships; uint256 extraUpkeepPaid = 0; if (_productionCapAsDuration > 0) { uint256 capWhenActive = _capWhenActive(production); uint256 cap = planetUpdate.active ? capWhenActive : 0; if (newNumSpaceships > cap) { uint256 decreaseRate = 1800; if (planetUpdate.overflow > 0) { decreaseRate = (uint256(planetUpdate.overflow) * 1800) / capWhenActive; if (decreaseRate < 1800) { decreaseRate = 1800; } } uint256 decrease = (timePassed * uint256(_productionSpeedUp) * decreaseRate) / 1 hours; if (decrease == 0) { // NOTE: To ensure a player cannot simply ping the planet continuously to avoid the decrease decrease = 1; } if (decrease > newNumSpaceships - cap) { decrease = newNumSpaceships - cap; } if (planetUpdate.active) { extraUpkeepPaid = decrease; } newNumSpaceships -= decrease; } else { if (planetUpdate.active) { uint256 increase = amountProducedTheWholeTime; if (planetUpdate.travelingUpkeep > 0) { uint256 timeBeforeUpkeepBackToZero = (uint256(uint40(planetUpdate.travelingUpkeep)) * 1 hours) / ((uint256(_productionSpeedUp) * uint256(production) * _upkeepProductionDecreaseRatePer10000th) / 10000); // 10,000 should be extracted as to not reach div by zero (like "1 hours") if (timeBeforeUpkeepBackToZero >= timePassed) { extraUpkeepPaid = increase; } else { extraUpkeepPaid = (timeBeforeUpkeepBackToZero * uint256(_productionSpeedUp) * uint256(production)) / 1 hours; if (extraUpkeepPaid > increase) { extraUpkeepPaid = increase; // TODO remove ? should not be possible } } increase -= extraUpkeepPaid; } uint256 maxIncrease = cap - newNumSpaceships; if (increase > maxIncrease) { extraUpkeepPaid += increase - maxIncrease; increase = maxIncrease; } newNumSpaceships += increase; // solhint-disable-next-line no-empty-blocks } else { // not effect currently, when inactive, cap == 0, meaning zero spaceship here // NOTE: we could do the following assuming we act on upkeepRepaid when inactive, we do not do that currently // extraUpkeepPaid = amountProducedTheWholeTime - upkeepRepaid; } } if (planetUpdate.active) { uint256 upkeepRepaid = ((amountProducedTheWholeTime * _upkeepProductionDecreaseRatePer10000th) / 10000) + extraUpkeepPaid; int256 newTravelingUpkeep = int256(planetUpdate.travelingUpkeep) - int40(uint40(upkeepRepaid)); if (newTravelingUpkeep < -int256(cap)) { newTravelingUpkeep = -int256(cap); } planetUpdate.travelingUpkeep = int40(newTravelingUpkeep); } } else { // TODO We are not using this branch, and in that branch there is no upkeep or overflow to consider if (planetUpdate.active) { newNumSpaceships += amountProducedTheWholeTime; } else { // NOTE no need to overflow here as there is no production cap, so no incentive to regroup spaceships uint256 decrease = (timePassed * uint256(_productionSpeedUp) * 1800) / 1 hours; if (decrease > newNumSpaceships) { decrease = newNumSpaceships; newNumSpaceships = 0; } else { newNumSpaceships -= decrease; } } } if (newNumSpaceships >= ACTIVE_MASK) { newNumSpaceships = ACTIVE_MASK - 1; } planetUpdate.numSpaceships = uint32(newNumSpaceships); if (!planetUpdate.active && planetUpdate.numSpaceships == 0) { planetUpdate.newOwner = address(0); } } function _setPlanet(Planet storage planet, PlanetUpdateState memory planetUpdate, bool exitInterupted) internal { if (planetUpdate.exitStartTime > 0 && planetUpdate.newExitStartTime == 0) { // NOTE: planetUpdate.newExitStartTime is only set to zero when exit is actually complete (not interupted) // interuption is handled by exitInterupted // exit has completed, newExitStartTime is not set to zero for interuption, // interuption is taken care below (owner changes) _handleExitComplete(planetUpdate); } if (planetUpdate.owner != planetUpdate.newOwner) { planet.owner = planetUpdate.newOwner; if (planetUpdate.newOwner != address(0)) { planet.ownershipStartTime = uint40(block.timestamp); } else { planet.ownershipStartTime = 0; } emit Transfer(planetUpdate.owner, planetUpdate.newOwner, planetUpdate.location); } if (exitInterupted) { // if (planetUpdate.newExitStartTime == 0 && planetUpdate.exitStartTime > 0) { // exit interupted // TODO event ? // } planet.exitStartTime = 0; } else if (planetUpdate.newExitStartTime != planetUpdate.exitStartTime) { planet.exitStartTime = planetUpdate.newExitStartTime; } planet.numSpaceships = _setActiveNumSpaceships(planetUpdate.active, planetUpdate.numSpaceships); planet.travelingUpkeep = planetUpdate.travelingUpkeep; planet.overflow = planetUpdate.overflow; planet.lastUpdated = uint40(block.timestamp); } // --------------------------------------------------------------------------------------------------------------- // STAKING / PRODUCTION CAPTURE // --------------------------------------------------------------------------------------------------------------- function _acquire(address player, uint256 stake, uint256 location, bool freegift) internal whenNotPaused { // ----------------------------------------------------------------------------------------------------------- // Initialise State Update // ----------------------------------------------------------------------------------------------------------- Planet storage planet = _getPlanet(location); PlanetUpdateState memory planetUpdate = _createPlanetUpdateState(planet, location); // ----------------------------------------------------------------------------------------------------------- // check requirements // ----------------------------------------------------------------------------------------------------------- require(stake == uint256(_stake(planetUpdate.data)) * (DECIMALS_14), "INVALID_STAKE_AMOUNT"); // ----------------------------------------------------------------------------------------------------------- // Compute Basic Planet Updates // ----------------------------------------------------------------------------------------------------------- _computePlanetUpdateForTimeElapsed(planetUpdate); // ----------------------------------------------------------------------------------------------------------- // Staking logic... // ----------------------------------------------------------------------------------------------------------- _computePlanetUpdateForStaking(player, planetUpdate); // ----------------------------------------------------------------------------------------------------------- // Write New State // ----------------------------------------------------------------------------------------------------------- _setPlanet(planet, planetUpdate, false); // _setAccountFromPlanetUpdate(planetUpdate); // ----------------------------------------------------------------------------------------------------------- // Update Space Discovery // ----------------------------------------------------------------------------------------------------------- _setDiscoveryAfterStaking(location); if (freegift) { _planetFlagged[location] = block.timestamp; } else { _planetFlagged[location] = 0; // staked with normal tokens } // ----------------------------------------------------------------------------------------------------------- // Emit Event // ----------------------------------------------------------------------------------------------------------- emit BlockTime(block.number, block.timestamp); emit PlanetStake( player, location, planetUpdate.numSpaceships, planetUpdate.travelingUpkeep, planetUpdate.overflow, stake, freegift ); _notifyGeneratorAdd(planetUpdate.newOwner, stake); } function _computePlanetUpdateForStaking(address player, PlanetUpdateState memory planetUpdate) internal view { require(!planetUpdate.active, "STILL_ACTIVE"); uint32 defense; // NOTE : natives are back automatically once spaceships reaches zero (here we know we are not active) // TODO consider making natives come back over time => would need to compute the time numSpaceship became zero if (planetUpdate.numSpaceships == 0) { defense = _natives(planetUpdate.data); } else { // Do not allow staking over occupied planets, they are going to zero at some point though require(planetUpdate.owner == player, "OCCUPIED"); } uint16 production = _production(planetUpdate.data); uint32 cap = uint32(_capWhenActive(production)); // We need to ensure a player staking on a planet it previously exited work here planetUpdate.newOwner = player; if (defense != 0) { (uint32 attackerLoss, ) = _computeFight( uint256(_acquireNumSpaceships), defense, 10000, _defense(planetUpdate.data) ); // attacker alwasy win as defense (and stats.native) is restricted to 3500 // (attackerLoss: 0, defenderLoss: 0) would mean defense was zero require(attackerLoss < _acquireNumSpaceships, "FAILED_CAPTURED"); planetUpdate.numSpaceships = _acquireNumSpaceships - attackerLoss; // NOTE cannot be overflow here as staking provide a number of spaceships below that planetUpdate.overflow = 0; } else { planetUpdate.numSpaceships += _acquireNumSpaceships; if (_productionCapAsDuration > 0) { if (planetUpdate.numSpaceships > cap) { planetUpdate.overflow = planetUpdate.numSpaceships - cap; } else { planetUpdate.overflow = 0; } } } // NOTE when staking on a planet, we set an allowance for traveling upkeep planetUpdate.travelingUpkeep = -int32(uint32((uint256(cap) * _upkeepProductionDecreaseRatePer10000th) / 10000)) - int32(planetUpdate.numSpaceships); planetUpdate.active = true; } // solhint-disable-next-line code-complexity function _setDiscoveryAfterStaking(uint256 location) internal { Discovered memory discovered = _discovered; int256 x = int256(int128(int256(location & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))); int256 y = int256(int128(int256(location >> 128))); bool changes = false; if (x < 0) { require(-x <= int256(uint256(discovered.minX)), "NOT_REACHABLE_YET_MINX"); x = -x + int32(_expansionDelta); if (x > UINT32_MAX) { x = UINT32_MAX; } if (int256(uint256(discovered.minX)) < x) { discovered.minX = uint32(uint256(x)); changes = true; } } else { require(x <= int256(uint256(discovered.maxX)), "NOT_REACHABLE_YET_MAXX"); x = x + int32(_expansionDelta); if (x > UINT32_MAX) { x = UINT32_MAX; } if (discovered.maxX < uint32(uint256(x))) { discovered.maxX = uint32(uint256(x)); changes = true; } } if (y < 0) { require(-y <= int256(uint256(discovered.minY)), "NOT_REACHABLE_YET_MINY"); y = -y + int32(_expansionDelta); if (y > UINT32_MAX) { y = UINT32_MAX; } if (int256(uint256(discovered.minY)) < y) { discovered.minY = uint32(uint256(y)); changes = true; } } else { require(y <= int256(uint256(discovered.maxY)), "NOT_REACHABLE_YET_MAXY"); y = y + int32(_expansionDelta); if (y > UINT32_MAX) { y = UINT32_MAX; } if (int256(uint256(discovered.maxY)) < y) { discovered.maxY = uint32(uint256(y)); changes = true; } } if (changes) { _discovered = discovered; } } // --------------------------------------------------------------------------------------------------------------- // EXITS / WITHDRAWALS // --------------------------------------------------------------------------------------------------------------- function _handleExitComplete(PlanetUpdateState memory planetUpdate) internal { uint256 stake = _completeExit(planetUpdate.owner, planetUpdate.location, planetUpdate.data); // Note we could Transfer to zero and Transfer from zero ? // optional so we can use it in the batch withdraw, uint256 flagTime = _planetFlagged[planetUpdate.location]; if (flagTime > 0) { // TODO reactivate once we siwtch to a fixed FreePlayToken // if (planetUpdate.exitStartTime >= flagTime + (6 days / _productionSpeedUp)) { // _freeStakingToken.burn(address(this), address(this), stake); // uint256 newStake = _stakeReadyToBeWithdrawn[planetUpdate.owner] + stake; // _stakeReadyToBeWithdrawn[planetUpdate.owner] = newStake; // emit StakeToWithdraw(planetUpdate.owner, newStake, false); // } else { uint256 newStake = _freeStakeReadyToBeWithdrawn[planetUpdate.owner] + stake; _freeStakeReadyToBeWithdrawn[planetUpdate.owner] = newStake; emit StakeToWithdraw(planetUpdate.owner, newStake, true); // } } else { uint256 newStake = _stakeReadyToBeWithdrawn[planetUpdate.owner] + stake; _stakeReadyToBeWithdrawn[planetUpdate.owner] = newStake; emit StakeToWithdraw(planetUpdate.owner, newStake, false); } } function _completeExit(address owner, uint256 location, bytes32 data) internal returns (uint256 stake) { stake = uint256(_stake(data)) * (DECIMALS_14); emit BlockTime(block.number, block.timestamp); emit ExitComplete(owner, location, stake); // -------------------------------------------------------- // Extra Reward was added // -------------------------------------------------------- uint256 rewardId = _rewards[location]; if (rewardId != 0) { // rewardId would contains the package. maybe this could be handled by an external contract _rewardsToWithdraw[owner][rewardId] = true; _rewards[location] = 0; // reset // if you had reward to a planet in he process of exiting, // you are adding the reward to the player exiting unless _setPlanetAfterExit is called first emit RewardToWithdraw(owner, location, rewardId); } // -------------------------------------------------------- } function _unsafe_exit_for(address owner, uint256 location) internal { Planet storage planet = _getPlanet(location); (bool active, ) = _activeNumSpaceships(planet.numSpaceships); require(active, "NOT_ACTIVE"); require(owner == planet.owner, "NOT_OWNER"); require(planet.exitStartTime == 0, "EXITING_ALREADY"); planet.exitStartTime = uint40(block.timestamp); emit BlockTime(block.number, block.timestamp); emit PlanetExit(owner, location); // stake is removed as soon as we start exist // If the exit is interupted, it is given to the player interupting _notifyGeneratorRemove(owner, uint256(_stake(_planetData(location))) * (DECIMALS_14)); } function _fetchAndWithdrawFor(address owner, uint256[] calldata locations) internal { uint256 addedStake = 0; uint256 freeAddedStake = 0; for (uint256 i = 0; i < locations.length; i++) { Planet storage planet = _getPlanet(locations[i]); if (_hasJustExited(planet.exitStartTime)) { require(owner == planet.owner, "NOT_OWNER"); emit Transfer(owner, address(0), locations[i]); uint256 flagTime = _planetFlagged[locations[i]]; if (flagTime > 0) { // TODO reactivate once we siwtch to a fixed FreePlayToken // if (planet.exitStartTime >= flagTime + (6 days / _productionSpeedUp)) { // uint256 extra = _completeExit(planet.owner, locations[i], _planetData(locations[i])); // addedStake += extra; // _freeStakingToken.burn(address(this), address(this), extra); // } else { freeAddedStake += _completeExit(planet.owner, locations[i], _planetData(locations[i])); // } } else { addedStake += _completeExit(planet.owner, locations[i], _planetData(locations[i])); } planet.owner = address(0); planet.ownershipStartTime = 0; planet.exitStartTime = 0; planet.numSpaceships = 0; planet.overflow = 0; planet.travelingUpkeep = 0; planet.lastUpdated = uint40(block.timestamp); } } uint256 newStake = _stakeReadyToBeWithdrawn[owner] + addedStake; _unsafe_withdrawAll(owner, newStake); uint256 newFreeStake = _freeStakeReadyToBeWithdrawn[owner] + freeAddedStake; _free_unsafe_withdrawAll(owner, newFreeStake); } function _unsafe_withdrawAll(address owner, uint256 amount) internal { _stakeReadyToBeWithdrawn[owner] = 0; emit StakeToWithdraw(owner, amount, false); require(_stakingToken.transfer(owner, amount), "FAILED_TRANSFER"); emit StakeToWithdraw(owner, 0, false); } function _free_unsafe_withdrawAll(address owner, uint256 amount) internal { _freeStakeReadyToBeWithdrawn[owner] = 0; emit StakeToWithdraw(owner, amount, true); require(_freeStakingToken.transfer(owner, amount), "FAILED_TRANSFER"); emit StakeToWithdraw(owner, 0, true); } function _hasJustExited(uint40 exitTime) internal view returns (bool) { if (exitTime == 0) { return false; } uint256 timestamp = block.timestamp; if (_bootstrapSessionEndTime > 0 && timestamp >= _bootstrapSessionEndTime && exitTime < _infinityStartTime) { return true; } return timestamp > exitTime + _exitDuration; } // --------------------------------------------------------------------------------------------------------------- // REWARDS // --------------------------------------------------------------------------------------------------------------- function _addReward(uint256 location, address sponsor) internal { uint256 rewardId = _rewards[location]; require(rewardId == 0, "REWARD_ALREADY_AT_THIS_LOCATION"); // TODO ? // Planet storage planet = _getPlanet(location); // require(planet.lastUpdated == 0, "PLANET_ALREADY_COLONIZED"); rewardId = ++_prevRewardIds[sponsor]; _rewards[location] = (uint256(uint160(sponsor)) << 96) + rewardId; emit RewardSetup(location, sponsor, rewardId); } // --------------------------------------------------------------------------------------------------------------- // FLEET SENDING // --------------------------------------------------------------------------------------------------------------- function _unsafe_sendFor(uint256 fleetId, address operator, FleetLaunch memory launch) internal whenNotPaused { // ----------------------------------------------------------------------------------------------------------- // Initialise State Update // ----------------------------------------------------------------------------------------------------------- Planet storage planet = _getPlanet(launch.from); PlanetUpdateState memory planetUpdate = _createPlanetUpdateState(planet, launch.from); // ----------------------------------------------------------------------------------------------------------- // check requirements // ----------------------------------------------------------------------------------------------------------- require(launch.quantity < 2 ** 30, "TOO_MANY_SPACESHIPS"); // only 2^30 because the first 2 bits = resolution require(launch.quantity > 0, "NO_SPACESHIPS"); require(planet.exitStartTime == 0, "PLANET_EXIT"); require(launch.fleetSender == planet.owner, "NOT_OWNER"); // ----------------------------------------------------------------------------------------------------------- // Compute Basic Planet Updates // ----------------------------------------------------------------------------------------------------------- _computePlanetUpdateForTimeElapsed(planetUpdate); // ----------------------------------------------------------------------------------------------------------- // Requirements post Planet Updates // ----------------------------------------------------------------------------------------------------------- require(planetUpdate.numSpaceships >= launch.quantity, "SPACESHIPS_NOT_ENOUGH"); // ----------------------------------------------------------------------------------------------------------- // Sending logic... // ----------------------------------------------------------------------------------------------------------- _computePlanetUpdateForFleetLaunch(planetUpdate, launch.quantity); // ----------------------------------------------------------------------------------------------------------- // Write New State // ----------------------------------------------------------------------------------------------------------- _setPlanet(planet, planetUpdate, false); // _setAccountFromPlanetUpdate(planetUpdate); _setFleetFlyingSlot(launch.from, launch.quantity); require(_fleets[fleetId].quantity == 0, "FLEET_EXISTS"); _fleets[fleetId] = Fleet({ launchTime: uint40(block.timestamp), owner: launch.fleetOwner, quantity: launch.quantity, futureExtraProduction: planetUpdate.futureExtraProduction, defender: address(0), arrivalTime: 0, defenderLoss: 0, victory: false, planetActive: false }); emit BlockTime(block.number, block.timestamp); emit FleetSent( launch.fleetSender, launch.fleetOwner, launch.from, operator, fleetId, launch.quantity, planetUpdate.numSpaceships, planetUpdate.travelingUpkeep, planetUpdate.overflow ); } function _computePlanetUpdateForFleetLaunch(PlanetUpdateState memory planetUpdate, uint32 quantity) internal view { planetUpdate.numSpaceships -= quantity; if (_productionCapAsDuration > 0) { if (planetUpdate.active) { // NOTE we do not update travelingUpkeep on Inactive planets // these get reset on staking uint16 production = _production(planetUpdate.data); uint256 cap = _capWhenActive(production); if (planetUpdate.numSpaceships < cap) { uint256 futureExtraProduction = cap - planetUpdate.numSpaceships; if (futureExtraProduction > quantity) { futureExtraProduction = quantity; } int256 newTravelingUpkeep = int256(planetUpdate.travelingUpkeep) + int256(futureExtraProduction); if (newTravelingUpkeep > int256(cap)) { newTravelingUpkeep = int256(cap); } planetUpdate.travelingUpkeep = int40(newTravelingUpkeep); planetUpdate.futureExtraProduction = uint24(futureExtraProduction); // cap is always smaller than uint24 } } if (planetUpdate.overflow > quantity) { planetUpdate.overflow -= quantity; } else { planetUpdate.overflow = 0; } } } function _setFleetFlyingSlot(uint256 from, uint32 quantity) internal { // ----------------------------------------------------------------------------------------------------------- // record flying fleets (to prevent front-running, see resolution) // ----------------------------------------------------------------------------------------------------------- uint256 timeSlot = block.timestamp / (_frontrunningDelay / 2); uint32 flying = _inFlight[from][timeSlot].flying; unchecked { flying = flying + quantity; } require(flying >= quantity, "ORBIT_OVERFLOW"); // unlikely to ever happen, // would need a huge amount of spaceships to be received and each in turn being sent // TOEXPLORE could also cap, that would result in some fleet being able to escape. _inFlight[from][timeSlot].flying = flying; // ----------------------------------------------------------------------------------------------------------- } // --------------------------------------------------------------------------------------------------------------- // FLEET RESOLUTION, ATTACK / REINFORCEMENT // --------------------------------------------------------------------------------------------------------------- struct ResolutionState { address fleetOwner; uint40 fleetLaunchTime; uint32 originalQuantity; uint32 fleetQuantity; bytes32 fromData; uint32 inFlightFleetLoss; uint32 inFlightPlanetLoss; bool gifting; bool taxed; bool victory; uint32 attackerLoss; uint32 defenderLoss; uint32 orbitDefense1; uint32 orbitDefenseDestroyed1; uint32 orbitDefense2; uint32 orbitDefenseDestroyed2; uint40 arrivalTime; uint32 accumulatedDefenseAdded; uint32 accumulatedAttackAdded; uint16 attackPower; uint24 futureExtraProduction; } function _resolveFleet(uint256 fleetId, FleetResolution calldata resolution) internal { // ----------------------------------------------------------------------------------------------------------- // Initialise State Update // ----------------------------------------------------------------------------------------------------------- Planet storage toPlanet = _getPlanet(resolution.to); PlanetUpdateState memory toPlanetUpdate = _createPlanetUpdateState(toPlanet, resolution.to); ResolutionState memory rState = _createResolutionState(_fleets[fleetId], resolution.from); // ----------------------------------------------------------------------------------------------------------- // check requirements // ----------------------------------------------------------------------------------------------------------- require( rState.fleetQuantity > 0, rState.fleetOwner != address(0) ? "FLEET_RESOLVED_ALREADY" : "FLEET_DO_NOT_EXIST" ); _requireCorrectDistance( resolution.distance, resolution.from, resolution.to, rState.fromData, toPlanetUpdate.data ); _requireCorrectTimeAndUpdateArrivalTime( resolution.distance, resolution.arrivalTimeWanted, rState.fleetLaunchTime, rState.fromData, rState ); if (_bootstrapSessionEndTime > 0) { uint256 timestamp = block.timestamp; if (timestamp >= _bootstrapSessionEndTime) { require(rState.fleetLaunchTime >= _infinityStartTime, "FLEET_LAUNCHED_IN_BOOTSTRAP"); } } // ----------------------------------------------------------------------------------------------------------- // Compute Basic Planet Updates // ----------------------------------------------------------------------------------------------------------- _computePlanetUpdateForTimeElapsed(toPlanetUpdate); address ownerAtArrival = toPlanetUpdate.newOwner; // this can be owner == address(0) uint32 numSpaceshipsAtArrival = toPlanetUpdate.numSpaceships; // ----------------------------------------------------------------------------------------------------------- // Traveling logic... // ----------------------------------------------------------------------------------------------------------- _computeInFlightLossForFleet(rState, resolution); // ----------------------------------------------------------------------------------------------------------- // Resolution logic... // ----------------------------------------------------------------------------------------------------------- _updateFleetForGifting(rState, resolution, toPlanetUpdate.newOwner); _computeResolutionResult(rState, toPlanetUpdate); // ----------------------------------------------------------------------------------------------------------- // Write New State // ----------------------------------------------------------------------------------------------------------- _recordInOrbitLossAfterAttack(rState, toPlanetUpdate); _recordOrbitLossAccountingForFleetOrigin(rState, resolution); _setTravelingUpkeepFromOrigin(fleetId, rState, resolution.from); _setPlanet(toPlanet, toPlanetUpdate, rState.victory); _setAccumulatedAttack(rState, toPlanetUpdate); _fleets[fleetId].quantity = (1 << 31) | _fleets[fleetId].quantity; _fleets[fleetId].defender = ownerAtArrival; _fleets[fleetId].defenderLoss = rState.defenderLoss; _fleets[fleetId].arrivalTime = uint40(block.timestamp); _fleets[fleetId].planetActive = toPlanetUpdate.active; _fleets[fleetId].victory = rState.victory; // ----------------------------------------------------------------------------------------------------------- // Events // ----------------------------------------------------------------------------------------------------------- _emitFleetArrived( fleetId, rState, ownerAtArrival, resolution, _arrivalData(rState, toPlanetUpdate, numSpaceshipsAtArrival) ); if (toPlanetUpdate.active && rState.victory) { // if active and the fleet was victorious we need to handle stake change of hands if (toPlanetUpdate.exitStartTime != 0) { // exit has been interupted // we add stake to new owner _notifyGeneratorAdd(toPlanetUpdate.newOwner, uint256(_stake(toPlanetUpdate.data)) * (DECIMALS_14)); } else { // there was no exit, so we move the stake _notifyGeneratorMove( toPlanetUpdate.owner, toPlanetUpdate.newOwner, uint256(_stake(toPlanetUpdate.data)) * (DECIMALS_14) ); } } } function _arrivalData( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate, uint32 numSpaceshipsAtArrival ) internal pure returns (ArrivalData memory arrivalData) { arrivalData.newNumspaceships = toPlanetUpdate.numSpaceships; arrivalData.newTravelingUpkeep = toPlanetUpdate.travelingUpkeep; arrivalData.newOverflow = toPlanetUpdate.overflow; arrivalData.numSpaceshipsAtArrival = numSpaceshipsAtArrival; arrivalData.taxLoss = rState.taxed ? (rState.originalQuantity - rState.inFlightFleetLoss) - rState.fleetQuantity : 0; arrivalData.fleetLoss = rState.attackerLoss; arrivalData.planetLoss = rState.defenderLoss; arrivalData.inFlightFleetLoss = rState.inFlightFleetLoss; arrivalData.inFlightPlanetLoss = rState.inFlightPlanetLoss; arrivalData.accumulatedDefenseAdded = rState.accumulatedDefenseAdded; arrivalData.accumulatedAttackAdded = rState.accumulatedAttackAdded; } function _emitFleetArrived( uint256 fleetId, ResolutionState memory rState, address planetOwner, FleetResolution memory resolution, ArrivalData memory arrivalData ) internal { emit BlockTime(block.number, block.timestamp); emit FleetRevealed( fleetId, resolution.from, resolution.to, resolution.arrivalTimeWanted, resolution.gift, resolution.specific, resolution.secret, resolution.fleetSender, resolution.operator ); emit FleetArrived( fleetId, rState.fleetOwner, planetOwner, resolution.to, rState.gifting, rState.victory, arrivalData ); } function _requireCorrectDistance( uint256 distance, uint256 from, uint256 to, bytes32 fromPlanetData, bytes32 toPlanetData ) internal pure { // check input instead of compute sqrt (int8 fromSubX, int8 fromSubY) = _subLocation(fromPlanetData); (int8 toSubX, int8 toSubY) = _subLocation(toPlanetData); uint256 distanceSquared = uint256( int256( // check input instead of compute sqrt ((int128(int256(to & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) * 4 + toSubX) - (int128(int256(from & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) * 4 + fromSubX)) ** 2 + ((int128(int256(to >> 128)) * 4 + toSubY) - (int128(int256(from >> 128)) * 4 + fromSubY)) ** 2 ) ); require(distance ** 2 <= distanceSquared && distanceSquared < (distance + 1) ** 2, "wrong distance"); } function _requireCorrectTimeAndUpdateArrivalTime( uint256 distance, uint256 arrivalTimeWanted, uint40 launchTime, bytes32 fromPlanetData, ResolutionState memory rState ) internal view { uint256 minReachTime = launchTime + (distance * (_timePerDistance * 10000)) / _speed(fromPlanetData); uint256 reachTime = Math.max(arrivalTimeWanted, minReachTime); if (arrivalTimeWanted > 0) { rState.arrivalTime = uint40(arrivalTimeWanted); } else { rState.arrivalTime = uint40(minReachTime); } require(block.timestamp >= reachTime, "too early"); require(block.timestamp < reachTime + _resolveWindow, "too late, your spaceships are lost in space"); } function _computeInFlightLossForFleet( ResolutionState memory rState, FleetResolution memory resolution ) internal view { // ----------------------------------------------------------------------------------------------------------- // check if fleet was attacked while departing (used to prevent front-running, see fleet sending) // ----------------------------------------------------------------------------------------------------------- uint256 timeSlot = rState.fleetLaunchTime / (_frontrunningDelay / 2); uint32 destroyed = _inFlight[resolution.from][timeSlot].destroyed; uint32 originalQuantity = rState.fleetQuantity; if (destroyed < rState.fleetQuantity) { rState.fleetQuantity -= uint32(destroyed); } else { rState.fleetQuantity = 0; } rState.inFlightFleetLoss = originalQuantity - rState.fleetQuantity; // ----------------------------------------------------------------------------------------------------------- } function _updateFleetForGifting( ResolutionState memory rState, FleetResolution memory resolution, address destinationOwner ) internal view { (bool gifting, bool taxed) = _computeGifting(destinationOwner, resolution, rState); rState.gifting = gifting; rState.taxed = taxed; } // TODO simplify and apply that to attack (when fleetOwner is not fleetSender) // if (resolution.gift) { rState.fleetOwner = destinationOwner } // then compute tax based on fleetOwner != fleetSender, box for attacks and gift // combined attack could even work for non-allies ? // in _computeGift calculate the tax for every branch that result in `gifting` being false // then in attack, add tax to the quantity of fleet + modify event // solhint-disable-next-line code-complexity function _computeGifting( address destinationOwner, FleetResolution memory resolution, ResolutionState memory rState ) internal view returns (bool gifting, bool taxed) { if (destinationOwner == address(0)) { // destination has no owner : this is an attack return (false, _isFleetOwnerTaxed(rState.fleetOwner, resolution.fleetSender, rState.fleetLaunchTime)); } if (destinationOwner == rState.fleetOwner && destinationOwner == resolution.fleetSender) { // destination is sender is fleet owner: this is a non-taxed gift return (true, false); } if (resolution.gift || destinationOwner == rState.fleetOwner) { // intent was gift if ( resolution.specific == address(0) || // anyone resolution.specific == destinationOwner || // only one address and matching owner destinationOwner == rState.fleetOwner // owner is fleet owner => gift ) { // and it was for anyone or specific destination owner that is the same as the current one // or it was simply that fleetOwner = destinationOwner // check tax applies with sender (, uint96 joinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (true, joinTime == 0 || joinTime > rState.fleetLaunchTime); } if (resolution.specific == address(1)) { // or the specific specify any common alliances (1) if (rState.fleetOwner == resolution.fleetSender) { (, uint96 joinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (joinTime > 0, joinTime > rState.fleetLaunchTime); } else { (, uint96 fleetOwnerJoinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( rState.fleetOwner, destinationOwner, rState.fleetLaunchTime ); if (fleetOwnerJoinTime == 0) { // not in an alliance return ( false, _isFleetOwnerTaxed(rState.fleetOwner, resolution.fleetSender, rState.fleetLaunchTime) ); } // alliance => means gift // check if taxed: (, uint96 senderJoinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (true, senderJoinTime == 0 || senderJoinTime > rState.fleetLaunchTime); } } if (uint160(resolution.specific) > 1) { // or a specific alliance that matches (uint96 joinTimeToSpecific, ) = _allianceRegistry.getAllianceData( destinationOwner, IAlliance(resolution.specific) ); if (joinTimeToSpecific > 0) { (, uint96 joinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (true, joinTime == 0 || joinTime > rState.fleetLaunchTime); } } } else { // intent was attack if (resolution.specific == address(1)) { // and the attack was on any non-allies if (rState.fleetOwner == resolution.fleetSender) { // make it a gift if the destination owner is actually an ally (, uint96 joinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (joinTime > 0, joinTime > rState.fleetLaunchTime); } else { (, uint96 fleetOwnerJoinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( rState.fleetOwner, destinationOwner, rState.fleetLaunchTime ); if (fleetOwnerJoinTime == 0) { // not in an alliance return ( false, _isFleetOwnerTaxed(rState.fleetOwner, resolution.fleetSender, rState.fleetLaunchTime) ); } // alliance => means gift // check if taxed: (, uint96 senderJoinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (true, senderJoinTime == 0 || senderJoinTime > rState.fleetLaunchTime); } } if (uint160(resolution.specific) > 1 && resolution.specific != destinationOwner) { // but specific not matching current owner (uint96 joinTimeToSpecific, ) = _allianceRegistry.getAllianceData( destinationOwner, IAlliance(resolution.specific) ); // make it a gift if the destination is not matching the specific alliance // (or owner, in which case since it is not an alliance, it will also not match) if (joinTimeToSpecific == 0) { (, uint96 joinTime) = _allianceRegistry.havePlayersAnAllianceInCommon( resolution.fleetSender, destinationOwner, rState.fleetLaunchTime ); return (true, joinTime == 0 || joinTime > rState.fleetLaunchTime); } } } return (false, _isFleetOwnerTaxed(rState.fleetOwner, resolution.fleetSender, rState.fleetLaunchTime)); } function _isFleetOwnerTaxed( address fleetOwner, address fleetSender, uint40 fleetLaunchTime ) internal view returns (bool) { if (fleetOwner == fleetSender) { return false; } (, uint96 joinTime) = _allianceRegistry.havePlayersAnAllianceInCommon(fleetOwner, fleetSender, fleetLaunchTime); return joinTime == 0 || joinTime > fleetLaunchTime; } function _setTravelingUpkeepFromOrigin(uint256 fleetID, ResolutionState memory rState, uint256 location) internal { // // we have to update the origin Planet storage fromPlanet = _planets[location]; PlanetUpdateState memory fromPlanetUpdate = _createPlanetUpdateState(fromPlanet, location); _computePlanetUpdateForTimeElapsed(fromPlanetUpdate); uint16 production = _production(fromPlanetUpdate.data); uint256 capWhenActive = _capWhenActive(production); uint256 refund = rState.futureExtraProduction; uint256 timePassed = block.timestamp - rState.fleetLaunchTime; uint256 amountProducedTheWholeTime = (timePassed * uint256(_productionSpeedUp) * uint256(production)) / 1 hours; uint256 consumed = amountProducedTheWholeTime + (amountProducedTheWholeTime * _upkeepProductionDecreaseRatePer10000th) / 10000; if (consumed > refund) { refund = 0; } else { refund -= consumed; } int256 newTravelingUpkeep = int256(fromPlanetUpdate.travelingUpkeep) - int256(refund); if (newTravelingUpkeep < -int256(capWhenActive)) { newTravelingUpkeep = -int256(capWhenActive); } fromPlanetUpdate.travelingUpkeep = int40(newTravelingUpkeep); _setPlanet(fromPlanet, fromPlanetUpdate, false); emit BlockTime(block.number, block.timestamp); emit TravelingUpkeepRefund( location, fleetID, fromPlanetUpdate.numSpaceships, fromPlanetUpdate.travelingUpkeep, fromPlanetUpdate.overflow ); } function _setAccumulatedAttack(ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate) internal { if (!rState.taxed) { AccumulatedAttack storage attack = _attacks[toPlanetUpdate.location][rState.fleetOwner][rState.arrivalTime]; // NOTE: target is required for the case where a different player capture the planet in-between // otherwise, that player would be hitted with higher attack than would be fair // hmm would it acutally ? the accumulatedDefenseAdded would still be counted // Indeed, the only real player affected by _attacks[location][fleetOwner][arrivalTime] is the fleetOwner // regardless of who is owner of the planet // attack.target = toPlanetUpdate.owner; // we leave this as is as we do not want to change the struct attack.damageCausedSoFar = rState.defenderLoss + rState.inFlightPlanetLoss + rState.accumulatedDefenseAdded; attack.numAttackSpent = rState.attackerLoss + rState.accumulatedAttackAdded + // when victorius we consider the full number of spaceship as used // this way if a combined attack arrive later, it can still count the whole attack and get a refund (rState.victory ? toPlanetUpdate.numSpaceships : 0); attack.averageAttackPower = rState.attackPower; } } function _combinedRefund( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view returns (uint256 accumulationRefund) { _updateAccumulation(rState, toPlanetUpdate); if (rState.accumulatedAttackAdded > 0) { uint16 attack = rState.attackPower; uint16 defense = _defense(toPlanetUpdate.data); uint256 numAttack = rState.fleetQuantity + rState.accumulatedAttackAdded; (uint32 attackerLoss, ) = _computeFight(numAttack, rState.accumulatedDefenseAdded, attack, defense); if (rState.accumulatedAttackAdded > attackerLoss) { accumulationRefund = rState.accumulatedAttackAdded - attackerLoss; if (accumulationRefund > rState.accumulatedAttackAdded) { rState.accumulatedAttackAdded = 0; } else { rState.accumulatedAttackAdded = uint32(uint256(rState.accumulatedAttackAdded) - accumulationRefund); } } } } function _createResolutionState( Fleet storage fleet, uint256 from ) internal view returns (ResolutionState memory rState) { uint32 q = fleet.quantity >> 31 == 1 ? 0 : fleet.quantity; rState.fleetOwner = fleet.owner; rState.fleetLaunchTime = fleet.launchTime; rState.originalQuantity = q; rState.fleetQuantity = q; rState.futureExtraProduction = fleet.futureExtraProduction; rState.fromData = _planetData(from); rState.attackPower = _attack(rState.fromData); } function _recordOrbitLossAccountingForFleetOrigin( ResolutionState memory rState, FleetResolution memory resolution ) internal { if (rState.inFlightFleetLoss > 0) { uint256 timeSlot = rState.fleetLaunchTime / (_frontrunningDelay / 2); // NOTE we already computed that destroyed cannot be smaller than inFlightFleetLoss // see _computeInFlightLossForFleet _inFlight[resolution.from][timeSlot].destroyed -= rState.inFlightFleetLoss; } } function _computeResolutionResult( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view { if (rState.taxed) { rState.fleetQuantity = uint32( uint256(rState.fleetQuantity) - (uint256(rState.fleetQuantity) * _giftTaxPer10000) / 10000 ); } if (rState.gifting) { _computeGiftingResolutionResult(rState, toPlanetUpdate); } else { _computeAttackResolutionResult(rState, toPlanetUpdate); } } function _computeGiftingResolutionResult( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view { uint256 newNumSpaceships = toPlanetUpdate.numSpaceships + rState.fleetQuantity + _combinedRefund(rState, toPlanetUpdate); if (newNumSpaceships >= ACTIVE_MASK) { newNumSpaceships = ACTIVE_MASK - 1; } toPlanetUpdate.numSpaceships = uint32(newNumSpaceships); if (!toPlanetUpdate.active) { // NOTE: not active, overflow is applied on cap = 0 if (toPlanetUpdate.numSpaceships > toPlanetUpdate.overflow) { toPlanetUpdate.overflow = toPlanetUpdate.numSpaceships; } } else { uint32 cap = uint32(_capWhenActive(_production(toPlanetUpdate.data))); if (_productionCapAsDuration > 0 && newNumSpaceships > cap) { if (toPlanetUpdate.numSpaceships - cap > toPlanetUpdate.overflow) { toPlanetUpdate.overflow = uint32(toPlanetUpdate.numSpaceships - cap); } } else { toPlanetUpdate.overflow = 0; } } } function _updateAccumulation(ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate) internal view { // TODO 45min config ? if (!rState.taxed && block.timestamp < rState.arrivalTime + 45 minutes) { AccumulatedAttack memory acc = _attacks[toPlanetUpdate.location][rState.fleetOwner][rState.arrivalTime]; // TODO acc.target == toPlanetUpdate.owner || toPlanetUpdate.owner == fleetOwner so your combined attack works when you get it // what about your allies ? // taxed work as he accumulated attack is already shared with allies (s) // so we should not need to modify here ? // if (acc.target == toPlanetUpdate.owner && acc.numAttackSpent != 0) { if (acc.numAttackSpent != 0) { rState.attackPower = uint16( (uint256(rState.attackPower) * uint256(rState.fleetQuantity) + uint256(acc.averageAttackPower) * uint256(acc.numAttackSpent)) / (uint256(rState.fleetQuantity) + uint256(acc.numAttackSpent)) ); rState.accumulatedAttackAdded = acc.numAttackSpent; rState.accumulatedDefenseAdded = acc.damageCausedSoFar; } } } function _computeAttackResolutionResult( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view { // NOTE natives come back to power once numSPaceships == 0 and planet not active if (!toPlanetUpdate.active && toPlanetUpdate.numSpaceships < _natives(toPlanetUpdate.data)) { _updatePlanetUpdateStateAndResolutionStateForNativeAttack(rState, toPlanetUpdate); } else { _updateAccumulation(rState, toPlanetUpdate); _updatePlanetUpdateStateAndResolutionStateForPlanetAttack(rState, toPlanetUpdate); } } function _updatePlanetUpdateStateAndResolutionStateForNativeAttack( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view { // NOTE: when we are dealing with native attacks, we do not consider combined attacks // TODO We need to consider that case in the UI uint16 attack = _attack(rState.fromData); uint16 defense = _defense(toPlanetUpdate.data); uint16 natives = _natives(toPlanetUpdate.data); (uint32 attackerLoss, uint32 defenderLoss) = _computeFight(rState.fleetQuantity, natives, attack, defense); rState.attackerLoss = attackerLoss; if (defenderLoss == natives && rState.fleetQuantity > attackerLoss) { // (attackerLoss: 0, defenderLoss: 0) means that numAttack was zero as natives cannot be zero toPlanetUpdate.numSpaceships = rState.fleetQuantity - attackerLoss; rState.defenderLoss = defenderLoss; rState.victory = true; toPlanetUpdate.newOwner = rState.fleetOwner; // solhint-disable-next-line no-empty-blocks } // NOTE else (attacker lost) then nothing happen } function _updatePlanetUpdateStateAndResolutionStateForPlanetAttack( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view { _updateResolutionStateFromOrbitDefense(rState, toPlanetUpdate); uint256 numDefense = toPlanetUpdate.numSpaceships + rState.accumulatedDefenseAdded + rState.orbitDefense1 + rState.orbitDefense2; uint16 production = _production(toPlanetUpdate.data); if (numDefense == 0 && rState.fleetQuantity > 0) { // scenario where there is actually no defense on the place, toPlanetUpdate.newOwner = rState.fleetOwner; toPlanetUpdate.numSpaceships = rState.fleetQuantity; if (!toPlanetUpdate.active) { // numDefense = 0 so numAttack is the overflow, attacker took over toPlanetUpdate.overflow = toPlanetUpdate.numSpaceships; } else { if (_productionCapAsDuration > 0) { uint32 cap = uint32(_capWhenActive(production)); if (toPlanetUpdate.numSpaceships > cap) { // numDefense = 0 so numAttack is the overflow, attacker took over toPlanetUpdate.overflow = uint32(toPlanetUpdate.numSpaceships - cap); } else { toPlanetUpdate.overflow = 0; } } } rState.victory = true; } else { _computeAttack(rState, toPlanetUpdate, numDefense); _computeTravelingUpkeepReductionFromDefenseLoss(rState, toPlanetUpdate, production); } } function _updateResolutionStateFromOrbitDefense( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal view { // ----------------------------------------------------------------------------------------------------------- // consider fleets that just departed from the planet (used to prevent front-running, see fleet sending) // ----------------------------------------------------------------------------------------------------------- uint256 timeSlot = block.timestamp / (_frontrunningDelay / 2); InFlight storage slot1 = _inFlight[toPlanetUpdate.location][timeSlot - 1]; rState.orbitDefense1 = slot1.flying > 2 ** 31 ? 2 ** 31 - 1 : uint32(slot1.flying); rState.orbitDefenseDestroyed1 = slot1.destroyed > 2 ** 31 ? 2 ** 31 - 1 : uint32(slot1.destroyed); InFlight storage slot2 = _inFlight[toPlanetUpdate.location][timeSlot]; rState.orbitDefense2 = slot2.flying > 2 ** 31 ? 2 ** 31 - 1 : uint32(slot2.flying); rState.orbitDefenseDestroyed2 = slot2.destroyed > 2 ** 31 ? 2 ** 31 - 1 : uint32(slot2.destroyed); } // solhint-disable-next-line code-complexity function _computeAttack( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate, uint256 numDefense ) internal view { uint16 attack = rState.attackPower; uint16 defense = _defense(toPlanetUpdate.data); uint256 numAttack = rState.fleetQuantity + rState.accumulatedAttackAdded; (uint32 attackerLoss, uint32 defenderLoss) = _computeFight(numAttack, numDefense, attack, defense); rState.defenderLoss = defenderLoss; rState.attackerLoss = rState.accumulatedAttackAdded > attackerLoss ? 0 : attackerLoss - rState.accumulatedAttackAdded; // (attackerLoss: 0, defenderLoss: 0) could either mean attack was zero or defense was zero : if (rState.fleetQuantity > 0 && rState.defenderLoss == numDefense) { // NOTE Attacker wins // all orbiting fleets are destroyed, inFlightPlanetLoss is all that is left uint256 inFlightPlanetLoss = numDefense - toPlanetUpdate.numSpaceships - rState.accumulatedDefenseAdded; if (inFlightPlanetLoss > ACTIVE_MASK) { // cap it // TODO investigate potential issues inFlightPlanetLoss = ACTIVE_MASK - 1; } rState.inFlightPlanetLoss = uint32(inFlightPlanetLoss); rState.defenderLoss = rState.defenderLoss - rState.inFlightPlanetLoss; toPlanetUpdate.numSpaceships = rState.fleetQuantity - rState.attackerLoss; rState.victory = true; toPlanetUpdate.newOwner = rState.fleetOwner; if (!toPlanetUpdate.active) { // attack took over, overflow is numSpaceships toPlanetUpdate.overflow = toPlanetUpdate.numSpaceships; } else { if (_productionCapAsDuration > 0) { uint16 production = _production(toPlanetUpdate.data); uint32 cap = uint32(_capWhenActive(production)); if (toPlanetUpdate.numSpaceships > cap) { if (toPlanetUpdate.numSpaceships - cap > toPlanetUpdate.overflow) { toPlanetUpdate.overflow = toPlanetUpdate.numSpaceships - cap; } } else { toPlanetUpdate.overflow = 0; } } } } else if (rState.attackerLoss == rState.fleetQuantity) { // NOTE Defender wins if (defenderLoss > toPlanetUpdate.numSpaceships + rState.accumulatedDefenseAdded) { rState.inFlightPlanetLoss = defenderLoss - toPlanetUpdate.numSpaceships - rState.accumulatedDefenseAdded; toPlanetUpdate.numSpaceships = 0; // TODO change owner already if incative ? // not needed though as this is the same has having numSpaceships = 1 and become zero over time if (rState.orbitDefense1 >= rState.inFlightPlanetLoss) { rState.orbitDefense1 -= rState.inFlightPlanetLoss; rState.orbitDefenseDestroyed1 += rState.inFlightPlanetLoss; } else { rState.orbitDefenseDestroyed1 += rState.orbitDefense1; uint32 extra = (rState.inFlightPlanetLoss - rState.orbitDefense1); if (rState.orbitDefense2 >= extra) { rState.orbitDefense2 -= extra; rState.orbitDefenseDestroyed2 += extra; } else { rState.orbitDefenseDestroyed2 += rState.orbitDefense2; rState.orbitDefense2 = 0; // should never reach minus but let simply set it to zero } rState.orbitDefense1 = 0; } } else { toPlanetUpdate.numSpaceships = toPlanetUpdate.numSpaceships + rState.accumulatedDefenseAdded - defenderLoss; // TODO change owner already if incative and numSpaceship == 0 (like above) // not needed though as this is the same has having numSpaceships = 1 and become zero over time } // same as numSpaceshipAtArrival - toPlanetUpdate.numSpaceship; rState.defenderLoss = rState.defenderLoss - rState.inFlightPlanetLoss - rState.accumulatedDefenseAdded; if (!toPlanetUpdate.active) { if (defenderLoss > toPlanetUpdate.overflow) { toPlanetUpdate.overflow = 0; } else { toPlanetUpdate.overflow -= defenderLoss; } } else { if (_productionCapAsDuration > 0) { uint16 production = _production(toPlanetUpdate.data); uint32 cap = uint32(_capWhenActive(production)); if (toPlanetUpdate.numSpaceships > cap) { if (defenderLoss <= toPlanetUpdate.overflow) { toPlanetUpdate.overflow -= defenderLoss; } else { toPlanetUpdate.overflow = 0; } } else { toPlanetUpdate.overflow = 0; } } } } else { // should not happen // because we check for numDefense == 0 before performing the attack, see _updatePlanetUpdateStateAndResolutionStateForPlanetAttack revert("ZERO_ZERO"); } } function _computeFight( uint256 numAttack, uint256 numDefense, uint256 attack, uint256 defense ) internal view returns (uint32 attackerLoss, uint32 defenderLoss) { if (numAttack == 0 || numDefense == 0) { // this edge case need to be considered, // as the result of this function cannot tell from it whos is winning here return (0, 0); } uint256 attackFactor = numAttack * ((1000000 - _fleetSizeFactor6) + ((_fleetSizeFactor6 * numAttack) / numDefense)); uint256 attackDamage = (attackFactor * attack) / defense / 1000000; if (numDefense > attackDamage) { // attack fails attackerLoss = uint32(numAttack); // all attack destroyed defenderLoss = uint32(attackDamage); // 1 spaceship will be left at least as attackDamage < numDefense } else { // attack succeed uint256 defenseFactor = numDefense * ((1000000 - _fleetSizeFactor6) + ((_fleetSizeFactor6 * numDefense) / numAttack)); uint256 defenseDamage = uint32((defenseFactor * defense) / attack / 1000000); if (defenseDamage >= numAttack) { defenseDamage = numAttack - 1; // ensure 1 spaceship left } attackerLoss = uint32(defenseDamage); defenderLoss = uint32(numDefense); // all defense destroyed } } function _computeTravelingUpkeepReductionFromDefenseLoss( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate, uint16 production ) internal view { // allow the attacker to pay for upkeep as part of the attack // only get to keep the upkeep that was there as a result of spaceships sent away uint256 capWhenActive = _capWhenActive(production); int256 totalDefenseLoss = int256(uint256(rState.defenderLoss) + uint256(rState.inFlightPlanetLoss)); int256 newTravelingUpkeep = int256(toPlanetUpdate.travelingUpkeep) - totalDefenseLoss; if (newTravelingUpkeep < -int256(capWhenActive)) { newTravelingUpkeep = -int256(capWhenActive); } toPlanetUpdate.travelingUpkeep = int40(newTravelingUpkeep); } function _recordInOrbitLossAfterAttack( ResolutionState memory rState, PlanetUpdateState memory toPlanetUpdate ) internal { if (rState.inFlightPlanetLoss > 0) { InFlight storage slot1 = _inFlight[toPlanetUpdate.location][block.timestamp / (_frontrunningDelay / 2) - 1]; slot1.flying = rState.orbitDefense1; slot1.destroyed = rState.orbitDefenseDestroyed1; InFlight storage slot2 = _inFlight[toPlanetUpdate.location][block.timestamp / (_frontrunningDelay / 2)]; slot2.flying = rState.orbitDefense2; slot2.destroyed = rState.orbitDefenseDestroyed2; } } function _callWithGas(address to, bytes memory data, uint256 gas) internal { // We want to ensure enough gas were given for the generator, but no more // This way if the generator is broken/compromised (we are planning to update it) // then this will always continue to work // Reversely, a player have to provide enough gas // and we want to ensure the player can't force a revert on the hook // In particular. to prevent players to make a call to `remove` fails if (to != address(0)) { // we could do the check prior: // uint256 gasAvailable = gasleft() - 2000; // require(gasAvailable - gasAvailable / 64 >= gas, "NOT_ENOUGH_GAS_FOR_INNER_CALL"); // to.call{gas: gas}(data); // but we instead chose to do the check after. // for more info see: https://ronan.eth.limo/blog/ethereum-gas-dangers/ to.call{gas: gas}(data); // we use after the gas check as this allow us to not require heavy gas use if not needed // instead of + 100,000 for 96,000 gas we can just add 1,524 gas (+ a bit more) require(gasleft() > gas / 63, "NOT_ENOUGH_GAS_FOR_INNER_CALL"); } } function _generator() internal view returns (address generator) { assembly { // keccak256("generator") - 1 generator := sload(0x27ec6af4a6510eb9b7e0cc7f39415b7f15e430e53eb0cd3997e7c7e0cf680f6e) } } function _notifyGeneratorAdd(address player, uint256 amount) internal { _callWithGas(_generator(), abi.encodeWithSelector(IOnStakeChange.add.selector, player, amount), 96000); } function _notifyGeneratorRemove(address player, uint256 amount) internal { _callWithGas(_generator(), abi.encodeWithSelector(IOnStakeChange.remove.selector, player, amount), 96000); } function _notifyGeneratorMove(address from, address to, uint256 amount) internal { _callWithGas(_generator(), abi.encodeWithSelector(IOnStakeChange.move.selector, from, to, amount), 192000); } // --------------------------------------------------------------------------------------------------------------- // PLANET STATS // --------------------------------------------------------------------------------------------------------------- function _planetData(uint256 location) internal view returns (bytes32) { return keccak256(abi.encodePacked(_genesis, location)); } function _subLocation(bytes32 data) internal pure returns (int8 subX, int8 subY) { subX = 1 - int8(data.value8Mod(0, 3)); subY = 1 - int8(data.value8Mod(2, 3)); } function _stake(bytes32 data) internal view returns (uint32) { require(_exists(data), "PLANET_NOT_EXISTS"); // return data.normal16(4, 0x000400050005000A000A000F000F00140014001E001E00280028005000500064); uint8 productionIndex = data.normal8(12); // production affect the stake value // TODO remove or decide otherwise: // uint16 offset = data.normal16(4, 0x0000000100010002000200030003000400040005000500060006000700070008); // uint16 stakeIndex = productionIndex + offset; // if (stakeIndex < 4) { // stakeIndex = 0; // } else if (stakeIndex > 19) { // stakeIndex = 15; // } else { // stakeIndex -= 4; // } uint16 stakeIndex = productionIndex; return uint32( uint256( uint16(uint8(_stakeRange[stakeIndex * 2])) * 0x100 + uint16(uint8(_stakeRange[stakeIndex * 2 + 1])) ) * _stakeMultiplier10000th ); } function _production(bytes32 data) internal pure returns (uint16) { require(_exists(data), "PLANET_NOT_EXISTS"); // TODO TRY : 1800,2100,2400,2700,3000,3300,3600, 3600, 3600, 3600,4000,4400,4800,5400,6200,7200 ? // 1800,2100,2400,2700,3000,3300,3600, 3600, 3600, 3600,4200,5400,6600,7800,9000,12000 // 0x0708083409600a8c0bb80ce40e100e100e100e101068151819c81e7823282ee0 return data.normal16(12, 0x0708083409600a8c0bb80ce40e100e100e100e101068151819c81e7823282ee0); // per hour } function _capWhenActive(uint16 production) internal view returns (uint256) { return _acquireNumSpaceships + (uint256(production) * _productionCapAsDuration) / 1 hours; } function _attack(bytes32 data) internal pure returns (uint16) { require(_exists(data), "PLANET_NOT_EXISTS"); return 4000 + data.normal8(20) * 400; // 4,000 - 7,000 - 10,000 } function _defense(bytes32 data) internal pure returns (uint16) { require(_exists(data), "PLANET_NOT_EXISTS"); return 4000 + data.normal8(28) * 400; // 4,000 - 7,000 - 10,000 } function _speed(bytes32 data) internal pure returns (uint16) { require(_exists(data), "PLANET_NOT_EXISTS"); return 5005 + data.normal8(36) * 333; // 5,005 - 7,502.5 - 10,000 } function _natives(bytes32 data) internal pure returns (uint16) { require(_exists(data), "PLANET_NOT_EXISTS"); return 15000 + data.normal8(44) * 3000; // 15,000 - 37,500 - 60,000 } function _exists(bytes32 data) internal pure returns (bool) { return data.value8Mod(52, 16) == 1; // 16 => 36 so : 1 planet per 6 (=24 min unit) square // also: // 20000 average starting numSpaceships (or max?) // speed of min unit = 30 min ( 1 hour per square) // production : 20000 per 6 hours // exit : 3 days ? => 72 distance } // --------------------------------------------------------------------------------------------------------------- // GETTERS // --------------------------------------------------------------------------------------------------------------- function _getPlanet(uint256 location) internal view returns (Planet storage) { return _planets[location]; } function _getPlanetStats(uint256 location) internal view returns (PlanetStats memory) { bytes32 data = _planetData(location); require(_exists(data), "no planet in this location"); (int8 subX, int8 subY) = _subLocation(data); return PlanetStats({ subX: subX, subY: subY, stake: _stake(data), production: _production(data), attack: _attack(data), defense: _defense(data), speed: _speed(data), natives: _natives(data) }); } // --------------------------------------------------------------------------------------------------------------- // UTILS // --------------------------------------------------------------------------------------------------------------- function _activeNumSpaceships(uint32 numSpaceshipsData) internal pure returns (bool active, uint32 numSpaceships) { active = (numSpaceshipsData & ACTIVE_MASK) == ACTIVE_MASK; numSpaceships = numSpaceshipsData % (ACTIVE_MASK); } function _setActiveNumSpaceships(bool active, uint32 numSpaceships) internal pure returns (uint32) { return uint32((active ? ACTIVE_MASK : 0) + numSpaceships); } function _msgSender() internal view returns (address) { return msg.sender; // TODO metatx } modifier whenNotPaused() { if (_bootstrapSessionEndTime > 0) { uint256 timestamp = block.timestamp; uint256 pauseStart = _bootstrapSessionEndTime; uint256 pauseEnd = _infinityStartTime; require(timestamp < pauseStart || timestamp >= pauseEnd, "PAUSED"); } _; } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; interface IOnStakeChange { function add(address account, uint256 amount) external; function remove(address account, uint256 amount) external; function move( address from, address to, uint256 amount ) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.9; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../interfaces/IOnStakeChange.sol"; interface ImportingOuterSpaceTypes { // front running protection : _frontruunningDelay / 2 slots struct InFlight { uint32 flying; uint32 destroyed; // STORE last attack too, to compute combined attack on it ? uint128 is plainty enough } // TODO remove // struct Account { // // TODO add more info // // stake for example ? => coild it be used by staking ? // // numPlanets ? // // numSpaceships ? => probably too much ? // uint64 totalProduction; // uint64 productionDebt; // } struct Discovered { uint32 minX; uint32 maxX; uint32 minY; uint32 maxY; } // TODO split in 2 structs ? PlanetOwnership and PlanetState ? struct Planet { address owner; uint40 ownershipStartTime; // ~ 34865 years, should be enough :) uint40 exitStartTime; // ~ 34865 years, should be enough :) // TODO uint16 ? /// uint32 numSpaceships; // uint31 + first bit => active // TODO use bool active ? uint40 lastUpdated; // ~ 34865 years, should be enough :) int40 travelingUpkeep; // decrease per _upkeepProductionDecreaseRatePer10000th * production uint32 overflow; // bool active; // TODO ? // bool exiting; // TODO ? } struct Fleet { address owner; uint40 launchTime; // ~ 34865 years, should be enough :) uint32 quantity; // TODO? first bit = done? to keep quantity value on-chain post resolution, actually not needed, can be given in the hash uint24 futureExtraProduction; address defender; uint40 arrivalTime; uint32 defenderLoss; bool planetActive; bool victory; // we got 24bit more to store if needed // operator ? // signer ? } struct FleetData { bool arrived; address owner; uint40 launchTime; uint32 quantity; uint64 flyingAtLaunch; // can be more than quantity if multiple fleet were launched around the same time from the same planet uint64 destroyedAtLaunch; address defender; uint40 arrivalTime; uint32 defenderLoss; bool planetActive; bool victory; } struct PlanetStats { int8 subX; int8 subY; uint32 stake; uint16 production; uint16 attack; uint16 defense; uint16 speed; uint16 natives; } struct ExternalPlanet { address owner; uint40 ownershipStartTime; // ~ 34865 years, should be enough :) uint40 exitStartTime; // ~ 34865 years, should be enough :) uint32 numSpaceships; uint32 overflow; uint40 lastUpdated; // ~ 34865 years, should be enough :) bool active; // bool exiting; uint256 reward; } struct FleetLaunch { address fleetSender; address fleetOwner; uint256 from; uint32 quantity; bytes32 toHash; } struct FleetResolution { uint256 from; uint256 to; uint256 distance; uint256 arrivalTimeWanted; bool gift; address specific; bytes32 secret; address fleetSender; // does not work ? address operator; // should be saved ? } struct AccumulatedAttack { address target; uint32 numAttackSpent; uint32 damageCausedSoFar; uint16 averageAttackPower; } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 999999 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"contract StakingToken","name":"stakingToken","type":"address"},{"internalType":"contract IFreePlayToken","name":"freeStakingToken","type":"address"},{"internalType":"contract AllianceRegistry","name":"allianceRegistry","type":"address"},{"internalType":"bytes32","name":"genesis","type":"bytes32"},{"internalType":"uint256","name":"resolveWindow","type":"uint256"},{"internalType":"uint256","name":"timePerDistance","type":"uint256"},{"internalType":"uint256","name":"exitDuration","type":"uint256"},{"internalType":"uint32","name":"acquireNumSpaceships","type":"uint32"},{"internalType":"uint32","name":"productionSpeedUp","type":"uint32"},{"internalType":"uint256","name":"frontrunningDelay","type":"uint256"},{"internalType":"uint256","name":"productionCapAsDuration","type":"uint256"},{"internalType":"uint256","name":"upkeepProductionDecreaseRatePer10000th","type":"uint256"},{"internalType":"uint256","name":"fleetSizeFactor6","type":"uint256"},{"internalType":"uint32","name":"initialSpaceExpansion","type":"uint32"},{"internalType":"uint32","name":"expansionDelta","type":"uint32"},{"internalType":"uint256","name":"giftTaxPer10000","type":"uint256"},{"internalType":"bytes32","name":"stakeRange","type":"bytes32"},{"internalType":"uint256","name":"stakeMultiplier10000th","type":"uint256"},{"internalType":"uint256","name":"bootstrapSessionEndTime","type":"uint256"},{"internalType":"uint256","name":"infinityStartTime","type":"uint256"}],"internalType":"struct OuterSpaceFacetBase.Config","name":"config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"block","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"BlockTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"}],"name":"ExitComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fleet","type":"uint256"},{"indexed":true,"internalType":"address","name":"fleetOwner","type":"address"},{"indexed":true,"internalType":"address","name":"destinationOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"destination","type":"uint256"},{"indexed":false,"internalType":"bool","name":"gift","type":"bool"},{"indexed":false,"internalType":"bool","name":"won","type":"bool"},{"components":[{"internalType":"uint32","name":"newNumspaceships","type":"uint32"},{"internalType":"int40","name":"newTravelingUpkeep","type":"int40"},{"internalType":"uint32","name":"newOverflow","type":"uint32"},{"internalType":"uint32","name":"numSpaceshipsAtArrival","type":"uint32"},{"internalType":"uint32","name":"taxLoss","type":"uint32"},{"internalType":"uint32","name":"fleetLoss","type":"uint32"},{"internalType":"uint32","name":"planetLoss","type":"uint32"},{"internalType":"uint32","name":"inFlightFleetLoss","type":"uint32"},{"internalType":"uint32","name":"inFlightPlanetLoss","type":"uint32"},{"internalType":"uint32","name":"accumulatedDefenseAdded","type":"uint32"},{"internalType":"uint32","name":"accumulatedAttackAdded","type":"uint32"}],"indexed":false,"internalType":"struct ImportingOuterSpaceEvents.ArrivalData","name":"data","type":"tuple"}],"name":"FleetArrived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fleetId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"to","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"arrivalTimeWanted","type":"uint256"},{"indexed":false,"internalType":"bool","name":"gift","type":"bool"},{"indexed":false,"internalType":"address","name":"specific","type":"address"},{"indexed":false,"internalType":"bytes32","name":"secret","type":"bytes32"},{"indexed":false,"internalType":"address","name":"fleetSender","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"FleetRevealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fleetSender","type":"address"},{"indexed":true,"internalType":"address","name":"fleetOwner","type":"address"},{"indexed":true,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"fleet","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"quantity","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"newNumSpaceships","type":"uint32"},{"indexed":false,"internalType":"int40","name":"newTravelingUpkeep","type":"int40"},{"indexed":false,"internalType":"uint32","name":"newOverflow","type":"uint32"}],"name":"FleetSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newGeneratorAdmin","type":"address"}],"name":"GeneratorAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newGenerator","type":"address"}],"name":"GeneratorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"genesis","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"resolveWindow","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timePerDistance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exitDuration","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"acquireNumSpaceships","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"productionSpeedUp","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"frontrunningDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"productionCapAsDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"upkeepProductionDecreaseRatePer10000th","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fleetSizeFactor6","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"initialSpaceExpansion","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"expansionDelta","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"giftTaxPer10000","type":"uint256"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"}],"name":"PlanetExit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"}],"name":"PlanetReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"acquirer","type":"address"},{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"numSpaceships","type":"uint32"},{"indexed":false,"internalType":"int40","name":"travelingUpkeep","type":"int40"},{"indexed":false,"internalType":"uint32","name":"overflow","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"},{"indexed":false,"internalType":"bool","name":"freegift","type":"bool"}],"name":"PlanetStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"},{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"newNumspaceships","type":"uint32"},{"indexed":false,"internalType":"int40","name":"newTravelingUpkeep","type":"int40"},{"indexed":false,"internalType":"uint32","name":"newOverflow","type":"uint32"}],"name":"PlanetTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"},{"indexed":true,"internalType":"address","name":"giver","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardId","type":"uint256"}],"name":"RewardSetup","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"rewardId","type":"uint256"}],"name":"RewardToWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"newStake","type":"uint256"},{"indexed":false,"internalType":"bool","name":"freegift","type":"bool"}],"name":"StakeToWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"location","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"origin","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"fleet","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"newNumspaceships","type":"uint32"},{"indexed":false,"internalType":"int40","name":"newTravelingUpkeep","type":"int40"},{"indexed":false,"internalType":"uint32","name":"newOverflow","type":"uint32"}],"name":"TravelingUpkeepRefund","type":"event"},{"inputs":[{"internalType":"uint256","name":"location","type":"uint256"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sponsor","type":"address"}],"name":"getPrevRewardIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"location","type":"uint256"}],"name":"getRewardId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"fullRewardId","type":"uint256"}],"name":"hasRewardGoalBeenAchieved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61030060405234801561001157600080fd5b506040516107eb3803806107eb833981016040819052610030916101f1565b80600060048260a001516100449190610314565b60a0830151909150610057826004610345565b63ffffffff16146100ae5760405162461bcd60e51b815260206004820152601d60248201527f54494d455f5045525f444953545f4e4f545f444956495349424c455f34000000604482015260640160405180910390fd5b81516001600160a01b0390811660809081526020840151821660a052604084015190911660c0908152606084015160e09081529184015161010090815263ffffffff93841661012090815291850151610140908152928501518416610160908152908501518416610180908152918501516101a0908152928501516101c0908152908501516101e09081529185015161020090815292850151841661022090815290850151909316610240908152908401516102609081529184015161028052918301516102a052908201516102c05201516102e0525061037f565b60405161028081016001600160401b03811182821017156101bb57634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b03811681146101d857600080fd5b919050565b805163ffffffff811681146101d857600080fd5b6000610280828403121561020457600080fd5b61020c61018a565b610215836101c1565b8152610223602084016101c1565b6020820152610234604084016101c1565b6040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015261026d60e084016101dd565b60e08201526101006102808185016101dd565b9082015261012083810151908201526101408084015190820152610160808401519082015261018080840151908201526101a06102be8185016101dd565b908201526101c06102d08482016101dd565b908201526101e08381015190820152610200808401519082015261022080840151908201526102408084015190820152610260928301519281019290925250919050565b600063ffffffff8084168061033957634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600063ffffffff8083168185168183048111821515161561037657634e487b7160e01b600052601160045260246000fd5b02949350505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e0516103bf61042c60003960005050600050506000505060005050600050506000505060005050600050506000505060005050600050506000505060005050600050506000505060005050600050506000505060005050600050506103bf6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063089435031461005157806340781c321461009a5780636131cc25146100f057806374de4ec414610110575b600080fd5b61008761005f3660046102a4565b73ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205490565b6040519081526020015b60405180910390f35b6100e06100a83660046102c6565b73ffffffffffffffffffffffffffffffffffffffff919091166000908152600860209081526040808320938352929052205460ff1690565b6040519015158152602001610091565b6100876100fe3660046102f0565b60009081526007602052604090205490565b61012361011e3660046102f0565b610125565b005b61012f8133610132565b50565b60008281526007602052604090205480156101ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5245574152445f414c52454144595f41545f544849535f4c4f434154494f4e00604482015260640160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040812080549091906101e090610338565b91829055509050610217817fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b16610371565b600084815260076020908152604091829020929092555182815273ffffffffffffffffffffffffffffffffffffffff84169185917fec3a2d89aa52417930dcfd96d54282db3cdc02a9c65e1d9def8f7407c60fc027910160405180910390a3505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461029f57600080fd5b919050565b6000602082840312156102b657600080fd5b6102bf8261027b565b9392505050565b600080604083850312156102d957600080fd5b6102e28361027b565b946020939093013593505050565b60006020828403121561030257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561036a5761036a610309565b5060010190565b6000821982111561038457610384610309565b50019056fea26469706673582212204c30608c3faf59ea97a1a54b430717a6f44d9a26c8820794b195475f1ae664b464736f6c634300080900330000000000000000000000001874f6326eebcce664410a93a5217741a977d14a0000000000000000000000008d82b1900bc77facdf6f2209869e4f816e4fbcb20000000000000000000000006bcac36717257096426e7b7a185d1250d1c83cd369ab0921cc2bcc5c203b2bccc4b5ce33acb9520a4776421236c81ad3da565991000000000000000000000000000000000000000000000000000000000000a8c00000000000000000000000000000000000000000000000000000000000001c20000000000000000000000000000000000000000000000000000000000003f48000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000003f4800000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000007d00064008200aa00c800f0010e012c014a014a017201900212029e032003a204b000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000067c820a00000000000000000000000000000000000000000000000000000000067c97220
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063089435031461005157806340781c321461009a5780636131cc25146100f057806374de4ec414610110575b600080fd5b61008761005f3660046102a4565b73ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205490565b6040519081526020015b60405180910390f35b6100e06100a83660046102c6565b73ffffffffffffffffffffffffffffffffffffffff919091166000908152600860209081526040808320938352929052205460ff1690565b6040519015158152602001610091565b6100876100fe3660046102f0565b60009081526007602052604090205490565b61012361011e3660046102f0565b610125565b005b61012f8133610132565b50565b60008281526007602052604090205480156101ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5245574152445f414c52454144595f41545f544849535f4c4f434154494f4e00604482015260640160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040812080549091906101e090610338565b91829055509050610217817fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b16610371565b600084815260076020908152604091829020929092555182815273ffffffffffffffffffffffffffffffffffffffff84169185917fec3a2d89aa52417930dcfd96d54282db3cdc02a9c65e1d9def8f7407c60fc027910160405180910390a3505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461029f57600080fd5b919050565b6000602082840312156102b657600080fd5b6102bf8261027b565b9392505050565b600080604083850312156102d957600080fd5b6102e28361027b565b946020939093013593505050565b60006020828403121561030257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561036a5761036a610309565b5060010190565b6000821982111561038457610384610309565b50019056fea26469706673582212204c30608c3faf59ea97a1a54b430717a6f44d9a26c8820794b195475f1ae664b464736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001874f6326eebcce664410a93a5217741a977d14a0000000000000000000000008d82b1900bc77facdf6f2209869e4f816e4fbcb20000000000000000000000006bcac36717257096426e7b7a185d1250d1c83cd369ab0921cc2bcc5c203b2bccc4b5ce33acb9520a4776421236c81ad3da565991000000000000000000000000000000000000000000000000000000000000a8c00000000000000000000000000000000000000000000000000000000000001c20000000000000000000000000000000000000000000000000000000000003f48000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000003f4800000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000007d00064008200aa00c800f0010e012c014a014a017201900212029e032003a204b000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000067c820a00000000000000000000000000000000000000000000000000000000067c97220
-----Decoded View---------------
Arg [0] : config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
20 Constructor Arguments found :
Arg [0] : 0000000000000000000000001874f6326eebcce664410a93a5217741a977d14a
Arg [1] : 0000000000000000000000008d82b1900bc77facdf6f2209869e4f816e4fbcb2
Arg [2] : 0000000000000000000000006bcac36717257096426e7b7a185d1250d1c83cd3
Arg [3] : 69ab0921cc2bcc5c203b2bccc4b5ce33acb9520a4776421236c81ad3da565991
Arg [4] : 000000000000000000000000000000000000000000000000000000000000a8c0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000001c20
Arg [6] : 000000000000000000000000000000000000000000000000000000000003f480
Arg [7] : 00000000000000000000000000000000000000000000000000000000000186a0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000708
Arg [10] : 000000000000000000000000000000000000000000000000000000000003f480
Arg [11] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [12] : 000000000000000000000000000000000000000000000000000000000007a120
Arg [13] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [15] : 00000000000000000000000000000000000000000000000000000000000007d0
Arg [16] : 0064008200aa00c800f0010e012c014a014a017201900212029e032003a204b0
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [18] : 0000000000000000000000000000000000000000000000000000000067c820a0
Arg [19] : 0000000000000000000000000000000000000000000000000000000067c97220
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.