Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
starknetdev committed Oct 2, 2023
2 parents 91d34ce + 77ce76c commit 32d3751
Show file tree
Hide file tree
Showing 25 changed files with 927 additions and 1,415 deletions.
14 changes: 0 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,6 @@ jobs:
run: |
cd contracts/market && scarb build && scarb cairo-test
build-pack:
name: Build Pack
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Scarb
run: |
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v ${{ env.SCARB_VERSION }}
- name: Scarb build
run: |
cd contracts/pack && scarb build && scarb cairo-test
build-obstacles:
name: Build Obstacles
runs-on: ubuntu-latest
Expand Down
1 change: 0 additions & 1 deletion contracts/adventurer/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ version = "0.1.0"
# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest

[dependencies]
pack = { path = "../pack" }
lootitems = { path = "../loot" }
obstacles = { path = "../obstacles" }
combat = { path = "../combat" }
Expand Down
234 changes: 102 additions & 132 deletions contracts/adventurer/src/adventurer.cairo

Large diffs are not rendered by default.

64 changes: 32 additions & 32 deletions contracts/adventurer/src/adventurer_meta.cairo
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
use starknet::{StorePacking};
use traits::{TryInto, Into};
use pack::constants::pow;
use pack::pack::{Packing, rshift_split};

#[derive(Drop, Copy, Serde)]
struct AdventurerMetadata {
name: u128,
entropy: u128,
}

