Skip to content

Commit

Permalink
Finished contract
Browse files Browse the repository at this point in the history
  • Loading branch information
af-afk committed Jan 24, 2025
1 parent fbdd3cf commit d1c1203
Show file tree
Hide file tree
Showing 21 changed files with 689 additions and 154 deletions.
7 changes: 7 additions & 0 deletions .cargo/mutants.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
exclude_globs = [
"src/host*.rs",
"src/wasm_*_call.rs",
"src/utils.rs",
"src/error.rs",
"src/storage*.rs"
]
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ docs/
.env
target
shahmeersgame.wasm
mutants.out
mutants.out.old
55 changes: 26 additions & 29 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@ incremental = false
stylus-sdk = "=0.7.0"
alloy-primitives = "=0.8.14"
alloy-sol-types = "=0.8.14"
const-hex = "1.14.0"
map-macro = "0.3.0"
mutants = "0.0.3"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tiny-keccak = "2.0.2"
proptest = "1.6.0"
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ during the next dilution event.
```mermaid
flowchart LR
IdeaCreator[Idea creator]
-->|Hashes proposal| SendsToWebApp[Sends to webapp the preimage]
-->|Hashes concept| SendsToWebApp[Sends to webapp the preimage]
```

## Voting
Expand All @@ -28,7 +28,7 @@ allocated.
```mermaid
flowchart LR
Predictor
--> ChoosesProposal[Chooses proposal based on webapp ideas]
--> ChoosesConcept[Chooses concept based on webapp ideas]
--> SpendsAmount[Predict with tokens]
```

Expand All @@ -43,8 +43,8 @@ true.
```mermaid
flowchart LR
Agent
--> SubmitsProposalData[Supplies proposals]
--> WinningProposalsChosen[Winning proposals have storage set of the amount of STG token available for them]
--> SubmitsConceptId[Supplies concepts]
--> WinningConceptsChosen[Winning concepts have storage set of the amount of STG token available for them]
--> ConceptsSTGAmtSet[STG that could be claimed in the future if the concept comes true marked]
```

