use serde::{Deserialize, Serialize};
use super::identity::IdentityRef;
use super::spend::{SignedBundle, UnsignedSpend};
use super::value::Address;
use super::{Amount, AssetId};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct OfferBuildId(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OfferedAssets {
pub xch: Amount,
pub cats: Vec<(AssetId, Amount)>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RequestedAssets {
pub xch: Amount,
pub cats: Vec<(AssetId, Amount)>,
pub payee: Address,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MakeOfferRequest {
pub identity: IdentityRef,
pub offered: OfferedAssets,
pub requested: RequestedAssets,
pub fee: Amount,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AssembleOfferRequest {
pub build_id: OfferBuildId,
pub signed: SignedBundle,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TakeOfferRequest {
pub identity: IdentityRef,
pub offer: String,
pub fee: Amount,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FinalizeTakeRequest {
pub build_id: OfferBuildId,
pub signed: SignedBundle,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CancelOfferRequest {
pub identity: IdentityRef,
pub offer: String,
pub fee: Amount,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CombineOffersRequest {
pub offers: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SummarizeOfferRequest {
pub offer: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PendingOfferBuild {
pub build_id: OfferBuildId,
pub unsigned: UnsignedSpend,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OfferString {
pub offer: String,
pub offer_id: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SummaryAsset {
Xch {
amount: Amount,
},
Cat {
asset_id: AssetId,
amount: Amount,
},
Nft {
launcher_id: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OfferSummary {
pub offer_id: String,
pub offered: Vec<SummaryAsset>,
pub requested: Vec<SummaryAsset>,
pub arbitrage: Vec<SummaryAsset>,
pub royalties: Vec<(String, u16)>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::WalletId;
fn make_request() -> MakeOfferRequest {
MakeOfferRequest {
identity: IdentityRef::new(WalletId(1)),
offered: OfferedAssets {
xch: Amount(0),
cats: vec![(AssetId("dbx".into()), Amount(1_000))],
},
requested: RequestedAssets {
xch: Amount(50_000),
cats: vec![],
payee: Address("xch1payee".into()),
},
fee: Amount(0),
}
}
#[test]
fn make_offer_request_round_trips() {
let req = make_request();
let json = serde_json::to_string(&req).unwrap();
let back: MakeOfferRequest = serde_json::from_str(&json).unwrap();
assert_eq!(req, back);
}
#[test]
fn take_and_finalize_round_trip() {
let take = TakeOfferRequest {
identity: IdentityRef::new(WalletId(2)),
offer: "offer1abc".into(),
fee: Amount(10),
};
let json = serde_json::to_string(&take).unwrap();
assert_eq!(take, serde_json::from_str(&json).unwrap());
let finalize = FinalizeTakeRequest {
build_id: OfferBuildId("build-7".into()),
signed: SignedBundle {
bundle: chia_protocol::SpendBundle::new(vec![], chia_bls::Signature::default()),
},
};
let json = serde_json::to_string(&finalize).unwrap();
assert_eq!(finalize, serde_json::from_str(&json).unwrap());
}
#[test]
fn summary_asset_is_tagged() {
let summary = OfferSummary {
offer_id: "ab".repeat(32),
offered: vec![SummaryAsset::Cat {
asset_id: AssetId("dbx".into()),
amount: Amount(1_000),
}],
requested: vec![SummaryAsset::Xch {
amount: Amount(50_000),
}],
arbitrage: vec![],
royalties: vec![("launcher".into(), 300)],
};
let json = serde_json::to_string(&summary).unwrap();
assert!(json.contains("\"kind\":\"cat\""), "tagged enum: {json}");
let back: OfferSummary = serde_json::from_str(&json).unwrap();
assert_eq!(summary, back);
}
#[test]
fn pending_offer_build_round_trips() {
let pending = PendingOfferBuild {
build_id: OfferBuildId("b1".into()),
unsigned: UnsignedSpend {
coin_spends: vec![],
required_signatures: vec![],
summary: crate::types::TransactionSummary {
melted_singletons: Vec::new(),
nft_operations: Vec::new(),
received: vec![],
outputs: vec![],
fee: Amount(0),
},
},
};
let json = serde_json::to_string(&pending).unwrap();
assert_eq!(pending, serde_json::from_str(&json).unwrap());
}
}