Skip to content

Commit

Permalink
feat: impl join_wager and get_wager_participants(#62)
Browse files Browse the repository at this point in the history
* implement join wager

* remove todo comment

* add test test_join_wager_success

* add test_join_wager_resolved

* add test_join_wager_insufficient_balance

* update panic message

* modify test and testUtils
  • Loading branch information
Hoossayn authored Feb 17, 2025
1 parent e535a6b commit 2eb01f8
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 30 deletions.
147 changes: 143 additions & 4 deletions contracts/src/tests/test_wager.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use starknet::ContractAddress;
use starknet::{testing, contract_address_const, get_caller_address};

use contracts::wager::wager::StrkWager;

use contracts::wager::types::{Category, Mode};
use contracts::wager::interface::{IStrkWagerDispatcher, IStrkWagerDispatcherTrait};
use contracts::escrow::interface::IEscrowDispatcherTrait;
use contracts::tests::utils::{
deploy_wager, create_wager, deploy_mock_erc20, deploy_escrow, OWNER, ADMIN
deploy_wager, create_wager, deploy_mock_erc20, deploy_escrow, OWNER, ADMIN, BOB
};
use openzeppelin::token::erc20::interface::IERC20DispatcherTrait;

Expand Down Expand Up @@ -98,14 +98,31 @@ fn test_get_escrow_address() {
#[test]
fn test_create_wager_success() {
let admin_address = ADMIN();
create_wager(3000, 2000, admin_address);
let (wager, wager_address) = deploy_wager(admin_address);
let (escrow, strk_dispatcher) = deploy_escrow(wager_address);
let mut spy = spy_events();

// Configure wager with escrow
start_cheat_caller_address(wager.contract_address, admin_address);
wager.set_escrow_address(escrow.contract_address);
stop_cheat_caller_address(wager.contract_address);

create_wager(wager, escrow, strk_dispatcher, 3000, 2000, admin_address);
}

#[test]
#[should_panic(expected: 'Insufficient balance')]
fn test_create_wager_insufficient_balance() {
let admin_address = ADMIN();
create_wager(2000, 2200, admin_address);
let (wager, wager_address) = deploy_wager(admin_address);
let (escrow, strk_dispatcher) = deploy_escrow(wager_address);
let mut spy = spy_events();

// Configure wager with escrow
start_cheat_caller_address(wager.contract_address, admin_address);
wager.set_escrow_address(escrow.contract_address);
stop_cheat_caller_address(wager.contract_address);
create_wager(wager, escrow, strk_dispatcher, 2000, 2200, admin_address);
}

#[test]
Expand Down Expand Up @@ -176,3 +193,125 @@ fn test_fund_wallet_without_approval() {
wager.fund_wallet(50_u256);
stop_cheat_caller_address(wager.contract_address);
}


#[test]
fn test_join_wager_success() {
let admin_address = ADMIN();
let (wager, wager_address) = deploy_wager(admin_address);
let (escrow, strk_dispatcher) = deploy_escrow(wager_address);
let mut spy = spy_events();

// Configure wager with escrow
start_cheat_caller_address(wager.contract_address, admin_address);
wager.set_escrow_address(escrow.contract_address);
stop_cheat_caller_address(wager.contract_address);

// Create a wager
let stake = 100_u256;
let wager_id = create_wager(wager, escrow, strk_dispatcher, stake, stake, admin_address);

// Approve tokens from OWNER for escrow
let owner = OWNER();
start_cheat_caller_address(strk_dispatcher.contract_address, owner);
strk_dispatcher.approve(escrow.contract_address, stake);
stop_cheat_caller_address(strk_dispatcher.contract_address);

// Fund the wallet of the participant
start_cheat_caller_address(wager.contract_address, owner);
wager.fund_wallet(stake);
stop_cheat_caller_address(wager.contract_address);

// Join the wager
start_cheat_caller_address(wager.contract_address, owner);
wager.join_wager(wager_id);
stop_cheat_caller_address(wager.contract_address);

let participants = wager.get_wager_participants(wager_id);
let mut found = false;
for participant_address in participants {
if participant_address == @owner {
found = true;
break;
}
};
assert!(found, "Participant should be added to the wager");

spy
.assert_emitted(
@array![
(
wager.contract_address,
StrkWager::Event::WagerJoined(
StrkWager::WagerJoinedEvent { wager_id, participant: owner }
)
)
]
);
}

#[test]
#[should_panic(expected: ('Insufficient balance',))]
fn test_join_wager_insufficient_balance() {
// Deploy contracts
let admin_address = ADMIN();
let (wager, wager_address) = deploy_wager(admin_address);
let (escrow, strk_dispatcher) = deploy_escrow(wager_address);
let bob = BOB();

// Configure wager with escrow
start_cheat_caller_address(wager.contract_address, admin_address);
wager.set_escrow_address(escrow.contract_address);
stop_cheat_caller_address(wager.contract_address);

// Create a wager
let stake = 100_u256;
let deposit = 20_u256; // Insufficient deposit
let wager_id = create_wager(wager, escrow, strk_dispatcher, stake, stake, admin_address);

// Mint tokens for BOB
start_cheat_caller_address(strk_dispatcher.contract_address, OWNER());
strk_dispatcher.transfer(bob, deposit);
stop_cheat_caller_address(strk_dispatcher.contract_address);

// BOB approves tokens
start_cheat_caller_address(strk_dispatcher.contract_address, bob);
strk_dispatcher.approve(escrow.contract_address, deposit);
stop_cheat_caller_address(strk_dispatcher.contract_address);

// Fund wallet with insufficient amount
start_cheat_caller_address(wager.contract_address, bob);
wager.fund_wallet(deposit);
stop_cheat_caller_address(wager.contract_address);

// Attempt to join the wager (should panic)
start_cheat_caller_address(wager.contract_address, bob);
wager.join_wager(wager_id);
stop_cheat_caller_address(wager.contract_address);
}


#[test]
#[should_panic(expected: ('Wager is already resolved',))]
fn test_join_wager_resolved() {
let admin_address = ADMIN();
let (wager, wager_address) = deploy_wager(admin_address);
let (escrow, strk_dispatcher) = deploy_escrow(wager_address);

// Configure wager with escrow
start_cheat_caller_address(wager.contract_address, admin_address);
wager.set_escrow_address(escrow.contract_address);
stop_cheat_caller_address(wager.contract_address);

// Create a wager
let stake = 100_u256;
let wager_id = create_wager(wager, escrow, strk_dispatcher, stake, stake, admin_address);

// Resolve the wager
let owner = OWNER();
wager.resolve_wager(wager_id, owner);

start_cheat_caller_address(wager.contract_address, owner);
wager.join_wager(wager_id);
stop_cheat_caller_address(wager.contract_address);
}
55 changes: 33 additions & 22 deletions contracts/src/tests/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -63,40 +63,51 @@ pub fn deploy_wager(admin_address: ContractAddress) -> (IStrkWagerDispatcher, Co
(dispatcher, contract_address)
}

pub fn create_wager(deposit: u256, stake: u256, admin_address: ContractAddress) {
let (wager, wager_contract) = deploy_wager(admin_address);
let (escrow, strk_dispatcher) = deploy_escrow(wager_contract);

pub fn create_wager(
wager: IStrkWagerDispatcher,
escrow: IEscrowDispatcher,
strk_dispatcher: IERC20Dispatcher,
deposit: u256,
stake: u256,
admin_address: ContractAddress,
) -> u64 {
let creator = OWNER();
let mut spy = spy_events();

start_cheat_caller_address(wager.contract_address, admin_address);
wager.set_escrow_address(escrow.contract_address);
stop_cheat_caller_address(wager.contract_address);

cheat_caller_address(strk_dispatcher.contract_address, creator, CheatSpan::TargetCalls(1));
// Approve and deposit into escrow for the creator
start_cheat_caller_address(strk_dispatcher.contract_address, creator);
strk_dispatcher.approve(escrow.contract_address, deposit);
stop_cheat_block_timestamp(strk_dispatcher.contract_address);
stop_cheat_caller_address(strk_dispatcher.contract_address);

start_cheat_caller_address(escrow.contract_address, wager_contract); // Simulate Wager Contract
// Simulate Wager Contract to deposit funds
start_cheat_caller_address(escrow.contract_address, wager.contract_address);
escrow.deposit_to_wallet(creator, deposit);
stop_cheat_caller_address(escrow.contract_address);

assert(strk_dispatcher.balance_of(escrow.contract_address) == deposit, 'wrong amount');

assert(escrow.get_balance(creator) == deposit, 'wrong balance');

// Create the wager
let title = "My Wager";
let terms = "My terms";
let category = Category::Sports;
let mode = Mode::HeadToHead;

println!("Creator's balance: {}", escrow.get_balance(creator));
println!("Creator's stake: {}", stake);

cheat_caller_address(wager_contract, creator, CheatSpan::TargetCalls(1));
start_cheat_caller_address(wager.contract_address, creator);
let wager_id = wager.create_wager(category, title.clone(), terms.clone(), stake, mode);
let expected_event = StrkWager::Event::WagerCreated(
StrkWager::WagerCreatedEvent { wager_id, category, title, terms, creator, stake, mode },
);
stop_cheat_caller_address(wager.contract_address);

spy.assert_emitted(@array![(wager_contract, expected_event)]);
spy
.assert_emitted(
@array![
(
wager.contract_address,
StrkWager::Event::WagerCreated(
StrkWager::WagerCreatedEvent {
wager_id, category, title, terms, creator, stake, mode,
}
)
)
]
);

wager_id
}
1 change: 1 addition & 0 deletions contracts/src/wager/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ pub trait IStrkWager<TContractState> {
fn get_wager_participants(self: @TContractState, wager_id: u64) -> Span<ContractAddress>;
fn set_escrow_address(ref self: TContractState, new_address: ContractAddress);
fn get_escrow_address(self: @TContractState) -> ContractAddress;
fn resolve_wager(ref self: TContractState, wager_id: u64, winner: ContractAddress);
}
48 changes: 44 additions & 4 deletions contracts/src/wager/wager.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub mod StrkWager {
pub enum Event {
EscrowAddressUpdated: EscrowAddressEvent,
WagerCreated: WagerCreatedEvent,
WagerJoined: WagerJoinedEvent,
#[flat]
AccessControlEvent: AccessControlComponent::Event,
#[flat]
Expand All @@ -67,6 +68,12 @@ pub mod StrkWager {
pub mode: Mode,
}

#[derive(Drop, starknet::Event)]
pub struct WagerJoinedEvent {
pub wager_id: u64,
pub participant: ContractAddress,
}

const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE"); // Unique identifier for the role


Expand Down Expand Up @@ -144,18 +151,41 @@ pub mod StrkWager {
wager_id
}

//TODO
fn join_wager(ref self: ContractState, wager_id: u64) {}

fn join_wager(ref self: ContractState, wager_id: u64) {
let wager = self.wagers.entry(wager_id).read();
assert(!wager.resolved, 'Wager is already resolved');

let caller = get_caller_address();
let caller_balance = self.get_balance(caller);
assert(caller_balance >= wager.stake, 'Insufficient balance');

let participant_id = self.wager_participants_count.entry(wager_id).read() + 1;
self.wager_participants.entry(wager_id).entry(participant_id).write(caller);
self.wager_participants_count.entry(wager_id).write(participant_id);

self.emit(WagerJoinedEvent { wager_id, participant: caller });
}

//TODO
fn get_wager(self: @ContractState, wager_id: u64) -> Wager {
// search the storage for the `wager_id`.
self.wagers.entry(wager_id).read()
}

//TODO

fn get_wager_participants(self: @ContractState, wager_id: u64) -> Span<ContractAddress> {
array![].span()
let participant_count = self.wager_participants_count.entry(wager_id).read();
let mut participants = array![];
let mut i = 1;

while i <= participant_count {
let participant = self.wager_participants.entry(wager_id).entry(i).read();
participants.append(participant);
i += 1;
};

participants.span()
}

fn get_escrow_address(self: @ContractState) -> ContractAddress {
Expand All @@ -170,5 +200,15 @@ pub mod StrkWager {

self.emit(EscrowAddressEvent { old_address: old_address, new_address: new_address });
}

fn resolve_wager(ref self: ContractState, wager_id: u64, winner: ContractAddress) {
let mut wager = self.wagers.entry(wager_id).read();
assert(!wager.resolved, 'Wager is already resolved');

wager.resolved = true;
wager.winner = winner;

self.wagers.entry(wager_id).write(wager);
}
}
}

0 comments on commit 2eb01f8

Please sign in to comment.