Skip to content

Commit

Permalink
Chore: restore commits (#36)
Browse files Browse the repository at this point in the history
* PR for issues #13, #14, #15, #16, #17 (#22)

* added revive and play again buttons

* feat: upgrade foundry

* feat: create tool-versions

* fix: clean tree

* feat: first batch of tests

* fix: clean tree

* fix: hardcode round cards tests

* feat: basic contract features

* feat: add CI

* feat: admin must also be a player

* fix: redundancy

* feat: check if already joined

---------

Co-authored-by: PeterOche <petergoddey08@gmail.com>
Co-authored-by: Xaxxoo <51526246+Xaxxoo@users.noreply.github.com>

* fix workflow

---------

Co-authored-by: Teddy Not Bear <106410805+TeddyNotBear@users.noreply.github.com>
Co-authored-by: PeterOche <petergoddey08@gmail.com>
Co-authored-by: Xaxxoo <51526246+Xaxxoo@users.noreply.github.com>
Co-authored-by: PeterOche <119618121+PeterOche@users.noreply.github.com>
  • Loading branch information
5 people authored Jan 17, 2025
1 parent 471368b commit a610312
Show file tree
Hide file tree
Showing 11 changed files with 520 additions and 133 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/cairo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: LyricsFlip Contracts

on:
workflow_dispatch:
push:
branches:
- main
pull_request:
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: asdf-vm/actions/install@v3
- run: scarb fmt --check
working-directory: contracts
- run: scarb build
working-directory: contracts

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: asdf-vm/actions/install@v3
- run: snforge test
working-directory: contracts
2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
starknet-foundry 0.31.0
scarb 2.8.4
8 changes: 4 additions & 4 deletions contracts/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ dependencies = [

[[package]]
name = "snforge_scarb_plugin"
version = "0.1.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496"
version = "0.31.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.31.0#72ea785ca354e9e506de3e5d687da9fb2c1b3c67"

[[package]]
name = "snforge_std"
version = "0.30.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496"
version = "0.31.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.31.0#72ea785ca354e9e506de3e5d687da9fb2c1b3c67"
dependencies = [
"snforge_scarb_plugin",
]
5 changes: 4 additions & 1 deletion contracts/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ edition = "2023_11"
starknet = "2.8.4"

[dev-dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.30.0" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.31.0" }

[[target.starknet-contract]]
sierra = true

[scripts]
test = "snforge test"

[tool.fmt]
sort-module-level-items = true
209 changes: 209 additions & 0 deletions contracts/src/contracts/lyricsflip.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#[starknet::contract]
pub mod LyricsFlip {
use core::traits::Into;
use lyricsflip::interfaces::lyricsflip::{ILyricsFlip};
use lyricsflip::utils::types::{Card, Genre, Round};
use starknet::storage::{
StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map, Vec,
MutableVecTrait, VecTrait
};
use starknet::{get_caller_address, get_block_timestamp, ContractAddress};

pub mod Errors {
pub const NON_EXISTING_ROUND: felt252 = 'Round does not exists';
pub const NOT_ROUND_ADMIN: felt252 = 'Only round admin can start';
pub const ROUND_ALREADY_STARTED: felt252 = 'Round already started';
pub const NON_EXISTING_GENRE: felt252 = 'Genre does not exists';
pub const ROUND_ALREADY_JOINED: felt252 = 'You are already a player';
}

#[storage]
struct Storage {
round_count: u64,
card_count: u64,
cards_per_round: u8,
cards: Map<u64, Card>,
rounds: Map<u64, Round>, // round_id -> Round
round_owner: Map<ContractAddress, Round>,
round_players: Map<u64, Map<u256, ContractAddress>>,
round_players_count: Map<u64, u256>,
round_cards: Map<u64, Vec<u64>>, // round_id -> vec<card_ids>
}


#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {
RoundCreated: RoundCreated,
RoundStarted: RoundStarted,
RoundJoined: RoundJoined,
}

#[derive(Drop, starknet::Event)]
pub struct RoundCreated {
#[key]
pub round_id: u64,
#[key]
pub admin: ContractAddress,
pub created_time: u64,
}

#[derive(Drop, starknet::Event)]
pub struct RoundStarted {
#[key]
pub round_id: u64,
#[key]
pub admin: ContractAddress,
pub start_time: u64,
}

#[derive(Drop, starknet::Event)]
pub struct RoundJoined {
#[key]
pub round_id: u64,
#[key]
pub player: ContractAddress,
pub joined_time: u64,
}

#[constructor]
fn constructor(ref self: ContractState) {}

#[abi(embed_v0)]
pub impl LyricsFlipImpl of ILyricsFlip<ContractState> {
fn get_round(self: @ContractState, round_id: u64) -> Round {
self.rounds.entry(round_id).read()
}

fn get_round_cards(self: @ContractState, round_id: u64) -> Span<u64> {
let round_card = self.round_cards.entry(round_id);

let mut round_cards = array![];
for i in 0..round_card.len() {
round_cards.append(round_card.at(i).read());
};
round_cards.span()
}

fn get_round_players(self: @ContractState, round_id: u64) -> Span<ContractAddress> {
let round_players_count = self.round_players_count.entry(round_id).read();
let mut round_players = array![];
let mut idx = 0;
while (idx < round_players_count) {
round_players.append(self.round_players.entry(round_id).entry(idx).read());
idx += 1;
};
round_players.span()
}

fn get_players_round_count(self: @ContractState, round_id: u64) -> u256 {
self.round_players_count.entry(round_id).read()
}

fn is_round_player(
self: @ContractState, round_id: u64, player_address: ContractAddress
) -> bool {
let round_players = self.get_round_players(round_id);
let mut is_player = false;
let mut idx = 0;
while (idx < round_players.len()) {
if *round_players.at(idx) == player_address {
is_player = true;
break;
}
idx += 1;
};
is_player
}

fn create_round(ref self: ContractState, genre: Option<Genre>) -> u64 {
assert(genre.is_some(), Errors::NON_EXISTING_GENRE);

let caller_address = get_caller_address();
let cards = self.get_random_cards();

let round_id = self.round_count.read() + 1;
let round = Round {
round_id,
admin: caller_address,
genre: genre.unwrap(),
wager_amount: 0, // TODO
start_time: 0,
is_started: false,
end_time: 0, //TODO
};

let round_players_count = self.round_players_count.entry(round_id).read();
self.round_players.entry(round_id).entry(round_players_count).write(caller_address);
self.round_players_count.entry(round_id).write(round_players_count + 1);
self.rounds.entry(round_id).write(round);

for i in 0
..cards.len() {
self.round_cards.entry(round_id).append().write(*cards.at(i))
};

self
.emit(
Event::RoundCreated(
RoundCreated {
round_id, admin: caller_address, created_time: get_block_timestamp()
}
)
);

round_id
}

fn start_round(ref self: ContractState, round_id: u64) {
assert(self.rounds.entry(round_id).round_id.read() != 0, Errors::NON_EXISTING_ROUND);

let caller_address = get_caller_address();
let round = self.rounds.entry(round_id);

assert(round.admin.read() == caller_address, Errors::NOT_ROUND_ADMIN);

let start_time = get_block_timestamp();
round.start_time.write(start_time);
round.is_started.write(true);

self
.emit(
Event::RoundStarted(
RoundStarted { round_id, admin: round.admin.read(), start_time: start_time }
)
);
}

fn join_round(ref self: ContractState, round_id: u64) {
let caller_address = get_caller_address();
assert(self.rounds.entry(round_id).round_id.read() != 0, Errors::NON_EXISTING_ROUND);
assert(!self.is_round_player(round_id, caller_address), Errors::ROUND_ALREADY_JOINED);

let round = self.rounds.entry(round_id);

assert(!round.is_started.read(), Errors::ROUND_ALREADY_STARTED);

let round_players_count = self.round_players_count.entry(round_id).read();
self.round_players.entry(round_id).entry(round_players_count).write(caller_address);
self.round_players_count.entry(round_id).write(round_players_count + 1);

self
.emit(
Event::RoundJoined(
RoundJoined {
round_id, player: caller_address, joined_time: get_block_timestamp()
}
)
);
}
}

#[generate_trait]
impl InternalFunctions of InternalFunctionsTrait {
//TODO
fn get_random_cards(ref self: ContractState) -> Span<u64> {
array![1, 2].span()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use lyricsflip::types::{Genre, Round};
use lyricsflip::utils::types::{Genre, Round};
use starknet::ContractAddress;

#[starknet::interface]
pub trait ILyricsFlip<TContractState> {
fn get_round(self: @TContractState, round_id: u64) -> Round;
fn get_round_cards(self: @TContractState, round_id: u64) -> Span<u64>;
fn get_round_players(self: @TContractState, round_id: u64) -> Span<ContractAddress>;
fn get_players_round_count(self: @TContractState, round_id: u64) -> u256;
fn is_round_player(
self: @TContractState, round_id: u64, player_address: ContractAddress
) -> bool;

fn create_round(ref self: TContractState, genre: Option<Genre>) -> u64;
fn start_round(ref self: TContractState, round_id: u64);
fn join_round(ref self: TContractState, round_id: u64);

fn get_round_cards(self: @TContractState, round_id: u64) -> Span<u64>;
fn get_round(self: @TContractState, round_id: u64) -> Round;
}
19 changes: 16 additions & 3 deletions contracts/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
pub mod interfaces;
pub mod lyricsflip;
pub mod types;
pub mod interfaces {
pub mod lyricsflip;
}

pub mod contracts {
pub mod lyricsflip;
}

pub mod utils {
pub mod types;
}

#[cfg(test)]
mod tests {
mod test_lyricsflip;
}
80 changes: 0 additions & 80 deletions contracts/src/lyricsflip.cairo

This file was deleted.

Loading

0 comments on commit a610312

Please sign in to comment.