Skip to content

Commit

Permalink
Merge pull request BibliothecaDAO#205 from BibliothecaDAO/raschel/dev
Browse files Browse the repository at this point in the history
feat: labor gas optimisation
  • Loading branch information
ponderingdemocritus authored Oct 23, 2023
2 parents d3b254b + 405c8dc commit 48b728c
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 63 deletions.
17 changes: 12 additions & 5 deletions client/src/components/cityview/realm/labor/LaborBuild.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,17 @@ export const LaborBuildPopup = ({ resourceId, setBuildLoadingStates, onClose }:
return amount * multiplier * (isFood ? 12 : laborAmount) * laborCoefficient;
};

const buildLabor = async ({ entity_id, resource_type, labor_units, multiplier }: PurchaseLaborProps & BuildLaborProps) => {
const buildLabor = async ({
entity_id,
resource_type,
labor_units,
multiplier,
}: PurchaseLaborProps & BuildLaborProps) => {
await purchase_and_build_labor({
signer: account,
entity_id,
resource_type,
labor_units: labor_units,
labor_units,
multiplier,
});
};
Expand Down Expand Up @@ -276,8 +281,9 @@ export const LaborBuildPopup = ({ resourceId, setBuildLoadingStates, onClose }:
)}
</div>
<div className="flex items-center">
{`+${isFood ? (LABOR_CONFIG.base_food_per_cycle * multiplier) / 2 : ""}${isFood ? "" : LABOR_CONFIG.base_resources_per_cycle / 2
}`}
{`+${isFood ? (LABOR_CONFIG.base_food_per_cycle * multiplier) / 2 : ""}${
isFood ? "" : LABOR_CONFIG.base_resources_per_cycle / 2
}`}
<ResourceIcon
containerClassName="mx-0.5"
className="!w-[12px]"
Expand Down Expand Up @@ -337,7 +343,8 @@ export const LaborBuildPopup = ({ resourceId, setBuildLoadingStates, onClose }:
{!isFood && (
<div className="flex items-center">
<div className="italic text-light-pink">Amount</div>
<NumberInput className="ml-2 mr-2" value={laborAmount} step={5} onChange={setLaborAmount} max={9999} />
{/* note: max 76 for now because of gas, can remove after new contract deployment */}
<NumberInput className="ml-2 mr-2" value={laborAmount} step={5} onChange={setLaborAmount} max={76} />
<div className="italic text-gold">
{formatSecondsLeftInDaysHours(laborAmount * (LABOR_CONFIG?.base_labor_units || 0))}
</div>
Expand Down
12 changes: 8 additions & 4 deletions client/src/dojo/createOptimisticSystemCalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
CreateRoadProps,
HarvestLaborProps,
PurchaseLaborProps,
BuildLaborProps
BuildLaborProps,
} from "@bibliothecadao/eternum";

export const HIGH_ENTITY_ID = 9999999999;
Expand Down Expand Up @@ -220,8 +220,10 @@ export function createOptimisticSystemCalls({
};
let balance =
currentResource.balance -
(laborUnits as number) * (multiplier as number) * costResources[i].amount * laborAuctionAverageCoefficient;
Resource.addOverride(overrideId, {
Math.floor(
(laborUnits as number) * (multiplier as number) * costResources[i].amount * laborAuctionAverageCoefficient,
);
Resource.addOverride(overrideId + i, {
entity: costId,
value: {
balance,
Expand Down Expand Up @@ -261,7 +263,9 @@ export function createOptimisticSystemCalls({
// remove overrides
Labor.removeOverride(overrideId);
// remove resource overrides
Resource.removeOverride(overrideId);
for (let i = 0; i < costResources.length; i++) {
Resource.removeOverride(overrideId + i);
}
}
};
}
Expand Down
19 changes: 14 additions & 5 deletions contracts/scripts/computeAuctionPrice.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function getTotalPrice(
// console.log("resource left", balance - price);

const DECAY = 0.1;
const UNITS_PER_DAY = 960;
const UNITS_PER_DAY = 50;
const SECONDS_PER_DAY = 86400;

function computeCoefficient(startTimestamp, nextBlockTimestamp, sold) {
Expand All @@ -58,7 +58,7 @@ function computeAverageCoefficient(
let multiplier = computeCoefficient(startTimestamp, nextBlockTimestamp, sold);
// start at number of units already sold and add 1 everytime
for (let i = sold; i < sold + laborUnits; i++) {
console.log({ multiplier });
// console.log({ multiplier });
if (i % interval == 0) {
multiplier = computeCoefficient(startTimestamp, nextBlockTimestamp, i);
sum += multiplier;
Expand All @@ -69,9 +69,18 @@ function computeAverageCoefficient(
return sum / laborUnits; // Return the average coefficient
}

const averageCoefficient = computeAverageCoefficient(0, 0, 0, 1566, 10);
const laborUnits = 90;
const interval = 20;
const averageCoefficient = computeAverageCoefficient(
0,
0,
0,
laborUnits,
interval
);
const totalCost = Math.floor(1000 * laborUnits * averageCoefficient);

// Example usage
// console.log({ averageCoefficient });
console.log({ averageCoefficient });
// console.log({ totalCost: 1000 * 16 * averageCoefficient });
// console.log({ remainder: 100000 - 1000 * 20 * averageCoefficient });
console.log({ remainder: 100000 - totalCost });
12 changes: 9 additions & 3 deletions contracts/src/models/labor_auction.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,25 @@ impl LaborAuctionImpl of LaborAuctionTrait {
}
}

fn get_price(self: LaborAuction) -> Fixed {
// time since auction start
fn get_time_since_start_fixed(self: LaborAuction) -> Fixed {
// time that has passed since auction start
// 1 period = 1 day
let time_since_start: u128 = get_block_timestamp().into() - self.start_time.into();
FixedTrait::new_unscaled(time_since_start / 86400, false)
}

fn get_price(self: LaborAuction) -> Fixed {
// get current price
self
.to_LinearVRGDA()
.get_vrgda_price(
// 1 period = 1 day
FixedTrait::new_unscaled(time_since_start / 86400, false), // time since start
self.get_time_since_start_fixed(), // time since start
FixedTrait::new_unscaled(self.sold, false), // amount sold
)
}

#[inline(always)]
fn sell(ref self: LaborAuction) {
self.sold += 1;
}
Expand Down
86 changes: 51 additions & 35 deletions contracts/src/systems/labor/contracts.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod labor_systems {
use eternum::models::resources::Resource;
use eternum::models::labor::{Labor, LaborTrait};
use eternum::models::labor_auction::{LaborAuction, LaborAuctionTrait};
use eternum::models::labor_auction::{LinearVRGDA, LinearVRGDATrait};
use eternum::models::config::{WorldConfig, LaborConfig, LaborCostResources, LaborCostAmount};

use eternum::systems::labor::utils::{assert_harvestable_resource, get_labor_resource_type};
Expand Down Expand Up @@ -320,76 +321,91 @@ mod labor_systems {

let zone = position.get_zone();
let mut labor_auction = get!(world, zone, (LaborAuction));
let mut labor_auction_vrgda = labor_auction.to_LinearVRGDA();
let mut labor_auction_time_since_start_fixed
= labor_auction.get_time_since_start_fixed();

assert(labor_auction.per_time_unit != 0, 'Labor auction not found');

let mut labor_units_remaining = labor_units;
let mut total_costs: Felt252Dict<u128> = Default::default();

let mut labor_cost_multiplier = labor_auction.get_price();
let zero_fixed = Fixed {sign: false, mag: 0};

let mut index = 0_usize;
loop {
if labor_units_remaining == 0 {
break;
if index == labor_cost_resources.resource_types_count.into() {
break ();
}

let mut index = 0_usize;
let labor_cost_resource_type = *labor_cost_resource_types[index];
let labor_cost_per_unit = get!(
world, (resource_type, labor_cost_resource_type).into(), LaborCostAmount
);

let labor_cost_per_unit_fixed
= FixedTrait::new_unscaled(labor_cost_per_unit.value, false);


let mut total_resource_labor_cost_fixed = FixedTrait::new_unscaled(0, false);

let mut labor_units_remaining = labor_units;

loop {
if index == labor_cost_resources.resource_types_count.into() {
break ();
if labor_units_remaining == 0 {
break;
}
let labor_cost_resource_type = *labor_cost_resource_types[index];
let labor_cost_per_unit = get!(
world, (resource_type, labor_cost_resource_type).into(), LaborCostAmount
);

let cost_fixed = FixedTrait::new_unscaled(labor_cost_per_unit.value, false)
* labor_cost_multiplier.into();
let cost: u128 = cost_fixed.try_into().unwrap();
let labor_cost_multiplier
= labor_auction_vrgda.get_vrgda_price(
labor_auction_time_since_start_fixed,
FixedTrait::new_unscaled(labor_auction.sold, false)
);

let total_cost = total_costs.get(labor_cost_resource_type.into());
total_costs.insert(labor_cost_resource_type.into(), total_cost + cost);
let mut labor_unit_count
= labor_auction.price_update_interval -
(labor_auction.sold % labor_auction.price_update_interval);

index += 1;
};
if labor_units_remaining < labor_unit_count {
labor_unit_count = labor_units_remaining;
}

labor_auction.sell();
if (labor_auction.sold) % labor_auction.price_update_interval == 0 {
labor_cost_multiplier = labor_auction.get_price();
};
labor_units_remaining -= 1;
};
let mut resource_labor_cost
= labor_cost_per_unit_fixed * labor_cost_multiplier * FixedTrait::new_unscaled(labor_unit_count, false);

let mut index = 0_usize;
loop {
if index == labor_cost_resources.resource_types_count.into() {
break ();
}
labor_units_remaining -= labor_unit_count;
labor_auction.sold += labor_unit_count;
total_resource_labor_cost_fixed += resource_labor_cost;

};

let labor_cost_resource_type = *labor_cost_resource_types[index];
let total_cost = total_costs.get(labor_cost_resource_type.into());
let total_resource_labor_cost: u128 = total_resource_labor_cost_fixed.try_into().unwrap();

// deduct total labor cost for the current
// resource from entity's balance
let current_resource: Resource = get!(
world, (entity_id, labor_cost_resource_type).into(), Resource
);
assert(current_resource.balance >= total_resource_labor_cost, 'Not enough resources');

assert(current_resource.balance >= total_cost, 'Not enough resources');
set!(
world,
Resource {
entity_id,
resource_type: labor_cost_resource_type,
balance: current_resource.balance - total_cost
balance: current_resource.balance - total_resource_labor_cost
}
);

// reset labor amount sold for next loop
labor_auction.sold -= labor_units;

// increment index
index += 1;
};

labor_auction.sold = labor_units;
set!(world, (labor_auction));

let labor_resource_type: u8 = get_labor_resource_type(resource_type);

// increment new labor resource in entity balance
let labor_resource = get!(world, (entity_id, labor_resource_type), Resource);

Expand Down
22 changes: 11 additions & 11 deletions contracts/src/systems/labor/tests/labor_purchase_tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn setup(resource_type: u8) -> (IWorldDispatcher, u128, ILaborSystemsDispatcher)
let zone: u8 = 5;
let decay_constant: u128 = _0_1;
let per_time_unit: u128 = 50;
let price_update_interval: u128 = 10;
let price_update_interval: u128 = 20;
labor_config_dispatcher.set_labor_auction(
world,
decay_constant,
Expand Down Expand Up @@ -159,25 +159,25 @@ fn test_purchase_labor_non_food() {
world,
realm_entity_id,
resource_type,
20 // labor_units
90 // labor_units
);


// assert resources are the right amount
let coal_resource = get!(world, (realm_entity_id, ResourceTypes::COAL), Resource);
assert(coal_resource.resource_type == ResourceTypes::COAL, 'failed resource type');
assert(coal_resource.balance == 79_790, 'failed resource amount');
assert(coal_resource.balance == 2_849, 'failed resource amount');

let stone_resource = get!(world, (realm_entity_id, ResourceTypes::STONE), Resource);
assert(stone_resource.resource_type == ResourceTypes::STONE, 'failed resource type');
assert(stone_resource.balance == 79_790, 'failed resource amount');
assert(stone_resource.balance == 2_849, 'failed resource amount');

// assert labor resource is right amount
let gold_labor_resource = get!(world, (realm_entity_id, resource_type + 28), Resource);
assert(gold_labor_resource.balance == 20, 'wrong labor resource balance');
assert(gold_labor_resource.balance == 90, 'wrong labor resource balance');

let labor_auction = get!(world, 1, LaborAuction);
assert(labor_auction.sold == 20, 'wrong labor auction sold');
assert(labor_auction.sold == 90, 'wrong labor auction sold');
}


Expand All @@ -194,22 +194,22 @@ fn test_purchase_labor_food() {
world,
realm_entity_id,
resource_type,
20 // labor_units
90 // labor_units
);

// assert resources are the right amount
let coal_resource = get!(world, (realm_entity_id, ResourceTypes::COAL), Resource);
assert(coal_resource.resource_type == ResourceTypes::COAL, 'failed resource type');
assert(coal_resource.balance == 79_790, 'failed resource amount');
assert(coal_resource.balance == 2_849, 'failed resource amount');

let stone_resource = get!(world, (realm_entity_id, ResourceTypes::STONE), Resource);
assert(stone_resource.resource_type == ResourceTypes::STONE, 'failed resource type');
assert(stone_resource.balance == 79_790, 'failed resource amount');
assert(stone_resource.balance == 2_849, 'failed resource amount');

// assert labor resource is right amount
let fish_labor_resource = get!(world, (realm_entity_id, resource_type - 3), Resource);
assert(fish_labor_resource.balance == 20, 'wrong labor resource balance');
assert(fish_labor_resource.balance == 90, 'wrong labor resource balance');

let labor_auction = get!(world, 1, LaborAuction);
assert(labor_auction.sold == 20, 'wrong labor auction sold');
assert(labor_auction.sold == 90, 'wrong labor auction sold');
}

0 comments on commit 48b728c

Please sign in to comment.