Expand All @@ -60,3 +60,15 @@ flowchart LR
--> SubmitsWinningConcepts[Submits correct concepts from the choices earlier that accomplished goals]
--> DeclaresConceptAsCorrect[Concept is declared as being correct, and being claimable]
```

## Correct predictors draw down amount

Previous stage predictors draw down the concepts they voted on. In doing so, they receive
their share of the token dilution for each claimable section.

```mermaid
flowchart LR
Predictor
--> SuppliesWinningConceptId[Supplies winning concept to claim for]
--> ReceivesSTGShare[Receives STG amount]
```
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
src = "src"
out = "out"
libs = ["foundry-libs"]
test = "tests"
8 changes: 8 additions & 0 deletions src/IEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,12 @@ interface IEvents {
);

event EpochBumped(uint256 indexed prevEpoch);

event ConceptCameTrue(bytes32 indexed concept);

event STGClaimed(
bytes32 indexed concept,
address indexed winner,
uint256 indexed amt
);
}
4 changes: 2 additions & 2 deletions src/calldata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ pub fn unpack_u256(x: Vec<u8>) -> R<U256> {

#[test]
fn test_unpack_u256() {
unpack_u256(
assert_eq!(
U256::from(123),
const_hex::decode("000000000000000000000000000000000000000000000000000000000000007b"),
unpack_u256(const_hex::decode("000000000000000000000000000000000000000000000000000000000000007b").unwrap()).unwrap(),
);
}
13 changes: 13 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
use alloc::{vec::Vec, vec};

#[repr(C)]
#[derive(Debug)]
pub enum Error {
AlreadyCreated,
ZeroSTGAmt,
NotEnabled,
ConceptRegistered,
ConceptNotRegistered,
Expand All @@ -16,6 +18,17 @@ pub enum Error {
BadConcepts,
WinnersPicked,
NotOperator,
BadConcept,
WinnersNotPicked,
NotCorrectConcept,
BadEpoch,
AlreadyClaimed,
BadBeneficiary,
ConceptDoneAlready,
ConceptZeroSupplied,
ConceptNoUserQuad,
CheckedSub,
ZeroVotes,
}

impl From<Error> for u8 {
Expand Down
123 changes: 123 additions & 0 deletions src/host.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#![doc(hidden)]
#![cfg(not(target_arch = "wasm32"))]

use std::{cell::RefCell, collections::HashMap, ptr};

use stylus_sdk::alloy_primitives::{Address, U256};

const WORD_BYTES: usize = 32;
pub type Word = [u8; WORD_BYTES];

pub const DEFAULT_MSG_SENDER: Address = Address::new([1u8; 20]);
pub const CONTRACT: Address = Address::new([2u8; 20]);

thread_local! {
static STORAGE: RefCell<HashMap<Word, Word>> = RefCell::new(HashMap::new());
static CUR_TIME: RefCell<u64> = const { RefCell::new(0) };
static MSG_SENDER: RefCell<Address> = const { RefCell::new(DEFAULT_MSG_SENDER) };
}

unsafe fn read_word(key: *const u8) -> Word {
let mut res = Word::default();
ptr::copy(key, res.as_mut_ptr(), WORD_BYTES);
res
}

unsafe fn write_word(key: *mut u8, val: Word) {
ptr::copy(val.as_ptr(), key, WORD_BYTES);
}

#[no_mangle]
pub unsafe extern "C" fn storage_store_bytes32(key: *const u8, value: *const u8) {
let (key, value) = unsafe {
// SAFETY - stylus insists these will both be valid words
(read_word(key), read_word(value))
};
STORAGE.with(|storage| storage.borrow_mut().insert(key, value));
}

#[no_mangle]
pub unsafe extern "C" fn storage_cache_bytes32(key: *const u8, value: *const u8) {
// do the same as storage... for now. if the tests are more comprehensive
// this may need to change.
storage_store_bytes32(key, value);
}

#[no_mangle]
pub unsafe extern "C" fn native_keccak256(bytes: *const u8, len: usize, output: *mut u8) {
// SAFETY
// stylus promises `bytes` will have length `len`, `output` will have length one word
use std::slice;
use tiny_keccak::{Hasher, Keccak};

let mut hasher = Keccak::v256();

let data = unsafe { slice::from_raw_parts(bytes, len) };
hasher.update(data);

let output = unsafe { slice::from_raw_parts_mut(output, 32) };
hasher.finalize(output);
}

#[no_mangle]
pub fn block_timestamp() -> u64 {
CUR_TIME.with(|v| v.clone().into_inner())
}

#[no_mangle]
pub unsafe fn storage_flush_cache(_clear: bool) {}

#[no_mangle]
pub unsafe extern "C" fn emit_log(_pointer: *const u8, _len: usize, _: usize) {}

#[no_mangle]
pub unsafe extern "C" fn storage_load_bytes32(key: *const u8, out: *mut u8) {
// SAFETY - stylus promises etc
let key = unsafe { read_word(key) };

let value = STORAGE.with(|storage| {
storage
.borrow()
.get(&key)
.map(Word::to_owned)
.unwrap_or_default()
});

unsafe { write_word(out, value) };
}

// We avoid setting this and contract_address so that we use our internal
// function, since Stylus does some caching.
#[no_mangle]
pub unsafe extern "C" fn msg_sender(_ptr: *mut u8) {}

pub fn get_msg_sender() -> Address {
MSG_SENDER.with(|v| v.clone().into_inner())
}

pub fn set_msg_sender(a: Address) {
MSG_SENDER.with(|v| *v.borrow_mut() = a)
}

#[no_mangle]
pub unsafe extern "C" fn contract_address(_addr: *mut u8) {}

pub fn get_contract_address() -> Address {
CONTRACT
}

pub fn clear_storage() {
STORAGE.with(|s| s.borrow_mut().clear());
}

#[allow(dead_code)]
pub fn with_contract<T, P: StorageNew, F: FnOnce(&mut P) -> T>(f: F) -> T {
clear_storage();
set_msg_sender(DEFAULT_MSG_SENDER);
f(&mut P::new(U256::ZERO, 0))
}

#[allow(dead_code)]
pub trait StorageNew {
fn new(i: U256, v: u8) -> Self;
}
Loading

0 comments on commit d1c1203

Please sign in to comment.