impl PackingAdventurerMetadata of Packing<AdventurerMetadata> {
fn pack(self: AdventurerMetadata) -> felt252 {
(self.entropy.into()
+ self.name.into() * pow::TWO_POW_128)
.try_into()
.expect('pack AdventurerMetadata')
impl PackingAdventurerMetadata of StorePacking<AdventurerMetadata, felt252> {
fn pack(value: AdventurerMetadata) -> felt252 {
(value.entropy.into() + value.name.into() * TWO_POW_128).try_into().unwrap()
}
fn unpack(packed: felt252) -> AdventurerMetadata {
let packed = packed.into();
let (packed, entropy) = rshift_split(packed, pow::TWO_POW_128);
let (_, name) = rshift_split(packed, pow::TWO_POW_128);
AdventurerMetadata {
name: name.try_into().expect('unpack AdvMetadata name'),
entropy: entropy.try_into().expect('unpack AdvMetadata entropy')
}
}

// TODO: add overflow pack protection
fn overflow_pack_protection(self: AdventurerMetadata) -> AdventurerMetadata {
self
fn unpack(value: felt252) -> AdventurerMetadata {
let packed = value.into();
let (packed, entropy) = integer::U256DivRem::div_rem(
packed, TWO_POW_128.try_into().unwrap()
);
let (_, name) = integer::U256DivRem::div_rem(packed, TWO_POW_128.try_into().unwrap());
AdventurerMetadata { name: name.try_into().unwrap(), entropy: entropy.try_into().unwrap() }
}
}

const TWO_POW_128: u256 = 0x100000000000000000000000000000000;

#[cfg(test)]
#[test]
#[available_gas(96380)]
fn test_pack_unpack_adventurer_meta() {
let meta = AdventurerMetadata {
name: 'abcdefghijklmno',
entropy: 340282366920938463463374607431768211455
};
#[available_gas(116600)]
fn test_adventurer_metadata_packing() {
// max value case
let max_u128 = 340282366920938463463374607431768211455;
let name_length = 'abcdefghijklmno';

let packed = meta.pack();
let unpacked: AdventurerMetadata = Packing::unpack(packed);
assert(meta.name == unpacked.name, 'name');
assert(meta.entropy == unpacked.entropy, 'entropy');
}
let meta = AdventurerMetadata { name: name_length, entropy: max_u128 };

let packed = PackingAdventurerMetadata::pack(meta);
let unpacked: AdventurerMetadata = PackingAdventurerMetadata::unpack(packed);
assert(meta.name == unpacked.name, 'name should be max');
assert(meta.entropy == unpacked.entropy, 'entropy should be max u128');

// zero case
let meta = AdventurerMetadata { name: 0, entropy: 0 };
let packed = PackingAdventurerMetadata::pack(meta);
let unpacked: AdventurerMetadata = PackingAdventurerMetadata::unpack(packed);
assert(unpacked.name == 0, 'name should be 0');
assert(unpacked.entropy == 0, 'entropy should be 0');
}
130 changes: 43 additions & 87 deletions contracts/adventurer/src/adventurer_stats.cairo
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
use option::OptionTrait;
use traits::{TryInto, Into};
use pack::{pack::{Packing, rshift_split}, constants::pow};
use survivor::constants::adventurer_constants::MAX_STAT_VALUE;
use core::{option::OptionTrait, starknet::{StorePacking}, traits::{TryInto, Into}};

#[derive(Drop, Copy, Serde)]
struct Stats { // 5 bits each
// Physical
struct Stats { // 30 storage bits
strength: u8, // 5 bits
dexterity: u8, // 5 bits
vitality: u8, // 5 bits
// Mental
intelligence: u8, // 5 bits
wisdom: u8, // 5 bits
charisma: u8, // 5 bits
// Metaphysical
luck: u8 // dynamically generated (not stored)
luck: u8 // // dynamically generated, not stored.
}

#[generate_trait]
Expand All @@ -26,74 +20,59 @@ impl StatUtils of IStat {
}
}

impl StatsPacking of Packing<Stats> {
fn pack(self: Stats) -> felt252 {
let overflow_protected = self.overflow_pack_protection();

(overflow_protected.strength.into()
+ overflow_protected.dexterity.into() * pow::TWO_POW_5
+ overflow_protected.vitality.into() * pow::TWO_POW_10
+ overflow_protected.intelligence.into() * pow::TWO_POW_15
+ overflow_protected.wisdom.into() * pow::TWO_POW_20
+ overflow_protected.charisma.into() * pow::TWO_POW_25)
impl StatsPacking of StorePacking<Stats, felt252> {
fn pack(value: Stats) -> felt252 {
(value.strength.into()
+ value.dexterity.into() * TWO_POW_5
+ value.vitality.into() * TWO_POW_10
+ value.intelligence.into() * TWO_POW_15
+ value.wisdom.into() * TWO_POW_20
+ value.charisma.into() * TWO_POW_25)
.try_into()
.expect('pack Stats')
.unwrap()
}

fn unpack(packed: felt252) -> Stats {
let packed = packed.into();
let (packed, strength) = rshift_split(packed, pow::TWO_POW_5);
let (packed, dexterity) = rshift_split(packed, pow::TWO_POW_5);
let (packed, vitality) = rshift_split(packed, pow::TWO_POW_5);
let (packed, intelligence) = rshift_split(packed, pow::TWO_POW_5);
let (packed, wisdom) = rshift_split(packed, pow::TWO_POW_5);
let (_, charisma) = rshift_split(packed, pow::TWO_POW_5);
fn unpack(value: felt252) -> Stats {
let packed = value.into();
let (packed, strength) = integer::U256DivRem::div_rem(
packed, TWO_POW_5.try_into().unwrap()
);
let (packed, dexterity) = integer::U256DivRem::div_rem(
packed, TWO_POW_5.try_into().unwrap()
);
let (packed, vitality) = integer::U256DivRem::div_rem(
packed, TWO_POW_5.try_into().unwrap()
);
let (packed, intelligence) = integer::U256DivRem::div_rem(
packed, TWO_POW_5.try_into().unwrap()
);
let (packed, wisdom) = integer::U256DivRem::div_rem(packed, TWO_POW_5.try_into().unwrap());
let (_, charisma) = integer::U256DivRem::div_rem(packed, TWO_POW_5.try_into().unwrap());

Stats {
strength: strength.try_into().expect('unpack Stats strength'),
dexterity: dexterity.try_into().expect('unpack Stats dexterity'),
vitality: vitality.try_into().expect('unpack Stats vitality'),
intelligence: intelligence.try_into().expect('unpack Stats intelligence'),
wisdom: wisdom.try_into().expect('unpack Stats wisdom'),
charisma: charisma.try_into().expect('unpack Stats charisma'),
strength: strength.try_into().unwrap(),
dexterity: dexterity.try_into().unwrap(),
vitality: vitality.try_into().unwrap(),
intelligence: intelligence.try_into().unwrap(),
wisdom: wisdom.try_into().unwrap(),
charisma: charisma.try_into().unwrap(),
luck: 0
}
}

fn overflow_pack_protection(self: Stats) -> Stats {
let mut overflow_protected_stats = self;

if self.strength > MAX_STAT_VALUE {
overflow_protected_stats.strength = MAX_STAT_VALUE;
};
if self.dexterity > MAX_STAT_VALUE {
overflow_protected_stats.dexterity = MAX_STAT_VALUE;
}
if self.vitality > MAX_STAT_VALUE {
overflow_protected_stats.vitality = MAX_STAT_VALUE;
}
if self.intelligence > MAX_STAT_VALUE {
overflow_protected_stats.intelligence = MAX_STAT_VALUE;
}
if self.wisdom > MAX_STAT_VALUE {
overflow_protected_stats.wisdom = MAX_STAT_VALUE;
}
if self.charisma > MAX_STAT_VALUE {
overflow_protected_stats.charisma = MAX_STAT_VALUE;
}

overflow_protected_stats
}
}

const TWO_POW_5: u256 = 0x20;
const TWO_POW_10: u256 = 0x400;
const TWO_POW_15: u256 = 0x8000;
const TWO_POW_20: u256 = 0x100000;
const TWO_POW_25: u256 = 0x2000000;

// ---------------------------
// ---------- Tests ----------
// ---------------------------
#[cfg(test)]
mod tests {
use survivor::{
constants::adventurer_constants::MAX_STAT_VALUE, adventurer_stats::{Stats, StatsPacking}
};
use survivor::adventurer_stats::{Stats, StatsPacking};

#[test]
#[available_gas(1039260)]
Expand All @@ -103,7 +82,7 @@ mod tests {
strength: 0, dexterity: 0, vitality: 0, intelligence: 0, wisdom: 0, charisma: 0, luck: 0
};

let packed = stats.pack();
let packed = StatsPacking::pack(stats);
let unpacked = StatsPacking::unpack(packed);
assert(stats.strength == unpacked.strength, 'strength zero case');
assert(stats.dexterity == unpacked.dexterity, 'dexterity zero case');
Expand All @@ -124,7 +103,7 @@ mod tests {
luck: 31
};

let packed = stats.pack();
let packed = StatsPacking::pack(stats);
let unpacked = StatsPacking::unpack(packed);
assert(stats.strength == unpacked.strength, 'strength storage limit');
assert(stats.dexterity == unpacked.dexterity, 'dexterity storage limit');
Expand All @@ -133,28 +112,5 @@ mod tests {
assert(stats.wisdom == unpacked.wisdom, 'wisdom storage limit');
assert(stats.charisma == unpacked.charisma, 'charisma storage limit');
assert(unpacked.luck == 0, 'luck is zero from storage');

// overflow storage limit using max u8
let stats = Stats {
strength: 255,
dexterity: 255,
vitality: 255,
intelligence: 255,
wisdom: 255,
charisma: 255,
luck: 255
};

let packed = stats.pack();
let unpacked = StatsPacking::unpack(packed);

// assert packing function prevented overflow
assert(unpacked.strength == MAX_STAT_VALUE, 'strength pack overflow');
assert(unpacked.dexterity == MAX_STAT_VALUE, 'dexterity pack overflow');
assert(unpacked.vitality == MAX_STAT_VALUE, 'vitality pack overflow');
assert(unpacked.intelligence == MAX_STAT_VALUE, 'intelligence pack overflow');
assert(unpacked.wisdom == MAX_STAT_VALUE, 'wisdom pack overflow');
assert(unpacked.charisma == MAX_STAT_VALUE, 'charisma pack overflow');
assert(unpacked.luck == 0, 'luck is zero from storage');
}
}
Loading

1 comment on commit 32d3751

@vercel
Copy link

@vercel vercel bot commented on 32d3751 Oct 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.