Skip to content

Commit

Permalink
near ctf
Browse files Browse the repository at this point in the history
  • Loading branch information
hackingsub committed Sep 28, 2022
1 parent a88c44b commit 226060c
Show file tree
Hide file tree
Showing 12 changed files with 10,889 additions and 0 deletions.
3,405 changes: 3,405 additions & 0 deletions HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/Cargo.lock

Large diffs are not rendered by default.

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
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 HalbornCTF_Rust_NEAR/halborn-near-ctf-associated-contract/src/lib.rs
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()));
}
}
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()
}
}
Loading

0 comments on commit 226060c

Please sign in to comment.