Merge branch 'development_add_incremental_mode_to_heromodels'

This commit is contained in:
timurgordon
2025-05-22 18:24:11 +03:00
34 changed files with 2399 additions and 433 deletions

View File

@@ -4,6 +4,8 @@ use serde::{Deserialize, Serialize};
use rhai::{CustomType, TypeBuilder};
use heromodels_derive::model;
use heromodels_core::BaseModelData;
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use super::asset::Asset;
@@ -22,18 +24,32 @@ pub struct Account {
}
impl Account {
/// Create a new account
/// Create a new account with auto-generated ID
///
/// # Arguments
/// * `id` - Optional ID for the account (use None for auto-generated ID)
/// * `name` - Name of the account
/// * `user_id` - ID of the user who owns the account
/// * `description` - Description of the account
/// * `ledger` - Ledger/blockchain where the account is located
/// * `address` - Address of the account on the blockchain
/// * `pubkey` - Public key
pub fn new(
id: u32,
name: impl ToString,
user_id: u32,
description: impl ToString,
ledger: impl ToString,
address: impl ToString,
pubkey: impl ToString
id: Option<u32>,
name: impl ToString,
user_id: u32,
description: impl ToString,
ledger: impl ToString,
address: impl ToString,
pubkey: impl ToString,
) -> Self {
let mut base_data = BaseModelData::new();
if let Some(id) = id {
base_data.update_id(id);
}
Self {
base_data: BaseModelData::new(id),
base_data,
name: name.to_string(),
user_id,
description: description.to_string(),

View File

@@ -4,6 +4,8 @@ use serde::{Deserialize, Serialize};
use rhai::{CustomType, TypeBuilder};
use heromodels_derive::model;
use heromodels_core::BaseModelData;
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
/// AssetType defines the type of blockchain asset
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@@ -25,18 +27,27 @@ impl Default for AssetType {
#[model] // Has base.Base in V spec
pub struct Asset {
pub base_data: BaseModelData,
pub name: String, // Name of the asset
pub description: String, // Description of the asset
pub amount: f64, // Amount of the asset
pub address: String, // Address of the asset on the blockchain or bank
pub asset_type: AssetType, // Type of the asset
pub decimals: u8, // Number of decimals of the asset
pub name: String, // Name of the asset
pub description: String, // Description of the asset
pub amount: f64, // Amount of the asset
pub address: String, // Address of the asset on the blockchain or bank
pub asset_type: AssetType, // Type of the asset
pub decimals: u8, // Number of decimals of the asset
}
impl Asset {
/// Create a new asset
/// Create a new asset with auto-generated ID
///
/// # Arguments
/// * `id` - Optional ID for the asset (use None for auto-generated ID)
/// * `name` - Name of the asset
/// * `description` - Description of the asset
/// * `amount` - Amount of the asset
/// * `address` - Address of the asset on the blockchain or bank
/// * `asset_type` - Type of the asset
/// * `decimals` - Number of decimals of the asset
pub fn new(
id: u32,
id: Option<u32>,
name: impl ToString,
description: impl ToString,
amount: f64,
@@ -44,8 +55,13 @@ impl Asset {
asset_type: AssetType,
decimals: u8,
) -> Self {
let mut base_data = BaseModelData::new();
if let Some(id) = id {
base_data.update_id(id);
}
Self {
base_data: BaseModelData::new(id),
base_data,
name: name.to_string(),
description: description.to_string(),
amount,
@@ -73,14 +89,14 @@ impl Asset {
if amount <= 0.0 {
return Err("Transfer amount must be positive");
}
if self.amount < amount {
return Err("Insufficient balance for transfer");
}
self.amount -= amount;
target.amount += amount;
Ok(())
}
}

View File

@@ -5,6 +5,8 @@ use rhai::{CustomType, TypeBuilder};
use chrono::{DateTime, Utc};
use heromodels_core::BaseModelData;
use heromodels_derive::model;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use super::asset::AssetType;
@@ -55,11 +57,11 @@ impl Default for BidStatus {
/// Bid represents a bid on an auction listing
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
pub struct Bid {
pub listing_id: String, // ID of the listing this bid belongs to
pub bidder_id: u32, // ID of the user who placed the bid
pub amount: f64, // Bid amount
pub currency: String, // Currency of the bid
pub status: BidStatus, // Status of the bid
pub listing_id: String, // ID of the listing this bid belongs to
pub bidder_id: u32, // ID of the user who placed the bid
pub amount: f64, // Bid amount
pub currency: String, // Currency of the bid
pub status: BidStatus, // Status of the bid
pub created_at: DateTime<Utc>, // When the bid was created
}
@@ -98,7 +100,7 @@ pub struct Listing {
pub asset_id: String,
pub asset_type: AssetType,
pub seller_id: String,
pub price: f64, // Initial price for fixed price, or starting price for auction
pub price: f64, // Initial price for fixed price, or starting price for auction
pub currency: String,
pub listing_type: ListingType,
pub status: ListingStatus,
@@ -112,9 +114,23 @@ pub struct Listing {
}
impl Listing {
/// Create a new listing
/// Create a new listing with auto-generated ID
///
/// # Arguments
/// * `id` - Optional ID for the listing (use None for auto-generated ID)
/// * `title` - Title of the listing
/// * `description` - Description of the listing
/// * `asset_id` - ID of the asset being listed
/// * `asset_type` - Type of the asset
/// * `seller_id` - ID of the seller
/// * `price` - Initial price for fixed price, or starting price for auction
/// * `currency` - Currency of the price
/// * `listing_type` - Type of the listing
/// * `expires_at` - Optional expiration date
/// * `tags` - Tags for the listing
/// * `image_url` - Optional image URL
pub fn new(
id: u32,
id: Option<u32>,
title: impl ToString,
description: impl ToString,
asset_id: impl ToString,
@@ -127,8 +143,13 @@ impl Listing {
tags: Vec<String>,
image_url: Option<impl ToString>,
) -> Self {
let mut base_data = BaseModelData::new();
if let Some(id) = id {
base_data.update_id(id);
}
Self {
base_data: BaseModelData::new(id),
base_data,
title: title.to_string(),
description: description.to_string(),
asset_id: asset_id.to_string(),
@@ -154,32 +175,32 @@ impl Listing {
if self.listing_type != ListingType::Auction {
return Err("Bids can only be placed on auction listings");
}
// Check if listing is active
if self.status != ListingStatus::Active {
return Err("Cannot place bid on inactive listing");
}
// Check if bid amount is higher than current price
if bid.amount <= self.price {
return Err("Bid amount must be higher than current price");
}
// Check if there are existing bids and if the new bid is higher
if let Some(highest_bid) = self.highest_bid() {
if bid.amount <= highest_bid.amount {
return Err("Bid amount must be higher than current highest bid");
}
}
// Add the bid
self.bids.push(bid);
// Update the current price to the new highest bid
if let Some(highest_bid) = self.highest_bid() {
self.price = highest_bid.amount;
}
Ok(self)
}
@@ -192,27 +213,33 @@ impl Listing {
}
/// Complete a sale (fixed price or auction)
pub fn complete_sale(mut self, buyer_id: impl ToString, sale_price: f64) -> Result<Self, &'static str> {
pub fn complete_sale(
mut self,
buyer_id: impl ToString,
sale_price: f64,
) -> Result<Self, &'static str> {
if self.status != ListingStatus::Active {
return Err("Cannot complete sale for inactive listing");
}
self.status = ListingStatus::Sold;
self.buyer_id = Some(buyer_id.to_string());
self.sale_price = Some(sale_price);
self.sold_at = Some(Utc::now());
// If this was an auction, accept the winning bid and reject others
if self.listing_type == ListingType::Auction {
for bid in &mut self.bids {
if bid.bidder_id.to_string() == self.buyer_id.as_ref().unwrap().to_string() && bid.amount == sale_price {
if bid.bidder_id.to_string() == self.buyer_id.as_ref().unwrap().to_string()
&& bid.amount == sale_price
{
bid.status = BidStatus::Accepted;
} else {
bid.status = BidStatus::Rejected;
}
}
}
Ok(self)
}
@@ -221,16 +248,16 @@ impl Listing {
if self.status != ListingStatus::Active {
return Err("Cannot cancel inactive listing");
}
self.status = ListingStatus::Cancelled;
// Cancel all active bids
for bid in &mut self.bids {
if bid.status == BidStatus::Active {
bid.status = BidStatus::Cancelled;
}
}
Ok(self)
}
@@ -240,7 +267,7 @@ impl Listing {
if let Some(expires_at) = self.expires_at {
if Utc::now() > expires_at {
self.status = ListingStatus::Expired;
// Cancel all active bids
for bid in &mut self.bids {
if bid.status == BidStatus::Active {
@@ -250,7 +277,7 @@ impl Listing {
}
}
}
self
}