gate.move
Overview
The promise of a truly decentralized metaverse lies in “digital physics”—a set of immutable, composable rules that enable emergent gameplay and player-driven innovation. In the EVE Frontier world contracts, the Smart Gate system is a primary example of this philosophy. Far more than a simple teleportation point, the Gate is a programmable structure that balances core game integrity with unprecedented player agency.
This guide provides a comprehensive technical breakdown of Gate architecture, logic, and extensibility for developers building on the Frontier platform.
Learning Objectives
By the end of this article, you will be able to:
- Explain the three-layer architecture of the Frontier world contracts.
- Describe the lifecycle of a Gate, from anchoring to linking.
- Analyze the “Typed Witness Pattern” used for securing extensions.
- Implement interactions with Gates using the developer toolkit and TypeScript SDK.
1. Architecture and Role
The Frontier world contracts utilize a three-layer model to prioritize composition over inheritance.
- Layer 1: Composable Primitives: Focused modules handling “physics” logic like spatial positioning (
location.move), resource consumption (fuel.move), and state management (status.move). - Layer 2: Game-Defined Assemblies: Structures like the
Gatethat compose these primitives into functional units. - Layer 3: Player Extensions: Custom smart contracts that register with assemblies to modify their behavior.
2. Operational Lifecycle and Physics
A Gate’s lifecycle begins with Anchoring, where it is initialized in the ObjectRegistry and linked to a NetworkNode for power.
The Gate Lifecycle
sequenceDiagram
participant Admin
participant Registry as ObjectRegistry
participant NWN as NetworkNode
participant Gate
participant Char as Character
Admin->>Registry: anchor()
Admin->>NWN: connect_assembly(gate_id)
Admin->>Gate: Create Gate Object
Admin->>Char: Transfer OwnerCap
Note over Gate: Status: Anchored/Offline
Char->>Gate: online(owner_cap, nwn)
Gate->>NWN: reserve_energy()
Note over Gate: Status: Online
Core Physics: Linking and Energy
Gates function by linking to another gate to create a transport link. This process is governed by strict “digital physics”:
- Ownership: Both gates must be owned by the same character.
- Distance: Gates must be within the maximum distance configured for their type in the
GateConfig(a shared object mappingtype_idtomax_distance). Admins configure distance limits viaset_max_distance. - Location Proofs: Linking requires a
distance_proof(a signature from a trusted server) to verify the gates are within range. Thelink_gatesfunction requiresAdminACLsponsor verification as a temporary access check until a location service is available. Note that theCharacterparameter has been removed fromlink_gates; authorization is handled entirely viaOwnerCaps. - Unlinking: Gates can be unlinked by the owner via
unlink_gates(requires bothOwnerCaps) or by an admin viaunlink_gates_by_admin. Gates must be unlinked before they can be unanchored. - Unlink and Unanchor: The
unlink_and_unanchorfunction combines unlinking and unanchoring a source gate in a single call (requiresAdminACL).unlink_and_unanchor_orphanhandles the same for orphaned gates (no energy source). - Events: Linking emits a
GateLinkedEventand unlinking emits aGateUnlinkedEvent, each containing the IDs and keys of both gates. These events enable off-chain indexers to track the gate network topology in real time. - Energy Integration: A gate cannot go online unless its connected
NetworkNodehas reserved energy for it. If a network node is updated or unanchored, the system uses a “Hot Potato” pattern (e.g.,UpdateEnergySources) to ensure all connected gates are updated atomically in the same transaction block.
3. The Moddability Pattern: Type-Based Authorization
The true power of Frontier lies in Moddability. Owners can define custom jump rules through extension contracts using the Typed Witness Pattern.
Authorization Flow
- Extension Development: A developer deploys a contract defining a witness type (e.g.,
XAuth). - Registration: The gate owner calls
authorize_extension<XAuth>, adding theTypeNameto the gate’sextensionfield. This emits anExtensionAuthorizedEventcontaining the gate ID, the new extension type, the previous extension (if any), and the owner cap ID. - Enforcement: Once an extension is configured, the standard
jumpfunction will abort. Travelers (via the game client) must usejump_with_permit.
Owners can permanently lock this extension choice with freeze_extension_config(). That one-way action requires an extension to already be configured and prevents any later replacement, which lets players inspect a gate and know its extension policy cannot be swapped after deployment.
graph TD
A[User wants to Jump] --> B{Extension Configured?}
B -- No --> C[Call jump]
C --> D[Check Online & Linked]
D --> E((Success))
B -- Yes --> F[Call jump_with_permit]
F --> G[Check Online & Linked]
G --> H[Validate JumpPermit]
H --> I[Check Auth Witness Type]
I --> J[Check Expiry & Route Hash]
J --> K[Delete Permit]
K --> E
3.1 Freezing Extension Configuration
Once a gate owner has chosen an extension, they can call freeze_extension_config() to make that configuration immutable. The function aborts if no extension has been configured yet, and it also aborts if the gate was already frozen. In practice, this gives builders a way to publish a gate whose access-control logic cannot be changed later.
3.2 Revoking Extension Authorization
Before freeze_extension_config is called, the owner may call revoke_extension_authorization to clear the gate’s configured witness type and restore default gate behavior. The call requires the matching OwnerCap and emits ExtensionRevokedEvent; it aborts if no extension is configured or if configuration is frozen.
4. Logic Deep Dive: Jumps and Permits
There are two primary ways to traverse a gate:
A. Default Jump
Allowed only when no extension logic is configured. It validates that both gates are online and linked before emitting a JumpEvent. Requires AdminACL sponsor verification.
B. Jump with Permit
Required when an extension is authorized. The extension logic (Layer 3) issues a JumpPermit object to the player. Also requires AdminACL sponsor verification.
- Route Hashing: Permits are bound to a specific source/destination pair via a
route_hash. - Direction Agnostic: The hash is computed from concatenated IDs (A+B) using
blake2b256, ensuring one permit works for both A→B and B→A. - Single-Use: The
JumpPermitobject is deleted upon a successful jump to prevent replay attacks. - Issuance IDs and events:
issue_jump_permit_with_idreturns the newly created permit ID, whileissue_jump_permitremains available for callers that do not need it. Both issue paths emitJumpPermitIssuedEvent, including the route, character, expiry, and extension type.
4.1 Example: Tribe-Gated Extension
To create a restricted gate, a developer must deploy a smart contract that defines the access logic. The following example demonstrates a “Tribe Gate” that only allows members of a specific tribe to pass.
The Extension Module
This logic enforces that only the extension contract can create a valid JumpPermit for a gate configured with TribeAuth. The standard gate::jump function will fail because the gate expects a permit, and the only way to get that permit is to pass the character.tribe() == gate_rules.tribe check.
5. Developer’s Toolkit: Bulk Queries and Discovery
External tools (like route planners) can interact with this system by querying Sui’s shared objects and indexed events.
Building a Route Graph
To map the traversable network, a developer should query for Gate objects and filter by:
status.is_online(): Only active gates can be used.linked_gate_id: This defines the edge in the graph.extension: If aTypeNameis present, the edge has restricted access.
Identifying Traversable Paths for Players
A planner determines if a restricted gate is “open” for a specific player by querying the player’s address for JumpPermit objects:
- Query Objects: Call
suix_getOwnedObjectsfor typeworld::gate::JumpPermit. - Validate Metadata:
- Character ID:
permit.character_idmust match the player’sCharacterID. - Route Hash: Match against the hash of the intended source and destination.
- Expiry:
permit.expires_at_timestamp_msmust be greater than the currentClocktime.
- Character ID:
6. Security and Obfuscation
To support “fog of war” mechanics, Frontier stores locations as cryptographic hashes. This allows for the verification of proximity without revealing exact coordinates on-chain. developers must use the verify_distance function within the world::location primitive to prove that two entities are legally interacting based on their private coordinates.
6.1 Events
The Gate module emits the following events for off-chain indexing and tracking:
| Event | Fields | Emitted When |
|---|---|---|
GateCreatedEvent |
assembly_id, assembly_key, owner_cap_id, type_id, location_hash, status |
A new gate is anchored. |
GateLinkedEvent |
source_gate_id, source_gate_key, destination_gate_id, destination_gate_key |
Two gates are linked via link_gates. |
GateUnlinkedEvent |
source_gate_id, source_gate_key, destination_gate_id, destination_gate_key |
Two gates are unlinked via unlink_gates or unlink_gates_by_admin. |
JumpEvent |
source_gate_id, source_gate_key, destination_gate_id, destination_gate_key, character_id, character_key |
A character jumps through a gate (default or with permit). |
ExtensionAuthorizedEvent |
assembly_id, assembly_key, extension_type, previous_extension, owner_cap_id |
An extension is authorized (or replaced) on a gate via authorize_extension. |
ExtensionRevokedEvent |
assembly_id, assembly_key, revoked_extension, owner_cap_id |
An owner clears an unfrozen extension authorization. |
JumpPermitIssuedEvent |
jump_permit_id, source/destination gate IDs and keys, character ID/key, route_hash, expiry, extension_type |
A permit is minted by either permit-issuance function. |
Metadata Updates
Gate owners can update their gate’s metadata (name, description, URL) using the following functions, each requiring a valid OwnerCap<Gate>:
update_metadata_name— Updates the gate’s display name.update_metadata_description— Updates the gate’s description.update_metadata_url— Updates the gate’s URL.
These functions assert that metadata has been set on the gate (EMetadataNotSet) before performing the update.
7. Developer’s Implementation Guide: TypeScript/JavaScript
Interacting with Gates requires a mix of standard Sui SDK patterns and Frontier-specific utilities for managing game state and character identity.
1. Environment Initialization
Before interacting with the world, developers must initialize a context that includes the SuiClient, the user’s Keypair, and the Frontier network configuration.
2. Addressing Objects: Deterministic Derivation
EVE Frontier uses a deterministic registry system to manage object IDs. Instead of hardcoding hex strings, developers should derive object IDs using the ObjectRegistry ID and the in-game ITEM_ID.
3. Pattern: Borrow, Use, Return (OwnerCaps)
Most Gate operations (linking, going online) require an OwnerCap. In Frontier, these are typically stored within the player’s Character object. Developers must use a “Borrow/Return” pattern within a single transaction block to authenticate.
4. Executing a Jump Transaction
When a user performs a jump, the client must construct the transaction based on whether an extension is active.
Standard Jump (Public)
Jump with Permit (Restricted)
For restricted gates, the developer must first fetch the JumpPermit object from the user’s inventory and pass it as an argument.
5. Sponsored Transactions
Frontier supports sponsored transactions, allowing admins to cover gas costs for players. This requires collecting signatures from both the player and the sponsor before execution.
Conclusion
The Smart Gate system represents a paradigm shift in game infrastructure. By separating core physics from player-defined rules, Frontier creates a living, programmable world. Whether building a simple transport route or a complex, tribe-restricted toll network, developers have the tools to define the very horizon of the EVE Frontier.
By combining the Typed Witness Pattern for logic with the Borrow/Return pattern for authentication, EVE Frontier provides developers with a robust framework for building complex space infrastructure. These TypeScript patterns allow your applications to navigate the “digital physics” of the world while maintaining strict security and character-based identity.