编译器
0.8.17+commit.8df45f5f
文件 1 的 24:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
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");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 24:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 24:EntityUtils.sol
pragma solidity ^0.8.17;
function tokenToEntity(address token, uint256 id) pure returns (uint256) {
return (uint256(uint160(token)) << 96) | id;
}
function entityToToken(uint256 entity)
pure
returns (address token, uint256 id)
{
token = address(uint160(entity >> 96));
id = entity & 0xffffffffffffffffffffffff;
}
function accountToEntity(address account) pure returns (uint256) {
return (uint256(uint160(account)));
}
function entityToAccount(uint256 entity) pure returns (address account) {
account = address(uint160(entity));
}
function entityIsAccount(uint256 entity) pure returns (bool) {
return entity >> 160 == 0;
}
文件 4 的 24:GenesisGalaxy.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/Multicall.sol";
import "./utils/EntityUtils.sol";
import "./utils/Sample.sol";
import "./systems/SpatialSystem.sol";
import "./systems/MiningSystem.sol";
import "./IERC20Resource.sol";
import "./IMiaocraft.sol";
import "./constants.sol";
struct EmissionInfo {
uint128 seed;
uint128 amount;
}
struct AsteroidInfo {
address resource;
uint256 initialSupply;
uint256 rewardPerSecond;
int256 x;
int256 y;
}
struct AsteroidInfoExtended {
uint256 id;
uint128 emissionId;
uint32 index;
bool identified;
AsteroidInfo asteroidInfo;
MineInfo mineInfo;
}
contract GenesisGalaxy is
SpatialSystem,
MiningSystem,
Initializable,
Ownable,
Multicall
{
uint256 public immutable ASTEROIDS_PER_EMISSION;
uint256 public immutable MAX_DEPLETION_INTERVAL;
uint256 public immutable MAX_RADIUS;
uint256 public immutable SPEED;
IERC20Resource public butter;
IMiaocraft public miaocraft;
address public sbh;
EmissionInfo[] public _emissionInfos;
mapping(uint256 => uint256) public identifiedBitmaps;
constructor(
uint256 asteroidsPerEmission,
uint256 maxDepletionInterval,
uint256 maxRadius,
uint256 speed
) {
ASTEROIDS_PER_EMISSION = asteroidsPerEmission;
MAX_DEPLETION_INTERVAL = maxDepletionInterval;
MAX_RADIUS = maxRadius;
SPEED = speed;
}
function initialize(
address butter_,
address miaocraft_,
address sbh_
) public initializer {
butter = IERC20Resource(butter_);
miaocraft = IMiaocraft(miaocraft_);
sbh = sbh_;
_add(getOrigin());
_transferOwnership(msg.sender);
}
function getEmission(uint256 emissionId)
public
view
returns (EmissionInfo memory emissionInfo)
{
emissionInfo = _emissionInfos[emissionId];
}
function getEmissionCount() public view returns (uint256) {
return _emissionInfos.length;
}
function getAsteroids(uint256 emissionId)
public
view
returns (AsteroidInfo[] memory asteroidInfos)
{
asteroidInfos = new AsteroidInfo[](ASTEROIDS_PER_EMISSION);
for (uint256 i = 0; i < ASTEROIDS_PER_EMISSION; i++) {
asteroidInfos[i] = getAsteroid(emissionId, i);
}
}
function getAsteroid(uint256 emissionId, uint256 index)
public
view
returns (AsteroidInfo memory asteroidInfo)
{
uint256 seed = uint256(
keccak256(abi.encodePacked(_emissionInfos[emissionId].seed, index))
);
uint256 initialSupply = (sampleInvSqrt(seed++, 1e15) *
_emissionInfos[emissionId].amount) /
1e18 /
ASTEROIDS_PER_EMISSION;
uint256 rewardPerSecond = (2 *
(sampleInvSqrt(seed++, 1e15) * initialSupply)) /
1e18 /
MAX_DEPLETION_INTERVAL;
(int256 x, int256 y) = sampleCircle(
seed,
MAX_RADIUS / ASTEROID_COORD_PRECISION
);
asteroidInfo = AsteroidInfo({
resource: address(butter),
initialSupply: initialSupply,
rewardPerSecond: rewardPerSecond,
x: x * int256(ASTEROID_COORD_PRECISION),
y: y * int256(ASTEROID_COORD_PRECISION)
});
}
function getAsteroidExtended(uint256 emissionId, uint256 index)
public
view
returns (AsteroidInfoExtended memory)
{
return
_getAsteroidExtended(
emissionId,
index,
identifiedBitmaps[emissionId]
);
}
function getOrigin() public view returns (AsteroidInfo memory) {
uint256 genesisCost = GENESIS_SUPPLY *
miaocraft.buildCost(SPINS_PRECISION);
return
AsteroidInfo({
resource: address(butter),
initialSupply: 100 * genesisCost,
rewardPerSecond: genesisCost / MAX_DEPLETION_INTERVAL,
x: 0,
y: 0
});
}
function getOriginExtended()
public
view
returns (AsteroidInfoExtended memory)
{
return
AsteroidInfoExtended({
id: 0,
emissionId: 0,
index: uint32(ASTEROIDS_PER_EMISSION),
identified: true,
asteroidInfo: getOrigin(),
mineInfo: getMineInfo(tokenToEntity(address(this), 0))
});
}
function coordinateToAsteroidId(int256 x, int256 y)
public
pure
returns (uint256)
{
x /= int256(ASTEROID_COORD_PRECISION);
y /= int256(ASTEROID_COORD_PRECISION);
return
(uint256(x < 0 ? -x + ASTEROID_COORD_NEG_FLAG : x) *
uint256(ASTEROID_COORD_NEG_FLAG * 10)) +
(uint256(y < 0 ? -y + ASTEROID_COORD_NEG_FLAG : y));
}
function asteroidIdToCoordinate(uint256 asteroidId)
public
pure
returns (int256 x, int256 y)
{
x = int256(asteroidId) / ASTEROID_COORD_NEG_FLAG / 10;
y = int256(asteroidId) - x * ASTEROID_COORD_NEG_FLAG * 10;
x =
(
x / ASTEROID_COORD_NEG_FLAG == 0
? x
: -(x - ASTEROID_COORD_NEG_FLAG)
) *
int256(ASTEROID_COORD_PRECISION);
y =
(
y / ASTEROID_COORD_NEG_FLAG == 0
? y
: -(y - ASTEROID_COORD_NEG_FLAG)
) *
int256(ASTEROID_COORD_PRECISION);
}
function identified(uint256 emissionId, uint256 index)
public
view
returns (bool)
{
return _mapped(identifiedBitmaps[emissionId], index);
}
function _getAsteroidExtended(
uint256 emissionId,
uint256 index,
uint256 identifiedBitmap
) internal view returns (AsteroidInfoExtended memory info) {
AsteroidInfo memory asteroidInfo = getAsteroid(emissionId, index);
uint256 asteroidId = coordinateToAsteroidId(
asteroidInfo.x,
asteroidInfo.y
);
return
AsteroidInfoExtended({
id: asteroidId,
emissionId: uint128(emissionId),
index: uint32(index),
identified: _mapped(identifiedBitmap, index),
asteroidInfo: asteroidInfo,
mineInfo: getMineInfo(tokenToEntity(address(this), asteroidId))
});
}
function _getAsteroidId(uint256 emissionId, uint256 index)
internal
view
returns (uint256)
{
AsteroidInfo memory info = getAsteroid(emissionId, index);
return coordinateToAsteroidId(info.x, info.y);
}
function _mapped(uint256 bitmap, uint256 index)
private
pure
returns (bool)
{
return bitmap & (1 << index) != 0;
}
function _requireDocked(uint256 shipEntityId, uint256 asteroidEntityId)
internal
view
{
require(locked(shipEntityId), "Not docked");
require(collocated(asteroidEntityId, shipEntityId), "Not docked here");
}
function addEmission(uint256 seed, uint256 amount) public {
require(msg.sender == sbh, "Only sbh");
_emissionInfos.push(
EmissionInfo({seed: uint128(seed), amount: uint128(amount)})
);
}
function identifyMultiple(uint256 emissionId, uint256[] memory indices)
public
{
for (uint256 i = 0; i < indices.length; i++) {
identify(emissionId, indices[i]);
}
}
function identifyAll(uint256 emissionId) public {
uint256 bitmap = identifiedBitmaps[emissionId];
for (uint256 i = 0; i < ASTEROIDS_PER_EMISSION; i++) {
if (!_mapped(bitmap, i)) identify(emissionId, i);
}
}
function identify(uint256 emissionId, uint256 index)
public
returns (uint256 asteroidId)
{
require(emissionId < _emissionInfos.length, "Invalid emissionId");
require(index < ASTEROIDS_PER_EMISSION, "Invalid index");
require(!identified(emissionId, index), "Already identified");
identifiedBitmaps[emissionId] |= 1 << index;
asteroidId = _add(getAsteroid(emissionId, index));
}
function dock(uint256 shipId, uint256 asteroidId)
public
onlyApprovedOrShipOwner(shipId)
{
uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId);
uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId);
require(!locked(shipEntityId), "Already docked");
_updateLocation(shipEntityId);
require(collocated(asteroidEntityId, shipEntityId), "Out of orbit");
_lock(shipEntityId);
_dock(shipEntityId, asteroidEntityId, miaocraft.spinsOf(shipId));
}
function redock(uint256 shipId, uint256 asteroidId) public {
uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId);
uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId);
_requireDocked(shipEntityId, asteroidEntityId);
uint256 sharesBefore = getExtractorInfo(asteroidEntityId, shipEntityId)
.shares;
uint256 sharesAfter = miaocraft.spinsOf(shipId);
if (sharesBefore > sharesAfter) {
_undock(shipEntityId, asteroidEntityId, sharesBefore - sharesAfter);
} else {
_dock(shipEntityId, asteroidEntityId, sharesAfter - sharesBefore);
}
}
function extract(uint256 shipId, uint256 asteroidId) public {
_extract(
tokenToEntity(address(miaocraft), shipId),
tokenToEntity(address(this), asteroidId)
);
}
function identifyAndDock(
uint256 emissionId,
uint256 index,
uint256 shipId
) public {
uint256 asteroidId;
if (!identified(emissionId, index)) {
asteroidId = identify(emissionId, index);
} else {
asteroidId = _getAsteroidId(emissionId, index);
}
dock(shipId, asteroidId);
}
function undockAndExtract(uint256 shipId, uint256 asteroidId)
public
onlyApprovedOrShipOwner(shipId)
{
uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId);
uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId);
_requireDocked(shipEntityId, asteroidEntityId);
_undockAndExtract(
shipEntityId,
asteroidEntityId,
getExtractorInfo(asteroidEntityId, shipEntityId).shares
);
_unlock(shipEntityId);
}
function emergencyUndock(uint256 shipId, uint256 asteroidId)
public
onlyApprovedOrShipOwner(shipId)
{
uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId);
_emergencyUndock(
shipEntityId,
tokenToEntity(address(this), asteroidId)
);
_unlock(shipEntityId);
}
function undockExtractAndMove(
uint256 shipId,
uint256 fromAsteroidId,
uint256 toAsteroidId
) public {
(int256 x, int256 y) = coordinate(
tokenToEntity(address(this), toAsteroidId)
);
undockExtractAndMove(shipId, fromAsteroidId, x, y);
}
function undockExtractAndMove(
uint256 shipId,
uint256 asteroidId,
int256 xDest,
int256 yDest
) public onlyApprovedOrShipOwner(shipId) {
uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId);
uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId);
_requireDocked(shipEntityId, asteroidEntityId);
_undockAndExtract(
shipEntityId,
asteroidEntityId,
getExtractorInfo(asteroidEntityId, shipEntityId).shares
);
_unlock(shipEntityId);
_move(shipEntityId, xDest, yDest, SPEED);
}
function move(uint256 shipId, uint256 asteroidId) public {
(int256 x, int256 y) = coordinate(
tokenToEntity(address(this), asteroidId)
);
move(shipId, x, y);
}
function move(
uint256 shipId,
int256 xDest,
int256 yDest
) public onlyApprovedOrShipOwner(shipId) {
_move(tokenToEntity(address(miaocraft), shipId), xDest, yDest, SPEED);
}
function remove(uint256 shipId, uint256 asteroidId) public {
try miaocraft.ownerOf(shipId) {
revert("Ship exists");
} catch Error(string memory reason) {
require(
keccak256(abi.encodePacked(reason)) ==
keccak256("ERC721: invalid token ID"),
"Invalid reason"
);
_destroyExtractor(
tokenToEntity(address(this), asteroidId),
tokenToEntity(address(miaocraft), shipId)
);
}
}
function _add(AsteroidInfo memory asteroidInfo)
internal
returns (uint256 asteroidId)
{
asteroidId = coordinateToAsteroidId(asteroidInfo.x, asteroidInfo.y);
uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId);
IERC20Resource(asteroidInfo.resource).mint(
asteroidEntityId,
asteroidInfo.initialSupply
);
_setCoordinate(asteroidEntityId, asteroidInfo.x, asteroidInfo.y);
_add(
asteroidEntityId,
asteroidInfo.resource,
asteroidInfo.rewardPerSecond
);
}
modifier onlyApprovedOrShipOwner(uint256 shipId) {
require(
miaocraft.isApprovedOrOwner(msg.sender, shipId),
"Only approved or owner"
);
_;
}
function paginateEmissions(uint256 offset, uint256 limit)
public
view
returns (EmissionInfo[] memory emissionInfos_)
{
limit = Math.min(limit, _emissionInfos.length - offset);
emissionInfos_ = new EmissionInfo[](limit);
uint256 start = _emissionInfos.length - offset - 1;
for (uint256 i = 0; i < limit; i++) {
emissionInfos_[i] = _emissionInfos[start - i];
}
}
function paginateAsteroids(uint256 offset, uint256 limit)
public
view
returns (AsteroidInfoExtended[] memory asteroidInfos)
{
limit = Math.min(limit, _emissionInfos.length - offset);
asteroidInfos = new AsteroidInfoExtended[](
limit * ASTEROIDS_PER_EMISSION
);
uint256 start = _emissionInfos.length - offset - 1;
for (uint256 i = 0; i < limit; i++) {
uint256 emissionId = start - i;
uint256 bitmap = identifiedBitmaps[i];
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 0
] = _getAsteroidExtended(emissionId, 0, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 1
] = _getAsteroidExtended(emissionId, 1, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 2
] = _getAsteroidExtended(emissionId, 2, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 3
] = _getAsteroidExtended(emissionId, 3, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 4
] = _getAsteroidExtended(emissionId, 4, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 5
] = _getAsteroidExtended(emissionId, 5, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 6
] = _getAsteroidExtended(emissionId, 6, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 7
] = _getAsteroidExtended(emissionId, 7, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 8
] = _getAsteroidExtended(emissionId, 8, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 9
] = _getAsteroidExtended(emissionId, 9, bitmap);
asteroidInfos[
emissionId * ASTEROIDS_PER_EMISSION + 10
] = _getAsteroidExtended(emissionId, 10, bitmap);
}
}
function setButter(IERC20Resource butter_) public onlyOwner {
butter = butter_;
}
function setMiaocraft(IMiaocraft miaocraft_) public onlyOwner {
miaocraft = miaocraft_;
}
function setSbh(address sbh_) public onlyOwner {
sbh = sbh_;
}
}
文件 5 的 24:IERC1363.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./IERC165.sol";
interface IERC1363 is IERC165, IERC20 {
function transferAndCall(address to, uint256 value) external returns (bool);
function transferAndCall(
address to,
uint256 value,
bytes memory data
) external returns (bool);
function transferFromAndCall(
address from,
address to,
uint256 value
) external returns (bool);
function transferFromAndCall(
address from,
address to,
uint256 value,
bytes memory data
) external returns (bool);
function approveAndCall(address spender, uint256 value) external returns (bool);
function approveAndCall(
address spender,
uint256 value,
bytes memory data
) external returns (bool);
}
文件 6 的 24:IERC165.sol
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
文件 7 的 24:IERC20.sol
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
文件 8 的 24:IERC20Entity.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/Interfaces/IERC1363.sol";
interface IERC20Entity is IERC1363 {
event EntityTransfer(
uint256 indexed from,
uint256 indexed to,
uint256 value
);
event EntityApproval(
uint256 indexed owner,
uint256 indexed spender,
uint256 value
);
function balanceOf(uint256 entity) external view returns (uint256);
function transfer(uint256 to, uint256 amount) external returns (bool);
function allowance(uint256 owner, uint256 spender)
external
view
returns (uint256);
function approve(uint256 spender, uint256 amount) external returns (bool);
function transferFrom(
uint256 from,
uint256 to,
uint256 amount
) external returns (bool);
}
文件 9 的 24:IERC20EntityBurnable.sol
pragma solidity ^0.8.17;
import "./IERC20Entity.sol";
interface IERC20EntityBurnable is IERC20Entity {
function burn(uint256 amount) external;
function burnFrom(uint256 entity, uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
}
文件 10 的 24:IERC20Resource.sol
pragma solidity ^0.8.17;
import "./extensions/IERC20EntityBurnable.sol";
interface IERC20Resource is IERC20EntityBurnable {
function mint(address to, uint256 amount) external;
function mint(uint256 to, uint256 amount) external;
function mintAndCall(address to, uint256 amount) external;
}
文件 11 的 24:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 12 的 24:IMiaocraft.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
struct ShipInfo {
uint96 spins;
uint96 spinsBurned;
uint40 lastServiceTime;
string name;
}
interface IMiaocraft is IERC721 {
event Build(
address indexed owner,
uint256 indexed id,
uint256 spins,
string name
);
event Upgrade(address indexed owner, uint256 indexed id, uint256 spins);
event Merge(
address indexed owner,
uint256 indexed id1,
uint256 indexed id2,
uint256 spins
);
event Scrap(
address indexed scavengerOwner,
uint256 indexed scavengerId,
uint256 indexed targetId
);
event Service(
address indexed owner,
uint256 indexed id,
uint256 spins,
uint256 cost
);
event Rename(address indexed owner, uint256 indexed id, string name);
function spinsOf(uint256 id) external view returns (uint256);
function spinsDecayOf(uint256 id) external view returns (uint256);
function buildCost(uint256 spins_) external view returns (uint256);
function serviceCostOf(uint256 id) external view returns (uint256);
function getShipInfo(uint256 id) external view returns (ShipInfo memory);
function build(uint256 spins_, string calldata name_) external;
function upgrade(uint256 id, uint256 spins_) external;
function merge(uint256 id1, uint256 id2) external;
function scrap(uint256 scavengerId, uint256 targetId) external;
function service(uint256 id) external;
function rename(uint256 id, string calldata name_) external;
function isApprovedOrOwner(address spender, uint256 id)
external
view
returns (bool);
}
文件 13 的 24:ISpatialSystem.sol
pragma solidity ^0.8.17;
struct LocationInfo {
int40 xOrigin;
int40 yOrigin;
int40 xDest;
int40 yDest;
uint40 speed;
uint40 departureTime;
bool locked;
}
interface ISpatialSystem {
event UpdateLocation(
uint256 indexed entityId,
int256 xOrigin,
int256 yOrigin,
int256 xDest,
int256 yDest,
uint256 speed,
uint256 departureTime
);
event Move(
uint256 indexed entityId,
int256 xOrigin,
int256 yOrigin,
int256 xDest,
int256 yDest,
uint256 speed,
uint256 departureTime
);
event SetLocation(
uint256 indexed entityId,
int256 xOrigin,
int256 yOrigin,
int256 xDest,
int256 yDest,
uint256 speed,
uint256 departureTime
);
event SetCoordinate(uint256 indexed entityId, int256 x, int256 y);
event Locked(uint256 indexed entityId);
event Unlocked(uint256 indexed entityId);
function coordinate(uint256 entityId)
external
view
returns (int256 x, int256 y);
function collocated(uint256 entityId1, uint256 entityId2)
external
view
returns (bool);
function collocated(
uint256 entityId1,
uint256 entityId2,
uint256 radius
) external view returns (bool);
function getLocationInfo(uint256 entityId)
external
view
returns (LocationInfo memory);
function locked(uint256 entityId) external view returns (bool);
function updateLocation(uint256 entityId) external;
}
文件 14 的 24:Initializable.sol
pragma solidity ^0.8.2;
import "../../utils/Address.sol";
abstract contract Initializable {
uint8 private _initialized;
bool private _initializing;
event Initialized(uint8 version);
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
文件 15 的 24:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 16 的 24:MiningSystem.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "../extensions/IERC20Entity.sol";
struct ExtractorInfo {
uint128 shares;
int128 rewardDebt;
}
struct MineInfo {
uint128 rewardPerShare;
uint64 lastRewardTimestamp;
uint64 rewardPerSecond;
uint128 totalShares;
uint128 totalReward;
}
contract MiningSystem {
event Dock(
uint256 indexed extractorId,
uint256 indexed mineId,
uint256 shares
);
event Undock(
uint256 indexed extractorId,
uint256 indexed mineId,
uint256 shares
);
event EmergencyUndock(
uint256 indexed extractorId,
uint256 indexed mineId,
uint256 shares
);
event Extract(
uint256 indexed extractorId,
uint256 indexed mineId,
uint256 reward
);
event AddMine(
uint256 indexed mineId,
address indexed rewardToken,
uint256 rewardPerSecond,
uint256 rewardPool
);
event SetMine(
uint256 indexed mineId,
address indexed rewardToken,
uint256 rewardPerSecond,
uint256 rewardPool
);
event UpdateMine(
uint256 indexed mineId,
uint64 lastRewardTimestamp,
uint256 totalShares,
uint256 rewardPerShare
);
event DestroyMine(uint256 indexed mineId);
uint256 public constant REWARD_PER_SHARE_PRECISION = 1e12;
mapping(uint256 => MineInfo) private _mineInfos;
mapping(uint256 => mapping(uint256 => ExtractorInfo))
private _extractorInfos;
mapping(uint256 => IERC20Entity) public rewardTokens;
function exists(uint256 mineId) public view returns (bool) {
return address(rewardTokens[mineId]) != address(0);
}
function pendingReward(uint256 extractorId, uint256 mineId)
external
view
returns (uint256 pending)
{
MineInfo memory mineInfo = _mineInfos[mineId];
ExtractorInfo storage extractorInfo = _extractorInfos[mineId][
extractorId
];
uint256 rewardPerShare = mineInfo.rewardPerShare;
if (
block.timestamp > mineInfo.lastRewardTimestamp &&
mineInfo.totalShares != 0
) {
uint256 duration = block.timestamp - mineInfo.lastRewardTimestamp;
uint256 reward = Math.min(
duration * mineInfo.rewardPerSecond,
rewardTokens[mineId].balanceOf(mineId) - mineInfo.totalReward
);
rewardPerShare +=
(reward * REWARD_PER_SHARE_PRECISION) /
mineInfo.totalShares;
}
pending = uint256(
int256(
(extractorInfo.shares * rewardPerShare) /
REWARD_PER_SHARE_PRECISION
) - extractorInfo.rewardDebt
);
}
function getMineInfo(uint256 mineId) public view returns (MineInfo memory) {
return _mineInfos[mineId];
}
function getExtractorInfo(uint256 mineId, uint256 extractorId)
public
view
returns (ExtractorInfo memory)
{
return _extractorInfos[mineId][extractorId];
}
function massUpdateMines(uint256[] calldata mineIds) external {
uint256 len = mineIds.length;
for (uint256 i = 0; i < len; ++i) {
updateMine(mineIds[i]);
}
}
function updateMine(uint256 mineId)
public
returns (MineInfo memory mineInfo)
{
mineInfo = _mineInfos[mineId];
if (block.timestamp > mineInfo.lastRewardTimestamp) {
if (mineInfo.totalShares > 0) {
uint256 duration = block.timestamp -
mineInfo.lastRewardTimestamp;
uint256 reward = Math.min(
duration * mineInfo.rewardPerSecond,
rewardTokens[mineId].balanceOf(mineId) -
mineInfo.totalReward
);
mineInfo.totalReward += uint128(reward);
mineInfo.rewardPerShare += uint128(
(reward * REWARD_PER_SHARE_PRECISION) / mineInfo.totalShares
);
}
mineInfo.lastRewardTimestamp = uint64(block.timestamp);
_mineInfos[mineId] = mineInfo;
emit UpdateMine(
mineId,
mineInfo.lastRewardTimestamp,
mineInfo.totalShares,
mineInfo.rewardPerShare
);
}
}
function _dock(
uint256 extractorId,
uint256 mineId,
uint256 shares
) internal {
MineInfo memory mineInfo = updateMine(mineId);
require(
(mineInfo.totalShares * uint256(mineInfo.rewardPerShare)) /
REWARD_PER_SHARE_PRECISION <
rewardTokens[mineId].balanceOf(mineId),
"Mine depleted"
);
ExtractorInfo storage extractorInfo = _extractorInfos[mineId][
extractorId
];
extractorInfo.shares += uint128(shares);
extractorInfo.rewardDebt += int128(
uint128(
(shares * mineInfo.rewardPerShare) / REWARD_PER_SHARE_PRECISION
)
);
_mineInfos[mineId].totalShares += uint128(shares);
emit Dock(extractorId, mineId, shares);
}
function _undock(
uint256 extractorId,
uint256 mineId,
uint256 shares
) internal {
MineInfo memory mineInfo = updateMine(mineId);
ExtractorInfo storage extractorInfo = _extractorInfos[mineId][
extractorId
];
extractorInfo.rewardDebt -= int128(
uint128(
(shares * mineInfo.rewardPerShare) / REWARD_PER_SHARE_PRECISION
)
);
extractorInfo.shares -= uint128(shares);
_mineInfos[mineId].totalShares -= uint128(shares);
_tryDestroy(mineId);
emit Undock(extractorId, mineId, shares);
}
function _extract(uint256 extractorId, uint256 mineId) internal {
MineInfo memory mineInfo = updateMine(mineId);
ExtractorInfo storage extractorInfo = _extractorInfos[mineId][
extractorId
];
int256 accumulatedReward = int256(
(extractorInfo.shares * uint256(mineInfo.rewardPerShare)) /
REWARD_PER_SHARE_PRECISION
);
uint256 _pendingReward = uint256(
accumulatedReward - extractorInfo.rewardDebt
);
extractorInfo.rewardDebt = int128(accumulatedReward);
_mineInfos[mineId].totalReward -= uint128(_pendingReward);
rewardTokens[mineId].transferFrom(mineId, extractorId, _pendingReward);
_tryDestroy(mineId);
emit Extract(extractorId, mineId, _pendingReward);
}
function _undockAndExtract(
uint256 extractorId,
uint256 mineId,
uint256 shares
) internal {
MineInfo memory mineInfo = updateMine(mineId);
ExtractorInfo storage extractorInfo = _extractorInfos[mineId][
extractorId
];
int256 accumulatedReward = int256(
(extractorInfo.shares * uint256(mineInfo.rewardPerShare)) /
REWARD_PER_SHARE_PRECISION
);
uint256 _pendingReward = uint256(
accumulatedReward - extractorInfo.rewardDebt
);
extractorInfo.rewardDebt = int128(
accumulatedReward -
int256(
(shares * mineInfo.rewardPerShare) /
REWARD_PER_SHARE_PRECISION
)
);
extractorInfo.shares -= uint128(shares);
_mineInfos[mineId].totalShares -= uint128(shares);
_mineInfos[mineId].totalReward -= uint128(_pendingReward);
rewardTokens[mineId].transferFrom(mineId, extractorId, _pendingReward);
_tryDestroy(mineId);
emit Undock(extractorId, mineId, shares);
emit Extract(extractorId, mineId, _pendingReward);
}
function _emergencyUndock(uint256 extractorId, uint256 mineId) internal {
ExtractorInfo storage extractorInfo = _extractorInfos[mineId][
extractorId
];
uint256 shares = extractorInfo.shares;
if (_mineInfos[mineId].totalShares >= shares) {
_mineInfos[mineId].totalShares -= uint128(shares);
}
delete _extractorInfos[mineId][extractorId];
emit EmergencyUndock(extractorId, mineId, shares);
}
function _add(
uint256 mineId,
address rewardToken,
uint256 rewardPerSecond
) internal {
require(
_mineInfos[mineId].lastRewardTimestamp == 0,
"Mine already exists"
);
_mineInfos[mineId] = MineInfo({
rewardPerSecond: uint64(rewardPerSecond),
lastRewardTimestamp: uint64(block.timestamp),
rewardPerShare: 0,
totalShares: 0,
totalReward: 0
});
rewardTokens[mineId] = IERC20Entity(rewardToken);
emit AddMine(
mineId,
rewardToken,
rewardPerSecond,
IERC20Entity(rewardToken).balanceOf(mineId)
);
}
function _set(uint256 mineId, uint256 rewardPerSecond) internal {
_mineInfos[mineId].rewardPerSecond = uint64(rewardPerSecond);
IERC20Entity rewardToken = rewardTokens[mineId];
emit SetMine(
mineId,
address(rewardToken),
rewardPerSecond,
rewardToken.balanceOf(mineId)
);
}
function _tryDestroy(uint256 mineId) internal {
if (
rewardTokens[mineId].balanceOf(mineId) < 1e15 &&
_mineInfos[mineId].totalShares < 1e15
) {
_destroy(mineId);
}
}
function _destroy(uint256 mineId) internal {
delete _mineInfos[mineId];
delete rewardTokens[mineId];
emit DestroyMine(mineId);
}
function _destroyExtractor(uint256 mineId, uint256 extractorId) internal {
ExtractorInfo memory extractorInfo = _extractorInfos[mineId][
extractorId
];
_mineInfos[mineId].totalShares -= uint128(extractorInfo.shares);
_mineInfos[mineId].totalReward -= uint128(
uint256(
int256(
(extractorInfo.shares *
uint256(_mineInfos[mineId].rewardPerShare)) /
REWARD_PER_SHARE_PRECISION
) - extractorInfo.rewardDebt
)
);
delete _extractorInfos[mineId][extractorId];
}
}
文件 17 的 24:Multicall.sol
pragma solidity ^0.8.0;
import "./Address.sol";
abstract contract Multicall {
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
return results;
}
}
文件 18 的 24:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 19 的 24:Sample.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "solmate/utils/SignedWadMath.sol";
function wadSigmoid(int256 x) pure returns (uint256) {
return uint256(unsafeWadDiv(1e18, 1e18 + wadExp(-x)));
}
function random(uint256 seed, uint256 max) pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(seed))) % max;
}
function sampleCircle(uint256 seed, uint256 radius)
pure
returns (int256 x, int256 y)
{
unchecked {
seed = uint256(keccak256(abi.encodePacked(seed)));
int256 r = int256(random(seed++, radius)) + 1;
int256 xUnit = int256(random(seed++, 2e18)) - 1e18;
int256 yUnit = int256(Math.sqrt(1e36 - uint256(xUnit * xUnit)));
x = int256((xUnit * r) / 1e18);
y = int256((yUnit * r) / 1e18);
if (random(seed, 2) == 0) {
y = -y;
}
}
}
function sampleInvSqrt(uint256 seed, uint256 e) pure returns (uint256) {
return wadInvSqrt(random(seed, 1e18), e) / 2;
}
function wadInvSqrt(uint256 x, uint256 e) pure returns (uint256) {
return Math.sqrt(1e54 / (e + x));
}
文件 20 的 24:SignedMath.sol
pragma solidity ^0.8.0;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 21 的 24:SignedWadMath.sol
pragma solidity >=0.8.0;
function toWadUnsafe(uint256 x) pure returns (int256 r) {
assembly {
r := mul(x, 1000000000000000000)
}
}
function toDaysWadUnsafe(uint256 x) pure returns (int256 r) {
assembly {
r := div(mul(x, 1000000000000000000), 86400)
}
}
function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) {
assembly {
r := div(mul(x, 86400), 1000000000000000000)
}
}
function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) {
assembly {
r := sdiv(mul(x, y), 1000000000000000000)
}
}
function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) {
assembly {
r := sdiv(mul(x, 1000000000000000000), y)
}
}
function wadMul(int256 x, int256 y) pure returns (int256 r) {
assembly {
r := mul(x, y)
if iszero(or(iszero(x), eq(sdiv(r, x), y))) {
revert(0, 0)
}
r := sdiv(r, 1000000000000000000)
}
}
function wadDiv(int256 x, int256 y) pure returns (int256 r) {
assembly {
r := mul(x, 1000000000000000000)
if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) {
revert(0, 0)
}
r := sdiv(r, y)
}
}
function wadPow(int256 x, int256 y) pure returns (int256) {
return wadExp((wadLn(x) * y) / 1e18);
}
function wadExp(int256 x) pure returns (int256 r) {
unchecked {
if (x <= -42139678854452767551) return 0;
if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
x = (x << 78) / 5**18;
int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
x = x - k * 54916777467707473351141471128;
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
assembly {
r := sdiv(p, q)
}
r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
}
}
function wadLn(int256 x) pure returns (int256 r) {
unchecked {
require(x > 0, "UNDEFINED");
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
r := or(r, shl(2, lt(0xf, shr(r, x))))
r := or(r, shl(1, lt(0x3, shr(r, x))))
r := or(r, lt(0x1, shr(r, x)))
}
int256 k = r - 96;
x <<= uint256(159 - k);
x = int256(uint256(x) >> 159);
int256 p = x + 3273285459638523848632254066296;
p = ((p * x) >> 96) + 24828157081833163892658089445524;
p = ((p * x) >> 96) + 43456485725739037958740375743393;
p = ((p * x) >> 96) - 11111509109440967052023855526967;
p = ((p * x) >> 96) - 45023709667254063763336534515857;
p = ((p * x) >> 96) - 14706773417378608786704636184526;
p = p * x - (795164235651350426258249787498 << 96);
int256 q = x + 5573035233440673466300451813936;
q = ((q * x) >> 96) + 71694874799317883764090561454958;
q = ((q * x) >> 96) + 283447036172924575727196451306956;
q = ((q * x) >> 96) + 401686690394027663651624208769553;
q = ((q * x) >> 96) + 204048457590392012362485061816622;
q = ((q * x) >> 96) + 31853899698501571402653359427138;
q = ((q * x) >> 96) + 909429971244387300277376558375;
assembly {
r := sdiv(p, q)
}
r *= 1677202110996718588342820967067443963516166;
r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
r += 600920179829731861736702779321621459595472258049074101567377883020018308;
r >>= 174;
}
}
function unsafeDiv(int256 x, int256 y) pure returns (int256 r) {
assembly {
r := sdiv(x, y)
}
}
文件 22 的 24:SpatialSystem.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "../utils/VectorWadMath.sol";
import "../utils/EntityUtils.sol";
import "./ISpatialSystem.sol";
contract SpatialSystem is ISpatialSystem {
mapping(uint256 => LocationInfo) private _locationInfos;
function coordinate(uint256 entityId)
public
view
virtual
override
returns (int256 x, int256 y)
{
return _coordinate(entityId);
}
function coordinate(address token, uint256 id)
public
view
virtual
returns (int256 x, int256 y)
{
return _coordinate(tokenToEntity(token, id));
}
function locked(uint256 entityId)
public
view
virtual
override
returns (bool)
{
return _locationInfos[entityId].locked;
}
function collocated(uint256 entityId1, uint256 entityId2)
public
view
virtual
override
returns (bool)
{
(int256 x1, int256 y1) = _coordinate(entityId1);
(int256 x2, int256 y2) = _coordinate(entityId2);
return x1 == x2 && y1 == y2;
}
function collocated(
uint256 entityId1,
uint256 entityId2,
uint256 radius
) public view virtual override returns (bool) {
(int256 x1, int256 y1) = _coordinate(entityId1);
(int256 x2, int256 y2) = _coordinate(entityId2);
return
VectorWadMath.distance(x1 * 1e18, y1 * 1e18, x2 * 1e18, y2 * 1e18) <=
radius * 1e18;
}
function getLocationInfo(uint256 entityId)
public
view
virtual
override
returns (LocationInfo memory)
{
return _locationInfos[entityId];
}
function _coordinate(uint256 entityId)
internal
view
virtual
returns (int256 x, int256 y)
{
LocationInfo memory info = _locationInfos[entityId];
if (info.speed == 0) {
return (info.xOrigin, info.yOrigin);
}
uint256 distance =
VectorWadMath.distance(
info.xOrigin,
info.yOrigin,
info.xDest,
info.yDest
);
uint256 distanceTraveled = (block.timestamp - info.departureTime) *
info.speed;
if (distanceTraveled >= distance) {
return (info.xDest, info.yDest);
}
(x, y) = VectorWadMath.scaleVector(
info.xOrigin,
info.yOrigin,
info.xDest,
info.yDest,
int256((distanceTraveled * 1e18) / distance)
);
}
function updateLocation(uint256 entityId) public virtual override {
_updateLocation(entityId);
}
function updateLocation(address token, uint256 id) public virtual {
_updateLocation(tokenToEntity(token, id));
}
function _move(
uint256 entityId,
int256 xDest,
int256 yDest,
uint256 speed
) internal virtual {
require(!_locationInfos[entityId].locked, "Locked");
(int256 x, int256 y) = _coordinate(entityId);
_locationInfos[entityId] = LocationInfo({
xOrigin: int40(x),
yOrigin: int40(y),
xDest: int40(xDest),
yDest: int40(yDest),
speed: uint40(speed),
departureTime: uint40(block.timestamp),
locked: false
});
emit Move(
entityId,
x,
y,
xDest,
yDest,
speed,
block.timestamp
);
}
function _updateLocation(uint256 entityId) internal virtual {
(int256 x, int256 y) = _coordinate(entityId);
LocationInfo memory info = _locationInfos[entityId];
if (
x == info.xDest &&
y == info.yDest
) {
info.speed = 0;
}
info.xOrigin = int40(x);
info.yOrigin = int40(y);
info.departureTime = uint40(block.timestamp);
_locationInfos[entityId] = info;
emit UpdateLocation(
entityId,
x,
y,
info.xDest,
info.yDest,
info.speed,
block.timestamp
);
}
function _setLocation(
uint256 entityId,
LocationInfo memory info
) internal virtual {
_locationInfos[entityId] = info;
emit SetLocation(
entityId,
info.xOrigin,
info.yOrigin,
info.xDest,
info.yDest,
info.speed,
info.departureTime
);
}
function _setCoordinate(
uint256 entityId,
int256 x,
int256 y
) internal virtual {
_locationInfos[entityId] = LocationInfo({
xOrigin: int40(x),
yOrigin: int40(y),
xDest: int40(x),
yDest: int40(y),
speed: 0,
departureTime: uint40(block.timestamp),
locked: false
});
emit SetCoordinate(entityId, x, y);
}
function _lock(
uint256 entityId
) internal virtual {
require(_locationInfos[entityId].speed == 0, "Moving");
_locationInfos[entityId].locked = true;
emit Locked(entityId);
}
function _unlock(
uint256 entityId
) internal virtual {
_locationInfos[entityId].locked = false;
emit Unlocked(entityId);
}
}
文件 23 的 24:VectorWadMath.sol
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
library VectorWadMath {
using Math for uint256;
using SignedMath for int256;
int256 constant PRECISION = 1e18;
int256 constant PRECISION_UINT = 1e18;
function distance(
int256 x1,
int256 y1,
int256 x2,
int256 y2
) internal pure returns (uint256) {
return ((x2 - x1).abs()**2 + (y2 - y1).abs()**2).sqrt();
}
function unitVector(
int256 x1,
int256 y1,
int256 x2,
int256 y2
) internal pure returns (int256, int256) {
int256 dist = int256(distance(x1, y1, x2, y2));
return (((x2 - x1) * PRECISION) / dist, ((y2 - y1) * PRECISION) / dist);
}
function scaleVector(
int256 x1,
int256 y1,
int256 x2,
int256 y2,
int256 scale
) internal pure returns (int256, int256) {
return (
x1 + ((x2 - x1) * scale) / PRECISION,
y1 + ((y2 - y1) * scale) / PRECISION
);
}
}
文件 24 的 24:constants.sol
pragma solidity ^0.8.17;
uint16 constant VRF_MIN_BLOCKS = 3;
uint32 constant VRF_GAS_LIMIT = 300000;
uint256 constant SPINS_PRECISION = 1e18;
uint256 constant GENESIS_SUPPLY = 2000;
uint256 constant ASTEROID_COORD_PRECISION = 1e3;
int256 constant ASTEROID_COORD_NEG_FLAG = 1e3;
{
"compilationTarget": {
"src/GenesisGalaxy.sol": "GenesisGalaxy"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@chainlink/=lib/chainlink/contracts/src/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":chainlink/=lib/chainlink/integration-tests/contracts/ethereum/src/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":miaocraft/=src/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[{"internalType":"uint256","name":"asteroidsPerEmission","type":"uint256"},{"internalType":"uint256","name":"maxDepletionInterval","type":"uint256"},{"internalType":"uint256","name":"maxRadius","type":"uint256"},{"internalType":"uint256","name":"speed","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPool","type":"uint256"}],"name":"AddMine","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"}],"name":"DestroyMine","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"extractorId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Dock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"extractorId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"EmergencyUndock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"extractorId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Extract","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"entityId","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"entityId","type":"uint256"},{"indexed":false,"internalType":"int256","name":"xOrigin","type":"int256"},{"indexed":false,"internalType":"int256","name":"yOrigin","type":"int256"},{"indexed":false,"internalType":"int256","name":"xDest","type":"int256"},{"indexed":false,"internalType":"int256","name":"yDest","type":"int256"},{"indexed":false,"internalType":"uint256","name":"speed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"departureTime","type":"uint256"}],"name":"Move","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"entityId","type":"uint256"},{"indexed":false,"internalType":"int256","name":"x","type":"int256"},{"indexed":false,"internalType":"int256","name":"y","type":"int256"}],"name":"SetCoordinate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"entityId","type":"uint256"},{"indexed":false,"internalType":"int256","name":"xOrigin","type":"int256"},{"indexed":false,"internalType":"int256","name":"yOrigin","type":"int256"},{"indexed":false,"internalType":"int256","name":"xDest","type":"int256"},{"indexed":false,"internalType":"int256","name":"yDest","type":"int256"},{"indexed":false,"internalType":"uint256","name":"speed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"departureTime","type":"uint256"}],"name":"SetLocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPool","type":"uint256"}],"name":"SetMine","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"extractorId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Undock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"entityId","type":"uint256"}],"name":"Unlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"entityId","type":"uint256"},{"indexed":false,"internalType":"int256","name":"xOrigin","type":"int256"},{"indexed":false,"internalType":"int256","name":"yOrigin","type":"int256"},{"indexed":false,"internalType":"int256","name":"xDest","type":"int256"},{"indexed":false,"internalType":"int256","name":"yDest","type":"int256"},{"indexed":false,"internalType":"uint256","name":"speed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"departureTime","type":"uint256"}],"name":"UpdateLocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"mineId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"lastRewardTimestamp","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerShare","type":"uint256"}],"name":"UpdateMine","type":"event"},{"inputs":[],"name":"ASTEROIDS_PER_EMISSION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DEPLETION_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_RADIUS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_PER_SHARE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPEED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_emissionInfos","outputs":[{"internalType":"uint128","name":"seed","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addEmission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"asteroidIdToCoordinate","outputs":[{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"butter","outputs":[{"internalType":"contract IERC20Resource","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"entityId1","type":"uint256"},{"internalType":"uint256","name":"entityId2","type":"uint256"},{"internalType":"uint256","name":"radius","type":"uint256"}],"name":"collocated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"entityId1","type":"uint256"},{"internalType":"uint256","name":"entityId2","type":"uint256"}],"name":"collocated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"entityId","type":"uint256"}],"name":"coordinate","outputs":[{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"coordinate","outputs":[{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"coordinateToAsteroidId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"dock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"emergencyUndock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mineId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"extract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getAsteroid","outputs":[{"components":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"internalType":"struct AsteroidInfo","name":"asteroidInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getAsteroidExtended","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"emissionId","type":"uint128"},{"internalType":"uint32","name":"index","type":"uint32"},{"internalType":"bool","name":"identified","type":"bool"},{"components":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"internalType":"struct AsteroidInfo","name":"asteroidInfo","type":"tuple"},{"components":[{"internalType":"uint128","name":"rewardPerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTimestamp","type":"uint64"},{"internalType":"uint64","name":"rewardPerSecond","type":"uint64"},{"internalType":"uint128","name":"totalShares","type":"uint128"},{"internalType":"uint128","name":"totalReward","type":"uint128"}],"internalType":"struct MineInfo","name":"mineInfo","type":"tuple"}],"internalType":"struct AsteroidInfoExtended","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"}],"name":"getAsteroids","outputs":[{"components":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"internalType":"struct AsteroidInfo[]","name":"asteroidInfos","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"}],"name":"getEmission","outputs":[{"components":[{"internalType":"uint128","name":"seed","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct EmissionInfo","name":"emissionInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEmissionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mineId","type":"uint256"},{"internalType":"uint256","name":"extractorId","type":"uint256"}],"name":"getExtractorInfo","outputs":[{"components":[{"internalType":"uint128","name":"shares","type":"uint128"},{"internalType":"int128","name":"rewardDebt","type":"int128"}],"internalType":"struct ExtractorInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"entityId","type":"uint256"}],"name":"getLocationInfo","outputs":[{"components":[{"internalType":"int40","name":"xOrigin","type":"int40"},{"internalType":"int40","name":"yOrigin","type":"int40"},{"internalType":"int40","name":"xDest","type":"int40"},{"internalType":"int40","name":"yDest","type":"int40"},{"internalType":"uint40","name":"speed","type":"uint40"},{"internalType":"uint40","name":"departureTime","type":"uint40"},{"internalType":"bool","name":"locked","type":"bool"}],"internalType":"struct LocationInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mineId","type":"uint256"}],"name":"getMineInfo","outputs":[{"components":[{"internalType":"uint128","name":"rewardPerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTimestamp","type":"uint64"},{"internalType":"uint64","name":"rewardPerSecond","type":"uint64"},{"internalType":"uint128","name":"totalShares","type":"uint128"},{"internalType":"uint128","name":"totalReward","type":"uint128"}],"internalType":"struct MineInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOrigin","outputs":[{"components":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"internalType":"struct AsteroidInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOriginExtended","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"emissionId","type":"uint128"},{"internalType":"uint32","name":"index","type":"uint32"},{"internalType":"bool","name":"identified","type":"bool"},{"components":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"internalType":"struct AsteroidInfo","name":"asteroidInfo","type":"tuple"},{"components":[{"internalType":"uint128","name":"rewardPerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTimestamp","type":"uint64"},{"internalType":"uint64","name":"rewardPerSecond","type":"uint64"},{"internalType":"uint128","name":"totalShares","type":"uint128"},{"internalType":"uint128","name":"totalReward","type":"uint128"}],"internalType":"struct MineInfo","name":"mineInfo","type":"tuple"}],"internalType":"struct AsteroidInfoExtended","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"identified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"identifiedBitmaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"identify","outputs":[{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"}],"name":"identifyAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"shipId","type":"uint256"}],"name":"identifyAndDock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"emissionId","type":"uint256"},{"internalType":"uint256[]","name":"indices","type":"uint256[]"}],"name":"identifyMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"butter_","type":"address"},{"internalType":"address","name":"miaocraft_","type":"address"},{"internalType":"address","name":"sbh_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"entityId","type":"uint256"}],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"mineIds","type":"uint256[]"}],"name":"massUpdateMines","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"miaocraft","outputs":[{"internalType":"contract IMiaocraft","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"int256","name":"xDest","type":"int256"},{"internalType":"int256","name":"yDest","type":"int256"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"paginateAsteroids","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"emissionId","type":"uint128"},{"internalType":"uint32","name":"index","type":"uint32"},{"internalType":"bool","name":"identified","type":"bool"},{"components":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"internalType":"struct AsteroidInfo","name":"asteroidInfo","type":"tuple"},{"components":[{"internalType":"uint128","name":"rewardPerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTimestamp","type":"uint64"},{"internalType":"uint64","name":"rewardPerSecond","type":"uint64"},{"internalType":"uint128","name":"totalShares","type":"uint128"},{"internalType":"uint128","name":"totalReward","type":"uint128"}],"internalType":"struct MineInfo","name":"mineInfo","type":"tuple"}],"internalType":"struct AsteroidInfoExtended[]","name":"asteroidInfos","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"paginateEmissions","outputs":[{"components":[{"internalType":"uint128","name":"seed","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct EmissionInfo[]","name":"emissionInfos_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"extractorId","type":"uint256"},{"internalType":"uint256","name":"mineId","type":"uint256"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"redock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"remove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"contract IERC20Entity","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sbh","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Resource","name":"butter_","type":"address"}],"name":"setButter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMiaocraft","name":"miaocraft_","type":"address"}],"name":"setMiaocraft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sbh_","type":"address"}],"name":"setSbh","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"}],"name":"undockAndExtract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"fromAsteroidId","type":"uint256"},{"internalType":"uint256","name":"toAsteroidId","type":"uint256"}],"name":"undockExtractAndMove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shipId","type":"uint256"},{"internalType":"uint256","name":"asteroidId","type":"uint256"},{"internalType":"int256","name":"xDest","type":"int256"},{"internalType":"int256","name":"yDest","type":"int256"}],"name":"undockExtractAndMove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"entityId","type":"uint256"}],"name":"updateLocation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"updateLocation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mineId","type":"uint256"}],"name":"updateMine","outputs":[{"components":[{"internalType":"uint128","name":"rewardPerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTimestamp","type":"uint64"},{"internalType":"uint64","name":"rewardPerSecond","type":"uint64"},{"internalType":"uint128","name":"totalShares","type":"uint128"},{"internalType":"uint128","name":"totalReward","type":"uint128"}],"internalType":"struct MineInfo","name":"mineInfo","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]