-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a88c44b
commit 226060c
Showing
12 changed files
with
10,889 additions
and
0 deletions.
There are no files selected for viewing
3,405 changes: 3,405 additions & 0 deletions
3,405
HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/Cargo.lock
Large diffs are not rendered by default.
Oops, something went wrong.
23 changes: 23 additions & 0 deletions
23
HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "halborn-near-ctf-associated-contract" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
[lib] | ||
crate-type = ["cdylib", "rlib"] | ||
|
||
[dependencies] | ||
near-sdk = "3.1.0" | ||
near-contract-standards = "3.1.0" | ||
|
||
[dev-dependencies] | ||
near-sdk-sim = "3.2.0" | ||
|
||
[profile.release] | ||
codegen-units = 1 | ||
opt-level = "z" | ||
lto = true | ||
debug = false | ||
panic = "abort" | ||
overflow-checks = true |
7 changes: 7 additions & 0 deletions
7
HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/deployer.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/bash | ||
|
||
rm -rf ./neardev | ||
|
||
CTF_ASSOCIATED_CONTRACT=$(near dev-deploy --wasmFile target/wasm32-unknown-unknown/release/halborn_near_ctf_associated_contract.wasm --initFunction new --initArgs '{"owner_id": "TODO"}' | sed -n '5,1p' | grep -o -E "dev-\d+-\d+") | ||
|
||
echo "CTF contract deployed to: $CTF_ASSOCIATED_CONTRACT" |
243 changes: 243 additions & 0 deletions
243
HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; | ||
use near_sdk::collections::{LookupMap, LookupSet}; | ||
use near_sdk::json_types::U64; | ||
use near_sdk::serde::{Deserialize, Serialize}; | ||
use near_sdk::{env, log, near_bindgen, AccountId, PanicOnDefault}; | ||
|
||
mod storage; | ||
|
||
use storage::StorageKey; | ||
|
||
#[derive( | ||
BorshDeserialize, BorshSerialize, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize, | ||
)] | ||
#[serde(crate = "near_sdk::serde")] | ||
pub enum ContractStatus { | ||
Working, | ||
Paused, | ||
} | ||
|
||
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize, Clone, Eq, PartialEq)] | ||
#[serde(crate = "near_sdk::serde")] | ||
pub struct Event { | ||
created_timestamp: u64, | ||
is_live: bool, | ||
title: Option<String>, | ||
} | ||
|
||
impl std::fmt::Display for ContractStatus { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
ContractStatus::Working => write!(f, "working"), | ||
ContractStatus::Paused => write!(f, "paused"), | ||
} | ||
} | ||
} | ||
|
||
type RegisteredUsers = LookupSet<AccountId>; | ||
|
||
#[near_bindgen] | ||
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)] | ||
pub struct AssociatedContract { | ||
privileged_clubs: LookupSet<AccountId>, | ||
events: LookupMap<U64, Event>, | ||
event_to_registered_users: LookupMap<U64, RegisteredUsers>, | ||
owner_id: AccountId, | ||
next_event_idx: u16, | ||
status: ContractStatus, | ||
} | ||
|
||
#[near_bindgen] | ||
impl AssociatedContract { | ||
#[init] | ||
pub fn new(owner_id: AccountId) -> Self { | ||
Self { | ||
privileged_clubs: LookupSet::new(StorageKey::PrivilegedClubs.into_bytes()), | ||
events: LookupMap::new(StorageKey::EventsOnline.into_bytes()), | ||
event_to_registered_users: LookupMap::new( | ||
StorageKey::EventToRegisteredUsers.into_bytes(), | ||
), | ||
owner_id: owner_id, | ||
next_event_idx: 1, | ||
status: ContractStatus::Working, | ||
} | ||
} | ||
|
||
pub fn get_next_event_idx(&self) -> u16 { | ||
self.next_event_idx | ||
} | ||
|
||
pub fn get_event(&self, event_idx: U64) -> Event { | ||
self.events.get(&event_idx).unwrap() | ||
} | ||
|
||
// Adds new event. Adds new event's id to LookupSet and creates a LookupMap | ||
// for checking which user registered for that event. Anyone can add an event. | ||
pub fn add_new_event(&mut self, event_title: String) -> u16 { | ||
let new_event = Event { | ||
created_timestamp: env::block_timestamp(), | ||
is_live: true, | ||
title: Some(event_title), | ||
}; | ||
self.events | ||
.insert(&U64::from(u64::from(self.next_event_idx)), &new_event); | ||
|
||
let new_ev_to_registered_users: RegisteredUsers = | ||
LookupSet::new(StorageKey::RegisteredUsers(self.next_event_idx).into_bytes()); | ||
|
||
self.event_to_registered_users.insert( | ||
&U64::from(u64::from(self.next_event_idx)), | ||
&new_ev_to_registered_users, | ||
); | ||
let created_event_idx = self.next_event_idx; | ||
self.next_event_idx += 1; | ||
created_event_idx | ||
} | ||
|
||
pub fn remove_event(&mut self, event_id: U64) { | ||
self.only_owner(); | ||
self.events.remove(&event_id); | ||
self.event_to_registered_users.remove(&event_id); | ||
} | ||
|
||
// If the event is over, or was cancelled, or whatever the reason | ||
// we delete it from events_online. We leave the event_to_registered_users intact | ||
// because we still might want to see who was registered for previous events | ||
pub fn make_event_offline(&mut self, event_id: U64) { | ||
self.only_owner(); | ||
self.events.get(&event_id).unwrap().is_live = false; | ||
} | ||
|
||
pub fn add_privileged_club(&mut self, account_id: AccountId) { | ||
self.only_owner(); | ||
self.privileged_clubs.insert(&account_id); | ||
} | ||
|
||
pub fn remove_privileged_club(&mut self, account_id: AccountId) { | ||
self.only_owner(); | ||
self.privileged_clubs.remove(&account_id); | ||
} | ||
|
||
pub fn register_for_an_event(&mut self, event_id: U64, account_id: AccountId) { | ||
self.only_from_privileged_club(); | ||
assert!(self.events.contains_key(&event_id), "No event with such ID"); | ||
assert!( | ||
self.events.get(&event_id).unwrap().is_live, | ||
"Event is no longer live" | ||
); | ||
|
||
self.event_to_registered_users | ||
.get(&event_id) | ||
.unwrap() | ||
.insert(&account_id); | ||
log!( | ||
"{} registered for event: {}", | ||
account_id, | ||
u64::from(event_id) | ||
); | ||
} | ||
|
||
pub fn check_user_registered(&self, event_id: U64, account_id: AccountId) -> bool { | ||
self.events.contains_key(&event_id) | ||
&& self | ||
.event_to_registered_users | ||
.get(&event_id) | ||
.unwrap() | ||
.contains(&account_id) | ||
} | ||
|
||
pub fn set_owner(&mut self, account_id: AccountId) { | ||
self.only_owner(); | ||
self.owner_id = account_id; | ||
} | ||
|
||
pub fn pause(&mut self) { | ||
self.only_owner(); | ||
self.status = ContractStatus::Paused; | ||
} | ||
|
||
pub fn resume(&mut self) { | ||
self.only_owner(); | ||
self.status = ContractStatus::Working; | ||
} | ||
|
||
fn only_from_privileged_club(&self) { | ||
if !self | ||
.privileged_clubs | ||
.contains(&env::predecessor_account_id()) | ||
{ | ||
env::panic("Can be called only from a privieleged club contract".as_bytes()); | ||
} | ||
} | ||
|
||
fn only_owner(&self) { | ||
if env::signer_account_id() != self.owner_id { | ||
env::panic("Only owner can call this function".as_bytes()); | ||
} | ||
} | ||
} | ||
|
||
#[cfg(all(test, not(target_arch = "wasm32")))] | ||
mod tests { | ||
use super::*; | ||
use near_sdk::test_utils::{accounts, VMContextBuilder}; | ||
use near_sdk::testing_env; | ||
use near_sdk::MockedBlockchain; | ||
|
||
fn get_context( | ||
predecessor_account_id: AccountId, | ||
signer_account_id: AccountId, | ||
) -> VMContextBuilder { | ||
let mut builder = VMContextBuilder::new(); | ||
builder | ||
.current_account_id(accounts(0)) | ||
.signer_account_id( | ||
near_sdk::json_types::ValidAccountId::try_from(signer_account_id).unwrap(), | ||
) | ||
.predecessor_account_id( | ||
near_sdk::json_types::ValidAccountId::try_from(predecessor_account_id).unwrap(), | ||
); | ||
builder | ||
} | ||
|
||
#[test] | ||
fn add_events() { | ||
let context = get_context(accounts(1).to_string(), accounts(1).to_string()); | ||
testing_env!(context.build()); | ||
|
||
let mut contract = AssociatedContract::new(accounts(1).into()); | ||
contract.add_new_event("Event1".to_string()); | ||
contract.add_new_event("Event2".to_string()); | ||
contract.add_new_event("Event3".to_string()); | ||
|
||
assert!(contract.events.contains_key(&U64::from(3))); | ||
assert_eq!(contract.next_event_idx, 4); | ||
} | ||
|
||
#[test] | ||
fn add_event_and_register_users() { | ||
let mut context = get_context(accounts(1).to_string(), accounts(1).to_string()); | ||
testing_env!(context.build()); | ||
|
||
let mut contract = AssociatedContract::new(accounts(1).into()); | ||
contract.add_privileged_club(accounts(2).to_string()); | ||
contract.add_new_event("Event1".to_string()); | ||
|
||
assert_eq!(contract.next_event_idx, 2); | ||
|
||
testing_env!(context | ||
.predecessor_account_id(accounts(2)) | ||
.signer_account_id(accounts(2)) | ||
.build()); | ||
|
||
contract.register_for_an_event(U64::from(1), accounts(3).to_string()); | ||
contract.register_for_an_event(U64::from(1), accounts(4).to_string()); | ||
|
||
let registered_users = contract | ||
.event_to_registered_users | ||
.get(&U64::from(1)) | ||
.unwrap(); | ||
assert!(registered_users.contains(&accounts(3).to_string())); | ||
assert!(registered_users.contains(&accounts(4).to_string())); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/src/storage.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
pub enum StorageKey { | ||
PrivilegedClubs, | ||
EventsOnline, | ||
EventToRegisteredUsers, | ||
RegisteredUsers(u16), | ||
} | ||
|
||
impl StorageKey { | ||
pub fn to_string(&self) -> String { | ||
match self { | ||
StorageKey::PrivilegedClubs => "priv_clubs".to_string(), | ||
StorageKey::EventsOnline => "events".to_string(), | ||
StorageKey::EventToRegisteredUsers => "ev_to_registered".to_string(), | ||
StorageKey::RegisteredUsers(event_id) => format!("event{}", event_id), | ||
} | ||
} | ||
|
||
pub fn into_bytes(&self) -> Vec<u8> { | ||
self.to_string().into_bytes() | ||
} | ||
} |
Oops, something went wrong.