diff --git a/crates/dojo-defi/src/market/models.cairo b/crates/dojo-defi/src/market/models.cairo index c7da959dfe..1bc694c539 100644 --- a/crates/dojo-defi/src/market/models.cairo +++ b/crates/dojo-defi/src/market/models.cairo @@ -1,5 +1,5 @@ use starknet::ContractAddress; -use dojo::model::StorageIntrospection; +use dojo::database::schema::{Struct, Ty, SchemaIntrospection, Member, serialize_member}; // Cubit fixed point math library use cubit::f128::types::fixed::Fixed; @@ -8,19 +8,42 @@ const SCALING_FACTOR: u128 = 10000; impl SchemaIntrospectionFixed of SchemaIntrospection { #[inline(always)] - fn unpacked_size() -> usize { - 1 + fn size() -> usize { + SchemaIntrospection::::size() + + SchemaIntrospection::::size() } #[inline(always)] - fn packed_size() -> usize { - 129 + fn layout(ref layout: Array) { + SchemaIntrospection::::layout(ref layout); + SchemaIntrospection::::layout(ref layout); } #[inline(always)] - fn layout(ref layout: Array) { - layout.append(128); - layout.append(1); + fn ty() -> Ty { + Ty::Struct( + Struct { + name: 'Fixed', + attrs: array![].span(), + children: array![ + serialize_member( + @Member { + name: 'mag', + ty: SchemaIntrospection::::ty(), + attrs: array![].span() + } + ), + serialize_member( + @Member { + name: 'sign', + ty: SchemaIntrospection::::ty(), + attrs: array![].span() + } + ) + ] + .span() + } + ) } } diff --git a/crates/dojo-defi/src/market/systems.cairo b/crates/dojo-defi/src/market/systems.cairo index 078bd5cec1..27d9b10b21 100644 --- a/crates/dojo-defi/src/market/systems.cairo +++ b/crates/dojo-defi/src/market/systems.cairo @@ -1,176 +1,195 @@ +use cubit::f128::types::fixed::Fixed; +use dojo::world::IWorldDispatcher; + + +trait ITrade { + fn buy(self: @TContractState, world: IWorldDispatcher, item_id: u32, quantity: u128); + fn sell(self: @TContractState, world: IWorldDispatcher, item_id: u32, quantity: u128); +} + + #[system] -mod Buy { +mod Trade { use dojo_defi::market::models::{Item, Cash, Market}; use dojo_defi::market::constant_product_market::MarketTrait; - use dojo::world::Context; - fn execute(ctx: Context, item_id: u32, quantity: u128) { - let player = starknet::get_caller_address(); + use super::ITrade; - let player_cash = get!(ctx.world, (player), Cash); + + #[external(v0)] + impl TradeImpl of ITrade { + fn buy(self: @ContractState, world: IWorldDispatcher, item_id: u32, quantity: u128) { + + let player = starknet::get_caller_address(); - let market = get!(ctx.world, (item_id), Market); + let player_cash = get!(world, (player), Cash); - let cost = market.buy(quantity); - assert(cost <= player_cash.amount, 'not enough cash'); + let market = get!(world, (item_id), Market); - // update market - set!( - ctx.world, - (Market { - item_id: item_id, - cash_amount: market.cash_amount + cost, - item_quantity: market.item_quantity - quantity, - }) - ); + let cost = market.buy(quantity); + assert(cost <= player_cash.amount, 'not enough cash'); - // update player cash - set!(ctx.world, (Cash { player: player, amount: player_cash.amount - cost })); + // update market + set!( + world, + (Market { + item_id: item_id, + cash_amount: market.cash_amount + cost, + item_quantity: market.item_quantity - quantity, + }) + ); - // update player item - let item = get!(ctx.world, (player, item_id), Item); - set!( - ctx.world, - (Item { player: player, item_id: item_id, quantity: item.quantity + quantity }) - ); - } -} + // update player cash + set!(world, (Cash { player: player, amount: player_cash.amount - cost })); + + // update player item + let item = get!(world, (player, item_id), Item); + set!( + world, + (Item { player: player, item_id: item_id, quantity: item.quantity + quantity }) + ); + } + + + + fn sell(self: @ContractState, world: IWorldDispatcher, item_id: u32, quantity: u128) { + let player = starknet::get_caller_address(); + + let item = get!(world, (player, item_id), Item); + let player_quantity = item.quantity; + assert(player_quantity >= quantity, 'not enough items'); + + let player_cash = get!(world, (player), Cash); + + let market = get!(world, (item_id), Market); + let payout = market.sell(quantity); + + // update market + set!( + world, + (Market { + item_id: item_id, + cash_amount: market.cash_amount - payout, + item_quantity: market.item_quantity + quantity, + }) + ); + + // update player cash + set!(world, (Cash { player: player, amount: player_cash.amount + payout })); + + // update player item + set!( + world, + (Item { player: player, item_id: item_id, quantity: player_quantity - quantity }) + ); + } -#[system] -mod Sell { - use dojo_defi::market::models::{Item, Cash, Market}; - use dojo_defi::market::constant_product_market::MarketTrait; - use dojo::world::Context; - - fn execute(ctx: Context, item_id: u32, quantity: u128) { - let player = starknet::get_caller_address(); - - let item = get!(ctx.world, (player, item_id), Item); - let player_quantity = item.quantity; - assert(player_quantity >= quantity, 'not enough items'); - - let player_cash = get!(ctx.world, (player), Cash); - - let market = get!(ctx.world, (item_id), Market); - let payout = market.sell(quantity); - - // update market - set!( - ctx.world, - (Market { - item_id: item_id, - cash_amount: market.cash_amount - payout, - item_quantity: market.item_quantity + quantity, - }) - ); - - // update player cash - set!(ctx.world, (Cash { player: player, amount: player_cash.amount + payout })); - - // update player item - set!( - ctx.world, - (Item { player: player, item_id: item_id, quantity: player_quantity - quantity }) - ); } + } -#[system] -mod AddLiquidity { - use dojo_defi::market::models::{Item, Cash, Market, Liquidity}; - use dojo_defi::market::constant_product_market::MarketTrait; - use dojo::world::Context; - - fn execute(ctx: Context, item_id: u32, amount: u128, quantity: u128) { - let player = starknet::get_caller_address(); - - let item = get!(ctx.world, (player, item_id), Item); - let player_quantity = item.quantity; - assert(player_quantity >= quantity, 'not enough items'); - - let player_cash = get!(ctx.world, (player), Cash); - assert(amount <= player_cash.amount, 'not enough cash'); - - let market = get!(ctx.world, (item_id), Market); - let (cost_cash, cost_quantity, liquidity_shares) = market.add_liquidity(amount, quantity); - - // update market - set!( - ctx.world, - (Market { - item_id: item_id, - cash_amount: market.cash_amount + cost_cash, - item_quantity: market.item_quantity + cost_quantity - }) - ); - - // update player cash - set!(ctx.world, (Cash { player: player, amount: player_cash.amount - cost_cash })); - - // update player item - set!( - ctx.world, - (Item { player: player, item_id: item_id, quantity: player_quantity - cost_quantity }) - ); - - // update player liquidity - let player_liquidity = get!(ctx.world, (player, item_id), Liquidity); - set!( - ctx.world, - (Liquidity { - player: player, item_id: item_id, shares: player_liquidity.shares + liquidity_shares - }) - ); - } + + +trait ILiquidity { + fn add(self: @TContractState, world: IWorldDispatcher, item_id: u32, amount: u128, quantity: u128); + fn remove(self: @TContractState, world: IWorldDispatcher, item_id: u32, shares: Fixed); } -#[system] -mod RemoveLiquidity { - use dojo_defi::market::models::{Item, Cash, Market, Liquidity}; - use dojo_defi::market::constant_product_market::MarketTrait; - use dojo::world::Context; +#[system] +mod Liquidity { use cubit::f128::types::fixed::Fixed; - fn execute(ctx: Context, item_id: u32, shares: Fixed) { - let player = starknet::get_caller_address(); - - let player_liquidity = get!(ctx.world, (player, item_id), Liquidity); - assert(player_liquidity.shares >= shares, 'not enough shares'); - - let market = get!(ctx.world, (item_id), Market); - let (payout_cash, payout_quantity) = market.remove_liquidity(shares); - - // update market - set!( - ctx.world, - (Market { - item_id: item_id, - cash_amount: market.cash_amount - payout_cash, - item_quantity: market.item_quantity - payout_quantity - }) - ); - - // update player cash - let player_cash = get!(ctx.world, (player), Cash); - set!(ctx.world, (Cash { player: player, amount: player_cash.amount + payout_cash })); - - // update player item - let item = get!(ctx.world, (player, item_id), Item); - let player_quantity = item.quantity; - set!( - ctx.world, - (Item { player: player, item_id: item_id, quantity: player_quantity + payout_quantity }) - ); - - // update player liquidity - let player_liquidity = get!(ctx.world, (player, item_id), Liquidity); - set!( - ctx.world, - (Liquidity { - player: player, item_id: item_id, shares: player_liquidity.shares - shares - }) - ); + use dojo_defi::market::models::{Item, Cash, Market, Liquidity}; + use dojo_defi::market::constant_product_market::MarketTrait; + + use super::ILiquidity; + + #[external(v0)] + impl LiquidityImpl of ILiquidity { + + fn add(self: @ContractState, world: IWorldDispatcher, item_id: u32, amount: u128, quantity: u128) { + let player = starknet::get_caller_address(); + + let item = get!(world, (player, item_id), Item); + let player_quantity = item.quantity; + assert(player_quantity >= quantity, 'not enough items'); + + let player_cash = get!(world, (player), Cash); + assert(amount <= player_cash.amount, 'not enough cash'); + + let market = get!(world, (item_id), Market); + let (cost_cash, cost_quantity, liquidity_shares) = market.add_liquidity(amount, quantity); + + // update market + set!( + world, + (Market { + item_id: item_id, + cash_amount: market.cash_amount + cost_cash, + item_quantity: market.item_quantity + cost_quantity + }) + ); + + // update player cash + set!(world, (Cash { player: player, amount: player_cash.amount - cost_cash })); + + // update player item + set!( + world, + (Item { player: player, item_id: item_id, quantity: player_quantity - cost_quantity }) + ); + + // update player liquidity + let player_liquidity = get!(world, (player, item_id), Liquidity); + set!( + world, + (Liquidity { + player: player, item_id: item_id, shares: player_liquidity.shares + liquidity_shares + }) + ); + } + + + fn remove(self: @ContractState, world: IWorldDispatcher, item_id: u32, shares: Fixed) { + let player = starknet::get_caller_address(); + + let player_liquidity = get!(world, (player, item_id), Liquidity); + assert(player_liquidity.shares >= shares, 'not enough shares'); + + let market = get!(world, (item_id), Market); + let (payout_cash, payout_quantity) = market.remove_liquidity(shares); + + // update market + set!( + world, + (Market { + item_id: item_id, + cash_amount: market.cash_amount - payout_cash, + item_quantity: market.item_quantity - payout_quantity + }) + ); + + // update player cash + let player_cash = get!(world, (player), Cash); + set!(world, (Cash { player: player, amount: player_cash.amount + payout_cash })); + + // update player item + let item = get!(world, (player, item_id), Item); + let player_quantity = item.quantity; + set!( + world, + (Item { player: player, item_id: item_id, quantity: player_quantity + payout_quantity }) + ); + + // update player liquidity + let player_liquidity = get!(world, (player, item_id), Liquidity); + set!( + world, + (Liquidity { + player: player, item_id: item_id, shares: player_liquidity.shares - shares + }) + ); + } } } -