Skip to content

Commit c5d58bd

Browse files
Starknet Devclaude
andcommitted
refactor(prize)!: payout_prize_extension replaces claim_prize_extension
Mirrors the metagame-extensions trait refactor: extensions are now asset managers driven by the host. The host computes recipient (winner for normal payout, sponsor for refund) and tells the extension where to send via a single payout_prize call. No separate claim/refund methods on the host dispatcher either. Bumps metagame-extensions to dbe56fa. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 025f012 commit c5d58bd

4 files changed

Lines changed: 40 additions & 23 deletions

File tree

Scarb.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ openzeppelin_introspection = { git = "https://github.com/OpenZeppelin/cairo-cont
4141
openzeppelin_token = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v3.0.0" }
4242
openzeppelin_interfaces = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v3.0.0" }
4343
ekubo = { git = "https://github.com/EkuboProtocol/starknet-contracts.git", tag = "v4.0.1" }
44-
metagame_extensions_interfaces = { git = "https://github.com/Provable-Games/metagame_extensions.git", rev = "51ac398f2fb4a0fa30f3e601b0eb3f0daabd8994" }
44+
metagame_extensions_interfaces = { git = "https://github.com/Provable-Games/metagame_extensions.git", rev = "dbe56fa608fd9f37766758c9e21c37546fad1346" }
4545
alexandria_merkle_tree = { git = "https://github.com/keep-starknet-strange/alexandria.git", tag = "v0.9.0" }
4646

4747
[dependencies]

packages/metagame/src/prize/prize_component.cairo

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -433,25 +433,32 @@ pub mod PrizeComponent {
433433
dispatcher.add_prize(context_id, prize_id, ext.config);
434434
}
435435

436-
/// Forward a claim call to the prize extension configured for
436+
/// Forward a payout call to the prize extension configured for
437437
/// `(context_id, prize_id)`. Reverts if `prize_id` was added via
438-
/// the built-in `Prize::Config` path (no extension address
439-
/// stored). `claim_params` is opaque — the extension deserializes
440-
/// whatever shape it expects.
438+
/// the built-in `Prize::Token` path (no extension address
439+
/// stored).
440+
///
441+
/// The host (e.g. budokan) decides whether the payout is a winner
442+
/// distribution or a sponsor refund by picking the right
443+
/// `recipient`. The extension itself is a dumb asset manager —
444+
/// it just transfers the escrow at `(prize_id, position)` to
445+
/// `recipient`. Per-position payout dedupe lives on the
446+
/// extension, not the host.
441447
///
442448
/// Hosts are responsible for any cross-cutting concerns
443-
/// (finalization checks, reentrancy guards, double-claim
444-
/// protection on the host side) before invoking this.
445-
fn claim_prize_extension(
449+
/// (finalization checks, reentrancy guards) before invoking this.
450+
fn payout_prize_extension(
446451
ref self: ComponentState<TContractState>,
447452
context_id: u64,
448453
prize_id: u64,
449-
claim_params: Span<felt252>,
454+
position: u32,
455+
recipient: ContractAddress,
456+
payout_params: Span<felt252>,
450457
) {
451458
let extension_address = Store::get_extension_address(@self, context_id, prize_id);
452459
assert!(!extension_address.is_zero(), "Prize: No extension configured for prize");
453460
let dispatcher = IPrizeExtensionDispatcher { contract_address: extension_address };
454-
dispatcher.claim_prize(context_id, prize_id, claim_params);
461+
dispatcher.payout_prize(context_id, prize_id, position, recipient, payout_params);
455462
}
456463

457464
/// Payout full ERC20 amount to a recipient

packages/metagame/src/prize/tests/mocks/prize_mock.cairo

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,17 @@ pub mod PrizeMock {
139139
self.prize.get_extension_address(context_id, prize_id)
140140
}
141141

142-
/// Forward a claim to the prize extension for (context_id, prize_id).
142+
/// Forward a payout to the prize extension for (context_id, prize_id).
143143
#[external(v0)]
144-
fn claim_prize_extension(
145-
ref self: ContractState, context_id: u64, prize_id: u64, claim_params: Span<felt252>,
144+
fn payout_prize_extension(
145+
ref self: ContractState,
146+
context_id: u64,
147+
prize_id: u64,
148+
position: u32,
149+
recipient: starknet::ContractAddress,
150+
payout_params: Span<felt252>,
146151
) {
147-
self.prize.claim_prize_extension(context_id, prize_id, claim_params);
152+
self.prize.payout_prize_extension(context_id, prize_id, position, recipient, payout_params);
148153
}
149154

150155
/// Add a prize (delegates to component). Exposes the full Prize sum-type

packages/metagame/src/prize/tests/test_prize_store.cairo

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,13 @@ trait IPrizeMockFull<TContractState> {
3232
fn get_extension_address(
3333
self: @TContractState, context_id: u64, prize_id: u64,
3434
) -> ContractAddress;
35-
fn claim_prize_extension(
36-
ref self: TContractState, context_id: u64, prize_id: u64, claim_params: Span<felt252>,
35+
fn payout_prize_extension(
36+
ref self: TContractState,
37+
context_id: u64,
38+
prize_id: u64,
39+
position: u32,
40+
recipient: ContractAddress,
41+
payout_params: Span<felt252>,
3742
);
3843
fn add_prize(
3944
ref self: TContractState, context_id: u64, prize: crate::prize::structs::Prize,
@@ -226,11 +231,11 @@ fn test_extension_address_default_zero() {
226231
}
227232

228233
// ============================================================================
229-
// claim_prize_extension dispatch
234+
// payout_prize_extension dispatch
230235
// ============================================================================
231236

232237
#[test]
233-
fn test_claim_prize_extension_dispatches_when_configured() {
238+
fn test_payout_prize_extension_dispatches_when_configured() {
234239
let mock = deploy();
235240
let ext_addr = addr(0xE0E0E0);
236241

@@ -250,15 +255,15 @@ fn test_claim_prize_extension_dispatches_when_configured() {
250255
),
251256
);
252257

253-
// Mock the extension's claim entrypoint and verify the component
258+
// Mock the extension's payout entrypoint and verify the component
254259
// dispatches without panicking.
255-
mock_call(ext_addr, selector!("claim_prize"), (), 10);
256-
mock.claim_prize_extension(42, prize_id, array![0xBEEF].span());
260+
mock_call(ext_addr, selector!("payout_prize"), (), 10);
261+
mock.payout_prize_extension(42, prize_id, 1, addr(0xFEED), array![].span());
257262
}
258263

259264
#[test]
260265
#[should_panic(expected: "Prize: No extension configured for prize")]
261-
fn test_claim_prize_extension_panics_when_unset() {
266+
fn test_payout_prize_extension_panics_when_unset() {
262267
let mock = deploy();
263-
mock.claim_prize_extension(1, 1, array![].span());
268+
mock.payout_prize_extension(1, 1, 1, addr(0xFEED), array![].span());
264269
}

0 commit comments

Comments
 (0)