GenesisExpedition
Inherits: IGenesisExpedition, EIP712, Ownable2Step
Author: luoyhang003
Core game logic contract for the Genesis Expedition event.
- Manages player inventories (raw stones, hammers, golden stones).
- Handles forging of raw stones into gems via EIP-712 server signatures.
- Manages GoldenStone activation, tapping, and group forging mechanics.
- Tracks daily system rewards (daily raw stones & daily hammers).
- Aggregates gem forging statistics for daily STO reward sharing.
- Only registered staking contracts can distribute base resources.
State Variables
FORGE_TYPEHASH
EIP-712 typehash used for forging typed data messages.
keccak256("Forge(address player,uint256 nonce,uint256 amount,bytes32 gemsHash,uint256 deadline)") This defines the struct used in server-side signing for forge operations.
bytes32 public constant FORGE_TYPEHASH =
keccak256("Forge(address player,uint256 nonce,uint256 amount,bytes32 gemsHash,uint256 deadline)")
BPS_DENOMINATOR
Denominator used for basis points (BPS) math.
- 100 == 1x (100%)
- e.g. slopeBps = 5 means 5% of baseReward.
uint256 internal constant BPS_DENOMINATOR = 100
DURATION
Duration of the Genesis Expedition event.
Used together with START_TIME to derive END_TIME.
uint256 public constant DURATION = 70 days
DAILY_REWARDED_HAMMERS
Daily rewarded hammer count (system-level, per eligible user).
- Given once per UTC day after daily hammer rewards are activated.
- These are stored virtually and consumed during golden stone actions / forging.
uint256 public constant DAILY_REWARDED_HAMMERS = 2
DAILY_REWARDED_RAW_STONES
Daily rewarded raw stones (system-level, per user).
- 3 system raw stones are granted virtually per day.
- They expire daily if not used (tracked via consumedRawStones).
uint256 public constant DAILY_REWARDED_RAW_STONES = 3
REFERRAL_REGISTRY_ADDR
Address of the ReferralRegistry contract.
Used in off-chain indexing / integrity checks; not called directly here.
address public immutable REFERRAL_REGISTRY_ADDR
START_TIME
Event start timestamp (UTC-0 aligned).
All time-based logic (daily rewards, availability, etc.) depends on this.
uint256 public immutable START_TIME
END_TIME
Event end timestamp.
After this time, the event is considered inactive for time-gated actions.
uint256 public immutable END_TIME
hammersPerReferral
Number of hammers rewarded per valid referral.
Used by staking contracts to reward referrers via this core contract.
uint256 public hammersPerReferral = 2
goldenStoneActiveDuration
Duration for which a GoldenStone remains active after activation.
- Used for both manual forging and auto-forging conditions.
- Measured in seconds; default is 3 days.
uint256 public goldenStoneActiveDuration = 3 days
goldenStoneMinParticipants
Minimum number of participants required to successfully forge a GoldenStone.
Must be >= 3 by design.
uint256 public goldenStoneMinParticipants = 3
goldenStoneMaxParticipants
Maximum number of participants allowed for a single GoldenStone.
Upper cap for fairness & gas constraints (default 10).
uint256 public goldenStoneMaxParticipants = 10
goldenStoneBaseReward
Base gem reward per participant when forging a GoldenStone.
- Actual reward scales with participant count via
rewardLinearSlopeBps. - Final reward per participant = baseReward + baseReward * slopeBps * N / BPS_DENOMINATOR.
uint256 public goldenStoneBaseReward = 1000
rewardLinearSlopeBps
Linear slope (in BPS) used to scale GoldenStone rewards with participants.
- Example: slopeBps = 5 -> +5% per extra participant (relative to baseReward).
uint256 public rewardLinearSlopeBps = 5
masterSigner
Address of the master signer used for EIP-712 forge signatures.
- Private key is used off-chain to sign forge messages.
- This address is used on-chain for signature verification.
address public masterSigner
inventories
Player inventory of stored resources (non-system, non-expiring).
Tracks raw stones, hammers, and golden stones that belong to players.
mapping(address => PlayerInventory) private inventories
consumedRawStones
Tracks how many system raw stones a user has consumed on a given day.
- Keyed by user and floored UTC day timestamp.
- Used to compute "available" daily system raw stones = DAILY_REWARDED_RAW_STONES - consumed.
mapping(address => mapping(uint256 => uint256)) private consumedRawStones
consumedRewardedHammers
Tracks total system hammers consumed by a user (across days).
- System rewarded hammers are computed from activation day and consumed count.
- This value is not keyed by day, only total count.
mapping(address => uint256) private consumedRewardedHammers
stakings
Registry of staking contracts allowed to call distributing functions.
Only staking contracts can mint raw stones/hammers/golden stones.
mapping(address => bool) private stakings
activatedGoldenStones
Activated GoldenStone instances per player and index.
- Each entry contains deadline, forged flag, and participant addresses.
- Indexed by player &
activatedGoldenStoneAmount[player].
mapping(address => mapping(uint256 => GoldenStone)) private activatedGoldenStones
activatedGoldenStoneAmount
Count of GoldenStones a player has activated.
Also used as upper bound for indexing into activatedGoldenStones.
mapping(address => uint256) private activatedGoldenStoneAmount
dailyHammerRewardsActivatedAt
Day on which a user first activated daily hammer rewards (UTC-floor).
- Zero means user has not activated daily hammer rewards.
- After activation, user accrues DAILY_REWARDED_HAMMERS per full day.
mapping(address => uint256) private dailyHammerRewardsActivatedAt
isNonceConsumed
Tracks whether a forge nonce has been consumed for a given player.
Used to prevent replay of EIP-712 signed forge messages.
mapping(address => mapping(uint256 => bool)) private isNonceConsumed
forgedGems
Per-player gems forged on a given UTC day.
Used for-share-of-daily rewards / analytics.
mapping(address => mapping(uint256 => uint256)) private forgedGems
totalForgedGems
Total gems forged by all players on a given day.
Combined with forgedGems to compute proportional STO rewards.
mapping(uint256 => uint256) private totalForgedGems
internalLotteryNonce
Internal nonce used in lottery code generation.
Incremented per-code to perturb randomness inputs.
uint256 private internalLotteryNonce
Functions
onlyStakings
Restricts function to authorized staking contracts only.
Reverts with NotStakingContract if caller is not whitelisted.
modifier onlyStakings() ;
onlyEventActive
Restricts function to when the event is active.
Reverts if block.timestamp is outside [START_TIME, END_TIME].
modifier onlyEventActive() ;
constructor
Initializes the Genesis Expedition core contract.
_startTimemust be in the future and aligned to UTC-0 (mod 1 days == 0).- EIP-712 domain is configured with name "GenesisExpedition" and version "1".
constructor(address _referralRegistryAddr, address _masterSigner, uint256 _startTime)
EIP712("GenesisExpedition", "1")
Ownable(msg.sender);
Parameters
| Name | Type | Description |
|---|---|---|
_referralRegistryAddr | address | Address of the ReferralRegistry contract. |
_masterSigner | address | Address of the EIP-712 master signer (with off-chain private key). |
_startTime | uint256 | UTC-0 aligned start timestamp of the event. |
getPlayerInventory
Returns the player's stored inventory (non-system resources only).
- Before event start, always returns zero-initialized inventory.
- This does not include daily system raw stones or system hammers.
function getPlayerInventory(address _player) public view returns (PlayerInventory memory inventory_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
Returns
| Name | Type | Description |
|---|---|---|
inventory_ | PlayerInventory | The player's stored inventory (rawStones, hammers, goldenStones). |
getSystemResources
Returns system-level resources available to a player (daily rewards).
- Daily raw stones: 3 per day minus consumed.
- Daily hammers: accrues since activation and minus consumed.
- GoldenStones are not system-level here (always 0 in this struct).
function getSystemResources(address _player) public view returns (PlayerInventory memory inventory_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
Returns
| Name | Type | Description |
|---|---|---|
inventory_ | PlayerInventory | Inventory representing system resources available today. |
getTotalResources
Returns total resources (stored + system) for a player.
- Aggregates getPlayerInventory and getSystemResources.
- Before event start, returns empty inventory.
function getTotalResources(address _player) external view returns (PlayerInventory memory inventory_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
Returns
| Name | Type | Description |
|---|---|---|
inventory_ | PlayerInventory | Aggregated inventory (stored + system resources). |
getActivatedGoldenStoneAmount
Returns how many golden stones a player has activated.
This describes the length of the player's activatedGoldenStones list.
function getActivatedGoldenStoneAmount(address _player) external view returns (uint256 amount_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
Returns
| Name | Type | Description |
|---|---|---|
amount_ | uint256 | The number of activated golden stones. |
getActivatedGoldenStones
Returns all activated golden stones for a player.
- Iterates from 0 up to activatedGoldenStoneAmount.
- Stops early if a goldenStone has deadline == 0 (sparse safety).
function getActivatedGoldenStones(address _player) external view returns (GoldenStone[] memory goldenStones_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
Returns
| Name | Type | Description |
|---|---|---|
goldenStones_ | GoldenStone[] | Array of GoldenStone structures. |
getActivatedGoldenStones
Returns a paginated slice of activated golden stones for a player.
- Validates that
_start + _limit - 1is < activatedGoldenStoneAmount. - May stop early if a golden stone with deadline == 0 is encountered.
function getActivatedGoldenStones(address _player, uint256 _start, uint256 _limit)
external
view
returns (GoldenStone[] memory goldenStones_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_start | uint256 | The starting index (inclusive). |
_limit | uint256 | The number of entries to fetch. |
Returns
| Name | Type | Description |
|---|---|---|
goldenStones_ | GoldenStone[] | Array of GoldenStone structures of size _limit. |
getActivatedGoldenStone
Returns a single activated golden stone for a player by index.
Reverts if _index is out of range.
function getActivatedGoldenStone(address _player, uint256 _index)
external
view
returns (GoldenStone memory goldenStone_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_index | uint256 | Index of the activated golden stone. |
Returns
| Name | Type | Description |
|---|---|---|
goldenStone_ | GoldenStone | The GoldenStone data at the given index. |
getHammersPerReferral
Returns the current configured hammers reward per referral.
Used by staking contracts to query the up-to-date per-referral reward.
function getHammersPerReferral() external view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | The number of hammers rewarded per valid referral. |
checkNonce
Checks whether a given forge nonce is still valid for a player.
Returns false if the nonce has already been consumed.
function checkNonce(address _player, uint256 _nonce) external view returns (bool valid_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_nonce | uint256 | The nonce to check. |
Returns
| Name | Type | Description |
|---|---|---|
valid_ | bool | True if nonce has not yet been consumed. |
getForgedGems
Returns the gems forged by a player today versus total forged today.
Uses current UTC day derived from block.timestamp.
function getForgedGems(address _player) external view returns (uint256 forged_, uint256 total_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
Returns
| Name | Type | Description |
|---|---|---|
forged_ | uint256 | Gems forged today by the player. |
total_ | uint256 | Total gems forged today by all players. |
getForgedGems
Returns the gems forged by a player on a specific day.
_daycan be any timestamp; it is floored to UTC day.
function getForgedGems(address _player, uint256 _day) external view returns (uint256 forged_, uint256 total_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_day | uint256 | Any timestamp in the desired day (UTC). |
Returns
| Name | Type | Description |
|---|---|---|
forged_ | uint256 | Gems forged by the player on that day. |
total_ | uint256 | Total gems forged by all players on that day. |
verifyForgeSignature
Verifies an off-chain EIP-712 forge signature.
- Does not mutate state.
- Returns true if signature is valid and signer == masterSigner.
function verifyForgeSignature(
address _player,
uint256 _nonce,
uint256 _amount,
uint256[] memory _gems,
uint256 _deadline,
bytes calldata _signature
) external view returns (bool valid_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | Player address in the signed struct. |
_nonce | uint256 | Unique nonce for replay protection. |
_amount | uint256 | Number of raw stones to forge. |
_gems | uint256[] | Array of gem rewards per raw stone. |
_deadline | uint256 | Signature expiry timestamp. |
_signature | bytes | Off-chain EIP-712 signature. |
Returns
| Name | Type | Description |
|---|---|---|
valid_ | bool | True if signature is valid and from masterSigner. |
getForgeDigest
Computes the EIP-712 digest for a forge operation.
- Helpful for debugging and off-chain tooling verification.
function getForgeDigest(
address _player,
uint256 _nonce,
uint256 _amount,
uint256[] memory _gems,
uint256 _deadline
) external view returns (bytes32 digest_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | Player address in the struct. |
_nonce | uint256 | Unique nonce. |
_amount | uint256 | Number of raw stones to forge. |
_gems | uint256[] | Array of gem amounts. |
_deadline | uint256 | Signature expiry timestamp. |
Returns
| Name | Type | Description |
|---|---|---|
digest_ | bytes32 | The EIP-712 message digest used for signing. |
forge
Forges raw stones into gems using a server-side signature.
Flow:
- Validates caller is the player.
- Validates array length and non-zero amount.
- Checks deadline, nonce, and EIP-712 signature.
- Marks nonce consumed.
- Consumes required resources (raw stones + hammers; system then stored).
- Emits gem rewards and generates lottery codes.
function forge(
address _player,
uint256 _nonce,
uint256 _amount,
uint256[] memory _gems,
uint256 _deadline,
bytes calldata _signature
) external onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | Address of the player (must equal msg.sender). |
_nonce | uint256 | Unique nonce provided in signed data. |
_amount | uint256 | Number of raw stones to forge (length of _gems). |
_gems | uint256[] | Gem rewards array for each forged raw stone. |
_deadline | uint256 | UNIX timestamp after which signature is invalid. |
_signature | bytes | Off-chain EIP-712 signature from masterSigner. |
activateGoldenStone
Activates one GoldenStone for the caller so others can join and forge together.
- Requires caller to have more golden stones than already activated.
- Creates a GoldenStone record with
deadline = now + goldenStoneActiveDuration. - First participant is always the owner.
Note: events: Emits GoldenStoneActivated.
function activateGoldenStone() external onlyEventActive;
tapGoldenStone
Allows a user to tap (join) another player's activated GoldenStone.
- Requires golden stone to be active and not yet forged.
- Enforces max participants.
- Ensures participant cannot join twice.
- Consumes either system rewarded hammer or stored hammer.
function tapGoldenStone(address _owner, uint256 _index) external onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_owner | address | The owner of the GoldenStone. |
_index | uint256 | Index of the GoldenStone in the owner's list. |
forgeGoldenStone
Manually forges an activated GoldenStone by its owner.
- Only the owner can call.
- Enforces participant count and deadline conditions.
function forgeGoldenStone(address _owner, uint256 _index) external onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_owner | address | Owner address of the GoldenStone. |
_index | uint256 | Index of the GoldenStone in the owner's list. |
autoForgeGoldenStone
Auto-forges a GoldenStone after expiration using the master signer.
- Can only be called by masterSigner.
- Requires the GoldenStone to have expired.
function autoForgeGoldenStone(address _owner, uint256 _index) external onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_owner | address | Owner address of the GoldenStone. |
_index | uint256 | Index of the GoldenStone in the owner's list. |
distributeRawStones
Distributes raw stones to a player (called by staking contracts).
- Restricted to registered staking contracts via
onlyStakings. - Increases the player's stored rawStones.
function distributeRawStones(address _player, uint256 _amount) external onlyStakings onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_amount | uint256 | Amount of raw stones to distribute. |
distributeHammers
Distributes hammers to a player (called by staking contracts).
Increases the player's stored hammers.
function distributeHammers(address _player, uint256 _amount) external onlyStakings onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_amount | uint256 | Amount of hammers to distribute. |
distributeGoldenStones
Distributes golden stones to a player (called by staking contracts).
Increases the player's stored goldenStones.
function distributeGoldenStones(address _player, uint256 _amount) external onlyStakings onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
_amount | uint256 | Amount of golden stones to distribute. |
activateDailyHammerRewards
Activates daily hammer rewards for a player (called by staking).
- Only callable once per player (re-activating simply resets date).
- Daily rewards start counting from this day forward.
function activateDailyHammerRewards(address _player) external onlyStakings onlyEventActive;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The address of the player. |
setStakings
Sets or unsets a staking contract address.
Only callable by owner.
function setStakings(address _staking, bool _flag) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_staking | address | The staking contract address. |
_flag | bool | True to enable as staking, false to disable. |
setMasterSigner
Updates the master signer address used for EIP-712 forging.
- Only callable by owner.
- Critical for security: masterSigner compromise requires changing this.
function setMasterSigner(address _key) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_key | address | New master signer address. |
setGoldenStoneConfigs
Updates configuration for GoldenStone activation and participant limits.
- _activeDuration must be > 0.
- _minParticipants must be > 1.
- _maxParticipants must be >= _minParticipants.
function setGoldenStoneConfigs(uint256 _activeDuration, uint256 _minParticipants, uint256 _maxParticipants)
external
onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_activeDuration | uint256 | New active duration in seconds. |
_minParticipants | uint256 | New minimum participants. |
_maxParticipants | uint256 | New maximum participants. |
setGoldenStoneReward
Updates the GoldenStone base reward and linear slope.
- No explicit bounds on
_baseRewardand_slopeBps; must be configured carefully.
function setGoldenStoneReward(uint256 _baseReward, uint256 _slopeBps) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_baseReward | uint256 | New base gem reward per participant. |
_slopeBps | uint256 | New BPS slope value for linear reward scaling. |
setHammersPerReferral
Updates the number of hammers rewarded per referral.
Does not enforce a max; must be set to reasonable values via governance.
function setHammersPerReferral(uint256 _hammersPerReferral) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_hammersPerReferral | uint256 | New hammer reward amount per referral. |
_onlyStakings
Internal check that caller is a registered staking contract.
Reverts with NotStakingContract if stakings[msg.sender] is false.
function _onlyStakings() internal view;
_onlyEventActive
Internal check that event is active.
Reverts with EventNotActive if timestamp not in [START_TIME, END_TIME].
function _onlyEventActive() internal view;
_floorToDay
Floors a timestamp down to its UTC-0 day boundary.
E.g. 2024-01-01 15:23 -> 2024-01-01 00:00.
function _floorToDay(uint256 timestamp) internal pure returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
timestamp | uint256 | The original timestamp. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | The floored timestamp at 00:00 UTC of that day. |
_generateLotteryCodes
Generates lottery codes for a forge action.
- Uses blockhash, timestamp, gasleft, player, and internalLotteryNonce as entropy.
- Emits LotteryGenerated per code.
function _generateLotteryCodes(address _player, uint256 _amount) internal;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The player address receiving lottery codes. |
_amount | uint256 | The number of lottery codes to generate. |
_distributeGems
Distributes gem rewards from a forge request.
- Emits a GemsForged event per entry.
- Aggregates per-player and global forged gems for the current day.
function _distributeGems(address _player, uint256[] memory _gems) internal returns (uint256 gemsForged_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The player who receives the gems. |
_gems | uint256[] | Array of gem amounts per forged raw stone. |
Returns
| Name | Type | Description |
|---|---|---|
gemsForged_ | uint256 | Total gems forged in this operation. |
_consumeResources
Consumes raw stones and hammers for a forge operation.
- Prioritizes consumption of system (daily) resources before stored resources.
- Reverts if not enough total raw stones or hammers.
function _consumeResources(address _player, uint256 _amount) internal;
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The player performing the forge. |
_amount | uint256 | The number of raw stones to consume. |
_isNonceConsumed
Internal helper to check if a forge nonce is consumed.
Returns true if isNonceConsumed[_player][_nonce] is true.
function _isNonceConsumed(address _player, uint256 _nonce) internal view returns (bool consumed_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | The player address. |
_nonce | uint256 | The nonce to check. |
Returns
| Name | Type | Description |
|---|---|---|
consumed_ | bool | True if nonce is already used. |
_forgeGoldenStone
Internal logic to forge a GoldenStone, manual or auto.
- If
_isAutois false:
- Caller must be the owner.
- GoldenStone must not be expired.
- If
_isAutois true:
- Caller must be masterSigner.
- GoldenStone must be expired.
- Enforces participant count and not-yet-forged.
- Distributes gem rewards to all participants.
function _forgeGoldenStone(address _owner, uint256 _index, bool _isAuto) internal;
Parameters
| Name | Type | Description |
|---|---|---|
_owner | address | The owner of the GoldenStone. |
_index | uint256 | Index of the GoldenStone in the owner's list. |
_isAuto | bool | True if called by auto-forge logic (masterSigner). |
_verifyForgeSignature
Internal EIP-712 signature verification for forge operations.
- Reverts if nonce already consumed.
- Returns true if recovered signer equals masterSigner.
function _verifyForgeSignature(
address _player,
uint256 _nonce,
uint256 _amount,
uint256[] memory _gems,
uint256 _deadline,
bytes calldata _signature
) internal view returns (bool valid_);
Parameters
| Name | Type | Description |
|---|---|---|
_player | address | Player address in the message. |
_nonce | uint256 | Nonce used for replay protection. |
_amount | uint256 | Amount of raw stones to forge. |
_gems | uint256[] | Array of gem rewards. |
_deadline | uint256 | Signature expiry timestamp. |
_signature | bytes | EIP-712 off-chain signature. |
Returns
| Name | Type | Description |
|---|---|---|
valid_ | bool | True if signature is valid and from masterSigner. |
_hashForForge
Internal helper to compute the struct hash for Forge EIP-712 messages.
- Computes keccak256(abi.encode(FORGE_TYPEHASH, ...)) with inline assembly.
_gemsis hashed first with keccak256 to abytes32 gemsHash.
function _hashForForge(
bytes32 _typehash,
address _player,
uint256 _nonce,
uint256 _amount,
uint256[] memory _gems,
uint256 _deadline
) internal pure returns (bytes32 hash_);
Parameters
| Name | Type | Description |
|---|---|---|
_typehash | bytes32 | The typehash of the Forge struct. |
_player | address | Player address. |
_nonce | uint256 | Unique nonce. |
_amount | uint256 | Forge amount. |
_gems | uint256[] | Array of gem values. |
_deadline | uint256 | Signature deadline. |
Returns
| Name | Type | Description |
|---|---|---|
hash_ | bytes32 | The keccak256 hash of the encoded struct. |