Trade Contracts¶
Trade contracts let players (and NPCs) commit to deliveries with deadlines and rewards. They are distinct from faction missions: missions are reputation-driven offers from a faction; contracts are pure economic exchange between two parties (NPC-to-player or player-to-player).
π Design-only β no Contract model, service, or routes are committed yet. This page is the target spec.
Overview¶
Two contract directions:
| Direction | Issuer | Browsed at |
|---|---|---|
| NPC-to-player | A station, corporation, or colony NPC | The station's contract board |
| Player-to-player | Any player who posts an offer | One or more chosen stations' boards |
Both directions share the same lifecycle, payment model, and dispute rules. Differences live in how the contract is generated and who pays the penalty on failure.
A Contract row carries:
id, issuer_type (npc|player), issuer_id,
contract_type (cargo_delivery, bulk_procurement, express_delivery,
hazardous_transport, refugee_transport, acquisition_bounty,
escort),
origin_station_id, destination_station_id,
commodity_type, quantity,
payment, penalty, reputation_reward, reputation_penalty,
deadline, posted_at, accepted_at, completed_at,
status (posted, accepted, in_transit, completed, failed, cancelled),
acceptor_player_id, insurance_premium, insurance_paid,
faction_id -- for NPC contracts: which faction's standing is affected
Contract boards¶
π Each station exposes a contract board β a per-station list of currently-posted contracts. A board is the union of:
- NPC contracts spawned by the generator at this station.
- Player-posted contracts whose
posting_stationsset includes this station. - Bounty-style acquisition contracts where this station is the destination.
Boards refresh on the same tick cadence as market prices (see trading.md Β§ Pricing). Players see only contracts they're eligible for: faction-gated NPC contracts hide below the minimum reputation threshold; player contracts hide for parties on the issuer's blocklist.
A station's board capacity is bounded β a Class-0 trade hub posts more contracts than a Class-8 black hole. The generator fills up to capacity on each tick, biased toward contract types that match the station's class trading pattern. (Station classes.)
NPC-issued contracts¶
π NPC contracts spawn dynamically on each station's contract board (Station.contract_board). The generator (contract_generator.py) seeds new entries on a tick and prunes expired ones. Generator inputs:
- Station class and current commodity surplus / deficit.
- Faction control of the surrounding region.
- Time of day in the game world (express-delivery rates spike during high-traffic windows).
- Active galaxy-wide events (war, plague, blockade) that modulate refugee and hazardous demand.
Categories:
Cargo delivery¶
Pick up commodity X at station A, deliver to station B by time T. Payment on delivery. Cargo is reserved at the origin: accepting the contract grants the player a one-time pickup right at a fixed price (often free or below-market).
Bulk procurement¶
Gather N units of a commodity from anywhere and deliver to one station. No fixed origin β the player sources however they like. Payment is per-unit on delivery; partial deliveries credit pro-rata up to the deadline.
Express delivery¶
High-priority cargo with a tight deadline. Payment is higher than standard cargo delivery, plus an early-arrival bonus (see Rewards). Express contracts use a stricter penalty on failure.
Hazardous transport¶
Illegal or contraband cargo routed via black-market channels. Issued by criminal NPCs at black-market terminals. See black-market.md for the goods list and detection mechanics. Hazardous transport pays significantly more, applies a faction penalty if completed, and exposes the carrier to scans during transit.
Refugee transport¶
Move colonists from one region to another. Interregional only β single-region jobs use the standard colonist trade flow described in planets/colonization.md. Refugee contracts are gated behind a passenger-rated ship and pay per surviving colonist on arrival.
Player-issued contracts¶
π Players post offers visible at one or more stations they control or have docking rights at. The poster pays the contract value into escrow at posting time.
Delivery contract¶
The player has cargo they need moved to a destination they can't easily reach. The player nominates origin, destination, commodity, quantity, deadline, and offered payment. Other players accept and execute the run.
Acquisition bounty¶
The player offers credits for any cargo of type X delivered to port Y by the deadline. Multiple acceptors can fulfill partial quantities until the bounty is met or the deadline lapses.
Escort contract¶
The player pays another player to fly with them through a sequence of sectors (combat support during traversal). Escort contracts complete when the protected player arrives at the destination intact, or when a defined number of hostile encounters are survived. Cross-link: ships.md.
Escrow handling¶
π Player-issued contracts use server-held escrow:
- At posting time, the issuer's account is debited by
payment + insurance_pool_reserve. The funds are held by the contract row, not in the issuer's wallet. - On
completed, escrow pays the acceptor. - On
failed, escrow is split per the failure rule: penalty fraction returns to the issuer (compensation), the rest is forfeit to a sink. - On
cancelledbefore acceptance, escrow returns to the issuer minus a small posting fee.
Escrow is never directly transferable between players β all settlement runs through the contract.
Contract lifecycle¶
| Status | Trigger | Effect |
|---|---|---|
| posted | Issuer creates the contract | Visible on contract board(s); awaiting acceptance |
| accepted | A player accepts | Acceptance fee charged; cargo (if delivery) reserved at origin; clock starts |
| in_transit | Cargo loaded into the acceptor's ship | Deadline timer running; player carries the load |
| completed | Cargo delivered at destination station before deadline | Payment + reputation reward issued; insurance refunded if held |
| failed | Deadline expires or cargo lost in transit | Penalty applied; reputation penalty; escrow paid to issuer |
| cancelled | Cancellation before acceptance, or by mutual agreement after | Partial penalty (kill-fee) β see Anti-griefing |
Status transitions are one-way except posted β cancelled. Once accepted, the only exits are completed, failed, or cancelled (with kill-fee).
posted ββacceptβββΆ accepted ββloadβββΆ in_transit ββdeliverβββΆ completed
β β β
β β βββdeadline_expiredβββΆ failed
β β βββcargo_destroyedββββΆ failed
β βββmutual cancelβββΆ cancelled (kill-fee)
βββissuer withdrawβββΆ cancelled (no fee)
API surface¶
π Target endpoints under /api/v1/contracts/:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/contracts/board?station_id=... |
List contracts visible at a station |
GET |
/api/v1/contracts/mine |
List the caller's posted + accepted contracts |
GET |
/api/v1/contracts/{id} |
Detail for a single contract |
POST |
/api/v1/contracts |
Post a new player-issued contract (escrow check) |
POST |
/api/v1/contracts/{id}/accept |
Accept a posted contract (charges acceptance fee) |
POST |
/api/v1/contracts/{id}/insure |
Buy insurance on an accepted contract |
POST |
/api/v1/contracts/{id}/complete |
Mark delivered (server verifies cargo at destination) |
POST |
/api/v1/contracts/{id}/cancel |
Cancel β kill-fee applied per state |
POST |
/api/v1/contracts/{id}/dispute |
File a dispute on a failed contract |
WebSocket events fire on every status transition for the issuer, acceptor, and any subscribed faction-management clients.
Rewards¶
Base payment is a function of:
payment = base_rate
Γ commodity_value(commodity_type, quantity)
Γ distance_factor(origin, destination)
Γ urgency_factor(deadline_tightness)
Γ contract_type_multiplier
commodity_value derives from the live midpoint price (see trading.md Β§ Pricing). distance_factor uses warp-jump count between origin and destination. urgency_factor rises as deadline tightness increases (express deliveries pay roughly 1.5β2.0Γ their non-express equivalents).
Bonuses¶
- Early-completion bonus β up to +25% of payment if delivered with greater than 50% of the time window remaining. Linear scale between 0β25% above the 50% threshold.
- Reputation reward β completion grants reputation with the issuing faction (NPC contracts) or a small mutual reputation bump between poster and acceptor (player contracts).
- Insurance refund β if the player paid an insurance premium and completed cleanly, the unused premium is not refunded β see Risk & insurance for why.
Penalties¶
On failure (deadline expired or cargo lost):
- Forfeit reserved cargo (if a delivery contract).
- Reputation penalty with the issuing faction (NPC) or the posting player.
- Cooldown on contract eligibility from that issuer (default 24 game-hours).
- Acceptance fee is not refunded.
- Penalty credits are debited from the acceptor's account; if insufficient, the deficit is recorded as a debt that must be cleared before posting new contracts.
Worked example¶
π A Class-2 station posts a cargo_delivery for 150 units of organics to a Class-3 station 8 jumps away, deadline 90 minutes:
base_rate = 1.0
commodity_value = 150 Γ midpoint(organics) β 150 Γ 16.5 = 2,475 cr
distance_factor = 1.0 + 0.05 Γ 8 = 1.40
urgency_factor (90 min) = 1.10
contract_type_multiplier = 1.0 (standard cargo_delivery)
payment β 2,475 Γ 1.40 Γ 1.10 β 3,810 cr
acceptance_fee β 76 cr (2%, refundable)
early-completion bonus cap β +953 cr (25%) if delivered with > 45 min left
penalty on failure = forfeit reserved cargo + 1Γ payment debit
Numbers are illustrative; the actual coefficients live in contract_service.py config.
Risk & insurance¶
π Optional contract insurance is a per-contract add-on, purchased at acceptance time:
| Coverage tier | Premium | Covers |
|---|---|---|
| Basic | 5% of contract value | Ship loss in low-security space during in-transit |
| Standard | 10% | Ship loss anywhere + 50% cargo replacement |
| Hazard | 15% | Ship loss anywhere + 100% cargo replacement + extended deadline grace |
If the insured ship is destroyed during in_transit, the policy pays out the contract penalty for the player, less a deductible. Insurance vs deductible model parallels the ship insurance system. Insurance does not cover wilful abandonment, deadline-only failures (the cargo arrived but late), or smuggling losses on hazardous-transport contracts.
Reputation effects¶
Completing NPC contracts boosts faction standing with the issuing faction. Failing damages it. The reward/penalty values are stored on the contract row at posting time, so they're stable across the lifecycle even if the faction's general standing thresholds shift.
Persistent failure β 3 or more failures in a row with the same faction β bans the player from accepting that faction's contracts for a cooldown (default 7 game-days). The cooldown clears either by waiting it out or by completing a non-contract faction mission to repair standing.
Player-to-player contracts also feed a lightweight trader-reputation stat (separate from faction reputation). Persistent contract reliability on the trader side becomes a public visible badge on the player's profile.
Anti-griefing¶
π Rules to keep contracts from being weaponised:
- Contracts cannot be accepted from players the acceptor has active hostility with (negative direct-relationship reputation between the two parties).
- An acceptance fee (small, fixed percentage of contract value, default 2%) is charged at accept time and refunded on completion. This discourages frivolous picks that lock the contract for the deadline window without intent to complete.
- The issuer cannot cancel a contract after it has been accepted without paying a kill-fee equal to the acceptance fee plus 10% of the contract value, paid to the acceptor.
- A player cannot post a contract whose escrow they cannot afford. Escrow is held server-side at posting time.
- Contract boards rate-limit per-player postings to prevent spam (default 10 active postings per player per region).
Disputes¶
π If a player believes a contract was completed but the system marked it failed (e.g. the destination station went offline mid-delivery), the player can file a dispute within 48 game-hours of the failure timestamp. Disputes pause the penalty until resolved. Resolution is automated where possible:
- Cargo manifest evidence β server-side cargo log shows correct cargo arrived at destination β completion is honoured retroactively.
- Destination unreachable β if the destination station was destroyed or made inaccessible after acceptance, the contract is voided and the acceptance fee is refunded.
- Issuer abandoned the destination β counts as cancellation by the issuer, full kill-fee owed.
Unresolvable disputes escalate to admin review.
Black-market contracts¶
Hazardous-transport NPC contracts and certain illegal-goods player contracts route through the black-market system. They pay 2β4Γ standard rates, carry detection risk during transit, and apply a faction penalty on completion (the law-side faction loses standing). See black-market.md for the full mechanics, terminal locations, and detection model.
Source map¶
π None of the following exist yet β these are target paths for the implementation:
| Concern | Target path |
|---|---|
| Contract model | services/gameserver/src/models/contract.py |
| Contract service | services/gameserver/src/services/contract_service.py |
| Contract API routes | services/gameserver/src/api/routes/contracts.py |
| NPC contract generator | services/gameserver/src/services/contract_generator.py |
| Insurance hooks | extension to services/gameserver/src/services/insurance_service.py |
| Contract board UI | new admin/player-UI surface (TBD) |
Status¶
π Design-only. The entire trade-contract system is unimplemented. No Contract model, no contract service, no API routes, no UI. This spec defines the target shape; implementation order should be:
Contractmodel + database migration.- NPC
cargo_deliverygenerator (simplest type) β proves the lifecycle end-to-end. - API routes (
/api/v1/contracts/...) β list, accept, complete, abandon, post. - Player-issued posting flow + escrow handling.
- Remaining contract types (bulk, express, hazardous, refugee, escort, acquisition bounty).
- Insurance integration.
- Anti-griefing limits and reputation cooldowns.
Related¶
- ./trading.md β main trading flow; contract payments use the same pricing midpoints.
- ./black-market.md β illegal-goods contracts, detection model.
- ../gameplay/missions.md β distinct system: missions are faction-reputation driven, contracts are economic.
- ../gameplay/factions-and-teams.md β faction-issued contracts impact standing.
- ../gameplay/ships.md β escort contracts and ship-insurance overlap.