The contract has full storage plumbing for matches —
storage::set_match, storage::next_match_id, storage::add_event_match
(src/storage.rs) — and r#match::list_event_matches /
r#match::get_match_count to read them back (src/match.rs). The README's
usage example even calls client.create_match(...).
But there is no create_match function anywhere in the contract. Creators
currently have no way to add matches to their event. This is the single most
critical missing piece.
Goal
Add a create_match entrypoint that lets an event's creator add a football
match (team A vs team B, kickoff time) to their event.
Requirements
New function in src/match.rs:
pub fn create_match(
env: &Env,
caller: Address,
event_id: u64,
team_a: String,
team_b: String,
match_time: u64,
) -> Result<u64, MatchError>
New MatchError enum (mirror the style of EventError / OracleError):
Paused = 1 — contract is paused (admin::is_paused)
EventNotFound = 2
EventCancelled = 3
Unauthorized = 4 — caller != event.creator
InvalidTeamNames = 5 — empty, too long (MAX_TEAM_NAME_LEN), or team_a == team_b
InvalidMatchTime = 6 — match_time must be in the future (> env.ledger().timestamp()); if Issue 2 has landed, it must also fall within [event.start_time, event.end_time]
Flow:
caller.require_auth()
admin::ensure_not_paused check
Load the event via storage::get_event; verify it exists, is not cancelled
Verify caller == event.creator
Validate team names via Match::validate() (already exists) plus the
team_a == team_b check
Validate match_time
let match_id = storage::next_match_id(env);
Build via Match::new(match_id, event_id, team_a, team_b, match_time)
storage::set_match(env, match_id, &match)
storage::add_event_match(env, event_id, match_id)
event.add_match() (existing helper on Event) then storage::set_event
Emit (Symbol("match"), Symbol("created")) with
(match_id, event_id, team_a, team_b, match_time)
Return match_id
Expose on the contract in src/lib.rs:
pub fn create_match(
env: Env,
caller: Address,
event_id: u64,
team_a: String,
team_b: String,
match_time: u64,
) -> u64
mapping MatchError variants to panics following the existing
panic!("snake_case_reason") convention (e.g. "unauthorized",
"event_not_found", "invalid_team_names", "invalid_match_time").
Acceptance criteria
create_match is callable from CreatorEventManagerContractClient
Only event.creator can add matches to their event
event.match_count increments and EventMatches(event_id) index grows
list_event_matches returns the new match, sorted by match_time
All error paths above are covered and panic with the documented strings
Testing checklist (tests/match_tests.rs)
test_create_match_success — creator adds a match; get_match_count and
list_event_matches reflect it
test_create_match_unauthorized — a non-creator address gets "unauthorized"
test_create_match_event_not_found
test_create_match_event_cancelled
test_create_match_invalid_team_names — empty name, name > MAX_TEAM_NAME_LEN, team_a == team_b
test_create_match_past_time_rejected
test_create_multiple_matches_sorted_by_time — add 3 matches out of
chronological order, assert list_event_matches returns them sorted
The contract has full storage plumbing for matches —
storage::set_match, storage::next_match_id, storage::add_event_match
(src/storage.rs) — and r#match::list_event_matches /
r#match::get_match_count to read them back (src/match.rs). The README's
usage example even calls client.create_match(...).
But there is no create_match function anywhere in the contract. Creators
currently have no way to add matches to their event. This is the single most
critical missing piece.
Goal
Add a create_match entrypoint that lets an event's creator add a football
match (team A vs team B, kickoff time) to their event.
Requirements
New function in src/match.rs:
pub fn create_match(
env: &Env,
caller: Address,
event_id: u64,
team_a: String,
team_b: String,
match_time: u64,
) -> Result<u64, MatchError>
New MatchError enum (mirror the style of EventError / OracleError):
Paused = 1 — contract is paused (admin::is_paused)
EventNotFound = 2
EventCancelled = 3
Unauthorized = 4 — caller != event.creator
InvalidTeamNames = 5 — empty, too long (MAX_TEAM_NAME_LEN), or team_a == team_b
InvalidMatchTime = 6 — match_time must be in the future (> env.ledger().timestamp()); if Issue 2 has landed, it must also fall within [event.start_time, event.end_time]
Flow:
caller.require_auth()
admin::ensure_not_paused check
Load the event via storage::get_event; verify it exists, is not cancelled
Verify caller == event.creator
Validate team names via Match::validate() (already exists) plus the
team_a == team_b check
Validate match_time
let match_id = storage::next_match_id(env);
Build via Match::new(match_id, event_id, team_a, team_b, match_time)
storage::set_match(env, match_id, &match)
storage::add_event_match(env, event_id, match_id)
event.add_match() (existing helper on Event) then storage::set_event
Emit (Symbol("match"), Symbol("created")) with
(match_id, event_id, team_a, team_b, match_time)
Return match_id
Expose on the contract in src/lib.rs:
pub fn create_match(
env: Env,
caller: Address,
event_id: u64,
team_a: String,
team_b: String,
match_time: u64,
) -> u64
mapping MatchError variants to panics following the existing
panic!("snake_case_reason") convention (e.g. "unauthorized",
"event_not_found", "invalid_team_names", "invalid_match_time").
Acceptance criteria
create_match is callable from CreatorEventManagerContractClient
Only event.creator can add matches to their event
event.match_count increments and EventMatches(event_id) index grows
list_event_matches returns the new match, sorted by match_time
All error paths above are covered and panic with the documented strings
Testing checklist (tests/match_tests.rs)
test_create_match_success — creator adds a match; get_match_count and
list_event_matches reflect it
test_create_match_unauthorized — a non-creator address gets "unauthorized"
test_create_match_event_not_found
test_create_match_event_cancelled
test_create_match_invalid_team_names — empty name, name > MAX_TEAM_NAME_LEN, team_a == team_b
test_create_match_past_time_rejected
test_create_multiple_matches_sorted_by_time — add 3 matches out of
chronological order, assert list_event_matches returns them sorted